feat: support checked explicit sentinel slices

This commit is contained in:
2026-10-23 11:18:08 +02:00
parent 7cb4ace0fa
commit 8ab5b71a0c
7 changed files with 465 additions and 31 deletions
+18 -1
View File
@@ -1556,6 +1556,11 @@ emit_instruction_stream :: proc(
emit_recovery_value(emitter, instruction_index, instruction, "invalid slice container")
continue
}
check_sentinel := instruction.b != ir.INVALID_INSTRUCTION
if check_sentinel && !valid_value(instructions, instruction.b, item.child, &emitter.module.types) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid slice sentinel")
continue
}
pointer_name := fmt.tprintf("%%v%d", instruction.a)
length_name := fmt.tprintf("%d", item.count)
if item.kind == .Array {
@@ -1597,13 +1602,25 @@ emit_instruction_stream :: proc(
if item.kind == .Pointer {
fmt.sbprintf(&emitter.builder, " %%slice_ok%d = or i1 false, %%slice_order%d\n", instruction_index, instruction_index)
} else {
fmt.sbprintf(&emitter.builder, " %%slice_end_ok%d = icmp ule i64 %s, %s\n", instruction_index, end_name, length_name)
comparison := "ult" if check_sentinel && !item.has_sentinel else "ule"
fmt.sbprintf(&emitter.builder, " %%slice_end_ok%d = icmp %s i64 %s, %s\n", instruction_index, comparison, end_name, length_name)
fmt.sbprintf(&emitter.builder, " %%slice_ok%d = and i1 %%slice_order%d, %%slice_end_ok%d\n", instruction_index, instruction_index, instruction_index)
}
fmt.sbprintf(&emitter.builder, " br i1 %%slice_ok%d, label %%slice_continue%d, label %%slice_trap%d\nslice_trap%d:\n", instruction_index, instruction_index, instruction_index, instruction_index)
message := diagnostic_message(emitter, source.INVALID_DIAGNOSTIC, instruction.span, "slice bounds out of range")
emit_trap_call(emitter, message)
fmt.sbprintf(&emitter.builder, " unreachable\nslice_continue%d:\n", instruction_index)
if check_sentinel {
element_type := llvm_type(item.child, &emitter.module.types)
fmt.sbprintf(&emitter.builder, " %%slice_sentinel_ptr%d = getelementptr %s, ptr %s, i64 %s\n", instruction_index, element_type, pointer_name, end_name)
fmt.sbprintf(&emitter.builder, " %%slice_sentinel_value%d = load %s, ptr %%slice_sentinel_ptr%d\n", instruction_index, element_type, instruction_index)
fmt.sbprintf(&emitter.builder, " %%slice_sentinel_ok%d = icmp eq %s %%slice_sentinel_value%d, ", instruction_index, element_type, instruction_index)
write_operand(&emitter.builder, instructions, instruction.b, item.child, &emitter.module.types)
fmt.sbprintf(&emitter.builder, "\n br i1 %%slice_sentinel_ok%d, label %%slice_sentinel_continue%d, label %%slice_sentinel_trap%d\nslice_sentinel_trap%d:\n", instruction_index, instruction_index, instruction_index, instruction_index)
sentinel_message := diagnostic_message(emitter, source.INVALID_DIAGNOSTIC, instruction.span, "slice sentinel mismatch")
emit_trap_call(emitter, sentinel_message)
fmt.sbprintf(&emitter.builder, " unreachable\nslice_sentinel_continue%d:\n", instruction_index)
}
fmt.sbprintf(&emitter.builder, " %%slice_start%d = getelementptr %s, ptr %s, i64 %s\n", instruction_index, llvm_type(item.child, &emitter.module.types), pointer_name, start_name)
fmt.sbprintf(&emitter.builder, " %%slice_result%d = insertvalue %s poison, ptr %%slice_start%d, 0\n", instruction_index, llvm_type(instruction.type, &emitter.module.types), instruction_index)
fmt.sbprintf(&emitter.builder, " %%slice_result_len%d = sub i64 %s, %s\n", instruction_index, end_name, start_name)