[gcc r17-3132] gccrs: lang: Add unsafe_cell

Arthur Cohen via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:f610d9c837080dc353512e46d55881f554ec1f02

commit r17-3132-gf610d9c837080dc353512e46d55881f554ec1f02
Author: Enes Cevik <[email protected]>
Date:   Thu Jul 16 17:24:01 2026 +0300

    gccrs: lang: Add unsafe_cell
    
    This patch implements the 'unsafe_cell' lang item to the compilers.
    Since, gccrs currently lacks niche-filling optimizations, this patch
    does not include any changes related to type layout sizes.
    
    gcc/rust/ChangeLog:
    
            * backend/rust-compile-type.cc
            (TyTyResolveCompile::visit): If type contains unsafe_cell type,
            do not mark it as const.
            * typecheck/rust-tyty.cc (ADTType::contains_unsafe_cell): New
            function.
            (TupleType::contains_unsafe_cell): Likewise.
            (ArrayType::contains_unsafe_cell): Likewise.
            (SliceType::contains_unsafe_cell): Likewise.
            * typecheck/rust-tyty.h (contains_unsafe_cell): New declaration.
            * util/rust-lang-item.cc (Rust::LangItem::lang_items): Add
            unsafe_cell to the BiMap.
            * util/rust-lang-item.h (class LangItem): Add UNSAFE_CELL to the
            Kind enum.
    
    gcc/testsuite/ChangeLog:
    
            * rust/compile/unsafe_cell.rs: New test.
    
    Signed-off-by: Enes Cevik <[email protected]>

Diff:
---
 gcc/rust/backend/rust-compile-type.cc     | 12 +++++++++-
 gcc/rust/typecheck/rust-tyty.cc           | 38 +++++++++++++++++++++++++++++++
 gcc/rust/typecheck/rust-tyty.h            | 10 ++++++++
 gcc/rust/util/rust-lang-item.cc           |  2 ++
 gcc/rust/util/rust-lang-item.h            |  2 ++
 gcc/testsuite/rust/compile/unsafe_cell.rs | 16 +++++++++++++
 6 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc
index f0c2d1bf1e04..eed8fd734c92 100644
--- a/gcc/rust/backend/rust-compile-type.cc
+++ b/gcc/rust/backend/rust-compile-type.cc
@@ -773,7 +773,17 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
     }
   else
     {
-      auto base = Backend::immutable_type (base_compiled_type);
+      // https://doc.rust-lang.org/core/cell/struct.UnsafeCell.html
+      // If you have a reference &T, then normally in Rust the compiler performs
+      // optimizations based on the knowledge that &T points to immutable data.
+      // Mutating that data, for example through an alias or by transmuting a &T
+      // into a &mut T, is considered undefined behavior. UnsafeCell<T> opts-out
+      // of the immutability guarantee for &T: a shared reference &UnsafeCell<T>
+      // may point to data that is being mutated. This is called “interior
+      // mutability”.
+      auto base = type.get_base ()->contains_unsafe_cell ()
+		    ? base_compiled_type
+		    : Backend::immutable_type (base_compiled_type);
       translated = Backend::reference_type (base);
     }
 }
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index bc26692058a2..af43b1c122ae 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -2053,6 +2053,23 @@ ADTType::handle_substitions (SubstitutionArgumentMappings &subst_mappings)
   return adt;
 }
 
+bool
+ADTType::contains_unsafe_cell () const
+{
+  if (auto unsafe_cell
+      = mappings.lookup_lang_item (LangItem::Kind::UNSAFE_CELL))
+    {
+      if (get_id () == *unsafe_cell)
+	return true;
+
+      for (auto &variant : get_variants ())
+	for (auto &field : variant->get_fields ())
+	  if (field->get_field_type ()->contains_unsafe_cell ())
+	    return true;
+    }
+  return false;
+}
+
 // TupleType
 
 TupleType::TupleType (HirId ref, location_t locus, std::vector<TyVar> fields,
@@ -2206,6 +2223,15 @@ TupleType::handle_substitions (SubstitutionArgumentMappings &mappings)
   return tuple;
 }
 
+bool
+TupleType::contains_unsafe_cell () const
+{
+  for (auto &field : get_fields ())
+    if (field.get_tyty ()->contains_unsafe_cell ())
+      return true;
+  return false;
+}
+
 void
 FnType::accept_vis (TyVisitor &vis)
 {
@@ -2670,6 +2696,12 @@ ArrayType::handle_substitions (SubstitutionArgumentMappings &mappings)
   return ref;
 }
 
+bool
+ArrayType::contains_unsafe_cell () const
+{
+  return get_element_type ()->contains_unsafe_cell ();
+}
+
 void
 SliceType::accept_vis (TyVisitor &vis)
 {
@@ -2737,6 +2769,12 @@ SliceType::handle_substitions (SubstitutionArgumentMappings &mappings)
   return ref;
 }
 
+bool
+SliceType::contains_unsafe_cell () const
+{
+  return get_element_type ()->contains_unsafe_cell ();
+}
+
 // BoolType
 
 BoolType::BoolType (HirId ref, std::set<HirId> refs)
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index ec9b71123ba3..3eaf23a3ce82 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -356,6 +356,8 @@ public:
   virtual BaseConstType *as_const_type () { return nullptr; }
   virtual const BaseConstType *as_const_type () const { return nullptr; }
 
+  virtual bool contains_unsafe_cell () const { return false; }
+
 protected:
   BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident,
 	    std::set<HirId> refs = std::set<HirId> ());
@@ -793,6 +795,8 @@ public:
 
   TupleType *handle_substitions (SubstitutionArgumentMappings &mappings);
 
+  bool contains_unsafe_cell () const override;
+
 private:
   std::vector<TyVar> fields;
 };
@@ -1035,6 +1039,8 @@ public:
   ADTType *
   handle_substitions (SubstitutionArgumentMappings &mappings) override final;
 
+  bool contains_unsafe_cell () const override;
+
 private:
   DefId id;
   std::string identifier;
@@ -1395,6 +1401,8 @@ public:
 
   ArrayType *handle_substitions (SubstitutionArgumentMappings &mappings);
 
+  bool contains_unsafe_cell () const override;
+
 private:
   TyVar element_type;
   TyVar capacity;
@@ -1435,6 +1443,8 @@ public:
 
   SliceType *handle_substitions (SubstitutionArgumentMappings &mappings);
 
+  bool contains_unsafe_cell () const override;
+
 private:
   TyVar element_type;
 };
diff --git a/gcc/rust/util/rust-lang-item.cc b/gcc/rust/util/rust-lang-item.cc
index c58ab401fd1c..e7bcc8f8e482 100644
--- a/gcc/rust/util/rust-lang-item.cc
+++ b/gcc/rust/util/rust-lang-item.cc
@@ -133,6 +133,8 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{
   {"box_free", Kind::BOX_FREE},
   {"maybe_uninit", Kind::MAYBE_UNINIT},
 
+  {"unsafe_cell", Kind::UNSAFE_CELL},
+
   {"future_trait", Kind::FUTURE_TRAIT},
   {"poll", Kind::POLL},
   {"Ready", Kind::READY},
diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h
index d6bea1a8e432..c1fd45d043db 100644
--- a/gcc/rust/util/rust-lang-item.h
+++ b/gcc/rust/util/rust-lang-item.h
@@ -169,6 +169,8 @@ public:
     BOX_FREE,
     MAYBE_UNINIT,
 
+    UNSAFE_CELL,
+
     FUTURE_TRAIT,
     POLL,
     READY,
diff --git a/gcc/testsuite/rust/compile/unsafe_cell.rs b/gcc/testsuite/rust/compile/unsafe_cell.rs
new file mode 100644
index 000000000000..0df31080f83b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/unsafe_cell.rs
@@ -0,0 +1,16 @@
+// { dg-additional-options "-fdump-tree-gimple" }
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "unsafe_cell"]
+pub struct UnsafeCell<T> { _v: T }
+
+pub fn normal_ref(_a: &i32) {}
+
+pub fn unsafe_ref(_b: &UnsafeCell<i32>) {}
+
+// { dg-final { scan-tree-dump "normal_ref \\(const i32 & const _a\\)" "gimple" } }
+// { dg-final { scan-tree-dump "unsafe_ref \\(struct unsafe_cell::UnsafeCell<i32> & const _b\\)" "gimple" } }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.