fix: slicing a many-pointer yields a correct slice (issue 0159)
emitSubslice handled a struct (slice/string) base and an array base, but a many-pointer [*]T base is an LLVM pointer kind — it fell through to the else arm that mapped the result to LLVMGetUndef(slice_ty), so a slice of a many-pointer (mp[lo..hi]) had a garbage .len/.ptr and iterating it segfaulted. Add a LLVMPointerTypeKind branch: the base value IS the data pointer, so GEP by lo and len = hi - lo (the caller supplies the bound; no length is read from the unbounded pointer). An open-ended mp[lo..] has no resolvable upper bound (a [*]T carries no length), so lowerSliceExpr now diagnoses it instead of emitting a .length op that yields garbage. A List (whose items is [*]T) is now iterable with for items[0..len] (e); applied in Scheduler.deinit. Regressions: examples/types/0195 (valid slice + List for-each) + examples/diagnostics/1192 (open-ended rejection).
This commit is contained in:
@@ -2122,6 +2122,22 @@ pub const Ops = struct {
|
||||
result = c.LLVMBuildInsertValue(self.e.builder, result, new_ptr, 0, "ss.wptr");
|
||||
result = c.LLVMBuildInsertValue(self.e.builder, result, new_len, 1, "ss.wlen");
|
||||
self.e.mapRef(result);
|
||||
} else if (base_kind == c.LLVMPointerTypeKind) {
|
||||
// Many-pointer `[*]T` (or a raw `*T`): the base value IS the data
|
||||
// pointer — GEP by `lo` for the new start, `len = hi - lo`. (issue
|
||||
// 0159: a many-pointer base previously fell to the `else` undef arm,
|
||||
// producing a slice with a garbage length. The caller supplies the
|
||||
// bound via `hi`; no length is read from the unbounded pointer.)
|
||||
var lo_indices = [_]c.LLVMValueRef{lo};
|
||||
const new_ptr = c.LLVMBuildGEP2(self.e.builder, elem_ty, base, &lo_indices, 1, "ss.ptr");
|
||||
var new_len = c.LLVMBuildSub(self.e.builder, hi, lo, "ss.len");
|
||||
if (c.LLVMTypeOf(new_len) != self.e.cached_i64) {
|
||||
new_len = c.LLVMBuildSExt(self.e.builder, new_len, self.e.cached_i64, "ss.ext");
|
||||
}
|
||||
var result = c.LLVMGetUndef(slice_ty);
|
||||
result = c.LLVMBuildInsertValue(self.e.builder, result, new_ptr, 0, "ss.wptr");
|
||||
result = c.LLVMBuildInsertValue(self.e.builder, result, new_len, 1, "ss.wlen");
|
||||
self.e.mapRef(result);
|
||||
} else {
|
||||
self.e.mapRef(c.LLVMGetUndef(slice_ty));
|
||||
}
|
||||
|
||||
@@ -1483,7 +1483,14 @@ pub fn lowerSliceExpr(self: *Lowering, se: *const ast.SliceExpr) Ref {
|
||||
self.lowerExpr(e)
|
||||
else if (!obj_ty.isBuiltin() and self.module.types.get(obj_ty) == .array)
|
||||
self.builder.constInt(@intCast(self.module.types.get(obj_ty).array.length), .i64)
|
||||
else
|
||||
else if (!obj_ty.isBuiltin() and self.module.types.get(obj_ty) == .many_pointer) blk: {
|
||||
// A many-pointer `[*]T` carries no length, so an open-ended slice
|
||||
// `mp[lo..]` has no upper bound to resolve — a `.length` op on it would
|
||||
// yield a garbage length (issue 0159). Require an explicit `hi`.
|
||||
if (self.diagnostics) |d|
|
||||
d.addFmt(.err, se.object.span, "slicing a many-pointer `[*]T` requires an explicit upper bound (`mp[lo..hi]`) — it has no length", .{});
|
||||
break :blk self.builder.constInt(0, .i64);
|
||||
} else
|
||||
self.builder.emit(.{ .length = .{ .operand = obj } }, .i64);
|
||||
if (se.end_inclusive) hi = self.builder.add(hi, self.builder.constInt(1, .i64), .i64);
|
||||
// Subslice of string stays string (same {ptr, i64} layout, correct type category)
|
||||
|
||||
Reference in New Issue
Block a user