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