I encountered this when reviewing the Fortran parser patches.
Namely, all three FE lacked a check for the following restriction,
here implemented for C/C++:
"At least one map clause that maps var or at least one element of
var is required."
While adding the simple check, I found more issues:
- map decay does not help modifiers like 'present' or 'always'
in the declare-mapper's map clauses (fine in target...'s map
clauses). This caused ICE (gcc_unreachable).
- For C++, several checks were not active as the check function
was not called during template expansion.
- For C++: compiling with -std=c++98 as done by the testsuite
caused bogus constexpr errors. That's preexisting, but due to
the additional diagnostic, it seems to occur now for some
previously passing test cases.
In any case, there is now a 'sorry' shown when compiled with
-std=c++98 (I bet no user will be affected by this!)
Comments, remarks, suggestions before I commit this patch?
Tobias
OpenMP: mapper [C/C++] reject w/o map usage, reject C++98, fix map decay
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.
gcc/c-family/c-omp.cc | 5 ++-
gcc/c/c-parser.cc | 12 +++++
gcc/cp/parser.cc | 2 +-
gcc/cp/pt.cc | 2 +
gcc/cp/semantics.cc | 52 ++++++++++++++++++++--
.../c-c++-common/gomp/declare-mapper-10.c | 2 +-
.../c-c++-common/gomp/declare-mapper-11.c | 5 +++
.../c-c++-common/gomp/declare-mapper-15.c | 2 +-
.../c-c++-common/gomp/declare-mapper-16.c | 2 +-
.../c-c++-common/gomp/declare-mapper-17.c | 23 ++++++++++
.../c-c++-common/gomp/declare-mapper-18.c | 39 ++++++++++++++++
gcc/testsuite/c-c++-common/gomp/declare-mapper-3.c | 2 +-
gcc/testsuite/c-c++-common/gomp/declare-mapper-4.c | 2 +-
gcc/testsuite/c-c++-common/gomp/declare-mapper-5.c | 2 +-
gcc/testsuite/c-c++-common/gomp/declare-mapper-6.c | 3 +-
gcc/testsuite/c-c++-common/gomp/declare-mapper-7.c | 3 +-
gcc/testsuite/c-c++-common/gomp/declare-mapper-8.c | 2 +-
gcc/testsuite/c-c++-common/gomp/declare-mapper-9.c | 2 +-
gcc/testsuite/c-c++-common/gomp/pr122866.c | 1 +
gcc/testsuite/g++.dg/gomp/declare-mapper-1.C | 2 +-
gcc/testsuite/g++.dg/gomp/declare-mapper-2.C | 2 +-
gcc/testsuite/g++.dg/gomp/declare-mapper-3.C | 6 +++
gcc/testsuite/g++.dg/gomp/declare-mapper-4.C | 23 ++++++++++
gcc/testsuite/g++.dg/gomp/declare-mapper-5.C | 29 ++++++++++++
24 files changed, 207 insertions(+), 18 deletions(-)
diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc
index f75f0788ac6..b48243a2261 100644
--- a/gcc/c-family/c-omp.cc
+++ b/gcc/c-family/c-omp.cc
@@ -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
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index daf57061ee9..07c7900c332 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -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;
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index c7708f15f39..1ab462160da 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -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;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index b6e8948f005..d19864774a3 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -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);
}
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e9fc01ef28f..6564d9e37a6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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;
}
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-10.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-10.c
index 4020c4bae30..6d0f285ee02 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-10.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-10.c
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
/* { dg-additional-options "-fdump-tree-gimple" } */
struct S {
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-11.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-11.c
index 1f65bad694d..89d84db87a0 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-11.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-11.c
@@ -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 }
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-15.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-15.c
index ecda2e5ebd1..2d5c50eb4ea 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-15.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-15.c
@@ -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-16.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-16.c
index 20383cc2d69..ba3559293c4 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-16.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-16.c
@@ -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
index 00000000000..a77896fe4cc
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-17.c
@@ -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
index 00000000000..6b53b1b1e18
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-18.c
@@ -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" }
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-3.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-3.c
index c0ec21b1b38..c78e54293b9 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-3.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-3.c
@@ -1,4 +1,4 @@
-// { dg-do compile }
+// { dg-do compile { target { c || c++11 } } }
// { dg-additional-options "-fdump-tree-gimple" }
#include <stdlib.h>
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-4.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-4.c
index 39e3ab11419..55a9af8edef 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-4.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-4.c
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
/* { dg-additional-options "-fdump-tree-original" } */
/* Check mapper binding clauses. */
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-5.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-5.c
index e8ab1594141..7671595f8d5 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-5.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-5.c
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
typedef struct S_ {
int *myarr;
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-6.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-6.c
index c13eb8b5816..6d0b607041a 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-6.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-6.c
@@ -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;
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-7.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-7.c
index 0f8dd25a18d..acd00678b56 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-7.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-7.c
@@ -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;
}
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-8.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-8.c
index dadca282711..6cf25df0ab7 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-8.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-8.c
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
struct Q {
int *arr1;
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-mapper-9.c b/gcc/testsuite/c-c++-common/gomp/declare-mapper-9.c
index 709bc0c8f4d..6e00bb688f6 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-mapper-9.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-mapper-9.c
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c || c++11 } } } */
int x = 5;
diff --git a/gcc/testsuite/c-c++-common/gomp/pr122866.c b/gcc/testsuite/c-c++-common/gomp/pr122866.c
index bb42bc634db..58972e1b9f4 100644
--- a/gcc/testsuite/c-c++-common/gomp/pr122866.c
+++ b/gcc/testsuite/c-c++-common/gomp/pr122866.c
@@ -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 ()
diff --git a/gcc/testsuite/g++.dg/gomp/declare-mapper-1.C b/gcc/testsuite/g++.dg/gomp/declare-mapper-1.C
index 2f2dd219bcb..f74c3bb3892 100644
--- a/gcc/testsuite/g++.dg/gomp/declare-mapper-1.C
+++ b/gcc/testsuite/g++.dg/gomp/declare-mapper-1.C
@@ -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.
diff --git a/gcc/testsuite/g++.dg/gomp/declare-mapper-2.C b/gcc/testsuite/g++.dg/gomp/declare-mapper-2.C
index 379be290018..cf2e4d0aaa3 100644
--- a/gcc/testsuite/g++.dg/gomp/declare-mapper-2.C
+++ b/gcc/testsuite/g++.dg/gomp/declare-mapper-2.C
@@ -1,4 +1,4 @@
-// { dg-do compile }
+// { dg-do compile { target c++11 } }
// Error-checking tests for "omp declare mapper".
diff --git a/gcc/testsuite/g++.dg/gomp/declare-mapper-3.C b/gcc/testsuite/g++.dg/gomp/declare-mapper-3.C
index 1f019c710ca..4ad09b2ffd2 100644
--- a/gcc/testsuite/g++.dg/gomp/declare-mapper-3.C
+++ b/gcc/testsuite/g++.dg/gomp/declare-mapper-3.C
@@ -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
index 00000000000..52ad3d7e95f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/declare-mapper-4.C
@@ -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
index 00000000000..b20b5e2ff71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/declare-mapper-5.C
@@ -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>();
+}