https://gcc.gnu.org/g:a9164dde46c41794c97d40a1a0271db16512f2c0

commit a9164dde46c41794c97d40a1a0271db16512f2c0
Author: Paul-Antoine Arras <par...@baylibre.com>
Date:   Wed Nov 20 15:28:58 2024 +0100

    OpenMP: C++ front-end support for dispatch + adjust_args
    
    This patch adds C++ support for the `dispatch` construct and the 
`adjust_args`
    clause. It relies on the c-family bits comprised in the corresponding C 
front
    end patch for pragmas and attributes.
    
    Additional C/C++ common testcases are provided in a subsequent patch in the
    series.
    
    gcc/cp/ChangeLog:
    
            * decl.cc (omp_declare_variant_finalize_one): Set adjust_args
            need_device_ptr attribute.
            * parser.cc (cp_parser_direct_declarator): Update call to
            cp_parser_late_return_type_opt.
            (cp_parser_late_return_type_opt): Add 'tree parms' parameter. Update
            call to cp_parser_late_parsing_omp_declare_simd.
            (cp_parser_omp_clause_name): Handle nocontext and novariants 
clauses.
            (cp_parser_omp_clause_novariants): New function.
            (cp_parser_omp_clause_nocontext): Likewise.
            (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_NOVARIANTS and
            PRAGMA_OMP_CLAUSE_NOCONTEXT.
            (cp_parser_omp_dispatch_body): New function, inspired from
            cp_parser_assignment_expression and cp_parser_postfix_expression.
            (OMP_DISPATCH_CLAUSE_MASK): Define.
            (cp_parser_omp_dispatch): New function.
            (cp_finish_omp_declare_variant): Add parameter. Handle adjust_args
            clause.
            (cp_parser_late_parsing_omp_declare_simd): Add parameter. Update 
calls
            to cp_finish_omp_declare_variant and cp_finish_omp_declare_variant.
            (cp_parser_omp_construct): Handle PRAGMA_OMP_DISPATCH.
            (cp_parser_pragma): Likewise.
            * semantics.cc (finish_omp_clauses): Handle OMP_CLAUSE_NOCONTEXT and
            OMP_CLAUSE_NOVARIANTS.
            * pt.cc (tsubst_omp_clauses): Handle OMP_CLAUSE_NOCONTEXT and
            OMP_CLAUSE_NOVARIANTS.
            (tsubst_stmt): Handle OMP_DISPATCH.
            (tsubst_expr): Handle IFN_GOMP_DISPATCH.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/gomp/adjust-args-1.C: New test.
            * g++.dg/gomp/adjust-args-2.C: New test.
            * g++.dg/gomp/adjust-args-3.C: New test.
            * g++.dg/gomp/dispatch-1.C: New test.
            * g++.dg/gomp/dispatch-2.C: New test.
            * g++.dg/gomp/dispatch-3.C: New test.
            * g++.dg/gomp/dispatch-4.C: New test.
            * g++.dg/gomp/dispatch-5.C: New test.
            * g++.dg/gomp/dispatch-6.C: New test.
            * g++.dg/gomp/dispatch-7.C: New test.
    
    (cherry picked from commit ed49709acda4938f71ef2dfac68450be5429db3d)

Diff:
---
 gcc/cp/ChangeLog.omp                      |  33 +++
 gcc/cp/decl.cc                            |   7 +
 gcc/cp/parser.cc                          | 466 +++++++++++++++++++++++++++---
 gcc/cp/pt.cc                              |  28 ++
 gcc/cp/semantics.cc                       |  20 ++
 gcc/testsuite/ChangeLog.omp               |  16 +
 gcc/testsuite/g++.dg/gomp/adjust-args-1.C |  39 +++
 gcc/testsuite/g++.dg/gomp/adjust-args-2.C |  51 ++++
 gcc/testsuite/g++.dg/gomp/adjust-args-3.C |   6 +
 gcc/testsuite/g++.dg/gomp/dispatch-1.C    |  53 ++++
 gcc/testsuite/g++.dg/gomp/dispatch-2.C    |  62 ++++
 gcc/testsuite/g++.dg/gomp/dispatch-3.C    |  17 ++
 gcc/testsuite/g++.dg/gomp/dispatch-4.C    |  22 ++
 gcc/testsuite/g++.dg/gomp/dispatch-5.C    |  17 ++
 gcc/testsuite/g++.dg/gomp/dispatch-6.C    |  29 ++
 gcc/testsuite/g++.dg/gomp/dispatch-7.C    |  43 +++
 16 files changed, 864 insertions(+), 45 deletions(-)

diff --git a/gcc/cp/ChangeLog.omp b/gcc/cp/ChangeLog.omp
index b68cd46caf42..01483816e018 100644
--- a/gcc/cp/ChangeLog.omp
+++ b/gcc/cp/ChangeLog.omp
@@ -1,3 +1,36 @@
+2025-01-27  Paul-Antoine Arras  <par...@baylibre.com>
+
+       Backported from master:
+       2024-11-20  Paul-Antoine Arras  <par...@baylibre.com>
+
+       * decl.cc (omp_declare_variant_finalize_one): Set adjust_args
+       need_device_ptr attribute.
+       * parser.cc (cp_parser_direct_declarator): Update call to
+       cp_parser_late_return_type_opt.
+       (cp_parser_late_return_type_opt): Add 'tree parms' parameter. Update
+       call to cp_parser_late_parsing_omp_declare_simd.
+       (cp_parser_omp_clause_name): Handle nocontext and novariants clauses.
+       (cp_parser_omp_clause_novariants): New function.
+       (cp_parser_omp_clause_nocontext): Likewise.
+       (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_NOVARIANTS and
+       PRAGMA_OMP_CLAUSE_NOCONTEXT.
+       (cp_parser_omp_dispatch_body): New function, inspired from
+       cp_parser_assignment_expression and cp_parser_postfix_expression.
+       (OMP_DISPATCH_CLAUSE_MASK): Define.
+       (cp_parser_omp_dispatch): New function.
+       (cp_finish_omp_declare_variant): Add parameter. Handle adjust_args
+       clause.
+       (cp_parser_late_parsing_omp_declare_simd): Add parameter. Update calls
+       to cp_finish_omp_declare_variant and cp_finish_omp_declare_variant.
+       (cp_parser_omp_construct): Handle PRAGMA_OMP_DISPATCH.
+       (cp_parser_pragma): Likewise.
+       * semantics.cc (finish_omp_clauses): Handle OMP_CLAUSE_NOCONTEXT and
+       OMP_CLAUSE_NOVARIANTS.
+       * pt.cc (tsubst_omp_clauses): Handle OMP_CLAUSE_NOCONTEXT and
+       OMP_CLAUSE_NOVARIANTS.
+       (tsubst_stmt): Handle OMP_DISPATCH.
+       (tsubst_expr): Handle IFN_GOMP_DISPATCH.
+
 2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
 
        Backported from master:
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 097e958b1ec1..b1f8759cee89 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8346,6 +8346,13 @@ omp_declare_variant_finalize_one (tree decl, tree attr)
          if (!omp_context_selector_matches (ctx, NULL_TREE, false))
            return true;
          TREE_PURPOSE (TREE_VALUE (attr)) = variant;
+
+         // Prepend adjust_args list to variant attributes
+         tree adjust_args_list = TREE_CHAIN (TREE_CHAIN (chain));
+         if (adjust_args_list != NULL_TREE)
+           DECL_ATTRIBUTES (variant) = tree_cons (
+             get_identifier ("omp declare variant variant adjust_args"),
+             TREE_VALUE (adjust_args_list), DECL_ATTRIBUTES (variant));
        }
     }
   else if (!processing_template_decl)
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 5a05fb18ef87..b1c17a451d79 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
+#include "omp-selectors.h"
 #define INCLUDE_MEMORY
 #include "system.h"
 #include "coretypes.h"
@@ -2585,7 +2586,7 @@ static cp_ref_qualifier cp_parser_ref_qualifier_opt
 static tree cp_parser_tx_qualifier_opt
   (cp_parser *);
 static tree cp_parser_late_return_type_opt
-  (cp_parser *, cp_declarator *, tree &);
+  (cp_parser *, cp_declarator *, tree &, tree);
 static tree cp_parser_declarator_id
   (cp_parser *, bool);
 static tree cp_parser_type_id
@@ -2620,7 +2621,7 @@ static void 
cp_parser_ctor_initializer_opt_and_function_body
   (cp_parser *, bool);
 
 static tree cp_parser_late_parsing_omp_declare_simd
-  (cp_parser *, tree);
+  (cp_parser *, tree, tree);
 
 static tree cp_parser_late_parsing_oacc_routine
   (cp_parser *, tree);
@@ -24136,7 +24137,7 @@ cp_parser_direct_declarator (cp_parser* parser,
                  tree requires_clause = NULL_TREE;
                  late_return
                    = cp_parser_late_return_type_opt (parser, declarator,
-                                                     requires_clause);
+                                                     requires_clause, params);
 
                  cp_finalize_omp_declare_simd (parser, &odsd);
 
@@ -25000,8 +25001,8 @@ parsing_function_declarator ()
    function.  */
 
 static tree
-cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator,
-                               tree& requires_clause)
+cp_parser_late_return_type_opt (cp_parser *parser, cp_declarator *declarator,
+                               tree &requires_clause, tree parms)
 {
   cp_token *token;
   tree type = NULL_TREE;
@@ -25037,8 +25038,8 @@ cp_parser_late_return_type_opt (cp_parser* parser, 
cp_declarator *declarator,
 
   if (declare_simd_p)
     declarator->attributes
-      = cp_parser_late_parsing_omp_declare_simd (parser,
-                                                declarator->attributes);
+      = cp_parser_late_parsing_omp_declare_simd (parser, 
declarator->attributes,
+                                                parms);
   if (oacc_routine_p)
     declarator->attributes
       = cp_parser_late_parsing_oacc_routine (parser,
@@ -38141,6 +38142,8 @@ cp_parser_omp_clause_name (cp_parser *parser)
        case 'n':
          if (!strcmp ("no_create", p))
            result = PRAGMA_OACC_CLAUSE_NO_CREATE;
+         else if (!strcmp ("nocontext", p))
+           result = PRAGMA_OMP_CLAUSE_NOCONTEXT;
          else if (!strcmp ("nogroup", p))
            result = PRAGMA_OMP_CLAUSE_NOGROUP;
          else if (!strcmp ("nohost", p))
@@ -38149,6 +38152,8 @@ cp_parser_omp_clause_name (cp_parser *parser)
            result = PRAGMA_OMP_CLAUSE_NONTEMPORAL;
          else if (!strcmp ("notinbranch", p))
            result = PRAGMA_OMP_CLAUSE_NOTINBRANCH;
+         else if (!strcmp ("novariants", p))
+           result = PRAGMA_OMP_CLAUSE_NOVARIANTS;
          else if (!strcmp ("nowait", p))
            result = PRAGMA_OMP_CLAUSE_NOWAIT;
          else if (!strcmp ("num_gangs", p))
@@ -40735,6 +40740,56 @@ cp_parser_omp_clause_partial (cp_parser *parser, tree 
list, location_t loc)
   return c;
 }
 
+/* OpenMP 5.1
+   novariants ( scalar-expression ) */
+
+static tree
+cp_parser_omp_clause_novariants (cp_parser *parser, tree list, location_t loc)
+{
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return list;
+
+  tree t = cp_parser_assignment_expression (parser);
+  if (t == 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_NOVARIANTS, "novariants", loc);
+
+  tree c = build_omp_clause (loc, OMP_CLAUSE_NOVARIANTS);
+  OMP_CLAUSE_NOVARIANTS_EXPR (c) = t;
+  OMP_CLAUSE_CHAIN (c) = list;
+
+  return c;
+}
+
+/* OpenMP 5.1
+   nocontext ( scalar-expression ) */
+
+static tree
+cp_parser_omp_clause_nocontext (cp_parser *parser, tree list, location_t loc)
+{
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return list;
+
+  tree t = cp_parser_assignment_expression (parser);
+  if (t == 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_NOCONTEXT, "nocontext", loc);
+
+  tree c = build_omp_clause (loc, OMP_CLAUSE_NOCONTEXT);
+  OMP_CLAUSE_NOCONTEXT_EXPR (c) = t;
+  OMP_CLAUSE_CHAIN (c) = list;
+
+  return c;
+}
+
 /* OpenMP 4.0:
    aligned ( variable-list )
    aligned ( variable-list : constant-expression )  */
@@ -43298,6 +43353,16 @@ cp_parser_omp_all_clauses (cp_parser *parser, 
omp_clause_mask mask,
          clauses = cp_parser_omp_clause_full (clauses, token->location);
          c_name = "full";
          break;
+       case PRAGMA_OMP_CLAUSE_NOVARIANTS:
+         clauses = cp_parser_omp_clause_novariants (parser, clauses,
+                                                    token->location);
+         c_name = "novariants";
+         break;
+       case PRAGMA_OMP_CLAUSE_NOCONTEXT:
+         clauses
+           = cp_parser_omp_clause_nocontext (parser, clauses, token->location);
+         c_name = "nocontext";
+         break;
        default:
          cp_parser_error (parser, "expected an OpenMP clause");
          goto saw_error;
@@ -49605,12 +49670,160 @@ cp_parser_omp_assumes (cp_parser *parser, cp_token 
*pragma_tok)
   return false;
 }
 
+/* Parse a function dispatch structured block:
+
+    lvalue-expression = target-call ( [expression-list] );
+    or
+    target-call ( [expression-list] );
+
+  Inspired from cp_parser_assignment_expression and
+  cp_parser_postfix_expression.
+*/
+
+static tree
+cp_parser_omp_dispatch_body (cp_parser *parser)
+{
+  /* Parse the binary expressions (lvalue-expression or target-call).  */
+  cp_expr expr = cp_parser_binary_expression (parser, false, false, false,
+                                             PREC_NOT_OPERATOR, NULL);
+  if (TREE_CODE (STRIP_REFERENCE_REF (expr.get_value ())) == CALL_EXPR
+      || TREE_CODE (expr) == ERROR_MARK)
+    return expr;
+
+  /* We have the lvalue, now deal with the assignment. */
+
+  if (!cp_parser_require (parser, CPP_EQ, RT_EQ))
+    return error_mark_node;
+
+  /* Peek at the next token.  */
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  location_t loc = token->location;
+
+  /* Parse function call.  */
+  cp_expr rhs = cp_parser_postfix_expression (parser, false, false, false,
+                                             false, nullptr);
+  if (rhs == error_mark_node)
+    return rhs;
+
+  if (TREE_CODE (STRIP_REFERENCE_REF (rhs.get_value ())) != CALL_EXPR)
+    {
+      error_at (EXPR_LOC_OR_LOC (rhs, rhs.get_location ()),
+               "expected target-function call");
+      return error_mark_node;
+    }
+
+  /* Build the assignment expression.  Its default
+     location:
+       LHS = RHS
+       ~~~~^~~~~
+     is the location of the '=' token as the
+     caret, ranging from the start of the lhs to the
+     end of the rhs.  */
+  loc = make_location (loc, expr.get_start (), rhs.get_finish ());
+  expr = build_x_modify_expr (loc, expr, NOP_EXPR, rhs, NULL_TREE,
+                             complain_flags (false));
+  /* TODO: build_x_modify_expr doesn't honor the location,
+     so we must set it here.  */
+  expr.set_location (loc);
+
+  return expr;
+}
+
+/* OpenMP 5.1:
+   # pragma omp dispatch dispatch-clause[optseq] new-line
+     expression-stmt
+
+   LOC is the location of the #pragma.
+*/
+
+#define OMP_DISPATCH_CLAUSE_MASK                                               
\
+  ((OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)                             
\
+   | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)                           
\
+   | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOVARIANTS)                       
\
+   | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOCONTEXT)                        
\
+   | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)                    
\
+   | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+cp_parser_omp_dispatch (cp_parser *parser, cp_token *pragma_tok)
+{
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+  tree stmt = make_node (OMP_DISPATCH);
+  SET_EXPR_LOCATION (stmt, loc);
+  TREE_TYPE (stmt) = void_type_node;
+
+  OMP_DISPATCH_CLAUSES (stmt)
+    = cp_parser_omp_all_clauses (parser, OMP_DISPATCH_CLAUSE_MASK,
+                                "#pragma omp dispatch", pragma_tok);
+
+  // Extract depend clauses and create taskwait
+  tree depend_clauses = NULL_TREE;
+  tree *depend_clauses_ptr = &depend_clauses;
+  for (tree c = OMP_DISPATCH_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c))
+    {
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND)
+       {
+         *depend_clauses_ptr = c;
+         depend_clauses_ptr = &OMP_CLAUSE_CHAIN (c);
+       }
+    }
+  if (depend_clauses != NULL_TREE)
+    {
+      tree stmt = make_node (OMP_TASK);
+      TREE_TYPE (stmt) = void_node;
+      OMP_TASK_CLAUSES (stmt) = depend_clauses;
+      OMP_TASK_BODY (stmt) = NULL_TREE;
+      SET_EXPR_LOCATION (stmt, loc);
+      add_stmt (stmt);
+    }
+
+  // Parse expression statement
+  loc = cp_lexer_peek_token (parser->lexer)->location;
+  tree dispatch_body = cp_parser_omp_dispatch_body (parser);
+  if (dispatch_body == error_mark_node)
+    {
+      inform (loc,
+             "%<#pragma omp dispatch%> must be followed by a direct function "
+             "call with optional assignment");
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+      return NULL_TREE;
+    }
+
+  // Walk the tree to find the dispatch function call and wrap it into an IFN
+  tree *dispatch_call;
+  switch (TREE_CODE (STRIP_REFERENCE_REF (dispatch_body)))
+    {
+    case MODIFY_EXPR:
+      dispatch_call = &TREE_OPERAND (dispatch_body, 1);
+      break;
+    case MODOP_EXPR:
+      dispatch_call = &TREE_OPERAND (dispatch_body, 2);
+      break;
+    case CALL_EXPR:
+      dispatch_call = &dispatch_body;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (TREE_CODE (*dispatch_call) == FLOAT_EXPR
+      || TREE_CODE (*dispatch_call) == CONVERT_EXPR)
+    dispatch_call = &TREE_OPERAND (*dispatch_call, 0);
+  *dispatch_call = build_call_expr_internal_loc (loc, IFN_GOMP_DISPATCH,
+                                                TREE_TYPE (*dispatch_call), 1,
+                                                *dispatch_call);
+
+  cp_parser_consume_semicolon_at_end_of_statement (parser);
+  OMP_DISPATCH_BODY (stmt) = dispatch_body;
+
+  return add_stmt (stmt);
+}
+
 /* Finalize #pragma omp declare variant after a fndecl has been parsed, and put
    that into "omp declare variant base" attribute.  */
 
 static tree
 cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
-                              tree attrs)
+                              tree attrs, tree parms)
 {
   matching_parens parens;
   if (!parens.require_open (parser))
@@ -49668,44 +49881,196 @@ cp_finish_omp_declare_variant (cp_parser *parser, 
cp_token *pragma_tok,
   location_t finish_loc = get_finish (varid.get_location ());
   location_t varid_loc = make_location (caret_loc, start_loc, finish_loc);
 
-  if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
-      && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
-    cp_lexer_consume_token (parser->lexer);
+  vec<tree> adjust_args_list = vNULL;
+  bool has_match = false, has_adjust_args = false;
+  location_t adjust_args_loc = UNKNOWN_LOCATION;
+  tree need_device_ptr_list = make_node (TREE_LIST);
 
-  const char *clause = "";
-  location_t match_loc = cp_lexer_peek_token (parser->lexer)->location;
-  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
-    clause = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value);
-  if (strcmp (clause, "match"))
+  do
     {
-      cp_parser_error (parser, "expected %<match%>");
-      goto fail;
-    }
+      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)
+         && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
+       cp_lexer_consume_token (parser->lexer);
 
-  cp_lexer_consume_token (parser->lexer);
+      const char *clause = "";
+      location_t match_loc = cp_lexer_peek_token (parser->lexer)->location;
+      if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+       clause
+         = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value);
 
-  if (!parens.require_open (parser))
-    goto fail;
+      enum clause
+      {
+       match,
+       adjust_args
+      } ccode;
 
-  tree ctx = cp_parser_omp_context_selector_specification (parser, true);
-  if (ctx == error_mark_node)
-    goto fail;
-  ctx = omp_check_context_selector (match_loc, ctx, false);
-  if (ctx != error_mark_node && variant != error_mark_node)
-    {
-      tree match_loc_node = maybe_wrap_with_location (integer_zero_node,
-                                                     match_loc);
-      tree loc_node = maybe_wrap_with_location (integer_zero_node, varid_loc);
-      loc_node = tree_cons (match_loc_node,
-                           build_int_cst (integer_type_node, idk),
-                           build_tree_list (loc_node, integer_zero_node));
-      attrs = tree_cons (get_identifier ("omp declare variant base"),
-                        tree_cons (variant, ctx, loc_node), attrs);
-      if (processing_template_decl)
-       ATTR_IS_DEPENDENT (attrs) = 1;
+      if (strcmp (clause, "match") == 0)
+       ccode = match;
+      else if (strcmp (clause, "adjust_args") == 0)
+       {
+         ccode = adjust_args;
+         adjust_args_loc = match_loc;
+       }
+      else
+       {
+         cp_parser_error (parser, "expected %<match%> clause");
+         goto fail;
+       }
+
+      cp_lexer_consume_token (parser->lexer);
+
+      if (!parens.require_open (parser))
+       goto fail;
+
+      if (ccode == match)
+       {
+         if (has_match)
+           error_at (match_loc, "too many %<match%> clauses");
+         has_match = true;
+         tree ctx
+           = cp_parser_omp_context_selector_specification (parser, true);
+         if (ctx == error_mark_node)
+           goto fail;
+         ctx = omp_check_context_selector (match_loc, ctx, false);
+         if (ctx != error_mark_node && variant != error_mark_node)
+           {
+             tree match_loc_node
+               = maybe_wrap_with_location (integer_zero_node, match_loc);
+             tree loc_node
+               = maybe_wrap_with_location (integer_zero_node, varid_loc);
+             loc_node
+               = tree_cons (match_loc_node,
+                            build_int_cst (integer_type_node, idk),
+                            build_tree_list (loc_node, integer_zero_node));
+             attrs = tree_cons (get_identifier ("omp declare variant base"),
+                                tree_cons (variant, ctx, loc_node), attrs);
+             if (processing_template_decl)
+               ATTR_IS_DEPENDENT (attrs) = 1;
+           }
+         if (!parens.require_close (parser))
+           goto fail;
+       }
+      else if (ccode == adjust_args)
+       {
+         has_adjust_args = true;
+         cp_token *adjust_op_tok = cp_lexer_peek_token (parser->lexer);
+         if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+             && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON))
+           {
+             const char *p = IDENTIFIER_POINTER (adjust_op_tok->u.value);
+             if (strcmp (p, "need_device_ptr") == 0
+                 || strcmp (p, "nothing") == 0)
+               {
+                 cp_lexer_consume_token (parser->lexer); // need_device_ptr
+                 cp_lexer_consume_token (parser->lexer); // :
+                 location_t arg_loc
+                   = cp_lexer_peek_token (parser->lexer)->location;
+
+                 tree arg;
+                 tree list
+                   = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_ERROR,
+                                                     NULL_TREE, NULL);
+
+                 for (tree c = list; c != NULL_TREE; c = TREE_CHAIN (c))
+                   {
+                     tree decl = TREE_PURPOSE (c);
+                     int idx;
+                     for (arg = parms, idx = 0; arg != NULL;
+                          arg = TREE_CHAIN (arg), idx++)
+                       if (TREE_VALUE (arg) == decl)
+                         break;
+                     if (arg == NULL_TREE)
+                       {
+                         error_at (arg_loc, "%qD is not a function argument",
+                                   decl);
+                         continue;
+                       }
+                     arg = TREE_VALUE (arg);
+                     if (adjust_args_list.contains (arg))
+                       {
+                         // TODO fix location
+                         error_at (arg_loc, "%qD is specified more than once",
+                                   decl);
+                         continue;
+                       }
+                     if (strcmp (p, "need_device_ptr") == 0)
+                       {
+                         bool is_ptr_or_template
+                           = TEMPLATE_PARM_P (TREE_TYPE (arg))
+                             || POINTER_TYPE_P (TREE_TYPE (arg));
+                         if (!is_ptr_or_template)
+                           {
+                             error_at (arg_loc, "%qD is not a C pointer",
+                                       decl);
+                             continue;
+                           }
+                       }
+                     adjust_args_list.safe_push (arg);
+                     if (strcmp (p, "need_device_ptr") == 0)
+                       {
+                         need_device_ptr_list = chainon (
+                           need_device_ptr_list,
+                           build_tree_list (
+                             NULL_TREE,
+                             build_int_cst (
+                               integer_type_node,
+                               idx))); // Store 0-based argument index,
+                                       // as in gimplify_call_expr
+                       }
+                   }
+               }
+             else
+               {
+                 error_at (adjust_op_tok->location,
+                           "expected %<nothing%> or %<need_device_ptr%>");
+                 goto fail;
+               }
+           }
+         else
+           {
+             error_at (adjust_op_tok->location,
+                       "expected %<nothing%> or %<need_device_ptr%> followed "
+                       "by %<:%>");
+             goto fail;
+           }
+       }
+  } while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL));
+
+  if (has_adjust_args)
+    {
+      if (!has_match)
+       {
+         error_at (adjust_args_loc,
+                   "an %<adjust_args%> clause requires a %<match%> clause");
+       }
+      else
+       {
+         tree ctx = TREE_VALUE (TREE_VALUE (attrs));
+         if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT,
+                                        OMP_TRAIT_CONSTRUCT_DISPATCH))
+           error_at (
+             adjust_args_loc,
+             "an %<adjust_args%> clause can only be specified if the "
+             "%<dispatch%> selector of the construct selector set appears "
+             "in the %<match%> clause");
+         else if (TREE_CHAIN (need_device_ptr_list) != NULL_TREE)
+           {
+             // We might not have a DECL for the variant yet. So we store the
+             // need_device_ptr list in the base function attribute, after loc
+             // nodes.
+             gcc_assert (TREE_PURPOSE (attrs)
+                         == get_identifier ("omp declare variant base"));
+             gcc_assert (TREE_PURPOSE (TREE_VALUE (attrs)) == variant);
+             TREE_VALUE (attrs) = chainon (
+               TREE_VALUE (attrs),
+               build_tree_list (
+                 NULL_TREE,
+                 build_tree_list (need_device_ptr_list,
+                                  NULL_TREE /*need_device_addr */)));
+           }
+       }
     }
 
-  parens.require_close (parser);
   cp_parser_skip_to_pragma_eol (parser, pragma_tok);
   return attrs;
 }
@@ -49715,7 +50080,8 @@ cp_finish_omp_declare_variant (cp_parser *parser, 
cp_token *pragma_tok,
    been parsed, and put that into "omp declare simd" attribute.  */
 
 static tree
-cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs)
+cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs,
+                                        tree parms)
 {
   struct cp_token_cache *ce;
   cp_omp_declare_simd_data *data = parser->omp_declare_simd;
@@ -49759,7 +50125,7 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser 
*parser, tree attrs)
        {
          gcc_assert (strcmp (kind, "variant") == 0);
          attrs
-           = cp_finish_omp_declare_variant (parser, pragma_tok, attrs);
+           = cp_finish_omp_declare_variant (parser, pragma_tok, attrs, parms);
        }
       cp_parser_pop_lexer (parser);
     }
@@ -49890,9 +50256,8 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser 
*parser, tree attrs)
                else
                  {
                    gcc_assert (strcmp (kind, "variant") == 0);
-                   attrs
-                     = cp_finish_omp_declare_variant (parser, pragma_tok,
-                                                      attrs);
+                   attrs = cp_finish_omp_declare_variant (parser, pragma_tok,
+                                                          attrs, parms);
                  }
                gcc_assert (parser->lexer != lexer);
                vec_safe_truncate (lexer->buffer, 0);
@@ -51352,7 +51717,11 @@ fail:
    #pragma omp declare target new-line
 
    OpenMP 5.0
-   #pragma omp declare variant (identifier) match (context-selector)  */
+   #pragma omp declare variant (identifier) match (context-selector)
+
+   OpenMP 5.1
+   #pragma omp declare variant (identifier) match (context-selector) \
+      adjust_args (adjust-op:argument-list)  */
 
 static bool
 cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok,
@@ -52219,6 +52588,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token 
*pragma_tok, bool *if_p)
     case PRAGMA_OMP_UNROLL:
       stmt = cp_parser_omp_unroll (parser, pragma_tok, if_p);
       break;
+    case PRAGMA_OMP_DISPATCH:
+      stmt = cp_parser_omp_dispatch (parser, pragma_tok);
+      break;
     default:
       gcc_unreachable ();
     }
@@ -52919,6 +53291,10 @@ cp_parser_pragma (cp_parser *parser, enum 
pragma_context context, bool *if_p)
                "%<#pragma omp sections%> construct");
       break;
 
+    case PRAGMA_OMP_DISPATCH:
+      cp_parser_omp_dispatch (parser, pragma_tok);
+      return true;
+
     case PRAGMA_IVDEP:
     case PRAGMA_UNROLL:
     case PRAGMA_NOVECTOR:
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 47ee7cd3ed6e..d3e6a76fd81c 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -17769,6 +17769,16 @@ tsubst_omp_clauses (tree clauses, enum 
c_omp_region_type ort,
            = tsubst_expr (OMP_CLAUSE_SIZES_LIST (oc), args, complain,
                           in_decl);
          break;
+       case OMP_CLAUSE_NOCONTEXT:
+         OMP_CLAUSE_NOCONTEXT_EXPR (nc)
+           = tsubst_expr (OMP_CLAUSE_NOCONTEXT_EXPR (oc), args, complain,
+                          in_decl);
+         break;
+       case OMP_CLAUSE_NOVARIANTS:
+         OMP_CLAUSE_NOVARIANTS_EXPR (nc)
+           = tsubst_expr (OMP_CLAUSE_NOVARIANTS_EXPR (oc), args, complain,
+                          in_decl);
+         break;
        case OMP_CLAUSE_REDUCTION:
        case OMP_CLAUSE_IN_REDUCTION:
        case OMP_CLAUSE_TASK_REDUCTION:
@@ -19481,6 +19491,16 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
       add_stmt (t);
       break;
 
+    case OMP_DISPATCH:
+      tmp = tsubst_omp_clauses (OMP_DISPATCH_CLAUSES (t), C_ORT_OMP, args,
+                               complain, in_decl);
+      stmt = RECUR (OMP_DISPATCH_BODY (t));
+      t = copy_node (t);
+      OMP_DISPATCH_BODY (t) = stmt;
+      OMP_DISPATCH_CLAUSES (t) = tmp;
+      add_stmt (t);
+      break;
+
     case OMP_ATOMIC:
       gcc_assert (OMP_ATOMIC_DEPENDENT_P (t));
       tmp = NULL_TREE;
@@ -21337,6 +21357,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
                }
              break;
 
+           case IFN_GOMP_DISPATCH:
+             ret = build_call_expr_internal_loc (EXPR_LOCATION (t),
+                                                 IFN_GOMP_DISPATCH,
+                                                 TREE_TYPE (call_args[0]), 1,
+                                                 call_args[0]);
+             RETURN (ret);
+             break;
+
            default:
              /* Unsupported internal function with arguments.  */
              gcc_unreachable ();
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 8c481fa625b2..d0c415f4692f 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -7924,6 +7924,26 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type 
ort)
          OMP_CLAUSE_FINAL_EXPR (c) = t;
          break;
 
+       case OMP_CLAUSE_NOCONTEXT:
+         t = OMP_CLAUSE_NOCONTEXT_EXPR (c);
+         t = maybe_convert_cond (t);
+         if (t == error_mark_node)
+           remove = true;
+         else if (!processing_template_decl)
+           t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+         OMP_CLAUSE_NOCONTEXT_EXPR (c) = t;
+         break;
+
+       case OMP_CLAUSE_NOVARIANTS:
+         t = OMP_CLAUSE_NOVARIANTS_EXPR (c);
+         t = maybe_convert_cond (t);
+         if (t == error_mark_node)
+           remove = true;
+         else if (!processing_template_decl)
+           t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+         OMP_CLAUSE_NOVARIANTS_EXPR (c) = t;
+         break;
+
        case OMP_CLAUSE_GANG:
          /* Operand 1 is the gang static: argument.  */
          t = OMP_CLAUSE_OPERAND (c, 1);
diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp
index 6959c9b8854d..2162805e5708 100644
--- a/gcc/testsuite/ChangeLog.omp
+++ b/gcc/testsuite/ChangeLog.omp
@@ -1,3 +1,19 @@
+2025-01-27  Paul-Antoine Arras  <par...@baylibre.com>
+
+       Backported from master:
+       2024-11-20  Paul-Antoine Arras  <par...@baylibre.com>
+
+       * g++.dg/gomp/adjust-args-1.C: New test.
+       * g++.dg/gomp/adjust-args-2.C: New test.
+       * g++.dg/gomp/adjust-args-3.C: New test.
+       * g++.dg/gomp/dispatch-1.C: New test.
+       * g++.dg/gomp/dispatch-2.C: New test.
+       * g++.dg/gomp/dispatch-3.C: New test.
+       * g++.dg/gomp/dispatch-4.C: New test.
+       * g++.dg/gomp/dispatch-5.C: New test.
+       * g++.dg/gomp/dispatch-6.C: New test.
+       * g++.dg/gomp/dispatch-7.C: New test.
+
 2025-01-27  Paul-Antoine Arras  <par...@baylibre.com>
 
        Backported from master:
diff --git a/gcc/testsuite/g++.dg/gomp/adjust-args-1.C 
b/gcc/testsuite/g++.dg/gomp/adjust-args-1.C
new file mode 100644
index 000000000000..29fde1464f44
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/adjust-args-1.C
@@ -0,0 +1,39 @@
+/* Test parsing of OMP clause adjust_args */
+/* { dg-do compile } */
+
+int b;
+
+int f0 (void *a);
+int g (void *a);
+int f1 (int);
+
+#pragma omp declare variant (f0) match (construct={target}) adjust_args 
(nothing: a) /* { dg-error "an 'adjust_args' clause can only be specified if 
the 'dispatch' selector of the construct selector set appears in the 'match' 
clause" } */
+int f2 (void *a);
+#pragma omp declare variant (f0) match (construct={dispatch,target}) 
adjust_args (need_device_ptr: a) /* { dg-error "'int f0.void..' used as a 
variant with incompatible 'construct' selector sets" } */
+int f2a (void *a);
+#pragma omp declare variant (f0) match (construct={target,dispatch}) 
adjust_args (need_device_ptr: a) /* { dg-error "'int f0.void..' used as a 
variant with incompatible 'construct' selector sets" } */
+int f2b (void *a);
+#pragma omp declare variant (f0) match 
(construct={dispatch},device={arch(gcn)}) adjust_args (need_device_ptr: a) /* { 
dg-error "'int f0.void..' used as a variant with incompatible 'construct' 
selector sets" } */
+int f2c (void *a);
+#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args 
(other: a) /* { dg-error "expected 'nothing' or 'need_device_ptr'" } */
+int f3 (int a);
+#pragma omp declare variant (f0) adjust_args (nothing: a) /* { dg-error "an 
'adjust_args' clause requires a 'match' clause" } */
+int f4 (void *a);
+#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args () 
/* { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } */
+int f5 (int a);
+#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args 
(nothing) /* { dg-error "expected 'nothing' or 'need_device_ptr' followed by 
':'" } */
+int f6 (int a);
+#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args 
(nothing:) /* { dg-error "expected unqualified-id before '\\)' token" } */
+int f7 (int a);
+#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args 
(nothing: z) /* { dg-error "'z' has not been declared" } */
+int f8 (int a);
+#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args 
(need_device_ptr: a) /* { dg-error "'a' is not a C pointer" } */
+int f9 (int a);
+#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args 
(nothing: a) adjust_args (nothing: a) /* { dg-error "'a' is specified more than 
once" } */
+int f10 (int a);
+#pragma omp declare variant (g) match (construct={dispatch}) adjust_args 
(nothing: a) adjust_args (need_device_ptr: a) /* { dg-error "'a' is specified 
more than once" } */
+int f11 (void *a);
+#pragma omp declare variant (g) match (construct={dispatch}) adjust_args 
(need_device_ptr: b) /* { dg-error "'b' is not a function argument" } */
+int f12 (void *a);
+#pragma omp declare variant (g) match (construct={dispatch}) adjust_args 
(need_device_ptr: this) /* { dg-error "expected unqualified-id before 'this'" } 
*/
+int f13 (void *a);
diff --git a/gcc/testsuite/g++.dg/gomp/adjust-args-2.C 
b/gcc/testsuite/g++.dg/gomp/adjust-args-2.C
new file mode 100644
index 000000000000..a78f06ec1937
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/adjust-args-2.C
@@ -0,0 +1,51 @@
+struct S { 
+  int a;
+  int g (const void *b);
+  #pragma omp declare variant (g) match (construct={dispatch}) adjust_args 
(need_device_ptr: b)
+  int f0(const void *b); 
+  int operator()() { return a; }
+  bool operator!() { return !a; }
+};
+
+template <typename T>
+T f0(T a, T *b);
+
+#pragma omp declare variant (f0) match (construct={dispatch}) adjust_args 
(need_device_ptr: a, b)
+template <typename T>
+T f1(T a, T *b);
+
+namespace N {
+  class C{
+    public:
+  void g(C *c);
+  #pragma omp declare variant (g) match (construct={dispatch}) adjust_args 
(need_device_ptr: c)
+  void f0(C *c);
+  };
+  void g(C *c);
+  #pragma omp declare variant (g) match (construct={dispatch}) adjust_args 
(need_device_ptr: c)
+  void f0(C *c);
+}
+
+#pragma omp declare variant (g) match (construct={dispatch}) adjust_args 
(need_device_ptr: c)
+void f3(N::C *c);
+void f4(S *&s);
+#pragma omp declare variant (f4) match (construct={dispatch}) adjust_args 
(need_device_ptr: s)
+void f5(S *&s);
+
+void test() {
+  S s, *sp;
+  N::C c;
+  int *a, b;
+  #pragma omp dispatch
+  s.f0(a);
+  #pragma omp dispatch
+  f1(b, a);
+  #pragma omp dispatch
+  c.f0(&c);
+  #pragma omp dispatch
+  N::f0(&c);
+  #pragma omp dispatch
+  f3(&c);
+  #pragma omp dispatch
+  f5(sp);
+}
diff --git a/gcc/testsuite/g++.dg/gomp/adjust-args-3.C 
b/gcc/testsuite/g++.dg/gomp/adjust-args-3.C
new file mode 100644
index 000000000000..3f9a0cd00713
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/adjust-args-3.C
@@ -0,0 +1,6 @@
+// Check that an adjust_args clause does not lead to an ICE when the match 
+// clause is missing.
+
+void f(int *, int *, int *);
+#pragma omp declare variant(f) adjust_args(need_device_ptr: xxx)  /* { 
dg-error "an 'adjust_args' clause requires a 'match' clause" } */
+void g(int *xxx, int *yyy, int *zzz);
diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-1.C 
b/gcc/testsuite/g++.dg/gomp/dispatch-1.C
new file mode 100644
index 000000000000..fb467afcd85b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/dispatch-1.C
@@ -0,0 +1,53 @@
+struct S { 
+  int a; 
+  void f0(double); 
+  int operator()() { return a; }
+  bool operator!() { return !a; }
+};
+
+int f0(int);
+template <typename T>
+T f1(T a, T b);
+void (*f2)(void);
+
+namespace N {
+  class C{};
+  void f0(C);
+  int a;
+}
+
+int test() {
+  int result;
+  double d = 5.0;
+  N::C c;
+  S s;
+  S* sp = &s;
+  int &r = result;
+  #pragma omp dispatch
+  result = f0(5);
+  #pragma omp dispatch
+  r = f0(5);
+  #pragma omp dispatch
+  N::a = ::f0(5);
+  #pragma omp dispatch
+  sp->a = f1<int>(5, 10);
+  #pragma omp dispatch
+  s.a = f1(5, 10);
+  #pragma omp dispatch
+  f2();
+  #pragma omp dispatch
+  N::f0(c);
+  #pragma omp dispatch
+  f0(c);
+  #pragma omp dispatch
+  s.f0(d);
+  #pragma omp dispatch
+  sp->f0(d);
+  #pragma omp dispatch
+  sp->f0(d);
+  #pragma omp dispatch
+  s();
+  #pragma omp dispatch
+  !s;
+  return result; 
+}
diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-2.C 
b/gcc/testsuite/g++.dg/gomp/dispatch-2.C
new file mode 100644
index 000000000000..c987a371b970
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/dispatch-2.C
@@ -0,0 +1,62 @@
+/* Test parsing of #pragma omp dispatch */
+/* { dg-do compile } */
+
+struct S {
+  int a;
+  int b;
+  virtual int f (double); 
+};
+
+int f0 (int);
+
+void f1 (void)
+{
+  int a, b;
+  double x;
+  int arr[1];
+  S s;
+
+#pragma omp dispatch
+  int c = f0 (a);      /* { dg-error "expected primary-expression before 
'int'" } */
+#pragma omp dispatch
+  int f2 (int d);      /* { dg-error "expected primary-expression before 
'int'" } */
+#pragma omp dispatch
+  a = b;       /* { dg-error "expected target-function call" } */
+#pragma omp dispatch
+  s.a = f0(a) + b;     /* { dg-error "expected ';' before '\\+' token" } */
+#pragma omp dispatch
+  b = !f0(a);  /* { dg-error "expected primary-expression before '!' token" } 
*/
+#pragma omp dispatch
+  s.b += f0(s.a);      /* { dg-error "expected '=' before '\\+=' token" } */
+#pragma omp dispatch
+#pragma omp threadprivate(a)   /* { dg-error "'#pragma' is not allowed here" } 
*/
+  a = f0(b);
+#pragma omp dispatch
+  a = s.f(x);   /* { dg-error "'f' is a virtual function but only a direct 
call is allowed in a dispatch construct" } */
+  
+#pragma omp dispatch nocontext(s) /* { dg-error "could not convert 's' from 
'S' to 'bool'" } */
+  f0(a);
+#pragma omp dispatch nocontext(a, b) /* { dg-error "expected '\\)' before ','" 
} */
+  f0(a);
+#pragma omp dispatch nocontext(a) nocontext(b) /* { dg-error "too many 
'nocontext' clauses" } */
+  f0(a);
+#pragma omp dispatch novariants(s) /* { dg-error "could not convert 's' from 
'S' to 'bool'" } */
+  f0(a);
+#pragma omp dispatch novariants(a, b) /* { dg-error "expected '\\)' before 
','" } */
+  f0(a);
+#pragma omp dispatch novariants(a) novariants(b) /* { dg-error "too many 
'novariants' clauses" } */
+  f0(a);
+#pragma omp dispatch nowait nowait /* { dg-error "too many 'nowait' clauses" } 
*/
+  f0(a);
+#pragma omp dispatch device(x) /* { dg-error "'device' id must be integral" } 
*/
+  f0(a);
+#pragma omp dispatch device(arr) /* { dg-error "'device' id must be integral" 
} */
+  f0(a);
+#pragma omp dispatch is_device_ptr(x) /* { dg-error "'is_device_ptr' variable 
is neither a pointer, nor an array nor reference to pointer" } */
+  f0(a);
+#pragma omp dispatch is_device_ptr(&x) /* { dg-error "expected unqualified-id 
before '&' token" } */
+  f0(a);
+#pragma omp dispatch depend(inout: s.f) /* { dg-error "'s.S::f' is not lvalue 
expression nor array section in 'depend' clause" } */
+  f0(a);
+
+}
diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-3.C 
b/gcc/testsuite/g++.dg/gomp/dispatch-3.C
new file mode 100644
index 000000000000..03fd7dc6f6ce
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/dispatch-3.C
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-original -fdump-tree-gimple" } */
+
+/* Check that the right call to f is wrapped in a GOMP_DISPATCH internal 
function
+   before translation and that it is stripped during gimplification. */
+
+int &f(int);
+void g(int *x)
+{
+  #pragma omp dispatch
+  x[f(1)] = f(f(2));
+  //        ^ only this call to f is a dispatch call
+}
+
+/* { dg-final { scan-tree-dump "\.GOMP_DISPATCH \\(\\*f \\(\\*f \\(2\\)\\)\\)" 
"original" } } */
+/* { dg-final { scan-tree-dump-times "\.GOMP_DISPATCH" 1 "original" } } */
+/* { dg-final { scan-tree-dump-not "\.GOMP_DISPATCH" "gimple" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-4.C 
b/gcc/testsuite/g++.dg/gomp/dispatch-4.C
new file mode 100644
index 000000000000..a0fe6c746c4b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/dispatch-4.C
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple" } */
+
+/* Check that no host-to-device pointer conversion happens for a nullptr 
+   argument. */
+
+#include <cstddef>
+
+int variant_fn(int *, int * = NULL);
+
+#pragma omp declare variant(variant_fn) match(construct={dispatch}) 
adjust_args(need_device_ptr : x, y)
+int bar(int *x, int *y = NULL);
+
+void sub(int *a, int *b)
+{
+  int x;
+  #pragma omp dispatch
+   x = bar(a);
+} 
+
+/* { dg-final { scan-tree-dump-times "__builtin_omp_get_mapped_ptr" 1 "gimple" 
} } */
+/* { dg-final { scan-tree-dump-not "__builtin_omp_get_mapped_ptr \\(OB" 
"gimple" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-5.C 
b/gcc/testsuite/g++.dg/gomp/dispatch-5.C
new file mode 100644
index 000000000000..268bbac5d766
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/dispatch-5.C
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+
+/* Check that the parser does not issue an error when a variant returns a 
+   reference. */
+
+int& variant_fn();
+
+#pragma omp declare variant(variant_fn) match(construct={target})
+int& bar();
+
+void sub(int a)
+{
+  #pragma omp dispatch
+    bar();
+  #pragma omp dispatch
+    a = bar();
+}
diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-6.C 
b/gcc/testsuite/g++.dg/gomp/dispatch-6.C
new file mode 100644
index 000000000000..675b1ec8d9ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/dispatch-6.C
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-original" } */
+
+/* Check that templates are properly handled. */
+
+template<typename T>
+T templ_var_fn(T x);
+
+#pragma omp declare variant(templ_var_fn) match(construct={dispatch}) 
adjust_args(need_device_ptr: x)
+template<typename T>
+T templ_base_fn(T x);
+
+template<typename T, typename TB>
+void f(int *y, TB x)
+{
+#pragma omp dispatch nocontext (x)
+  y = templ_base_fn<T> (y); 
+#pragma omp dispatch novariants (x)
+  y = templ_base_fn<T> (y); 
+}
+
+void bar()
+{
+  int a;
+  bool b = true;
+  f<int*,bool> (&a, b);
+}
+
+/* { dg-final { scan-tree-dump-times "y = \.GOMP_DISPATCH 
\\(templ_base_fn<int\\*> \\(y\\)\\)" 2 "original" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-7.C 
b/gcc/testsuite/g++.dg/gomp/dispatch-7.C
new file mode 100644
index 000000000000..193cca860150
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/dispatch-7.C
@@ -0,0 +1,43 @@
+// { dg-do compile { target c++11 } }
+
+
+template<typename T>
+T templ_var_fn(T x);
+
+
+template<typename T> [[omp::directive (declare variant(templ_var_fn) 
match(construct={dispatch}) adjust_args(need_device_ptr: x))]]
+T templ_base_fn(T x);
+
+template<typename T, typename TB>
+void f(int *y, TB x)
+{
+[[omp::directive (dispatch nocontext (x))]]
+  y = templ_base_fn<T> (y); 
+[[omp::directive (dispatch novariants (x))]]
+  y = templ_base_fn<T> (y); 
+}
+
+void bar()
+{
+  int a;
+  bool b = true;
+  f<int*,bool> (&a, b);
+}
+
+
+void variant_fn(int *x, int *y, int *z);
+
+[[omp::directive (declare variant(variant_fn) match(construct={dispatch}) 
adjust_args(need_device_ptr: x,y) adjust_args(nothing: z))]]
+void bar(int *x, int *y, int *z);
+
+void sub(int *x, int *y, int *z)
+{
+  [[omp::directive (dispatch is_device_ptr(y))]]
+     bar(x, y, z);
+  [[omp::directive (dispatch device(0))]]
+     bar(x, y, z);
+  [[omp::directive (dispatch nocontext(1) novariants(1))]]
+     bar(x, y, z);
+  [[omp::directive (dispatch depend(inout: x) nowait)]]
+     bar(x, y, z);
+}

Reply via email to