diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Sema.zig | 54 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 17 | ||||
| -rw-r--r-- | src/type.zig | 6 |
3 files changed, 57 insertions, 20 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index e7cb40420e..2562948e8e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8013,14 +8013,24 @@ fn analyzePtrArithmetic( const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src); // TODO adjust the return type according to alignment and other factors const runtime_src = rs: { - if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { - if (try sema.resolveDefinedValue(block, offset_src, offset)) |offset_val| { + if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| { + if (try sema.resolveMaybeUndefVal(block, offset_src, offset)) |offset_val| { const ptr_ty = sema.typeOf(ptr); - const offset_int = offset_val.toUnsignedInt(); const new_ptr_ty = ptr_ty; // TODO modify alignment + + if (ptr_val.isUndef() or offset_val.isUndef()) { + return sema.addConstUndef(new_ptr_ty); + } + + const offset_int = offset_val.toUnsignedInt(); if (ptr_val.getUnsignedInt()) |addr| { const target = sema.mod.getTarget(); - const elem_ty = ptr_ty.childType(); + const ptr_child_ty = ptr_ty.childType(); + const elem_ty = if (ptr_ty.isSinglePointer() and ptr_child_ty.zigTypeTag() == .Array) + ptr_child_ty.childType() + else + ptr_child_ty; + const elem_size = elem_ty.abiSize(target); const new_addr = switch (air_tag) { .ptr_add => addr + elem_size * offset_int, @@ -13217,8 +13227,8 @@ fn analyzeSlice( var elem_ty = ptr_ptr_child_ty.childType(); switch (ptr_ptr_child_ty.zigTypeTag()) { .Array => {}, - .Pointer => { - if (ptr_ptr_child_ty.isSinglePointer()) { + .Pointer => switch (ptr_ptr_child_ty.ptrSize()) { + .One => { const double_child_ty = ptr_ptr_child_ty.childType(); if (double_child_ty.zigTypeTag() == .Array) { ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); @@ -13228,10 +13238,23 @@ fn analyzeSlice( } else { return sema.fail(block, ptr_src, "slice of single-item pointer", .{}); } - } + }, + .Many, .C => { + ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); + slice_ty = ptr_ptr_child_ty; + array_ty = ptr_ptr_child_ty; + elem_ty = ptr_ptr_child_ty.childType(); + }, + .Slice => { + ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); + slice_ty = ptr_ptr_child_ty; + array_ty = ptr_ptr_child_ty; + elem_ty = ptr_ptr_child_ty.childType(); + }, }, else => return sema.fail(block, ptr_src, "slice of non-array type '{}'", .{ptr_ptr_child_ty}), } + const ptr = if (slice_ty.isSlice()) try sema.analyzeSlicePtr(block, src, ptr_or_slice, slice_ty, ptr_src) else @@ -13263,7 +13286,6 @@ fn analyzeSlice( const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src); - const opt_new_ptr_val = try sema.resolveDefinedValue(block, ptr_src, new_ptr); const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data; @@ -13287,11 +13309,21 @@ fn analyzeSlice( .size = .One, }); - if (opt_new_ptr_val) |new_ptr_val| { - return sema.addConstant(return_ty, new_ptr_val); - } else { + const opt_new_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr); + const new_ptr_val = opt_new_ptr_val orelse { return block.addBitCast(return_ty, new_ptr); + }; + + if (!new_ptr_val.isUndef()) { + return sema.addConstant(return_ty, new_ptr_val); } + + // Special case: @as([]i32, undefined)[x..x] + if (new_len_int == 0) { + return sema.addConstUndef(return_ty); + } + + return sema.fail(block, ptr_src, "non-zero length slice of undefined pointer", .{}); } const return_ty = try Type.ptr(sema.arena, .{ diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 80625928cb..ca9e973354 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -767,7 +767,7 @@ pub const DeclGen = struct { } const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace()); const elem_ty = t.childType(); - const llvm_elem_ty = if (elem_ty.hasCodeGenBits()) + const llvm_elem_ty = if (elem_ty.hasCodeGenBits() or elem_ty.zigTypeTag() == .Array) try dg.llvmType(elem_ty) else dg.context.intType(8); @@ -1480,7 +1480,7 @@ pub const DeclGen = struct { } const llvm_type = try self.llvmType(tv.ty); - if (!tv.ty.childType().hasCodeGenBits()) { + if (!tv.ty.childType().hasCodeGenBits() or !decl.ty.hasCodeGenBits()) { return self.lowerPtrToVoid(tv.ty); } @@ -1502,7 +1502,7 @@ pub const DeclGen = struct { // for non-optional pointers. We also need to respect the alignment, even though // the address will never be dereferenced. const llvm_usize = try dg.llvmType(Type.usize); - const llvm_ptr_ty = dg.context.intType(8).pointerType(0); + const llvm_ptr_ty = try dg.llvmType(ptr_ty); if (alignment != 0) { return llvm_usize.constInt(alignment, .False).constIntToPtr(llvm_ptr_ty); } @@ -2475,6 +2475,12 @@ pub const FuncGen = struct { const operand = try self.resolveInst(un_op); const operand_ty = self.air.typeOf(un_op); const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; + if (optional_ty.isPtrLikeOptional()) { + const optional_llvm_ty = try self.dg.llvmType(optional_ty); + const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand; + return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); + } + var buf: Type.Payload.ElemType = undefined; const payload_ty = optional_ty.optionalChild(&buf); if (!payload_ty.hasCodeGenBits()) { @@ -2484,11 +2490,6 @@ pub const FuncGen = struct { return operand; } } - if (optional_ty.isPtrLikeOptional()) { - const optional_llvm_ty = try self.dg.llvmType(optional_ty); - const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand; - return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); - } if (operand_is_ptr or isByRef(optional_ty)) { const index_type = self.context.intType(32); diff --git a/src/type.zig b/src/type.zig index 4682b3ed10..ca18b182a6 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2347,11 +2347,13 @@ pub const Type = extern union { } } - /// Asserts that the type is an optional + /// Asserts that the type is an optional or a pointer that can be null. pub fn isPtrLikeOptional(self: Type) bool { switch (self.tag()) { .optional_single_const_pointer, .optional_single_mut_pointer, + .c_const_pointer, + .c_mut_pointer, => return true, .optional => { @@ -2367,6 +2369,8 @@ pub const Type = extern union { .Many, .One => return !info.@"allowzero", } }, + + .pointer => return self.castTag(.pointer).?.data.size == .C, else => unreachable, } } |
