https://gcc.gnu.org/g:98f8571728647a8f650c85f7b5d3d31666ef902a

commit 98f8571728647a8f650c85f7b5d3d31666ef902a
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.
    
    (cherry picked from commit 08c299a410b9314957e48a87f5bf50a4c034b744)

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 d132704c197d..368caf898e00 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -28425,17 +28425,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 f984940981ca..e512c72aab3b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7951,6 +7951,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 9c1d97625ed8..4e1a491856d8 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -51717,12 +51717,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 fc2b31ffcc42..274712606bb3 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -18415,7 +18415,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:
@@ -18423,12 +18425,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 f1523ed9dd51..0029080cdcd5 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" } } */

Reply via email to