Hi Jakub,
there was a first version of this patch here:
https://gcc.gnu.org/pipermail/gcc-patches/2020-September/554087.html

The attached patch here is a v2 version  that adds implementation of
this part in the this[:1] functionality description in the OpenMP 5.0 spec:

 "if the [member] variable [accessed in a target region] is of a type pointer
  or reference to pointer, it is also treated as if it has appeared in a map
  clause as a zero-length array section."

Basically, referencing a pointer member 'ptr' automatically maps it with the
equivalent of 'map(this->ptr[:0])'

To achieve this, two new map kinds GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION,
and GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION were added, which are
basically split from GOMP_MAP_ATTACH and GOMP_MAP_POINTER, except now allowing
the pointer target to be NULL.

This patch has been tested for gcc, g++, gfortran (C and Fortran are not really
affected, but since omp-low.c was slightly touched, tested along for 
completeness)
and libgomp on x86_64-linux with nvptx offloading, all without regressions.

Is this okay for trunk?

Thanks,
Chung-Lin

2020-11-13  Chung-Lin Tang  <clt...@codesourcery.com>

        PR middle-end/92120

        gcc/cp/
        * cp-tree.h (finish_omp_target): New declaration.
        (set_omp_target_this_expr): Likewise.
        * lambda.c (lambda_expr_this_capture): Add call to
        set_omp_target_this_expr.
        * parser.c (cp_parser_omp_target): Factor out code, change to call
        finish_omp_target, add re-initing call to set_omp_target_this_expr.
        * semantics.c (omp_target_this_expr): New static variable.
        (omp_target_ptr_members_accessed): New static hash_map for tracking
        accessed non-static pointer-type members.
        (finish_non_static_data_member): Add call to set_omp_target_this_expr.
        Add recording of non-static pointer-type members access.
        (finish_this_expr): Add call to set_omp_target_this_expr.
        (set_omp_target_this_expr): New function to set omp_target_this_expr.
        (finish_omp_target): New function with code merged from
        cp_parser_omp_target, plus code to implement this[:1] and __closure map
        clauses for OpenMP.

        gcc/
        * omp-low.c (lower_omp_target):
        Handle GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION, and
        GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION map kinds.
        * tree-pretty-print.c (dump_omp_clause): Likewise.

        include/
        * gomp-constants.h (enum gomp_map_kind):
        Add GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION, and
        GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION map kinds.
        (GOMP_MAP_POINTER_P):
        Include GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION.

        libgomp/
        * libgomp.h (gomp_attach_pointer): Add bool parameter.
        * oacc-mem.c (acc_attach_async): Update call to gomp_attach_pointer.
        (goacc_enter_data_internal): Likewise.
        * target.c (gomp_map_vars_existing): Update assert condition to
        include GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION.
        (gomp_map_pointer): Add 'bool allow_zero_length_array_sections'
        parameter, add support for mapping a pointer with NULL target.
        (gomp_attach_pointer): Add 'bool allow_zero_length_array_sections'
        parameter, add support for attaching a pointer with NULL target.
        (gomp_map_vars_internal): Update calls to gomp_map_pointer and
        gomp_attach_pointer, add handling for
        GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION, and
        GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION cases.

        gcc/testsuite/
        * g++.dg/gomp/target-this-1.C: New testcase.
        * g++.dg/gomp/target-this-2.C: New testcase.
        * g++.dg/gomp/target-this-3.C: New testcase.
        * g++.dg/gomp/target-this-4.C: New testcase.

        libgomp/
        * testsuite/libgomp.c++/target-this-1.C: New testcase.
        * testsuite/libgomp.c++/target-this-2.C: New testcase.
        * testsuite/libgomp.c++/target-this-3.C: New testcase.
        * testsuite/libgomp.c++/target-this-4.C: New testcase.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 63724c0e84f..e45540e08f1 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7277,6 +7277,8 @@ extern void record_null_lambda_scope              (tree);
 extern void finish_lambda_scope                        (void);
 extern tree start_lambda_function              (tree fn, tree lambda_expr);
 extern void finish_lambda_function             (tree body);
+extern tree finish_omp_target                  (location_t, tree, tree, bool);
+extern void set_omp_target_this_expr           (tree);
 
 /* in tree.c */
 extern int cp_tree_operand_length              (const_tree);
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 1a1647f465e..eb09971f288 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -841,6 +841,9 @@ lambda_expr_this_capture (tree lambda, int add_capture_p)
         type cast (_expr.cast_ 5.4) to the type of 'this'. [ The cast
         ensures that the transformed expression is an rvalue. ] */
       result = rvalue (result);
+
+      /* Acknowledge to OpenMP target that 'this' was referenced.  */
+      set_omp_target_this_expr (result);
     }
 
   return result;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index efcdce04777..0277de212ce 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -41132,8 +41132,6 @@ static bool
 cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
                      enum pragma_context context, bool *if_p)
 {
-  tree *pc = NULL, stmt;
-
   if (flag_openmp)
     omp_requires_mask
       = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED);
@@ -41186,6 +41184,7 @@ cp_parser_omp_target (cp_parser *parser, cp_token 
*pragma_tok,
          keep_next_level (true);
          tree sb = begin_omp_structured_block (), ret;
          unsigned save = cp_parser_begin_omp_structured_block (parser);
+         set_omp_target_this_expr (NULL_TREE);
          switch (ccode)
            {
            case OMP_TEAMS:
@@ -41237,15 +41236,9 @@ cp_parser_omp_target (cp_parser *parser, cp_token 
*pragma_tok,
                    cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = tc;
                  }
            }
-         tree stmt = make_node (OMP_TARGET);
-         TREE_TYPE (stmt) = void_type_node;
-         OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
-         OMP_TARGET_BODY (stmt) = body;
-         OMP_TARGET_COMBINED (stmt) = 1;
-         SET_EXPR_LOCATION (stmt, pragma_tok->location);
-         add_stmt (stmt);
-         pc = &OMP_TARGET_CLAUSES (stmt);
-         goto check_clauses;
+         finish_omp_target (pragma_tok->location,
+                            cclauses[C_OMP_CLAUSE_SPLIT_TARGET], body, true);
+         return true;
        }
       else if (!flag_openmp)  /* flag_openmp_simd  */
        {
@@ -41282,49 +41275,14 @@ cp_parser_omp_target (cp_parser *parser, cp_token 
*pragma_tok,
       return false;
     }
 
-  stmt = make_node (OMP_TARGET);
-  TREE_TYPE (stmt) = void_type_node;
-
-  OMP_TARGET_CLAUSES (stmt)
-    = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
-                                "#pragma omp target", pragma_tok);
-  c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true);
-
-  pc = &OMP_TARGET_CLAUSES (stmt);
+  tree clauses = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
+                                           "#pragma omp target", pragma_tok);
+  c_omp_adjust_map_clauses (clauses, true);
   keep_next_level (true);
-  OMP_TARGET_BODY (stmt) = cp_parser_omp_structured_block (parser, if_p);
+  set_omp_target_this_expr (NULL_TREE);
+  tree body = cp_parser_omp_structured_block (parser, if_p);
 
-  SET_EXPR_LOCATION (stmt, pragma_tok->location);
-  add_stmt (stmt);
-
-check_clauses:
-  while (*pc)
-    {
-      if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc))
-         {
-         case GOMP_MAP_TO:
-         case GOMP_MAP_ALWAYS_TO:
-         case GOMP_MAP_FROM:
-         case GOMP_MAP_ALWAYS_FROM:
-         case GOMP_MAP_TOFROM:
-         case GOMP_MAP_ALWAYS_TOFROM:
-         case GOMP_MAP_ALLOC:
-         case GOMP_MAP_FIRSTPRIVATE_POINTER:
-         case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
-         case GOMP_MAP_ALWAYS_POINTER:
-         case GOMP_MAP_ATTACH_DETACH:
-           break;
-         default:
-           error_at (OMP_CLAUSE_LOCATION (*pc),
-                     "%<#pragma omp target%> with map-type other "
-                     "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
-                     "on %<map%> clause");
-           *pc = OMP_CLAUSE_CHAIN (*pc);
-           continue;
-         }
-      pc = &OMP_CLAUSE_CHAIN (*pc);
-    }
+  finish_omp_target (pragma_tok->location, clauses, body, false);
   return true;
 }
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0389198dab8..e31d4f19f43 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -61,6 +61,10 @@ static hash_map<tree, tree> *omp_private_member_map;
 static vec<tree> omp_private_member_vec;
 static bool omp_private_member_ignore_next;
 
+/* Used for OpenMP target region 'this' references.  */
+static tree omp_target_this_expr = NULL_TREE;
+
+static hash_map<tree, tree> omp_target_ptr_members_accessed;
 
 /* Deferred Access Checking Overview
    ---------------------------------
@@ -1958,6 +1962,7 @@ tree
 finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 {
   gcc_assert (TREE_CODE (decl) == FIELD_DECL);
+  tree orig_object = object;
   bool try_omp_private = !object && omp_private_member_map;
   tree ret;
 
@@ -1996,6 +2001,14 @@ finish_non_static_data_member (tree decl, tree object, 
tree qualifying_scope)
       return error_mark_node;
     }
 
+  if (orig_object == NULL_TREE)
+    {
+      tree this_expr = TREE_OPERAND (object, 0);
+
+      /* Acknowledge to OpenMP target that 'this' was referenced.  */
+      set_omp_target_this_expr (this_expr);
+    }
+
   if (current_class_ptr)
     TREE_USED (current_class_ptr) = 1;
   if (processing_template_decl)
@@ -2056,6 +2069,14 @@ finish_non_static_data_member (tree decl, tree object, 
tree qualifying_scope)
       if (v)
        ret = convert_from_reference (*v);
     }
+  else if (omp_target_this_expr
+          && TREE_TYPE (ret)
+          && POINTER_TYPE_P (TREE_TYPE (ret)))
+    {
+      if (omp_target_ptr_members_accessed.get (decl) == NULL)
+       omp_target_ptr_members_accessed.put (decl, ret);
+    }
+
   return ret;
 }
 
@@ -2783,8 +2804,15 @@ finish_this_expr (void)
     }
 
   if (result)
-    /* The keyword 'this' is a prvalue expression.  */
-    return rvalue (result);
+    {
+      /* The keyword 'this' is a prvalue expression.  */
+      result = rvalue (result);
+
+      /* Acknowledge to OpenMP target that 'this' was referenced.  */
+      set_omp_target_this_expr (result);
+
+      return result;
+    }
 
   tree fn = current_nonlambda_function ();
   if (fn && DECL_STATIC_FUNCTION_P (fn))
@@ -8652,6 +8680,193 @@ finish_omp_construct (enum tree_code code, tree body, 
tree clauses)
   return add_stmt (stmt);
 }
 
+void
+set_omp_target_this_expr (tree this_val)
+{
+  omp_target_this_expr = this_val;
+
+  if (omp_target_this_expr == NULL_TREE)
+    omp_target_ptr_members_accessed.empty ();
+}
+
+tree
+finish_omp_target (location_t loc, tree clauses, tree body, bool combined_p)
+{
+  tree last_inserted_clause = NULL_TREE;
+  if (DECL_LAMBDA_FUNCTION_P (current_function_decl))
+    {
+      tree closure = DECL_ARGUMENTS (current_function_decl);
+      tree c = build_omp_clause (loc, OMP_CLAUSE_MAP);
+      OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_TO);
+      OMP_CLAUSE_DECL (c) = build_simple_mem_ref (closure);
+      OMP_CLAUSE_SIZE (c) = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (closure)));
+
+      tree c2 = build_omp_clause (loc, OMP_CLAUSE_MAP);
+      OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER);
+      OMP_CLAUSE_DECL (c2) = closure;
+      OMP_CLAUSE_SIZE (c2) = size_zero_node;
+      OMP_CLAUSE_CHAIN (c2) = clauses;
+      OMP_CLAUSE_CHAIN (c) = c2;
+      last_inserted_clause = c2;
+      clauses = c;
+
+      if (omp_target_this_expr)
+       {
+         STRIP_NOPS (omp_target_this_expr);
+         gcc_assert (DECL_HAS_VALUE_EXPR_P (omp_target_this_expr));
+         omp_target_this_expr = DECL_VALUE_EXPR (omp_target_this_expr);
+         tree c3 = build_omp_clause (loc, OMP_CLAUSE_MAP);
+         OMP_CLAUSE_SET_MAP_KIND (c3, GOMP_MAP_TOFROM);
+         OMP_CLAUSE_DECL (c3) = build_simple_mem_ref (omp_target_this_expr);
+         OMP_CLAUSE_SIZE (c3)
+           = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (omp_target_this_expr)));
+
+         tree c4 = build_omp_clause (loc, OMP_CLAUSE_MAP);
+         OMP_CLAUSE_SET_MAP_KIND (c4, GOMP_MAP_ALWAYS_POINTER);
+
+         OMP_CLAUSE_DECL (c4) = omp_target_this_expr;
+         OMP_CLAUSE_SIZE (c4) = size_zero_node;
+
+         OMP_CLAUSE_CHAIN (c3) = c4;
+         OMP_CLAUSE_CHAIN (c4) = OMP_CLAUSE_CHAIN (c2);
+         OMP_CLAUSE_CHAIN (c2) = c3;
+         last_inserted_clause = c4;
+         omp_target_this_expr = NULL_TREE;
+       }
+    }
+  else if (omp_target_this_expr)
+    {
+      tree c = build_omp_clause (loc, OMP_CLAUSE_MAP);
+      OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_TOFROM);
+      OMP_CLAUSE_DECL (c) = build_simple_mem_ref (omp_target_this_expr);
+      OMP_CLAUSE_SIZE (c)
+       = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (omp_target_this_expr)));
+
+      tree c2 = build_omp_clause (loc, OMP_CLAUSE_MAP);
+      OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER);
+      STRIP_NOPS (omp_target_this_expr);
+      OMP_CLAUSE_DECL (c2) = omp_target_this_expr;
+      OMP_CLAUSE_SIZE (c2) = size_zero_node;
+      OMP_CLAUSE_CHAIN (c2) = clauses;
+      OMP_CLAUSE_CHAIN (c) = c2;
+      clauses = c;
+      last_inserted_clause = c2;
+      omp_target_this_expr = NULL_TREE;
+    }
+
+  if (last_inserted_clause && !omp_target_ptr_members_accessed.is_empty ())
+    for (hash_map<tree, tree>::iterator i
+          = omp_target_ptr_members_accessed.begin ();
+        i != omp_target_ptr_members_accessed.end (); ++i)
+      {
+       /* For each referenced member that is of pointer or reference-to-pointer
+          type, create the equivalent of map(alloc:this->ptr[:0]).  */
+       tree field_decl = (*i).first;
+       tree ptr_member = (*i).second;
+       if (!cxx_mark_addressable (ptr_member))
+         gcc_unreachable ();
+
+       if (TREE_CODE (TREE_TYPE (field_decl)) == REFERENCE_TYPE)
+         {
+           /* For reference to pointers, we need to map the referenced pointer
+              first for things to be correct.  */
+           tree ptr_member_type = TREE_TYPE (ptr_member);
+
+           /* Map pointer target as zero-length array section.  */
+           tree c = build_omp_clause (loc, OMP_CLAUSE_MAP);
+           OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_ALLOC);
+           OMP_CLAUSE_DECL (c)
+             = build1 (INDIRECT_REF, TREE_TYPE (ptr_member_type), ptr_member);
+           OMP_CLAUSE_SIZE (c) = size_zero_node;
+           OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1;
+
+           /* Map pointer to zero-length array section.  */
+           tree c2 = build_omp_clause (loc, OMP_CLAUSE_MAP);
+           OMP_CLAUSE_SET_MAP_KIND
+             (c2, GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION);
+           OMP_CLAUSE_DECL (c2) = ptr_member;
+           OMP_CLAUSE_SIZE (c2) = size_zero_node;
+
+           /* Attach reference-to-pointer field to pointer.  */
+           tree c3 = build_omp_clause (loc, OMP_CLAUSE_MAP);
+           OMP_CLAUSE_SET_MAP_KIND (c3, GOMP_MAP_ATTACH);
+           OMP_CLAUSE_DECL (c3) = TREE_OPERAND (ptr_member, 0);
+           OMP_CLAUSE_SIZE (c3) = size_zero_node;
+
+           OMP_CLAUSE_CHAIN (c) = c2;
+           OMP_CLAUSE_CHAIN (c2) = c3;
+           OMP_CLAUSE_CHAIN (c3) = OMP_CLAUSE_CHAIN (last_inserted_clause);
+
+           OMP_CLAUSE_CHAIN (last_inserted_clause) = c;
+           last_inserted_clause = c3;
+         }
+       else if (TREE_CODE (TREE_TYPE (field_decl)) == POINTER_TYPE)
+         {
+           /* Map pointer target as zero-length array section.  */
+           tree c = build_omp_clause (loc, OMP_CLAUSE_MAP);
+           OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_ALLOC);
+           OMP_CLAUSE_DECL (c)
+             = build2 (MEM_REF, char_type_node, ptr_member,
+                       build_int_cst (build_pointer_type (char_type_node), 0));
+           OMP_CLAUSE_SIZE (c) = size_zero_node;
+           OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1;
+
+           /* Attach zero-length array section to pointer.  */
+           tree c2 = build_omp_clause (loc, OMP_CLAUSE_MAP);
+           OMP_CLAUSE_SET_MAP_KIND
+             (c2, GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION);
+           OMP_CLAUSE_DECL (c2) = ptr_member;
+           OMP_CLAUSE_SIZE (c2) = size_zero_node;
+
+           OMP_CLAUSE_CHAIN (c) = c2;
+           OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (last_inserted_clause);
+           OMP_CLAUSE_CHAIN (last_inserted_clause) = c;
+           last_inserted_clause = c2;
+         }
+       else
+         gcc_unreachable ();
+      }
+
+  tree stmt = make_node (OMP_TARGET);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_TARGET_CLAUSES (stmt) = clauses;
+  OMP_TARGET_BODY (stmt) = body;
+  OMP_TARGET_COMBINED (stmt) = combined_p;
+  SET_EXPR_LOCATION (stmt, loc);
+
+  tree c = clauses;
+  while (c)
+    {
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
+       switch (OMP_CLAUSE_MAP_KIND (c))
+         {
+         case GOMP_MAP_TO:
+         case GOMP_MAP_ALWAYS_TO:
+         case GOMP_MAP_FROM:
+         case GOMP_MAP_ALWAYS_FROM:
+         case GOMP_MAP_TOFROM:
+         case GOMP_MAP_ALWAYS_TOFROM:
+         case GOMP_MAP_ALLOC:
+         case GOMP_MAP_FIRSTPRIVATE_POINTER:
+         case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
+         case GOMP_MAP_ALWAYS_POINTER:
+         case GOMP_MAP_ATTACH_DETACH:
+         case GOMP_MAP_ATTACH:
+         case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
+         case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
+           break;
+         default:
+           error_at (OMP_CLAUSE_LOCATION (c),
+                     "%<#pragma omp target%> with map-type other "
+                     "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
+                     "on %<map%> clause");
+           break;
+         }
+      c = OMP_CLAUSE_CHAIN (c);
+    }
+  return add_stmt (stmt);
+}
+
 tree
 finish_omp_parallel (tree clauses, tree body)
 {
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index ed805e2e6d2..f63a14d1106 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -11652,6 +11652,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
          case GOMP_MAP_ALWAYS_POINTER:
          case GOMP_MAP_ATTACH:
          case GOMP_MAP_DETACH:
+         case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
+         case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
            break;
          case GOMP_MAP_IF_PRESENT:
          case GOMP_MAP_FORCE_ALLOC:
diff --git a/gcc/testsuite/g++.dg/gomp/target-this-1.C 
b/gcc/testsuite/g++.dg/gomp/target-this-1.C
new file mode 100644
index 00000000000..de93a3e5e57
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/target-this-1.C
@@ -0,0 +1,33 @@
+// { dg-do compile }
+// { dg-additional-options "-fdump-tree-gimple" }
+extern "C" void abort ();
+
+struct S
+{
+  int a, b, c, d;
+
+  int sum (void)
+  {
+    int val = 0;
+    val += a + b + this->c + this->d;
+    return val;
+  }
+
+  int sum_offload (void)
+  {
+    int val = 0;
+    #pragma omp target map(val)
+    val += a + b + this->c + this->d;
+    return val;
+  }
+};
+
+int main (void)
+{
+  S s = { 1, 2, 3, 4 };
+  if (s.sum () != s.sum_offload ())
+    abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump {map\(tofrom:\*this \[len: [0-9]+\]\) 
map\(firstprivate:this \[pointer assign, bias: 0\]\)} "gimple" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/target-this-2.C 
b/gcc/testsuite/g++.dg/gomp/target-this-2.C
new file mode 100644
index 00000000000..a5e832130fb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/target-this-2.C
@@ -0,0 +1,49 @@
+// We use 'auto' without a function return type, so specify dialect here
+// { dg-do compile }
+// { dg-additional-options "-std=c++14 -fdump-tree-gimple" }
+
+extern "C" void abort ();
+
+struct T
+{
+  int x, y;
+
+  auto sum_func (int n)
+  {
+    auto fn = [=](int m) -> int
+      {
+       int v;
+       v = (x + y) * n + m;
+       return v;
+      };
+    return fn;
+  }
+
+  auto sum_func_offload (int n)
+  {
+    auto fn = [=](int m) -> int
+      {
+       int v;
+       #pragma omp target map(from:v)
+       v = (x + y) * n + m;
+       return v;
+      };
+    return fn;
+  }
+
+};
+
+int main (void)
+{
+  T a = { 1, 2 };
+
+  auto s1 = a.sum_func (3);
+  auto s2 = a.sum_func_offload (3);
+
+  if (s1 (1) != s2 (1))
+    abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump {map\(to:\*__closure \[len: [0-9]+\]\) 
map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ 
\[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 
0\]\)} "gimple" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/target-this-3.C 
b/gcc/testsuite/g++.dg/gomp/target-this-3.C
new file mode 100644
index 00000000000..208ea079b95
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/target-this-3.C
@@ -0,0 +1,105 @@
+// { dg-do compile }
+// { dg-additional-options "-fdump-tree-gimple" }
+#include <cstdlib>
+#include <cstring>
+extern "C" void abort ();
+
+struct S
+{
+  int * ptr;
+  int ptr_len;
+
+  int *&refptr;
+  int refptr_len;
+
+  bool set_ptr (int n)
+  {
+    bool mapped;
+    #pragma omp target map(from:mapped)
+    {
+      if (ptr != NULL)
+       for (int i = 0; i < ptr_len; i++)
+         ptr[i] = n;
+      mapped = (ptr != NULL);
+    }
+    return mapped;
+  }
+
+  bool set_refptr (int n)
+  {
+    bool mapped;
+    #pragma omp target map(from:mapped)
+    {
+      if (refptr != NULL)
+       for (int i = 0; i < refptr_len; i++)
+         refptr[i] = n;
+      mapped = (refptr != NULL);
+    }
+    return mapped;
+  }
+};
+
+int main (void)
+{
+  #define N 10
+  int *ptr1 = new int[N];
+  int *ptr2 = new int[N];
+
+  memset (ptr1, 0, sizeof (int) * N);
+  memset (ptr2, 0, sizeof (int) * N);
+
+  S s = { ptr1, N, ptr2, N };
+
+  bool mapped;
+  int val = 123;
+
+  mapped = s.set_ptr (val);
+  if (mapped)
+    abort ();
+  if (s.ptr != ptr1)
+    abort ();
+  for (int i = 0; i < N; i++)
+    if (ptr1[i] != 0)
+      abort ();
+
+  mapped = s.set_refptr (val);
+  if (mapped)
+    abort ();
+  if (s.refptr != ptr2)
+    abort ();
+  for (int i = 0; i < N; i++)
+    if (ptr2[i] != 0)
+      abort ();
+
+  #pragma omp target data map(ptr1[:N])
+  mapped = s.set_ptr (val);
+
+  if (!mapped)
+    abort ();
+  if (s.set_refptr (0))
+    abort ();
+  if (s.ptr != ptr1 || s.refptr != ptr2)
+    abort ();
+  for (int i = 0; i < N; i++)
+    if (ptr1[i] != val)
+      abort ();
+
+  #pragma omp target data map(ptr2[:N])
+  mapped = s.set_refptr (val);
+
+  if (!mapped)
+    abort ();
+  if (s.set_ptr (0))
+    abort ();
+  if (s.ptr != ptr1 || s.refptr != ptr2)
+    abort ();
+  for (int i = 0; i < N; i++)
+    if (ptr2[i] != val)
+      abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* 
map\(tofrom:\*this \[len: [0-9]+\]\) map\(firstprivate:this \[pointer assign, 
bias: 0\]\) map\(alloc:\*this->refptr \[pointer assign, zero-length array 
section, bias: 0\]\) map\(attach:this->refptr \[bias: 0\]\) map\(from:mapped 
\[len: [0-9]+\]\) map\(alloc:\*_[0-9+] \[len: 0\]\) firstprivate\(n\)} "gimple" 
} } */
+
+/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* 
map\(tofrom:\*this \[len: [0-9]+\]\) map\(firstprivate:this \[pointer assign, 
bias: 0\]\) map\(attach_zero_length_array_section:this->ptr \[bias: 0\]\) 
map\(from:mapped \[len: [0-9]+\]\) map\(alloc:MEM.* \[len: 0\]\) 
firstprivate\(n\)} "gimple" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/target-this-4.C 
b/gcc/testsuite/g++.dg/gomp/target-this-4.C
new file mode 100644
index 00000000000..f42cf384541
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/target-this-4.C
@@ -0,0 +1,107 @@
+// We use 'auto' without a function return type, so specify dialect here
+// { dg-additional-options "-std=c++14 -fdump-tree-gimple" }
+#include <cstdlib>
+#include <cstring>
+
+struct T
+{
+  int *ptr;
+  int ptr_len;
+
+  int *&refptr;
+  int refptr_len;
+
+  auto set_ptr_func (int n)
+  {
+    auto fn = [=](void) -> bool
+      {
+       bool mapped;
+       #pragma omp target map(from:mapped)
+       {
+         if (ptr)
+           for (int i = 0; i < ptr_len; i++)
+             ptr[i] = n;
+         mapped = (ptr != NULL);
+       }
+       return mapped;
+      };
+    return fn;
+  }
+
+  auto set_refptr_func (int n)
+  {
+    auto fn = [=](void) -> bool
+      {
+       bool mapped;
+       #pragma omp target map(from:mapped)
+       {
+         if (refptr)
+           for (int i = 0; i < refptr_len; i++)
+             refptr[i] = n;
+         mapped = (refptr != NULL);
+       }
+       return mapped;
+      };
+    return fn;
+  }
+};
+
+int main (void)
+{
+  #define N 10
+  int *ptr1 = new int[N];
+  int *ptr2 = new int[N];
+
+  memset (ptr1, 0, sizeof (int) * N);
+  memset (ptr2, 0, sizeof (int) * N);
+
+  T a = { ptr1, N, ptr2, N };
+
+  auto p1 = a.set_ptr_func (1);
+  auto r2 = a.set_refptr_func (2);
+
+  if (p1 ())
+    abort ();
+  if (r2 ())
+    abort ();
+
+  if (a.ptr != ptr1)
+    abort ();
+  if (a.refptr != ptr2)
+    abort ();
+
+  for (int i = 0; i < N; i++)
+    if (ptr1[i] != 0)
+      abort ();
+
+  for (int i = 0; i < N; i++)
+    if (ptr2[i] != 0)
+      abort ();
+
+  #pragma omp target data map(ptr1[:N], ptr2[:N])
+  {
+    if (!p1 ())
+      abort ();
+    if (!r2 ())
+      abort ();
+  }
+
+  if (a.ptr != ptr1)
+    abort ();
+  if (a.refptr != ptr2)
+    abort ();
+
+  for (int i = 0; i < N; i++)
+    if (ptr1[i] != 1)
+      abort ();
+
+  for (int i = 0; i < N; i++)
+    if (ptr2[i] != 2)
+      abort ();
+
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* 
map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer 
assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) 
map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) 
map\(attach_zero_length_array_section:_[0-9]+->ptr \[bias: 0\]\) 
map\(from:mapped \[len: 1\]\) map\(alloc:MEM.* \[len: 0\]\) firstprivate\(n\) 
map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 
0\]\)} "gimple" } } */
+
+/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* 
map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer 
assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) 
map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) 
map\(alloc:\*_[0-9]+->refptr \[pointer assign, zero-length array section, bias: 
0\]\) map\(attach:_3->refptr \[bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) 
map\(alloc:\*_[0-9]+ \[len: 0\]\) firstprivate\(n\) map\(alloc:MEM.* \[len: 
0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\)} "gimple" } } */
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 318f048bcff..f6063923b55 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -798,6 +798,7 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, 
dump_flags_t flags)
        {
        case GOMP_MAP_ALLOC:
        case GOMP_MAP_POINTER:
+       case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
          pp_string (pp, "alloc");
          break;
        case GOMP_MAP_IF_PRESENT:
@@ -876,6 +877,9 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, 
dump_flags_t flags)
        case GOMP_MAP_ATTACH_DETACH:
          pp_string (pp, "attach_detach");
          break;
+       case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
+         pp_string (pp, "attach_zero_length_array_section");
+         break;
        default:
          gcc_unreachable ();
        }
@@ -894,6 +898,9 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, 
dump_flags_t flags)
            case GOMP_MAP_ALWAYS_POINTER:
              pp_string (pp, " [pointer assign, bias: ");
              break;
+           case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
+             pp_string (pp, " [pointer assign, zero-length array section, 
bias: ");
+             break;
            case GOMP_MAP_TO_PSET:
              pp_string (pp, " [pointer set, len: ");
              break;
@@ -901,6 +908,7 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, 
dump_flags_t flags)
            case GOMP_MAP_DETACH:
            case GOMP_MAP_FORCE_DETACH:
            case GOMP_MAP_ATTACH_DETACH:
+           case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
              pp_string (pp, " [bias: ");
              break;
            default:
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 309cbcadd83..f541ac0cba4 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -132,6 +132,11 @@ enum gomp_map_kind
        No refcount is bumped by this, and the store is done unconditionally.  
*/
     GOMP_MAP_ALWAYS_POINTER =          (GOMP_MAP_FLAG_SPECIAL_2
                                         | GOMP_MAP_FLAG_SPECIAL | 1),
+    /* Like GOMP_MAP_POINTER, but allow zero-length array section, i.e. set to
+       NULL if target is not mapped.  */
+    GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION
+      =                                        (GOMP_MAP_FLAG_SPECIAL_2
+                                        | GOMP_MAP_FLAG_SPECIAL | 2),
     /* Forced deallocation of zero length array section.  */
     GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION
       =                                        (GOMP_MAP_FLAG_SPECIAL_2
@@ -152,6 +157,12 @@ enum gomp_map_kind
     GOMP_MAP_FORCE_DETACH =            (GOMP_MAP_DEEP_COPY
                                         | GOMP_MAP_FLAG_FORCE | 1),
 
+    /* Like GOMP_MAP_ATTACH, but allow attaching to zero-length array sections
+       (i.e. set to NULL when array section is not mapped) Currently only used
+       by OpenMP.  */
+    GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION
+      =                                        (GOMP_MAP_DEEP_COPY | 2),
+
     /* Internal to GCC, not used in libgomp.  */
     /* Do not map, but pointer assign a pointer instead.  */
     GOMP_MAP_FIRSTPRIVATE_POINTER =    (GOMP_MAP_LAST | 1),
@@ -175,7 +186,8 @@ enum gomp_map_kind
   ((X) == GOMP_MAP_ALWAYS_POINTER)
 
 #define GOMP_MAP_POINTER_P(X) \
-  ((X) == GOMP_MAP_POINTER)
+  ((X) == GOMP_MAP_POINTER \
+   || (X) == GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION)
 
 #define GOMP_MAP_ALWAYS_TO_P(X) \
   (((X) == GOMP_MAP_ALWAYS_TO) || ((X) == GOMP_MAP_ALWAYS_TOFROM))
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index 0cc3f4d406b..28c507fcb46 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -1181,7 +1181,7 @@ extern uintptr_t gomp_map_val (struct target_mem_desc *, 
void **, size_t);
 extern void gomp_attach_pointer (struct gomp_device_descr *,
                                 struct goacc_asyncqueue *, splay_tree,
                                 splay_tree_key, uintptr_t, size_t,
-                                struct gomp_coalesce_buf *);
+                                struct gomp_coalesce_buf *, bool);
 extern void gomp_detach_pointer (struct gomp_device_descr *,
                                 struct goacc_asyncqueue *, splay_tree_key,
                                 uintptr_t, bool, struct gomp_coalesce_buf *);
diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c
index 4c8f0e0828e..3c5db96632d 100644
--- a/libgomp/oacc-mem.c
+++ b/libgomp/oacc-mem.c
@@ -939,7 +939,7 @@ acc_attach_async (void **hostaddr, int async)
     }
 
   gomp_attach_pointer (acc_dev, aq, &acc_dev->mem_map, n, (uintptr_t) hostaddr,
-                      0, NULL);
+                      0, NULL, false);
 
   gomp_mutex_unlock (&acc_dev->lock);
 }
@@ -1143,7 +1143,7 @@ goacc_enter_data_internal (struct gomp_device_descr 
*acc_dev, size_t mapnum,
          if ((kinds[i] & 0xff) == GOMP_MAP_ATTACH)
            {
              gomp_attach_pointer (acc_dev, aq, &acc_dev->mem_map, n,
-                                  (uintptr_t) h, s, NULL);
+                                  (uintptr_t) h, s, NULL, false);
              /* OpenACC 'attach'/'detach' doesn't affect structured/dynamic
                 reference counts ('n->refcount', 'n->dynamic_refcount').  */
            }
@@ -1161,7 +1161,8 @@ goacc_enter_data_internal (struct gomp_device_descr 
*acc_dev, size_t mapnum,
                splay_tree_key m
                  = lookup_host (acc_dev, hostaddrs[j], sizeof (void *));
                gomp_attach_pointer (acc_dev, aq, &acc_dev->mem_map, m,
-                                    (uintptr_t) hostaddrs[j], sizes[j], NULL);
+                                    (uintptr_t) hostaddrs[j], sizes[j], NULL,
+                                    false);
              }
 
          bool processed = false;
diff --git a/libgomp/target.c b/libgomp/target.c
index 6152f58e13d..50f1d5f9b37 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -371,7 +371,8 @@ gomp_map_vars_existing (struct gomp_device_descr *devicep,
                        unsigned char kind, bool always_to_flag,
                        struct gomp_coalesce_buf *cbuf)
 {
-  assert (kind != GOMP_MAP_ATTACH);
+  assert (kind != GOMP_MAP_ATTACH
+         || kind != GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION);
 
   tgt_var->key = oldn;
   tgt_var->copy_from = GOMP_MAP_COPY_FROM_P (kind);
@@ -412,7 +413,8 @@ get_kind (bool short_mapkind, void *kinds, int idx)
 static void
 gomp_map_pointer (struct target_mem_desc *tgt, struct goacc_asyncqueue *aq,
                  uintptr_t host_ptr, uintptr_t target_offset, uintptr_t bias,
-                 struct gomp_coalesce_buf *cbuf)
+                 struct gomp_coalesce_buf *cbuf,
+                 bool allow_zero_length_array_sections)
 {
   struct gomp_device_descr *devicep = tgt->device_descr;
   struct splay_tree_s *mem_map = &devicep->mem_map;
@@ -434,16 +436,24 @@ gomp_map_pointer (struct target_mem_desc *tgt, struct 
goacc_asyncqueue *aq,
   splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   if (n == NULL)
     {
-      gomp_mutex_unlock (&devicep->lock);
-      gomp_fatal ("Pointer target of array section wasn't mapped");
-    }
-  cur_node.host_start -= n->host_start;
-  cur_node.tgt_offset
-    = n->tgt->tgt_start + n->tgt_offset + cur_node.host_start;
-  /* At this point tgt_offset is target address of the
-     array section.  Now subtract bias to get what we want
-     to initialize the pointer with.  */
-  cur_node.tgt_offset -= bias;
+      if (allow_zero_length_array_sections)
+       cur_node.tgt_offset = 0;
+      else
+       {
+         gomp_mutex_unlock (&devicep->lock);
+         gomp_fatal ("Pointer target of array section wasn't mapped");
+       }
+    }
+  else
+    {
+      cur_node.host_start -= n->host_start;
+      cur_node.tgt_offset
+       = n->tgt->tgt_start + n->tgt_offset + cur_node.host_start;
+      /* At this point tgt_offset is target address of the
+        array section.  Now subtract bias to get what we want
+        to initialize the pointer with.  */
+      cur_node.tgt_offset -= bias;
+    }
   gomp_copy_host2dev (devicep, aq, (void *) (tgt->tgt_start + target_offset),
                      (void *) &cur_node.tgt_offset, sizeof (void *), cbuf);
 }
@@ -514,7 +524,8 @@ attribute_hidden void
 gomp_attach_pointer (struct gomp_device_descr *devicep,
                     struct goacc_asyncqueue *aq, splay_tree mem_map,
                     splay_tree_key n, uintptr_t attach_to, size_t bias,
-                    struct gomp_coalesce_buf *cbufp)
+                    struct gomp_coalesce_buf *cbufp,
+                    bool allow_zero_length_array_sections)
 {
   struct splay_tree_key_s s;
   size_t size, idx;
@@ -566,11 +577,21 @@ gomp_attach_pointer (struct gomp_device_descr *devicep,
 
       if (!tn)
        {
-         gomp_mutex_unlock (&devicep->lock);
-         gomp_fatal ("pointer target not mapped for attach");
+         if (allow_zero_length_array_sections)
+           {
+             /* When allowing attachment to zero-length array sections, we
+                allow attaching to NULL pointers when the target region is not
+                mapped.  */
+             data = 0;
+           }
+         else
+           {
+             gomp_mutex_unlock (&devicep->lock);
+             gomp_fatal ("pointer target not mapped for attach");
+           }
        }
-
-      data = tn->tgt->tgt_start + tn->tgt_offset + target - tn->host_start;
+      else
+       data = tn->tgt->tgt_start + tn->tgt_offset + target - tn->host_start;
 
       gomp_debug (1,
                  "%s: attaching host %p, target %p (struct base %p) to %p\n",
@@ -824,7 +845,9 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep,
          has_firstprivate = true;
          continue;
        }
-      else if ((kind & typemask) == GOMP_MAP_ATTACH)
+      else if ((kind & typemask) == GOMP_MAP_ATTACH
+              || ((kind & typemask)
+                  == GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION))
        {
          tgt->list[i].key = NULL;
          has_firstprivate = true;
@@ -1070,7 +1093,7 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep,
                                      (uintptr_t) *(void **) hostaddrs[j],
                                      k->tgt_offset + ((uintptr_t) hostaddrs[j]
                                                       - k->host_start),
-                                     sizes[j], cbufp);
+                                     sizes[j], cbufp, false);
                  }
              }
            i = j - 1;
@@ -1197,6 +1220,7 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep,
                  ++i;
                continue;
              case GOMP_MAP_ATTACH:
+             case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
                {
                  cur_node.host_start = (uintptr_t) hostaddrs[i];
                  cur_node.host_end = cur_node.host_start + sizeof (void *);
@@ -1213,9 +1237,12 @@ gomp_map_vars_internal (struct gomp_device_descr 
*devicep,
                         structured/dynamic reference counts ('n->refcount',
                         'n->dynamic_refcount').  */
 
+                     bool zlas
+                       = ((kind & typemask)
+                          == GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION);
                      gomp_attach_pointer (devicep, aq, mem_map, n,
                                           (uintptr_t) hostaddrs[i], sizes[i],
-                                          cbufp);
+                                          cbufp, zlas);
                    }
                  else if ((pragma_kind & GOMP_MAP_VARS_OPENACC) != 0)
                    {
@@ -1298,9 +1325,12 @@ gomp_map_vars_internal (struct gomp_device_descr 
*devicep,
                                        k->host_end - k->host_start, cbufp);
                    break;
                  case GOMP_MAP_POINTER:
-                   gomp_map_pointer (tgt, aq,
-                                     (uintptr_t) *(void **) k->host_start,
-                                     k->tgt_offset, sizes[i], cbufp);
+                 case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:
+                   gomp_map_pointer
+                     (tgt, aq, (uintptr_t) *(void **) k->host_start,
+                      k->tgt_offset, sizes[i], cbufp,
+                      ((kind & typemask)
+                       == GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION));
                    break;
                  case GOMP_MAP_TO_PSET:
                    gomp_copy_host2dev (devicep, aq,
@@ -1335,7 +1365,7 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep,
                                              k->tgt_offset
                                              + ((uintptr_t) hostaddrs[j]
                                                 - k->host_start),
-                                             sizes[j], cbufp);
+                                             sizes[j], cbufp, false);
                          }
                        }
                    i = j - 1;
diff --git a/libgomp/testsuite/libgomp.c++/target-this-1.C 
b/libgomp/testsuite/libgomp.c++/target-this-1.C
new file mode 100644
index 00000000000..a591ea4c564
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-this-1.C
@@ -0,0 +1,29 @@
+extern "C" void abort ();
+
+struct S
+{
+  int a, b, c, d;
+
+  int sum (void)
+  {
+    int val = 0;
+    val += a + b + this->c + this->d;
+    return val;
+  }
+
+  int sum_offload (void)
+  {
+    int val = 0;
+    #pragma omp target map(val)
+    val += a + b + this->c + this->d;
+    return val;
+  }
+};
+
+int main (void)
+{
+  S s = { 1, 2, 3, 4 };
+  if (s.sum () != s.sum_offload ())
+    abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/target-this-2.C 
b/libgomp/testsuite/libgomp.c++/target-this-2.C
new file mode 100644
index 00000000000..8119be8c2c5
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-this-2.C
@@ -0,0 +1,47 @@
+
+// We use 'auto' without a function return type, so specify dialect here
+// { dg-additional-options "-std=c++14" }
+
+extern "C" void abort ();
+
+struct T
+{
+  int x, y;
+
+  auto sum_func (int n)
+  {
+    auto fn = [=](int m) -> int
+      {
+       int v;
+       v = (x + y) * n + m;
+       return v;
+      };
+    return fn;
+  }
+
+  auto sum_func_offload (int n)
+  {
+    auto fn = [=](int m) -> int
+      {
+       int v;
+       #pragma omp target map(from:v)
+       v = (x + y) * n + m;
+       return v;
+      };
+    return fn;
+  }
+
+};
+
+int main (void)
+{
+  T a = { 1, 2 };
+
+  auto s1 = a.sum_func (3);
+  auto s2 = a.sum_func_offload (3);
+
+  if (s1 (1) != s2 (1))
+    abort ();
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/target-this-3.C 
b/libgomp/testsuite/libgomp.c++/target-this-3.C
new file mode 100644
index 00000000000..e15f69a1623
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-this-3.C
@@ -0,0 +1,99 @@
+#include <stdio.h>
+#include <string.h>
+extern "C" void abort ();
+
+struct S
+{
+  int * ptr;
+  int ptr_len;
+
+  int *&refptr;
+  int refptr_len;
+
+  bool set_ptr (int n)
+  {
+    bool mapped;
+    #pragma omp target map(from:mapped)
+    {
+      if (ptr != NULL)
+       for (int i = 0; i < ptr_len; i++)
+         ptr[i] = n;
+      mapped = (ptr != NULL);
+    }
+    return mapped;
+  }
+
+  bool set_refptr (int n)
+  {
+    bool mapped;
+    #pragma omp target map(from:mapped)
+    {
+      if (refptr != NULL)
+       for (int i = 0; i < refptr_len; i++)
+         refptr[i] = n;
+      mapped = (refptr != NULL);
+    }
+    return mapped;
+  }
+};
+
+int main (void)
+{
+  #define N 10
+  int *ptr1 = new int[N];
+  int *ptr2 = new int[N];
+
+  memset (ptr1, 0, sizeof (int) * N);
+  memset (ptr2, 0, sizeof (int) * N);
+
+  S s = { ptr1, N, ptr2, N };
+
+  bool mapped;
+  int val = 123;
+
+  mapped = s.set_ptr (val);
+  if (mapped)
+    abort ();
+  if (s.ptr != ptr1)
+    abort ();
+  for (int i = 0; i < N; i++)
+    if (ptr1[i] != 0)
+      abort ();
+
+  mapped = s.set_refptr (val);
+  if (mapped)
+    abort ();
+  if (s.refptr != ptr2)
+    abort ();
+  for (int i = 0; i < N; i++)
+    if (ptr2[i] != 0)
+      abort ();
+
+  #pragma omp target data map(ptr1[:N])
+  mapped = s.set_ptr (val);
+
+  if (!mapped)
+    abort ();
+  if (s.set_refptr (0))
+    abort ();
+  if (s.ptr != ptr1 || s.refptr != ptr2)
+    abort ();
+  for (int i = 0; i < N; i++)
+    if (ptr1[i] != val)
+      abort ();
+
+  #pragma omp target data map(ptr2[:N])
+  mapped = s.set_refptr (val);
+
+  if (!mapped)
+    abort ();
+  if (s.set_ptr (0))
+    abort ();
+  if (s.ptr != ptr1 || s.refptr != ptr2)
+    abort ();
+  for (int i = 0; i < N; i++)
+    if (ptr2[i] != val)
+      abort ();
+
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/target-this-4.C 
b/libgomp/testsuite/libgomp.c++/target-this-4.C
new file mode 100644
index 00000000000..9f53677a240
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-this-4.C
@@ -0,0 +1,104 @@
+
+// We use 'auto' without a function return type, so specify dialect here
+// { dg-additional-options "-std=c++14" }
+#include <cstdlib>
+#include <cstring>
+
+struct T
+{
+  int *ptr;
+  int ptr_len;
+
+  int *&refptr;
+  int refptr_len;
+
+  auto set_ptr_func (int n)
+  {
+    auto fn = [=](void) -> bool
+      {
+       bool mapped;
+       #pragma omp target map(from:mapped)
+       {
+         if (ptr)
+           for (int i = 0; i < ptr_len; i++)
+             ptr[i] = n;
+         mapped = (ptr != NULL);
+       }
+       return mapped;
+      };
+    return fn;
+  }
+
+  auto set_refptr_func (int n)
+  {
+    auto fn = [=](void) -> bool
+      {
+       bool mapped;
+       #pragma omp target map(from:mapped)
+       {
+         if (refptr)
+           for (int i = 0; i < refptr_len; i++)
+             refptr[i] = n;
+         mapped = (refptr != NULL);
+       }
+       return mapped;
+      };
+    return fn;
+  }
+};
+
+int main (void)
+{
+  #define N 10
+  int *ptr1 = new int[N];
+  int *ptr2 = new int[N];
+
+  memset (ptr1, 0, sizeof (int) * N);
+  memset (ptr2, 0, sizeof (int) * N);
+
+  T a = { ptr1, N, ptr2, N };
+
+  auto p1 = a.set_ptr_func (1);
+  auto r2 = a.set_refptr_func (2);
+
+  if (p1 ())
+    abort ();
+  if (r2 ())
+    abort ();
+
+  if (a.ptr != ptr1)
+    abort ();
+  if (a.refptr != ptr2)
+    abort ();
+
+  for (int i = 0; i < N; i++)
+    if (ptr1[i] != 0)
+      abort ();
+
+  for (int i = 0; i < N; i++)
+    if (ptr2[i] != 0)
+      abort ();
+
+  #pragma omp target data map(ptr1[:N], ptr2[:N])
+  {
+    if (!p1 ())
+      abort ();
+    if (!r2 ())
+      abort ();
+  }
+
+  if (a.ptr != ptr1)
+    abort ();
+  if (a.refptr != ptr2)
+    abort ();
+
+  for (int i = 0; i < N; i++)
+    if (ptr1[i] != 1)
+      abort ();
+
+  for (int i = 0; i < N; i++)
+    if (ptr2[i] != 2)
+      abort ();
+
+  return 0;
+}

Reply via email to