From cf49e8f0186e78479b2e356b5139d3989c039f92 Mon Sep 17 00:00:00 2001
From: Yuao Ma <c8ef@outlook.com>
Date: Fri, 12 Sep 2025 20:28:19 +0800
Subject: [PATCH] fortran: implement conditional expression for fortran 2023

This patch adds support for conditional expressions in Fortran 2023 for a
limited set of types (logical, numerical), and also includes limited support
for conditional arguments without `.nil.` support.

gcc/fortran/ChangeLog:

	* dump-parse-tree.cc (show_expr): Add support for EXPR_CONDITIONAL.
	* expr.cc (gfc_get_conditional_expr): Add cond-expr constructor.
	(gfc_copy_expr, free_expr0, gfc_is_constant_expr,
	simplify_conditional, gfc_simplify_expr, gfc_check_init_expr,
	check_restricted, gfc_traverse_expr): Add support for EXPR_CONDITIONAL.
	* frontend-passes.cc (gfc_expr_walker): Ditto.
	* gfortran.h (enum expr_t): Add EXPR_CONDITIONAL.
	(gfc_get_operator_expr): Format fix.
	(gfc_get_conditional_expr): New decl.
	* matchexp.cc
	(match_conditional, match_primary): Parsing for EXPR_CONDITIONAL.
	* module.cc (mio_expr): Add support for EXPR_CONDITIONAL.
	* resolve.cc (resolve_conditional, gfc_resolve_expr): Ditto.
	* trans-array.cc (gfc_walk_conditional_expr, gfc_walk_subexpr): Ditto.
	* trans-expr.cc
	(gfc_conv_conditional_expr): Codegen for EXPR_CONDITIONAL.
	(gfc_apply_interface_mapping_to_expr, gfc_conv_expr,
	gfc_conv_expr_reference): Add support for EXPR_CONDITIONAL.

gcc/testsuite/ChangeLog:

	* gfortran.dg/conditional_1.f90: New test.
	* gfortran.dg/conditional_2.f90: New test.
	* gfortran.dg/conditional_3.f90: New test.
	* gfortran.dg/conditional_4.f90: New test.
	* gfortran.dg/conditional_5.f90: New test.
	* gfortran.dg/conditional_6.f90: New test.
	* gfortran.dg/conditional_7.f90: New test.
	* gfortran.dg/conditional_8.f90: New test.
	* gfortran.dg/conditional_9.f90: New test.
---
 gcc/fortran/dump-parse-tree.cc              |  10 ++
 gcc/fortran/expr.cc                         | 118 ++++++++++++++++++++
 gcc/fortran/frontend-passes.cc              |   5 +
 gcc/fortran/gfortran.h                      |  30 ++++-
 gcc/fortran/matchexp.cc                     |  79 +++++++++++--
 gcc/fortran/module.cc                       |  10 +-
 gcc/fortran/resolve.cc                      |  71 ++++++++++++
 gcc/fortran/trans-array.cc                  |  13 +++
 gcc/fortran/trans-expr.cc                   |  70 ++++++++++++
 gcc/testsuite/gfortran.dg/conditional_1.f90 |  32 ++++++
 gcc/testsuite/gfortran.dg/conditional_2.f90 |  13 +++
 gcc/testsuite/gfortran.dg/conditional_3.f90 |   9 ++
 gcc/testsuite/gfortran.dg/conditional_4.f90 |  21 ++++
 gcc/testsuite/gfortran.dg/conditional_5.f90 |   7 ++
 gcc/testsuite/gfortran.dg/conditional_6.f90 |  16 +++
 gcc/testsuite/gfortran.dg/conditional_7.f90 |  11 ++
 gcc/testsuite/gfortran.dg/conditional_8.f90 |  14 +++
 gcc/testsuite/gfortran.dg/conditional_9.f90 |  11 ++
 18 files changed, 522 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/conditional_1.f90
 create mode 100644 gcc/testsuite/gfortran.dg/conditional_2.f90
 create mode 100644 gcc/testsuite/gfortran.dg/conditional_3.f90
 create mode 100644 gcc/testsuite/gfortran.dg/conditional_4.f90
 create mode 100644 gcc/testsuite/gfortran.dg/conditional_5.f90
 create mode 100644 gcc/testsuite/gfortran.dg/conditional_6.f90
 create mode 100644 gcc/testsuite/gfortran.dg/conditional_7.f90
 create mode 100644 gcc/testsuite/gfortran.dg/conditional_8.f90
 create mode 100644 gcc/testsuite/gfortran.dg/conditional_9.f90

diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 3cd2eeef11a..eda0659d6e2 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -767,6 +767,16 @@ show_expr (gfc_expr *p)
 
       break;
 
+    case EXPR_CONDITIONAL:
+      fputc ('(', dumpfile);
+      show_expr (p->value.conditional.condition);
+      fputs (" ? ", dumpfile);
+      show_expr (p->value.conditional.true_expr);
+      fputs (" : ", dumpfile);
+      show_expr (p->value.conditional.false_expr);
+      fputc (')', dumpfile);
+      break;
+
     case EXPR_COMPCALL:
       show_compcall (p);
       break;
diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index 3dbf8cb287a..a11ff79ab6b 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -116,6 +116,25 @@ gfc_get_operator_expr (locus *where, gfc_intrinsic_op op,
   return e;
 }
 
+/* Get a new expression node that is an conditional expression node.  */
+
+gfc_expr *
+gfc_get_conditional_expr (locus *where, gfc_expr *condition,
+			  gfc_expr *true_expr, gfc_expr *false_expr)
+{
+  gfc_expr *e;
+
+  e = gfc_get_expr ();
+  e->expr_type = EXPR_CONDITIONAL;
+  e->value.conditional.condition = condition;
+  e->value.conditional.true_expr = true_expr;
+  e->value.conditional.false_expr = false_expr;
+
+  if (where)
+    e->where = *where;
+
+  return e;
+}
 
 /* Get a new expression node that is an structure constructor
    of given type and kind.  */
@@ -393,6 +412,15 @@ gfc_copy_expr (gfc_expr *p)
 
       break;
 
+    case EXPR_CONDITIONAL:
+      q->value.conditional.condition
+	= gfc_copy_expr (p->value.conditional.condition);
+      q->value.conditional.true_expr
+	= gfc_copy_expr (p->value.conditional.true_expr);
+      q->value.conditional.false_expr
+	= gfc_copy_expr (p->value.conditional.false_expr);
+      break;
+
     case EXPR_FUNCTION:
       q->value.function.actual =
 	gfc_copy_actual_arglist (p->value.function.actual);
@@ -502,6 +530,12 @@ free_expr0 (gfc_expr *e)
 	gfc_free_expr (e->value.op.op2);
       break;
 
+    case EXPR_CONDITIONAL:
+      gfc_free_expr (e->value.conditional.condition);
+      gfc_free_expr (e->value.conditional.true_expr);
+      gfc_free_expr (e->value.conditional.false_expr);
+      break;
+
     case EXPR_FUNCTION:
       gfc_free_actual_arglist (e->value.function.actual);
       break;
@@ -1083,6 +1117,11 @@ gfc_is_constant_expr (gfc_expr *e)
 	      && (e->value.op.op2 == NULL
 		  || gfc_is_constant_expr (e->value.op.op2)));
 
+    case EXPR_CONDITIONAL:
+      return gfc_is_constant_expr (e->value.conditional.condition)
+	     && gfc_is_constant_expr (e->value.conditional.true_expr)
+	     && gfc_is_constant_expr (e->value.conditional.false_expr);
+
     case EXPR_VARIABLE:
       /* The only context in which this can occur is in a parameterized
 	 derived type declaration, so returning true is OK.  */
@@ -1354,6 +1393,43 @@ simplify_intrinsic_op (gfc_expr *p, int type)
   return true;
 }
 
+/* Try to collapse conditional expressions.  */
+
+static bool
+simplify_conditional (gfc_expr *p, int type)
+{
+  gfc_expr *condition, *true_expr, *false_expr;
+
+  condition = p->value.conditional.condition;
+  true_expr = p->value.conditional.true_expr;
+  false_expr = p->value.conditional.false_expr;
+
+  if (!gfc_simplify_expr (condition, type)
+      || !gfc_simplify_expr (true_expr, type)
+      || !gfc_simplify_expr (false_expr, type))
+    return false;
+
+  if (!gfc_is_constant_expr (condition))
+    return true;
+
+  p->value.conditional.condition = NULL;
+  p->value.conditional.true_expr = NULL;
+  p->value.conditional.false_expr = NULL;
+
+  if (condition->value.logical)
+    {
+      gfc_replace_expr (p, true_expr);
+      gfc_free_expr (false_expr);
+    }
+  else
+    {
+      gfc_replace_expr (p, false_expr);
+      gfc_free_expr (true_expr);
+    }
+  gfc_free_expr (condition);
+
+  return true;
+}
 
 /* Subroutine to simplify constructor expressions.  Mutually recursive
    with gfc_simplify_expr().  */
@@ -2459,6 +2535,11 @@ gfc_simplify_expr (gfc_expr *p, int type)
 	return false;
       break;
 
+    case EXPR_CONDITIONAL:
+      if (!simplify_conditional (p, type))
+	return false;
+      break;
+
     case EXPR_VARIABLE:
       /* Only substitute array parameter variables if we are in an
 	 initialization expression, or we want a subsection.  */
@@ -3133,6 +3214,20 @@ gfc_check_init_expr (gfc_expr *e)
 
       break;
 
+    case EXPR_CONDITIONAL:
+      t = gfc_check_init_expr (e->value.conditional.condition);
+      if (!t)
+	break;
+      t = gfc_check_init_expr (e->value.conditional.true_expr);
+      if (!t)
+	break;
+      t = gfc_check_init_expr (e->value.conditional.false_expr);
+      if (t)
+	t = gfc_simplify_expr (e, 0);
+      else
+	t = false;
+      break;
+
     case EXPR_FUNCTION:
       t = false;
 
@@ -3609,6 +3704,20 @@ check_restricted (gfc_expr *e)
 
       break;
 
+    case EXPR_CONDITIONAL:
+      t = check_restricted (e->value.conditional.condition);
+      if (!t)
+	break;
+      t = check_restricted (e->value.conditional.true_expr);
+      if (!t)
+	break;
+      t = check_restricted (e->value.conditional.false_expr);
+      if (t)
+	t = gfc_simplify_expr (e, 0);
+      else
+	t = false;
+      break;
+
     case EXPR_FUNCTION:
       if (e->value.function.esym)
 	{
@@ -5700,6 +5809,15 @@ gfc_traverse_expr (gfc_expr *expr, gfc_symbol *sym,
 	return true;
       break;
 
+    case EXPR_CONDITIONAL:
+      if (gfc_traverse_expr (expr->value.conditional.condition, sym, func, f))
+	return true;
+      if (gfc_traverse_expr (expr->value.conditional.true_expr, sym, func, f))
+	return true;
+      if (gfc_traverse_expr (expr->value.conditional.false_expr, sym, func, f))
+	return true;
+      break;
+
     default:
       gcc_unreachable ();
       break;
diff --git a/gcc/fortran/frontend-passes.cc b/gcc/fortran/frontend-passes.cc
index 02a0a2326a6..4a468b93600 100644
--- a/gcc/fortran/frontend-passes.cc
+++ b/gcc/fortran/frontend-passes.cc
@@ -5218,6 +5218,11 @@ gfc_expr_walker (gfc_expr **e, walk_expr_fn_t exprfn, void *data)
 	    for (a = (*e)->value.function.actual; a; a = a->next)
 	      WALK_SUBEXPR (a->expr);
 	    break;
+	  case EXPR_CONDITIONAL:
+	    WALK_SUBEXPR ((*e)->value.conditional.condition);
+	    WALK_SUBEXPR ((*e)->value.conditional.true_expr);
+	    WALK_SUBEXPR ((*e)->value.conditional.false_expr);
+	    break;
 	  case EXPR_COMPCALL:
 	  case EXPR_PPC:
 	    WALK_SUBEXPR ((*e)->value.compcall.base_object);
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 482031d2600..2e6b368b4c2 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -176,8 +176,19 @@ enum gfc_source_form
 
 /* Expression node types.  */
 enum expr_t
-  { EXPR_UNKNOWN = 0, EXPR_OP = 1, EXPR_FUNCTION, EXPR_CONSTANT, EXPR_VARIABLE,
-  EXPR_SUBSTRING, EXPR_STRUCTURE, EXPR_ARRAY, EXPR_NULL, EXPR_COMPCALL, EXPR_PPC
+{
+  EXPR_UNKNOWN = 0,
+  EXPR_OP = 1,
+  EXPR_FUNCTION,
+  EXPR_CONSTANT,
+  EXPR_VARIABLE,
+  EXPR_SUBSTRING,
+  EXPR_STRUCTURE,
+  EXPR_ARRAY,
+  EXPR_NULL,
+  EXPR_COMPCALL,
+  EXPR_PPC,
+  EXPR_CONDITIONAL,
 };
 
 /* Array types.  */
@@ -2809,8 +2820,14 @@ typedef struct gfc_expr
     character;
 
     gfc_constructor_base constructor;
-  }
-  value;
+
+    struct
+    {
+      struct gfc_expr *condition;
+      struct gfc_expr *true_expr;
+      struct gfc_expr *false_expr;
+    } conditional;
+  } value;
 
   /* Used to store PDT expression lists associated with expressions.  */
   gfc_actual_arglist *param_list;
@@ -3925,7 +3942,10 @@ bool gfc_is_ptr_fcn (gfc_expr *);
 gfc_expr *gfc_get_expr (void);
 gfc_expr *gfc_get_array_expr (bt type, int kind, locus *);
 gfc_expr *gfc_get_null_expr (locus *);
-gfc_expr *gfc_get_operator_expr (locus *, gfc_intrinsic_op,gfc_expr *, gfc_expr *);
+gfc_expr *gfc_get_operator_expr (locus *, gfc_intrinsic_op, gfc_expr *,
+				 gfc_expr *);
+gfc_expr *gfc_get_conditional_expr (locus *, gfc_expr *, gfc_expr *,
+				    gfc_expr *);
 gfc_expr *gfc_get_structure_constructor_expr (bt, int, locus *);
 gfc_expr *gfc_get_constant_expr (bt, int, locus *);
 gfc_expr *gfc_get_character_expr (int, locus *, const char *, gfc_charlen_t len);
diff --git a/gcc/fortran/matchexp.cc b/gcc/fortran/matchexp.cc
index 9b66243b4fa..e3a99253841 100644
--- a/gcc/fortran/matchexp.cc
+++ b/gcc/fortran/matchexp.cc
@@ -138,6 +138,65 @@ gfc_get_parentheses (gfc_expr *e)
   return e2;
 }
 
+/* Match a conditional expression.  */
+
+static match
+match_conditional (gfc_expr **result)
+{
+  gfc_expr *condition, *true_expr, *false_expr;
+  locus where;
+  match m;
+
+  where = gfc_current_locus;
+
+  m = gfc_match_expr (&condition);
+  if (m != MATCH_YES)
+    {
+      gfc_error (expression_syntax);
+      return MATCH_ERROR;
+    }
+
+  m = gfc_match_char ('?');
+  if (m != MATCH_YES)
+    {
+      *result = condition;
+      return MATCH_YES;
+    }
+  else if (!gfc_notify_std (GFC_STD_F2023, "Conditional expression at %L",
+			    &where))
+    {
+      gfc_free_expr (condition);
+      return MATCH_ERROR;
+    }
+
+  gfc_gobble_whitespace ();
+  m = gfc_match_expr (&true_expr);
+  if (m != MATCH_YES)
+    {
+      gfc_free_expr (condition);
+      return m;
+    }
+
+  m = gfc_match_char (':');
+  if (m != MATCH_YES)
+    {
+      gfc_error ("Expected ':' in conditional expression at %C");
+      gfc_free_expr (condition);
+      gfc_free_expr (true_expr);
+      return MATCH_ERROR;
+    }
+
+  m = match_conditional (&false_expr);
+  if (m != MATCH_YES)
+    {
+      gfc_free_expr (condition);
+      gfc_free_expr (true_expr);
+      return m;
+    }
+
+  *result = gfc_get_conditional_expr (&where, condition, true_expr, false_expr);
+  return MATCH_YES;
+}
 
 /* Match a primary expression.  */
 
@@ -163,20 +222,20 @@ match_primary (gfc_expr **result)
   if (gfc_match_char ('(') != MATCH_YES)
     return MATCH_NO;
 
-  m = gfc_match_expr (&e);
-  if (m == MATCH_NO)
-    goto syntax;
-  if (m == MATCH_ERROR)
+  m = match_conditional (&e);
+  if (m != MATCH_YES)
     return m;
 
   m = gfc_match_char (')');
   if (m == MATCH_NO)
     gfc_error ("Expected a right parenthesis in expression at %C");
 
-  /* Now we have the expression inside the parentheses, build the
-     expression pointing to it. By 7.1.7.2, any expression in
-     parentheses shall be treated as a data entity.  */
-  *result = gfc_get_parentheses (e);
+  /* Now we have the expression inside the parentheses, build the expression
+     pointing to it. By 7.1.7.2, any expression in parentheses shall be treated
+     as a data entity.
+     Note that if the expression is a conditional expression, we will omit the
+     extra parentheses.  */
+  *result = e->expr_type == EXPR_CONDITIONAL ? e : gfc_get_parentheses (e);
 
   if (m != MATCH_YES)
     {
@@ -185,10 +244,6 @@ match_primary (gfc_expr **result)
     }
 
   return MATCH_YES;
-
-syntax:
-  gfc_error (expression_syntax);
-  return MATCH_ERROR;
 }
 
 
diff --git a/gcc/fortran/module.cc b/gcc/fortran/module.cc
index e05b08bd14e..3168a6082eb 100644
--- a/gcc/fortran/module.cc
+++ b/gcc/fortran/module.cc
@@ -3622,7 +3622,9 @@ static const mstring expr_types[] = {
     minit ("ARRAY", EXPR_ARRAY),
     minit ("NULL", EXPR_NULL),
     minit ("COMPCALL", EXPR_COMPCALL),
-    minit (NULL, -1)
+    minit ("PPC", EXPR_PPC),
+    minit ("CONDITIONAL", EXPR_CONDITIONAL),
+    minit (NULL, -1),
 };
 
 /* INTRINSIC_ASSIGN is missing because it is used as an index for
@@ -3843,6 +3845,12 @@ mio_expr (gfc_expr **ep)
 
       break;
 
+    case EXPR_CONDITIONAL:
+      mio_expr (&e->value.conditional.condition);
+      mio_expr (&e->value.conditional.true_expr);
+      mio_expr (&e->value.conditional.false_expr);
+      break;
+
     case EXPR_FUNCTION:
       mio_symtree_ref (&e->symtree);
       mio_actual_arglist (&e->value.function.actual, false);
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 1a7c9dddb15..b83961fe6f1 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -4989,6 +4989,73 @@ simplify_op:
   return t;
 }
 
+static bool
+resolve_conditional (gfc_expr *expr)
+{
+  gfc_expr *condition, *true_expr, *false_expr;
+
+  condition = expr->value.conditional.condition;
+  true_expr = expr->value.conditional.true_expr;
+  false_expr = expr->value.conditional.false_expr;
+
+  if (!gfc_resolve_expr (condition) || !gfc_resolve_expr (true_expr)
+      || !gfc_resolve_expr (false_expr))
+    return false;
+
+  if (condition->ts.type != BT_LOGICAL || condition->rank != 0)
+    {
+      gfc_error (
+	"Condition in conditional expression must be a scalar logical at %L",
+	&condition->where);
+      return false;
+    }
+
+  if (true_expr->ts.type != false_expr->ts.type)
+    {
+      gfc_error ("expr at %L and expr at %L in conditional expression "
+		 "must have the same declared type",
+		 &true_expr->where, &false_expr->where);
+      return false;
+    }
+
+  if (true_expr->ts.kind != false_expr->ts.kind)
+    {
+      gfc_error ("expr at %L and expr at %L in conditional expression "
+		 "must have the same kind parameter",
+		 &true_expr->where, &false_expr->where);
+      return false;
+    }
+
+  if (true_expr->rank != false_expr->rank)
+    {
+      gfc_error ("expr at %L and expr at %L in conditional expression "
+		 "must have the same rank",
+		 &true_expr->where, &false_expr->where);
+      return false;
+    }
+
+  /* TODO: support more data types for conditional expressions  */
+  if (true_expr->ts.type != BT_INTEGER && true_expr->ts.type != BT_LOGICAL
+      && true_expr->ts.type != BT_REAL && true_expr->ts.type != BT_COMPLEX)
+    {
+      gfc_error ("Sorry, only integer, logical, real and complex types "
+		 "are currently supported for conditional expressions at %L",
+		 &expr->where);
+      return false;
+    }
+
+  if (true_expr->rank > 0)
+    {
+      gfc_error ("Sorry, array is currently unsupported for conditional "
+		 "expressions at %L",
+		 &expr->where);
+      return false;
+    }
+
+  expr->ts = true_expr->ts;
+  expr->rank = true_expr->rank;
+  return true;
+}
 
 /************** Array resolution subroutines **************/
 
@@ -8040,6 +8107,10 @@ gfc_resolve_expr (gfc_expr *e)
       t = resolve_operator (e);
       break;
 
+    case EXPR_CONDITIONAL:
+      t = resolve_conditional (e);
+      break;
+
     case EXPR_FUNCTION:
     case EXPR_VARIABLE:
 
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 0449c26ce6d..7f9168410a2 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -12713,6 +12713,15 @@ gfc_walk_op_expr (gfc_ss * ss, gfc_expr * expr)
   return head2;
 }
 
+static gfc_ss *
+gfc_walk_conditional_expr (gfc_ss *ss, gfc_expr *expr)
+{
+  gfc_ss *head;
+
+  head = gfc_walk_subexpr (ss, expr->value.conditional.true_expr);
+  head = gfc_walk_subexpr (head, expr->value.conditional.false_expr);
+  return head;
+}
 
 /* Reverse a SS chain.  */
 
@@ -12985,6 +12994,10 @@ gfc_walk_subexpr (gfc_ss * ss, gfc_expr * expr)
       head = gfc_walk_op_expr (ss, expr);
       return head;
 
+    case EXPR_CONDITIONAL:
+      head = gfc_walk_conditional_expr (ss, expr);
+      return head;
+
     case EXPR_FUNCTION:
       head = gfc_walk_function_expr (ss, expr);
       return head;
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index a9ea29f760f..e0ae41f12c6 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -4368,6 +4368,58 @@ gfc_conv_expr_op (gfc_se * se, gfc_expr * expr)
   gfc_add_block_to_block (&se->post, &lse.post);
 }
 
+static void
+gfc_conv_conditional_expr (gfc_se *se, gfc_expr *expr)
+{
+  gfc_se cond_se, true_se, false_se;
+  tree condition, true_val, false_val;
+  tree type;
+
+  gfc_init_se (&cond_se, se);
+  gfc_init_se (&true_se, se);
+  gfc_init_se (&false_se, se);
+
+  gfc_conv_expr (&cond_se, expr->value.conditional.condition);
+  gfc_add_block_to_block (&se->pre, &cond_se.pre);
+  condition = gfc_evaluate_now (cond_se.expr, &se->pre);
+
+  true_se.want_pointer = se->want_pointer;
+  gfc_conv_expr (&true_se, expr->value.conditional.true_expr);
+  true_val = true_se.expr;
+  false_se.want_pointer = se->want_pointer;
+  gfc_conv_expr (&false_se, expr->value.conditional.false_expr);
+  false_val = false_se.expr;
+
+  if (true_se.pre.head != NULL_TREE || false_se.pre.head != NULL_TREE)
+    gfc_add_expr_to_block (
+      &se->pre,
+      fold_build3_loc (input_location, COND_EXPR, void_type_node, condition,
+		       true_se.pre.head != NULL_TREE
+			 ? gfc_finish_block (&true_se.pre)
+			 : build_empty_stmt (input_location),
+		       false_se.pre.head != NULL_TREE
+			 ? gfc_finish_block (&false_se.pre)
+			 : build_empty_stmt (input_location)));
+
+  if (true_se.post.head != NULL_TREE || false_se.post.head != NULL_TREE)
+    gfc_add_expr_to_block (
+      &se->post,
+      fold_build3_loc (input_location, COND_EXPR, void_type_node, condition,
+		       true_se.post.head != NULL_TREE
+			 ? gfc_finish_block (&true_se.post)
+			 : build_empty_stmt (input_location),
+		       false_se.post.head != NULL_TREE
+			 ? gfc_finish_block (&false_se.post)
+			 : build_empty_stmt (input_location)));
+
+  type = gfc_typenode_for_spec (&expr->ts);
+  if (se->want_pointer)
+    type = build_pointer_type (type);
+
+  se->expr = fold_build3_loc (input_location, COND_EXPR, type, condition,
+			      true_val, false_val);
+}
+
 /* If a string's length is one, we convert it to a single character.  */
 
 tree
@@ -5317,6 +5369,13 @@ gfc_apply_interface_mapping_to_expr (gfc_interface_mapping * mapping,
       gfc_apply_interface_mapping_to_expr (mapping, expr->value.op.op2);
       break;
 
+    case EXPR_CONDITIONAL:
+      gfc_apply_interface_mapping_to_expr (mapping,
+					   expr->value.conditional.true_expr);
+      gfc_apply_interface_mapping_to_expr (mapping,
+					   expr->value.conditional.false_expr);
+      break;
+
     case EXPR_FUNCTION:
       for (actual = expr->value.function.actual; actual; actual = actual->next)
 	gfc_apply_interface_mapping_to_expr (mapping, actual->expr);
@@ -10464,6 +10523,10 @@ gfc_conv_expr (gfc_se * se, gfc_expr * expr)
       gfc_conv_expr_op (se, expr);
       break;
 
+    case EXPR_CONDITIONAL:
+      gfc_conv_conditional_expr (se, expr);
+      break;
+
     case EXPR_FUNCTION:
       gfc_conv_function_expr (se, expr);
       break;
@@ -10607,6 +10670,13 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr)
       return;
     }
 
+  if (expr->expr_type == EXPR_CONDITIONAL)
+    {
+      se->want_pointer = 1;
+      gfc_conv_expr (se, expr);
+      return;
+    }
+
   if (expr->expr_type == EXPR_FUNCTION
       && ((expr->value.function.esym
 	   && expr->value.function.esym->result
diff --git a/gcc/testsuite/gfortran.dg/conditional_1.f90 b/gcc/testsuite/gfortran.dg/conditional_1.f90
new file mode 100644
index 00000000000..ca7d21db1a7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_1.f90
@@ -0,0 +1,32 @@
+! { dg-do run }
+! { dg-options "-std=f2023" }
+program conditional_simple
+  implicit none
+  integer :: i = 42
+  logical :: l = .true.
+  real(4) :: r1 = 1.e-4, r2 = 1.e-5
+  complex :: z = (3.0, 4.0)
+
+  i = (i > 0 ? 1 : -1)
+  if (i /= 1) stop 1
+
+  i = 0
+  i = (i > 0 ? 1 : i < 0 ? -1 : 0)
+  if (i /= 0) stop 2
+
+  i = 0
+  i = (i > 0 ? 1 : (i < 0 ? -1 : 0))
+  if (i /= 0) stop 3
+
+  i = 0
+  i = (l .eqv. .false. ? 1 : 0)
+  if (i /= 0) stop 4
+
+  i = 0
+  i = (r1 /= r2 ? 0 : 1)
+  if (i /= 0) stop 5
+
+  i = 0
+  z = (i /= 0 ? z : (-3.0, -4.0))
+  if (z /= (-3.0, -4.0)) stop 6
+end program conditional_simple
diff --git a/gcc/testsuite/gfortran.dg/conditional_2.f90 b/gcc/testsuite/gfortran.dg/conditional_2.f90
new file mode 100644
index 00000000000..e78cd084154
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_2.f90
@@ -0,0 +1,13 @@
+! { dg-do run }
+! { dg-options "-std=f2023" }
+program conditional_constant
+  implicit none
+  integer :: i = 42
+
+  i = (.true. ? 1 : -1)
+  if (i /= 1) stop 1
+
+  i = 0
+  i = (i > 0 ? 1 : .false. ? -1 : 0)
+  if (i /= 0) stop 2
+end program conditional_constant
diff --git a/gcc/testsuite/gfortran.dg/conditional_3.f90 b/gcc/testsuite/gfortran.dg/conditional_3.f90
new file mode 100644
index 00000000000..5596cf5a59c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_3.f90
@@ -0,0 +1,9 @@
+! { dg-do compile }
+! { dg-options "-std=f2023" }
+program conditional_syntax
+  implicit none
+  integer :: i = 42
+
+  i = i > 0 ? 1 : -1 ! { dg-error "Unclassifiable statement at" }
+  i = (i > 0 ? 1 -1) ! { dg-error "Expected ':' in conditional expression" }
+end program conditional_syntax
diff --git a/gcc/testsuite/gfortran.dg/conditional_4.f90 b/gcc/testsuite/gfortran.dg/conditional_4.f90
new file mode 100644
index 00000000000..38033b9ec1d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_4.f90
@@ -0,0 +1,21 @@
+! { dg-do compile }
+! { dg-options "-std=f2023" }
+program conditional_resolve
+  implicit none
+  integer :: i = 42
+  integer, parameter :: ucs4 = selected_char_kind('ISO_10646')
+  character(kind=1) :: k1 = "k1"
+  character(kind=ucs4) :: k4 = "k4"
+  integer, dimension(1) :: a_1d
+  integer, dimension(1, 1) :: a_2d
+  logical :: l1(2)
+  integer :: i1(2)
+
+  i = (l1 ? 1 : -1) ! { dg-error "Condition in conditional expression must be a scalar logical" }
+  i = (i ? 1 : -1) ! { dg-error "Condition in conditional expression must be a scalar logical" }
+  i = (i /= 0 ? 1 : "oh no") ! { dg-error "must have the same declared type" }
+  i = (i /= 0 ? k1 : k4) ! { dg-error "must have the same kind parameter" }
+  i = (i /= 0 ? a_1d : a_2d) ! { dg-error "must have the same rank" }
+  k1 = (i /= 0 ? k1 : k1) ! { dg-error "Sorry, only integer, logical, real and complex types are currently supported for conditional expressions" }
+  i1 = (i /= 0 ? i1 : i1 + 1) ! { dg-error "Sorry, array is currently unsupported for conditional expressions" }
+end program conditional_resolve
diff --git a/gcc/testsuite/gfortran.dg/conditional_5.f90 b/gcc/testsuite/gfortran.dg/conditional_5.f90
new file mode 100644
index 00000000000..98b479d3e9d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_5.f90
@@ -0,0 +1,7 @@
+! { dg-do compile }
+! { dg-options "-std=f2018" }
+program conditional_std
+  implicit none
+  integer :: i = 42
+  i = (i > 0 ? 1 : -1) ! { dg-error "Fortran 2023: Conditional expression at" }
+end program conditional_std
diff --git a/gcc/testsuite/gfortran.dg/conditional_6.f90 b/gcc/testsuite/gfortran.dg/conditional_6.f90
new file mode 100644
index 00000000000..c9ac7132c45
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_6.f90
@@ -0,0 +1,16 @@
+! { dg-do run }
+! { dg-options "-std=f2023" }
+program conditional_arg
+  implicit none
+  integer :: a = 4
+  integer :: b = 5
+  call five((a < 5 ? a : b))
+  if (a /= 5) stop 1
+contains
+  subroutine five(x)
+    integer, optional :: x
+    if (present(x)) then
+      x = 5
+    end if
+  end subroutine five
+end program conditional_arg
diff --git a/gcc/testsuite/gfortran.dg/conditional_7.f90 b/gcc/testsuite/gfortran.dg/conditional_7.f90
new file mode 100644
index 00000000000..87e621a6f74
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_7.f90
@@ -0,0 +1,11 @@
+! { dg-do compile }
+! { dg-options "-std=f2023" }
+module m
+  contains
+    function f(n) result(str)
+      integer, value :: n
+      character(len=(n > 5 ? n : 5)) :: str
+      str = ""
+      str(1:5) = "abcde"
+    end
+end
diff --git a/gcc/testsuite/gfortran.dg/conditional_8.f90 b/gcc/testsuite/gfortran.dg/conditional_8.f90
new file mode 100644
index 00000000000..913acc7f4a8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_8.f90
@@ -0,0 +1,14 @@
+! { dg-do run }
+! { dg-options "-std=f2023" }
+implicit none
+integer :: aa(2)
+aa = [1, 2]
+
+print *, (aa(1) > 0 ? aa(2) : g())
+contains
+integer function g()
+  allocatable :: g
+  error stop "should not be called"
+  g = 3
+end
+end
diff --git a/gcc/testsuite/gfortran.dg/conditional_9.f90 b/gcc/testsuite/gfortran.dg/conditional_9.f90
new file mode 100644
index 00000000000..d1bb15e6315
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_9.f90
@@ -0,0 +1,11 @@
+! { dg-do compile }
+! { dg-options "-std=f2023" }
+implicit none
+integer :: i, j
+do concurrent (i=(j > 1 ? 0 : 1) : 5) local(j) ! { dg-error "must not appear in LOCAL locality-spec at" }
+end do
+do concurrent (i=(.true. ? j : 1) : 5) local(j) ! { dg-error "must not appear in LOCAL locality-spec at" }
+end do
+do concurrent (i=(.false. ? 1 : j) : 5) local(j) ! { dg-error "must not appear in LOCAL locality-spec at" }
+end do
+end
-- 
2.43.0
