On 5/29/25 02:51, Tobias Burnus wrote:
@Jason – The idea is make semantics.cc's maybe_convert_cond callable
from parser.cc + pt.cc, i.e. to make it a non-static function.
Any reasons not do so?

Sandra Loosemore wrote:

[…] 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.

Can you also add type-dependent testcases? They seem to work fine,
but are missing. Like

template<typename T, typename T2>
void f(T x, T2 y) {
 #pragma omp metadirective when(user={condition(x)}, target_device={device_num(y)} : flush)
}

plus calls to them.

* * *

In parser.cc and pt.cc, you don't call maybe_convert_cond (because it is
currently accessible) - but by calling some of its ingredients, you
bypass some code.
I discussed with Jakub and the idea is (see top of the page) to make
maybe_convert_cond non-static and use it instead.

Additionally, it seems as if we should add

   if (!processing_template_decl)
     t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);

as we do for the other clauses.


Like the attached V2 patch?

-Sandra
From 802bbefdf57548cee0e5aaab518b95a99aa26593 Mon Sep 17 00:00:00 2001
From: Sandra Loosemore <sloosem...@baylibre.com>
Date: Fri, 30 May 2025 03:14:35 +0000
Subject: [PATCH V2] 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.
---
 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 ++++++
 .../gomp/metadirective-condition.c            | 25 +++++++++++
 .../gomp/metadirective-error-recovery.c       |  9 +++-
 .../gomp/metadirective-condition-class.C      | 43 +++++++++++++++++++
 .../gomp/metadirective-condition-template.C   | 41 ++++++++++++++++++
 11 files changed, 188 insertions(+), 19 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
 create mode 100644 gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 4144aa17fde..e11e6034461 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -26865,17 +26865,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 d9fc80b92e5..b42c67872a6 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7948,6 +7948,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 3e39bf33fab..2dcf263a531 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -49883,12 +49883,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 c687fdc71a3..b003e5df326 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,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 241f2730878..f3bd08be3b2 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -51,7 +51,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.  */
@@ -1116,7 +1115,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 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" } } */
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 00000000000..3632b75381e
--- /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 "if \\(x != 0" "original" } } */
+/* { dg-final { scan-tree-dump "if \\(x != 0B" "original" } } */
+/* { dg-final { scan-tree-dump "if \\(<<cleanup_point c::operator bool \\(&x\\)>>" "original" } } */
+/* { dg-final { scan-tree-dump "if \\(<<cleanup_point d<int>::operator bool \\(&x\\)>>" "original" } } */
-- 
2.34.1

Reply via email to