authorgravatar for 77421532+sin-ack@users.noreply.github.comsin-ack <77421532+sin-ack@users.noreply.github.com> 2022-04-30 05:53:06+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-04-29 22:53:06-04:00
log032c722d2019a475362c0ae01241a80417bdd8a2
tree97e0d9229e2f1173d2bfb8f53351476656042db4
parent609896a6e8180ec32844d2b4656b52ef41fe7757
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Sema: Fix many-pointer array concatenation at comptime (#11512)

* Sema: Correctly determine whether array_cat lhs and rhs are single ptrs Many-pointers are also not single-pointers and wouldn't be considered here. This commit makes the conditions use the appropriately-named isSinglePointer instead. * Sema: Correctly obtain ArrayInfo for many-pointer concatenation Many-pointers at comptime have a known size like slices and can be used in array concatenation. This fixes a stage1 regression. * test: Add comptime manyptr concatenation test Co-authored-by: sin-ack <sin-ack@users.noreply.github.com>

2 files changed, 41 insertions(+), 12 deletions(-)

src/Sema.zig+16-12
...@@ -9106,8 +9106,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9106,8 +9106,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9106 const rhs_len = try sema.usizeCast(block, lhs_src, rhs_info.len);9106 const rhs_len = try sema.usizeCast(block, lhs_src, rhs_info.len);
9107 const final_len = lhs_len + rhs_len;9107 const final_len = lhs_len + rhs_len;
9108 const final_len_including_sent = final_len + @boolToInt(res_sent != null);9108 const final_len_including_sent = final_len + @boolToInt(res_sent != null);
9109 const lhs_single_ptr = lhs_ty.zigTypeTag() == .Pointer and !lhs_ty.isSlice();9109 const lhs_single_ptr = lhs_ty.isSinglePointer();
9110 const rhs_single_ptr = rhs_ty.zigTypeTag() == .Pointer and !rhs_ty.isSlice();9110 const rhs_single_ptr = rhs_ty.isSinglePointer();
9111 const lhs_sub_val = if (lhs_single_ptr) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;9111 const lhs_sub_val = if (lhs_single_ptr) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;
9112 const rhs_sub_val = if (rhs_single_ptr) (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? else rhs_val;9112 const rhs_sub_val = if (rhs_single_ptr) (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? else rhs_val;
9113 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);9113 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
...@@ -9160,17 +9160,21 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, inst: Air.Inst.R...@@ -9160,17 +9160,21 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, inst: Air.Inst.R
9160 .Array => t.arrayInfo(),9160 .Array => t.arrayInfo(),
9161 .Pointer => blk: {9161 .Pointer => blk: {
9162 const ptrinfo = t.ptrInfo().data;9162 const ptrinfo = t.ptrInfo().data;
9163 if (ptrinfo.size == .Slice) {9163 switch (ptrinfo.size) {
9164 const val = try sema.resolveConstValue(block, src, inst);9164 .Slice, .Many => {
9165 return Type.ArrayInfo{9165 const val = try sema.resolveConstValue(block, src, inst);
9166 .elem_type = t.childType(),9166 return Type.ArrayInfo{
9167 .sentinel = t.sentinel(),9167 .elem_type = t.childType(),
9168 .len = val.sliceLen(sema.mod),9168 .sentinel = t.sentinel(),
9169 };9169 .len = val.sliceLen(sema.mod),
9170 };
9171 },
9172 .One => {
9173 if (ptrinfo.pointee_type.zigTypeTag() != .Array) return null;
9174 break :blk ptrinfo.pointee_type.arrayInfo();
9175 },
9176 .C => return null,
9170 }9177 }
9171 if (ptrinfo.pointee_type.zigTypeTag() != .Array) return null;
9172 if (ptrinfo.size != .One) return null;
9173 break :blk ptrinfo.pointee_type.arrayInfo();
9174 },9178 },
9175 else => null,9179 else => null,
9176 };9180 };
test/behavior/basic.zig+25
...@@ -709,6 +709,31 @@ test "string concatenation" {...@@ -709,6 +709,31 @@ test "string concatenation" {
709 try expect(b[len] == 0);709 try expect(b[len] == 0);
710}710}
711711
712fn manyptrConcat(comptime s: [*:0]const u8) [*:0]const u8 {
713 return "very " ++ s;
714}
715
716test "comptime manyptr concatenation" {
717 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
718 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
719 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
720
721 const s = "epic";
722 const actual = manyptrConcat(s);
723 const expected = "very epic";
724
725 const len = mem.len(actual);
726 const len_with_null = len + 1;
727 {
728 var i: u32 = 0;
729 while (i < len_with_null) : (i += 1) {
730 try expect(actual[i] == expected[i]);
731 }
732 }
733 try expect(actual[len] == 0);
734 try expect(expected[len] == 0);
735}
736
712test "thread local variable" {737test "thread local variable" {
713 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO738 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
714 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO739 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO