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 b8d04ff6f36..ac0882f49ab 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.  */
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 2644cd82210..0b750348292 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.  */
@@ -2808,8 +2819,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;
@@ -3924,7 +3941,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..1daf180224b 100644
--- a/gcc/fortran/matchexp.cc
+++ b/gcc/fortran/matchexp.cc
@@ -138,6 +138,64 @@ 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;
+    }
+
+  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,11 +221,11 @@ 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)
-    return m;
+  m = match_conditional (&e);
+  if (m != MATCH_YES)
+    {
+      return m;
+    }
 
   m = gfc_match_char (')');
   if (m == MATCH_NO)
@@ -185,10 +243,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..ad920979f0e 100644
--- a/gcc/fortran/module.cc
+++ b/gcc/fortran/module.cc
@@ -3843,6 +3843,11 @@ mio_expr (gfc_expr **ep)
 
       break;
 
+    case EXPR_CONDITIONAL:
+      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 d51301aec44..b08aa7aa294 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -4989,6 +4989,65 @@ 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 ("true_expr at %L and false_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 ("true_expr at %L and false_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 ("true_expr at %L and false_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)
+    {
+      gfc_error ("Sorry, conditional expression at %L currently only support "
+		 "integer, logical, and real types",
+		 &expr->where);
+      return false;
+    }
+
+  expr->ts = true_expr->ts;
+  expr->rank = true_expr->rank;
+  return true;
+}
 
 /************** Array resolution subroutines **************/
 
@@ -8018,6 +8077,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 193bac51240..f03e71d487e 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -12703,6 +12703,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.  */
 
@@ -12975,6 +12984,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 69952b33eaa..15ba9aab03a 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -4368,6 +4368,37 @@ 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);
+
+  gfc_conv_expr (&true_se, expr->value.conditional.true_expr);
+  gfc_add_block_to_block (&se->pre, &true_se.pre);
+  true_val = true_se.expr;
+
+  gfc_conv_expr (&false_se, expr->value.conditional.false_expr);
+  gfc_add_block_to_block (&se->pre, &false_se.pre);
+  false_val = false_se.expr;
+
+  type = gfc_typenode_for_spec (&expr->ts);
+  true_val = fold_convert (type, true_val);
+  false_val = fold_convert (type, false_val);
+
+  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 +5348,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);
@@ -10416,6 +10454,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;
diff --git a/gcc/testsuite/gfortran.dg/conditional_1.f90 b/gcc/testsuite/gfortran.dg/conditional_1.f90
new file mode 100644
index 00000000000..633f8e70248
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_1.f90
@@ -0,0 +1,27 @@
+! { 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
+
+  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
+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..15f07e9dd45
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/conditional_4.f90
@@ -0,0 +1,19 @@
+! { 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)
+
+  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 "currently only support integer, logical, and real types" }
+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
