diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 08b64439dab6..7ca8182d0a8d 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::mapget_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 param_vars; + compile_fn_params (ctx, fntype, fndecl, ¶m_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{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{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 35798f5e01a1..10a91f33585c 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 258b5f3b61f3..df06026387c1 100644 --- a/gcc/rust/rust-lang.cc +++ b/gcc/rust/rust-lang.cc @@ -146,6 +146,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 1cf58e814f69..e88dc69356bf 100644 --- a/gcc/rust/rust-session-manager.cc +++ b/gcc/rust/rust-session-manager.cc @@ -265,6 +265,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 17b52bae4b1d..c6ddccb62294 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 (strategy); + } + + const PanicStrategy &get_panic_strategy () const { return panic_strategy; } + void set_metadata_output (const std::string &path) { metadata_output_path = path;