Skip to content

Commit 43c20ab

Browse files
committed
gccrs: Introduce CStr language item
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. Signed-Off-By: Yap Zhi Heng <yapzhhg@gmail.com>
1 parent d5379d2 commit 43c20ab

8 files changed

Lines changed: 101 additions & 19 deletions

File tree

gcc/rust/backend/rust-compile-type.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
650650
const TyTy::SliceType *slice = nullptr;
651651
const TyTy::StrType *str = nullptr;
652652
const TyTy::DynamicObjectType *dyn = nullptr;
653+
const TyTy::ADTType *adt = nullptr;
653654
if (type.is_dyn_slice_type (&slice))
654655
{
655656
tree type_record = create_slice_type_record (*slice);
@@ -684,6 +685,28 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
684685

685686
return;
686687
}
688+
// Check for CStr, create a specific record for it
689+
else if (type.is_dyn_cstr_type (&adt))
690+
{
691+
// CStr in core crate is defined as the following:
692+
//
693+
// #[repr(transparent)]
694+
// pub struct CStr {
695+
// inner: [u8]
696+
// }
697+
//
698+
// Reuse the c_char (u8) slice fat-pointer layout
699+
TyTy::BaseType *u8 = nullptr;
700+
ctx->get_tyctx ()->lookup_builtin ("u8", &u8);
701+
// Create a synthetic SliceType over u8 and use that record layout
702+
TyTy::SliceType synthetic_slice (adt->get_ref (), adt->get_ident ().locus,
703+
TyTy::TyVar (u8->get_ref ()));
704+
tree type_record = create_slice_type_record (synthetic_slice);
705+
translated
706+
= Backend::named_type ("&CStr", type_record, adt->get_ident ().locus);
707+
708+
return;
709+
}
687710

688711
tree base_compiled_type
689712
= TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);

gcc/rust/typecheck/rust-hir-type-check-base.cc

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -397,24 +397,28 @@ TypeCheckBase::resolve_literal (const Analysis::NodeMapping &expr_mappings,
397397
break;
398398
}
399399

400-
/* This is a pointer to a null-terminated byte slice (&[u8]). */
401-
TyTy::BaseType *u8;
402-
auto ok = context->lookup_builtin ("u8", &u8);
403-
rust_assert (ok);
400+
auto lang_item_defined
401+
= mappings.lookup_lang_item (LangItem::Kind::CSTR);
404402

405-
auto crate_num = mappings.get_current_crate ();
406-
Analysis::NodeMapping slice_mapping (crate_num, UNKNOWN_NODEID,
407-
mappings.get_next_hir_id (
408-
crate_num),
409-
UNKNOWN_LOCAL_DEFID);
403+
if (!lang_item_defined)
404+
{
405+
rust_error_at (locus, "unable to find lang item: %<c_str%>");
406+
infered = new TyTy::ErrorType (expr_mappings.get_hirid (), locus);
407+
break;
408+
}
410409

411-
TyTy::SliceType *slice
412-
= new TyTy::SliceType (slice_mapping.get_hirid (), locus,
413-
TyTy::TyVar (u8->get_ref ()));
414-
context->insert_type (slice_mapping, slice);
410+
DefId cstr_defid = lang_item_defined.value ();
411+
HIR::Item *item = mappings.lookup_defid (cstr_defid).value ();
412+
413+
TyTy::BaseType *item_type = nullptr;
414+
bool ok = context->lookup_type (item->get_mappings ().get_hirid (),
415+
&item_type);
416+
417+
rust_assert (ok);
418+
rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
415419

416420
infered = new TyTy::ReferenceType (expr_mappings.get_hirid (),
417-
TyTy::TyVar (slice->get_ref ()),
421+
TyTy::TyVar (item_type->get_ref ()),
418422
Mutability::Imm,
419423
TyTy::Region::make_static ());
420424
}

gcc/rust/typecheck/rust-tyty.cc

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3085,7 +3085,8 @@ ReferenceType::get_region () const
30853085
bool
30863086
ReferenceType::is_dyn_object () const
30873087
{
3088-
return is_dyn_slice_type () || is_dyn_str_type () || is_dyn_obj_type ();
3088+
return is_dyn_slice_type () || is_dyn_str_type () || is_dyn_obj_type ()
3089+
|| is_dyn_cstr_type ();
30893090
}
30903091

30913092
bool
@@ -3127,6 +3128,27 @@ ReferenceType::is_dyn_obj_type (const TyTy::DynamicObjectType **dyn) const
31273128
return true;
31283129
}
31293130

3131+
bool
3132+
ReferenceType::is_dyn_cstr_type (const TyTy::ADTType **adt) const
3133+
{
3134+
if (get_base ()->get_kind () != TyTy::TypeKind::ADT)
3135+
return false;
3136+
3137+
const TyTy::ADTType *adt_ty
3138+
= static_cast<const TyTy::ADTType *> (get_base ());
3139+
auto &mappings = Analysis::Mappings::get ();
3140+
auto cstr_item = mappings.lookup_lang_item (LangItem::Kind::CSTR);
3141+
3142+
if (!cstr_item.has_value ())
3143+
return false;
3144+
3145+
if (cstr_item.value () != adt_ty->get_id ())
3146+
return false;
3147+
3148+
*adt = adt_ty;
3149+
return true;
3150+
}
3151+
31303152
void
31313153
ReferenceType::accept_vis (TyVisitor &vis)
31323154
{

gcc/rust/typecheck/rust-tyty.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,6 +1693,7 @@ class ReferenceType : public BaseType
16931693
bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const;
16941694
bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const;
16951695
bool is_dyn_obj_type (const TyTy::DynamicObjectType **dyn = nullptr) const;
1696+
bool is_dyn_cstr_type (const TyTy::ADTType **adt = nullptr) const;
16961697

16971698
private:
16981699
TyVar base;

gcc/rust/util/rust-lang-item.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{
9292
{"slice_u8", Kind::SLICE_U8},
9393
{"slice", Kind::SLICE},
9494
{"str", Kind::STR},
95+
// NOTE: CStr is not present in Rust 1.49, and is only backported for
96+
// compilation of Rust for Linux with a patched core lib.
97+
{"CStr", Kind::CSTR},
9598
{"f32_runtime", Kind::F32_RUNTIME},
9699
{"f64_runtime", Kind::F64_RUNTIME},
97100

gcc/rust/util/rust-lang-item.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ class LangItem
125125
SLICE_U8,
126126
SLICE,
127127
STR,
128+
// NOTE: CStr is not present in Rust 1.49, and is only backported for
129+
// compilation of Rust for Linux with a patched core lib.
130+
CSTR,
128131
F32_RUNTIME,
129132
F64_RUNTIME,
130133

gcc/testsuite/rust/compile/c_string_null_byte_check.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
// { dg-additional-options "-frust-c-style-string-literals" }
2-
#![feature(no_core)]
2+
#![feature(no_core, lang_items)]
33
#![no_core]
44

5+
type c_char = u8;
6+
7+
#[lang = "CStr"]
8+
pub struct CStr {
9+
inner: [c_char]
10+
}
11+
12+
impl CStr {
13+
pub const fn to_ptr(&self) -> *const c_char {
14+
&self.inner as *const [c_char] as *const c_char
15+
}
16+
}
17+
518
pub fn main() {
619
let _fail = c"gc\0crs";
720
// { dg-error "null characters in C string literals are not supported" "" { target *-*-* } .-1 }
Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
// { dg-additional-options "-frust-c-style-string-literals" }
22
// { dg-output "gccrs\n" }
3-
#![feature(no_core)]
3+
#![feature(no_core, lang_items)]
44
#![no_core]
55

66
extern "C" {
7-
fn printf(s: *const i8, ...);
7+
fn printf(s: *const u8, ...);
8+
}
9+
10+
type c_char = u8;
11+
12+
#[lang = "CStr"]
13+
pub struct CStr {
14+
inner: [c_char]
15+
}
16+
17+
impl CStr {
18+
pub const fn to_ptr(&self) -> *const c_char {
19+
&self.inner as *const [c_char] as *const c_char
20+
}
821
}
922

1023
pub fn main() {
1124
let a = c"gccrs";
1225
unsafe {
13-
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
26+
printf(a.to_ptr());
1427
}
1528
}

0 commit comments

Comments
 (0)