Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2226758/?format=api
{ "id": 2226758, "url": "http://patchwork.ozlabs.org/api/patches/2226758/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhup2dpico.gcc.gcc-TEST.yuao.80.1.1@forge-stage.sourceware.org/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<bmm.hhup2dpico.gcc.gcc-TEST.yuao.80.1.1@forge-stage.sourceware.org>", "list_archive_url": null, "date": "2026-04-22T18:46:59", "name": "[v1,1/1] fortran: implement conditional expression for fortran 2023", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "d62384349fbc2d4d9dd483ca3c70e42d5dabc0bf", "submitter": { "id": 93230, "url": "http://patchwork.ozlabs.org/api/people/93230/?format=api", "name": "yuao via Sourceware Forge", "email": "forge-bot+yuao@forge-stage.sourceware.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhup2dpico.gcc.gcc-TEST.yuao.80.1.1@forge-stage.sourceware.org/mbox/", "series": [ { "id": 501093, "url": "http://patchwork.ozlabs.org/api/series/501093/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=501093", "date": "2026-04-22T18:46:59", "name": "fortran: implement conditional expression for fortran 2023", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/501093/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2226758/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2226758/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org; dmarc=none (p=none dis=none)\n header.from=forge-stage.sourceware.org", "sourceware.org;\n spf=pass smtp.mailfrom=forge-stage.sourceware.org", "server2.sourceware.org;\n arc=none smtp.remote-ip=38.145.34.39" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g18Ls2dw2z1yD5\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 23 Apr 2026 05:25:09 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 8574141627F9\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 19:25:07 +0000 (GMT)", "from forge-stage.sourceware.org (vm08.sourceware.org [38.145.34.39])\n by sourceware.org (Postfix) with ESMTPS id 44D684716838\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 18:48:23 +0000 (GMT)", "from forge-stage.sourceware.org (localhost [IPv6:::1])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256)\n (No client certificate requested)\n by forge-stage.sourceware.org (Postfix) with ESMTPS id 213DC43545\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 18:48:23 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 8574141627F9", "OpenDKIM Filter v2.11.0 sourceware.org 44D684716838" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 44D684716838", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 44D684716838", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776883703; cv=none;\n b=uJJeAbV23QnbNROSv4EO5nqubjBohkp4DgPJdYAtKoH9o3hdjqRh+3jZSJXRM1pOukXzLPGoXNt3ieqGfHrG7jaoWCGzXrWRanGvvpeDtVz2DcaeRMD7n9Tj4M5dIPTJShxM9UG001XTy+xTf+FUyA7IDnZUuowwyisjCcCnbFI=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776883703; c=relaxed/simple;\n bh=vOyW/gYU/TWoP7N1RZBBDQZpTala7Ltf0wfMszdSrak=;\n h=From:Date:Subject:To:Message-ID;\n b=SMxn2M0NJmT5FTE8ux16C9UtBUgEYEZrwbWsYGu1jVcfF5+Ut+VUpmnoNpPayVnDSUpdviYBzif7y/CoU4Gg2jThnrW9uhA7jbHG1o8urQxKhsk3S+TbCr75pDrfPcmnNQ4dy82q2WXge9lVZYgHeFT2LxX8W8XNadwZ7dSicuk=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "From": "yuao via Sourceware Forge <forge-bot+yuao@forge-stage.sourceware.org>", "Date": "Wed, 22 Apr 2026 18:46:59 +0000", "Subject": "[PATCH v1 1/1] fortran: implement conditional expression for fortran\n 2023", "To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>", "Message-ID": "\n <bmm.hhup2dpico.gcc.gcc-TEST.yuao.80.1.1@forge-stage.sourceware.org>", "X-Mailer": "batrachomyomachia", "X-Pull-Request-Organization": "gcc", "X-Pull-Request-Repository": "gcc-TEST", "X-Pull-Request": "https://forge.sourceware.org/gcc/gcc-TEST/pulls/80", "References": "\n <bmm.hhup2dpico.gcc.gcc-TEST.yuao.80.1.0@forge-stage.sourceware.org>", "In-Reply-To": "\n <bmm.hhup2dpico.gcc.gcc-TEST.yuao.80.1.0@forge-stage.sourceware.org>", "X-Patch-URL": "\n https://forge.sourceware.org/yuao/gcc-TEST/commit/12edebd03a6e418f14688eb7bb4a04a4bb7266e1", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Reply-To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>,\n yuao@noreply.localhost", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "From: Yuao Ma <c8ef@outlook.com>\n\nThis patch adds support for conditional expressions in Fortran 2023 for a\nlimited set of types (logical, numerical), and also includes limited support\nfor conditional arguments without `.nil.` support.\n\ngcc/fortran/ChangeLog:\n\n\t* dump-parse-tree.cc (show_expr): Add support for EXPR_CONDITIONAL.\n\t* expr.cc (gfc_get_conditional_expr): Add cond-expr constructor.\n\t(gfc_copy_expr, free_expr0, gfc_is_constant_expr,\n\tsimplify_conditional, gfc_simplify_expr, gfc_check_init_expr,\n\tcheck_restricted, gfc_traverse_expr): Add support for EXPR_CONDITIONAL.\n\t* frontend-passes.cc (gfc_expr_walker): Ditto.\n\t* gfortran.h (enum expr_t): Add EXPR_CONDITIONAL.\n\t(gfc_get_operator_expr): Format fix.\n\t(gfc_get_conditional_expr): New decl.\n\t* matchexp.cc\n\t(match_conditional, match_primary): Parsing for EXPR_CONDITIONAL.\n\t* module.cc (mio_expr): Add support for EXPR_CONDITIONAL.\n\t* resolve.cc (resolve_conditional, gfc_resolve_expr): Ditto.\n\t* trans-array.cc (gfc_walk_conditional_expr, gfc_walk_subexpr): Ditto.\n\t* trans-expr.cc\n\t(gfc_conv_conditional_expr): Codegen for EXPR_CONDITIONAL.\n\t(gfc_apply_interface_mapping_to_expr, gfc_conv_expr,\n\tgfc_conv_expr_reference): Add support for EXPR_CONDITIONAL.\n\ngcc/testsuite/ChangeLog:\n\n\t* gfortran.dg/conditional_1.f90: New test.\n\t* gfortran.dg/conditional_2.f90: New test.\n\t* gfortran.dg/conditional_3.f90: New test.\n\t* gfortran.dg/conditional_4.f90: New test.\n\t* gfortran.dg/conditional_5.f90: New test.\n\t* gfortran.dg/conditional_6.f90: New test.\n\t* gfortran.dg/conditional_7.f90: New test.\n\t* gfortran.dg/conditional_8.f90: New test.\n\t* gfortran.dg/conditional_9.f90: New test.\n---\n gcc/fortran/dump-parse-tree.cc | 10 ++\n gcc/fortran/expr.cc | 118 ++++++++++++++++++++\n gcc/fortran/frontend-passes.cc | 5 +\n gcc/fortran/gfortran.h | 30 ++++-\n gcc/fortran/matchexp.cc | 79 +++++++++++--\n gcc/fortran/module.cc | 10 +-\n gcc/fortran/resolve.cc | 71 ++++++++++++\n gcc/fortran/trans-array.cc | 13 +++\n gcc/fortran/trans-expr.cc | 70 ++++++++++++\n gcc/testsuite/gfortran.dg/conditional_1.f90 | 32 ++++++\n gcc/testsuite/gfortran.dg/conditional_2.f90 | 13 +++\n gcc/testsuite/gfortran.dg/conditional_3.f90 | 9 ++\n gcc/testsuite/gfortran.dg/conditional_4.f90 | 21 ++++\n gcc/testsuite/gfortran.dg/conditional_5.f90 | 7 ++\n gcc/testsuite/gfortran.dg/conditional_6.f90 | 16 +++\n gcc/testsuite/gfortran.dg/conditional_7.f90 | 11 ++\n gcc/testsuite/gfortran.dg/conditional_8.f90 | 14 +++\n gcc/testsuite/gfortran.dg/conditional_9.f90 | 11 ++\n 18 files changed, 522 insertions(+), 18 deletions(-)\n create mode 100644 gcc/testsuite/gfortran.dg/conditional_1.f90\n create mode 100644 gcc/testsuite/gfortran.dg/conditional_2.f90\n create mode 100644 gcc/testsuite/gfortran.dg/conditional_3.f90\n create mode 100644 gcc/testsuite/gfortran.dg/conditional_4.f90\n create mode 100644 gcc/testsuite/gfortran.dg/conditional_5.f90\n create mode 100644 gcc/testsuite/gfortran.dg/conditional_6.f90\n create mode 100644 gcc/testsuite/gfortran.dg/conditional_7.f90\n create mode 100644 gcc/testsuite/gfortran.dg/conditional_8.f90\n create mode 100644 gcc/testsuite/gfortran.dg/conditional_9.f90", "diff": "diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc\nindex 3cd2eeef11a6..eda0659d6e23 100644\n--- a/gcc/fortran/dump-parse-tree.cc\n+++ b/gcc/fortran/dump-parse-tree.cc\n@@ -767,6 +767,16 @@ show_expr (gfc_expr *p)\n \n break;\n \n+ case EXPR_CONDITIONAL:\n+ fputc ('(', dumpfile);\n+ show_expr (p->value.conditional.condition);\n+ fputs (\" ? \", dumpfile);\n+ show_expr (p->value.conditional.true_expr);\n+ fputs (\" : \", dumpfile);\n+ show_expr (p->value.conditional.false_expr);\n+ fputc (')', dumpfile);\n+ break;\n+\n case EXPR_COMPCALL:\n show_compcall (p);\n break;\ndiff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc\nindex 3dbf8cb287aa..a11ff79ab6be 100644\n--- a/gcc/fortran/expr.cc\n+++ b/gcc/fortran/expr.cc\n@@ -116,6 +116,25 @@ gfc_get_operator_expr (locus *where, gfc_intrinsic_op op,\n return e;\n }\n \n+/* Get a new expression node that is an conditional expression node. */\n+\n+gfc_expr *\n+gfc_get_conditional_expr (locus *where, gfc_expr *condition,\n+\t\t\t gfc_expr *true_expr, gfc_expr *false_expr)\n+{\n+ gfc_expr *e;\n+\n+ e = gfc_get_expr ();\n+ e->expr_type = EXPR_CONDITIONAL;\n+ e->value.conditional.condition = condition;\n+ e->value.conditional.true_expr = true_expr;\n+ e->value.conditional.false_expr = false_expr;\n+\n+ if (where)\n+ e->where = *where;\n+\n+ return e;\n+}\n \n /* Get a new expression node that is an structure constructor\n of given type and kind. */\n@@ -393,6 +412,15 @@ gfc_copy_expr (gfc_expr *p)\n \n break;\n \n+ case EXPR_CONDITIONAL:\n+ q->value.conditional.condition\n+\t= gfc_copy_expr (p->value.conditional.condition);\n+ q->value.conditional.true_expr\n+\t= gfc_copy_expr (p->value.conditional.true_expr);\n+ q->value.conditional.false_expr\n+\t= gfc_copy_expr (p->value.conditional.false_expr);\n+ break;\n+\n case EXPR_FUNCTION:\n q->value.function.actual =\n \tgfc_copy_actual_arglist (p->value.function.actual);\n@@ -502,6 +530,12 @@ free_expr0 (gfc_expr *e)\n \tgfc_free_expr (e->value.op.op2);\n break;\n \n+ case EXPR_CONDITIONAL:\n+ gfc_free_expr (e->value.conditional.condition);\n+ gfc_free_expr (e->value.conditional.true_expr);\n+ gfc_free_expr (e->value.conditional.false_expr);\n+ break;\n+\n case EXPR_FUNCTION:\n gfc_free_actual_arglist (e->value.function.actual);\n break;\n@@ -1083,6 +1117,11 @@ gfc_is_constant_expr (gfc_expr *e)\n \t && (e->value.op.op2 == NULL\n \t\t || gfc_is_constant_expr (e->value.op.op2)));\n \n+ case EXPR_CONDITIONAL:\n+ return gfc_is_constant_expr (e->value.conditional.condition)\n+\t && gfc_is_constant_expr (e->value.conditional.true_expr)\n+\t && gfc_is_constant_expr (e->value.conditional.false_expr);\n+\n case EXPR_VARIABLE:\n /* The only context in which this can occur is in a parameterized\n \t derived type declaration, so returning true is OK. */\n@@ -1354,6 +1393,43 @@ simplify_intrinsic_op (gfc_expr *p, int type)\n return true;\n }\n \n+/* Try to collapse conditional expressions. */\n+\n+static bool\n+simplify_conditional (gfc_expr *p, int type)\n+{\n+ gfc_expr *condition, *true_expr, *false_expr;\n+\n+ condition = p->value.conditional.condition;\n+ true_expr = p->value.conditional.true_expr;\n+ false_expr = p->value.conditional.false_expr;\n+\n+ if (!gfc_simplify_expr (condition, type)\n+ || !gfc_simplify_expr (true_expr, type)\n+ || !gfc_simplify_expr (false_expr, type))\n+ return false;\n+\n+ if (!gfc_is_constant_expr (condition))\n+ return true;\n+\n+ p->value.conditional.condition = NULL;\n+ p->value.conditional.true_expr = NULL;\n+ p->value.conditional.false_expr = NULL;\n+\n+ if (condition->value.logical)\n+ {\n+ gfc_replace_expr (p, true_expr);\n+ gfc_free_expr (false_expr);\n+ }\n+ else\n+ {\n+ gfc_replace_expr (p, false_expr);\n+ gfc_free_expr (true_expr);\n+ }\n+ gfc_free_expr (condition);\n+\n+ return true;\n+}\n \n /* Subroutine to simplify constructor expressions. Mutually recursive\n with gfc_simplify_expr(). */\n@@ -2459,6 +2535,11 @@ gfc_simplify_expr (gfc_expr *p, int type)\n \treturn false;\n break;\n \n+ case EXPR_CONDITIONAL:\n+ if (!simplify_conditional (p, type))\n+\treturn false;\n+ break;\n+\n case EXPR_VARIABLE:\n /* Only substitute array parameter variables if we are in an\n \t initialization expression, or we want a subsection. */\n@@ -3133,6 +3214,20 @@ gfc_check_init_expr (gfc_expr *e)\n \n break;\n \n+ case EXPR_CONDITIONAL:\n+ t = gfc_check_init_expr (e->value.conditional.condition);\n+ if (!t)\n+\tbreak;\n+ t = gfc_check_init_expr (e->value.conditional.true_expr);\n+ if (!t)\n+\tbreak;\n+ t = gfc_check_init_expr (e->value.conditional.false_expr);\n+ if (t)\n+\tt = gfc_simplify_expr (e, 0);\n+ else\n+\tt = false;\n+ break;\n+\n case EXPR_FUNCTION:\n t = false;\n \n@@ -3609,6 +3704,20 @@ check_restricted (gfc_expr *e)\n \n break;\n \n+ case EXPR_CONDITIONAL:\n+ t = check_restricted (e->value.conditional.condition);\n+ if (!t)\n+\tbreak;\n+ t = check_restricted (e->value.conditional.true_expr);\n+ if (!t)\n+\tbreak;\n+ t = check_restricted (e->value.conditional.false_expr);\n+ if (t)\n+\tt = gfc_simplify_expr (e, 0);\n+ else\n+\tt = false;\n+ break;\n+\n case EXPR_FUNCTION:\n if (e->value.function.esym)\n \t{\n@@ -5700,6 +5809,15 @@ gfc_traverse_expr (gfc_expr *expr, gfc_symbol *sym,\n \treturn true;\n break;\n \n+ case EXPR_CONDITIONAL:\n+ if (gfc_traverse_expr (expr->value.conditional.condition, sym, func, f))\n+\treturn true;\n+ if (gfc_traverse_expr (expr->value.conditional.true_expr, sym, func, f))\n+\treturn true;\n+ if (gfc_traverse_expr (expr->value.conditional.false_expr, sym, func, f))\n+\treturn true;\n+ break;\n+\n default:\n gcc_unreachable ();\n break;\ndiff --git a/gcc/fortran/frontend-passes.cc b/gcc/fortran/frontend-passes.cc\nindex 02a0a2326a66..4a468b936004 100644\n--- a/gcc/fortran/frontend-passes.cc\n+++ b/gcc/fortran/frontend-passes.cc\n@@ -5218,6 +5218,11 @@ gfc_expr_walker (gfc_expr **e, walk_expr_fn_t exprfn, void *data)\n \t for (a = (*e)->value.function.actual; a; a = a->next)\n \t WALK_SUBEXPR (a->expr);\n \t break;\n+\t case EXPR_CONDITIONAL:\n+\t WALK_SUBEXPR ((*e)->value.conditional.condition);\n+\t WALK_SUBEXPR ((*e)->value.conditional.true_expr);\n+\t WALK_SUBEXPR ((*e)->value.conditional.false_expr);\n+\t break;\n \t case EXPR_COMPCALL:\n \t case EXPR_PPC:\n \t WALK_SUBEXPR ((*e)->value.compcall.base_object);\ndiff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h\nindex 482031d26005..2e6b368b4c26 100644\n--- a/gcc/fortran/gfortran.h\n+++ b/gcc/fortran/gfortran.h\n@@ -176,8 +176,19 @@ enum gfc_source_form\n \n /* Expression node types. */\n enum expr_t\n- { EXPR_UNKNOWN = 0, EXPR_OP = 1, EXPR_FUNCTION, EXPR_CONSTANT, EXPR_VARIABLE,\n- EXPR_SUBSTRING, EXPR_STRUCTURE, EXPR_ARRAY, EXPR_NULL, EXPR_COMPCALL, EXPR_PPC\n+{\n+ EXPR_UNKNOWN = 0,\n+ EXPR_OP = 1,\n+ EXPR_FUNCTION,\n+ EXPR_CONSTANT,\n+ EXPR_VARIABLE,\n+ EXPR_SUBSTRING,\n+ EXPR_STRUCTURE,\n+ EXPR_ARRAY,\n+ EXPR_NULL,\n+ EXPR_COMPCALL,\n+ EXPR_PPC,\n+ EXPR_CONDITIONAL,\n };\n \n /* Array types. */\n@@ -2809,8 +2820,14 @@ typedef struct gfc_expr\n character;\n \n gfc_constructor_base constructor;\n- }\n- value;\n+\n+ struct\n+ {\n+ struct gfc_expr *condition;\n+ struct gfc_expr *true_expr;\n+ struct gfc_expr *false_expr;\n+ } conditional;\n+ } value;\n \n /* Used to store PDT expression lists associated with expressions. */\n gfc_actual_arglist *param_list;\n@@ -3925,7 +3942,10 @@ bool gfc_is_ptr_fcn (gfc_expr *);\n gfc_expr *gfc_get_expr (void);\n gfc_expr *gfc_get_array_expr (bt type, int kind, locus *);\n gfc_expr *gfc_get_null_expr (locus *);\n-gfc_expr *gfc_get_operator_expr (locus *, gfc_intrinsic_op,gfc_expr *, gfc_expr *);\n+gfc_expr *gfc_get_operator_expr (locus *, gfc_intrinsic_op, gfc_expr *,\n+\t\t\t\t gfc_expr *);\n+gfc_expr *gfc_get_conditional_expr (locus *, gfc_expr *, gfc_expr *,\n+\t\t\t\t gfc_expr *);\n gfc_expr *gfc_get_structure_constructor_expr (bt, int, locus *);\n gfc_expr *gfc_get_constant_expr (bt, int, locus *);\n gfc_expr *gfc_get_character_expr (int, locus *, const char *, gfc_charlen_t len);\ndiff --git a/gcc/fortran/matchexp.cc b/gcc/fortran/matchexp.cc\nindex 9b66243b4fa1..e3a992538413 100644\n--- a/gcc/fortran/matchexp.cc\n+++ b/gcc/fortran/matchexp.cc\n@@ -138,6 +138,65 @@ gfc_get_parentheses (gfc_expr *e)\n return e2;\n }\n \n+/* Match a conditional expression. */\n+\n+static match\n+match_conditional (gfc_expr **result)\n+{\n+ gfc_expr *condition, *true_expr, *false_expr;\n+ locus where;\n+ match m;\n+\n+ where = gfc_current_locus;\n+\n+ m = gfc_match_expr (&condition);\n+ if (m != MATCH_YES)\n+ {\n+ gfc_error (expression_syntax);\n+ return MATCH_ERROR;\n+ }\n+\n+ m = gfc_match_char ('?');\n+ if (m != MATCH_YES)\n+ {\n+ *result = condition;\n+ return MATCH_YES;\n+ }\n+ else if (!gfc_notify_std (GFC_STD_F2023, \"Conditional expression at %L\",\n+\t\t\t &where))\n+ {\n+ gfc_free_expr (condition);\n+ return MATCH_ERROR;\n+ }\n+\n+ gfc_gobble_whitespace ();\n+ m = gfc_match_expr (&true_expr);\n+ if (m != MATCH_YES)\n+ {\n+ gfc_free_expr (condition);\n+ return m;\n+ }\n+\n+ m = gfc_match_char (':');\n+ if (m != MATCH_YES)\n+ {\n+ gfc_error (\"Expected ':' in conditional expression at %C\");\n+ gfc_free_expr (condition);\n+ gfc_free_expr (true_expr);\n+ return MATCH_ERROR;\n+ }\n+\n+ m = match_conditional (&false_expr);\n+ if (m != MATCH_YES)\n+ {\n+ gfc_free_expr (condition);\n+ gfc_free_expr (true_expr);\n+ return m;\n+ }\n+\n+ *result = gfc_get_conditional_expr (&where, condition, true_expr, false_expr);\n+ return MATCH_YES;\n+}\n \n /* Match a primary expression. */\n \n@@ -163,20 +222,20 @@ match_primary (gfc_expr **result)\n if (gfc_match_char ('(') != MATCH_YES)\n return MATCH_NO;\n \n- m = gfc_match_expr (&e);\n- if (m == MATCH_NO)\n- goto syntax;\n- if (m == MATCH_ERROR)\n+ m = match_conditional (&e);\n+ if (m != MATCH_YES)\n return m;\n \n m = gfc_match_char (')');\n if (m == MATCH_NO)\n gfc_error (\"Expected a right parenthesis in expression at %C\");\n \n- /* Now we have the expression inside the parentheses, build the\n- expression pointing to it. By 7.1.7.2, any expression in\n- parentheses shall be treated as a data entity. */\n- *result = gfc_get_parentheses (e);\n+ /* Now we have the expression inside the parentheses, build the expression\n+ pointing to it. By 7.1.7.2, any expression in parentheses shall be treated\n+ as a data entity.\n+ Note that if the expression is a conditional expression, we will omit the\n+ extra parentheses. */\n+ *result = e->expr_type == EXPR_CONDITIONAL ? e : gfc_get_parentheses (e);\n \n if (m != MATCH_YES)\n {\n@@ -185,10 +244,6 @@ match_primary (gfc_expr **result)\n }\n \n return MATCH_YES;\n-\n-syntax:\n- gfc_error (expression_syntax);\n- return MATCH_ERROR;\n }\n \n \ndiff --git a/gcc/fortran/module.cc b/gcc/fortran/module.cc\nindex e05b08bd14ed..3168a6082eb6 100644\n--- a/gcc/fortran/module.cc\n+++ b/gcc/fortran/module.cc\n@@ -3622,7 +3622,9 @@ static const mstring expr_types[] = {\n minit (\"ARRAY\", EXPR_ARRAY),\n minit (\"NULL\", EXPR_NULL),\n minit (\"COMPCALL\", EXPR_COMPCALL),\n- minit (NULL, -1)\n+ minit (\"PPC\", EXPR_PPC),\n+ minit (\"CONDITIONAL\", EXPR_CONDITIONAL),\n+ minit (NULL, -1),\n };\n \n /* INTRINSIC_ASSIGN is missing because it is used as an index for\n@@ -3843,6 +3845,12 @@ mio_expr (gfc_expr **ep)\n \n break;\n \n+ case EXPR_CONDITIONAL:\n+ mio_expr (&e->value.conditional.condition);\n+ mio_expr (&e->value.conditional.true_expr);\n+ mio_expr (&e->value.conditional.false_expr);\n+ break;\n+\n case EXPR_FUNCTION:\n mio_symtree_ref (&e->symtree);\n mio_actual_arglist (&e->value.function.actual, false);\ndiff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc\nindex 1a7c9dddb15b..b83961fe6f10 100644\n--- a/gcc/fortran/resolve.cc\n+++ b/gcc/fortran/resolve.cc\n@@ -4989,6 +4989,73 @@ simplify_op:\n return t;\n }\n \n+static bool\n+resolve_conditional (gfc_expr *expr)\n+{\n+ gfc_expr *condition, *true_expr, *false_expr;\n+\n+ condition = expr->value.conditional.condition;\n+ true_expr = expr->value.conditional.true_expr;\n+ false_expr = expr->value.conditional.false_expr;\n+\n+ if (!gfc_resolve_expr (condition) || !gfc_resolve_expr (true_expr)\n+ || !gfc_resolve_expr (false_expr))\n+ return false;\n+\n+ if (condition->ts.type != BT_LOGICAL || condition->rank != 0)\n+ {\n+ gfc_error (\n+\t\"Condition in conditional expression must be a scalar logical at %L\",\n+\t&condition->where);\n+ return false;\n+ }\n+\n+ if (true_expr->ts.type != false_expr->ts.type)\n+ {\n+ gfc_error (\"expr at %L and expr at %L in conditional expression \"\n+\t\t \"must have the same declared type\",\n+\t\t &true_expr->where, &false_expr->where);\n+ return false;\n+ }\n+\n+ if (true_expr->ts.kind != false_expr->ts.kind)\n+ {\n+ gfc_error (\"expr at %L and expr at %L in conditional expression \"\n+\t\t \"must have the same kind parameter\",\n+\t\t &true_expr->where, &false_expr->where);\n+ return false;\n+ }\n+\n+ if (true_expr->rank != false_expr->rank)\n+ {\n+ gfc_error (\"expr at %L and expr at %L in conditional expression \"\n+\t\t \"must have the same rank\",\n+\t\t &true_expr->where, &false_expr->where);\n+ return false;\n+ }\n+\n+ /* TODO: support more data types for conditional expressions */\n+ if (true_expr->ts.type != BT_INTEGER && true_expr->ts.type != BT_LOGICAL\n+ && true_expr->ts.type != BT_REAL && true_expr->ts.type != BT_COMPLEX)\n+ {\n+ gfc_error (\"Sorry, only integer, logical, real and complex types \"\n+\t\t \"are currently supported for conditional expressions at %L\",\n+\t\t &expr->where);\n+ return false;\n+ }\n+\n+ if (true_expr->rank > 0)\n+ {\n+ gfc_error (\"Sorry, array is currently unsupported for conditional \"\n+\t\t \"expressions at %L\",\n+\t\t &expr->where);\n+ return false;\n+ }\n+\n+ expr->ts = true_expr->ts;\n+ expr->rank = true_expr->rank;\n+ return true;\n+}\n \n /************** Array resolution subroutines **************/\n \n@@ -8040,6 +8107,10 @@ gfc_resolve_expr (gfc_expr *e)\n t = resolve_operator (e);\n break;\n \n+ case EXPR_CONDITIONAL:\n+ t = resolve_conditional (e);\n+ break;\n+\n case EXPR_FUNCTION:\n case EXPR_VARIABLE:\n \ndiff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc\nindex 0449c26ce6d5..7f9168410a2e 100644\n--- a/gcc/fortran/trans-array.cc\n+++ b/gcc/fortran/trans-array.cc\n@@ -12713,6 +12713,15 @@ gfc_walk_op_expr (gfc_ss * ss, gfc_expr * expr)\n return head2;\n }\n \n+static gfc_ss *\n+gfc_walk_conditional_expr (gfc_ss *ss, gfc_expr *expr)\n+{\n+ gfc_ss *head;\n+\n+ head = gfc_walk_subexpr (ss, expr->value.conditional.true_expr);\n+ head = gfc_walk_subexpr (head, expr->value.conditional.false_expr);\n+ return head;\n+}\n \n /* Reverse a SS chain. */\n \n@@ -12985,6 +12994,10 @@ gfc_walk_subexpr (gfc_ss * ss, gfc_expr * expr)\n head = gfc_walk_op_expr (ss, expr);\n return head;\n \n+ case EXPR_CONDITIONAL:\n+ head = gfc_walk_conditional_expr (ss, expr);\n+ return head;\n+\n case EXPR_FUNCTION:\n head = gfc_walk_function_expr (ss, expr);\n return head;\ndiff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc\nindex a9ea29f760fe..e0ae41f12c6d 100644\n--- a/gcc/fortran/trans-expr.cc\n+++ b/gcc/fortran/trans-expr.cc\n@@ -4368,6 +4368,58 @@ gfc_conv_expr_op (gfc_se * se, gfc_expr * expr)\n gfc_add_block_to_block (&se->post, &lse.post);\n }\n \n+static void\n+gfc_conv_conditional_expr (gfc_se *se, gfc_expr *expr)\n+{\n+ gfc_se cond_se, true_se, false_se;\n+ tree condition, true_val, false_val;\n+ tree type;\n+\n+ gfc_init_se (&cond_se, se);\n+ gfc_init_se (&true_se, se);\n+ gfc_init_se (&false_se, se);\n+\n+ gfc_conv_expr (&cond_se, expr->value.conditional.condition);\n+ gfc_add_block_to_block (&se->pre, &cond_se.pre);\n+ condition = gfc_evaluate_now (cond_se.expr, &se->pre);\n+\n+ true_se.want_pointer = se->want_pointer;\n+ gfc_conv_expr (&true_se, expr->value.conditional.true_expr);\n+ true_val = true_se.expr;\n+ false_se.want_pointer = se->want_pointer;\n+ gfc_conv_expr (&false_se, expr->value.conditional.false_expr);\n+ false_val = false_se.expr;\n+\n+ if (true_se.pre.head != NULL_TREE || false_se.pre.head != NULL_TREE)\n+ gfc_add_expr_to_block (\n+ &se->pre,\n+ fold_build3_loc (input_location, COND_EXPR, void_type_node, condition,\n+\t\t true_se.pre.head != NULL_TREE\n+\t\t\t ? gfc_finish_block (&true_se.pre)\n+\t\t\t : build_empty_stmt (input_location),\n+\t\t false_se.pre.head != NULL_TREE\n+\t\t\t ? gfc_finish_block (&false_se.pre)\n+\t\t\t : build_empty_stmt (input_location)));\n+\n+ if (true_se.post.head != NULL_TREE || false_se.post.head != NULL_TREE)\n+ gfc_add_expr_to_block (\n+ &se->post,\n+ fold_build3_loc (input_location, COND_EXPR, void_type_node, condition,\n+\t\t true_se.post.head != NULL_TREE\n+\t\t\t ? gfc_finish_block (&true_se.post)\n+\t\t\t : build_empty_stmt (input_location),\n+\t\t false_se.post.head != NULL_TREE\n+\t\t\t ? gfc_finish_block (&false_se.post)\n+\t\t\t : build_empty_stmt (input_location)));\n+\n+ type = gfc_typenode_for_spec (&expr->ts);\n+ if (se->want_pointer)\n+ type = build_pointer_type (type);\n+\n+ se->expr = fold_build3_loc (input_location, COND_EXPR, type, condition,\n+\t\t\t true_val, false_val);\n+}\n+\n /* If a string's length is one, we convert it to a single character. */\n \n tree\n@@ -5317,6 +5369,13 @@ gfc_apply_interface_mapping_to_expr (gfc_interface_mapping * mapping,\n gfc_apply_interface_mapping_to_expr (mapping, expr->value.op.op2);\n break;\n \n+ case EXPR_CONDITIONAL:\n+ gfc_apply_interface_mapping_to_expr (mapping,\n+\t\t\t\t\t expr->value.conditional.true_expr);\n+ gfc_apply_interface_mapping_to_expr (mapping,\n+\t\t\t\t\t expr->value.conditional.false_expr);\n+ break;\n+\n case EXPR_FUNCTION:\n for (actual = expr->value.function.actual; actual; actual = actual->next)\n \tgfc_apply_interface_mapping_to_expr (mapping, actual->expr);\n@@ -10464,6 +10523,10 @@ gfc_conv_expr (gfc_se * se, gfc_expr * expr)\n gfc_conv_expr_op (se, expr);\n break;\n \n+ case EXPR_CONDITIONAL:\n+ gfc_conv_conditional_expr (se, expr);\n+ break;\n+\n case EXPR_FUNCTION:\n gfc_conv_function_expr (se, expr);\n break;\n@@ -10607,6 +10670,13 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr)\n return;\n }\n \n+ if (expr->expr_type == EXPR_CONDITIONAL)\n+ {\n+ se->want_pointer = 1;\n+ gfc_conv_expr (se, expr);\n+ return;\n+ }\n+\n if (expr->expr_type == EXPR_FUNCTION\n && ((expr->value.function.esym\n \t && expr->value.function.esym->result\ndiff --git a/gcc/testsuite/gfortran.dg/conditional_1.f90 b/gcc/testsuite/gfortran.dg/conditional_1.f90\nnew file mode 100644\nindex 000000000000..ca7d21db1a7d\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/conditional_1.f90\n@@ -0,0 +1,32 @@\n+! { dg-do run }\n+! { dg-options \"-std=f2023\" }\n+program conditional_simple\n+ implicit none\n+ integer :: i = 42\n+ logical :: l = .true.\n+ real(4) :: r1 = 1.e-4, r2 = 1.e-5\n+ complex :: z = (3.0, 4.0)\n+\n+ i = (i > 0 ? 1 : -1)\n+ if (i /= 1) stop 1\n+\n+ i = 0\n+ i = (i > 0 ? 1 : i < 0 ? -1 : 0)\n+ if (i /= 0) stop 2\n+\n+ i = 0\n+ i = (i > 0 ? 1 : (i < 0 ? -1 : 0))\n+ if (i /= 0) stop 3\n+\n+ i = 0\n+ i = (l .eqv. .false. ? 1 : 0)\n+ if (i /= 0) stop 4\n+\n+ i = 0\n+ i = (r1 /= r2 ? 0 : 1)\n+ if (i /= 0) stop 5\n+\n+ i = 0\n+ z = (i /= 0 ? z : (-3.0, -4.0))\n+ if (z /= (-3.0, -4.0)) stop 6\n+end program conditional_simple\ndiff --git a/gcc/testsuite/gfortran.dg/conditional_2.f90 b/gcc/testsuite/gfortran.dg/conditional_2.f90\nnew file mode 100644\nindex 000000000000..e78cd0841543\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/conditional_2.f90\n@@ -0,0 +1,13 @@\n+! { dg-do run }\n+! { dg-options \"-std=f2023\" }\n+program conditional_constant\n+ implicit none\n+ integer :: i = 42\n+\n+ i = (.true. ? 1 : -1)\n+ if (i /= 1) stop 1\n+\n+ i = 0\n+ i = (i > 0 ? 1 : .false. ? -1 : 0)\n+ if (i /= 0) stop 2\n+end program conditional_constant\ndiff --git a/gcc/testsuite/gfortran.dg/conditional_3.f90 b/gcc/testsuite/gfortran.dg/conditional_3.f90\nnew file mode 100644\nindex 000000000000..5596cf5a59c5\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/conditional_3.f90\n@@ -0,0 +1,9 @@\n+! { dg-do compile }\n+! { dg-options \"-std=f2023\" }\n+program conditional_syntax\n+ implicit none\n+ integer :: i = 42\n+\n+ i = i > 0 ? 1 : -1 ! { dg-error \"Unclassifiable statement at\" }\n+ i = (i > 0 ? 1 -1) ! { dg-error \"Expected ':' in conditional expression\" }\n+end program conditional_syntax\ndiff --git a/gcc/testsuite/gfortran.dg/conditional_4.f90 b/gcc/testsuite/gfortran.dg/conditional_4.f90\nnew file mode 100644\nindex 000000000000..38033b9ec1de\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/conditional_4.f90\n@@ -0,0 +1,21 @@\n+! { dg-do compile }\n+! { dg-options \"-std=f2023\" }\n+program conditional_resolve\n+ implicit none\n+ integer :: i = 42\n+ integer, parameter :: ucs4 = selected_char_kind('ISO_10646')\n+ character(kind=1) :: k1 = \"k1\"\n+ character(kind=ucs4) :: k4 = \"k4\"\n+ integer, dimension(1) :: a_1d\n+ integer, dimension(1, 1) :: a_2d\n+ logical :: l1(2)\n+ integer :: i1(2)\n+\n+ i = (l1 ? 1 : -1) ! { dg-error \"Condition in conditional expression must be a scalar logical\" }\n+ i = (i ? 1 : -1) ! { dg-error \"Condition in conditional expression must be a scalar logical\" }\n+ i = (i /= 0 ? 1 : \"oh no\") ! { dg-error \"must have the same declared type\" }\n+ i = (i /= 0 ? k1 : k4) ! { dg-error \"must have the same kind parameter\" }\n+ i = (i /= 0 ? a_1d : a_2d) ! { dg-error \"must have the same rank\" }\n+ k1 = (i /= 0 ? k1 : k1) ! { dg-error \"Sorry, only integer, logical, real and complex types are currently supported for conditional expressions\" }\n+ i1 = (i /= 0 ? i1 : i1 + 1) ! { dg-error \"Sorry, array is currently unsupported for conditional expressions\" }\n+end program conditional_resolve\ndiff --git a/gcc/testsuite/gfortran.dg/conditional_5.f90 b/gcc/testsuite/gfortran.dg/conditional_5.f90\nnew file mode 100644\nindex 000000000000..98b479d3e9df\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/conditional_5.f90\n@@ -0,0 +1,7 @@\n+! { dg-do compile }\n+! { dg-options \"-std=f2018\" }\n+program conditional_std\n+ implicit none\n+ integer :: i = 42\n+ i = (i > 0 ? 1 : -1) ! { dg-error \"Fortran 2023: Conditional expression at\" }\n+end program conditional_std\ndiff --git a/gcc/testsuite/gfortran.dg/conditional_6.f90 b/gcc/testsuite/gfortran.dg/conditional_6.f90\nnew file mode 100644\nindex 000000000000..c9ac7132c45f\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/conditional_6.f90\n@@ -0,0 +1,16 @@\n+! { dg-do run }\n+! { dg-options \"-std=f2023\" }\n+program conditional_arg\n+ implicit none\n+ integer :: a = 4\n+ integer :: b = 5\n+ call five((a < 5 ? a : b))\n+ if (a /= 5) stop 1\n+contains\n+ subroutine five(x)\n+ integer, optional :: x\n+ if (present(x)) then\n+ x = 5\n+ end if\n+ end subroutine five\n+end program conditional_arg\ndiff --git a/gcc/testsuite/gfortran.dg/conditional_7.f90 b/gcc/testsuite/gfortran.dg/conditional_7.f90\nnew file mode 100644\nindex 000000000000..87e621a6f74e\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/conditional_7.f90\n@@ -0,0 +1,11 @@\n+! { dg-do compile }\n+! { dg-options \"-std=f2023\" }\n+module m\n+ contains\n+ function f(n) result(str)\n+ integer, value :: n\n+ character(len=(n > 5 ? n : 5)) :: str\n+ str = \"\"\n+ str(1:5) = \"abcde\"\n+ end\n+end\ndiff --git a/gcc/testsuite/gfortran.dg/conditional_8.f90 b/gcc/testsuite/gfortran.dg/conditional_8.f90\nnew file mode 100644\nindex 000000000000..913acc7f4a80\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/conditional_8.f90\n@@ -0,0 +1,14 @@\n+! { dg-do run }\n+! { dg-options \"-std=f2023\" }\n+implicit none\n+integer :: aa(2)\n+aa = [1, 2]\n+\n+print *, (aa(1) > 0 ? aa(2) : g())\n+contains\n+integer function g()\n+ allocatable :: g\n+ error stop \"should not be called\"\n+ g = 3\n+end\n+end\ndiff --git a/gcc/testsuite/gfortran.dg/conditional_9.f90 b/gcc/testsuite/gfortran.dg/conditional_9.f90\nnew file mode 100644\nindex 000000000000..d1bb15e63153\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/conditional_9.f90\n@@ -0,0 +1,11 @@\n+! { dg-do compile }\n+! { dg-options \"-std=f2023\" }\n+implicit none\n+integer :: i, j\n+do concurrent (i=(j > 1 ? 0 : 1) : 5) local(j) ! { dg-error \"must not appear in LOCAL locality-spec at\" }\n+end do\n+do concurrent (i=(.true. ? j : 1) : 5) local(j) ! { dg-error \"must not appear in LOCAL locality-spec at\" }\n+end do\n+do concurrent (i=(.false. ? 1 : j) : 5) local(j) ! { dg-error \"must not appear in LOCAL locality-spec at\" }\n+end do\n+end\n", "prefixes": [ "v1", "1/1" ] }