]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
OpenMP: mapper [C/C++] reject w/o map usage, reject C++98, fix map decay
authorTobias Burnus <tburnus@baylibre.com>
Thu, 14 May 2026 16:23:57 +0000 (18:23 +0200)
committerTobias Burnus <tburnus@baylibre.com>
Thu, 14 May 2026 16:23:57 +0000 (18:23 +0200)
This commit adds a check for the following 'declare mapper restriction:
"At least one map clause that maps var or at least one element of var is
 required."

It additionally fixes a bug in the map-decay code, which did not handle
map modifiers like 'always' when specified in the declare mapper's map
clause.

For C++, some checks are now also run when templates are involved.
Additionally, it turned out that the internal use of constexpr caused
bogus errors when compiled with -std=c++98; therefore, a sorry is now
shown. Solution is to use -std=c++11 or higher.

gcc/c-family/ChangeLog:

* c-omp.cc (omp_map_decayed_kind): Handle map modifiers
also for declare-mapper's map clauses.

gcc/c/ChangeLog:

* c-parser.cc (c_parser_omp_declare_mapper): Check that the
struct var is actually used by at least one map clause.

gcc/cp/ChangeLog:

* semantics.cc (cp_check_omp_declare_mapper): Change what
argument is expected; check that the struct var is used by at
least one map war. Print sorry when compiling with -std=c++98.
* pt.cc (tsubst_stmt, tsubst_expr): Call it.
* parser.cc (cp_parser_omp_declare_mapper): Update call.

gcc/testsuite/ChangeLog:

* c-c++-common/gomp/declare-mapper-10.c: Exclude C++98.
* c-c++-common/gomp/declare-mapper-15.c: Likewise.
* c-c++-common/gomp/declare-mapper-16.c: Likewise.
* c-c++-common/gomp/declare-mapper-3.c: Likewise.
* c-c++-common/gomp/declare-mapper-4.c: Likewise.
* c-c++-common/gomp/declare-mapper-5.c: Likewise.
* c-c++-common/gomp/declare-mapper-6.c: Likewise.
* c-c++-common/gomp/declare-mapper-7.c: Likewise.
* c-c++-common/gomp/declare-mapper-8.c: Likewise.
* c-c++-common/gomp/declare-mapper-9.c: Likewise.
* g++.dg/gomp/declare-mapper-1.C: Likewise.
* g++.dg/gomp/declare-mapper-2.C: Likewise.
* c-c++-common/gomp/pr122866.c: Expect sorry with C++98.
* c-c++-common/gomp/declare-mapper-11.c: Likewise.
Add dg-error for missing var-in-map-clause use.
* g++.dg/gomp/declare-mapper-3.C: Likewise.
* c-c++-common/gomp/declare-mapper-17.c: New test.
* c-c++-common/gomp/declare-mapper-18.c: New test.
* g++.dg/gomp/declare-mapper-4.C: New test.
* g++.dg/gomp/declare-mapper-5.C: New test.

24 files changed:
gcc/c-family/c-omp.cc
gcc/c/c-parser.cc
gcc/cp/parser.cc
gcc/cp/pt.cc
gcc/cp/semantics.cc
gcc/testsuite/c-c++-common/gomp/declare-mapper-10.c
gcc/testsuite/c-c++-common/gomp/declare-mapper-11.c
gcc/testsuite/c-c++-common/gomp/declare-mapper-15.c
gcc/testsuite/c-c++-common/gomp/declare-mapper-16.c
gcc/testsuite/c-c++-common/gomp/declare-mapper-17.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/declare-mapper-18.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/declare-mapper-3.c
gcc/testsuite/c-c++-common/gomp/declare-mapper-4.c
gcc/testsuite/c-c++-common/gomp/declare-mapper-5.c
gcc/testsuite/c-c++-common/gomp/declare-mapper-6.c
gcc/testsuite/c-c++-common/gomp/declare-mapper-7.c
gcc/testsuite/c-c++-common/gomp/declare-mapper-8.c
gcc/testsuite/c-c++-common/gomp/declare-mapper-9.c
gcc/testsuite/c-c++-common/gomp/pr122866.c
gcc/testsuite/g++.dg/gomp/declare-mapper-1.C
gcc/testsuite/g++.dg/gomp/declare-mapper-2.C
gcc/testsuite/g++.dg/gomp/declare-mapper-3.C
gcc/testsuite/g++.dg/gomp/declare-mapper-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/declare-mapper-5.C [new file with mode: 0644]

index f75f0788ac6611aa46b53eb1c99a4fec231fa6b9..b48243a22616eca67230aa11d3bf1d5419823699 100644 (file)
@@ -4517,8 +4517,10 @@ omp_map_decayed_kind (enum gomp_map_kind mapper_kind,
   if (invoked_as == GOMP_MAP_RELEASE || invoked_as == GOMP_MAP_DELETE)
     return invoked_as;
 
+  bool m_force_p, m_always_p, m_present_p;
   bool force_p, always_p, present_p;
 
+  mapper_kind = omp_split_map_kind (mapper_kind, &m_force_p, &m_always_p, &m_present_p);
   invoked_as = omp_split_map_kind (invoked_as, &force_p, &always_p, &present_p);
   gomp_map_kind decay_to;
 
@@ -4556,7 +4558,8 @@ omp_map_decayed_kind (enum gomp_map_kind mapper_kind,
       gcc_unreachable ();
     }
 
-  return omp_join_map_kind (decay_to, force_p, always_p, present_p);
+  return omp_join_map_kind (decay_to, m_force_p | force_p,
+                           m_always_p | always_p, m_present_p | present_p);
 }
 
 /* Instantiate a mapper MAPPER for expression EXPR, adding new clauses to
index daf57061ee9a421b7e30ff789e007dec321fa113..07c7900c332e41c9a171f20c8fcd7094b653c52b 100644 (file)
@@ -29219,6 +29219,18 @@ c_parser_omp_declare_mapper (c_parser *parser, enum pragma_context context)
       error_at (input_location, "missing %<map%> clause");
       goto fail;
     }
+  tree list;
+  for (list = maplist; list; list = OMP_CLAUSE_CHAIN (list))
+    {
+      tree dvar = OMP_CLAUSE_DECL (list);
+      while (!DECL_P (dvar) && TREE_OPERAND_LENGTH (dvar))
+       dvar = TREE_OPERAND (dvar, 0);
+      if (dvar == var)
+       break;
+    }
+  if (!list)
+    error_at (input_location, "at least one %<map%> clause must map %qD or an "
+                             "element of it", var);
 
   stmt = make_node (OMP_DECLARE_MAPPER);
   TREE_TYPE (stmt) = type;
index c7708f15f39b6bb97221c8d4f951cef62264b5a2..1ab462160da8996990eaa24cd616c7049d801c33 100644 (file)
@@ -55723,7 +55723,7 @@ cp_parser_omp_declare_mapper (cp_parser *parser, cp_token *pragma_tok,
   else
     pushdecl (vardecl);
 
-  cp_check_omp_declare_mapper (vardecl);
+  cp_check_omp_declare_mapper (mapper);
 
   cp_parser_require_pragma_eol (parser, pragma_tok);
   return;
index b6e8948f005a42213a401b8c690d8f57c4bda50c..d19864774a3c4adc79f108c556c6f1ee7cdbe8ba 100644 (file)
@@ -20762,6 +20762,7 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        TREE_TYPE (t) = type;
        OMP_DECLARE_MAPPER_DECL (t) = decl;
        OMP_DECLARE_MAPPER_CLAUSES (t) = clauses;
+       cp_check_omp_declare_mapper (t);
        RETURN (t);
       }
 
@@ -21881,6 +21882,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
        TREE_TYPE (t) = type;
        OMP_DECLARE_MAPPER_DECL (t) = decl;
        OMP_DECLARE_MAPPER_CLAUSES (t) = clauses;
+       cp_check_omp_declare_mapper (t);
        RETURN (t);
       }
 
index e9fc01ef28fb3cefbfa5741ae59c43659a594bae..6564d9e37a6f77189f9c7a5d3003a056cd3f87a5 100644 (file)
@@ -7440,25 +7440,69 @@ finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
 bool
 cp_check_omp_declare_mapper (tree udm)
 {
-  tree type = TREE_TYPE (udm);
-  location_t loc = DECL_SOURCE_LOCATION (udm);
+  tree var = OMP_DECLARE_MAPPER_DECL (udm);
+  tree type = TREE_TYPE (var);
+  location_t loc = DECL_SOURCE_LOCATION (var);
 
   if (type == error_mark_node)
     return false;
 
-  if (!processing_template_decl && !RECORD_OR_UNION_TYPE_P (type))
+  if (processing_template_decl)
+    return true;
+
+  if (!RECORD_OR_UNION_TYPE_P (type))
     {
       error_at (loc, "%qT is not a struct, union or class type in "
                "%<#pragma omp declare mapper%>", type);
       return false;
     }
-  if (!processing_template_decl && CLASSTYPE_VBASECLASSES (type))
+  if (CLASSTYPE_VBASECLASSES (type))
     {
       error_at (loc, "%qT must not be a virtual base class in "
                "%<#pragma omp declare mapper%>", type);
       return false;
     }
 
+  tree c = OMP_DECLARE_MAPPER_CLAUSES (udm);
+  for ( ; c; c = OMP_CLAUSE_CHAIN (c))
+    {
+      tree dvar = OMP_CLAUSE_DECL (c);
+      while (!DECL_P (dvar) && TREE_OPERAND_LENGTH (dvar))
+       dvar = TREE_OPERAND (dvar, 0);
+      if (dvar == var)
+       break;
+    }
+  if (!c)
+    {
+      // After template handling, the var is mangled, demangle it
+      const char *name = IDENTIFIER_POINTER (DECL_NAME (var));
+      char *n = NULL;
+      if (startswith (name, "omp declare mapper "))
+       {
+         name += strlen ("omp declare mapper ");
+         n = xstrdup (name);
+         n[strchr (n, '~')-n] = '\0';
+         name = n;
+       }
+      error_at (loc, "at least one %<map%> clause must map %qs or an "
+                    "element of it", name);
+      if (n)
+       free (n);
+      return false;
+    }
+
+  /* FIXME: The vardecl created for the mapper_id uses DECL_DECLARED_CONSTEXPR_P
+     = 1, which is set to false in finalize_literal_type_property for C++ < 11,
+     leading to an error in ensure_literal_type_for_constexpr_object.
+     Examples (compile with -std=c++98): gcc.dg/gomp/declare-mapper-13.c and
+     libgomp.c++/declare-mapper-{5,6,8}.C.  */
+  if (cxx_dialect < cxx11)
+    {
+      sorry_at (loc, "%<#pragma omp declare mapper%> with %<-std=%> set to "
+                    "before C++11");
+      return false;
+    }
+
   return true;
 }
 
index 4020c4bae3072a1da291ecaf445033f4d7db07d7..6d0f285ee029b727c533ab90ebabc202f3f89105 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
 /* { dg-additional-options "-fdump-tree-gimple" } */
 
 struct S {
index 1f65bad694dd295c9ec42de766ac11219d3b8aa2..89d84db87a0425271358aae2fab917bb8e1a55db 100644 (file)
@@ -18,9 +18,11 @@ struct XT {
 // { dg-error "expected primary-expression before '\\)' token" "" { target c++ } .-1 }
 // { dg-error "unknown type name 'XT'" "" { target c } .-2 }
 // { dg-error "expected end of line before 'y'" "" { target c } .-3 }
+// { dg-error "at least one 'map' clause must map 'y' or an element of it" "" { target c++ } .-4 }
 #pragma omp declare mapper ( bar : struct XT y) map()
 // { dg-error "expected primary-expression before '\\)' token" "" { target c++ } .-1 }
 // { dg-error "expected expression before '\\)' token" "" { target c } .-2 }
+// { dg-error "at least one 'map' clause must map 'y' or an element of it" "" { target *-*-* } .-3 }
 
 struct t {
   int x;
@@ -45,8 +47,10 @@ typedef struct t myStruct;
 // { dg-error "expected primary-expression before '\\)' token" "" { target c++ } .-1 }
 // { dg-error "unknown type name 't'" "" { target c } .-2 }
 // { dg-error "expected end of line before 'v'" "" { target c } .-3 }
+// { dg-error "at least one 'map' clause must map 'v' or an element of it" "" { target c++ } .-4 }
 
 #pragma omp declare mapper(fancy : struct t v) map(always,present,close,mapper(d),tofrom: v) // { dg-error "in 'declare mapper' directives, parameter to 'mapper' modifier must be 'default'" }
+// { dg-message "sorry, unimplemented: '#pragma omp declare mapper' with '-std=' set to before C++11" "" { target c++98_only } .-1 }
 
 #pragma omp declare mapper(myStruct v) map(v, v.x)
 // { dg-note "'#pragma omp declare mapper \\(myStruct\\)' previously declared here" "" { target c++ } .-1 }
@@ -61,6 +65,7 @@ union u_q { };
 #pragma omp declare mapper(union u_t v) map()
 // { dg-error "expected primary-expression before '\\)' token" "" { target c++ } .-1 }
 // { dg-error "expected expression before '\\)' token" "" { target c } .-2 }
+// { dg-error "at least one 'map' clause must map 'v' or an element of it" "" { target *-*-* } .-3 }
 
 #pragma omp declare mapper( one : union u_t v) map(v)
 // { dg-note "'#pragma omp declare mapper \\(one: u_t\\)' previously declared here" "" { target c++ } .-1 }
index ecda2e5ebd1a12a37a8330142e7f1670d8528805..2d5c50eb4eae353e5f7b689e20188fc861c86263 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
 /* { dg-options "-fopenmp -fdump-tree-gimple" } */
 
 typedef struct {
index 20383cc2d69f18229527c6b2cf47772214016af0..ba3559293c4d88f6929d232591368cd72b37a9a4 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
 /* { dg-options "-fopenmp -fdump-tree-gimple" } */
 
 typedef struct {
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-17.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-17.c
new file mode 100644 (file)
index 0000000..a77896f
--- /dev/null
@@ -0,0 +1,23 @@
+typedef struct S { int x;} S;
+int x;
+S s;
+
+void f() {
+  #pragma omp declare mapper(S var) map(to: x) /* { dg-error "at least one 'map' clause must map 'var' or an element of it" } */
+  #pragma omp target enter data map(s)
+}
+
+void f2()
+{
+  int x;
+  #pragma omp declare mapper (int var) map(always, to: var)
+// { dg-error "'int' is not a struct or union type in '#pragma omp declare mapper'" "" { target c } .-1 }
+// { dg-error "'int' is not a struct, union or class type in '#pragma omp declare mapper'" "" { target c++ } .-2 }
+  #pragma omp target enter data map(x)
+}
+
+void f3() {
+  float g[2];
+  #pragma omp declare mapper (S var) map(always, to: g[var.x]) // { dg-error "at least one 'map' clause must map 'var' or an element of it" }
+  #pragma omp target enter data map(g)
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-18.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-18.c
new file mode 100644 (file)
index 0000000..6b53b1b
--- /dev/null
@@ -0,0 +1,39 @@
+// { dg-do compile { target { c || c++11 } } }
+// { dg-additional-options "-fdump-tree-gimple" }
+
+typedef struct S { int x;} S;
+int x;
+S s1;
+S s2;
+
+void f() {
+  #pragma omp declare mapper(S var) map(to: var)
+  #pragma omp target exit data map(always, from: s1)
+}
+
+void f2() {
+  #pragma omp declare mapper(S var) map(present, to: var)
+  #pragma omp target enter data map(always, tofrom : s2)
+}
+
+void f3()
+{
+  S x;
+  int y;
+  #pragma omp declare mapper (S var) map(always, to: var, y)
+  #pragma omp target enter data map(x)
+}
+
+
+// to + 'exit date' always from -> release
+// { dg final { scan-dump "static int omp declare mapper <default> = struct S #pragma omp declare mapper \\(struct S var\\) map\\(to:var\\);" "gimple" }
+// { dg final { scan-dump "#pragma omp target exit data map\\(release:s1 \\\[len: 4\\\]\\)" "gimple" }
+
+
+// present,to + always,from -> always,present,to
+// { dg final { scan-dump "static int omp declare mapper <default> = struct S #pragma omp declare mapper \\(struct S var\\) map\\(present,to:var\\);" "gimple" }
+// { dg final { scan-dump "#pragma omp target enter data map\\(always,present,to:s2 \\\[len: 4\\\]\\)" "gimple" }
+
+// always,to + - -> always,to
+// { dg final { scan-dump "static int omp declare mapper <default> = struct S #pragma omp declare mapper \\(struct S var\\) map\\(always,to:y\\) map\\(always,to:var\\);" "gimple" }
+// { dg final { scan-dump "#pragma omp target enter data map\\(always,to:y \\\[len: 4\\\]\\) map\\(always,to:x \\\[len: 4\\\]\\)" "gimple" }
index c0ec21b1b380adcbbb8fc52fac51af22bc847f45..c78e54293b965cf01a962e4b534ebdbd8feb05a3 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-do compile }
+// { dg-do compile { target { c || c++11 } } }
 // { dg-additional-options "-fdump-tree-gimple" }
 
 #include <stdlib.h>
index 39e3ab1141996afe5a802b3c4bd6da6973ac4cf4..55a9af8edef641fbca12db5b9e5151ca62d5b0fd 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
 /* { dg-additional-options "-fdump-tree-original" } */
 
 /* Check mapper binding clauses.  */
index e8ab15941419a03c4a3d17d1908eb8629157c1a6..7671595f8d5d8b5ed4c877957c582b3457ef934f 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
 
 typedef struct S_ {
   int *myarr;
index c13eb8b5816ec92c09f947009af2718c9b5ea22f..6d0b607041ae9b694485a950d330ed9a441cc2a9 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
 
 int x = 5;
 
@@ -19,5 +19,6 @@ struct R {
 #pragma omp declare mapper (struct R myr) map(myr.arr3[0:y])
 /* { dg-error "'y' undeclared" "" { target c } .-1 } */
 /* { dg-error "'y' was not declared in this scope" "" { target c++ } .-2 } */
+/* { dg-error "at least one 'map' clause must map 'myr' or an element of it" "" { target c++ } .-3 } */
 
 int y = 7;
index 0f8dd25a18dcd58d0293b7405a49dff727f0cbcb..acd00678b5690247834a31a7d3d0118b85b459e2 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
 
 struct Q {
   int *arr1;
@@ -24,6 +24,7 @@ int bar (void)
   #pragma omp declare mapper (struct R myr) map(myr.arr3[0:y])
   /* { dg-error "'y' undeclared" "" { target c } .-1 } */
   /* { dg-error "'y' was not declared in this scope" "" { target c++ } .-2 } */
+  /* { dg-error "at least one 'map' clause must map 'myr' or an element of it" "" { target c++ } .-3 } */
   int y = 7;
   return y;
 }
index dadca282711c26df2f85992c12e85b69f848ea68..6cf25df0ab7f2b107da171ccf01e84124cbb2316 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
 
 struct Q {
   int *arr1;
index 709bc0c8f4def4c30565c3b04962ce1b1256e12c..6e00bb688f6c1fa26e25e5e8f917fd6b27d7833b 100644 (file)
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
 
 int x = 5;
 
index bb42bc634dbd8b4cd019bbfeb0215e75465b8443..58972e1b9f410766eb984a3f0b718643323e98bb 100644 (file)
@@ -8,6 +8,7 @@ void froggify (struct test);
 
 #pragma omp declare mapper(struct test v) map(iterator(i = 0:1), tofrom: v.x)
 /* { dg-message "sorry, unimplemented: user-defined mapper that uses a .map. clause with .iterator." "" { target *-*-* } .-1 } */
+/* { dg-message "'#pragma omp declare mapper' with '-std=' set to before C++11" "" { target c++98_only } .-2 } */
 
 int
 main ()
index 2f2dd219bcb5d50e19013dadc1d524c501f9627f..f74c3bb3892924216f299afb667f87d8df328c2e 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-do compile }
+// { dg-do compile { target c++11 } }
 // { dg-additional-options "-fdump-tree-gimple" }
 
 // "omp declare mapper" support -- check expansion in gimple.
index 379be29001822bc75587d3108dc8ffe3b4361de2..cf2e4d0aaa3c1367db35434621123a656c9dae3a 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-do compile }
+// { dg-do compile { target c++11 } }
 
 // Error-checking tests for "omp declare mapper".
 
index 1f019c710ca1ca3b7be022a1e28b335aab7bb790..4ad09b2ffd2e734e5d31c502d5ae0bdb43a8d167 100644 (file)
@@ -1,3 +1,5 @@
+// { dg-do compile { target c++11 } }
+
 #pragma omp declare mapper (int v)  // { dg-error "missing 'map' clause before end of line" }
 #pragma omp declare mapper (float v) map()  // { dg-error "expected primary-expression before '\\)' token" }
 // { dg-error "'float' is not a struct, union or class type in '#pragma omp declare mapper'" "" { target *-*-* } .-1 }
@@ -8,6 +10,8 @@ struct XT {
   int x;
 };
 #pragma omp declare mapper (XT y) map()  // { dg-error "expected primary-expression before '\\)' token" }
+// { dg-error "at least one 'map' clause must map 'y' or an element of it" "" { target *-*-* } .-1 }
+
 
 struct t {
   int x;
@@ -20,6 +24,7 @@ typedef struct t myStruct;
 #pragma omp declare mapper(myStruct) // { dg-error "expected unqualified-id before '\\)' token" }
 
 #pragma omp declare mapper(name : t v)  map() // { dg-error "expected primary-expression before '\\)' token" } 
+// { dg-error "at least one 'map' clause must map 'v' or an element of it" "" { target *-*-* } .-1 }
 
 #pragma omp declare mapper(fancy : struct t v) map(always,present,close,mapper(d),tofrom: v) // { dg-error "in 'declare mapper' directives, parameter to 'mapper' modifier must be 'default'" }
 
@@ -37,3 +42,4 @@ class B : public virtual A { };
 union u_t { };
 
 #pragma omp declare mapper(u_t v) map()  // { dg-error "expected primary-expression before '\\)' token" }
+// { dg-error "at least one 'map' clause must map 'v' or an element of it" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/gomp/declare-mapper-4.C b/gcc/testsuite/g++.dg/gomp/declare-mapper-4.C
new file mode 100644 (file)
index 0000000..52ad3d7
--- /dev/null
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fdump-tree-original" }
+
+// Ensure that always in mapper does not ICE and gets propagated to both 'x' and 'y'
+
+struct S { int x; };
+
+template<typename T>
+void f()
+{
+  T x;
+  int y;
+  #pragma omp declare mapper (T var) map(always, to: var, y)
+// error: the type 'S' of 'constexpr' variable '#pragma omp declare mapper' is not literal
+  #pragma omp target enter data map(x)
+}
+
+void g()
+{
+  f<S>();
+}
+
+// { dg-final { scan-tree-dump "#pragma omp target enter data map\\(always,to:y\\) map\\(always,to:x\\)" "original" } }
diff --git a/gcc/testsuite/g++.dg/gomp/declare-mapper-5.C b/gcc/testsuite/g++.dg/gomp/declare-mapper-5.C
new file mode 100644 (file)
index 0000000..b20b5e2
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+
+struct S { int x; };
+
+template<typename T>
+void f()
+{
+  T x;
+  int y;
+  #pragma omp declare mapper (T var) map(always, to: var, y) // { dg-error "'int' is not a struct, union or class type in '#pragma omp declare mapper'" }
+  #pragma omp target enter data map(x)
+}
+
+void g()
+{
+  f<int>();
+}
+
+template<typename T>
+void h() {
+  T g[2];
+  #pragma omp declare mapper (S var) map(always, to: g[var.x]) // { dg-error "at least one 'map' clause must map 'var' or an element of it" }
+  #pragma omp target enter data map(g)
+}
+
+void h2()
+{
+  h<S>();
+}