I started looking into this based on some unified-/managed-memory
discussions. At the end, I ended up doing the following where only
the 'local' clause is directly related to USM - albeit 'groupprivate'
implies 'declare target' with 'local' clause, which is the link.

Note: The following is only the Fortran parser work, i.e. new features
will print a sorry.

- some janitorial changes to 'declare target' (missing diagnostic,
  cleanup). In particular, check that with 'link' there is no
  'device_type(nohost)'.
- add the 'local' clause to 'declare target' (+ sorry)
- add the 'groupprivate' directive (+ sorry)
- add the 'dyn_groupprivate' clause to 'target' (+ sorry)

Comments before I commit it?

Tobias

PS: Eventually, GCC needs to handle 'device_type(host)'
(for variables and functions and enter/link/local),
besides improving/supporting the 'device_type(nohost)'
behavior. And, of course, actually implementing 'local'
and (dyn_)groupprivate also has eventually to be done ...
OpenMP/Fortran: 'declare target' fix + parse 'local' clause; parse groupprivate

Declare target's 'link' clause disallows 'nohost'; check for it.
Additionally, some other cleanups have been done.

The 'local' clause to 'declare target' is now supported in the FE,
but a 'sorry, unimplemented' is printed at TREE generation time.

This commit also adds the 'groupprivate' directive, which implies
'declare target' with the 'local' clause. And for completeness also
the 'dyn_groupprivate' clause to 'target'. However, all those new
features will eventually print 'sorry, unimplemented' for now.

gcc/fortran/ChangeLog:

	* dump-parse-tree.cc (show_attr): Handle OpenMP's 'local' clause
	and the 'groupprivate' directive.
	(show_omp_clauses): Handle dyn_groupprivate.
	* frontend-passes.cc (gfc_code_walker): Walk dyn_groupprivate.
	* gfortran.h (enum gfc_statement): Add ST_OMP_GROUPPRIVATE.
	(enum gfc_omp_fallback, gfc_add_omp_groupprivate,
	gfc_add_omp_declare_target_local): New.
	* match.h (gfc_match_omp_groupprivate): New.
	* module.cc (enum ab_attribute, mio_symbol_attribute, load_commons,
	write_common_0): Handle 'groupprivate' + declare target's 'local'.
	* openmp.cc (gfc_omp_directives): Add 'groupprivate'.
	(gfc_free_omp_clauses): Free dyn_groupprivate.
	(enum omp_mask2): Add OMP_CLAUSE_LOCAL and OMP_CLAUSE_DYN_GROUPPRIVATE.
	(gfc_match_omp_clauses): Match them.
	(OMP_TARGET_CLAUSES): Add OMP_CLAUSE_DYN_GROUPPRIVATE.
	(OMP_DECLARE_TARGET_CLAUSES): Add OMP_CLAUSE_LOCAL.
	(gfc_match_omp_declare_target): Handle groupprivate + fixes.
	(gfc_match_omp_threadprivate): Code move to and calling now ...
	(gfc_match_omp_thread_group_private): ... this new function.
	Also handle groupprivate.
	(gfc_match_omp_groupprivate): New.
	(resolve_omp_clauses): Resolve dyn_groupprivate.
	* parse.cc (decode_omp_directive): Match groupprivate.
	(case_omp_decl, parse_spec, gfc_ascii_statement): Handle it.
	* resolve.cc (resolve_symbol): Handle groupprivate.
	* symbol.cc (gfc_check_conflict, gfc_copy_attr): Handle 'local'
	and 'groupprivate'.
	(gfc_add_omp_groupprivate, gfc_add_omp_declare_target_local): New.
	* trans-common.cc (build_common_decl,
	accumulate_equivalence_attributes): Print 'sorry' for
	groupprivate and declare target's local.
	* trans-decl.cc (add_attributes_to_decl): Likewise..
	* trans-openmp.cc (gfc_trans_omp_clauses): Print 'sorry' for
	dyn_groupprivate.
	(fallback): Process declare target with link/local as
	done for 'enter'.

gcc/testsuite/ChangeLog:

	* gfortran.dg/gomp/crayptr2.f90: Move dg-error line.
	* gfortran.dg/gomp/declare-target-2.f90: Extend.
	* gfortran.dg/gomp/declare-target-4.f90: Update comment,
	enable one test.
	* gfortran.dg/gomp/declare-target-5.f90: Update dg- wording,
	add new test.
	* gfortran.dg/gomp/declare-target-indirect-2.f90: Expect
	'device_type(any)' in scan-tree-dump.
	* gfortran.dg/gomp/declare-target-6.f90: New test.
	* gfortran.dg/gomp/dyn_groupprivate-1.f90: New test.
	* gfortran.dg/gomp/dyn_groupprivate-2.f90: New test.
	* gfortran.dg/gomp/groupprivate-1.f90: New test.
	* gfortran.dg/gomp/groupprivate-2.f90: New test.
	* gfortran.dg/gomp/groupprivate-3.f90: New test.
	* gfortran.dg/gomp/groupprivate-4.f90: New test.
	* gfortran.dg/gomp/groupprivate-5.f90: New test.
	* gfortran.dg/gomp/groupprivate-6.f90: New test.

 gcc/fortran/dump-parse-tree.cc                     |  18 ++
 gcc/fortran/frontend-passes.cc                     |   1 +
 gcc/fortran/gfortran.h                             |  19 ++
 gcc/fortran/match.h                                |   1 +
 gcc/fortran/module.cc                              |  20 +-
 gcc/fortran/openmp.cc                              | 359 ++++++++++++++++-----
 gcc/fortran/parse.cc                               |  10 +-
 gcc/fortran/resolve.cc                             |  19 +-
 gcc/fortran/symbol.cc                              |  64 +++-
 gcc/fortran/trans-common.cc                        |  31 +-
 gcc/fortran/trans-decl.cc                          |  26 +-
 gcc/fortran/trans-openmp.cc                        |  23 +-
 gcc/testsuite/gfortran.dg/gomp/crayptr2.f90        |   4 +-
 .../gfortran.dg/gomp/declare-target-2.f90          |   4 +
 .../gfortran.dg/gomp/declare-target-4.f90          |   9 +-
 .../gfortran.dg/gomp/declare-target-5.f90          |  37 +--
 .../gfortran.dg/gomp/declare-target-6.f90          |  15 +
 .../gfortran.dg/gomp/declare-target-indirect-2.f90 |   4 +-
 .../gfortran.dg/gomp/dyn_groupprivate-1.f90        |  20 ++
 .../gfortran.dg/gomp/dyn_groupprivate-2.f90        |  23 ++
 gcc/testsuite/gfortran.dg/gomp/groupprivate-1.f90  |  23 ++
 gcc/testsuite/gfortran.dg/gomp/groupprivate-2.f90  |  37 +++
 gcc/testsuite/gfortran.dg/gomp/groupprivate-3.f90  |  16 +
 gcc/testsuite/gfortran.dg/gomp/groupprivate-4.f90  |  25 ++
 gcc/testsuite/gfortran.dg/gomp/groupprivate-5.f90  |  58 ++++
 gcc/testsuite/gfortran.dg/gomp/groupprivate-6.f90  |  34 ++
 26 files changed, 778 insertions(+), 122 deletions(-)

diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index eda0659d6e2..2a4ebb0fa0f 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -843,6 +843,8 @@ show_attr (symbol_attribute *attr, const char * module)
     fputs (" VALUE", dumpfile);
   if (attr->volatile_)
     fputs (" VOLATILE", dumpfile);
+  if (attr->omp_groupprivate)
+    fputs (" GROUPPRIVATE", dumpfile);
   if (attr->threadprivate)
     fputs (" THREADPRIVATE", dumpfile);
   if (attr->temporary)
@@ -938,6 +940,8 @@ show_attr (symbol_attribute *attr, const char * module)
     fputs (" OMP-DECLARE-TARGET", dumpfile);
   if (attr->omp_declare_target_link)
     fputs (" OMP-DECLARE-TARGET-LINK", dumpfile);
+  if (attr->omp_declare_target_local)
+    fputs (" OMP-DECLARE-TARGET-LOCAL", dumpfile);
   if (attr->omp_declare_target_indirect)
     fputs (" OMP-DECLARE-TARGET-INDIRECT", dumpfile);
   if (attr->omp_device_type == OMP_DEVICE_TYPE_HOST)
@@ -2211,6 +2215,20 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
     fputs (" DEPEND(source)", dumpfile);
   if (omp_clauses->doacross_source)
     fputs (" DOACROSS(source:)", dumpfile);
+  if (omp_clauses->dyn_groupprivate)
+    {
+      fputs (" DYN_GROUPPRIVATE(", dumpfile);
+      if (omp_clauses->fallback != OMP_FALLBACK_NONE)
+	fputs ("FALLBACK(", dumpfile);
+      if (omp_clauses->fallback == OMP_FALLBACK_ABORT)
+	fputs ("ABORT):", dumpfile);
+      else if (omp_clauses->fallback == OMP_FALLBACK_DEFAULT_MEM)
+	fputs ("DEFAULT_MEM):", dumpfile);
+      else if (omp_clauses->fallback == OMP_FALLBACK_NULL)
+	fputs ("NULL):", dumpfile);
+      show_expr (omp_clauses->dyn_groupprivate);
+      fputc (')', dumpfile);
+    }
   if (omp_clauses->capture)
     fputs (" CAPTURE", dumpfile);
   if (omp_clauses->depobj_update != OMP_DEPEND_UNSET)
diff --git a/gcc/fortran/frontend-passes.cc b/gcc/fortran/frontend-passes.cc
index 595c5095eaf..b699231e971 100644
--- a/gcc/fortran/frontend-passes.cc
+++ b/gcc/fortran/frontend-passes.cc
@@ -5645,6 +5645,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
 		  WALK_SUBEXPR (co->ext.omp_clauses->num_tasks);
 		  WALK_SUBEXPR (co->ext.omp_clauses->priority);
 		  WALK_SUBEXPR (co->ext.omp_clauses->detach);
+		  WALK_SUBEXPR (co->ext.omp_clauses->dyn_groupprivate);
 		  WALK_SUBEXPR (co->ext.omp_clauses->novariants);
 		  WALK_SUBEXPR (co->ext.omp_clauses->nocontext);
 		  for (idx = 0; idx < ARRAY_SIZE (list_types); idx++)
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 2997c0326ca..72aecfb8379 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -311,6 +311,7 @@ enum gfc_statement
   ST_OMP_TASKLOOP, ST_OMP_END_TASKLOOP, ST_OMP_SCAN, ST_OMP_DEPOBJ,
   ST_OMP_TASKLOOP_SIMD, ST_OMP_END_TASKLOOP_SIMD, ST_OMP_ORDERED_DEPEND,
   ST_OMP_REQUIRES, ST_PROCEDURE, ST_GENERIC, ST_CRITICAL, ST_END_CRITICAL,
+  ST_OMP_GROUPPRIVATE,
   ST_GET_FCN_CHARACTERISTICS, ST_LOCK, ST_UNLOCK, ST_EVENT_POST,
   ST_EVENT_WAIT, ST_FAIL_IMAGE, ST_FORM_TEAM, ST_CHANGE_TEAM,
   ST_END_TEAM, ST_SYNC_TEAM,  ST_OMP_PARALLEL_MASTER,
@@ -1042,8 +1043,10 @@ typedef struct
   /* Mentioned in OMP DECLARE TARGET.  */
   unsigned omp_declare_target:1;
   unsigned omp_declare_target_link:1;
+  unsigned omp_declare_target_local:1;
   unsigned omp_declare_target_indirect:1;
   ENUM_BITFIELD (gfc_omp_device_type) omp_device_type:2;
+  unsigned omp_groupprivate:1;
   unsigned omp_allocate:1;
 
   /* Mentioned in OACC DECLARE.  */
@@ -1488,6 +1491,7 @@ enum
   OMP_LIST_TASK_REDUCTION,
   OMP_LIST_DEVICE_RESIDENT,
   OMP_LIST_LINK,
+  OMP_LIST_LOCAL,
   OMP_LIST_USE_DEVICE,
   OMP_LIST_CACHE,
   OMP_LIST_IS_DEVICE_PTR,
@@ -1614,6 +1618,14 @@ enum gfc_omp_bind_type
   OMP_BIND_THREAD
 };
 
+enum gfc_omp_fallback
+{
+  OMP_FALLBACK_NONE,
+  OMP_FALLBACK_ABORT,
+  OMP_FALLBACK_DEFAULT_MEM,
+  OMP_FALLBACK_NULL
+};
+
 typedef struct gfc_omp_assumptions
 {
   int n_absent, n_contains;
@@ -1649,6 +1661,7 @@ typedef struct gfc_omp_clauses
   struct gfc_expr *detach;
   struct gfc_expr *depobj;
   struct gfc_expr *dist_chunk_size;
+  struct gfc_expr *dyn_groupprivate;
   struct gfc_expr *message;
   struct gfc_expr *novariants;
   struct gfc_expr *nocontext;
@@ -1681,6 +1694,7 @@ typedef struct gfc_omp_clauses
   ENUM_BITFIELD (gfc_omp_at_type) at:2;
   ENUM_BITFIELD (gfc_omp_severity_type) severity:2;
   ENUM_BITFIELD (gfc_omp_sched_kind) dist_sched_kind:3;
+  ENUM_BITFIELD (gfc_omp_fallback) fallback:2;
 
   /* OpenACC. */
   struct gfc_expr *async_expr;
@@ -2118,6 +2132,8 @@ typedef struct gfc_common_head
   char use_assoc, saved, threadprivate;
   unsigned char omp_declare_target : 1;
   unsigned char omp_declare_target_link : 1;
+  unsigned char omp_declare_target_local : 1;
+  unsigned char omp_groupprivate : 1;
   ENUM_BITFIELD (gfc_omp_device_type) omp_device_type:2;
   /* Provide sufficient space to hold "symbol.symbol.eq.1234567890".  */
   char name[2*GFC_MAX_SYMBOL_LEN + 1 + 14 + 1];
@@ -3717,6 +3733,9 @@ bool gfc_add_threadprivate (symbol_attribute *, const char *, locus *);
 bool gfc_add_omp_declare_target (symbol_attribute *, const char *, locus *);
 bool gfc_add_omp_declare_target_link (symbol_attribute *, const char *,
 				      locus *);
+bool gfc_add_omp_declare_target_local (symbol_attribute *, const char *,
+				       locus *);
+bool gfc_add_omp_groupprivate (symbol_attribute *, const char *, locus *);
 bool gfc_add_target (symbol_attribute *, locus *);
 bool gfc_add_dummy (symbol_attribute *, const char *, locus *);
 bool gfc_add_generic (symbol_attribute *, const char *, locus *);
diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
index 410361c4bd1..314be6baa92 100644
--- a/gcc/fortran/match.h
+++ b/gcc/fortran/match.h
@@ -174,6 +174,7 @@ match gfc_match_omp_do_simd (void);
 match gfc_match_omp_loop (void);
 match gfc_match_omp_error (void);
 match gfc_match_omp_flush (void);
+match gfc_match_omp_groupprivate (void);
 match gfc_match_omp_interop (void);
 match gfc_match_omp_masked (void);
 match gfc_match_omp_masked_taskloop (void);
diff --git a/gcc/fortran/module.cc b/gcc/fortran/module.cc
index c489decec8d..262f72b8e7c 100644
--- a/gcc/fortran/module.cc
+++ b/gcc/fortran/module.cc
@@ -2092,7 +2092,8 @@ enum ab_attribute
   AB_ARRAY_OUTER_DEPENDENCY, AB_MODULE_PROCEDURE, AB_OACC_DECLARE_CREATE,
   AB_OACC_DECLARE_COPYIN, AB_OACC_DECLARE_DEVICEPTR,
   AB_OACC_DECLARE_DEVICE_RESIDENT, AB_OACC_DECLARE_LINK,
-  AB_OMP_DECLARE_TARGET_LINK, AB_PDT_KIND, AB_PDT_LEN, AB_PDT_TYPE,
+  AB_OMP_DECLARE_TARGET_LINK, AB_OMP_DECLARE_TARGET_LOCAL,
+  AB_PDT_KIND, AB_PDT_LEN, AB_PDT_TYPE,
   AB_PDT_COMP, AB_PDT_TEMPLATE, AB_PDT_ARRAY, AB_PDT_STRING,
   AB_OACC_ROUTINE_LOP_GANG, AB_OACC_ROUTINE_LOP_WORKER,
   AB_OACC_ROUTINE_LOP_VECTOR, AB_OACC_ROUTINE_LOP_SEQ,
@@ -2102,7 +2103,7 @@ enum ab_attribute
   AB_OMP_REQ_MEM_ORDER_SEQ_CST, AB_OMP_REQ_MEM_ORDER_ACQ_REL,
   AB_OMP_REQ_MEM_ORDER_ACQUIRE, AB_OMP_REQ_MEM_ORDER_RELEASE,
   AB_OMP_REQ_MEM_ORDER_RELAXED, AB_OMP_DEVICE_TYPE_NOHOST,
-  AB_OMP_DEVICE_TYPE_HOST, AB_OMP_DEVICE_TYPE_ANY
+  AB_OMP_DEVICE_TYPE_HOST, AB_OMP_DEVICE_TYPE_ANY, AB_OMP_GROUPPRIVATE
 };
 
 static const mstring attr_bits[] =
@@ -2166,6 +2167,8 @@ static const mstring attr_bits[] =
     minit ("OACC_DECLARE_DEVICE_RESIDENT", AB_OACC_DECLARE_DEVICE_RESIDENT),
     minit ("OACC_DECLARE_LINK", AB_OACC_DECLARE_LINK),
     minit ("OMP_DECLARE_TARGET_LINK", AB_OMP_DECLARE_TARGET_LINK),
+    minit ("OMP_DECLARE_TARGET_LOCAL", AB_OMP_DECLARE_TARGET_LOCAL),
+    minit ("OMP_GROUPPRIVATE", AB_OMP_GROUPPRIVATE),
     minit ("PDT_KIND", AB_PDT_KIND),
     minit ("PDT_LEN", AB_PDT_LEN),
     minit ("PDT_TYPE", AB_PDT_TYPE),
@@ -2399,6 +2402,10 @@ mio_symbol_attribute (symbol_attribute *attr)
 	MIO_NAME (ab_attribute) (AB_OACC_DECLARE_LINK, attr_bits);
       if (attr->omp_declare_target_link)
 	MIO_NAME (ab_attribute) (AB_OMP_DECLARE_TARGET_LINK, attr_bits);
+      if (attr->omp_declare_target_local)
+	MIO_NAME (ab_attribute) (AB_OMP_DECLARE_TARGET_LOCAL, attr_bits);
+      if (attr->omp_groupprivate)
+	MIO_NAME (ab_attribute) (AB_OMP_GROUPPRIVATE, attr_bits);
       if (attr->pdt_kind)
 	MIO_NAME (ab_attribute) (AB_PDT_KIND, attr_bits);
       if (attr->pdt_len)
@@ -2654,6 +2661,12 @@ mio_symbol_attribute (symbol_attribute *attr)
 	    case AB_OMP_DECLARE_TARGET_LINK:
 	      attr->omp_declare_target_link = 1;
 	      break;
+	    case AB_OMP_DECLARE_TARGET_LOCAL:
+	      attr->omp_declare_target_local = 1;
+	      break;
+	    case AB_OMP_GROUPPRIVATE:
+	      attr->omp_groupprivate = 1;
+	      break;
 	    case AB_ARRAY_OUTER_DEPENDENCY:
 	      attr->array_outer_dependency =1;
 	      break;
@@ -5268,6 +5281,8 @@ load_commons (void)
       if (flags & 2)
 	p->threadprivate = 1;
       p->omp_device_type = (gfc_omp_device_type) ((flags >> 2) & 3);
+      if ((flags >> 4) & 1)
+	p->omp_groupprivate = 1;
       p->use_assoc = 1;
 
       /* Get whether this was a bind(c) common or not.  */
@@ -6191,6 +6206,7 @@ write_common_0 (gfc_symtree *st, bool this_module)
       if (p->threadprivate)
 	flags |= 2;
       flags |= p->omp_device_type << 2;
+      flags |= p->omp_groupprivate << 4;
       mio_integer (&flags);
 
       /* Write out whether the common block is bind(c) or not.  */
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 81d624b7b54..f047028187f 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -84,6 +84,7 @@ static const struct gfc_omp_directive gfc_omp_directives[] = {
   /* {"flatten", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLATTEN}, */
   {"flush", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLUSH},
   /* {"fuse", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLUSE}, */
+  {"groupprivate", GFC_OMP_DIR_DECLARATIVE, ST_OMP_GROUPPRIVATE},
   /* {"interchange", GFC_OMP_DIR_EXECUTABLE, ST_OMP_INTERCHANGE}, */
   {"interop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_INTEROP},
   {"loop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_LOOP},
@@ -195,6 +196,7 @@ gfc_free_omp_clauses (gfc_omp_clauses *c)
   gfc_free_expr (c->num_teams_lower);
   gfc_free_expr (c->num_teams_upper);
   gfc_free_expr (c->device);
+  gfc_free_expr (c->dyn_groupprivate);
   gfc_free_expr (c->thread_limit);
   gfc_free_expr (c->dist_chunk_size);
   gfc_free_expr (c->grainsize);
@@ -1172,6 +1174,8 @@ enum omp_mask2
   OMP_CLAUSE_NOVARIANTS, /* OpenMP 5.1  */
   OMP_CLAUSE_NOCONTEXT, /* OpenMP 5.1  */
   OMP_CLAUSE_INTEROP, /* OpenMP 5.1  */
+  OMP_CLAUSE_LOCAL, /* OpenMP 6.0 */
+  OMP_CLAUSE_DYN_GROUPPRIVATE, /* OpenMP 6.1 */
   /* This must come last.  */
   OMP_MASK2_LAST
 };
@@ -3096,6 +3100,22 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	      else
 		continue;
 	    }
+	  if ((mask & OMP_CLAUSE_DYN_GROUPPRIVATE)
+	      && gfc_match_dupl_check (!c->dyn_groupprivate,
+				       "dyn_groupprivate", true) == MATCH_YES)
+	    {
+	      if (gfc_match ("fallback ( abort ) : ") == MATCH_YES)
+		c->fallback = OMP_FALLBACK_ABORT;
+	      else if (gfc_match ("fallback ( default_mem ) : ") == MATCH_YES)
+		c->fallback = OMP_FALLBACK_DEFAULT_MEM;
+	      else if (gfc_match ("fallback ( null ) : ") == MATCH_YES)
+		c->fallback = OMP_FALLBACK_NULL;
+	      if (gfc_match_expr (&c->dyn_groupprivate) != MATCH_YES)
+		return MATCH_ERROR;
+	      if (gfc_match (" )") != MATCH_YES)
+		goto error;
+	      continue;
+	    }
 	  break;
 	case 'e':
 	  if ((mask & OMP_CLAUSE_ENTER))
@@ -3567,6 +3587,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 					      &c->lists[OMP_LIST_LINK])
 		       == MATCH_YES))
 	    continue;
+	  if ((mask & OMP_CLAUSE_LOCAL)
+	      && (gfc_match_omp_to_link ("local (", &c->lists[OMP_LIST_LOCAL])
+		  == MATCH_YES))
+	    continue;
 	  break;
 	case 'm':
 	  if ((mask & OMP_CLAUSE_MAP)
@@ -5064,7 +5088,8 @@ cleanup:
    | OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_DEFAULTMAP			\
    | OMP_CLAUSE_IS_DEVICE_PTR | OMP_CLAUSE_IN_REDUCTION			\
    | OMP_CLAUSE_THREAD_LIMIT | OMP_CLAUSE_ALLOCATE			\
-   | OMP_CLAUSE_HAS_DEVICE_ADDR | OMP_CLAUSE_USES_ALLOCATORS)
+   | OMP_CLAUSE_HAS_DEVICE_ADDR | OMP_CLAUSE_USES_ALLOCATORS		\
+   | OMP_CLAUSE_DYN_GROUPPRIVATE)
 #define OMP_TARGET_DATA_CLAUSES \
   (omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF	\
    | OMP_CLAUSE_USE_DEVICE_PTR | OMP_CLAUSE_USE_DEVICE_ADDR)
@@ -5092,7 +5117,7 @@ cleanup:
   (omp_mask (OMP_CLAUSE_THREADS) | OMP_CLAUSE_SIMD)
 #define OMP_DECLARE_TARGET_CLAUSES \
   (omp_mask (OMP_CLAUSE_ENTER) | OMP_CLAUSE_LINK | OMP_CLAUSE_DEVICE_TYPE \
-   | OMP_CLAUSE_TO | OMP_CLAUSE_INDIRECT)
+   | OMP_CLAUSE_TO | OMP_CLAUSE_INDIRECT | OMP_CLAUSE_LOCAL)
 #define OMP_ATOMIC_CLAUSES \
   (omp_mask (OMP_CLAUSE_ATOMIC) | OMP_CLAUSE_CAPTURE | OMP_CLAUSE_HINT	\
    | OMP_CLAUSE_MEMORDER | OMP_CLAUSE_COMPARE | OMP_CLAUSE_FAIL 	\
@@ -6113,7 +6138,7 @@ gfc_match_omp_declare_target (void)
   gfc_buffer_error (false);
 
   static const int to_enter_link_lists[]
-    = { OMP_LIST_TO, OMP_LIST_ENTER, OMP_LIST_LINK };
+    = { OMP_LIST_TO, OMP_LIST_ENTER, OMP_LIST_LINK, OMP_LIST_LOCAL };
   for (size_t listn = 0; listn < ARRAY_SIZE (to_enter_link_lists)
 			 && (list = to_enter_link_lists[listn], true); ++listn)
     for (n = c->lists[list]; n; n = n->next)
@@ -6122,6 +6147,8 @@ gfc_match_omp_declare_target (void)
       else if (n->u.common->head)
 	n->u.common->head->mark = 0;
 
+  if (c->device_type == OMP_DEVICE_TYPE_UNSET)
+    c->device_type = OMP_DEVICE_TYPE_ANY;
   for (size_t listn = 0; listn < ARRAY_SIZE (to_enter_link_lists)
 			 && (list = to_enter_link_lists[listn], true); ++listn)
     for (n = c->lists[list]; n; n = n->next)
@@ -6130,105 +6157,161 @@ gfc_match_omp_declare_target (void)
 	  if (n->sym->attr.in_common)
 	    gfc_error_now ("OMP DECLARE TARGET variable at %L is an "
 			   "element of a COMMON block", &n->where);
+	  else if (n->sym->attr.omp_groupprivate && list != OMP_LIST_LOCAL)
+	    gfc_error_now ("List item %qs at %L not appear in the %qs clause "
+			   "as it was previously specified in a GROUPPRIVATE "
+			   "directive", n->sym->name, &n->where,
+			   list == OMP_LIST_LINK
+			   ? "link" : list == OMP_LIST_TO ? "to" : "enter");
 	  else if (n->sym->mark)
 	    gfc_error_now ("Variable at %L mentioned multiple times in "
 			   "clauses of the same OMP DECLARE TARGET directive",
 			   &n->where);
-	  else if (n->sym->attr.omp_declare_target
-		   && n->sym->attr.omp_declare_target_link
-		   && list != OMP_LIST_LINK)
+	  else if ((n->sym->attr.omp_declare_target_link
+		    || n->sym->attr.omp_declare_target_local)
+		   && list != OMP_LIST_LINK
+		   && list != OMP_LIST_LOCAL)
 	    gfc_error_now ("OMP DECLARE TARGET variable at %L previously "
-			   "mentioned in LINK clause and later in %s clause",
-			   &n->where, list == OMP_LIST_TO ? "TO" : "ENTER");
+			   "mentioned in %s clause and later in %s clause",
+			   &n->where,
+			   n->sym->attr.omp_declare_target_link ? "LINK"
+								: "LOCAL",
+			   list == OMP_LIST_TO ? "TO" : "ENTER");
 	  else if (n->sym->attr.omp_declare_target
-		   && !n->sym->attr.omp_declare_target_link
-		   && list == OMP_LIST_LINK)
+		   && (list == OMP_LIST_LINK || list == OMP_LIST_LOCAL))
 	    gfc_error_now ("OMP DECLARE TARGET variable at %L previously "
 			   "mentioned in TO or ENTER clause and later in "
-			   "LINK clause", &n->where);
-	  else if (gfc_add_omp_declare_target (&n->sym->attr, n->sym->name,
-					       &n->sym->declared_at))
+			   "%s clause", &n->where,
+			   list == OMP_LIST_LINK ? "LINK" : "LOCAL");
+	  else
 	    {
+	      if (list == OMP_LIST_TO || list == OMP_LIST_ENTER)
+		gfc_add_omp_declare_target (&n->sym->attr, n->sym->name,
+					    &n->sym->declared_at);
 	      if (list == OMP_LIST_LINK)
 		gfc_add_omp_declare_target_link (&n->sym->attr, n->sym->name,
 						 &n->sym->declared_at);
+	      if (list == OMP_LIST_LOCAL)
+		gfc_add_omp_declare_target_local (&n->sym->attr, n->sym->name,
+						  &n->sym->declared_at);
+	    }
+	  if (n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
+	      && n->sym->attr.omp_device_type != c->device_type)
+	    {
+	      const char *dt = "any";
+	      if (n->sym->attr.omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+		dt = "nohost";
+	      else if (n->sym->attr.omp_device_type == OMP_DEVICE_TYPE_HOST)
+		dt = "host";
+	      if (n->sym->attr.omp_groupprivate)
+		gfc_error_now ("List item %qs at %L set in previous OMP "
+			       "GROUPPRIVATE directive to the different "
+			       "DEVICE_TYPE %qs", n->sym->name, &n->where, dt);
+	      else
+		gfc_error_now ("List item %qs at %L set in previous OMP "
+			       "DECLARE TARGET directive to the different "
+			       "DEVICE_TYPE %qs", n->sym->name, &n->where, dt);
 	    }
-	  if (c->device_type != OMP_DEVICE_TYPE_UNSET)
-	    {
-	      if (n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
-		  && n->sym->attr.omp_device_type != c->device_type)
-		gfc_error_now ("List item %qs at %L set in previous OMP DECLARE "
-			       "TARGET directive to a different DEVICE_TYPE",
-			       n->sym->name, &n->where);
-	      n->sym->attr.omp_device_type = c->device_type;
-	    }
-	  if (c->indirect)
+	  n->sym->attr.omp_device_type = c->device_type;
+	  if (c->indirect && c->device_type != OMP_DEVICE_TYPE_ANY)
 	    {
-	      if (n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
-		  && n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_ANY)
-		gfc_error_now ("DEVICE_TYPE must be ANY when used with "
-			       "INDIRECT at %L", &n->where);
-	      n->sym->attr.omp_declare_target_indirect = c->indirect;
+	      gfc_error_now ("DEVICE_TYPE must be ANY when used with INDIRECT "
+			     "at %L", &n->where);
+	      c->indirect = 0;
 	    }
-
+	  n->sym->attr.omp_declare_target_indirect = c->indirect;
+	  if (list == OMP_LIST_LINK && c->device_type == OMP_DEVICE_TYPE_NOHOST)
+	    gfc_error_now ("List item %qs at %L set with NOHOST specified may "
+			   "not appear in a LINK clause", n->sym->name,
+			   &n->where);
 	  n->sym->mark = 1;
 	}
-      else if (n->u.common->omp_declare_target
-	       && n->u.common->omp_declare_target_link
-	       && list != OMP_LIST_LINK)
-	gfc_error_now ("OMP DECLARE TARGET COMMON at %L previously "
-		       "mentioned in LINK clause and later in %s clause",
-		       &n->where, list == OMP_LIST_TO ? "TO" : "ENTER");
-      else if (n->u.common->omp_declare_target
-	       && !n->u.common->omp_declare_target_link
-	       && list == OMP_LIST_LINK)
-	gfc_error_now ("OMP DECLARE TARGET COMMON at %L previously "
-		       "mentioned in TO or ENTER clause and later in "
-		       "LINK clause", &n->where);
-      else if (n->u.common->head && n->u.common->head->mark)
-	gfc_error_now ("COMMON at %L mentioned multiple times in "
-		       "clauses of the same OMP DECLARE TARGET directive",
-		       &n->where);
-      else
-	{
-	  n->u.common->omp_declare_target = 1;
-	  n->u.common->omp_declare_target_link = (list == OMP_LIST_LINK);
+      else  /* common block  */
+	{
+	  if (n->u.common->omp_groupprivate && list != OMP_LIST_LOCAL)
+	    gfc_error_now ("Common block %</%s/%> at %L not appear in the %qs "
+			   "clause as it was previously specified in a "
+			   "GROUPPRIVATE directive",
+			   n->u.common->name, &n->where,
+			   list == OMP_LIST_LINK
+			   ? "link" : list == OMP_LIST_TO ? "to" : "enter");
+	  else if (n->u.common->head && n->u.common->head->mark)
+	    gfc_error_now ("Common block %</%s/%> at %L mentioned multiple "
+			   "times in clauses of the same OMP DECLARE TARGET "
+			   "directive", n->u.common->name, &n->where);
+	  else if ((n->u.common->omp_declare_target_link
+		    || n->u.common->omp_declare_target_local)
+		   && list != OMP_LIST_LINK
+		   && list != OMP_LIST_LOCAL)
+	    gfc_error_now ("Common block %</%s/%> at %L previously mentioned "
+			   "in %s clause and later in %s clause",
+			   n->u.common->name, &n->where,
+			   n->u.common->omp_declare_target_link ? "LINK"
+								: "LOCAL",
+			   list == OMP_LIST_TO ? "TO" : "ENTER");
+	  else if (n->u.common->omp_declare_target
+		   && (list == OMP_LIST_LINK || list == OMP_LIST_LOCAL))
+	    gfc_error_now ("Common block %</%s/%> at %L previously mentioned "
+			   "in TO or ENTER clause and later in %s clause",
+			   n->u.common->name, &n->where,
+			   list == OMP_LIST_LINK ? "LINK" : "LOCAL");
 	  if (n->u.common->omp_device_type != OMP_DEVICE_TYPE_UNSET
 	      && n->u.common->omp_device_type != c->device_type)
-	    gfc_error_now ("COMMON at %L set in previous OMP DECLARE "
-			   "TARGET directive to a different DEVICE_TYPE",
-			   &n->where);
+	    {
+	      const char *dt = "any";
+	      if (n->u.common->omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+		dt = "nohost";
+	      else if (n->u.common->omp_device_type == OMP_DEVICE_TYPE_HOST)
+		dt = "host";
+	      if (n->u.common->omp_groupprivate)
+		gfc_error_now ("Common block %</%s/%> at %L set in previous OMP "
+			       "GROUPPRIVATE directive to the different "
+			       "DEVICE_TYPE %qs", n->u.common->name, &n->where,
+				dt);
+	      else
+		gfc_error_now ("Common block %</%s/%> at %L set in previous OMP "
+			       "DECLARE TARGET directive to the different "
+			       "DEVICE_TYPE %qs", n->u.common->name, &n->where,
+				dt);
+	    }
 	  n->u.common->omp_device_type = c->device_type;
 
+	  if (c->indirect && c->device_type != OMP_DEVICE_TYPE_ANY)
+	    {
+	      gfc_error_now ("DEVICE_TYPE must be ANY when used with INDIRECT "
+			     "at %L", &n->where);
+	      c->indirect = 0;
+	    }
+	  if (list == OMP_LIST_LINK && c->device_type == OMP_DEVICE_TYPE_NOHOST)
+	    gfc_error_now ("Common block %</%s/%> at %L set with NOHOST "
+			   "specified may not appear in a LINK clause",
+			   n->u.common->name, &n->where);
+
+	  if (list == OMP_LIST_TO || list == OMP_LIST_ENTER)
+	    n->u.common->omp_declare_target = 1;
+	  if (list == OMP_LIST_LINK)
+	    n->u.common->omp_declare_target_link = 1;
+	  if (list == OMP_LIST_LOCAL)
+	    n->u.common->omp_declare_target_local = 1;
+
 	  for (s = n->u.common->head; s; s = s->common_next)
 	    {
 	      s->mark = 1;
-	      if (gfc_add_omp_declare_target (&s->attr, s->name,
-					      &s->declared_at))
-		{
-		  if (list == OMP_LIST_LINK)
-		    gfc_add_omp_declare_target_link (&s->attr, s->name,
-						     &s->declared_at);
-		}
-	      if (s->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
-		  && s->attr.omp_device_type != c->device_type)
-		gfc_error_now ("List item %qs at %L set in previous OMP DECLARE"
-			       " TARGET directive to a different DEVICE_TYPE",
-			       s->name, &n->where);
+	      if (list == OMP_LIST_TO || list == OMP_LIST_ENTER)
+		gfc_add_omp_declare_target (&s->attr, s->name, &n->where);
+	      if (list == OMP_LIST_LINK)
+		gfc_add_omp_declare_target_link (&s->attr, s->name, &n->where);
+	      if (list == OMP_LIST_LOCAL)
+		gfc_add_omp_declare_target_local (&s->attr, s->name, &n->where);
 	      s->attr.omp_device_type = c->device_type;
-
-	      if (c->indirect
-		  && s->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
-		  && s->attr.omp_device_type != OMP_DEVICE_TYPE_ANY)
-		gfc_error_now ("DEVICE_TYPE must be ANY when used with "
-			       "INDIRECT at %L", &n->where);
 	      s->attr.omp_declare_target_indirect = c->indirect;
 	    }
 	}
   if ((c->device_type || c->indirect)
       && !c->lists[OMP_LIST_ENTER]
       && !c->lists[OMP_LIST_TO]
-      && !c->lists[OMP_LIST_LINK])
+      && !c->lists[OMP_LIST_LINK]
+      && !c->lists[OMP_LIST_LOCAL])
     gfc_warning_now (OPT_Wopenmp,
 		     "OMP DECLARE TARGET directive at %L with only "
 		     "DEVICE_TYPE or INDIRECT clauses is ignored",
@@ -7108,32 +7191,44 @@ gfc_match_omp_metadirective (void)
   return match_omp_metadirective (false);
 }
 
-match
-gfc_match_omp_threadprivate (void)
+/* Match 'omp threadprivate' or 'omp groupprivate'.  */
+static match
+gfc_match_omp_thread_group_private (bool is_groupprivate)
 {
   locus old_loc;
   char n[GFC_MAX_SYMBOL_LEN+1];
   gfc_symbol *sym;
   match m;
   gfc_symtree *st;
+  struct sym_loc_t { gfc_symbol *sym; gfc_common_head *com; locus loc; };
+  auto_vec<sym_loc_t> syms;
 
   old_loc = gfc_current_locus;
 
-  m = gfc_match (" (");
+  m = gfc_match (" ( ");
   if (m != MATCH_YES)
     return m;
 
   for (;;)
     {
+      locus sym_loc = gfc_current_locus;
       m = gfc_match_symbol (&sym, 0);
       switch (m)
 	{
 	case MATCH_YES:
 	  if (sym->attr.in_common)
-	    gfc_error_now ("Threadprivate variable at %C is an element of "
-			   "a COMMON block");
-	  else if (!gfc_add_threadprivate (&sym->attr, sym->name, &sym->declared_at))
+	    gfc_error_now ("%qs variable at %L is an element of a COMMON block",
+			   is_groupprivate ? "groupprivate" : "threadprivate",
+			   &sym_loc);
+	  else if (!is_groupprivate
+		   && !gfc_add_threadprivate (&sym->attr, sym->name, &sym_loc))
 	    goto cleanup;
+	  else if (is_groupprivate)
+	    {
+	      if (!gfc_add_omp_groupprivate (&sym->attr, sym->name, &sym_loc))
+		goto cleanup;
+	      syms.safe_push ({sym, nullptr, sym_loc});
+	    }
 	  goto next_item;
 	case MATCH_NO:
 	  break;
@@ -7150,12 +7245,20 @@ gfc_match_omp_threadprivate (void)
       st = gfc_find_symtree (gfc_current_ns->common_root, n);
       if (st == NULL)
 	{
-	  gfc_error ("COMMON block /%s/ not found at %C", n);
+	  gfc_error ("COMMON block /%s/ not found at %L", n, &sym_loc);
 	  goto cleanup;
 	}
-      st->n.common->threadprivate = 1;
+      syms.safe_push ({nullptr, st->n.common, sym_loc});
+      if (is_groupprivate)
+	st->n.common->omp_groupprivate = 1;
+      else
+	st->n.common->threadprivate = 1;
       for (sym = st->n.common->head; sym; sym = sym->common_next)
-	if (!gfc_add_threadprivate (&sym->attr, sym->name, &sym->declared_at))
+	if (!is_groupprivate
+	    && !gfc_add_threadprivate (&sym->attr, sym->name, &sym_loc))
+	  goto cleanup;
+	else if (is_groupprivate
+		 && !gfc_add_omp_groupprivate (&sym->attr, sym->name, &sym_loc))
 	  goto cleanup;
 
     next_item:
@@ -7165,16 +7268,89 @@ gfc_match_omp_threadprivate (void)
 	goto syntax;
     }
 
+  if (is_groupprivate)
+    {
+      gfc_omp_clauses *c;
+      m = gfc_match_omp_clauses (&c, omp_mask (OMP_CLAUSE_DEVICE_TYPE));
+      if (m == MATCH_ERROR)
+	return MATCH_ERROR;
+
+      if (c->device_type == OMP_DEVICE_TYPE_UNSET)
+	c->device_type = OMP_DEVICE_TYPE_ANY;
+
+      for (size_t i = 0; i < syms.length (); i++)
+	if (syms[i].sym)
+	  {
+	    sym_loc_t &n = syms[i];
+	    if (n.sym->attr.in_common)
+	      gfc_error_now ("Variable %qs at %L is an element of a COMMON "
+			     "block", n.sym->name, &n.loc);
+	    else if (n.sym->attr.omp_declare_target
+		     || n.sym->attr.omp_declare_target_link)
+	      gfc_error_now ("List item %qs at %L implies OMP DECLARE TARGET "
+			     "with the LOCAL clause, but it has been specified"
+			     " with a different clause before",
+			     n.sym->name, &n.loc);
+	    if (n.sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
+		&& n.sym->attr.omp_device_type != c->device_type)
+	      {
+              const char *dt = "any";
+	      if (n.sym->attr.omp_device_type == OMP_DEVICE_TYPE_HOST)
+		dt = "host";
+	      else if (n.sym->attr.omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+		dt = "nohost";
+	      gfc_error_now ("List item %qs at %L set in previous OMP DECLARE "
+			     "TARGET directive to the different DEVICE_TYPE %qs",
+			     n.sym->name, &n.loc, dt);
+	      }
+	    gfc_add_omp_declare_target_local (&n.sym->attr, n.sym->name,
+					      &n.loc);
+	    n.sym->attr.omp_device_type = c->device_type;
+	  }
+	else  /* Common block.  */
+	  {
+	    sym_loc_t &n = syms[i];
+	    if (n.com->omp_declare_target
+		|| n.com->omp_declare_target_link)
+	      gfc_error_now ("List item %</%s/%> at %L implies OMP DECLARE "
+			     "TARGET with the LOCAL clause, but it has been "
+			     "specified with a different clause before",
+			     n.com->name, &n.loc);
+	    if (n.com->omp_device_type != OMP_DEVICE_TYPE_UNSET
+		&& n.com->omp_device_type != c->device_type)
+	      {
+		const char *dt = "any";
+		if (n.com->omp_device_type == OMP_DEVICE_TYPE_HOST)
+		  dt = "host";
+		else if (n.com->omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+		  dt = "nohost";
+		gfc_error_now ("List item %qs at %L set in previous OMP DECLARE"
+			       " TARGET directive to the different DEVICE_TYPE "
+			       "%qs", n.com->name, &n.loc, dt);
+	      }
+	    n.com->omp_declare_target_local = 1;
+	    n.com->omp_device_type = c->device_type;
+	    for (gfc_symbol *s = n.com->head; s; s = s->common_next)
+	      {
+		gfc_add_omp_declare_target_local (&s->attr, s->name, &n.loc);
+		s->attr.omp_device_type = c->device_type;
+	      }
+	  }
+      free (c);
+    }
+
   if (gfc_match_omp_eos () != MATCH_YES)
     {
-      gfc_error ("Unexpected junk after OMP THREADPRIVATE at %C");
+      gfc_error ("Unexpected junk after OMP %s at %C",
+		 is_groupprivate ? "GROUPPRIVATE" : "THREADPRIVATE");
       goto cleanup;
     }
 
   return MATCH_YES;
 
 syntax:
-  gfc_error ("Syntax error in !$OMP THREADPRIVATE list at %C");
+  gfc_error ("Syntax error in !$OMP %s list at %C",
+	     is_groupprivate ? "GROUPPRIVATE" : "THREADPRIVATE");
 
 cleanup:
   gfc_current_locus = old_loc;
@@ -7182,6 +7358,20 @@ cleanup:
 }
 
 
+match
+gfc_match_omp_groupprivate (void)
+{
+  return gfc_match_omp_thread_group_private (true);
+}
+
+
+match
+gfc_match_omp_threadprivate (void)
+{
+  return gfc_match_omp_thread_group_private (false);
+}
+
+
 match
 gfc_match_omp_parallel (void)
 {
@@ -8554,7 +8744,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 	"TO", "FROM", "INCLUSIVE", "EXCLUSIVE",
 	"REDUCTION", "REDUCTION" /*inscan*/, "REDUCTION" /*task*/,
 	"IN_REDUCTION", "TASK_REDUCTION",
-	"DEVICE_RESIDENT", "LINK", "USE_DEVICE",
+	"DEVICE_RESIDENT", "LINK", "LOCAL", "USE_DEVICE",
 	"CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR",
 	"NONTEMPORAL", "ALLOCATE", "HAS_DEVICE_ADDR", "ENTER",
 	"USES_ALLOCATORS", "INIT", "USE", "DESTROY", "INTEROP", "ADJUST_ARGS" };
@@ -8761,6 +8951,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
     }
   if (omp_clauses->num_threads)
     resolve_positive_int_expr (omp_clauses->num_threads, "NUM_THREADS");
+  if (omp_clauses->dyn_groupprivate)
+    resolve_positive_int_expr (omp_clauses->dyn_groupprivate,
+			       "DYN_GROUPPRIVATE");
   if (omp_clauses->chunk_size)
     {
       gfc_expr *expr = omp_clauses->chunk_size;
diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc
index e4d65200f3a..3fd45b9518e 100644
--- a/gcc/fortran/parse.cc
+++ b/gcc/fortran/parse.cc
@@ -1195,6 +1195,9 @@ decode_omp_directive (void)
     case 'f':
       matcho ("flush", gfc_match_omp_flush, ST_OMP_FLUSH);
       break;
+    case 'g':
+      matchdo ("groupprivate", gfc_match_omp_groupprivate, ST_OMP_GROUPPRIVATE);
+      break;
     case 'i':
       matcho ("interop", gfc_match_omp_interop, ST_OMP_INTEROP);
       break;
@@ -1990,7 +1993,8 @@ next_statement (void)
 #define case_omp_decl case ST_OMP_THREADPRIVATE: case ST_OMP_DECLARE_SIMD: \
   case ST_OMP_DECLARE_TARGET: case ST_OMP_DECLARE_REDUCTION: \
   case ST_OMP_DECLARE_VARIANT: case ST_OMP_ALLOCATE: case ST_OMP_ASSUMES: \
-  case ST_OMP_REQUIRES: case ST_OACC_ROUTINE: case ST_OACC_DECLARE
+  case ST_OMP_REQUIRES: case ST_OMP_GROUPPRIVATE: \
+  case ST_OACC_ROUTINE: case ST_OACC_DECLARE
 
 /* OpenMP statements that are followed by a structured block.  */
 
@@ -2909,6 +2913,9 @@ gfc_ascii_statement (gfc_statement st, bool strip_sentinel)
     case ST_OMP_FLUSH:
       p = "!$OMP FLUSH";
       break;
+    case ST_OMP_GROUPPRIVATE:
+      p = "!$OMP GROUPPRIVATE";
+      break;
     case ST_OMP_INTEROP:
       p = "!$OMP INTEROP";
       break;
@@ -4437,6 +4444,7 @@ loop:
 	case ST_EQUIVALENCE:
 	case ST_IMPLICIT:
 	case ST_IMPLICIT_NONE:
+	case ST_OMP_GROUPPRIVATE:
 	case ST_OMP_THREADPRIVATE:
 	case ST_PARAMETER:
 	case ST_STRUCTURE_DECL:
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index e4e7751dbf0..9f3ce1d2ad6 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -18714,17 +18714,30 @@ skip_interfaces:
     }
 
   /* Check threadprivate restrictions.  */
-  if (sym->attr.threadprivate
+  if ((sym->attr.threadprivate || sym->attr.omp_groupprivate)
       && !(sym->attr.save || sym->attr.data || sym->attr.in_common)
       && !(sym->ns->save_all && !sym->attr.automatic)
       && sym->module == NULL
       && (sym->ns->proc_name == NULL
 	  || (sym->ns->proc_name->attr.flavor != FL_MODULE
 	      && !sym->ns->proc_name->attr.is_main_program)))
-    gfc_error ("Threadprivate at %L isn't SAVEd", &sym->declared_at);
+    {
+      if (sym->attr.threadprivate)
+	gfc_error ("Threadprivate at %L isn't SAVEd", &sym->declared_at);
+      else
+	gfc_error ("OpenMP groupprivate variable %qs at %L must have the SAVE "
+		   "attribute", sym->name, &sym->declared_at);
+    }
+
+  if (sym->attr.omp_groupprivate && sym->value)
+    gfc_error ("!$OMP GROUPPRIVATE variable %qs at %L must not have an "
+	       "initializer", sym->name, &sym->declared_at);
 
   /* Check omp declare target restrictions.  */
-  if (sym->attr.omp_declare_target
+  if ((sym->attr.omp_declare_target
+       || sym->attr.omp_declare_target_link
+       || sym->attr.omp_declare_target_local)
+      && !sym->attr.omp_groupprivate  /* already warned.  */
       && sym->attr.flavor == FL_VARIABLE
       && !sym->attr.save
       && !(sym->ns->save_all && !sym->attr.automatic)
diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc
index becaaf39450..62925c028e6 100644
--- a/gcc/fortran/symbol.cc
+++ b/gcc/fortran/symbol.cc
@@ -458,8 +458,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
     *contiguous = "CONTIGUOUS", *generic = "GENERIC", *automatic = "AUTOMATIC",
     *pdt_len = "LEN", *pdt_kind = "KIND";
   static const char *threadprivate = "THREADPRIVATE";
+  static const char *omp_groupprivate = "OpenMP GROUPPRIVATE";
   static const char *omp_declare_target = "OMP DECLARE TARGET";
   static const char *omp_declare_target_link = "OMP DECLARE TARGET LINK";
+  static const char *omp_declare_target_local = "OMP DECLARE TARGET LOCAL";
   static const char *oacc_declare_copyin = "OACC DECLARE COPYIN";
   static const char *oacc_declare_create = "OACC DECLARE CREATE";
   static const char *oacc_declare_deviceptr = "OACC DECLARE DEVICEPTR";
@@ -553,8 +555,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
   conf (dummy, entry);
   conf (dummy, intrinsic);
   conf (dummy, threadprivate);
+  conf (dummy, omp_groupprivate);
   conf (dummy, omp_declare_target);
   conf (dummy, omp_declare_target_link);
+  conf (dummy, omp_declare_target_local);
   conf (pointer, target);
   conf (pointer, intrinsic);
   conf (pointer, elemental);
@@ -604,8 +608,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
   conf (in_equivalence, entry);
   conf (in_equivalence, allocatable);
   conf (in_equivalence, threadprivate);
+  conf (in_equivalence, omp_groupprivate);
   conf (in_equivalence, omp_declare_target);
   conf (in_equivalence, omp_declare_target_link);
+  conf (in_equivalence, omp_declare_target_local);
   conf (in_equivalence, oacc_declare_create);
   conf (in_equivalence, oacc_declare_copyin);
   conf (in_equivalence, oacc_declare_deviceptr);
@@ -616,6 +622,7 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
   conf (entry, result);
   conf (generic, result);
   conf (generic, omp_declare_target);
+  conf (generic, omp_declare_target_local);
   conf (generic, omp_declare_target_link);
 
   conf (function, subroutine);
@@ -661,8 +668,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
   conf (cray_pointee, in_common);
   conf (cray_pointee, in_equivalence);
   conf (cray_pointee, threadprivate);
+  conf (cray_pointee, omp_groupprivate);
   conf (cray_pointee, omp_declare_target);
   conf (cray_pointee, omp_declare_target_link);
+  conf (cray_pointee, omp_declare_target_local);
   conf (cray_pointee, oacc_declare_create);
   conf (cray_pointee, oacc_declare_copyin);
   conf (cray_pointee, oacc_declare_deviceptr);
@@ -720,9 +729,11 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
 
   conf (proc_pointer, abstract)
   conf (proc_pointer, omp_declare_target)
+  conf (proc_pointer, omp_declare_target_local)
   conf (proc_pointer, omp_declare_target_link)
 
   conf (entry, omp_declare_target)
+  conf (entry, omp_declare_target_local)
   conf (entry, omp_declare_target_link)
   conf (entry, oacc_declare_create)
   conf (entry, oacc_declare_copyin)
@@ -782,8 +793,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
       conf2 (function);
       conf2 (subroutine);
       conf2 (threadprivate);
+      conf2 (omp_groupprivate);
       conf2 (omp_declare_target);
       conf2 (omp_declare_target_link);
+      conf2 (omp_declare_target_local);
       conf2 (oacc_declare_create);
       conf2 (oacc_declare_copyin);
       conf2 (oacc_declare_deviceptr);
@@ -828,7 +841,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
 	  conf2 (dimension);
 	  conf2 (function);
 	  if (!attr->proc_pointer)
-	    conf2 (threadprivate);
+	    {
+	      conf2 (threadprivate);
+	      conf2 (omp_groupprivate);
+	    }
 	}
 
       /* Procedure pointers in COMMON blocks are allowed in F03,
@@ -836,6 +852,7 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
       if (!attr->proc_pointer || (gfc_option.allow_std & GFC_STD_F2008))
 	conf2 (in_common);
 
+      conf2 (omp_declare_target_local);
       conf2 (omp_declare_target_link);
 
       switch (attr->proc)
@@ -852,6 +869,7 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
 	case PROC_DUMMY:
 	  conf2 (result);
 	  conf2 (threadprivate);
+	  conf2 (omp_groupprivate);
 	  break;
 
 	default:
@@ -872,8 +890,10 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
       conf2 (function);
       conf2 (subroutine);
       conf2 (threadprivate);
+      conf2 (omp_groupprivate);
       conf2 (result);
       conf2 (omp_declare_target);
+      conf2 (omp_declare_target_local);
       conf2 (omp_declare_target_link);
       conf2 (oacc_declare_create);
       conf2 (oacc_declare_copyin);
@@ -905,6 +925,7 @@ gfc_check_conflict (symbol_attribute *attr, const char *name, locus *where)
       conf2 (volatile_);
       conf2 (asynchronous);
       conf2 (threadprivate);
+      conf2 (omp_groupprivate);
       conf2 (value);
       conf2 (codimension);
       conf2 (result);
@@ -1406,6 +1427,25 @@ gfc_add_asynchronous (symbol_attribute *attr, const char *name, locus *where)
 }
 
 
+bool
+gfc_add_omp_groupprivate (symbol_attribute *attr, const char *name,
+			  locus *where)
+{
+
+  if (check_used (attr, name, where))
+    return false;
+
+  if (attr->omp_groupprivate)
+    {
+      duplicate_attr ("OpenMP GROUPPRIVATE", where);
+      return false;
+    }
+
+  attr->omp_groupprivate = true;
+  return gfc_check_conflict (attr, name, where);
+}
+
+
 bool
 gfc_add_threadprivate (symbol_attribute *attr, const char *name, locus *where)
 {
@@ -1456,6 +1496,22 @@ gfc_add_omp_declare_target_link (symbol_attribute *attr, const char *name,
 }
 
 
+bool
+gfc_add_omp_declare_target_local (symbol_attribute *attr, const char *name,
+				  locus *where)
+{
+
+  if (check_used (attr, name, where))
+    return false;
+
+  if (attr->omp_declare_target_local)
+    return true;
+
+  attr->omp_declare_target_local = 1;
+  return gfc_check_conflict (attr, name, where);
+}
+
+
 bool
 gfc_add_oacc_declare_create (symbol_attribute *attr, const char *name,
 			     locus *where)
@@ -2110,6 +2166,9 @@ gfc_copy_attr (symbol_attribute *dest, symbol_attribute *src, locus *where)
     goto fail;
   if (src->asynchronous && !gfc_add_asynchronous (dest, NULL, where))
     goto fail;
+  if (src->omp_groupprivate
+      && !gfc_add_omp_groupprivate (dest, NULL, where))
+    goto fail;
   if (src->threadprivate
       && !gfc_add_threadprivate (dest, NULL, where))
     goto fail;
@@ -2119,6 +2178,9 @@ gfc_copy_attr (symbol_attribute *dest, symbol_attribute *src, locus *where)
   if (src->omp_declare_target_link
       && !gfc_add_omp_declare_target_link (dest, NULL, where))
     goto fail;
+  if (src->omp_declare_target_local
+      && !gfc_add_omp_declare_target_local (dest, NULL, where))
+    goto fail;
   if (src->oacc_declare_create
       && !gfc_add_oacc_declare_create (dest, NULL, where))
     goto fail;
diff --git a/gcc/fortran/trans-common.cc b/gcc/fortran/trans-common.cc
index 135d3047a15..6439a1530c6 100644
--- a/gcc/fortran/trans-common.cc
+++ b/gcc/fortran/trans-common.cc
@@ -488,6 +488,27 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
 	    }
 	  omp_clauses = c;
 	}
+      /* Also check trans-decl.cc when updating/removing the following;
+	 also update f95.c's gfc_gnu_attributes.
+	 For the warning, see also OpenMP spec issue 4663.  */
+      if (com->omp_groupprivate && com->threadprivate)
+	{
+	  /* Unset this flag; implicit 'declare target local(...)' remains.  */
+	  com->omp_groupprivate = 0;
+	  gfc_warning (OPT_Wopenmp,
+		       "Ignoring the %<groupprivate%> attribute for "
+		       "%<threadprivate%> common block %</%s/%> declared at %L",
+		       com->name, &com->where);
+	}
+      if (com->omp_groupprivate)
+	gfc_error ("Sorry, OMP GROUPPRIVATE not implemented, used by common "
+		   "block %</%s/%> declared at %L", com->name, &com->where);
+      else if (com->omp_declare_target_local)
+	/* Use 'else if' as groupprivate implies 'local'.  */
+	gfc_error ("Sorry, OMP DECLARE TARGET with LOCAL clause not implemented"
+		   ", used by common block %</%s/%> declared at %L",
+		   com->name, &com->where);
+
       if (com->omp_declare_target_link)
 	DECL_ATTRIBUTES (decl)
 	  = tree_cons (get_identifier ("omp declare target link"),
@@ -497,10 +518,12 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
 	  = tree_cons (get_identifier ("omp declare target"),
 		       omp_clauses, DECL_ATTRIBUTES (decl));
 
-      if (com->omp_declare_target_link || com->omp_declare_target)
+      if (com->omp_declare_target_link || com->omp_declare_target
+	  /* FIXME: || com->omp_declare_target_local */)
 	{
-	  /* Add to offload_vars; get_create does so for omp_declare_target,
-	     omp_declare_target_link requires manual work.  */
+	  /* Add to offload_vars; get_create does so for omp_declare_target
+	     and omp_declare_target_local, omp_declare_target_link requires
+	     manual work.  */
 	  gcc_assert (symtab_node::get (decl) == 0);
 	  symtab_node *node = symtab_node::get_create (decl);
 	  if (node != NULL && com->omp_declare_target_link)
@@ -1045,8 +1068,10 @@ accumulate_equivalence_attributes (symbol_attribute *dummy_symbol, gfc_equiv *e)
   dummy_symbol->generic |= attr.generic;
   dummy_symbol->automatic |= attr.automatic;
   dummy_symbol->threadprivate |= attr.threadprivate;
+  dummy_symbol->omp_groupprivate |= attr.omp_groupprivate;
   dummy_symbol->omp_declare_target |= attr.omp_declare_target;
   dummy_symbol->omp_declare_target_link |= attr.omp_declare_target_link;
+  dummy_symbol->omp_declare_target_local |= attr.omp_declare_target_local;
   dummy_symbol->oacc_declare_copyin |= attr.oacc_declare_copyin;
   dummy_symbol->oacc_declare_create |= attr.oacc_declare_create;
   dummy_symbol->oacc_declare_deviceptr |= attr.oacc_declare_deviceptr;
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 419de2c63cf..2164b37e4cb 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -1560,7 +1560,11 @@ add_attributes_to_decl (tree *decl_p, const gfc_symbol *sym)
       clauses = c;
     }
 
-  if (sym_attr.omp_device_type != OMP_DEVICE_TYPE_UNSET)
+  /* FIXME: 'declare_target_link' permits both any and host, but
+     will fail if one sets OMP_CLAUSE_DEVICE_TYPE_KIND.  */
+  if (sym_attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
+      && !sym_attr.omp_declare_target_link
+      && !sym_attr.omp_declare_target_indirect /* implies 'any' */)
     {
       tree c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE_DEVICE_TYPE);
       switch (sym_attr.omp_device_type)
@@ -1581,6 +1585,26 @@ add_attributes_to_decl (tree *decl_p, const gfc_symbol *sym)
       clauses = c;
     }
 
+  /* Also check trans-common.cc when updating/removing the following;
+     also update f95.c's gfc_gnu_attributes.
+     For the warning, see also OpenMP spec issue 4663.  */
+  if (sym_attr.omp_groupprivate && sym_attr.threadprivate)
+    {
+      /* Unset this flag; implicit 'declare target local(...)' remains.  */
+      sym_attr.omp_groupprivate = 0;
+      gfc_warning (OPT_Wopenmp,
+		   "Ignoring the %<groupprivate%> attribute for "
+		   "%<threadprivate%> variable %qs declared at %L",
+		   sym->name, &sym->declared_at);
+    }
+  if (sym_attr.omp_groupprivate)
+    gfc_error ("Sorry, OMP GROUPPRIVATE not implemented, "
+	       "used by %qs declared at %L", sym->name, &sym->declared_at);
+  else if (sym_attr.omp_declare_target_local)
+    /* Use 'else if' as groupprivate implies 'local'.  */
+    gfc_error ("Sorry, OMP DECLARE TARGET with LOCAL clause not implemented, "
+	       "used by %qs declared at %L", sym->name, &sym->declared_at);
+
   bool has_declare = true;
   if (sym_attr.omp_declare_target_link
       || sym_attr.oacc_declare_link)
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 69a70d7138c..c0a8ed927d9 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -4180,7 +4180,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		  tree type = TREE_TYPE (decl);
 		  if (n->sym->ts.type == BT_CHARACTER
 		      && n->sym->ts.deferred
-		      && n->sym->attr.omp_declare_target
+		      && (n->sym->attr.omp_declare_target
+			  || n->sym->attr.omp_declare_target_link
+			  || n->sym->attr.omp_declare_target_local)
 		      && (always_modifier || n->sym->attr.pointer)
 		      && op != EXEC_OMP_TARGET_EXIT_DATA
 		      && n->u.map.op != OMP_MAP_DELETE
@@ -5263,6 +5265,25 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
+  if (clauses->dyn_groupprivate)
+    {
+      sorry_at (gfc_get_location (&where), "%<dyn_groupprivate%> clause");
+#if 0  /* FIXME: Handle it, including 'fallback(abort/default_mem/null)'  */
+      tree dyn_groupprivate;
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr (&se, clauses->dyn_groupprivate);
+      gfc_add_block_to_block (block, &se.pre);
+      dyn_groupprivate = gfc_evaluate_now (se.expr, block);
+      gfc_add_block_to_block (block, &se.post);
+
+      c = build_omp_clause (gfc_get_location (&where),
+			    OMP_CLAUSE_DYN_GROUPPRIVATE);
+      OMP_CLAUSE_NUM_THREADS_EXPR (c) = num_threads;
+      omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+#endif
+    }
+
   chunk_size = NULL_TREE;
   if (clauses->chunk_size)
     {
diff --git a/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90 b/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90
index 476d7b9e771..06ac60424e9 100644
--- a/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/crayptr2.f90
@@ -3,7 +3,7 @@
 ! { dg-require-effective-target tls }
 
 module crayptr2
-  integer :: e		! { dg-error "CRAY POINTEE attribute conflicts with THREADPRIVATE" }
+  integer :: e
   pointer (ip5, e)
 
 ! The standard is not very clear about this.
@@ -12,6 +12,6 @@ module crayptr2
 ! be if they are module variables.  But threadprivate pointees don't
 ! make any sense anyway.
 
-!$omp threadprivate (e)
+!$omp threadprivate (e)  ! { dg-error "CRAY POINTEE attribute conflicts with THREADPRIVATE" }
 
 end module crayptr2
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90
index 93075fb147e..b4f1e52f725 100644
--- a/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90
@@ -24,7 +24,11 @@ module declare_target_2
   end interface
 end
 subroutine bar
+  !$omp declare target enter (q)	! { dg-error "isn.t SAVEd" }
+  !$omp declare target link (r)		! { dg-error "isn.t SAVEd" }
+  !$omp declare target local (s)	! { dg-error "isn.t SAVEd" }
   !$omp declare target link (baz)	! { dg-error "isn.t SAVEd" }
+  integer :: q, r, s
   call baz				! { dg-error "attribute conflicts" }
 end subroutine
 subroutine foo				! { dg-error "attribute conflicts" }
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-target-4.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-target-4.f90
index 55534d8fe99..296c0dbd869 100644
--- a/gcc/testsuite/gfortran.dg/gomp/declare-target-4.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-target-4.f90
@@ -42,15 +42,14 @@ module mymod
   !$omp declare target to(a) device_type(nohost)
   !$omp declare target to(b) device_type(host)
   !$omp declare target to(c) device_type(any)
- ! Fails in ME with "Error: wrong number of arguments specified for 'omp declare target link' attribute"
- ! !$omp declare target link(e) device_type(nohost)
- ! !$omp declare target link(f) device_type(host)
- ! !$omp declare target link(g) device_type(any)
+ ! !$omp declare target link(e) device_type(nohost) ! -> invalid: only 'any' is permitted
+ ! !$omp declare target link(f) device_type(host) ! -> invalid: only 'any' is permitted
+ !$omp declare target link(g) device_type(any)
 
   !$omp declare target to(/block1/) device_type(nohost)
   !$omp declare target to(/block2/) device_type(host)
   !$omp declare target to(/block3/) device_type(any)
-  !$omp declare target link(/block4/) device_type(nohost)
+  ! !$omp declare target link(/block4/) device_type(nohost) ! -> invalid, link requires host or any
   !$omp declare target link(/block5/) device_type(host)
   !$omp declare target link(/block6/) device_type(any)
 contains
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-target-5.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-target-5.f90
index 76687d476d5..0dacb895229 100644
--- a/gcc/testsuite/gfortran.dg/gomp/declare-target-5.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-target-5.f90
@@ -4,9 +4,15 @@ end
 
 subroutine bar()
   !$omp declare target  to(bar) device_type(nohost)
-  !$omp declare target  to(bar) device_type(host)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
+  !$omp declare target  to(bar) device_type(host)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'nohost'" }
 end
 
+module invalid
+  implicit none
+  integer :: d
+  !$omp declare target  link(d) device_type(nohost)  ! { dg-error "set with NOHOST specified may not appear in a LINK clause" }
+end module
+
 module mymod_one
   implicit none
   integer :: a, b, c, d, e ,f
@@ -17,24 +23,21 @@ module mymod_one
   !$omp declare target  to(a) device_type(nohost)
   !$omp declare target  to(b) device_type(any)
   !$omp declare target  to(c) device_type(host)
-  !$omp declare target  link(d) device_type(nohost)
   !$omp declare target  link(e) device_type(any)
   !$omp declare target  link(f) device_type(host)
 
   !$omp declare target  to(c) device_type(host)
-  !$omp declare target  link(d) device_type(nohost)
 end module
 
 module mtest
   use mymod_one ! { dg-error "Cannot change attributes of USE-associated symbol" }
   implicit none
 
-  !$omp declare target  to(a) device_type(any)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
-  !$omp declare target  to(b) device_type(host)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
-  !$omp declare target  to(c) device_type(nohost)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
-  !$omp declare target  link(d) device_type(host)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
-  !$omp declare target  link(e) device_type(nohost)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
-  !$omp declare target  link(f) device_type(any)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
+  !$omp declare target  to(a) device_type(any)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'nohost'" }
+  !$omp declare target  to(b) device_type(host)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'any'" }
+  !$omp declare target  to(c) device_type(nohost)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'host'" }
+  !$omp declare target  link(e) device_type(host)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'any'" }
+  !$omp declare target  link(f) device_type(any)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'host'" }
 end module
 
 module mymod
@@ -47,17 +50,15 @@ module mymod
   !$omp declare target  to(a) device_type(nohost)
   !$omp declare target  to(b) device_type(any)
   !$omp declare target  to(c) device_type(host)
-  !$omp declare target  link(d) device_type(nohost)
+  !$omp declare target  link(d) device_type(nohost)  ! { dg-error "set with NOHOST specified may not appear in a LINK clause" }
   !$omp declare target  link(e) device_type(any)
   !$omp declare target  link(f) device_type(host)
 
   !$omp declare target  to(c) device_type(host)
-  !$omp declare target  link(d) device_type(nohost)
-
-  !$omp declare target  to(a) device_type(any)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
-  !$omp declare target  to(b) device_type(host)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
-  !$omp declare target  to(c) device_type(nohost)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
-  !$omp declare target  link(d) device_type(host)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
-  !$omp declare target  link(e) device_type(nohost)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
-  !$omp declare target  link(f) device_type(any)  ! { dg-error "previous OMP DECLARE TARGET directive to a different DEVICE_TYPE" }
+
+  !$omp declare target  to(a) device_type(any)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'nohost'" }
+  !$omp declare target  to(b) device_type(host)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'any'" }
+  !$omp declare target  to(c) device_type(nohost)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'host'" }
+  !$omp declare target  link(e) device_type(host)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'any'" }
+  !$omp declare target  link(f) device_type(any)  ! { dg-error "set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'host'" }
 end
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-target-6.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-target-6.f90
new file mode 100644
index 00000000000..21970e6fbb4
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-target-6.f90
@@ -0,0 +1,15 @@
+subroutine sub  ! { dg-error "SUBROUTINE attribute conflicts with OMP DECLARE TARGET LINK attribute in 'sub'" }
+  !$omp declare target link(sub)
+end subroutine sub
+
+subroutine sub2  ! { dg-error "SUBROUTINE attribute conflicts with OMP DECLARE TARGET LOCAL attribute in 'sub2'" }
+  !$omp declare target local(sub2)
+end subroutine sub2
+
+integer function func()  ! { dg-error "PROCEDURE attribute conflicts with OMP DECLARE TARGET LINK attribute in 'func'" }
+  !$omp declare target link(func)
+end
+
+integer function func2()  ! { dg-error "PROCEDURE attribute conflicts with OMP DECLARE TARGET LOCAL attribute in 'func2'" }
+  !$omp declare target local(func2)
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-target-indirect-2.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-target-indirect-2.f90
index f6b3ae17856..4345c69b74b 100644
--- a/gcc/testsuite/gfortran.dg/gomp/declare-target-indirect-2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-target-indirect-2.f90
@@ -11,7 +11,7 @@ contains
   subroutine sub2
     !$omp declare target indirect (.false.) to (sub2)
   end subroutine
-  ! { dg-final { scan-tree-dump "__attribute__\\\(\\\(omp declare target\\\)\\\)\\\n.*\\\nvoid sub2" "gimple" } }
+  ! { dg-final { scan-tree-dump "__attribute__\\\(\\\(omp declare target \\(device_type\\(any\\)\\)\\\)\\\)\\\n.*\\\nvoid sub2" "gimple" } }
 
   subroutine sub3
     !$omp declare target indirect (.true.) to (sub3)
@@ -21,5 +21,5 @@ contains
   subroutine sub4
     !$omp declare target indirect (.false.) enter (sub4)
   end subroutine
-  ! { dg-final { scan-tree-dump "__attribute__\\\(\\\(omp declare target\\\)\\\)\\\n.*\\\nvoid sub4" "gimple" } }
+  ! { dg-final { scan-tree-dump "__attribute__\\\(\\\(omp declare target \\(device_type\\(any\\)\\)\\\)\\\)\\\n.*\\\nvoid sub4" "gimple" } }
 end module
diff --git a/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-1.f90 b/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-1.f90
new file mode 100644
index 00000000000..2e09febe18c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-1.f90
@@ -0,0 +1,20 @@
+implicit none
+
+integer :: N
+N = 1024
+
+!$omp target dyn_groupprivate(1024)  ! { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
+!$omp end target
+
+!$omp target dyn_groupprivate (1024 * N)  ! { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
+!$omp end target
+
+!$omp target dyn_groupprivate ( fallback ( abort ) : N)  ! { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
+!$omp end target
+
+!$omp target dyn_groupprivate ( fallback ( null ) : N)  ! { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
+!$omp end target
+
+!$omp target dyn_groupprivate ( fallback ( default_mem ) : N)  ! { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
+!$omp end target
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-2.f90 b/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-2.f90
new file mode 100644
index 00000000000..0a5a644b9f4
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-2.f90
@@ -0,0 +1,23 @@
+implicit none
+
+integer, parameter :: M = 1024
+integer :: N, A(1)
+
+N = 1024
+
+!$omp target dyn_groupprivate(-123)  ! { dg-warning "INTEGER expression of DYN_GROUPPRIVATE clause at .1. must be positive \\\[-Wopenmp\\\]" }
+block; end block
+
+!$omp target dyn_groupprivate (0 * M)  ! { dg-warning "INTEGER expression of DYN_GROUPPRIVATE clause at .1. must be positive \\\[-Wopenmp\\\]" }
+block; end block
+
+!$omp target dyn_groupprivate ( fallback ( other ) : N)  ! { dg-error "Failed to match clause" }
+block; end block
+
+!$omp target dyn_groupprivate ( A )  ! { dg-error "DYN_GROUPPRIVATE clause at .1. requires a scalar INTEGER expression" }
+block; end block
+
+!$omp target dyn_groupprivate ( 1024. )  ! { dg-error "DYN_GROUPPRIVATE clause at .1. requires a scalar INTEGER expression" }
+block; end block
+
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/groupprivate-1.f90 b/gcc/testsuite/gfortran.dg/gomp/groupprivate-1.f90
new file mode 100644
index 00000000000..f776c0875dd
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/groupprivate-1.f90
@@ -0,0 +1,23 @@
+module m
+ implicit none
+ integer :: ii
+ integer :: x, y(20), z, v, u, k  ! { dg-warning "Ignoring the 'groupprivate' attribute for 'threadprivate' variable 'k' declared at .1. \\\[-Wopenmp\\\]" }
+! { dg-error "Sorry, OMP GROUPPRIVATE not implemented, used by 'x' declared at .1." "" { target *-*-* } .-1 }
+! { dg-error "Sorry, OMP GROUPPRIVATE not implemented, used by 'y' declared at .1." "" { target *-*-* } .-2 }
+! { dg-error "Sorry, OMP GROUPPRIVATE not implemented, used by 'z' declared at .1." "" { target *-*-* } .-3 }
+! { dg-error "Sorry, OMP GROUPPRIVATE not implemented, used by 'v' declared at .1." "" { target *-*-* } .-4 }
+! { dg-error "Sorry, OMP GROUPPRIVATE not implemented, used by 'u' declared at .1." "" { target *-*-* } .-5 }
+!
+! Note:Error different as 'groupprivate' flag is overwritten by 'threadprivate', cf. warning above.
+! { dg-error "Sorry, OMP DECLARE TARGET with LOCAL clause not implemented, used by 'k' declared at .1." "" { target *-*-* } .-8 }
+ !$omp groupprivate(x, z) device_Type( any )
+ !$omp declare target local(x) device_type ( any )
+ !$omp declare target enter( ii) ,local(y), device_type ( host )
+ !$omp groupprivate(y) device_type( host)
+ !$omp groupprivate(v) device_type (nohost )
+ !$omp groupprivate(u)
+
+ ! See also (currently unresolved) OpenMP Specification Issue 4663.
+ !$omp groupprivate(k)
+ !$omp threadprivate(k)
+end module
diff --git a/gcc/testsuite/gfortran.dg/gomp/groupprivate-2.f90 b/gcc/testsuite/gfortran.dg/gomp/groupprivate-2.f90
new file mode 100644
index 00000000000..922d229bf89
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/groupprivate-2.f90
@@ -0,0 +1,37 @@
+module m
+ implicit none
+ integer :: ii
+ integer :: x, y(20), z, v, q, r,o, b2,c
+
+ !$omp groupprivate(x, z, o) device_Type( any )
+ !$omp declare target enter(x) device_type ( any )  ! { dg-error "List item 'x' at .1. not appear in the 'enter' clause as it was previously specified in a GROUPPRIVATE directive" }
+ !$omp declare target to(z) device_type ( any )  ! { dg-error "List item 'z' at .1. not appear in the 'to' clause as it was previously specified in a GROUPPRIVATE directive" }
+ !$omp declare target link(o) device_type ( any )  ! { dg-error "List item 'o' at .1. not appear in the 'link' clause as it was previously specified in a GROUPPRIVATE directive" }
+ !$omp declare target enter( ii) ,local(y,c), link(r), to(q) device_type ( host )
+ !$omp groupprivate(r,q) device_type(host)
+! { dg-error "List item 'q' at .1. implies OMP DECLARE TARGET with the LOCAL clause, but it has been specified with a different clause before" "" { target *-*-* } .-1 }
+! { dg-error "List item 'r' at .1. implies OMP DECLARE TARGET with the LOCAL clause, but it has been specified with a different clause before" "" { target *-*-* } .-2 }
+ !$omp groupprivate(c) ! { dg-error "List item 'c' at .1. set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'host'" }
+ !$omp groupprivate(y) device_type( any)  ! { dg-error "List item 'y' at .1. set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'host'" }
+ !$omp groupprivate(v) device_type (nohost )
+ !$omp groupprivate(v)  ! { dg-error "Duplicate OpenMP GROUPPRIVATE attribute specified" }
+
+ !$omp declare target link(b2) device_type(nohost)  ! { dg-error "List item 'b2' at .1. set with NOHOST specified may not appear in a LINK clause" }
+end module
+
+subroutine sub()
+  implicit none
+  integer, save :: x0,x1,x2,x3,x4
+  !$omp groupprivate(x0)
+  !$omp groupprivate(x1)
+  !$omp groupprivate(x2) device_type ( any)
+  !$omp groupprivate(x3) device_type (host )
+  !$omp groupprivate(x4) device_type( nohost)
+
+  !$omp declare target(x0)  ! { dg-error "List item 'x0' at .1. not appear in the 'enter' clause as it was previously specified in a GROUPPRIVATE directive" }
+  !$omp declare target device_type(any) to(x1)  ! { dg-error "List item 'x1' at .1. not appear in the 'to' clause as it was previously specified in a GROUPPRIVATE directive" }
+  !$omp declare target device_type(any) enter(x2)  ! { dg-error "List item 'x2' at .1. not appear in the 'enter' clause as it was previously specified in a GROUPPRIVATE directive" }
+  !$omp declare target device_type(host) link(x3)  ! { dg-error "List item 'x3' at .1. not appear in the 'link' clause as it was previously specified in a GROUPPRIVATE directive" }
+  !$omp declare target device_type(host) local(x4) ! { dg-error "List item 'x4' at .1. set in previous OMP GROUPPRIVATE directive to the different DEVICE_TYPE 'nohost'" }
+
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/groupprivate-3.f90 b/gcc/testsuite/gfortran.dg/gomp/groupprivate-3.f90
new file mode 100644
index 00000000000..d7ccbe292d5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/groupprivate-3.f90
@@ -0,0 +1,16 @@
+module m
+implicit none
+integer :: y = 5 ! { dg-error "!.OMP GROUPPRIVATE variable 'y' at .1. must not have an initializer" }
+!$omp groupprivate(y)
+end
+
+subroutine sub
+  integer :: k  ! { dg-error "OpenMP groupprivate variable 'k' at .1. must have the SAVE attribute" }
+  !$omp groupprivate(k)
+end
+
+subroutine sub2
+  !$omp groupprivate(q)
+  integer, save :: q
+  !$omp groupprivate(q) ! { dg-error "Duplicate OpenMP GROUPPRIVATE attribute specified at .1." }
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/groupprivate-4.f90 b/gcc/testsuite/gfortran.dg/gomp/groupprivate-4.f90
new file mode 100644
index 00000000000..2a3a054483e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/groupprivate-4.f90
@@ -0,0 +1,25 @@
+module m
+ implicit none
+ integer :: ii
+ integer :: x, y(20), z, v, u, k
+
+ common /b_ii/ ii
+ common /b_x/ x  ! { dg-error "Sorry, OMP GROUPPRIVATE not implemented, used by common block '/b_x/' declared at .1." }
+ common /b_y/ y  ! { dg-error "Sorry, OMP GROUPPRIVATE not implemented, used by common block '/b_y/' declared at .1." }
+ common /b_z/ z  ! { dg-error "Sorry, OMP GROUPPRIVATE not implemented, used by common block '/b_z/' declared at .1." }
+ common /b_v/ v  ! { dg-error "Sorry, OMP GROUPPRIVATE not implemented, used by common block '/b_v/' declared at .1." }
+ common /b_u/ u  ! { dg-error "Sorry, OMP GROUPPRIVATE not implemented, used by common block '/b_u/' declared at .1." }
+ common /b_k/ k  ! { dg-warning "Ignoring the 'groupprivate' attribute for 'threadprivate' common block '/b_k/' declared at .1. \\\[-Wopenmp\\\]" }
+! { dg-error "Sorry, OMP DECLARE TARGET with LOCAL clause not implemented, used by common block '/b_k/' declared at .1." "" { target *-*-* } .-1 }
+
+ !$omp groupprivate(/b_x/, /b_z/) device_Type( any )
+ !$omp declare target local(/b_x/) device_type ( any )
+ !$omp declare target enter( /b_ii/) ,local(/b_y/), device_type ( host )
+ !$omp groupprivate(/b_y/) device_type( host)
+ !$omp groupprivate(/b_v/) device_type (nohost )
+ !$omp groupprivate(/b_u/)
+
+ ! See also (currently unresolved) OpenMP Specification Issue 4663.
+ !$omp groupprivate(/b_k/)
+ !$omp threadprivate(/b_k/)
+end module
diff --git a/gcc/testsuite/gfortran.dg/gomp/groupprivate-5.f90 b/gcc/testsuite/gfortran.dg/gomp/groupprivate-5.f90
new file mode 100644
index 00000000000..c9f89feb4aa
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/groupprivate-5.f90
@@ -0,0 +1,58 @@
+module m
+ implicit none
+ integer :: ii
+ integer :: x, y(20), z, v, q, r,o, b2,c
+
+ common /b_ii/ ii
+ common /b_x/ x
+ common /b_y/ y
+ common /b_z/ z
+ common /b_v/ v
+ common /b_q/ q
+ common /b_r/ r
+ common /b_o/ o
+ common /b_b2/ b2
+ common /b_c/ c
+
+ !$omp groupprivate(/b_x/, /b_z/, /b_o/) device_Type( any )
+ !$omp declare target enter(/b_x/) device_type ( any )  ! { dg-error "Common block '/b_x/' at .1. not appear in the 'enter' clause as it was previously specified in a GROUPPRIVATE directive" }
+ !$omp declare target to(/b_z/) device_type ( any )  ! { dg-error "Common block '/b_z/' at .1. not appear in the 'to' clause as it was previously specified in a GROUPPRIVATE directive" }
+ !$omp declare target link(/b_o/) device_type ( any )  ! { dg-error "Common block '/b_o/' at .1. not appear in the 'link' clause as it was previously specified in a GROUPPRIVATE directive" }
+ !$omp declare target enter( / b_ii / ) ,local(/b_y/ , /b_c/), link(/b_r/), to(/b_q/) device_type ( host )
+ !$omp groupprivate( /b_r/ ,/b_q/) device_type(host)
+! { dg-error "List item '/b_r/' at .1. implies OMP DECLARE TARGET with the LOCAL clause, but it has been specified with a different clause before" "" { target *-*-* } .-1 }
+! { dg-error "List item '/b_q/' at .1. implies OMP DECLARE TARGET with the LOCAL clause, but it has been specified with a different clause before" "" { target *-*-* } .-2 }
+ !$omp groupprivate(/b_c/)  ! { dg-error "List item 'b_c' at .1. set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'host'" }
+ !$omp groupprivate(/b_y/) device_type( any)  ! { dg-error "List item 'b_y' at .1. set in previous OMP DECLARE TARGET directive to the different DEVICE_TYPE 'host'" }
+ !$omp groupprivate(/b_v/) device_type (nohost )
+ !$omp groupprivate(/b_v/)  ! { dg-error "Duplicate OpenMP GROUPPRIVATE attribute specified at .1." }
+
+ !$omp declare target link(/b_b2/) device_type(nohost)  ! { dg-error "Common block '/b_b2/' at .1. set with NOHOST specified may not appear in a LINK clause" }
+end module
+
+subroutine sub()
+  implicit none
+  integer, save :: xx
+  integer :: x0,x1,x2,x3,x4
+
+  common /b_xx/ xx  ! { dg-error "COMMON attribute conflicts with SAVE attribute in 'xx' at .1." }
+  common /b_x0/ x0
+  common /b_x1/ x1
+  common /b_x2/ x2
+  common /b_x3/ x3
+  common /b_x4/ x4
+
+  !$omp groupprivate(/b_xx/)  ! { dg-error "COMMON attribute conflicts with SAVE attribute in 'xx' at .1." }
+  !$omp groupprivate(/b_x0/)
+  !$omp groupprivate(/b_x1/)
+  !$omp groupprivate(/b_x2/) device_type ( any)
+  !$omp groupprivate(/b_x3/) device_type (host )
+  !$omp groupprivate(/b_x4/) device_type( nohost)
+
+  !$omp declare target(/b_x0/)  ! { dg-error "Common block '/b_x0/' at .1. not appear in the 'enter' clause as it was previously specified in a GROUPPRIVATE directive" }
+  !$omp declare target device_type(any) to(/b_x1/)  ! { dg-error "Common block '/b_x1/' at .1. not appear in the 'to' clause as it was previously specified in a GROUPPRIVATE directive" }
+  !$omp declare target device_type(any) enter(/b_x2/)  ! { dg-error "Common block '/b_x2/' at .1. not appear in the 'enter' clause as it was previously specified in a GROUPPRIVATE directive" }
+  !$omp declare target device_type(host) link(/b_x3/)  ! { dg-error "Common block '/b_x3/' at .1. not appear in the 'link' clause as it was previously specified in a GROUPPRIVATE directive" }
+  !$omp declare target device_type(host) local(/b_x4/) ! { dg-error "Common block '/b_x4/' at .1. set in previous OMP GROUPPRIVATE directive to the different DEVICE_TYPE 'nohost'" }
+
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/groupprivate-6.f90 b/gcc/testsuite/gfortran.dg/gomp/groupprivate-6.f90
new file mode 100644
index 00000000000..6ae5b3dc59b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/groupprivate-6.f90
@@ -0,0 +1,34 @@
+module m
+implicit none
+integer :: y = 5 ! { dg-error "!.OMP GROUPPRIVATE variable 'y' at .1. must not have an initializer" }
+common /b_y/ y
+!$omp groupprivate(/b_y/)
+end
+
+subroutine sub
+  integer, save :: k
+  common /b_k/ k  ! { dg-error "COMMON attribute conflicts with SAVE attribute in 'k' at .1." }
+  !$omp groupprivate(/b_k/)  ! { dg-error "COMMON attribute conflicts with SAVE attribute in 'k' at .1." }
+end
+
+subroutine sub2
+  common /b_q/ q
+  !$omp groupprivate(/b_q/)
+  integer :: q
+  !$omp groupprivate(/b_q/) ! { dg-error "Duplicate OpenMP GROUPPRIVATE attribute specified at .1." }
+end
+
+subroutine dupl
+  integer :: a,b,c,d
+  integer :: u,v,w,x
+  common /b_a/ a
+  common /b_b/ b
+  common /b_c/ c
+  common /b_d/ d
+
+  !$omp groupprivate(/b_a/,u,/b_a/) ! { dg-error "Duplicate OpenMP GROUPPRIVATE attribute specified" }
+  !$omp groupprivate(v,/b_b/,v) ! { dg-error "Duplicate OpenMP GROUPPRIVATE attribute specified" }
+
+  !$omp threadprivate(/b_a/,u,/b_a/) ! { dg-error "Duplicate THREADPRIVATE attribute specified" }
+  !$omp threadprivate(v,/b_b/,v) ! { dg-error "Duplicate THREADPRIVATE attribute specified" }
+end

Reply via email to