aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuao Ma <c8ef@outlook.com>2025-09-12 20:28:19 +0800
committerc8ef <c8ef@outlook.com>2025-09-14 18:24:50 +0800
commitaf53cfeb8352b18cbc0684f04c5106db20142f7b (patch)
tree3de0e72cacf6f091a6a6c85f4e76ffc1c486eab6
parent21d1bb1922fa7cd98f2a27d002e48b488e772176 (diff)
downloadgcc-af53cfeb8352b18cbc0684f04c5106db20142f7b.zip
gcc-af53cfeb8352b18cbc0684f04c5106db20142f7b.tar.gz
gcc-af53cfeb8352b18cbc0684f04c5106db20142f7b.tar.bz2
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.
-rw-r--r--gcc/fortran/dump-parse-tree.cc10
-rw-r--r--gcc/fortran/expr.cc118
-rw-r--r--gcc/fortran/frontend-passes.cc5
-rw-r--r--gcc/fortran/gfortran.h30
-rw-r--r--gcc/fortran/matchexp.cc79
-rw-r--r--gcc/fortran/module.cc10
-rw-r--r--gcc/fortran/resolve.cc71
-rw-r--r--gcc/fortran/trans-array.cc13
-rw-r--r--gcc/fortran/trans-expr.cc70
-rw-r--r--gcc/testsuite/gfortran.dg/conditional_1.f9032
-rw-r--r--gcc/testsuite/gfortran.dg/conditional_2.f9013
-rw-r--r--gcc/testsuite/gfortran.dg/conditional_3.f909
-rw-r--r--gcc/testsuite/gfortran.dg/conditional_4.f9021
-rw-r--r--gcc/testsuite/gfortran.dg/conditional_5.f907
-rw-r--r--gcc/testsuite/gfortran.dg/conditional_6.f9016
-rw-r--r--gcc/testsuite/gfortran.dg/conditional_7.f9011
-rw-r--r--gcc/testsuite/gfortran.dg/conditional_8.f9014
-rw-r--r--gcc/testsuite/gfortran.dg/conditional_9.f9011
18 files changed, 522 insertions, 18 deletions
diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 3cd2eee..eda0659 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 3dbf8cb..a11ff79 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 02a0a23..4a468b9 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 482031d..2e6b368 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 9b66243..e3a9925 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 e05b08b..3168a60 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 1a7c9dd..b83961f 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 0449c26..7f91684 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 a9ea29f..e0ae41f1 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 0000000..ca7d21d
--- /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 0000000..e78cd08
--- /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 0000000..5596cf5
--- /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 0000000..38033b9
--- /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 0000000..98b479d
--- /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 0000000..c9ac713
--- /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 0000000..87e621a
--- /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 0000000..913acc7f
--- /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 0000000..d1bb15e
--- /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