Hi! In GCC 8 and older, we were implementing the OpenMP 3.1 rule that const vars without mutable members are predetermined shared, but in GCC 9 and later we follow the unfortunate OpenMP 4.0 change where they need to be listed explicitly if default(none). This isn't very conventient for __func__/__FUNCTION__/__PRETTY_FUNCTION__, which are function-local predeclared variables and often appear in macros etc., especially when GCC nor other compilers actually allowed them to be specified in the data sharing clauses.
In the upcoming OpenMP 5.1/TR8 we state that __func__ and other predeclared variables are predetermined shared (so they don't have to be specified with default(none)), but as exception may be specified in shared and firstprivate clauses (so they can be specified if users want and override or confirm the default data sharing). The following patch implements that change. Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk, queued for backport to 9.x. 2019-09-27 Jakub Jelinek <ja...@redhat.com> PR c++/88203 c-family/ * c-common.h (c_omp_predefined_variable): Declare. * c-omp.c (c_omp_predefined_variable): New function. (c_omp_predetermined_sharing): Return OMP_CLAUSE_DEFAULT_SHARED for predefined variables. c/ * c-parser.c (c_parser_predefined_identifier): New function. (c_parser_postfix_expression): Use it. (c_parser_omp_variable_list): Parse predefined identifiers. * c-typeck.c (c_finish_omp_clauses): Allow predefined variables in shared and firstprivate clauses, even when they are predetermined shared. cp/ * parser.c (cp_parser_omp_var_list_no_open): Parse predefined variables. * semantics.c (finish_omp_clauses): Allow predefined variables in shared and firstprivate clauses, even when they are predetermined shared. * cp-gimplify.c (cxx_omp_predetermined_sharing_1): Return OMP_CLAUSE_DEFAULT_SHARED for predefined variables. testsuite/ * c-c++-common/gomp/pr88203-1.c: New test. * c-c++-common/gomp/pr88203-2.c: New test. * c-c++-common/gomp/pr88203-3.c: New test. --- gcc/c-family/c-common.h.jj 2019-09-27 12:22:53.302891806 +0200 +++ gcc/c-family/c-common.h 2019-09-27 12:57:56.629349468 +0200 @@ -1187,6 +1187,7 @@ extern void c_omp_split_clauses (locatio tree, tree *); extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree); extern void c_omp_declare_simd_clauses_to_decls (tree, tree); +extern bool c_omp_predefined_variable (tree); extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); /* Return next tree in the chain for chain_next walking of tree nodes. */ --- gcc/c-family/c-omp.c.jj 2019-09-20 12:24:56.308191050 +0200 +++ gcc/c-family/c-omp.c 2019-09-27 16:27:16.032950885 +0200 @@ -2083,6 +2083,25 @@ c_omp_declare_simd_clauses_to_decls (tre } } +/* Return true for __func__ and similar function-local predefined + variables (which are in OpenMP predetermined shared, allowed in + shared/firstprivate clauses). */ + +bool +c_omp_predefined_variable (tree decl) +{ + if (VAR_P (decl) + && DECL_ARTIFICIAL (decl) + && TREE_READONLY (decl) + && TREE_STATIC (decl) + && DECL_NAME (decl) + && (DECL_NAME (decl) == ridpointers[RID_C99_FUNCTION_NAME] + || DECL_NAME (decl) == ridpointers[RID_FUNCTION_NAME] + || DECL_NAME (decl) == ridpointers[RID_PRETTY_FUNCTION_NAME])) + return true; + return false; +} + /* True if OpenMP sharing attribute of DECL is predetermined. */ enum omp_clause_default_kind @@ -2096,5 +2115,8 @@ c_omp_predetermined_sharing (tree decl) && INTEGRAL_TYPE_P (TREE_TYPE (decl))) return OMP_CLAUSE_DEFAULT_SHARED; + if (c_omp_predefined_variable (decl)) + return OMP_CLAUSE_DEFAULT_SHARED; + return OMP_CLAUSE_DEFAULT_UNSPECIFIED; } --- gcc/c/c-parser.c.jj 2019-09-20 12:24:56.198192754 +0200 +++ gcc/c/c-parser.c 2019-09-27 16:56:13.233124695 +0200 @@ -8049,6 +8049,41 @@ enum tgmath_parm_kind tgmath_fixed, tgmath_real, tgmath_complex }; +/* Helper function for c_parser_postfix_expression. Parse predefined + identifiers. */ + +static struct c_expr +c_parser_predefined_identifier (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + switch (c_parser_peek_token (parser)->keyword) + { + case RID_FUNCTION_NAME: + pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " + "identifier", "__FUNCTION__"); + break; + case RID_PRETTY_FUNCTION_NAME: + pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined " + "identifier", "__PRETTY_FUNCTION__"); + break; + case RID_C99_FUNCTION_NAME: + pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not support " + "%<__func__%> predefined identifier"); + break; + default: + gcc_unreachable (); + } + + struct c_expr expr; + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + expr.value = fname_decl (loc, c_parser_peek_token (parser)->keyword, + c_parser_peek_token (parser)->value); + set_c_expr_source_range (&expr, loc, loc); + c_parser_consume_token (parser); + return expr; +} + /* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2, C11 6.5.1-6.5.2). Compound literals aren't handled here; callers have to call c_parser_postfix_expression_after_paren_type on encountering them. @@ -8269,31 +8304,9 @@ c_parser_postfix_expression (c_parser *p switch (c_parser_peek_token (parser)->keyword) { case RID_FUNCTION_NAME: - pedwarn (loc, OPT_Wpedantic, "ISO C does not support " - "%<__FUNCTION__%> predefined identifier"); - expr.value = fname_decl (loc, - c_parser_peek_token (parser)->keyword, - c_parser_peek_token (parser)->value); - set_c_expr_source_range (&expr, loc, loc); - c_parser_consume_token (parser); - break; case RID_PRETTY_FUNCTION_NAME: - pedwarn (loc, OPT_Wpedantic, "ISO C does not support " - "%<__PRETTY_FUNCTION__%> predefined identifier"); - expr.value = fname_decl (loc, - c_parser_peek_token (parser)->keyword, - c_parser_peek_token (parser)->value); - set_c_expr_source_range (&expr, loc, loc); - c_parser_consume_token (parser); - break; case RID_C99_FUNCTION_NAME: - pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not support " - "%<__func__%> predefined identifier"); - expr.value = fname_decl (loc, - c_parser_peek_token (parser)->keyword, - c_parser_peek_token (parser)->value); - set_c_expr_source_range (&expr, loc, loc); - c_parser_consume_token (parser); + expr = c_parser_predefined_identifier (parser); break; case RID_VA_ARG: { @@ -11997,15 +12010,9 @@ c_parser_omp_variable_list (c_parser *pa { auto_vec<c_token> tokens; unsigned int tokens_avail = 0; + bool first = true; - if (kind != OMP_CLAUSE_DEPEND - && (c_parser_next_token_is_not (parser, CPP_NAME) - || c_parser_peek_token (parser)->id_kind != C_ID_ID)) - c_parser_error (parser, "expected identifier"); - - while (kind == OMP_CLAUSE_DEPEND - || (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_ID)) + while (1) { bool array_section_p = false; if (kind == OMP_CLAUSE_DEPEND) @@ -12026,6 +12033,7 @@ c_parser_omp_variable_list (c_parser *pa break; c_parser_consume_token (parser); + first = false; continue; } @@ -12076,16 +12084,35 @@ c_parser_omp_variable_list (c_parser *pa parser->tokens_avail = tokens.length (); } - tree t = lookup_name (c_parser_peek_token (parser)->value); + tree t = NULL_TREE; - if (t == NULL_TREE) + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) { - undeclared_variable (c_parser_peek_token (parser)->location, - c_parser_peek_token (parser)->value); - t = error_mark_node; - } + t = lookup_name (c_parser_peek_token (parser)->value); - c_parser_consume_token (parser); + if (t == NULL_TREE) + { + undeclared_variable (c_parser_peek_token (parser)->location, + c_parser_peek_token (parser)->value); + t = error_mark_node; + } + + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is (parser, CPP_KEYWORD) + && (c_parser_peek_token (parser)->keyword == RID_FUNCTION_NAME + || (c_parser_peek_token (parser)->keyword + == RID_PRETTY_FUNCTION_NAME) + || (c_parser_peek_token (parser)->keyword + == RID_C99_FUNCTION_NAME))) + t = c_parser_predefined_identifier (parser).value; + else + { + if (first) + c_parser_error (parser, "expected identifier"); + break; + } if (t == error_mark_node) ; @@ -12223,6 +12250,7 @@ c_parser_omp_variable_list (c_parser *pa break; c_parser_consume_token (parser); + first = false; } return list; --- gcc/c/c-typeck.c.jj 2019-09-27 12:22:53.529888399 +0200 +++ gcc/c/c-typeck.c 2019-09-27 13:20:33.433958093 +0200 @@ -14822,6 +14822,13 @@ c_finish_omp_clauses (tree clauses, enum case OMP_CLAUSE_DEFAULT_UNSPECIFIED: break; case OMP_CLAUSE_DEFAULT_SHARED: + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) + && c_omp_predefined_variable (t)) + /* The __func__ variable and similar function-local + predefined variables may be listed in a shared or + firstprivate clause. */ + break; share_name = "shared"; break; case OMP_CLAUSE_DEFAULT_PRIVATE: --- gcc/cp/parser.c.jj 2019-09-26 21:34:26.302847332 +0200 +++ gcc/cp/parser.c 2019-09-27 15:54:55.458954251 +0200 @@ -32736,6 +32736,14 @@ cp_parser_omp_var_list_no_open (cp_parse decl = TREE_OPERAND (decl, 0); cp_lexer_consume_token (parser->lexer); } + else if (cp_parser_is_keyword (token, RID_FUNCTION_NAME) + || cp_parser_is_keyword (token, RID_PRETTY_FUNCTION_NAME) + || cp_parser_is_keyword (token, RID_C99_FUNCTION_NAME)) + { + cp_id_kind idk; + decl = cp_parser_primary_expression (parser, false, false, false, + &idk); + } else { name = cp_parser_id_expression (parser, /*template_p=*/false, --- gcc/cp/semantics.c.jj 2019-09-20 12:25:26.070729807 +0200 +++ gcc/cp/semantics.c 2019-09-27 13:21:05.597473200 +0200 @@ -7967,6 +7967,13 @@ finish_omp_clauses (tree clauses, enum c case OMP_CLAUSE_DEFAULT_UNSPECIFIED: break; case OMP_CLAUSE_DEFAULT_SHARED: + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) + && c_omp_predefined_variable (t)) + /* The __func__ variable and similar function-local predefined + variables may be listed in a shared or firstprivate + clause. */ + break; if (VAR_P (t) && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE && TREE_STATIC (t) --- gcc/cp/cp-gimplify.c.jj 2019-08-29 10:22:17.554533572 +0200 +++ gcc/cp/cp-gimplify.c 2019-09-27 13:01:03.078550974 +0200 @@ -2055,6 +2055,9 @@ cxx_omp_predetermined_sharing_1 (tree de tree ctx = CP_DECL_CONTEXT (decl); if (TYPE_P (ctx) && MAYBE_CLASS_TYPE_P (ctx)) return OMP_CLAUSE_DEFAULT_SHARED; + + if (c_omp_predefined_variable (decl)) + return OMP_CLAUSE_DEFAULT_SHARED; } /* this may not be specified in data-sharing clauses, still we need --- gcc/testsuite/c-c++-common/gomp/pr88203-1.c.jj 2019-09-27 16:30:59.633617735 +0200 +++ gcc/testsuite/c-c++-common/gomp/pr88203-1.c 2019-09-27 16:07:03.997053776 +0200 @@ -0,0 +1,61 @@ +/* PR c++/88203 */ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99" { target c } } */ +/* { dg-additional-options "-std=c++11" { target c++ } } */ + +void foo (const char *); +#pragma omp declare target to (foo) + +void +f1 (void) +{ + #pragma omp parallel default(none) + foo (__func__); +} + +void +f2 (void) +{ + #pragma omp parallel default(none) shared(__func__) + foo (__func__); +} + +void +f3 (void) +{ + #pragma omp parallel default(none) firstprivate(__func__) + foo (__func__); +} + +void +f4 (void) +{ + foo (__func__); + #pragma omp parallel default(none) + foo (__func__); +} + +void +f5 (void) +{ + foo (__func__); + #pragma omp parallel default(none) shared(__func__) + foo (__func__); +} + +void +f6 (void) +{ + foo (__func__); + #pragma omp parallel default(none) firstprivate(__func__) + foo (__func__); +} + +void +f7 (void) +{ + #pragma omp target map(to: __func__) + foo (__func__); + #pragma omp task depend(inout:__func__) + foo (__func__); +} --- gcc/testsuite/c-c++-common/gomp/pr88203-2.c.jj 2019-09-27 16:31:16.317370301 +0200 +++ gcc/testsuite/c-c++-common/gomp/pr88203-2.c 2019-09-27 16:33:19.533542874 +0200 @@ -0,0 +1,65 @@ +/* PR c++/88203 */ +/* { dg-do compile } */ +/* { dg-additional-options "-std=gnu99" { target c } } */ +/* { dg-additional-options "-std=gnu++11" { target c++ } } */ + +void foo (const char *, const char *); +#pragma omp declare target to (foo) + +void +f1 (void) +{ + #pragma omp parallel default(none) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f2 (void) +{ + #pragma omp parallel default(none) shared(__FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp parallel default(none) shared(__FUNCTION__) firstprivate(__PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f3 (void) +{ + #pragma omp parallel default(none) firstprivate(__FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp parallel default(none) firstprivate(__FUNCTION__), shared(__PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f4 (void) +{ + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp parallel default(none) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f5 (void) +{ + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp parallel default(none) shared(__FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f6 (void) +{ + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp parallel default(none) firstprivate(__FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} + +void +f7 (void) +{ + #pragma omp target map(to: __FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); + #pragma omp task depend(inout:__FUNCTION__, __PRETTY_FUNCTION__) + foo (__FUNCTION__, __PRETTY_FUNCTION__); +} --- gcc/testsuite/c-c++-common/gomp/pr88203-3.c.jj 2019-09-27 16:39:59.077617196 +0200 +++ gcc/testsuite/c-c++-common/gomp/pr88203-3.c 2019-09-27 17:32:23.966774256 +0200 @@ -0,0 +1,28 @@ +/* PR c++/88203 */ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99" { target c } } */ +/* { dg-additional-options "-std=c++11" { target c++ } } */ + +void foo (const char *); +#pragma omp declare target to (foo) + +void +f1 (void) +{ + #pragma omp parallel for lastprivate (__func__) /* { dg-error "'__func__' is predetermined 'shared' for 'lastprivate'" } */ + for (int i = 0; i < 2; i++) + foo (__func__); + #pragma omp parallel private (__func__) /* { dg-error "'__func__' is predetermined 'shared' for 'private'" } */ + foo (__func__); +} + +void +f2 (void) +{ + foo (__func__); + #pragma omp parallel default(none) private (__func__) /* { dg-error "'__func__' is predetermined 'shared' for 'private'" } */ + foo (__func__); + #pragma omp parallel for default(none) lastprivate (__func__) /* { dg-error "'__func__' is predetermined 'shared' for 'lastprivate'" } */ + for (int i = 0; i < 2; i++) + foo (__func__); +} Jakub