lang: introduce cstring — the C-boundary string (Odin model)
cstring is ONE pointer to a null-terminated u8 buffer, C's char*: thin (8 bytes, no length; cstring_len walks to the terminator), crossing #foreign boundaries verbatim in both directions, with ?cstring as the nullable case lowering to the same bare pointer (null = absent). Conversion discipline mirrors Odin: a string LITERAL coerces implicitly (its bytes are terminated constants); any other string is rejected with a diagnostic naming to_cstring (it may be an unterminated view); and cstring never coerces to string implicitly — from_cstring(c) is the explicit zero-copy view, pricing the strlen. Plumbing: TypeId/TypeInfo builtin slot 18 (first_user 19), name classifiers, size/align/name tables, LLVM ptr lowering, the ?T pointer niche, the xx pointer ladder, the literal-gated coercion plan (isConstString + data_ptr), and the reserved-spelling set. std gains cstring_len/from_cstring/to_cstring (fmt.sx, re-exported); the old cstring(size) allocator helper is renamed alloc_string everywhere; getenv migrates to (name: cstring) -> ?cstring as the canonical user and env() drops its manual strlen/memcpy. Pinned: examples/1222 (FFI both directions, literal coercion, ?cstring null paths, round trip) and examples/1173 (both coercion diagnostics); FAIL pre-feature. The alloc_string rename + getenv signature shift the .ir snapshots — regenerated. zig build test 426/426; run_examples 604/604. Spec: reserved spelling + cstring section + C-interop rows.
This commit is contained in:
@@ -43,11 +43,15 @@ pub const CoercionResolver = struct {
|
||||
widen, // same kind, dst wider
|
||||
narrow, // same kind, dst narrower
|
||||
array_to_slice, // [N]T → []T (materialize backing storage + header)
|
||||
string_to_cstring, // literal-only implicit; other strings need to_cstring
|
||||
cstring_to_string_reject, // explicit from_cstring required (diagnostic)
|
||||
none, // nothing applies — pass the value through
|
||||
};
|
||||
|
||||
pub fn classify(self: CoercionResolver, src_ty: TypeId, dst_ty: TypeId) CoercionPlan {
|
||||
if (src_ty == dst_ty) return .no_op;
|
||||
if (src_ty == .string and dst_ty == .cstring) return .string_to_cstring;
|
||||
if (src_ty == .cstring and dst_ty == .string) return .cstring_to_string_reject;
|
||||
if (src_ty == .any and dst_ty != .any) return .unbox_any;
|
||||
if (dst_ty == .any and src_ty != .any) return .box_any;
|
||||
|
||||
@@ -113,8 +117,8 @@ pub const CoercionResolver = struct {
|
||||
const dst_float = Lowering.isFloat(dst_ty);
|
||||
const src_int = self.l.isIntEx(src_ty);
|
||||
const dst_int = self.l.isIntEx(dst_ty);
|
||||
const src_ptr = !src_ty.isBuiltin() and self.l.module.types.get(src_ty) == .pointer;
|
||||
const dst_ptr = !dst_ty.isBuiltin() and self.l.module.types.get(dst_ty) == .pointer;
|
||||
const src_ptr = (!src_ty.isBuiltin() and self.l.module.types.get(src_ty) == .pointer) or src_ty == .cstring;
|
||||
const dst_ptr = (!dst_ty.isBuiltin() and self.l.module.types.get(dst_ty) == .pointer) or dst_ty == .cstring;
|
||||
|
||||
if (src_int and dst_float) return .int_to_float;
|
||||
if (src_float and dst_int) return .float_to_int;
|
||||
|
||||
Reference in New Issue
Block a user