]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: desugar: Handle try-blocks
authorArthur Cohen <arthur.cohen@embecosm.com>
Tue, 22 Jul 2025 11:30:11 +0000 (13:30 +0200)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 5 Aug 2025 14:36:58 +0000 (16:36 +0200)
gcc/rust/ChangeLog:

* Make-lang.in: Compile it.
* ast/rust-expression-yeast.cc (ExpressionYeast::dispatch): Dispatch to try-block
desugar.
* ast/rust-desugar-try-block.cc: New file.
* ast/rust-desugar-try-block.h: New file.

gcc/testsuite/ChangeLog:

* rust/compile/try_block1.rs: New test.

gcc/rust/Make-lang.in
gcc/rust/ast/rust-desugar-try-block.cc [new file with mode: 0644]
gcc/rust/ast/rust-desugar-try-block.h [new file with mode: 0644]
gcc/rust/ast/rust-expression-yeast.cc
gcc/testsuite/rust/compile/try_block1.rs [new file with mode: 0644]

index 506435d20038ef51fb958897a94136fc4b54271a..12c9a427143fc33e76ce27e883af94720f28627d 100644 (file)
@@ -246,7 +246,7 @@ GRS_OBJS = \
        rust/rust-desugar-for-loops.o \
        rust/rust-desugar-question-mark.o \
        rust/rust-desugar-apit.o \
-       rust/rust-desugar-try-block.o \
+       rust/rust-desugar-try-block.o \
     $(END)
 # removed object files from here
 
diff --git a/gcc/rust/ast/rust-desugar-try-block.cc b/gcc/rust/ast/rust-desugar-try-block.cc
new file mode 100644 (file)
index 0000000..cd03350
--- /dev/null
@@ -0,0 +1,60 @@
+// 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-try-block.h"
+#include "rust-ast-builder.h"
+#include "rust-expr.h"
+
+namespace Rust {
+namespace AST {
+
+DesugarTryBlock::DesugarTryBlock () {}
+
+void
+DesugarTryBlock::go (std::unique_ptr<Expr> &ptr)
+{
+  auto original = static_cast<TryExpr &> (*ptr);
+  auto desugared = DesugarTryBlock ().desugar (original);
+
+  ptr = std::move (desugared);
+}
+
+std::unique_ptr<Expr>
+DesugarTryBlock::desugar (TryExpr &expr)
+{
+  auto builder = Builder (expr.get_locus ());
+  auto &block = expr.get_block_expr ();
+
+  if (block.has_statements ())
+    rust_sorry_at (expr.get_locus (),
+                  "cannot desugar try-blocks with statements");
+
+  auto tail_expr = builder.tuple ();
+
+  if (block.has_tail_expr ())
+    tail_expr = block.get_tail_expr ().clone_expr ();
+
+  // Wrap in Try::from_ok call
+  auto from_ok = builder.path_in_expression (LangItem::Kind::TRY_FROM_OK);
+  auto call = builder.call (ptrify (from_ok), std::move (tail_expr));
+
+  return builder.block (std::move (call));
+}
+
+} // namespace AST
+} // namespace Rust
diff --git a/gcc/rust/ast/rust-desugar-try-block.h b/gcc/rust/ast/rust-desugar-try-block.h
new file mode 100644 (file)
index 0000000..bfd0463
--- /dev/null
@@ -0,0 +1,42 @@
+// 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_TRY_BLOCK
+#define RUST_DESUGAR_TRY_BLOCK
+
+#include "rust-expr.h"
+
+namespace Rust {
+namespace AST {
+
+// FIXME: Add documentation
+class DesugarTryBlock
+{
+public:
+  static void go (std::unique_ptr<Expr> &ptr);
+
+private:
+  DesugarTryBlock ();
+
+  std::unique_ptr<Expr> desugar (TryExpr &);
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // ! RUST_DESUGAR_TRY_BLOCK
index 1089b71034c212abb0ef92313fc90cde038f0353..6c0b3d3cced3e84aa87d1db8f9ae263a8cb08256 100644 (file)
@@ -19,6 +19,7 @@
 #include "rust-expression-yeast.h"
 #include "rust-ast-visitor.h"
 #include "rust-desugar-question-mark.h"
+#include "rust-desugar-try-block.h"
 #include "rust-ast-full.h"
 
 namespace Rust {
@@ -39,6 +40,9 @@ ExpressionYeast::dispatch (std::unique_ptr<Expr> &expr)
     case Expr::Kind::ErrorPropagation:
       DesugarQuestionMark::go (expr);
       break;
+    case Expr::Kind::Try:
+      DesugarTryBlock::go (expr);
+      break;
 
     default:
       break;
diff --git a/gcc/testsuite/rust/compile/try_block1.rs b/gcc/testsuite/rust/compile/try_block1.rs
new file mode 100644 (file)
index 0000000..7ae0536
--- /dev/null
@@ -0,0 +1,89 @@
+// { dg-additional-options "-frust-edition=2018" }
+
+#[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 main() {
+    let _: Option<i32> = try { 15i32 };
+}