Commit d97928bf52
Changed files (3)
src
test
behavior
src/Sema.zig
@@ -1940,7 +1940,7 @@ fn zirRetPtr(
try sema.requireFunctionBlock(block, src);
if (block.is_comptime) {
- return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty);
+ return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty, 0);
}
const ptr_type = try Type.ptr(sema.arena, .{
@@ -2067,9 +2067,7 @@ fn zirAllocExtended(
const type_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
break :blk try sema.resolveType(block, ty_src, type_ref);
- } else {
- return sema.fail(block, src, "TODO implement Sema.zirAllocExtended inferred", .{});
- };
+ } else undefined;
const alignment: u16 = if (small.has_align) blk: {
const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
@@ -2078,22 +2076,47 @@ fn zirAllocExtended(
break :blk alignment;
} else 0;
+ const inferred_alloc_ty = if (small.is_const)
+ Type.initTag(.inferred_alloc_const)
+ else
+ Type.initTag(.inferred_alloc_mut);
+
if (small.is_comptime) {
- return sema.fail(block, src, "TODO implement Sema.zirAllocExtended comptime", .{});
+ if (small.has_type) {
+ return sema.analyzeComptimeAlloc(block, var_ty, alignment);
+ } else {
+ return sema.addConstant(
+ inferred_alloc_ty,
+ try Value.Tag.inferred_alloc_comptime.create(sema.arena, undefined),
+ );
+ }
}
- if (!small.is_const) {
- return sema.fail(block, src, "TODO implement Sema.zirAllocExtended var", .{});
+ if (small.has_type) {
+ if (!small.is_const) {
+ try sema.validateVarType(block, ty_src, var_ty, false);
+ }
+ const ptr_type = try Type.ptr(sema.arena, .{
+ .pointee_type = var_ty,
+ .@"align" = alignment,
+ .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
+ });
+ try sema.requireRuntimeBlock(block, src);
+ try sema.resolveTypeLayout(block, src, var_ty);
+ return block.addTy(.alloc, ptr_type);
}
- const ptr_type = try Type.ptr(sema.arena, .{
- .pointee_type = var_ty,
- .@"align" = alignment,
- .@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .local),
- });
- try sema.requireRuntimeBlock(block, src);
- try sema.resolveTypeLayout(block, src, var_ty);
- return block.addTy(.alloc, ptr_type);
+ // `Sema.addConstant` does not add the instruction to the block because it is
+ // not needed in the case of constant values. However here, we plan to "downgrade"
+ // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
+ // to the block even though it is currently a `.constant`.
+ const result = try sema.addConstant(
+ inferred_alloc_ty,
+ try Value.Tag.inferred_alloc.create(sema.arena, .{}),
+ );
+ try sema.requireFunctionBlock(block, src);
+ try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
+ return result;
}
fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -2103,7 +2126,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
- return sema.analyzeComptimeAlloc(block, var_ty);
+ return sema.analyzeComptimeAlloc(block, var_ty, 0);
}
fn zirAllocInferredComptime(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -2125,7 +2148,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
const var_decl_src = inst_data.src();
const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
if (block.is_comptime) {
- return sema.analyzeComptimeAlloc(block, var_ty);
+ return sema.analyzeComptimeAlloc(block, var_ty, 0);
}
const ptr_type = try Type.ptr(sema.arena, .{
.pointee_type = var_ty,
@@ -2145,7 +2168,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
if (block.is_comptime) {
- return sema.analyzeComptimeAlloc(block, var_ty);
+ return sema.analyzeComptimeAlloc(block, var_ty, 0);
}
try sema.validateVarType(block, ty_src, var_ty, false);
const ptr_type = try Type.ptr(sema.arena, .{
@@ -9436,8 +9459,10 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ty = try sema.resolveType(block, operand_src, inst_data.operand);
+ const resolved_ty = try sema.resolveTypeFields(block, operand_src, ty);
+ try sema.resolveTypeLayout(block, operand_src, resolved_ty);
const target = sema.mod.getTarget();
- const abi_align = ty.abiAlignment(target);
+ const abi_align = resolved_ty.abiAlignment(target);
return sema.addIntUnsigned(Type.comptime_int, abi_align);
}
@@ -9735,8 +9760,33 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
- return sema.fail(block, src, "TODO: Sema.zirAlignCast", .{});
+ const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
+ const align_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+ const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+ const dest_align = try sema.resolveAlign(block, align_src, extra.lhs);
+ const ptr = sema.resolveInst(extra.rhs);
+ const ptr_ty = sema.typeOf(ptr);
+
+ // TODO in addition to pointers, this instruction is supposed to work for
+ // pointer-like optionals and slices.
+ try sema.checkPtrType(block, ptr_src, ptr_ty);
+
+ // TODO compile error if the result pointer is comptime known and would have an
+ // alignment that disagrees with the Decl's alignment.
+
+ // TODO insert safety check that the alignment is correct
+
+ const ptr_info = ptr_ty.ptrInfo().data;
+ const dest_ty = try Type.ptr(sema.arena, .{
+ .pointee_type = ptr_info.pointee_type,
+ .@"align" = dest_align,
+ .@"addrspace" = ptr_info.@"addrspace",
+ .mutable = ptr_info.mutable,
+ .@"allowzero" = ptr_info.@"allowzero",
+ .@"volatile" = ptr_info.@"volatile",
+ .size = ptr_info.size,
+ });
+ return sema.coerceCompatiblePtrs(block, dest_ty, ptr, ptr_src);
}
fn zirClz(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -9838,6 +9888,18 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr
}
}
+fn checkPtrType(
+ sema: *Sema,
+ block: *Block,
+ ty_src: LazySrcLoc,
+ ty: Type,
+) CompileError!void {
+ switch (ty.zigTypeTag()) {
+ .Pointer => {},
+ else => return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty}),
+ }
+}
+
fn checkFloatType(
sema: *Sema,
block: *Block,
@@ -14630,14 +14692,22 @@ fn analyzeComptimeAlloc(
sema: *Sema,
block: *Block,
var_type: Type,
+ alignment: u32,
) CompileError!Air.Inst.Ref {
const ptr_type = try Type.ptr(sema.arena, .{
.pointee_type = var_type,
.@"addrspace" = target_util.defaultAddressSpace(sema.mod.getTarget(), .global_constant),
+ .@"align" = alignment,
});
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
+
+ const align_val = if (alignment == 0)
+ Value.@"null"
+ else
+ try Value.Tag.int_u64.create(anon_decl.arena(), alignment);
+
const decl = try anon_decl.finish(
try var_type.copy(anon_decl.arena()),
// There will be stores before the first load, but they may be to sub-elements or
@@ -14645,6 +14715,8 @@ fn analyzeComptimeAlloc(
// into fields/elements and have those overridden with stored values.
Value.undef,
);
+ decl.align_val = align_val;
+
try sema.mod.declareDeclDependency(sema.owner_decl, decl);
return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{
.runtime_index = block.runtime_index,
test/behavior/align.zig
@@ -41,3 +41,82 @@ test "implicitly decreasing slice alignment" {
fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
return a[0] + b[0];
}
+
+test "@alignCast pointers" {
+ var x: u32 align(4) = 1;
+ expectsOnly1(&x);
+ try expect(x == 2);
+}
+fn expectsOnly1(x: *align(1) u32) void {
+ expects4(@alignCast(4, x));
+}
+fn expects4(x: *align(4) u32) void {
+ x.* += 1;
+}
+
+test "specifying alignment allows pointer cast" {
+ try testBytesAlign(0x33);
+}
+fn testBytesAlign(b: u8) !void {
+ var bytes align(4) = [_]u8{ b, b, b, b };
+ const ptr = @ptrCast(*u32, &bytes[0]);
+ try expect(ptr.* == 0x33333333);
+}
+
+test "@alignCast slices" {
+ var array align(4) = [_]u32{ 1, 1 };
+ const slice = array[0..];
+ sliceExpectsOnly1(slice);
+ try expect(slice[0] == 2);
+}
+fn sliceExpectsOnly1(slice: []align(1) u32) void {
+ sliceExpects4(@alignCast(4, slice));
+}
+fn sliceExpects4(slice: []align(4) u32) void {
+ slice[0] += 1;
+}
+
+test "alignment of structs" {
+ try expect(@alignOf(struct {
+ a: i32,
+ b: *i32,
+ }) == @alignOf(usize));
+}
+
+test "return error union with 128-bit integer" {
+ try expect(3 == try give());
+}
+fn give() anyerror!u128 {
+ return 3;
+}
+
+test "alignment of >= 128-bit integer type" {
+ try expect(@alignOf(u128) == 16);
+ try expect(@alignOf(u129) == 16);
+}
+
+test "alignment of struct with 128-bit field" {
+ try expect(@alignOf(struct {
+ x: u128,
+ }) == 16);
+
+ comptime {
+ try expect(@alignOf(struct {
+ x: u128,
+ }) == 16);
+ }
+}
+
+test "size of extern struct with 128-bit field" {
+ try expect(@sizeOf(extern struct {
+ x: u128,
+ y: u8,
+ }) == 32);
+
+ comptime {
+ try expect(@sizeOf(extern struct {
+ x: u128,
+ y: u8,
+ }) == 32);
+ }
+}
test/behavior/align_stage1.zig
@@ -39,43 +39,6 @@ test "bit field alignment" {
try expect(@TypeOf(&blah.b) == *align(1:3:1) const u3);
}
-test "specifying alignment allows pointer cast" {
- try testBytesAlign(0x33);
-}
-fn testBytesAlign(b: u8) !void {
- var bytes align(4) = [_]u8{ b, b, b, b };
- const ptr = @ptrCast(*u32, &bytes[0]);
- try expect(ptr.* == 0x33333333);
-}
-
-test "@alignCast pointers" {
- var x: u32 align(4) = 1;
- expectsOnly1(&x);
- try expect(x == 2);
-}
-fn expectsOnly1(x: *align(1) u32) void {
- expects4(@alignCast(4, x));
-}
-fn expects4(x: *align(4) u32) void {
- x.* += 1;
-}
-
-test "@alignCast slices" {
- var array align(4) = [_]u32{
- 1,
- 1,
- };
- const slice = array[0..];
- sliceExpectsOnly1(slice);
- try expect(slice[0] == 2);
-}
-fn sliceExpectsOnly1(slice: []align(1) u32) void {
- sliceExpects4(@alignCast(4, slice));
-}
-fn sliceExpects4(slice: []align(4) u32) void {
- slice[0] += 1;
-}
-
test "implicitly decreasing fn alignment" {
// function alignment is a compile error on wasm32/wasm64
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
@@ -180,13 +143,6 @@ fn fnWithAlignedStack() i32 {
return 1234;
}
-test "alignment of structs" {
- try expect(@alignOf(struct {
- a: i32,
- b: *i32,
- }) == @alignOf(usize));
-}
-
test "alignment of function with c calling convention" {
var runtime_nothing = nothing;
const casted1 = @ptrCast(*const u8, runtime_nothing);
@@ -196,44 +152,6 @@ test "alignment of function with c calling convention" {
fn nothing() callconv(.C) void {}
-test "return error union with 128-bit integer" {
- try expect(3 == try give());
-}
-fn give() anyerror!u128 {
- return 3;
-}
-
-test "alignment of >= 128-bit integer type" {
- try expect(@alignOf(u128) == 16);
- try expect(@alignOf(u129) == 16);
-}
-
-test "alignment of struct with 128-bit field" {
- try expect(@alignOf(struct {
- x: u128,
- }) == 16);
-
- comptime {
- try expect(@alignOf(struct {
- x: u128,
- }) == 16);
- }
-}
-
-test "size of extern struct with 128-bit field" {
- try expect(@sizeOf(extern struct {
- x: u128,
- y: u8,
- }) == 32);
-
- comptime {
- try expect(@sizeOf(extern struct {
- x: u128,
- y: u8,
- }) == 32);
- }
-}
-
const DefaultAligned = struct {
nevermind: u32,
badguy: i128,