Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc fixes #14333

Merged
merged 10 commits into from
Jan 18, 2023
11 changes: 10 additions & 1 deletion lib/std/zig/tokenizer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1151,7 +1151,13 @@ pub const Tokenizer = struct {
},
},
.line_comment => switch (c) {
0 => break,
0 => {
if (self.index != self.buffer.len) {
result.tag = .invalid;
self.index += 1;
}
break;
},
'\n' => {
state = .start;
result.loc.start = self.index + 1;
Expand Down Expand Up @@ -1865,6 +1871,9 @@ test "null byte before eof" {
try testTokenize("//\x00", &.{.invalid});
try testTokenize("\\\\\x00", &.{ .multiline_string_literal_line, .invalid });
try testTokenize("\x00", &.{.invalid});
try testTokenize("// NUL\x00\n", &.{.invalid});
try testTokenize("///\x00\n", &.{ .doc_comment, .invalid });
try testTokenize("/// NUL\x00\n", &.{ .doc_comment, .invalid });
}

fn testTokenize(source: [:0]const u8, expected_token_tags: []const Token.Tag) !void {
Expand Down
25 changes: 21 additions & 4 deletions src/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3341,6 +3341,9 @@ fn ptrType(
return gz.astgen.failTok(ptr_info.allowzero_token.?, "C pointers always allow address zero", .{});
}

const source_offset = gz.astgen.source_offset;
const source_line = gz.astgen.source_line;
const source_column = gz.astgen.source_column;
const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type);

var sentinel_ref: Zir.Inst.Ref = .none;
Expand All @@ -3351,17 +3354,31 @@ fn ptrType(
var trailing_count: u32 = 0;

if (ptr_info.ast.sentinel != 0) {
// These attributes can appear in any order and they all come before the
// element type so we need to reset the source cursor before generating them.
gz.astgen.source_offset = source_offset;
gz.astgen.source_line = source_line;
gz.astgen.source_column = source_column;

sentinel_ref = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = elem_type } }, ptr_info.ast.sentinel);
trailing_count += 1;
}
if (ptr_info.ast.align_node != 0) {
align_ref = try expr(gz, scope, coerced_align_ri, ptr_info.ast.align_node);
trailing_count += 1;
}
if (ptr_info.ast.addrspace_node != 0) {
gz.astgen.source_offset = source_offset;
gz.astgen.source_line = source_line;
gz.astgen.source_column = source_column;

addrspace_ref = try expr(gz, scope, .{ .rl = .{ .ty = .address_space_type } }, ptr_info.ast.addrspace_node);
trailing_count += 1;
}
if (ptr_info.ast.align_node != 0) {
gz.astgen.source_offset = source_offset;
gz.astgen.source_line = source_line;
gz.astgen.source_column = source_column;

align_ref = try expr(gz, scope, coerced_align_ri, ptr_info.ast.align_node);
trailing_count += 1;
}
if (ptr_info.ast.bit_range_start != 0) {
assert(ptr_info.ast.bit_range_end != 0);
bit_start_ref = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u16_type } }, ptr_info.ast.bit_range_start);
Expand Down
25 changes: 22 additions & 3 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11288,6 +11288,7 @@ fn resolveSwitchItemVal(
// Only if we know for sure we need to report a compile error do we resolve the
// full source locations.
if (sema.resolveConstValue(block, .unneeded, item, "")) |val| {
try sema.resolveLazyValue(val);
return TypedValue{ .ty = item_ty, .val = val };
} else |err| switch (err) {
error.NeededSourceLocation => {
Expand Down Expand Up @@ -16258,6 +16259,7 @@ fn typeInfoNamespaceDecls(
for (decls) |decl_index| {
const decl = sema.mod.declPtr(decl_index);
if (decl.kind == .@"usingnamespace") {
if (decl.analysis == .in_progress) continue;
try sema.mod.ensureDeclAnalyzed(decl_index);
var buf: Value.ToTypeBuffer = undefined;
const new_ns = decl.val.toType(&buf).getNamespace().?;
Expand Down Expand Up @@ -24820,8 +24822,13 @@ fn coerceExtra(
// empty tuple to zero-length slice
// note that this allows coercing to a mutable slice.
if (inst_child_ty.structFieldCount() == 0) {
// Optional slice is represented with a null pointer so
// we use a dummy pointer value with the required alignment.
const slice_val = try Value.Tag.slice.create(sema.arena, .{
.ptr = Value.undef,
.ptr = if (dest_info.@"align" != 0)
try Value.Tag.int_u64.create(sema.arena, dest_info.@"align")
else
try inst_child_ty.lazyAbiAlignment(target, sema.arena),
.len = Value.zero,
});
return sema.addConstant(dest_ty, slice_val);
Expand Down Expand Up @@ -26065,7 +26072,8 @@ fn coerceVarArgParam(
) !Air.Inst.Ref {
if (block.is_typeof) return inst;

const coerced = switch (sema.typeOf(inst).zigTypeTag()) {
const uncasted_ty = sema.typeOf(inst);
const coerced = switch (uncasted_ty.zigTypeTag()) {
// TODO consider casting to c_int/f64 if they fit
.ComptimeInt, .ComptimeFloat => return sema.fail(
block,
Expand All @@ -26079,6 +26087,17 @@ fn coerceVarArgParam(
break :blk try sema.analyzeDeclRef(fn_decl);
},
.Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
.Float => float: {
const target = sema.mod.getTarget();
const double_bits = @import("type.zig").CType.sizeInBits(.double, target);
const inst_bits = uncasted_ty.floatBits(sema.mod.getTarget());
if (inst_bits >= double_bits) break :float inst;
switch (double_bits) {
32 => break :float try sema.coerce(block, Type.f32, inst, inst_src),
64 => break :float try sema.coerce(block, Type.f64, inst, inst_src),
else => unreachable,
}
},
else => inst,
};

Expand Down Expand Up @@ -27316,7 +27335,7 @@ fn coerceCompatiblePtrs(
return sema.addConstant(dest_ty, val);
}
try sema.requireRuntimeBlock(block, inst_src, null);
const inst_allows_zero = (inst_ty.zigTypeTag() == .Pointer and inst_ty.ptrAllowsZero()) or true;
const inst_allows_zero = inst_ty.zigTypeTag() != .Pointer or inst_ty.ptrAllowsZero();
if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and
try sema.typeHasRuntimeBits(dest_ty.elemType2()))
{
Expand Down
18 changes: 9 additions & 9 deletions src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3370,15 +3370,15 @@ pub const DeclGen = struct {
return llvm_int.constIntToPtr(try dg.lowerType(tv.ty));
},
.field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => {
return dg.lowerParentPtr(tv.val);
return dg.lowerParentPtr(tv.val, tv.ty.ptrInfo().data.bit_offset % 8 == 0);
},
.null_value, .zero => {
const llvm_type = try dg.lowerType(tv.ty);
return llvm_type.constNull();
},
.opt_payload => {
const payload = tv.val.castTag(.opt_payload).?.data;
return dg.lowerParentPtr(payload);
return dg.lowerParentPtr(payload, tv.ty.ptrInfo().data.bit_offset % 8 == 0);
},
else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{
tv.ty.fmtDebug(), tag,
Expand Down Expand Up @@ -3967,7 +3967,7 @@ pub const DeclGen = struct {
return try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index);
}

fn lowerParentPtr(dg: *DeclGen, ptr_val: Value) Error!*llvm.Value {
fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, byte_aligned: bool) Error!*llvm.Value {
const target = dg.module.getTarget();
switch (ptr_val.tag()) {
.decl_ref_mut => {
Expand Down Expand Up @@ -3996,7 +3996,7 @@ pub const DeclGen = struct {
},
.field_ptr => {
const field_ptr = ptr_val.castTag(.field_ptr).?.data;
const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.container_ptr);
const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.container_ptr, byte_aligned);
const parent_ty = field_ptr.container_ty;

const field_index = @intCast(u32, field_ptr.field_index);
Expand Down Expand Up @@ -4026,6 +4026,7 @@ pub const DeclGen = struct {
},
.Struct => {
if (parent_ty.containerLayout() == .Packed) {
if (!byte_aligned) return parent_llvm_ptr;
const llvm_usize = dg.context.intType(target.cpu.arch.ptrBitWidth());
const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize);
// count bits of fields before this one
Expand Down Expand Up @@ -4072,7 +4073,7 @@ pub const DeclGen = struct {
},
.elem_ptr => {
const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr);
const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr, true);

const llvm_usize = try dg.lowerType(Type.usize);
const indices: [1]*llvm.Value = .{
Expand All @@ -4083,7 +4084,7 @@ pub const DeclGen = struct {
},
.opt_payload_ptr => {
const opt_payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data;
const parent_llvm_ptr = try dg.lowerParentPtr(opt_payload_ptr.container_ptr);
const parent_llvm_ptr = try dg.lowerParentPtr(opt_payload_ptr.container_ptr, true);
var buf: Type.Payload.ElemType = undefined;

const payload_ty = opt_payload_ptr.container_ty.optionalChild(&buf);
Expand All @@ -4105,7 +4106,7 @@ pub const DeclGen = struct {
},
.eu_payload_ptr => {
const eu_payload_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
const parent_llvm_ptr = try dg.lowerParentPtr(eu_payload_ptr.container_ptr);
const parent_llvm_ptr = try dg.lowerParentPtr(eu_payload_ptr.container_ptr, true);

const payload_ty = eu_payload_ptr.container_ty.errorUnionPayload();
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
Expand Down Expand Up @@ -10667,8 +10668,7 @@ const ParamTypeIterator = struct {
.memory => {
it.zig_index += 1;
it.llvm_index += 1;
it.byval_attr = true;
return .byref;
return .byref_mut;
},
.sse => {
it.zig_index += 1;
Expand Down
26 changes: 26 additions & 0 deletions test/behavior/packed-struct.zig
Original file line number Diff line number Diff line change
Expand Up @@ -599,3 +599,29 @@ test "packed struct initialized in bitcast" {
const t = @bitCast(u8, T{ .val = val });
try expect(t == val);
}

test "pointer to container level packed struct field" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;

const S = packed struct(u32) {
test_bit: bool,
someother_data: u12,
other_test_bit: bool,
someother_more_different_data: u12,
other_bits: packed struct(u6) {
enable_1: bool,
enable_2: bool,
enable_3: bool,
enable_4: bool,
enable_5: bool,
enable_6: bool,
},
var arr = [_]u32{0} ** 2;
};
@ptrCast(*S, &S.arr[0]).other_bits.enable_3 = true;
try expect(S.arr[0] == 0x10000000);
}
10 changes: 10 additions & 0 deletions test/behavior/pointers.zig
Original file line number Diff line number Diff line change
Expand Up @@ -522,3 +522,13 @@ test "ptrToInt on a generic function" {
};
try S.doTheTest(&S.generic);
}

test "pointer alignment and element type include call expression" {
const S = struct {
fn T() type {
return struct { _: i32 };
}
const P = *align(@alignOf(T())) [@sizeOf(T())]u8;
};
try expect(@alignOf(S.P) > 0);
}
14 changes: 14 additions & 0 deletions test/behavior/switch.zig
Original file line number Diff line number Diff line change
Expand Up @@ -686,3 +686,17 @@ test "enum value without tag name used as switch item" {
_ => return error.TestFailed,
}
}

test "switch item sizeof" {
const S = struct {
fn doTheTest() !void {
var a: usize = 0;
switch (a) {
@sizeOf(struct {}) => {},
else => return error.TestFailed,
}
}
};
try S.doTheTest();
comptime try S.doTheTest();
}
13 changes: 13 additions & 0 deletions test/behavior/type_info.zig
Original file line number Diff line number Diff line change
Expand Up @@ -590,3 +590,16 @@ test "@typeInfo decls and usingnamespace" {
try expectEqualStrings(decls[1].name, "y");
try expectEqualStrings(decls[2].name, "z");
}

test "@typeInfo decls ignore dependency loops" {
const S = struct {
fn Def(comptime T: type) type {
std.debug.assert(@typeInfo(T).Struct.decls.len == 1);
return struct {
const foo = u32;
};
}
usingnamespace Def(@This());
};
_ = S.foo;
}
1 change: 0 additions & 1 deletion test/c_abi/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,6 @@ extern fn c_modify_by_ref_param(ByRef) ByRef;

test "C function modifies by ref param" {
if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows and builtin.mode != .Debug) return error.SkipZigTest;

const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined });
try expect(res.val == 42);
Expand Down
19 changes: 10 additions & 9 deletions test/cases/compile_errors/invalid_store_to_comptime_field.zig
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ pub export fn entry5() void {
comptime var y = .{ 1, 2 };
y = .{ 3, 4 };
}
// pub export fn entry5() void {
// var x: u32 = 15;
// const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x });
// const S = struct {
// fn foo(_: T) void {}
// };
// _ = S.foo(.{ -1234, 5679, x });
// }
pub export fn entry6() void {
var x: u32 = 15;
const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x });
const S = struct {
fn foo(_: T) void {}
};
_ = S.foo(.{ -1234, 5679, x });
}
pub export fn entry7() void {
const State = struct {
comptime id: bool = true,
fn init(comptime id: bool) @This() {
Expand All @@ -61,7 +61,7 @@ pub export fn entry6() void {
};
_ = State.init(false);
}
pub export fn entry7() void {
pub export fn entry8() void {
const list1 = .{ "sss", 1, 2, 3 };
const list2 = @TypeOf(list1){ .@"0" = "xxx", .@"1" = 4, .@"2" = 5, .@"3" = 6 };
_ = list2;
Expand All @@ -73,6 +73,7 @@ pub export fn entry7() void {
//
// :6:19: error: value stored in comptime field does not match the default value of the field
// :14:19: error: value stored in comptime field does not match the default value of the field
// :53:16: error: value stored in comptime field does not match the default value of the field
// :19:38: error: value stored in comptime field does not match the default value of the field
// :31:19: error: value stored in comptime field does not match the default value of the field
// :25:29: note: default value set here
Expand Down
15 changes: 15 additions & 0 deletions test/cases/f32_passed_to_variadic_fn.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
extern fn printf(format: [*:0]const u8, ...) c_int;
pub fn main() void {
var a: f64 = 2.0;
var b: f32 = 10.0;
_ = printf("f64: %f\n", a);
_ = printf("f32: %f\n", b);
}

// run
// backend=llvm
// target=x86_64-linux-gnu
//
// f64: 2.000000
// f32: 10.000000
//