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 * parser.cc (cp_parser_omp_context_selector): Call convert_from_reference and condition_conversion on the expression for OMP_TRAIT_PROPERTY_BOOL_EXPR. * pt.cc (tsubst_omp_context_selector): Likewise. 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. --- gcc/c/c-parser.cc | 19 ++++++-- gcc/cp/parser.cc | 9 +++- gcc/cp/pt.cc | 23 +++++++--- .../c-c++-common/gomp/declare-variant-2.c | 2 +- .../gomp/metadirective-condition-constexpr.c | 13 ++++++ .../gomp/metadirective-condition.c | 25 +++++++++++ .../gomp/metadirective-error-recovery.c | 9 +++- .../gomp/metadirective-condition-class.C | 43 +++++++++++++++++++ 8 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c create mode 100644 gcc/testsuite/c-c++-common/gomp/metadirective-condition.c create mode 100644 gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index faef65879c6..ec1d7698aac 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -26818,17 +26818,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/parser.cc b/gcc/cp/parser.cc index 022e4db4650..20ad6f160b3 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -49877,7 +49877,14 @@ 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))) + t = convert_from_reference (t); + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) + { + t = condition_conversion (t); + 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"); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index c687fdc71a3..40d8ebd15a5 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -18368,7 +18368,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: @@ -18376,12 +18378,19 @@ 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)) + { + t = convert_from_reference (t); + if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR) + t = condition_conversion (t); + else 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; + } + } + 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/testsuite/c-c++-common/gomp/declare-variant-2.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c index f8f51431353..83e1bb10058 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 00000000000..3484478567c --- /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 00000000000..099ad9d2cc1 --- /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 324228113c2..92995a22319 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 00000000000..64036116df8 --- /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" } } */ -- 2.34.1