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" } }

Reply via email to