From: Philip Herron <herron.phi...@googlemail.com>

Addresses Rust-GCC#3348

gcc/rust/ChangeLog:

        * backend/rust-compile-intrinsic.cc (variant_count_handler): new 
intrinsic

gcc/testsuite/ChangeLog:

        * rust/execute/torture/enum_intrinsics2.rs: New test.

Signed-off-by: Philip Herron <herron.phi...@googlemail.com>
---
 gcc/rust/backend/rust-compile-intrinsic.cc    | 56 ++++++++++++++++++-
 .../rust/execute/torture/enum_intrinsics2.rs  | 25 +++++++++
 2 files changed, 80 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/rust/execute/torture/enum_intrinsics2.rs

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc 
b/gcc/rust/backend/rust-compile-intrinsic.cc
index 1f93e82a93a..28c69d50b46 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -90,6 +90,8 @@ static tree
 assume_handler (Context *ctx, TyTy::FnType *fntype);
 static tree
 discriminant_value_handler (Context *ctx, TyTy::FnType *fntype);
+static tree
+variant_count_handler (Context *ctx, TyTy::FnType *fntype);
 
 enum class Prefetch
 {
@@ -252,7 +254,8 @@ static const std::map<std::string,
      {"assume", assume_handler},
      {"try", try_handler (false)},
      {"catch_unwind", try_handler (true)},
-     {"discriminant_value", discriminant_value_handler}};
+     {"discriminant_value", discriminant_value_handler},
+     {"variant_count", variant_count_handler}};
 
 Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
 
@@ -1436,5 +1439,56 @@ discriminant_value_handler (Context *ctx, TyTy::FnType 
*fntype)
   return fndecl;
 }
 
+static tree
+variant_count_handler (Context *ctx, TyTy::FnType *fntype)
+{
+  rust_assert (fntype->get_num_type_params () == 1);
+  auto &mapping = fntype->get_substs ().at (0);
+  auto param_ty = mapping.get_param_ty ();
+  rust_assert (param_ty->can_resolve ());
+  auto resolved = param_ty->resolve ();
+
+  size_t variant_count = 0;
+  bool is_adt = resolved->is<TyTy::ADTType> ();
+  if (is_adt)
+    {
+      const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
+      variant_count = adt.number_of_variants ();
+    }
+
+  tree lookup = NULL_TREE;
+  if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+    return lookup;
+
+  auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+  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;
+
+  enter_intrinsic_block (ctx, fndecl);
+
+  // BUILTIN disriminant_value FN BODY BEGIN
+  tree result_decl = DECL_RESULT (fndecl);
+  tree type = TREE_TYPE (result_decl);
+
+  mpz_t ival;
+  mpz_init_set_ui (ival, variant_count);
+  tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true));
+  mpz_clear (ival);
+
+  auto return_statement
+    = Backend::return_statement (fndecl, result, BUILTINS_LOCATION);
+  ctx->add_statement (return_statement);
+
+  // BUILTIN disriminant_value FN BODY END
+
+  finalize_intrinsic_block (ctx, fndecl);
+
+  return fndecl;
+}
+
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/testsuite/rust/execute/torture/enum_intrinsics2.rs 
b/gcc/testsuite/rust/execute/torture/enum_intrinsics2.rs
new file mode 100644
index 00000000000..c1bae35deb2
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/enum_intrinsics2.rs
@@ -0,0 +1,25 @@
+#![feature(intrinsics)]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+enum BookFormat {
+    Paperback,
+    Hardback,
+    Ebook,
+}
+
+mod core {
+    mod intrinsics {
+        extern "rust-intrinsic" {
+            #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+            pub fn variant_count<T>() -> usize;
+        }
+    }
+}
+
+pub fn main() -> i32 {
+    let count = core::intrinsics::variant_count::<BookFormat>();
+
+    (count as i32) - 3
+}
-- 
2.45.2

Reply via email to