]> gcc.gnu.org Git - gcc.git/commitdiff
gccrs: add uninit intrinsic
authorPhilip Herron <herron.philip@googlemail.com>
Wed, 1 Mar 2023 12:43:56 +0000 (12:43 +0000)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 16 Jan 2024 17:19:02 +0000 (18:19 +0100)
Following an investigation from rustc and discussions on zulip the
recommendation was that for uninit we memset to 0x01 which is less likely
to be a null ptr but still an invalid reference.

Fixes #1899

Signed-off-by: Philip Herron <herron.philip@googlemail.com>
gcc/rust/ChangeLog:

* backend/rust-builtins.cc (BuiltinsContext::setup): add memset builtin to the map
* backend/rust-compile-intrinsic.cc (uninit_handler): implement uninit intrinsic

gcc/testsuite/ChangeLog:

* rust/compile/torture/uninit-intrinsic-1.rs: New test.

gcc/rust/backend/rust-builtins.cc
gcc/rust/backend/rust-compile-intrinsic.cc
gcc/testsuite/rust/compile/torture/uninit-intrinsic-1.rs [new file with mode: 0644]

index 0517a9aeaf0f9c2c2e2a4bee76e01f0accd9df47..c96553b8c5951f809cb0ddb8a9e174651eb3aae8 100644 (file)
@@ -249,6 +249,12 @@ BuiltinsContext::setup ()
                                            size_type_node, NULL_TREE),
                  0);
 
+  define_builtin ("memset", BUILT_IN_MEMSET, "__builtin_memset", "memset",
+                 build_function_type_list (void_type_node, ptr_type_node,
+                                           integer_type_node, size_type_node,
+                                           NULL_TREE),
+                 0);
+
   define_builtin ("prefetch", BUILT_IN_PREFETCH, "__builtin_prefetch",
                  "prefetch",
                  build_varargs_function_type_list (
index 04b0d3a26110d0e8df415d44a8fdd36f28e43f2f..85f6e1c63d2120a52a752fa6c91a5054bc852b25 100644 (file)
@@ -81,6 +81,8 @@ static tree
 copy_nonoverlapping_handler (Context *ctx, TyTy::FnType *fntype);
 static tree
 op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op);
+static tree
+uninit_handler (Context *ctx, TyTy::FnType *fntype);
 
 enum class Prefetch
 {
@@ -202,6 +204,7 @@ static const std::map<std::string,
     {"unchecked_rem", unchecked_op_handler (TRUNC_MOD_EXPR)},
     {"unchecked_shl", unchecked_op_handler (LSHIFT_EXPR)},
     {"unchecked_shr", unchecked_op_handler (RSHIFT_EXPR)},
+    {"uninit", uninit_handler},
 };
 
 Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
@@ -986,5 +989,58 @@ unchecked_op_inner (Context *ctx, TyTy::FnType *fntype, tree_code op)
   return fndecl;
 }
 
+static tree
+uninit_handler (Context *ctx, TyTy::FnType *fntype)
+{
+  // uninit has _zero_ parameters its parameter is the generic one
+  rust_assert (fntype->get_params ().size () == 0);
+
+  tree lookup = NULL_TREE;
+  if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+    return lookup;
+
+  auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+  // get the template parameter type tree fn size_of<T>();
+  rust_assert (fntype->get_num_substitutions () == 1);
+  auto &param_mapping = fntype->get_substs ().at (0);
+  const TyTy::ParamType *param_tyty = param_mapping.get_param_ty ();
+  TyTy::BaseType *resolved_tyty = param_tyty->resolve ();
+  tree template_parameter_type
+    = TyTyResolveCompile::compile (ctx, resolved_tyty);
+
+  enter_intrinsic_block (ctx, fndecl);
+
+  // BUILTIN size_of FN BODY BEGIN
+
+  tree memset_builtin = error_mark_node;
+  BuiltinsContext::get ().lookup_simple_builtin ("memset", &memset_builtin);
+  rust_assert (memset_builtin != error_mark_node);
+
+  // call memset with 0x01 and size of the thing see
+  // https://github.com/Rust-GCC/gccrs/issues/1899
+
+  tree dst = DECL_RESULT (fndecl);
+  tree constant_byte = build_int_cst (integer_type_node, 0x01);
+  tree size_expr = TYPE_SIZE_UNIT (template_parameter_type);
+
+  tree memset_call = build_call_expr_loc (BUILTINS_LOCATION, memset_builtin, 3,
+                                         dst, constant_byte, size_expr);
+  TREE_READONLY (memset_call) = 0;
+  TREE_SIDE_EFFECTS (memset_call) = 1;
+
+  ctx->add_statement (memset_call);
+
+  auto return_statement
+    = ctx->get_backend ()->return_statement (fndecl, {DECL_RESULT (fndecl)},
+                                            Location ());
+  ctx->add_statement (return_statement);
+  // BUILTIN size_of FN BODY END
+
+  finalize_intrinsic_block (ctx, fndecl);
+
+  return fndecl;
+}
+
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/testsuite/rust/compile/torture/uninit-intrinsic-1.rs b/gcc/testsuite/rust/compile/torture/uninit-intrinsic-1.rs
new file mode 100644 (file)
index 0000000..0c6772b
--- /dev/null
@@ -0,0 +1,21 @@
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn uninit<T>() -> T;
+    }
+}
+
+mod mem {
+    pub unsafe fn uninitialized<T>() -> T {
+        intrinsics::uninit()
+    }
+}
+
+struct Foo(i32, i32);
+// { dg-warning "struct is never constructed: .Foo." "" { target *-*-* } .-1 }
+// FIXME ^^ above is a bad-warning
+
+impl Foo {
+    pub fn new() -> Self {
+        unsafe { mem::uninitialized::<Foo>() }
+    }
+}
This page took 0.070654 seconds and 5 git commands to generate.