mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 00:26:57 +00:00
Merge pull request #13338 from Vexu/stage2-compile-errors
Improve some error messages
This commit is contained in:
commit
8c4faa5f3f
@ -16,7 +16,7 @@ jobs:
|
||||
vmImage: 'windows-2019'
|
||||
variables:
|
||||
TARGET: 'x86_64-windows-gnu'
|
||||
ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.10.0-dev.4560+828735ac0'
|
||||
ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.11.0-dev.25+499dddb4c'
|
||||
ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip'
|
||||
steps:
|
||||
- pwsh: |
|
||||
|
@ -304,7 +304,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
|
||||
.Array = .{
|
||||
.len = array_info.len,
|
||||
.child = array_info.child,
|
||||
.sentinel = &sentinel_val,
|
||||
.sentinel = @ptrCast(?*const anyopaque, &sentinel_val),
|
||||
},
|
||||
}),
|
||||
.is_allowzero = info.is_allowzero,
|
||||
@ -322,7 +322,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
|
||||
.address_space = info.address_space,
|
||||
.child = info.child,
|
||||
.is_allowzero = info.is_allowzero,
|
||||
.sentinel = &sentinel_val,
|
||||
.sentinel = @ptrCast(?*const anyopaque, &sentinel_val),
|
||||
},
|
||||
}),
|
||||
else => {},
|
||||
@ -340,7 +340,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
|
||||
.address_space = ptr_info.address_space,
|
||||
.child = ptr_info.child,
|
||||
.is_allowzero = ptr_info.is_allowzero,
|
||||
.sentinel = &sentinel_val,
|
||||
.sentinel = @ptrCast(?*const anyopaque, &sentinel_val),
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
@ -42,7 +42,7 @@ export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{
|
||||
.StartAddressOfRawData = &_tls_start,
|
||||
.EndAddressOfRawData = &_tls_end,
|
||||
.AddressOfIndex = &_tls_index,
|
||||
.AddressOfCallBacks = &__xl_a,
|
||||
.AddressOfCallBacks = @ptrCast(*anyopaque, &__xl_a),
|
||||
.SizeOfZeroFill = 0,
|
||||
.Characteristics = 0,
|
||||
};
|
||||
|
@ -197,7 +197,7 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
|
||||
});
|
||||
},
|
||||
.expected_labelable => {
|
||||
return stream.print("expected 'while', 'for', 'inline', 'suspend', or '{{', found '{s}'", .{
|
||||
return stream.print("expected 'while', 'for', 'inline', or '{{', found '{s}'", .{
|
||||
token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
|
||||
});
|
||||
},
|
||||
@ -356,6 +356,12 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
|
||||
.next_field => {
|
||||
return stream.writeAll("field after declarations here");
|
||||
},
|
||||
.expected_var_const => {
|
||||
return stream.writeAll("expected 'var' or 'const' before variable declaration");
|
||||
},
|
||||
.wrong_equal_var_decl => {
|
||||
return stream.writeAll("variable initialized with '==' instead of '='");
|
||||
},
|
||||
|
||||
.expected_token => {
|
||||
const found_tag = token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)];
|
||||
@ -2579,6 +2585,8 @@ pub const Error = struct {
|
||||
mismatched_binary_op_whitespace,
|
||||
invalid_ampersand_ampersand,
|
||||
c_style_container,
|
||||
expected_var_const,
|
||||
wrong_equal_var_decl,
|
||||
|
||||
zig_style_container,
|
||||
previous_field,
|
||||
|
@ -812,7 +812,18 @@ const Parser = struct {
|
||||
const align_node = try p.parseByteAlign();
|
||||
const addrspace_node = try p.parseAddrSpace();
|
||||
const section_node = try p.parseLinkSection();
|
||||
const init_node: Node.Index = if (p.eatToken(.equal) == null) 0 else try p.expectExpr();
|
||||
const init_node: Node.Index = switch (p.token_tags[p.tok_i]) {
|
||||
.equal_equal => blk: {
|
||||
try p.warn(.wrong_equal_var_decl);
|
||||
p.tok_i += 1;
|
||||
break :blk try p.expectExpr();
|
||||
},
|
||||
.equal => blk: {
|
||||
p.tok_i += 1;
|
||||
break :blk try p.expectExpr();
|
||||
},
|
||||
else => 0,
|
||||
};
|
||||
if (section_node == 0 and addrspace_node == 0) {
|
||||
if (align_node == 0) {
|
||||
return p.addNode(.{
|
||||
@ -1118,7 +1129,18 @@ const Parser = struct {
|
||||
if (loop_stmt != 0) return loop_stmt;
|
||||
|
||||
if (label_token != 0) {
|
||||
return p.fail(.expected_labelable);
|
||||
const after_colon = p.tok_i;
|
||||
const node = try p.parseTypeExpr();
|
||||
if (node != 0) {
|
||||
const a = try p.parseByteAlign();
|
||||
const b = try p.parseAddrSpace();
|
||||
const c = try p.parseLinkSection();
|
||||
const d = if (p.eatToken(.equal) == null) 0 else try p.expectExpr();
|
||||
if (a != 0 or b != 0 or c != 0 or d != 0) {
|
||||
return p.failMsg(.{ .tag = .expected_var_const, .token = label_token });
|
||||
}
|
||||
}
|
||||
return p.failMsg(.{ .tag = .expected_labelable, .token = after_colon });
|
||||
}
|
||||
|
||||
return null_node;
|
||||
|
@ -5145,6 +5145,40 @@ test "zig fmt: make single-line if no trailing comma" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: variable initialized with ==" {
|
||||
try testError(
|
||||
\\comptime {
|
||||
\\ var z: u32 == 12 + 1;
|
||||
\\}
|
||||
, &.{.wrong_equal_var_decl});
|
||||
}
|
||||
|
||||
test "zig fmt: missing const/var before local variable" {
|
||||
try testError(
|
||||
\\comptime {
|
||||
\\ z: u32;
|
||||
\\}
|
||||
\\comptime {
|
||||
\\ z: u32 align(1);
|
||||
\\}
|
||||
\\comptime {
|
||||
\\ z: u32 addrspace(.generic);
|
||||
\\}
|
||||
\\comptime {
|
||||
\\ z: u32 linksection("foo");
|
||||
\\}
|
||||
\\comptime {
|
||||
\\ z: u32 = 1;
|
||||
\\}
|
||||
, &.{
|
||||
.expected_labelable,
|
||||
.expected_var_const,
|
||||
.expected_var_const,
|
||||
.expected_var_const,
|
||||
.expected_var_const,
|
||||
});
|
||||
}
|
||||
|
||||
test "zig fmt: while continue expr" {
|
||||
try testCanonical(
|
||||
\\test {
|
||||
|
@ -6500,9 +6500,14 @@ fn switchExpr(
|
||||
}
|
||||
|
||||
const operand_ri: ResultInfo = .{ .rl = if (any_payload_is_ref) .ref else .none };
|
||||
astgen.advanceSourceCursorToNode(operand_node);
|
||||
const operand_line = astgen.source_line - parent_gz.decl_line;
|
||||
const operand_column = astgen.source_column;
|
||||
const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node);
|
||||
const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond;
|
||||
const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node);
|
||||
// Sema expects a dbg_stmt immediately after switch_cond(_ref)
|
||||
try emitDbgStmt(parent_gz, operand_line, operand_column);
|
||||
// We need the type of the operand to use as the result location for all the prong items.
|
||||
const cond_ty_inst = try parent_gz.addUnNode(.typeof, cond, operand_node);
|
||||
const item_ri: ResultInfo = .{ .rl = .{ .ty = cond_ty_inst } };
|
||||
|
63
src/Sema.zig
63
src/Sema.zig
@ -9662,6 +9662,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
|
||||
|
||||
const operand = try sema.resolveInst(extra.data.operand);
|
||||
// AstGen guarantees that the instruction immediately following
|
||||
// switch_cond(_ref) is a dbg_stmt
|
||||
const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1;
|
||||
|
||||
var header_extra_index: usize = extra.end;
|
||||
|
||||
@ -10358,6 +10361,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
if (backend_supports_is_named_enum and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and
|
||||
(!operand_ty.isNonexhaustiveEnum() or union_originally))
|
||||
{
|
||||
try sema.zirDbgStmt(block, cond_dbg_node_index);
|
||||
const ok = try block.addUnOp(.is_named_enum_value, operand);
|
||||
try sema.addSafetyCheck(block, ok, .corrupt_switch);
|
||||
}
|
||||
@ -10827,6 +10831,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
if (backend_supports_is_named_enum and special.body.len != 0 and block.wantSafety() and
|
||||
operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally))
|
||||
{
|
||||
try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
|
||||
const ok = try case_block.addUnOp(.is_named_enum_value, operand);
|
||||
try sema.addSafetyCheck(&case_block, ok, .corrupt_switch);
|
||||
}
|
||||
@ -10850,6 +10855,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
// We still need a terminator in this block, but we have proven
|
||||
// that it is unreachable.
|
||||
if (case_block.wantSafety()) {
|
||||
try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
|
||||
_ = try sema.safetyPanic(&case_block, src, .corrupt_switch);
|
||||
} else {
|
||||
_ = try case_block.addNoOp(.unreach);
|
||||
@ -16620,7 +16626,17 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
const bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node };
|
||||
const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node };
|
||||
|
||||
const unresolved_elem_ty = try sema.resolveType(block, elem_ty_src, extra.data.elem_type);
|
||||
const unresolved_elem_ty = blk: {
|
||||
const air_inst = try sema.resolveInst(extra.data.elem_type);
|
||||
const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| {
|
||||
if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer()) {
|
||||
try sema.errNote(block, elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{});
|
||||
}
|
||||
return err;
|
||||
};
|
||||
if (ty.tag() == .generic_poison) return error.GenericPoison;
|
||||
break :blk ty;
|
||||
};
|
||||
const target = sema.mod.getTarget();
|
||||
|
||||
var extra_i = extra.end;
|
||||
@ -18666,6 +18682,13 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
|
||||
}
|
||||
|
||||
try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
|
||||
if (dest_ty.intInfo(sema.mod.getTarget()).bits == 0) {
|
||||
if (block.wantSafety()) {
|
||||
const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, try sema.addConstant(operand_ty, Value.zero));
|
||||
try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
|
||||
}
|
||||
return sema.addConstant(dest_ty, Value.zero);
|
||||
}
|
||||
const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand);
|
||||
if (block.wantSafety()) {
|
||||
const back = try block.addTyOp(.int_to_float, operand_ty, result);
|
||||
@ -18932,6 +18955,9 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) {
|
||||
return sema.fail(block, operand_src, "null pointer casted to type {}", .{dest_ty.fmt(sema.mod)});
|
||||
}
|
||||
if (dest_ty.zigTypeTag() == .Optional and sema.typeOf(ptr).zigTypeTag() != .Optional) {
|
||||
return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, operand_val));
|
||||
}
|
||||
return sema.addConstant(aligned_dest_ty, operand_val);
|
||||
}
|
||||
|
||||
@ -23919,9 +23945,20 @@ fn coerceExtra(
|
||||
// cast from ?*T and ?[*]T to ?*anyopaque
|
||||
// but don't do it if the source type is a double pointer
|
||||
if (dest_ty.isPtrLikeOptional() and dest_ty.elemType2().tag() == .anyopaque and
|
||||
inst_ty.isPtrLikeOptional() and inst_ty.elemType2().zigTypeTag() != .Pointer)
|
||||
{
|
||||
inst_ty.isPtrAtRuntime())
|
||||
anyopaque_check: {
|
||||
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;
|
||||
const elem_ty = inst_ty.elemType2();
|
||||
if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) {
|
||||
in_memory_result = .{ .double_ptr_to_anyopaque = .{
|
||||
.actual = inst_ty,
|
||||
.wanted = dest_ty,
|
||||
} };
|
||||
break :optional;
|
||||
}
|
||||
// Let the logic below handle wrapping the optional now that
|
||||
// it has been checked to correctly coerce.
|
||||
if (!inst_ty.isPtrLikeOptional()) break :anyopaque_check;
|
||||
return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
|
||||
}
|
||||
|
||||
@ -24044,9 +24081,16 @@ fn coerceExtra(
|
||||
|
||||
// cast from *T and [*]T to *anyopaque
|
||||
// but don't do it if the source type is a double pointer
|
||||
if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and
|
||||
inst_ty.childType().zigTypeTag() != .Pointer and sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
|
||||
{
|
||||
if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer) {
|
||||
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
|
||||
const elem_ty = inst_ty.elemType2();
|
||||
if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) {
|
||||
in_memory_result = .{ .double_ptr_to_anyopaque = .{
|
||||
.actual = inst_ty,
|
||||
.wanted = dest_ty,
|
||||
} };
|
||||
break :pointer;
|
||||
}
|
||||
return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
|
||||
}
|
||||
|
||||
@ -24528,6 +24572,7 @@ const InMemoryCoercionResult = union(enum) {
|
||||
ptr_allowzero: Pair,
|
||||
ptr_bit_range: BitRange,
|
||||
ptr_alignment: IntPair,
|
||||
double_ptr_to_anyopaque: Pair,
|
||||
|
||||
const Pair = struct {
|
||||
actual: Type,
|
||||
@ -24820,6 +24865,12 @@ const InMemoryCoercionResult = union(enum) {
|
||||
});
|
||||
break;
|
||||
},
|
||||
.double_ptr_to_anyopaque => |pair| {
|
||||
try sema.errNote(block, src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{
|
||||
pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
|
||||
});
|
||||
break;
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -3944,10 +3944,7 @@ pub const Type = extern union {
|
||||
.optional => {
|
||||
var buf: Payload.ElemType = undefined;
|
||||
const child_type = self.optionalChild(&buf);
|
||||
// optionals of zero sized pointers behave like bools
|
||||
if (!child_type.hasRuntimeBits()) return false;
|
||||
if (child_type.zigTypeTag() != .Pointer) return false;
|
||||
|
||||
const info = child_type.ptrInfo().data;
|
||||
switch (info.size) {
|
||||
.Slice, .C => return false,
|
||||
|
@ -1411,3 +1411,11 @@ test "peer type resolution of const and non-const pointer to array" {
|
||||
try std.testing.expect(@TypeOf(a, b) == *const [1024]u8);
|
||||
try std.testing.expect(a == b);
|
||||
}
|
||||
|
||||
test "floatToInt to zero-bit int" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
var a: f32 = 0.0;
|
||||
comptime try std.testing.expect(@floatToInt(u0, a) == 0);
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
export fn entry() void {
|
||||
var a: u32 = 1;
|
||||
var ptr: *align(@alignOf(u32)) anyopaque = &a;
|
||||
var b: *u32 = @ptrCast(*u32, ptr);
|
||||
var ptr2: *anyopaque = &b;
|
||||
_ = ptr2;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :5:28: error: expected type '*anyopaque', found '**u32'
|
||||
// :5:28: note: pointer type child '*u32' cannot cast into pointer type child 'anyopaque'
|
@ -0,0 +1,28 @@
|
||||
pub export fn entry1() void {
|
||||
const x: usize = 5;
|
||||
|
||||
const ptr: *const anyopaque = &(&x);
|
||||
_ = ptr;
|
||||
}
|
||||
pub export fn entry2() void {
|
||||
var val: [*:0]u8 = undefined;
|
||||
func(&val);
|
||||
}
|
||||
fn func(_: ?*anyopaque) void {}
|
||||
pub export fn entry3() void {
|
||||
var x: *?*usize = undefined;
|
||||
|
||||
const ptr: *const anyopaque = x;
|
||||
_ = ptr;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :4:35: error: expected type '*const anyopaque', found '*const *const usize'
|
||||
// :4:35: note: cannot implicitly cast double pointer '*const *const usize' to anyopaque pointer '*const anyopaque'
|
||||
// :9:10: error: expected type '?*anyopaque', found '*[*:0]u8'
|
||||
// :9:10: note: cannot implicitly cast double pointer '*[*:0]u8' to anyopaque pointer '?*anyopaque'
|
||||
// :15:35: error: expected type '*const anyopaque', found '*?*usize'
|
||||
// :15:35: note: cannot implicitly cast double pointer '*?*usize' to anyopaque pointer '*const anyopaque'
|
@ -0,0 +1,11 @@
|
||||
pub export fn entry() void {
|
||||
var a: *u32 = undefined;
|
||||
_ = *a;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:10: error: expected type 'type', found '*u32'
|
||||
// :3:10: note: use '.*' to dereference pointer
|
Loading…
Reference in New Issue
Block a user