mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
commit
24b065a6a8
12
src/Sema.zig
12
src/Sema.zig
@ -8441,7 +8441,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
|
||||
const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand);
|
||||
const zero_val = Air.internedToRef((try mod.intValue(Type.err_int, 0)).toIntern());
|
||||
const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val);
|
||||
const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero);
|
||||
const ok = try block.addBinOp(.bool_and, is_lt_len, is_non_zero);
|
||||
try sema.addSafetyCheck(block, src, ok, .invalid_error_code);
|
||||
}
|
||||
return block.addInst(.{
|
||||
@ -21914,7 +21914,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
|
||||
} else {
|
||||
// Error must be in destination set or zero.
|
||||
const has_value = try block.addTyOp(.error_set_has_value, dest_ty, err_code);
|
||||
const ok = try block.addBinOp(.bit_or, has_value, is_zero);
|
||||
const ok = try block.addBinOp(.bool_or, has_value, is_zero);
|
||||
try sema.addSafetyCheck(block, src, ok, .invalid_error_code);
|
||||
}
|
||||
} else {
|
||||
@ -22279,7 +22279,7 @@ fn ptrCastFull(
|
||||
const ok = if (src_info.flags.size == .Slice and dest_info.flags.size == .Slice) ok: {
|
||||
const len = try sema.analyzeSliceLen(block, operand_src, ptr);
|
||||
const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
|
||||
break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
|
||||
break :ok try block.addBinOp(.bool_or, len_zero, is_non_zero);
|
||||
} else is_non_zero;
|
||||
try sema.addSafetyCheck(block, src, ok, .cast_to_null);
|
||||
}
|
||||
@ -22296,7 +22296,7 @@ fn ptrCastFull(
|
||||
const ok = if (src_info.flags.size == .Slice and dest_info.flags.size == .Slice) ok: {
|
||||
const len = try sema.analyzeSliceLen(block, operand_src, ptr);
|
||||
const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
|
||||
break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
|
||||
break :ok try block.addBinOp(.bool_or, len_zero, is_aligned);
|
||||
} else is_aligned;
|
||||
try sema.addSafetyCheck(block, src, ok, .incorrect_alignment);
|
||||
}
|
||||
@ -24644,7 +24644,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
|
||||
const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src);
|
||||
const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len);
|
||||
const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len);
|
||||
const ok = try block.addBinOp(.bit_or, ok1, ok2);
|
||||
const ok = try block.addBinOp(.bool_or, ok1, ok2);
|
||||
try sema.addSafetyCheck(block, src, ok, .memcpy_alias);
|
||||
}
|
||||
|
||||
@ -30996,7 +30996,7 @@ fn coerceCompatiblePtrs(
|
||||
const ok = if (inst_ty.isSlice(mod)) ok: {
|
||||
const len = try sema.analyzeSliceLen(block, inst_src, inst);
|
||||
const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
|
||||
break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
|
||||
break :ok try block.addBinOp(.bool_or, len_zero, is_non_zero);
|
||||
} else is_non_zero;
|
||||
try sema.addSafetyCheck(block, inst_src, ok, .cast_to_null);
|
||||
}
|
||||
|
||||
@ -2012,6 +2012,7 @@ const DeclGen = struct {
|
||||
.array_to_slice => try self.airArrayToSlice(inst),
|
||||
.slice => try self.airSlice(inst),
|
||||
.aggregate_init => try self.airAggregateInit(inst),
|
||||
.memcpy => return self.airMemcpy(inst),
|
||||
|
||||
.slice_ptr => try self.airSliceField(inst, 0),
|
||||
.slice_len => try self.airSliceField(inst, 1),
|
||||
@ -2021,7 +2022,7 @@ const DeclGen = struct {
|
||||
.ptr_elem_val => try self.airPtrElemVal(inst),
|
||||
.array_elem_val => try self.airArrayElemVal(inst),
|
||||
|
||||
.set_union_tag => return try self.airSetUnionTag(inst),
|
||||
.set_union_tag => return self.airSetUnionTag(inst),
|
||||
.get_union_tag => try self.airGetUnionTag(inst),
|
||||
.union_init => try self.airUnionInit(inst),
|
||||
|
||||
@ -3159,6 +3160,46 @@ const DeclGen = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn sliceOrArrayLen(self: *DeclGen, operand_id: IdRef, ty: Type) !IdRef {
|
||||
const mod = self.module;
|
||||
switch (ty.ptrSize(mod)) {
|
||||
.Slice => return self.extractField(Type.usize, operand_id, 1),
|
||||
.One => {
|
||||
const array_ty = ty.childType(mod);
|
||||
const elem_ty = array_ty.childType(mod);
|
||||
const abi_size = elem_ty.abiSize(mod);
|
||||
const usize_ty_ref = try self.resolveType(Type.usize, .direct);
|
||||
return self.spv.constInt(usize_ty_ref, array_ty.arrayLenIncludingSentinel(mod) * abi_size);
|
||||
},
|
||||
.Many, .C => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn sliceOrArrayPtr(self: *DeclGen, operand_id: IdRef, ty: Type) !IdRef {
|
||||
const mod = self.module;
|
||||
if (ty.isSlice(mod)) {
|
||||
const ptr_ty = ty.slicePtrFieldType(mod);
|
||||
return self.extractField(ptr_ty, operand_id, 0);
|
||||
}
|
||||
return operand_id;
|
||||
}
|
||||
|
||||
fn airMemcpy(self: *DeclGen, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const dest_slice = try self.resolve(bin_op.lhs);
|
||||
const src_slice = try self.resolve(bin_op.rhs);
|
||||
const dest_ty = self.typeOf(bin_op.lhs);
|
||||
const src_ty = self.typeOf(bin_op.rhs);
|
||||
const dest_ptr = try self.sliceOrArrayPtr(dest_slice, dest_ty);
|
||||
const src_ptr = try self.sliceOrArrayPtr(src_slice, src_ty);
|
||||
const len = try self.sliceOrArrayLen(dest_slice, dest_ty);
|
||||
try self.func.body.emit(self.spv.gpa, .OpCopyMemorySized, .{
|
||||
.target = dest_ptr,
|
||||
.source = src_ptr,
|
||||
.size = len,
|
||||
});
|
||||
}
|
||||
|
||||
fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef {
|
||||
if (self.liveness.isUnused(inst)) return null;
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
|
||||
@ -28,7 +28,6 @@ test "@memcpy with both operands single-ptr-to-array, one is null-terminated" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
try testMemcpyBothSinglePtrArrayOneIsNullTerminated();
|
||||
try comptime testMemcpyBothSinglePtrArrayOneIsNullTerminated();
|
||||
@ -49,7 +48,6 @@ test "@memcpy dest many pointer" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
try testMemcpyDestManyPtr();
|
||||
try comptime testMemcpyDestManyPtr();
|
||||
@ -68,16 +66,14 @@ fn testMemcpyDestManyPtr() !void {
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.zig_backend != .stage2_spirv64) {
|
||||
const S = struct {
|
||||
buffer: [8]u8 = undefined,
|
||||
fn set(self: *@This(), items: []const u8) void {
|
||||
@memcpy(self.buffer[0..items.len], items);
|
||||
}
|
||||
};
|
||||
const S = struct {
|
||||
buffer: [8]u8 = undefined,
|
||||
fn set(self: *@This(), items: []const u8) void {
|
||||
@memcpy(self.buffer[0..items.len], items);
|
||||
}
|
||||
};
|
||||
|
||||
var s = S{};
|
||||
s.set("hello");
|
||||
if (!std.mem.eql(u8, s.buffer[0..5], "hello")) @compileError("bad");
|
||||
}
|
||||
var s = S{};
|
||||
s.set("hello");
|
||||
if (!std.mem.eql(u8, s.buffer[0..5], "hello")) @compileError("bad");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user