https://gcc.gnu.org/g:08c299a410b9314957e48a87f5bf50a4c034b744
commit r16-1044-g08c299a410b9314957e48a87f5bf50a4c034b744 Author: Sandra Loosemore <sloosem...@baylibre.com> Date: Mon Jun 2 03:26:42 2025 +0000 OpenMP: Handle more cases in user/condition selector Tobias had noted that the C front end was not treating C23 constexprs as constant in the user/condition selector property, which led to missed opportunities to resolve metadirectives at parse time. Additionally neither C nor C++ was permitting the expression to have pointer or floating-point type -- the former being a common idiom in other C/C++ conditional expressions. By using the existing front-end hooks for the implicit conversion to bool in conditional expressions, we also get free support for using a C++ class object that has a bool conversion operator in the user/condition selector. gcc/c/ChangeLog * c-parser.cc (c_parser_omp_context_selector): Call convert_lvalue_to_rvalue and c_objc_common_truthvalue_conversion on the expression for OMP_TRAIT_PROPERTY_BOOL_EXPR. gcc/cp/ChangeLog * cp-tree.h (maybe_convert_cond): Declare. * parser.cc (cp_parser_omp_context_selector): Call maybe_convert_cond and fold_build_cleanup_point_expr on the expression for OMP_TRAIT_PROPERTY_BOOL_EXPR. * pt.cc (tsubst_omp_context_selector): Likewise. * semantics.cc (maybe_convert_cond): Remove static declaration. gcc/testsuite/ChangeLog * c-c++-common/gomp/declare-variant-2.c: Update expected output. * c-c++-common/gomp/metadirective-condition-constexpr.c: New. * c-c++-common/gomp/metadirective-condition.c: New. * c-c++-common/gomp/metadirective-error-recovery.c: Update expected output. * g++.dg/gomp/metadirective-condition-class.C: New. * g++.dg/gomp/metadirective-condition-template.C: New. Diff: --- gcc/c/c-parser.cc | 19 ++++++++-- gcc/cp/cp-tree.h | 1 + gcc/cp/parser.cc | 21 +++++++++-- gcc/cp/pt.cc | 30 +++++++++++---- gcc/cp/semantics.cc | 3 +- .../c-c++-common/gomp/declare-variant-2.c | 2 +- .../gomp/metadirective-condition-constexpr.c | 13 +++++++ .../c-c++-common/gomp/metadirective-condition.c | 25 +++++++++++++ .../gomp/metadirective-error-recovery.c | 9 ++++- .../g++.dg/gomp/metadirective-condition-class.C | 43 ++++++++++++++++++++++ .../g++.dg/gomp/metadirective-condition-template.C | 41 +++++++++++++++++++++ 11 files changed, 188 insertions(+), 19 deletions(-) diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index cc0ab1231660..85580c57abfe 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -26966,17 +26966,30 @@ c_parser_omp_context_selector (c_parser *parser, enum omp_tss_code set, break; case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR: case OMP_TRAIT_PROPERTY_BOOL_EXPR: - t = c_parser_expr_no_commas (parser, NULL).value; + { + c_expr texpr = c_parser_expr_no_commas (parser, NULL); + texpr = convert_lvalue_to_rvalue (token->location, texpr, + true, true); + t = texpr.value; + } if (t == error_mark_node) return error_mark_node; mark_exp_read (t); - t = c_fully_fold (t, false, NULL); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) + { + t = c_objc_common_truthvalue_conversion (token->location, + t, + boolean_type_node); + if (t == error_mark_node) + return error_mark_node; + } + else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) { error_at (token->location, "property must be integer expression"); return error_mark_node; } + t = c_fully_fold (t, false, NULL); properties = make_trait_property (NULL_TREE, t, properties); break; case OMP_TRAIT_PROPERTY_CLAUSE_LIST: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e5e20e1e7a54..3cf4a7654b39 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7956,6 +7956,7 @@ extern bool perform_deferred_access_checks (tsubst_flags_t); extern bool perform_or_defer_access_check (tree, tree, tree, tsubst_flags_t, access_failure_info *afi = NULL); +extern tree maybe_convert_cond (tree); /* RAII sentinel to ensures that deferred access checks are popped before a function returns. */ diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3d30339b7b05..86337635f48d 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -49986,12 +49986,25 @@ cp_parser_omp_context_selector (cp_parser *parser, enum omp_tss_code set, && !value_dependent_expression_p (t)) { t = fold_non_dependent_expr (t); - if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) { - error_at (token->location, - "property must be integer expression"); - return error_mark_node; + t = maybe_convert_cond (t); + if (t == error_mark_node) + return error_mark_node; + } + else + { + t = convert_from_reference (t); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (token->location, + "property must be integer expression"); + return error_mark_node; + } } + if (!processing_template_decl + && TREE_CODE (t) != CLEANUP_POINT_EXPR) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); } properties = make_trait_property (NULL_TREE, t, properties); break; diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index ccb623da499f..c5a3abe6d8b9 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -18380,7 +18380,9 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain, } } - switch (omp_ts_map[OMP_TS_CODE (sel)].tp_type) + enum omp_tp_type property_kind + = omp_ts_map[OMP_TS_CODE (sel)].tp_type; + switch (property_kind) { case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR: case OMP_TRAIT_PROPERTY_BOOL_EXPR: @@ -18388,12 +18390,26 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain, args, complain, in_decl); t = fold_non_dependent_expr (t); if (!value_dependent_expression_p (t) - && !type_dependent_expression_p (t) - && !INTEGRAL_TYPE_P (TREE_TYPE (t))) - error_at (cp_expr_loc_or_input_loc (t), - "property must be integer expression"); - else - properties = make_trait_property (NULL_TREE, t, NULL_TREE); + && !type_dependent_expression_p (t)) + { + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) + t = maybe_convert_cond (t); + else + { + t = convert_from_reference (t); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (cp_expr_loc_or_input_loc (t), + "property must be integer expression"); + t = error_mark_node; + } + } + } + if (t != error_mark_node + && !processing_template_decl + && TREE_CODE (t) != CLEANUP_POINT_EXPR) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + properties = make_trait_property (NULL_TREE, t, NULL_TREE); break; case OMP_TRAIT_PROPERTY_CLAUSE_LIST: if (OMP_TS_CODE (sel) == OMP_TRAIT_CONSTRUCT_SIMD) diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index cafc9d0ee2c3..6551ca919286 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -52,7 +52,6 @@ along with GCC; see the file COPYING3. If not see during template instantiation, which may be regarded as a degenerate form of parsing. */ -static tree maybe_convert_cond (tree); static tree finalize_nrv_r (tree *, int *, void *); /* Used for OpenMP non-static data member privatization. */ @@ -1117,7 +1116,7 @@ annotate_saver::restore (tree new_inner) statement. Convert it to a boolean value, if appropriate. In addition, verify sequence points if -Wsequence-point is enabled. */ -static tree +tree maybe_convert_cond (tree cond) { /* Empty conditions remain empty. */ diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c index f8f514313533..83e1bb10058a 100644 --- a/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c +++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c @@ -38,7 +38,7 @@ void f18 (void); void f19 (void); #pragma omp declare variant (f1) match(user={condition()}) /* { dg-error "expected \[^\n\r]*expression before '\\)' token" } */ void f20 (void); -#pragma omp declare variant (f1) match(user={condition(f1)}) /* { dg-error "property must be integer expression" } */ +#pragma omp declare variant (f1) match(user={condition(f1)}) void f21 (void); #pragma omp declare variant (f1) match(user={condition(1, 2, 3)}) /* { dg-error "expected '\\)' before ',' token" } */ void f22 (void); diff --git a/gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c b/gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c new file mode 100644 index 000000000000..3484478567c3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target { c || c++11 } } } */ +/* { dg-additional-options "-std=c23" { target c } } */ +/* { dg-additional-options "-fdump-tree-original" } */ + +constexpr int flag = 1; + +void f() { +#pragma omp metadirective when(user={condition(flag)} : nothing) \ + otherwise(error at(execution)) +} + +/* { dg-final { scan-tree-dump-not "__builtin_GOMP_error" "original" } } */ + diff --git a/gcc/testsuite/c-c++-common/gomp/metadirective-condition.c b/gcc/testsuite/c-c++-common/gomp/metadirective-condition.c new file mode 100644 index 000000000000..099ad9d2cc1f --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/metadirective-condition.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-original" } */ + +static int arr[10]; +static int g (int a) { return -a; } + +void f (int *ptr, float x) { + + /* Implicit conversion float -> bool */ + #pragma omp metadirective when(user={condition(x)} : nothing) otherwise(nothing) + + /* Implicit conversion pointer -> bool */ + #pragma omp metadirective when(user={condition(ptr)} : nothing) otherwise(nothing) + + /* Array expression undergoes array->pointer conversion, OK but test is + always optimized away. */ + #pragma omp metadirective when(user={condition(arr)} : nothing) otherwise(nothing) + + /* Function reference has pointer-to-function type, OK but test is + always optimized away. */ + #pragma omp metadirective when(user={condition(g)} : nothing) otherwise(nothing) +} + +/* { dg-final { scan-tree-dump "x != 0.0" "original" } } */ +/* { dg-final { scan-tree-dump "ptr != 0B" "original" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c b/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c index 324228113c25..92995a22319f 100644 --- a/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c +++ b/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c @@ -15,6 +15,11 @@ void f (int aa, int bb) s2.b = bb + 1; /* A struct is not a valid argument for the condition selector. */ - #pragma omp metadirective when(user={condition(s1)} : nothing) otherwise(nothing) /* { dg-error "property must be integer expression" } */ - #pragma omp metadirective when(user={condition(s2)} : nothing) otherwise(nothing) /* { dg-error "property must be integer expression" } */ + #pragma omp metadirective when(user={condition(s1)} : nothing) otherwise(nothing) + /* { dg-error "used struct type value where scalar is required" "" { target c } .-1 } */ + /* { dg-error "could not convert .s1. from .s. to .bool." "" { target c++ } .-2 } */ + #pragma omp metadirective when(user={condition(s2)} : nothing) otherwise(nothing) + /* { dg-error "used struct type value where scalar is required" "" { target c } .-1 } */ + /* { dg-error "could not convert .s2. from .s. to .bool." "" { target c++ } .-2 } */ + } diff --git a/gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C b/gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C new file mode 100644 index 000000000000..64036116df81 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-original" } */ + +class c +{ + public: + int x; + c (int xx) { x = xx; } + operator bool() { return x != 0; } +}; + +void f (c &objref) +{ + #pragma omp metadirective when(user={condition(objref)} : nothing) otherwise(nothing) +} + + +template <typename T> class d +{ + public: + T x; + d (T xx) { x = xx; } + operator bool() { return x != 0; } +}; + +template <typename T> +void g (d<T> &objref) +{ + #pragma omp metadirective when(user={condition(objref)} : nothing) otherwise(nothing) +} + +int main (void) +{ + c obj1 (42); + d<int> obj2 (69); + + f (obj1); + g (obj2); +} + +/* { dg-final { scan-tree-dump "c::operator bool \\(\\(struct c .\\) objref\\)" "original" } } */ + +/* { dg-final { scan-tree-dump "d<int>::operator bool \\(\\(struct d .\\) objref\\)" "original" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C b/gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C new file mode 100644 index 000000000000..30783d97305d --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-original" } */ + +template<typename T, typename T2> +void f (T x, T2 y) +{ + #pragma omp metadirective when(user={condition(x)}, \ + target_device={device_num(y)} : flush) +} + +class c +{ + public: + int x; + c (int xx) { x = xx; } + operator bool() { return x != 0; } +}; + +template <typename T> class d +{ + public: + T x; + d (T xx) { x = xx; } + operator bool() { return x != 0; } +}; + +int main (void) +{ + c obj1 (42); + d<int> obj2 (69); + + f (42, 0); + f (&obj1, 0); + f (obj1, 0); + f (obj2, 0); +} + +/* { dg-final { scan-tree-dump-times "if \\(x != 0 &&" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "if \\(x != 0B &&" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "if \\(<<cleanup_point c::operator bool \\(&x\\)>> &&" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "if \\(<<cleanup_point d<int>::operator bool \\(&x\\)>> &&" 1 "original" } } */