The attached patch adds parser support for the 'dyn_groupprivate'
clause to C/C++. (The Fortran support was added before.) However,
for now, the clause is rejected with a 'sorry' in gimplify.cc.

[To do: Supporting it requires that the clause is forwarded to
libgomp and the memory allocation handled there, including two
routines to make it accessible in the target region.]

(Review) comments, remarks, suggestions before I push the patch?

Tobias
OpenMP: C/C++ parser support for dyn_groupprivate

Follow-up to the Fortran patch r16-5633-g26d41e245dbba3, which (besides
other changes) added parser support for the 'dyn_groupprivate' clause to
the target directive.
This commit adds now the parser support to C/C++ and moves the
not-yet-implemented 'sorry' to the early middle end.

gcc/c-family/ChangeLog:

	* c-omp.cc (c_omp_split_clauses): Handle
	OMP_CLAUSE_DYN_GROUPPRIVATE, sort target clauses
	alphabetically.
	* c-pragma.h (enum pragma_omp_clause): Add
	PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_omp_clause_dyn_groupprivate): New. 
	(OMP_TARGET_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE;
	sort clauses alphabetically.
	(c_parser_omp_clause_name, c_parser_omp_all_clauses):
	Handle 'dyn_groupprivate' clause.
	* c-typeck.cc (c_finish_omp_clauses): Likewise.

gcc/cp/ChangeLog:

	* pt.cc (tsubst_omp_clauses): Handle OMP_CLAUSE_DYN_GROUPPRIVATE.
	* semantics.cc (finish_omp_clauses): Likewise.
	* parser.cc (cp_parser_omp_clause_dyn_groupprivate): New.
	(cp_parser_omp_clause_name, cp_parser_omp_all_clauses):
	Handle 'dyn_groupprivate' clause.
	(OMP_TARGET_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE;
	sort clauses alphabetically.


gcc/fortran/ChangeLog:

	* openmp.cc (resolve_omp_clauses): Permit zero with
	DYN_GROUPPRIVATE clause.
	* trans-openmp.cc (fallback): Generate TREE code
	for DYN_GROUPPRIVATE and remove 'sorry'.

gcc/ChangeLog:

	* gimplify.cc (gimplify_scan_omp_clauses): Handle
	OMP_CLAUSE_DYN_GROUPPRIVATE by printing 'sorry, unimplemented'.
	* tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_DYN_GROUPPRIVATE.
	(enum omp_clause_fallback_kind): New.
	(struct tree_omp_clause): Add fallback_kind union member.
	* tree-nested.cc (convert_nonlocal_omp_clauses): Handle
	(convert_local_omp_clauses):
	* tree.cc (omp_clause_num_ops, omp_clause_code_name): Add
	OMP_CLAUSE_DYN_GROUPPRIVATE.
	* tree-pretty-print.cc (dump_omp_clause): Handle
	OMP_CLAUSE_DYN_GROUPPRIVATE.
	* tree.h (OMP_CLAUSE_DYN_GROUPPRIVATE_EXPR,
	OMP_CLAUSE_DYN_GROUPPRIVATE_KIND): New #define.

gcc/testsuite/ChangeLog:

	* gfortran.dg/gomp/dyn_groupprivate-1.f90: Add scan-dump test.
	* gfortran.dg/gomp/dyn_groupprivate-2.f90: Extend and update.
	* c-c++-common/gomp/dyn_groupprivate-1.c: New test.
	* c-c++-common/gomp/dyn_groupprivate-2.c: New test.

 gcc/c-family/c-omp.cc                              |   7 +-
 gcc/c-family/c-pragma.h                            |   1 +
 gcc/c/c-parser.cc                                  | 115 +++++++++++++++++++--
 gcc/c/c-typeck.cc                                  |   1 +
 gcc/cp/parser.cc                                   | 111 ++++++++++++++++++--
 gcc/cp/pt.cc                                       |   1 +
 gcc/cp/semantics.cc                                |  13 ++-
 gcc/fortran/openmp.cc                              |   4 +-
 gcc/fortran/trans-openmp.cc                        |  26 +++--
 gcc/gimplify.cc                                    |   5 +
 .../c-c++-common/gomp/dyn_groupprivate-1.c         |  28 +++++
 .../c-c++-common/gomp/dyn_groupprivate-2.c         |  72 +++++++++++++
 .../gfortran.dg/gomp/dyn_groupprivate-1.f90        |   9 ++
 .../gfortran.dg/gomp/dyn_groupprivate-2.f90        |  12 ++-
 gcc/tree-core.h                                    |  11 ++
 gcc/tree-nested.cc                                 |   2 +
 gcc/tree-pretty-print.cc                           |  21 ++++
 gcc/tree.cc                                        |   2 +
 gcc/tree.h                                         |   5 +
 19 files changed, 413 insertions(+), 33 deletions(-)

diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc
index c80d2de6deb..e183c400652 100644
--- a/gcc/c-family/c-omp.cc
+++ b/gcc/c-family/c-omp.cc
@@ -2176,11 +2176,12 @@ c_omp_split_clauses (location_t loc, enum tree_code code,
 	{
 	/* First the clauses that are unique to some constructs.  */
 	case OMP_CLAUSE_DEVICE:
-	case OMP_CLAUSE_MAP:
-	case OMP_CLAUSE_IS_DEVICE_PTR:
-	case OMP_CLAUSE_HAS_DEVICE_ADDR:
 	case OMP_CLAUSE_DEFAULTMAP:
 	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE_DYN_GROUPPRIVATE:
+	case OMP_CLAUSE_IS_DEVICE_PTR:
+	case OMP_CLAUSE_HAS_DEVICE_ADDR:
+	case OMP_CLAUSE_MAP:
 	  s = C_OMP_CLAUSE_SPLIT_TARGET;
 	  break;
 	case OMP_CLAUSE_DOACROSS:
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index 13df9ea490e..a61a2c7bec3 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -119,6 +119,7 @@ enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_DEVICE_TYPE,
   PRAGMA_OMP_CLAUSE_DIST_SCHEDULE,
   PRAGMA_OMP_CLAUSE_DOACROSS,
+  PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE,
   PRAGMA_OMP_CLAUSE_ENTER,
   PRAGMA_OMP_CLAUSE_FILTER,
   PRAGMA_OMP_CLAUSE_FINAL,
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index b4dc741c6fd..15bfd0dc3f4 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -16411,6 +16411,8 @@ c_parser_omp_clause_name (c_parser *parser)
 	    result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
 	  else if (!strcmp ("doacross", p))
 	    result = PRAGMA_OMP_CLAUSE_DOACROSS;
+	  else if (!strcmp ("dyn_groupprivate", p))
+	    result = PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE;
 	  break;
 	case 'e':
 	  if (!strcmp ("enter", p))
@@ -20262,6 +20264,96 @@ c_parser_omp_clause_doacross (c_parser *parser, tree list)
   return list;
 }
 
+/* OpenMP 6.1:
+   dyn_groupprivate ( [fallback-modifier : ] integer-expression )
+
+   fallback-modifier
+      fallback( abort | default_mem | null )  */
+
+static tree
+c_parser_omp_clause_dyn_groupprivate (c_parser *parser, tree list)
+{
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return list;
+
+  enum omp_clause_fallback_kind kind = OMP_CLAUSE_FALLBACK_UNSPECIFIED;
+
+  unsigned n = 3;
+  if (c_parser_next_token_is (parser, CPP_NAME)
+      && (c_parser_peek_2nd_token (parser)->type == CPP_COLON
+	  || (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN
+	      && c_parser_check_balanced_raw_token_sequence (parser, &n)
+	      && (c_parser_peek_nth_token_raw (parser, n)->type
+		  == CPP_CLOSE_PAREN)
+	      && (c_parser_peek_nth_token_raw (parser, n + 1)->type
+		  == CPP_COLON))))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "fallback") != 0)
+	{
+	  c_parser_error (parser, "expected %<fallback%> modifier");
+	  return list;
+	}
+      c_parser_consume_token (parser);
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+	return list;
+      p = "";
+      if (c_parser_next_token_is (parser, CPP_NAME))
+	p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "abort") == 0)
+	kind = OMP_CLAUSE_FALLBACK_ABORT;
+      else if (strcmp (p, "default_mem") == 0)
+	kind = OMP_CLAUSE_FALLBACK_DEFAULT_MEM;
+      else if (strcmp (p, "null") == 0)
+	kind = OMP_CLAUSE_FALLBACK_NULL;
+      else
+	{
+	  c_parser_error (parser, "expected %<abort%>, %<default_mem%>, or "
+				  "%<null%> as fallback mode");
+	  return list;
+	}
+      c_parser_consume_token (parser);
+      if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+	return list;
+      if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+	return list;
+    }
+  location_t expr_loc = c_parser_peek_token (parser)->location;
+  c_expr expr = c_parser_expr_no_commas (parser, NULL);
+  expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+  tree size = c_fully_fold (expr.value, false, NULL);
+  parens.skip_until_found_close (parser);
+
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (size)))
+    {
+      error_at (expr_loc, "expected integer expression");
+      return list;
+    }
+
+  /* Attempt to statically determine when the number is negative.  */
+  tree c = fold_build2_loc (expr_loc, LT_EXPR, boolean_type_node, size,
+			    build_int_cst (TREE_TYPE (size), 0));
+  protected_set_expr_location (c, expr_loc);
+  if (c == boolean_true_node)
+    {
+      warning_at (expr_loc, OPT_Wopenmp,
+		  "%<dyn_groupprivate%> value must be non-negative");
+      size = integer_zero_node;
+    }
+  check_no_duplicate_clause (list, OMP_CLAUSE_DYN_GROUPPRIVATE,
+			     "dyn_groupprivate");
+
+  c = build_omp_clause (clause_loc, OMP_CLAUSE_DYN_GROUPPRIVATE);
+  OMP_CLAUSE_DYN_GROUPPRIVATE_KIND (c) = kind;
+  OMP_CLAUSE_DYN_GROUPPRIVATE_EXPR (c) = size;
+  OMP_CLAUSE_CHAIN (c) = list;
+  list = c;
+
+  return list;
+}
+
 /* OpenMP 4.0:
    map ( map-kind: variable-list )
    map ( variable-list )
@@ -21982,6 +22074,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
 	  clauses = c_parser_omp_clause_destroy (parser, clauses);
 	  c_name = "destroy";
 	  break;
+	case PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE:
+	  clauses = c_parser_omp_clause_dyn_groupprivate (parser, clauses);
+	  c_name = "dyn_groupprivate";
+	  break;
 	case PRAGMA_OMP_CLAUSE_INIT:
 	  clauses = c_parser_omp_clause_init (parser, clauses);
 	  c_name = "init";
@@ -26796,19 +26892,20 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser,
      structured-block  */
 
 #define OMP_TARGET_CLAUSE_MASK					\
-	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)		\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE) \
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR) \
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)		\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR))
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT))
 
 static bool
 c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p)
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index a34ca2ab97c..d7c9a324d7a 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -17879,6 +17879,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_DIST_SCHEDULE:
+	case OMP_CLAUSE_DYN_GROUPPRIVATE:
 	case OMP_CLAUSE_PARALLEL:
 	case OMP_CLAUSE_FOR:
 	case OMP_CLAUSE_SECTIONS:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 4289f47e1b2..cdfa8f0122d 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -40047,6 +40047,8 @@ cp_parser_omp_clause_name (cp_parser *parser)
 	    result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
 	  else if (!strcmp ("doacross", p))
 	    result = PRAGMA_OMP_CLAUSE_DOACROSS;
+	  else if (!strcmp ("dyn_groupprivate", p))
+	    result = PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE;
 	  break;
 	case 'e':
 	  if (!strcmp ("enter", p))
@@ -43743,6 +43745,91 @@ cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind,
   return nl;
 }
 
+/* OpenMP 6.1:
+   dyn_groupprivate ( [fallback-modifier : ] integer-expression )
+
+   fallback-modifier
+      fallback( abort | default_mem | null )  */
+
+static tree
+cp_parser_omp_clause_dyn_groupprivate (cp_parser *parser, tree list,
+				       location_t location)
+{
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return list;
+
+  enum omp_clause_fallback_kind kind = OMP_CLAUSE_FALLBACK_UNSPECIFIED;
+
+  size_t n;
+  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+      && (cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)
+	  || (cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)
+	      && (n = cp_parser_skip_balanced_tokens (parser, 2)) != 3
+	      && cp_lexer_nth_token_is (parser->lexer, n, CPP_COLON))))
+    {
+      tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+      if (strcmp (IDENTIFIER_POINTER (id), "fallback") != 0)
+	{
+	  cp_parser_error (parser, "expected %<fallback%> modifier");
+	  cp_parser_skip_to_closing_parenthesis (parser,
+						 /*recovering=*/true,
+						 /*or_comma=*/false,
+						 /*consume_paren=*/true);
+	  return list;
+	}
+      cp_lexer_consume_token (parser->lexer);
+      if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+	return list;
+      const char *p = "";
+      if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+	{
+	  id = cp_lexer_peek_token (parser->lexer)->u.value;
+	  p = IDENTIFIER_POINTER (id);
+	}
+      if (strcmp (p, "abort") == 0)
+	kind = OMP_CLAUSE_FALLBACK_ABORT;
+      else if (strcmp (p, "default_mem") == 0)
+	kind = OMP_CLAUSE_FALLBACK_DEFAULT_MEM;
+      else if (strcmp (p, "null") == 0)
+	kind = OMP_CLAUSE_FALLBACK_NULL;
+      else
+	{
+	  cp_parser_error (parser, "expected %<abort%>, %<default_mem%>, or "
+				   "%<null%> as fallback mode");
+	  cp_parser_skip_to_closing_parenthesis (parser,
+						 /*recovering=*/true,
+						 /*or_comma=*/false,
+						 /*consume_paren=*/true);
+	  return list;
+	}
+      cp_lexer_consume_token (parser->lexer);
+      if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+	return list;
+      if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+	return list;
+    }
+
+  tree size = cp_parser_assignment_expression (parser);
+
+  if (size == error_mark_node
+      || !parens.require_close (parser))
+    cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+					   /*or_comma=*/false,
+					   /*consume_paren=*/true);
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_DYN_GROUPPRIVATE,
+			     "dyn_groupprivate", location);
+
+  tree c = build_omp_clause (location, OMP_CLAUSE_DYN_GROUPPRIVATE);
+  OMP_CLAUSE_DYN_GROUPPRIVATE_KIND (c) = kind;
+  OMP_CLAUSE_DYN_GROUPPRIVATE_EXPR (c) = size;
+  OMP_CLAUSE_CHAIN (c) = list;
+  list = c;
+
+  return list;
+}
+
 /* OpenMP 4.0:
    map ( map-kind : variable-list )
    map ( variable-list )
@@ -45352,6 +45439,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
 					    clauses);
 	  c_name = "destroy";
 	  break;
+	case PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE:
+	  clauses = cp_parser_omp_clause_dyn_groupprivate (parser, clauses,
+							   token->location);
+	  c_name = "dyn_groupprivate";
+	  break;
 	case PRAGMA_OMP_CLAUSE_INIT:
 	  {
 	    /* prefer_type parsing fails often such that many follow-up errors
@@ -50230,19 +50322,20 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok,
      structured-block  */
 
 #define OMP_TARGET_CLAUSE_MASK					\
-	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)		\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DYN_GROUPPRIVATE) \
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR) \
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)		\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR))
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT))
 
 static bool
 cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index cd66aeafd86..7a019d33bda 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -18214,6 +18214,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
 	case OMP_CLAUSE_ASYNC:
 	case OMP_CLAUSE_WAIT:
 	case OMP_CLAUSE_DETACH:
+	case OMP_CLAUSE_DYN_GROUPPRIVATE:
 	  OMP_CLAUSE_OPERAND (nc, 0)
 	    = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl);
 	  break;
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index f472be21c4b..331db16f76d 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -8356,6 +8356,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	case OMP_CLAUSE_NUM_THREADS:
 	case OMP_CLAUSE_NUM_GANGS:
 	case OMP_CLAUSE_NUM_WORKERS:
+	case OMP_CLAUSE_DYN_GROUPPRIVATE:
 	case OMP_CLAUSE_VECTOR_LENGTH:
 	  t = OMP_CLAUSE_OPERAND (c, 0);
 	  if (t == error_mark_node)
@@ -8389,7 +8390,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	      if (!processing_template_decl)
 		{
 		  t = maybe_constant_value (t);
-		  if (TREE_CODE (t) == INTEGER_CST
+		  if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DYN_GROUPPRIVATE
+		      && TREE_CODE (t) == INTEGER_CST
 		      && tree_int_cst_sgn (t) != 1)
 		    {
 		      switch (OMP_CLAUSE_CODE (c))
@@ -8418,6 +8420,15 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 			}
 		      t = integer_one_node;
 		    }
+		  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DYN_GROUPPRIVATE
+			   && TREE_CODE (t) == INTEGER_CST
+			   && tree_int_cst_sgn (t) < 0)
+		    {
+		      warning_at (OMP_CLAUSE_LOCATION (c), OPT_Wopenmp,
+				  "%<dyn_groupprivate%> value must be "
+				  "non-negative");
+		      t = integer_zero_node;
+		    }
 		  t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
 		}
 	      OMP_CLAUSE_OPERAND (c, 0) = t;
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index e847c1c0c08..abc27d59a0c 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -8977,8 +8977,8 @@ 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");
+    resolve_nonnegative_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/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index c0a8ed927d9..8eb4fc4bcc6 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -5267,21 +5267,33 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *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);
+      tree expr = (CONSTANT_CLASS_P (se.expr) || DECL_P (se.expr)
+		   ? se.expr : gfc_evaluate_now (se.expr, block));
       gfc_add_block_to_block (block, &se.post);
 
+      enum omp_clause_fallback_kind kind = OMP_CLAUSE_FALLBACK_UNSPECIFIED;
+      switch (clauses->fallback)
+	{
+	case OMP_FALLBACK_ABORT:
+	  kind = OMP_CLAUSE_FALLBACK_ABORT;
+	  break;
+	case OMP_FALLBACK_DEFAULT_MEM:
+	  kind = OMP_CLAUSE_FALLBACK_DEFAULT_MEM;
+	  break;
+	case OMP_FALLBACK_NULL:
+	  kind = OMP_CLAUSE_FALLBACK_NULL;
+	  break;
+	case OMP_FALLBACK_NONE:
+	  break;
+	}
       c = build_omp_clause (gfc_get_location (&where),
 			    OMP_CLAUSE_DYN_GROUPPRIVATE);
-      OMP_CLAUSE_NUM_THREADS_EXPR (c) = num_threads;
+      OMP_CLAUSE_DYN_GROUPPRIVATE_KIND (c) = kind;
+      OMP_CLAUSE_DYN_GROUPPRIVATE_EXPR (c) = expr;
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
-#endif
     }
 
   chunk_size = NULL_TREE;
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 9371195fa01..0023728ad8e 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -14881,6 +14881,11 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 	case OMP_CLAUSE_DESTROY:
 	  break;
 
+	case OMP_CLAUSE_DYN_GROUPPRIVATE:
+	  remove = true;
+	  sorry_at (OMP_CLAUSE_LOCATION (c),"%<dyn_groupprivate%> clause");
+	  break;
+
 	case OMP_CLAUSE_ORDER:
 	  ctx->order_concurrent = true;
 	  break;
diff --git a/gcc/testsuite/c-c++-common/gomp/dyn_groupprivate-1.c b/gcc/testsuite/c-c++-common/gomp/dyn_groupprivate-1.c
new file mode 100644
index 00000000000..c49189d6b9a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/dyn_groupprivate-1.c
@@ -0,0 +1,28 @@
+/* { dg-do compile }  */
+/* { dg-additional-options "-fdump-tree-original" }  */
+
+void f()
+{
+  int N = 1024;
+
+  #pragma omp target dyn_groupprivate(1024)  // { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
+    ;
+
+  #pragma omp target dyn_groupprivate (1024 * N)  // { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
+    ;
+
+  #pragma omp target dyn_groupprivate ( fallback ( abort ) : N)  // { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
+    ;
+
+  #pragma omp target dyn_groupprivate ( fallback ( null ) : N)  // { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
+    ;
+
+  #pragma omp target dyn_groupprivate ( fallback ( default_mem ) : N)  // { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
+    ;
+}
+
+/* { dg-final { scan-tree-dump-times "#pragma omp target dyn_groupprivate\\(1024\\)" 1 "original" } }  */
+/* { dg-final { scan-tree-dump-times "#pragma omp target dyn_groupprivate\\(N \\* 1024\\)" 1 "original" } }  */
+/* { dg-final { scan-tree-dump-times "#pragma omp target dyn_groupprivate\\(fallback\\(abort\\):N\\)" 1 "original" } }  */
+/* { dg-final { scan-tree-dump-times "#pragma omp target dyn_groupprivate\\(fallback\\(null\\):N\\)" 1 "original" } }  */
+/* { dg-final { scan-tree-dump-times "#pragma omp target dyn_groupprivate\\(fallback\\(default_mem\\):N\\)" 1 "original" } }  */
diff --git a/gcc/testsuite/c-c++-common/gomp/dyn_groupprivate-2.c b/gcc/testsuite/c-c++-common/gomp/dyn_groupprivate-2.c
new file mode 100644
index 00000000000..f12ff7b2132
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/dyn_groupprivate-2.c
@@ -0,0 +1,72 @@
+/* { dg-do compile }  */
+
+void f()
+{
+#if !defined(__cplusplus) || __cplusplus >= 201103L
+  constexpr int M = 1024; // C20 + C++11
+#endif
+  int N, A[1];
+  N = 1024;
+
+  #pragma omp target dyn_groupprivate(0)
+    ;
+
+  #pragma omp target dyn_groupprivate(0) dyn_groupprivate(0)  // { dg-error "too many 'dyn_groupprivate' clauses" }
+    ;
+
+  #pragma omp target dyn_groupprivate(1,)  // { dg-error "expected '\\)' before ',' token" }
+    ;
+
+  #pragma omp target dyn_groupprivate(-123)  // { dg-warning "'dyn_groupprivate' value must be non-negative \\\[-Wopenmp\\\]" }
+    ;
+
+#if !defined(__cplusplus) || __cplusplus >= 201103L
+  #pragma omp target dyn_groupprivate (0 * M - 1)  // { dg-warning "'dyn_groupprivate' value must be non-negative \\\[-Wopenmp\\\]" "" { target { ! c++98_only } } }
+#endif
+    ;
+
+  #pragma omp target dyn_groupprivate (- 4)  // { dg-warning "'dyn_groupprivate' value must be non-negative \\\[-Wopenmp\\\]" }
+    ;
+
+  #pragma omp target dyn_groupprivate ( fallback ( other ) : N)  // { dg-error "expected 'abort', 'default_mem', or 'null' as fallback mode before 'other'" }
+    // { dg-error "expected an OpenMP clause before ':' token" "" { target c++ } .-1 }
+    ;
+
+  #pragma omp target dyn_groupprivate ( A )
+  // { dg-error "expected integer expression" "" { target c } .-1 }
+  // { dg-error "'dyn_groupprivate' expression must be integral" "" { target c++ } .-2 }
+    ;
+
+  #pragma omp target dyn_groupprivate ( 1024. )
+  // { dg-error "expected integer expression" "" { target c } .-1 }
+  // { dg-error "'dyn_groupprivate' expression must be integral" "" { target c++ } .-2 }
+    ;
+
+  #pragma omp target dyn_groupprivate ( foo ( 4 ) : 10 )  // { dg-error "expected 'fallback' modifier before 'foo'" }
+    ;
+
+  #pragma omp target dyn_groupprivate ( foo2 (  ) : 10 )  // { dg-error "expected 'fallback' modifier before 'foo2'" }
+    ;
+
+  #pragma omp target dyn_groupprivate ( fallback (  ) : 10 )  // { dg-error "expected 'abort', 'default_mem', or 'null' as fallback mode before '\\)'" }
+    // { dg-error "expected an OpenMP clause before ':' token" "" { target c++ } .-1 }
+    ;
+
+  #pragma omp target dyn_groupprivate ( bar : 10 )  // { dg-error "expected 'fallback' modifier before 'bar'" }
+    ;
+
+  #pragma omp target dyn_groupprivate ( fallback : 10 )  // { dg-error "expected '\\(' before ':' token" }
+    // { dg-error "expected an OpenMP clause before ':' token" "" { target c++ } .-1 }
+    ;
+
+  #pragma omp target dyn_groupprivate ( fallback ( null,) : 10 )  // { dg-error "expected '\\)' before ',' token" }
+    // { dg-error "expected an OpenMP clause before '\\)' token" "" { target c++ } .-1 }
+    ;
+}
+
+// { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" "" { target *-*-* } 11 }
+// { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" "" { target *-*-* } 14 }
+// { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" "" { target *-*-* } 17 }
+// { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" "" { target *-*-* } 20 }
+// { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" "" { target { ! c++98_only } } 24 }
+// { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" "" { target *-*-* } 28 }
diff --git a/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-1.f90 b/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-1.f90
index 2e09febe18c..3661f142ca5 100644
--- a/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-1.f90
@@ -1,3 +1,6 @@
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+
 implicit none
 
 integer :: N
@@ -18,3 +21,9 @@ N = 1024
 !$omp target dyn_groupprivate ( fallback ( default_mem ) : N)  ! { dg-message "sorry, unimplemented: 'dyn_groupprivate' clause" }
 !$omp end target
 end
+
+! { dg-final { scan-tree-dump-times "#pragma omp target dyn_groupprivate\\(1024\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target dyn_groupprivate\\(D.4680\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target dyn_groupprivate\\(fallback\\(abort\\):n\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target dyn_groupprivate\\(fallback\\(null\\):n\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target dyn_groupprivate\\(fallback\\(default_mem\\):n\\)" 1 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-2.f90 b/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-2.f90
index 0a5a644b9f4..8410334f4f5 100644
--- a/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/dyn_groupprivate-2.f90
@@ -1,3 +1,5 @@
+! { dg-do compile }
+
 implicit none
 
 integer, parameter :: M = 1024
@@ -5,10 +7,16 @@ 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\\\]" }
+!$omp target dyn_groupprivate(0)  ! OK, zero is permitted
+block; end block
+
+!$omp target dyn_groupprivate(0)  dyn_groupprivate(0)  ! { dg-error "Duplicated 'dyn_groupprivate' clause" }
+block; end block
+
+!$omp target dyn_groupprivate(-123)  ! { dg-warning "INTEGER expression of DYN_GROUPPRIVATE clause at .1. must be non-negative \\\[-Wopenmp\\\]" }
 block; end block
 
-!$omp target dyn_groupprivate (0 * M)  ! { dg-warning "INTEGER expression of DYN_GROUPPRIVATE clause at .1. must be positive \\\[-Wopenmp\\\]" }
+!$omp target dyn_groupprivate (0 * M-1)  ! { dg-warning "INTEGER expression of DYN_GROUPPRIVATE clause at .1. must be non-negative \\\[-Wopenmp\\\]" }
 block; end block
 
 !$omp target dyn_groupprivate ( fallback ( other ) : N)  ! { dg-error "Failed to match clause" }
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 88627ac9381..674d6ec8c7f 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -596,6 +596,8 @@ enum omp_clause_code {
   /* OpenMP clause: nocontext (scalar-expression).  */
   OMP_CLAUSE_NOCONTEXT,
 
+  /* OpenMP clause: dyn_groupprivate ( [fallback (...)] : integer-expression).  */
+  OMP_CLAUSE_DYN_GROUPPRIVATE,
 };
 
 #undef DEFTREESTRUCT
@@ -655,6 +657,14 @@ enum omp_clause_bind_kind {
   OMP_CLAUSE_BIND_THREAD
 };
 
+enum omp_clause_fallback_kind {
+  OMP_CLAUSE_FALLBACK_UNSPECIFIED,
+  OMP_CLAUSE_FALLBACK_ABORT,
+  OMP_CLAUSE_FALLBACK_DEFAULT_MEM,
+  OMP_CLAUSE_FALLBACK_NULL
+};
+
+
 /* memory-order-clause on OpenMP atomic/flush constructs or
    argument of atomic_default_mem_order clause.  */
 enum omp_memory_order {
@@ -1747,6 +1757,7 @@ struct GTY(()) tree_omp_clause {
     enum omp_clause_defaultmap_kind defaultmap_kind;
     enum omp_clause_bind_kind      bind_kind;
     enum omp_clause_device_type_kind device_type_kind;
+    enum omp_clause_fallback_kind fallback_kind;
   } GTY ((skip)) subcode;
 
   /* The gimplification of OMP_CLAUSE_REDUCTION_{INIT,MERGE} for omp-low's
diff --git a/gcc/tree-nested.cc b/gcc/tree-nested.cc
index 813334b5c92..21a289b0860 100644
--- a/gcc/tree-nested.cc
+++ b/gcc/tree-nested.cc
@@ -1411,6 +1411,7 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 	case OMP_CLAUSE_DEPEND:
 	case OMP_CLAUSE_DOACROSS:
 	case OMP_CLAUSE_DEVICE:
+	case OMP_CLAUSE_DYN_GROUPPRIVATE:
 	case OMP_CLAUSE_NUM_TEAMS:
 	case OMP_CLAUSE_THREAD_LIMIT:
 	case OMP_CLAUSE_SAFELEN:
@@ -2192,6 +2193,7 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 	case OMP_CLAUSE_DEPEND:
 	case OMP_CLAUSE_DOACROSS:
 	case OMP_CLAUSE_DEVICE:
+	case OMP_CLAUSE_DYN_GROUPPRIVATE:
 	case OMP_CLAUSE_NUM_TEAMS:
 	case OMP_CLAUSE_THREAD_LIMIT:
 	case OMP_CLAUSE_SAFELEN:
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index c19babadead..ba04911ae90 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -1327,6 +1327,27 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
       pp_right_paren (pp);
       break;
 
+    case OMP_CLAUSE_DYN_GROUPPRIVATE:
+      pp_string (pp, "dyn_groupprivate(");
+      switch (OMP_CLAUSE_DYN_GROUPPRIVATE_KIND (clause))
+	{
+	case OMP_CLAUSE_FALLBACK_ABORT:
+	  pp_string (pp, "fallback(abort):");
+	  break;
+	case OMP_CLAUSE_FALLBACK_DEFAULT_MEM:
+	  pp_string (pp, "fallback(default_mem):");
+	  break;
+	case OMP_CLAUSE_FALLBACK_NULL:
+	  pp_string (pp, "fallback(null):");
+	  break;
+	case OMP_CLAUSE_FALLBACK_UNSPECIFIED:
+	  break;
+	}
+      dump_generic_node (pp, OMP_CLAUSE_DYN_GROUPPRIVATE_EXPR (clause),
+			 spc, flags, false);
+      pp_right_paren (pp);
+      break;
+
     case OMP_CLAUSE_SAFELEN:
       pp_string (pp, "safelen(");
       dump_generic_node (pp, OMP_CLAUSE_SAFELEN_EXPR (clause),
diff --git a/gcc/tree.cc b/gcc/tree.cc
index e8376dd04bd..52fc83e3c07 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -398,6 +398,7 @@ unsigned const char omp_clause_num_ops[] =
   0, /* OMP_CLAUSE_NOHOST */
   1, /* OMP_CLAUSE_NOVARIANTS */
   1, /* OMP_CLAUSE_NOCONTEXT */
+  1, /* OMP_CLAUSE_DYN_GROUPPRIVATE  */
 };
 
 const char * const omp_clause_code_name[] =
@@ -501,6 +502,7 @@ const char * const omp_clause_code_name[] =
   "nohost",
   "novariants",
   "nocontext",
+  "dyn_groupprivate",
 };
 
 /* Unless specific to OpenACC, we tend to internally maintain OpenMP-centric
diff --git a/gcc/tree.h b/gcc/tree.h
index 762228c336f..56f4fc16dcd 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2116,6 +2116,11 @@ class auto_suppress_location_wrappers
 #define OMP_CLAUSE_BIND_KIND(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_BIND)->omp_clause.subcode.bind_kind)
 
+#define OMP_CLAUSE_DYN_GROUPPRIVATE_EXPR(NODE)                                        \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DYN_GROUPPRIVATE), 0)
+#define OMP_CLAUSE_DYN_GROUPPRIVATE_KIND(NODE) \
+  (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DYN_GROUPPRIVATE)->omp_clause.subcode.fallback_kind)
+
 /* True if ENTER clause is spelled as TO.  */
 #define OMP_CLAUSE_ENTER_TO(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ENTER)->base.public_flag)

Reply via email to