Hi! This patch implements some new restrictions, clarifications etc. on the declare target construct. Committed to gomp-4_5-branch.
2015-10-15 Jakub Jelinek <ja...@redhat.com> gcc/c/ * c-parser.c (c_parser_omp_declare_target): Call c_finish_omp_clauses in the parenthesized extended-list syntax case. * c-decl.c (c_decl_attributes): Don't diagnose block scope vars inside declare target. * c-typeck.c (c_finish_omp_clauses): Diagnose the same var or function appearing multiple times on the same directive. Fix up wording for the to clause if t is neither a FUNCTION_DECL nor a VAR_DECL. gcc/cp/ * parser.c (cp_parser_omp_declare_target): Call finish_omp_clauses in the parenthesized extended-list syntax case. Call cp_parser_require_pragma_eol instead of cp_parser_skip_to_pragma_eol. (cp_parser_omp_end_declare_target): Call cp_parser_require_pragma_eol instead of cp_parser_skip_to_pragma_eol. * decl2.c (cplus_decl_attributes): Don't diagnose block scope vars inside declare target. * semantics.c (finish_omp_clauses): Diagnose the same var or function appearing multiple times on the same directive. Fix up wording for the to clause if t is neither a FUNCTION_DECL nor a VAR_DECL, use special wording for OVERLOADs and TEMPLATE_ID_EXPR. gcc/testsuite/ * c-c++-common/gomp/declare-target-2.c: Add various new tests. Adjust expected diagnostics wording in one case. * g++.dg/gomp/declare-target-1.C: New test. libgomp/ * testsuite/libgomp.c/target-28.c: New test. * testsuite/libgomp.c++/target-13.C: New test. --- gcc/c/c-parser.c.jj 2015-10-14 18:04:13.000000000 +0200 +++ gcc/c/c-parser.c 2015-10-15 16:55:36.639169199 +0200 @@ -15531,6 +15531,7 @@ c_parser_omp_declare_target (c_parser *p { clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, clauses); + clauses = c_finish_omp_clauses (clauses, true); c_parser_skip_to_pragma_eol (parser); } else --- gcc/c/c-decl.c.jj 2015-10-14 10:24:55.000000000 +0200 +++ gcc/c/c-decl.c 2015-10-15 19:24:50.809431612 +0200 @@ -4417,13 +4417,7 @@ c_decl_attributes (tree *node, tree attr || TREE_CODE (*node) == FUNCTION_DECL)) { if (VAR_P (*node) - && ((DECL_CONTEXT (*node) - && TREE_CODE (DECL_CONTEXT (*node)) == FUNCTION_DECL) - || (current_function_decl && !DECL_EXTERNAL (*node)))) - error ("%q+D in block scope inside of declare target directive", - *node); - else if (VAR_P (*node) - && !lang_hooks.types.omp_mappable_type (TREE_TYPE (*node))) + && !lang_hooks.types.omp_mappable_type (TREE_TYPE (*node))) error ("%q+D in declare target directive does not have mappable type", *node); else --- gcc/c/c-typeck.c.jj 2015-10-14 18:04:13.000000000 +0200 +++ gcc/c/c-typeck.c 2015-10-15 18:17:41.991147724 +0200 @@ -12837,17 +12837,22 @@ c_finish_omp_clauses (tree clauses, bool break; case OMP_CLAUSE_TO_DECLARE: - t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == FUNCTION_DECL) - break; - /* FALLTHRU */ case OMP_CLAUSE_LINK: t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t)) + if (TREE_CODE (t) == FUNCTION_DECL + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) + ; + else if (!VAR_P (t)) { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is neither a variable nor a function name in " + "clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } else if (DECL_THREAD_LOCAL_P (t)) @@ -12864,6 +12869,17 @@ c_finish_omp_clauses (tree clauses, bool omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + if (remove) + break; + if (bitmap_bit_p (&generic_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once on the same " + "%<declare target%> directive", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); break; case OMP_CLAUSE_UNIFORM: --- gcc/cp/parser.c.jj 2015-10-14 18:04:13.000000000 +0200 +++ gcc/cp/parser.c 2015-10-15 17:36:30.206793453 +0200 @@ -34673,11 +34673,12 @@ cp_parser_omp_declare_target (cp_parser { clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO_DECLARE, clauses); - cp_parser_skip_to_pragma_eol (parser, pragma_tok); + clauses = finish_omp_clauses (clauses, true); + cp_parser_require_pragma_eol (parser, pragma_tok); } else { - cp_parser_skip_to_pragma_eol (parser, pragma_tok); + cp_parser_require_pragma_eol (parser, pragma_tok); scope_chain->omp_declare_target_attribute++; return; } @@ -34744,7 +34745,7 @@ cp_parser_omp_end_declare_target (cp_par cp_parser_skip_to_pragma_eol (parser, pragma_tok); return; } - cp_parser_skip_to_pragma_eol (parser, pragma_tok); + cp_parser_require_pragma_eol (parser, pragma_tok); if (!scope_chain->omp_declare_target_attribute) error_at (pragma_tok->location, "%<#pragma omp end declare target%> without corresponding " --- gcc/cp/decl2.c.jj 2015-10-14 10:25:31.000000000 +0200 +++ gcc/cp/decl2.c 2015-10-15 19:25:38.678722369 +0200 @@ -1454,11 +1454,6 @@ cplus_decl_attributes (tree *decl, tree && DECL_CLASS_SCOPE_P (*decl)) error ("%q+D static data member inside of declare target directive", *decl); - else if (VAR_P (*decl) - && (DECL_FUNCTION_SCOPE_P (*decl) - || (current_function_decl && !DECL_EXTERNAL (*decl)))) - error ("%q+D in block scope inside of declare target directive", - *decl); else if (!processing_template_decl && VAR_P (*decl) && !cp_omp_mappable_type (TREE_TYPE (*decl))) --- gcc/cp/semantics.c.jj 2015-10-14 18:04:13.000000000 +0200 +++ gcc/cp/semantics.c 2015-10-15 18:32:24.482064935 +0200 @@ -6521,17 +6521,33 @@ finish_omp_clauses (tree clauses, bool a break; case OMP_CLAUSE_TO_DECLARE: - t = OMP_CLAUSE_DECL (c); - if (TREE_CODE (t) == FUNCTION_DECL) - break; - /* FALLTHRU */ case OMP_CLAUSE_LINK: t = OMP_CLAUSE_DECL (c); - if (!VAR_P (t)) + if (TREE_CODE (t) == FUNCTION_DECL + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) + ; + else if (!VAR_P (t)) { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in clause %qs", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO_DECLARE) + { + if (TREE_CODE (t) == OVERLOAD && OVL_CHAIN (t)) + error_at (OMP_CLAUSE_LOCATION (c), + "overloaded function name %qE in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else if (TREE_CODE (t) == TEMPLATE_ID_EXPR) + error_at (OMP_CLAUSE_LOCATION (c), + "template %qE in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is neither a variable nor a function name " + "in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + } + else + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } else if (DECL_THREAD_LOCAL_P (t)) @@ -6548,6 +6564,17 @@ finish_omp_clauses (tree clauses, bool a omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + if (remove) + break; + if (bitmap_bit_p (&generic_head, DECL_UID (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once on the same " + "%<declare target%> directive", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); break; case OMP_CLAUSE_UNIFORM: --- gcc/testsuite/c-c++-common/gomp/declare-target-2.c.jj 2015-10-14 10:25:30.000000000 +0200 +++ gcc/testsuite/c-c++-common/gomp/declare-target-2.c 2015-10-15 18:07:05.489584542 +0200 @@ -6,7 +6,7 @@ extern int a; #pragma omp declare target to (a) /* { dg-error "with clauses in between" } */ #pragma omp end declare target int b; -#pragma omp declare target to (b) link (b) /* { dg-error "specified both in declare target" } */ +#pragma omp declare target to (b) link (b) /* { dg-error "appears more than once on the same .declare target. directive" } */ int c; #pragma omp declare target (c) #pragma omp declare target link (c) /* { dg-error "specified both in declare target" } */ @@ -25,3 +25,21 @@ int g, h; #pragma omp declare target link (h) /* { dg-error "is threadprivate variable in" } */ int j[10]; #pragma omp declare target to (j[0:4]) /* { dg-error "expected" } */ +int k, l; +#pragma omp declare target +int m; +#pragma omp end declare target +#pragma omp declare target to (k) +#pragma omp declare target (k) +#pragma omp declare target to (k, m) link (l) +#pragma omp declare target link (l) +int n, o, s, t; +#pragma omp declare target to (n) to (n) /* { dg-error "appears more than once on the same .declare target. directive" } */ +#pragma omp declare target link (o, o) /* { dg-error "appears more than once on the same .declare target. directive" } */ +#pragma omp declare target (s, t, s) /* { dg-error "appears more than once on the same .declare target. directive" } */ +int p, q, r; +#pragma omp declare target (p) to (q) /* { dg-error "expected end of line before .to." } */ +#pragma omp declare target to (p) (q) link (r) /* { dg-error "expected .#pragma omp. clause before" } */ +#pragma omp declare target link (r) (p) /* { dg-error "expected .#pragma omp. clause before" } */ +#pragma omp declare target +#pragma omp end declare target to (p) /* { dg-error "expected end of line before .to." } */ --- gcc/testsuite/g++.dg/gomp/declare-target-1.C.jj 2015-10-15 18:09:08.043767545 +0200 +++ gcc/testsuite/g++.dg/gomp/declare-target-1.C 2015-10-15 19:11:29.037310874 +0200 @@ -0,0 +1,37 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +#pragma omp declare target +void f1 (int); +void f1 (double); +template <typename T> +void f2 (T); +template<> void f2<int> (int); +#pragma omp end declare target +void f3 (int); +void f4 (int); +void f4 (short); +template <typename T> +void f5 (T); +#pragma omp declare target (f3) +#pragma omp declare target to (f4) // { dg-error "overloaded function name .f4. in clause .to." } +#pragma omp declare target to (f5<int>) // { dg-error "template .f5<int>. in clause .to." } +template <int N> +void f6 (int) +{ + static int s; + #pragma omp declare target (s) +} +namespace N +{ + namespace M + { + void f7 (int); + } + void f8 (long); +} +void f9 (short); +int v; +#pragma omp declare target (N::M::f7) +#pragma omp declare target to (::N::f8) +#pragma omp declare target to (::f9) to (::v) --- libgomp/testsuite/libgomp.c/target-28.c.jj 2015-10-15 18:56:27.932665314 +0200 +++ libgomp/testsuite/libgomp.c/target-28.c 2015-10-15 19:21:22.756514178 +0200 @@ -0,0 +1,33 @@ +extern void abort (void); + +#pragma omp declare target +int +foo (void) +{ + static int s; + return ++s; +} +#pragma omp end declare target + +int +bar (void) +{ + static int s; + #pragma omp declare target to (s) + return ++s; +} +#pragma omp declare target (bar) + +int +main () +{ + int r; + #pragma omp target map(from:r) + { + r = (foo () == 1) + (bar () == 1); + r += (foo () == 2) + (bar () == 2); + } + if (r != 4) + abort (); + return 0; +} --- libgomp/testsuite/libgomp.c++/target-13.C.jj 2015-10-15 19:27:52.179745374 +0200 +++ libgomp/testsuite/libgomp.c++/target-13.C 2015-10-15 19:29:00.188739477 +0200 @@ -0,0 +1,33 @@ +extern "C" void abort (void); + +#pragma omp declare target +int +foo (void) +{ + static int s; + return ++s; +} +#pragma omp end declare target + +int +bar (void) +{ + static int s; + #pragma omp declare target to (s) + return ++s; +} +#pragma omp declare target (bar) + +int +main () +{ + int r; + #pragma omp target map(from:r) + { + r = (foo () == 1) + (bar () == 1); + r += (foo () == 2) + (bar () == 2); + } + if (r != 4) + abort (); + return 0; +} Jakub