From: Enes Cevik <[email protected]>
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]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github:
https://github.com/Rust-GCC/gccrs/commit/efaeba75ab09c066482927f8ef845b8f12c2d6fd
The commit has NOT been mentioned in any issue.
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4719
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(-)
create mode 100644 gcc/testsuite/rust/compile/unsafe_cell.rs
diff --git a/gcc/rust/backend/rust-compile-type.cc
b/gcc/rust/backend/rust-compile-type.cc
index f0c2d1bf1..eed8fd734 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 bc2669205..af43b1c12 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 ec9b71123..3eaf23a3c 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 c58ab401f..e7bcc8f8e 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 d6bea1a8e..c1fd45d04 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 000000000..0df31080f
--- /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" } }
--
2.54.0