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

Reply via email to