From: liushuyu <liushuyu...@gmail.com>

gcc/rust/ChangeLog:
        * backend/rust-compile-intrinsic.cc: add `try` intrinsic handler.
        * lang.opt: add `-frust-panic` option.
        * rust-lang.cc: enable exception handler code generation.
        * rust-session-manager.cc: add getter and setter for panic
        strategy option.
        * rust-session-manager.h: Likewise.

Signed-off-by: Zixing Liu <liushuyu...@gmail.com>
---
 gcc/rust/backend/rust-compile-intrinsic.cc | 72 ++++++++++++++++++++++
 gcc/rust/lang.opt                          | 13 ++++
 gcc/rust/rust-lang.cc                      |  2 +
 gcc/rust/rust-session-manager.cc           |  3 +
 gcc/rust/rust-session-manager.h            | 14 +++++
 5 files changed, 104 insertions(+)

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc 
b/gcc/rust/backend/rust-compile-intrinsic.cc
index 16447b29a51..77b67c36c3e 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -23,6 +23,7 @@
 #include "rust-diagnostics.h"
 #include "rust-location.h"
 #include "rust-constexpr.h"
+#include "rust-session-manager.h"
 #include "rust-tree.h"
 #include "tree-core.h"
 #include "rust-gcc.h"
@@ -194,6 +195,9 @@ expect_handler (bool likely)
   };
 }
 
+static tree
+try_handler (Context *ctx, TyTy::FnType *fntype);
+
 inline tree
 sorry_handler (Context *ctx, TyTy::FnType *fntype)
 {
@@ -241,6 +245,7 @@ static const std::map<std::string,
     {"likely", expect_handler (true)},
     {"unlikely", expect_handler (false)},
     {"assume", assume_handler},
+    {"try", try_handler},
 };
 
 Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
@@ -1266,5 +1271,72 @@ assume_handler (Context *ctx, TyTy::FnType *fntype)
   return fndecl;
 }
 
+static tree
+try_handler (Context *ctx, TyTy::FnType *fntype)
+{
+  rust_assert (fntype->get_params ().size () == 3);
+
+  tree lookup = NULL_TREE;
+  if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+    return lookup;
+  auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+  enter_intrinsic_block (ctx, fndecl);
+
+  // BUILTIN try_handler FN BODY BEGIN
+  // setup the params
+  std::vector<Bvariable *> param_vars;
+  compile_fn_params (ctx, fntype, fndecl, &param_vars);
+  if (!Backend::function_set_parameters (fndecl, param_vars))
+    return error_mark_node;
+  tree enclosing_scope = NULL_TREE;
+
+  bool panic_is_abort = Session::get_instance ().options.get_panic_strategy ()
+                       == CompileOptions::PanicStrategy::Abort;
+  tree try_fn = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
+  tree user_data = Backend::var_expression (param_vars[1], UNDEF_LOCATION);
+  tree catch_fn = Backend::var_expression (param_vars[2], UNDEF_LOCATION);
+  tree normal_return_stmt
+    = Backend::return_statement (fndecl, integer_zero_node, BUILTINS_LOCATION);
+  tree error_return_stmt
+    = Backend::return_statement (fndecl, integer_one_node, BUILTINS_LOCATION);
+  tree try_call = Backend::call_expression (try_fn, {user_data}, nullptr,
+                                           BUILTINS_LOCATION);
+  tree catch_call = NULL_TREE;
+  tree try_block = Backend::block (fndecl, enclosing_scope, {}, UNDEF_LOCATION,
+                                  UNDEF_LOCATION);
+  Backend::block_add_statements (try_block,
+                                std::vector<tree>{try_call,
+                                                  normal_return_stmt});
+  if (panic_is_abort)
+    {
+      // skip building the try-catch construct
+      ctx->add_statement (try_block);
+      finalize_intrinsic_block (ctx, fndecl);
+      return fndecl;
+    }
+
+  tree eh_pointer
+    = build_call_expr (builtin_decl_explicit (BUILT_IN_EH_POINTER), 1,
+                      integer_zero_node);
+  catch_call = Backend::call_expression (catch_fn, {user_data, eh_pointer},
+                                        nullptr, BUILTINS_LOCATION);
+
+  tree catch_block = Backend::block (fndecl, enclosing_scope, {},
+                                    UNDEF_LOCATION, UNDEF_LOCATION);
+  Backend::block_add_statements (catch_block,
+                                std::vector<tree>{catch_call,
+                                                  error_return_stmt});
+  // TODO(liushuyu): eh_personality needs to be implemented as a runtime thing
+  auto eh_construct
+    = Backend::exception_handler_statement (try_block, catch_block, NULL_TREE,
+                                           BUILTINS_LOCATION);
+  ctx->add_statement (eh_construct);
+  // BUILTIN try_handler FN BODY END
+  finalize_intrinsic_block (ctx, fndecl);
+
+  return fndecl;
+}
+
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/rust/lang.opt b/gcc/rust/lang.opt
index ae601eb13ad..0e9aab48dfb 100644
--- a/gcc/rust/lang.opt
+++ b/gcc/rust/lang.opt
@@ -212,4 +212,17 @@ frust-borrowcheck
 Rust Var(flag_borrowcheck)
 Use the WIP borrow checker.
 
+frust-panic=
+Rust Joined RejectNegative Enum(frust_panic) Var(flag_rust_panic)
+-frust-edition=[unwind|abort]             Panic strategy to compile crate with
+
+Enum
+Name(frust_panic) Type(int) UnknownError(unknown panic strategy %qs)
+
+EnumValue
+Enum(frust_panic) String(unwind) Value(0)
+
+EnumValue
+Enum(frust_panic) String(abort) Value(1)
+
 ; This comment is to ensure we retain the blank line above.
diff --git a/gcc/rust/rust-lang.cc b/gcc/rust/rust-lang.cc
index b84e114390a..f3a155dbad1 100644
--- a/gcc/rust/rust-lang.cc
+++ b/gcc/rust/rust-lang.cc
@@ -143,6 +143,8 @@ grs_langhook_init_options_struct (struct gcc_options *opts)
   opts->x_warn_unused_result = 1;
   /* lets warn for infinite recursion*/
   opts->x_warn_infinite_recursion = 1;
+  /* Enable exception handling (aka `panic!` in Rust) */
+  opts->x_flag_exceptions = 1;
 
   // nothing yet - used by frontends to change specific options for the 
language
   Rust::Session::get_instance ().init_options ();
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index c0b4796c4e9..1039fdfb5b9 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -266,6 +266,9 @@ Session::handle_option (
     case OPT_frust_metadata_output_:
       options.set_metadata_output (arg);
       break;
+    case OPT_frust_panic_:
+      options.set_panic_strategy (flag_rust_panic);
+      break;
 
     default:
       break;
diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h
index b5a715ca4d6..73a85b32e97 100644
--- a/gcc/rust/rust-session-manager.h
+++ b/gcc/rust/rust-session-manager.h
@@ -264,6 +264,13 @@ struct CompileOptions
   } compile_until
     = CompileStep::End;
 
+  enum class PanicStrategy
+  {
+    Unwind,
+    Abort,
+  } panic_strategy
+    = PanicStrategy::Unwind;
+
   bool dump_option_enabled (DumpOption option) const
   {
     return dump_options.find (option) != dump_options.end ();
@@ -320,6 +327,13 @@ struct CompileOptions
 
   const CompileStep &get_compile_until () const { return compile_until; }
 
+  void set_panic_strategy (int strategy)
+  {
+    panic_strategy = static_cast<PanicStrategy> (strategy);
+  }
+
+  const PanicStrategy &get_panic_strategy () const { return panic_strategy; }
+
   void set_metadata_output (const std::string &path)
   {
     metadata_output_path = path;
-- 
2.45.2

Reply via email to