commit 12294a1345d981b72ef61d285057fb4c7e378fd7
Author: Julian Brown <julian@codesourcery.com>
Date:   Wed Aug 29 18:19:44 2018 -0700

    Support C++ "this" in OpenACC directives
    
    20xx-xx-xx  Joseph Myers  <joseph@codesourcery.com>
    
    	PR C++/66053
    
    	gcc/cp/
    	* cp-tree.h (enum cxx_mark_addressable_flags): New.
    	(cxx_mark_addressable): Use it.  Adjust users.
    	* parser.c (cp_parser_omp_var_list_no_open): Handle RID_THIS.
    	* semantics.c (handle_omp_array_sections_1)
    	(handle_omp_array_sections, finish_omp_reduction_clause)
    	(finish_omp_clauses): Pass CXX_MARK_ADDRESSABLE_FLAGS_ALLOW_THIS
    	to cxx_mark_addressable.  Enforce "this" usage limitation only for
    	OpenMP.
    	* typeck.c (cp_build_array_ref): Adjust cxx_mark_addressble call.
    	(cxx_mark_addressable): Handle CXX_MARK_ADDRESSABLE_FLAGS_ALLOW_THIS.
    
    	libgomp/
    	* testsuite/libgomp.oacc-c++/this.C: New test.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 43e452c..127e15a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7214,7 +7214,24 @@ extern void cxx_print_error_function		(diagnostic_context *,
 						 struct diagnostic_info *);
 
 /* in typeck.c */
-extern bool cxx_mark_addressable		(tree, bool = false);
+
+/* Flags for cxx_mark_addressable.  */
+
+enum cxx_mark_addressable_flags
+{
+  CXX_MARK_ADDRESSABLE_FLAGS_NONE = 0,
+  /* This is for ARRAY_REF construction - in that case we don't want
+     to look through VIEW_CONVERT_EXPR from VECTOR_TYPE to ARRAY_TYPE,
+     it is fine to use ARRAY_REFs for vector subscripts on vector
+     register variables.  */
+  CXX_MARK_ADDRESSABLE_FLAGS_ARRAY_REF = 1 << 0,
+  /* Allow `current_class_ptr' to be addressable.  */
+  CXX_MARK_ADDRESSABLE_FLAGS_ALLOW_THIS = 1 << 1
+};
+
+extern bool cxx_mark_addressable		(tree,
+						 enum cxx_mark_addressable_flags flags
+						 = CXX_MARK_ADDRESSABLE_FLAGS_NONE);
 extern int string_conv_p			(const_tree, const_tree, int);
 extern tree cp_truthvalue_conversion		(tree);
 extern tree condition_conversion		(tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 92e6b40..0cf2526 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -31726,7 +31726,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 	  OMP_CLAUSE_CHAIN (u) = list;
 	  list = u;
 	}
-      else
+      else if (decl != error_mark_node)
 	list = tree_cons (decl, NULL_TREE, list);
 
     get_comma:
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 676de01..9a722df 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -4598,7 +4598,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
 		      omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 	  return error_mark_node;
 	}
-      else if (TREE_CODE (t) == PARM_DECL
+      else if (ort == C_ORT_OMP
+	       && TREE_CODE (t) == PARM_DECL
 	       && DECL_ARTIFICIAL (t)
 	       && DECL_NAME (t) == this_identifier)
 	{
@@ -5101,7 +5102,8 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort)
 	  else
 	    OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER);
 	  if (OMP_CLAUSE_MAP_KIND (c2) != GOMP_MAP_FIRSTPRIVATE_POINTER
-	      && !cxx_mark_addressable (t))
+	      && !cxx_mark_addressable (t,
+					CXX_MARK_ADDRESSABLE_FLAGS_ALLOW_THIS))
 	    return false;
 	  OMP_CLAUSE_DECL (c2) = t;
 	  t = build_fold_addr_expr (first);
@@ -5689,7 +5691,8 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
 	      if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[1]))
 		  && !TYPE_REF_P (TREE_TYPE (OMP_CLAUSE_DECL (c))))
 		cxx_mark_addressable (decl_placeholder ? decl_placeholder
-				      : OMP_CLAUSE_DECL (c));
+				      : OMP_CLAUSE_DECL (c),
+				      CXX_MARK_ADDRESSABLE_FLAGS_ALLOW_THIS);
 	      tree omp_out = placeholder;
 	      tree omp_in = decl_placeholder ? decl_placeholder
 			    : convert_from_reference (OMP_CLAUSE_DECL (c));
@@ -5715,7 +5718,8 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
 			  && TREE_CODE (stmts[4]) == DECL_EXPR);
 	      if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[3])))
 		cxx_mark_addressable (decl_placeholder ? decl_placeholder
-				      : OMP_CLAUSE_DECL (c));
+				      : OMP_CLAUSE_DECL (c),
+				      CXX_MARK_ADDRESSABLE_FLAGS_ALLOW_THIS);
 	      if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[4])))
 		cxx_mark_addressable (placeholder);
 	      tree omp_priv = decl_placeholder ? decl_placeholder
@@ -6655,7 +6659,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 	      remove = true;
 	    }
 	  else if (!processing_template_decl
-		   && !cxx_mark_addressable (t))
+		   && !cxx_mark_addressable (t,
+					     CXX_MARK_ADDRESSABLE_FLAGS_ALLOW_THIS))
 	    remove = true;
 	  break;
 
@@ -6803,7 +6808,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
 		   && (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP
 		       || (OMP_CLAUSE_MAP_KIND (c)
 			   != GOMP_MAP_FIRSTPRIVATE_POINTER))
-		   && !cxx_mark_addressable (t))
+		   && !cxx_mark_addressable (t,
+					     CXX_MARK_ADDRESSABLE_FLAGS_ALLOW_THIS))
 	    remove = true;
 	  else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 		     && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ab088a9..b24f3b2 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -3335,7 +3335,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
 	      && (TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))))
 		  != INTEGER_CST)))
 	{
-	  if (!cxx_mark_addressable (array, true))
+	  if (!cxx_mark_addressable (array,
+				     CXX_MARK_ADDRESSABLE_FLAGS_ARRAY_REF))
 	    return error_mark_node;
 	}
 
@@ -6476,16 +6477,10 @@ unary_complex_lvalue (enum tree_code code, tree arg)
 
 /* Mark EXP saying that we need to be able to take the
    address of it; it should not be allocated in a register.
-   Value is true if successful.  ARRAY_REF_P is true if this
-   is for ARRAY_REF construction - in that case we don't want
-   to look through VIEW_CONVERT_EXPR from VECTOR_TYPE to ARRAY_TYPE,
-   it is fine to use ARRAY_REFs for vector subscripts on vector
-   register variables.
-
-   C++: we do not allow `current_class_ptr' to be addressable.  */
+   Value is true if successful.  */
 
 bool
-cxx_mark_addressable (tree exp, bool array_ref_p)
+cxx_mark_addressable (tree exp, enum cxx_mark_addressable_flags flags)
 {
   tree x = exp;
 
@@ -6493,7 +6488,7 @@ cxx_mark_addressable (tree exp, bool array_ref_p)
     switch (TREE_CODE (x))
       {
       case VIEW_CONVERT_EXPR:
-	if (array_ref_p
+	if ((flags & CXX_MARK_ADDRESSABLE_FLAGS_ARRAY_REF)
 	    && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
 	    && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))))
 	  return true;
@@ -6509,7 +6504,8 @@ cxx_mark_addressable (tree exp, bool array_ref_p)
       case PARM_DECL:
 	if (x == current_class_ptr)
 	  {
-	    error ("cannot take the address of %<this%>, which is an rvalue expression");
+	    if (!(flags & CXX_MARK_ADDRESSABLE_FLAGS_ALLOW_THIS))
+	      error ("cannot take the address of %<this%>, which is an rvalue expression");
 	    TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later.  */
 	    return true;
 	  }
@@ -6552,7 +6548,7 @@ cxx_mark_addressable (tree exp, bool array_ref_p)
 
       case TARGET_EXPR:
 	TREE_ADDRESSABLE (x) = 1;
-	cxx_mark_addressable (TREE_OPERAND (x, 0));
+	cxx_mark_addressable (TREE_OPERAND (x, 0), flags);
 	return true;
 
       default:
diff --git a/libgomp/testsuite/libgomp.oacc-c++/this.C b/libgomp/testsuite/libgomp.oacc-c++/this.C
new file mode 100644
index 0000000..5e70f3d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c++/this.C
@@ -0,0 +1,43 @@
+#include <cstdlib>
+#include <iostream>
+using namespace std;
+
+class test {
+  public:
+  int a;
+
+  test ()
+  {
+    a = -1;
+#pragma acc enter data copyin (this[0:1])
+  }
+
+  ~test ()
+  {
+#pragma acc exit data delete (this[0:1])
+  }
+  
+  void set (int i)
+  {
+    a = i;
+#pragma acc update device (this[0:1])
+  }
+
+  int get ()
+  {
+#pragma acc update host (this[0:1])
+    return a;
+  }
+};
+
+int
+main ()
+{
+  test t;
+
+  t.set (4);
+  if (t.get () != 4)
+    abort ();
+
+  return 0;
+}
