https://gcc.gnu.org/g:bdb6f7f2c065c878f84e9d52c74962cb2d40fc2c

commit r16-2978-gbdb6f7f2c065c878f84e9d52c74962cb2d40fc2c
Author: Arthur Cohen <arthur.co...@embecosm.com>
Date:   Tue Jul 22 17:16:02 2025 +0200

    gccrs: desugar: Add base for desugaring while-let loops
    
    gcc/rust/ChangeLog:
    
            * Make-lang.in:
            * ast/rust-expression-yeast.cc (ExpressionYeast::dispatch_loops): 
Call DesugarWhileLet.
            * ast/rust-desugar-while-let.cc: New file.
            * ast/rust-desugar-while-let.h: New file.
    
    gcc/testsuite/ChangeLog:
    
            * rust/compile/while_let1.rs: New test.

Diff:
---
 gcc/rust/Make-lang.in                    |   1 +
 gcc/rust/ast/rust-desugar-while-let.cc   | 104 +++++++++++++++++++++++++++++
 gcc/rust/ast/rust-desugar-while-let.h    |  71 ++++++++++++++++++++
 gcc/rust/ast/rust-expression-yeast.cc    |   6 +-
 gcc/testsuite/rust/compile/while_let1.rs | 109 +++++++++++++++++++++++++++++++
 5 files changed, 289 insertions(+), 2 deletions(-)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 98590d20b8ce..1c58bc88e9cd 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -245,6 +245,7 @@ GRS_OBJS = \
        rust/rust-collect-lang-items.o \
        rust/rust-expression-yeast.o \
        rust/rust-desugar-for-loops.o \
+       rust/rust-desugar-while-let.o \
        rust/rust-desugar-question-mark.o \
        rust/rust-desugar-apit.o \
        rust/rust-desugar-try-block.o \
diff --git a/gcc/rust/ast/rust-desugar-while-let.cc 
b/gcc/rust/ast/rust-desugar-while-let.cc
new file mode 100644
index 000000000000..5eadc5908fd0
--- /dev/null
+++ b/gcc/rust/ast/rust-desugar-while-let.cc
@@ -0,0 +1,104 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-desugar-while-let.h"
+#include "rust-ast.h"
+#include "rust-hir-map.h"
+#include "rust-path.h"
+#include "rust-pattern.h"
+#include "rust-stmt.h"
+#include "rust-expr.h"
+#include "rust-ast-builder.h"
+
+namespace Rust {
+namespace AST {
+
+DesugarWhileLet::DesugarWhileLet () {}
+
+MatchCase
+DesugarWhileLet::DesugarCtx::make_break_arm ()
+{
+  auto arm = builder.match_arm (builder.wildcard ());
+
+  auto break_expr
+    = std::unique_ptr<Expr> (new BreakExpr (tl::nullopt, nullptr, {}, loc));
+
+  return MatchCase (std::move (arm), std::move (break_expr));
+}
+
+MatchCase
+DesugarWhileLet::DesugarCtx::make_continue_arm (
+  std::unique_ptr<Pattern> &&pattern, std::unique_ptr<BlockExpr> &&body)
+{
+  auto arm = builder.match_arm (std::move (pattern));
+
+  return MatchCase (std::move (arm), std::move (body));
+}
+
+std::unique_ptr<Expr>
+DesugarWhileLet::desugar (WhileLetLoopExpr &expr)
+{
+  rust_assert (expr.get_patterns ().size () == 1);
+
+  auto pattern = expr.get_patterns ()[0]->clone_pattern ();
+  auto body = expr.get_loop_block ().clone_block_expr ();
+  auto scrutinee = expr.get_scrutinee_expr ().clone_expr ();
+
+  auto ctx = DesugarCtx (expr.get_locus ());
+
+  // _ => break,
+  auto break_arm = ctx.make_break_arm ();
+
+  // <pattern> => <body>,
+  auto continue_arm
+    = ctx.make_continue_arm (std::move (pattern), std::move (body));
+
+  // match <scrutinee> {
+  //     <continue_arm>
+  //     <break_arm>
+  // }
+  auto match_expr
+    = ctx.builder.match (std::move (scrutinee),
+                        {std::move (continue_arm), std::move (break_arm)});
+
+  auto loop_stmts = std::vector<std::unique_ptr<Stmt>> ();
+  loop_stmts.emplace_back (ctx.builder.statementify (std::move (match_expr)));
+
+  // loop {
+  //     <match_expr>
+  // }
+  return ctx.builder.loop (std::move (loop_stmts));
+}
+
+void
+DesugarWhileLet::go (std::unique_ptr<Expr> &ptr)
+{
+  rust_assert (ptr->get_expr_kind () == Expr::Kind::Loop);
+
+  auto &loop = static_cast<BaseLoopExpr &> (*ptr);
+
+  rust_assert (loop.get_loop_kind () == BaseLoopExpr::Kind::WhileLet);
+
+  auto &while_let = static_cast<WhileLetLoopExpr &> (loop);
+  auto desugared = DesugarWhileLet ().desugar (while_let);
+
+  ptr = std::move (desugared);
+}
+
+} // namespace AST
+} // namespace Rust
diff --git a/gcc/rust/ast/rust-desugar-while-let.h 
b/gcc/rust/ast/rust-desugar-while-let.h
new file mode 100644
index 000000000000..60e06934e492
--- /dev/null
+++ b/gcc/rust/ast/rust-desugar-while-let.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_DESUGAR_WHILE_LET_H
+#define RUST_DESUGAR_WHILE_LET_H
+
+#include "rust-ast-builder.h"
+#include "rust-expr.h"
+
+namespace Rust {
+namespace AST {
+
+// Desugar while-let into a set of other AST nodes. The desugar is of the
+// following form:
+//
+// ```
+// whilet let <pat> = <expr> <body>
+// ```
+//
+// becomes:
+//
+// ```
+// loop {
+//     match <expr> {
+//         <pat> => <body>,
+//         _ => break
+//     }
+// }
+// ```
+class DesugarWhileLet
+{
+public:
+  static void go (std::unique_ptr<Expr> &ptr);
+
+private:
+  DesugarWhileLet ();
+
+  struct DesugarCtx
+  {
+    DesugarCtx (location_t loc) : builder (Builder (loc)), loc (loc) {}
+
+    Builder builder;
+    location_t loc;
+
+    MatchCase make_break_arm ();
+    MatchCase make_continue_arm (std::unique_ptr<Pattern> &&pattern,
+                                std::unique_ptr<BlockExpr> &&body);
+  };
+
+  std::unique_ptr<Expr> desugar (WhileLetLoopExpr &expr);
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // ! RUST_DESUGAR_WHILE_LET_H
diff --git a/gcc/rust/ast/rust-expression-yeast.cc 
b/gcc/rust/ast/rust-expression-yeast.cc
index e8cf6d5af8e4..9f6a62ff37c2 100644
--- a/gcc/rust/ast/rust-expression-yeast.cc
+++ b/gcc/rust/ast/rust-expression-yeast.cc
@@ -22,6 +22,7 @@
 #include "rust-desugar-try-block.h"
 #include "rust-desugar-for-loops.h"
 #include "rust-ast-full.h"
+#include "rust-desugar-while-let.h"
 #include "rust-expr.h"
 #include "rust-stmt.h"
 
@@ -44,9 +45,10 @@ ExpressionYeast::dispatch_loops (std::unique_ptr<Expr> 
&loop_expr)
     case BaseLoopExpr::Kind::For:
       DesugarForLoops::go (loop_expr);
       break;
-    case BaseLoopExpr::Kind::Loop:
-    case BaseLoopExpr::Kind::While:
     case BaseLoopExpr::Kind::WhileLet:
+      DesugarWhileLet::go (loop_expr);
+      break;
+    default:
       break;
     }
 }
diff --git a/gcc/testsuite/rust/compile/while_let1.rs 
b/gcc/testsuite/rust/compile/while_let1.rs
new file mode 100644
index 000000000000..a3fa3053226a
--- /dev/null
+++ b/gcc/testsuite/rust/compile/while_let1.rs
@@ -0,0 +1,109 @@
+// use self::Ordering::*;
+// use Ordering::*;
+
+// enum Ordering {
+//     A,
+//     B,
+// }
+
+// fn foo(_: Ordering) {}
+
+// fn main() {
+//     let a = A;
+
+//     foo(a);
+//     foo(B);
+// }
+
+#[lang = "sized"]
+trait Sized {}
+
+enum Result<T, E> {
+    Ok(T),
+    Err(E),
+}
+
+pub trait Try {
+    /// The type of this value when viewed as successful.
+    #[unstable(feature = "try_trait", issue = "42327")]
+    type Ok;
+    /// The type of this value when viewed as failed.
+    #[unstable(feature = "try_trait", issue = "42327")]
+    type Error;
+
+    /// Applies the "?" operator. A return of `Ok(t)` means that the
+    /// execution should continue normally, and the result of `?` is the
+    /// value `t`. A return of `Err(e)` means that execution should branch
+    /// to the innermost enclosing `catch`, or return from the function.
+    ///
+    /// If an `Err(e)` result is returned, the value `e` will be "wrapped"
+    /// in the return type of the enclosing scope (which must itself implement
+    /// `Try`). Specifically, the value `X::from_error(From::from(e))`
+    /// is returned, where `X` is the return type of the enclosing function.
+    #[lang = "into_result"]
+    #[unstable(feature = "try_trait", issue = "42327")]
+    fn into_result(self) -> Result<Self::Ok, Self::Error>;
+
+    /// Wrap an error value to construct the composite result. For example,
+    /// `Result::Err(x)` and `Result::from_error(x)` are equivalent.
+    #[lang = "from_error"]
+    #[unstable(feature = "try_trait", issue = "42327")]
+    fn from_error(v: Self::Error) -> Self;
+
+    /// Wrap an OK value to construct the composite result. For example,
+    /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent.
+    #[lang = "from_ok"]
+    #[unstable(feature = "try_trait", issue = "42327")]
+    fn from_ok(v: Self::Ok) -> Self;
+}
+
+pub struct NoneError;
+
+pub enum Option<T> {
+    /// No value
+    None,
+    /// Some value `T`
+    Some(T),
+}
+
+impl<T> Option<T> {
+    pub fn ok_or<E>(self, err: E) -> Result<T, E> {
+        match self {
+            Some(ok) => Result::Ok(ok),
+            None => Result::Err(err),
+        }
+    }
+}
+
+use Option::*;
+
+#[unstable(feature = "try_trait", issue = "42327")]
+impl<T> Try for Option<T> {
+    type Ok = T;
+    type Error = NoneError;
+
+    #[inline]
+    fn into_result(self) -> Result<T, NoneError> {
+        self.ok_or(NoneError)
+    }
+
+    #[inline]
+    fn from_ok(v: T) -> Self {
+        Some(v)
+    }
+
+    #[inline]
+    fn from_error(_: NoneError) -> Self {
+        None
+    }
+}
+
+fn foo() -> Option<i32> {
+    Option::Some(15)
+}
+
+fn main() {
+    // let _: Option<i32> = try { 15i32 };
+
+    while let Option::Some(15) = foo() {}
+}

Reply via email to