mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 05:48:31 +00:00
commit
7f604b6f48
@ -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;
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
@ -3351,15 +3354,29 @@ 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);
|
||||
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.addrspace_node != 0) {
|
||||
addrspace_ref = try expr(gz, scope, .{ .rl = .{ .ty = .address_space_type } }, ptr_info.ast.addrspace_node);
|
||||
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) {
|
||||
|
||||
25
src/Sema.zig
25
src/Sema.zig
@ -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 => {
|
||||
@ -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().?;
|
||||
@ -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);
|
||||
@ -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,
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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()))
|
||||
{
|
||||
|
||||
@ -3370,7 +3370,7 @@ 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);
|
||||
@ -3378,7 +3378,7 @@ pub const DeclGen = struct {
|
||||
},
|
||||
.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,
|
||||
@ -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 => {
|
||||
@ -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);
|
||||
@ -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
|
||||
@ -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 = .{
|
||||
@ -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);
|
||||
@ -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()) {
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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() {
|
||||
@ -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;
|
||||
@ -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
|
||||
|
||||
15
test/cases/f32_passed_to_variadic_fn.zig
Normal file
15
test/cases/f32_passed_to_variadic_fn.zig
Normal file
@ -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
|
||||
//
|
||||
Loading…
x
Reference in New Issue
Block a user