Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions gcc/rust/ast/rust-ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,7 @@ class Expr : public Visitable
TypeCast,
Assignment,
CompoundAssignment,
Try,
};

virtual Kind get_expr_kind () const = 0;
Expand Down
60 changes: 60 additions & 0 deletions gcc/rust/ast/rust-desugar-try-block.cc
Original file line number Diff line number Diff line change
@@ -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
42 changes: 42 additions & 0 deletions gcc/rust/ast/rust-desugar-try-block.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion gcc/rust/ast/rust-expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -3792,7 +3792,7 @@ class TryExpr : public ExprWithBlock
outer_attrs = std::move (new_attrs);
}

Expr::Kind get_expr_kind () const override { return Expr::Kind::Return; }
Expr::Kind get_expr_kind () const override { return Expr::Kind::Try; }

protected:
/* Use covariance to implement clone function as returning this object rather
Expand Down
4 changes: 4 additions & 0 deletions gcc/rust/ast/rust-expression-yeast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down
89 changes: 89 additions & 0 deletions gcc/testsuite/rust/compile/try_block1.rs
Original file line number Diff line number Diff line change
@@ -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 };
}
Loading