From: Yap Zhi Heng <[email protected]>
gcc/rust/ChangeLog:
* util/rust-lang-item.h (LangItem::Kind): New CSTR kind.
* util/rust-lang-item.cc (LangItem::lang_items): Ditto.
* backend/rust-compile-type.cc (visit(TyTy::ReferenceType)): Add
specific record
type for CStr.
* typecheck/rust-tyty.h (ReferenceType): Add function definition for
is_dyn_cstr_type.
* typecheck/rust-tyty.cc (ReferenceType::is_dyn_object): Update to
include
is_dyn_cstr_type.
(ReferenceType::is_dyn_cstr_type): Add implementation to check whether
the
ReferenceType is of type CStr.
* typecheck/rust-hir-type-check-base.cc(resolve_literal): Update
C_STRING case to
resolve to the CStr language item instead.
gcc/testsuite/ChangeLog:
* rust/execute/torture/c_string.rs: Add CStr language item definition.
* rust/compile/c_string_null_byte_check.rs: Ditto.
* rust/execute/torture/c_string_ensure_null_term.rs: New test.
Signed-Off-By: Yap Zhi Heng <[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/0a1e7a4435e772cf76cdb023f94afb8f905097d3
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/4565
gcc/rust/backend/rust-compile-type.cc | 23 +++++++++
.../typecheck/rust-hir-type-check-base.cc | 32 ++++++------
gcc/rust/typecheck/rust-tyty.cc | 24 ++++++++-
gcc/rust/typecheck/rust-tyty.h | 1 +
gcc/rust/util/rust-lang-item.cc | 3 ++
gcc/rust/util/rust-lang-item.h | 3 ++
.../rust/compile/c_string_null_byte_check.rs | 15 +++++-
.../rust/execute/torture/c_string.rs | 24 +++++++--
.../torture/c_string_ensure_null_term.rs | 50 +++++++++++++++++++
9 files changed, 154 insertions(+), 21 deletions(-)
create mode 100644
gcc/testsuite/rust/execute/torture/c_string_ensure_null_term.rs
diff --git a/gcc/rust/backend/rust-compile-type.cc
b/gcc/rust/backend/rust-compile-type.cc
index 35d56cc47..da6a8ee4a 100644
--- a/gcc/rust/backend/rust-compile-type.cc
+++ b/gcc/rust/backend/rust-compile-type.cc
@@ -664,6 +664,7 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
const TyTy::SliceType *slice = nullptr;
const TyTy::StrType *str = nullptr;
const TyTy::DynamicObjectType *dyn = nullptr;
+ const TyTy::ADTType *adt = nullptr;
if (type.is_dyn_slice_type (&slice))
{
tree type_record = create_slice_type_record (*slice);
@@ -698,6 +699,28 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
return;
}
+ // Check for CStr, create a specific record for it
+ else if (type.is_dyn_cstr_type (&adt))
+ {
+ // CStr in core crate is defined as the following:
+ //
+ // #[repr(transparent)]
+ // pub struct CStr {
+ // inner: [u8]
+ // }
+ //
+ // Reuse the c_char (u8) slice fat-pointer layout
+ TyTy::BaseType *u8 = nullptr;
+ ctx->get_tyctx ()->lookup_builtin ("u8", &u8);
+ // Create a synthetic SliceType over u8 and use that record layout
+ TyTy::SliceType synthetic_slice (adt->get_ref (), adt->get_ident
().locus,
+ TyTy::TyVar (u8->get_ref ()));
+ tree type_record = create_slice_type_record (synthetic_slice);
+ translated
+ = Backend::named_type ("&CStr", type_record, adt->get_ident ().locus);
+
+ return;
+ }
tree base_compiled_type
= TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc
b/gcc/rust/typecheck/rust-hir-type-check-base.cc
index 9cded2dbc..ade16808e 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc
@@ -408,24 +408,28 @@ TypeCheckBase::resolve_literal (const
Analysis::NodeMapping &expr_mappings,
break;
}
- /* This is a pointer to a null-terminated byte slice (&[u8]). */
- TyTy::BaseType *u8;
- auto ok = context->lookup_builtin ("u8", &u8);
- rust_assert (ok);
+ auto lang_item_defined
+ = mappings.lookup_lang_item (LangItem::Kind::CSTR);
- auto crate_num = mappings.get_current_crate ();
- Analysis::NodeMapping slice_mapping (crate_num, UNKNOWN_NODEID,
- mappings.get_next_hir_id (
- crate_num),
- UNKNOWN_LOCAL_DEFID);
+ if (!lang_item_defined)
+ {
+ rust_error_at (locus, "unable to find lang item: %<c_str%>");
+ infered = new TyTy::ErrorType (expr_mappings.get_hirid (), locus);
+ break;
+ }
- TyTy::SliceType *slice
- = new TyTy::SliceType (slice_mapping.get_hirid (), locus,
- TyTy::TyVar (u8->get_ref ()));
- context->insert_type (slice_mapping, slice);
+ DefId cstr_defid = lang_item_defined.value ();
+ HIR::Item *item = mappings.lookup_defid (cstr_defid).value ();
+
+ TyTy::BaseType *item_type = nullptr;
+ bool ok = context->lookup_type (item->get_mappings ().get_hirid (),
+ &item_type);
+
+ rust_assert (ok);
+ rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
- TyTy::TyVar (slice->get_ref ()),
+ TyTy::TyVar (item_type->get_ref ()),
Mutability::Imm,
TyTy::Region::make_static ());
}
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 144cca0e9..9ad09a323 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -3060,7 +3060,8 @@ ReferenceType::get_region () const
bool
ReferenceType::is_dyn_object () const
{
- return is_dyn_slice_type () || is_dyn_str_type () || is_dyn_obj_type ();
+ return is_dyn_slice_type () || is_dyn_str_type () || is_dyn_obj_type ()
+ || is_dyn_cstr_type ();
}
static const TyTy::BaseType *
@@ -3122,6 +3123,27 @@ ReferenceType::is_dyn_obj_type (const
TyTy::DynamicObjectType **dyn) const
return true;
}
+bool
+ReferenceType::is_dyn_cstr_type (const TyTy::ADTType **adt) const
+{
+ if (get_base ()->get_kind () != TyTy::TypeKind::ADT)
+ return false;
+
+ const TyTy::ADTType *adt_ty
+ = static_cast<const TyTy::ADTType *> (get_base ());
+ auto &mappings = Analysis::Mappings::get ();
+ auto cstr_item = mappings.lookup_lang_item (LangItem::Kind::CSTR);
+
+ if (!cstr_item.has_value ())
+ return false;
+
+ if (cstr_item.value () != adt_ty->get_id ())
+ return false;
+
+ *adt = adt_ty;
+ return true;
+}
+
void
ReferenceType::accept_vis (TyVisitor &vis)
{
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 1079314a4..b27de7422 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -1691,6 +1691,7 @@ public:
bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const;
bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const;
bool is_dyn_obj_type (const TyTy::DynamicObjectType **dyn = nullptr) const;
+ bool is_dyn_cstr_type (const TyTy::ADTType **adt = nullptr) const;
private:
TyVar base;
diff --git a/gcc/rust/util/rust-lang-item.cc b/gcc/rust/util/rust-lang-item.cc
index 21e2c81e9..2f7704546 100644
--- a/gcc/rust/util/rust-lang-item.cc
+++ b/gcc/rust/util/rust-lang-item.cc
@@ -92,6 +92,9 @@ const BiMap<std::string, LangItem::Kind>
Rust::LangItem::lang_items = {{
{"slice_u8", Kind::SLICE_U8},
{"slice", Kind::SLICE},
{"str", Kind::STR},
+ // NOTE: CStr is not present in Rust 1.49, and is only backported for
+ // compilation of Rust for Linux with a patched core lib.
+ {"CStr", Kind::CSTR},
{"f32_runtime", Kind::F32_RUNTIME},
{"f64_runtime", Kind::F64_RUNTIME},
diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h
index 5a765282b..75f4090b9 100644
--- a/gcc/rust/util/rust-lang-item.h
+++ b/gcc/rust/util/rust-lang-item.h
@@ -125,6 +125,9 @@ public:
SLICE_U8,
SLICE,
STR,
+ // NOTE: CStr is not present in Rust 1.49, and is only backported for
+ // compilation of Rust for Linux with a patched core lib.
+ CSTR,
F32_RUNTIME,
F64_RUNTIME,
diff --git a/gcc/testsuite/rust/compile/c_string_null_byte_check.rs
b/gcc/testsuite/rust/compile/c_string_null_byte_check.rs
index ac464bb28..040ba9ad4 100644
--- a/gcc/testsuite/rust/compile/c_string_null_byte_check.rs
+++ b/gcc/testsuite/rust/compile/c_string_null_byte_check.rs
@@ -1,7 +1,20 @@
// { dg-additional-options "-frust-c-style-string-literals" }
-#![feature(no_core)]
+#![feature(no_core, lang_items)]
#![no_core]
+type c_char = u8;
+
+#[lang = "CStr"]
+pub struct CStr {
+ inner: [c_char]
+}
+
+impl CStr {
+ pub const fn to_ptr(&self) -> *const c_char {
+ &self.inner as *const [c_char] as *const c_char
+ }
+}
+
pub fn main() {
let _fail = c"gc\0crs";
// { dg-error "null characters in C string literals are not supported" ""
{ target *-*-* } .-1 }
diff --git a/gcc/testsuite/rust/execute/torture/c_string.rs
b/gcc/testsuite/rust/execute/torture/c_string.rs
index af96d0591..5aef4db0c 100644
--- a/gcc/testsuite/rust/execute/torture/c_string.rs
+++ b/gcc/testsuite/rust/execute/torture/c_string.rs
@@ -1,15 +1,29 @@
// { dg-additional-options "-frust-c-style-string-literals" }
-// { dg-output "gccrs\n" }
-#![feature(no_core)]
+// { dg-output "gccrs" }
+#![feature(no_core, lang_items)]
#![no_core]
extern "C" {
- fn printf(s: *const i8, ...);
+ fn printf(s: *const u8, ...);
}
-pub fn main() {
+type c_char = u8;
+
+#[lang = "CStr"]
+pub struct CStr {
+ inner: [c_char]
+}
+
+impl CStr {
+ pub const fn to_ptr(&self) -> *const c_char {
+ &self.inner as *const [c_char] as *const c_char
+ }
+}
+
+fn main() -> i32 {
let a = c"gccrs";
unsafe {
- printf(a as *const [u8] as *const i8); // TODO change `as *const [u8]`
to `.as_ptr()` when C strings are compiled to their own CStr type
+ printf(a.to_ptr());
}
+ 0
}
diff --git a/gcc/testsuite/rust/execute/torture/c_string_ensure_null_term.rs
b/gcc/testsuite/rust/execute/torture/c_string_ensure_null_term.rs
new file mode 100644
index 000000000..26e0fed21
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/c_string_ensure_null_term.rs
@@ -0,0 +1,50 @@
+// { dg-additional-options "-frust-c-style-string-literals" }
+#![feature(no_core, intrinsics, staged_api, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+// below's helper code copied from issue-1232.rs
+extern "rust-intrinsic" {
+ #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
+ fn offset<T>(dst: *const T, offset: isize) -> *const T;
+}
+
+#[lang = "const_ptr"]
+impl<T> *const T {
+ pub const unsafe fn offset(self, count: isize) -> *const T {
+ unsafe { offset(self, count) }
+ }
+
+ pub const unsafe fn add(self, count: usize) -> Self {
+ unsafe { self.offset(count as isize) }
+ }
+
+ pub const fn as_ptr(self) -> *const T {
+ self as *const T
+ }
+}
+
+extern "C" {
+ fn printf(s: *const u8, ...);
+}
+
+type c_char = u8;
+
+#[lang = "CStr"]
+pub struct CStr {
+ inner: [c_char]
+}
+
+impl CStr {
+ pub const fn to_ptr(&self) -> *const c_char {
+ &self.inner as *const [c_char] as *const c_char
+ }
+}
+
+pub fn main() -> u8 {
+ let a = c"gccrs";
+ let val = unsafe { a.to_ptr().add(5) };
+ unsafe { *val }
+}
--
2.54.0