aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-25 19:41:19 -0400
committerGitHub <noreply@github.com>2021-10-25 19:41:19 -0400
commitdf198ea60e05664b5b72a43aae815fa06d94c19c (patch)
treeedf13ce2d73ab17a56d6b07b4734b97260bde3eb /src
parent30d01c8fea68baab396081da040f49defa494088 (diff)
parent21bf3b80666c14c9b2a2e1ec984a6b4bb23a5bb7 (diff)
downloadzig-df198ea60e05664b5b72a43aae815fa06d94c19c.tar.gz
zig-df198ea60e05664b5b72a43aae815fa06d94c19c.zip
Merge pull request #10034 from Snektron/stage2-slice
stage2: slice and optional improvements
Diffstat (limited to 'src')
-rw-r--r--src/Sema.zig54
-rw-r--r--src/codegen/llvm.zig17
-rw-r--r--src/type.zig6
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,
}
}