]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
fortran: implement conditional expression for fortran 2023
authorYuao Ma <c8ef@outlook.com>
Fri, 12 Sep 2025 12:28:19 +0000 (20:28 +0800)
committerc8ef <c8ef@outlook.com>
Sun, 14 Sep 2025 10:24:50 +0000 (18:24 +0800)
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.

18 files changed:
gcc/fortran/dump-parse-tree.cc
gcc/fortran/expr.cc
gcc/fortran/frontend-passes.cc
gcc/fortran/gfortran.h
gcc/fortran/matchexp.cc
gcc/fortran/module.cc
gcc/fortran/resolve.cc
gcc/fortran/trans-array.cc
gcc/fortran/trans-expr.cc
gcc/testsuite/gfortran.dg/conditional_1.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/conditional_2.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/conditional_3.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/conditional_4.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/conditional_5.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/conditional_6.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/conditional_7.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/conditional_8.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/conditional_9.f90 [new file with mode: 0644]

index 3cd2eeef11a6ee3164efd57ac6bc12c0c49a67bf..eda0659d6e23958dfaefe131fb12358ac35082ea 100644 (file)
@@ -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;
index 3dbf8cb287aa5d2efa6d35d0567399083ad01776..a11ff79ab6be0596f4f0cf8e0ceec8a4552cd9a7 100644 (file)
@@ -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;
index 02a0a2326a66ef57fd773b379c84142c77fda671..4a468b936004732a68479cff9661737bc5f560d7 100644 (file)
@@ -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);
index 482031d2600560c7cfb05f900188d029345aed42..2e6b368b4c266049ca1c65baa064bb6767a38362 100644 (file)
@@ -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);
index 9b66243b4fa1b08db4c43251755a45c3ad62ae0c..e3a9925384130322c92f112619a1e305639152aa 100644 (file)
@@ -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;
 }
 
 
index e05b08bd14ed523d698faf926fcc1d4fbf0180dc..3168a6082eb651fd8ffeb2731b4f666bd45c44fb 100644 (file)
@@ -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);
index 1a7c9dddb15ba4ec669be9345cce472b8a21dcc2..b83961fe6f10c17b3876ea3a0371e7934838646d 100644 (file)
@@ -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:
 
index 0449c26ce6d5c03472dad40cdd3e4b6338bb64f0..7f9168410a2eba6886e519b5ee49f9624c267baa 100644 (file)
@@ -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;
index a9ea29f760fe16343dc5518c34bdd9af19b0f5a6..e0ae41f12c6d7649838362d3e7922811f045acf5 100644 (file)
@@ -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 (file)
index 0000000..ca7d21d
--- /dev/null
@@ -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 (file)
index 0000000..e78cd08
--- /dev/null
@@ -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 (file)
index 0000000..5596cf5
--- /dev/null
@@ -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 (file)
index 0000000..38033b9
--- /dev/null
@@ -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 (file)
index 0000000..98b479d
--- /dev/null
@@ -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 (file)
index 0000000..c9ac713
--- /dev/null
@@ -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 (file)
index 0000000..87e621a
--- /dev/null
@@ -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 (file)
index 0000000..913acc7
--- /dev/null
@@ -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 (file)
index 0000000..d1bb15e
--- /dev/null
@@ -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