]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
OpenMP: Handle more cases in user/condition selector
authorSandra Loosemore <sloosemore@baylibre.com>
Mon, 2 Jun 2025 03:26:42 +0000 (03:26 +0000)
committerSandra Loosemore <sloosemore@baylibre.com>
Mon, 2 Jun 2025 03:29:14 +0000 (03:29 +0000)
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.

gcc/c/c-parser.cc
gcc/cp/cp-tree.h
gcc/cp/parser.cc
gcc/cp/pt.cc
gcc/cp/semantics.cc
gcc/testsuite/c-c++-common/gomp/declare-variant-2.c
gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/metadirective-condition.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c
gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C [new file with mode: 0644]

index cc0ab1231660ac1166f035e7bc2b097f8c101f5e..85580c57abfe4626e431a3fe3f12e20af208cf2f 100644 (file)
@@ -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:
index e5e20e1e7a54f2ae13a7cb8bdde46557ea31c76a..3cf4a7654b3956775ca0d38848e2b32b25f899df 100644 (file)
@@ -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.  */
index 3d30339b7b05d4c8e085dc2e4e807b69c1136e3d..86337635f48d7ab558320e5dca23223407797200 100644 (file)
@@ -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;
index ccb623da499f469a6d78aae4a5d3373475764ea6..c5a3abe6d8b9b82cb3fe69123903049321fb7ae2 100644 (file)
@@ -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)
index cafc9d0ee2c3b4ae733c4833a9945c92a36586c4..6551ca919286cc918787349495c76b7501b1eddf 100644 (file)
@@ -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.  */
index f8f514313533ac9e396d9d6b59dc210952034b67..83e1bb10058a2bbeb08e04c30b13ecbf6fd9c670 100644 (file)
@@ -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 (file)
index 0000000..3484478
--- /dev/null
@@ -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 (file)
index 0000000..099ad9d
--- /dev/null
@@ -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" } } */
index 324228113c258fefb50d3a5ea07e582aeed4aeca..92995a22319f3456ceb3ebea6c3c9f4a9012dc21 100644 (file)
@@ -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 (file)
index 0000000..6403611
--- /dev/null
@@ -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 (file)
index 0000000..30783d9
--- /dev/null
@@ -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" } } */