mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Merge pull request #13744 from Vexu/stage2-fixes
Improve error messages, fix dependency loops
This commit is contained in:
parent
fd57487e35
commit
af958e95cc
@ -809,8 +809,6 @@ pub const IterableDir = struct {
|
|||||||
// and we avoid the code complexity here.
|
// and we avoid the code complexity here.
|
||||||
const w = os.wasi;
|
const w = os.wasi;
|
||||||
start_over: while (true) {
|
start_over: while (true) {
|
||||||
// TODO https://github.com/ziglang/zig/issues/12498
|
|
||||||
_ = @sizeOf(w.dirent_t) + 1;
|
|
||||||
// According to the WASI spec, the last entry might be truncated,
|
// According to the WASI spec, the last entry might be truncated,
|
||||||
// so we need to check if the left buffer contains the whole dirent.
|
// so we need to check if the left buffer contains the whole dirent.
|
||||||
if (self.end_index - self.index < @sizeOf(w.dirent_t)) {
|
if (self.end_index - self.index < @sizeOf(w.dirent_t)) {
|
||||||
|
|||||||
@ -2625,7 +2625,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
|||||||
.compile_error,
|
.compile_error,
|
||||||
.ret_node,
|
.ret_node,
|
||||||
.ret_load,
|
.ret_load,
|
||||||
.ret_tok,
|
.ret_implicit,
|
||||||
.ret_err_value,
|
.ret_err_value,
|
||||||
.@"unreachable",
|
.@"unreachable",
|
||||||
.repeat,
|
.repeat,
|
||||||
@ -3689,6 +3689,29 @@ fn fnDecl(
|
|||||||
if (param.anytype_ellipsis3) |tok| {
|
if (param.anytype_ellipsis3) |tok| {
|
||||||
return astgen.failTok(tok, "missing parameter name", .{});
|
return astgen.failTok(tok, "missing parameter name", .{});
|
||||||
} else {
|
} else {
|
||||||
|
ambiguous: {
|
||||||
|
if (tree.nodes.items(.tag)[param.type_expr] != .identifier) break :ambiguous;
|
||||||
|
const main_token = tree.nodes.items(.main_token)[param.type_expr];
|
||||||
|
const identifier_str = tree.tokenSlice(main_token);
|
||||||
|
if (isPrimitive(identifier_str)) break :ambiguous;
|
||||||
|
return astgen.failNodeNotes(
|
||||||
|
param.type_expr,
|
||||||
|
"missing parameter name or type",
|
||||||
|
.{},
|
||||||
|
&[_]u32{
|
||||||
|
try astgen.errNoteNode(
|
||||||
|
param.type_expr,
|
||||||
|
"if this is a name, annotate its type '{s}: T'",
|
||||||
|
.{identifier_str},
|
||||||
|
),
|
||||||
|
try astgen.errNoteNode(
|
||||||
|
param.type_expr,
|
||||||
|
"if this is a type, give it a name '<name>: {s}'",
|
||||||
|
.{identifier_str},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
return astgen.failNode(param.type_expr, "missing parameter name", .{});
|
return astgen.failNode(param.type_expr, "missing parameter name", .{});
|
||||||
}
|
}
|
||||||
} else 0;
|
} else 0;
|
||||||
@ -3884,9 +3907,8 @@ fn fnDecl(
|
|||||||
// As our last action before the return, "pop" the error trace if needed
|
// As our last action before the return, "pop" the error trace if needed
|
||||||
_ = try gz.addRestoreErrRetIndex(.ret, .always);
|
_ = try gz.addRestoreErrRetIndex(.ret, .always);
|
||||||
|
|
||||||
// Since we are adding the return instruction here, we must handle the coercion.
|
// Add implicit return at end of function.
|
||||||
// We do this by using the `ret_tok` instruction.
|
_ = try fn_gz.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node));
|
||||||
_ = try fn_gz.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break :func try decl_gz.addFunc(.{
|
break :func try decl_gz.addFunc(.{
|
||||||
@ -4330,9 +4352,8 @@ fn testDecl(
|
|||||||
// As our last action before the return, "pop" the error trace if needed
|
// As our last action before the return, "pop" the error trace if needed
|
||||||
_ = try gz.addRestoreErrRetIndex(.ret, .always);
|
_ = try gz.addRestoreErrRetIndex(.ret, .always);
|
||||||
|
|
||||||
// Since we are adding the return instruction here, we must handle the coercion.
|
// Add implicit return at end of function.
|
||||||
// We do this by using the `ret_tok` instruction.
|
_ = try fn_block.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node));
|
||||||
_ = try fn_block.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const func_inst = try decl_block.addFunc(.{
|
const func_inst = try decl_block.addFunc(.{
|
||||||
@ -5580,6 +5601,14 @@ fn simpleBinOp(
|
|||||||
const tree = astgen.tree;
|
const tree = astgen.tree;
|
||||||
const node_datas = tree.nodes.items(.data);
|
const node_datas = tree.nodes.items(.data);
|
||||||
|
|
||||||
|
if (op_inst_tag == .cmp_neq or op_inst_tag == .cmp_eq) {
|
||||||
|
const node_tags = tree.nodes.items(.tag);
|
||||||
|
const str = if (op_inst_tag == .cmp_eq) "==" else "!=";
|
||||||
|
if (node_tags[node_datas[node].lhs] == .string_literal or
|
||||||
|
node_tags[node_datas[node].rhs] == .string_literal)
|
||||||
|
return astgen.failNode(node, "cannot compare strings with {s}", .{str});
|
||||||
|
}
|
||||||
|
|
||||||
const lhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].lhs, node);
|
const lhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].lhs, node);
|
||||||
var line: u32 = undefined;
|
var line: u32 = undefined;
|
||||||
var column: u32 = undefined;
|
var column: u32 = undefined;
|
||||||
@ -6577,6 +6606,11 @@ fn switchExpr(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (case.ast.values) |val| {
|
||||||
|
if (node_tags[val] == .string_literal)
|
||||||
|
return astgen.failNode(val, "cannot switch on strings", .{});
|
||||||
|
}
|
||||||
|
|
||||||
if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) {
|
if (case.ast.values.len == 1 and node_tags[case.ast.values[0]] != .switch_range) {
|
||||||
scalar_cases_len += 1;
|
scalar_cases_len += 1;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -938,6 +938,7 @@ pub const Struct = struct {
|
|||||||
known_non_opv: bool,
|
known_non_opv: bool,
|
||||||
requires_comptime: PropertyBoolean = .unknown,
|
requires_comptime: PropertyBoolean = .unknown,
|
||||||
have_field_inits: bool = false,
|
have_field_inits: bool = false,
|
||||||
|
assumed_runtime_bits: bool = false,
|
||||||
|
|
||||||
pub const Fields = std.StringArrayHashMapUnmanaged(Field);
|
pub const Fields = std.StringArrayHashMapUnmanaged(Field);
|
||||||
|
|
||||||
@ -1203,6 +1204,7 @@ pub const Union = struct {
|
|||||||
fully_resolved,
|
fully_resolved,
|
||||||
},
|
},
|
||||||
requires_comptime: PropertyBoolean = .unknown,
|
requires_comptime: PropertyBoolean = .unknown,
|
||||||
|
assumed_runtime_bits: bool = false,
|
||||||
|
|
||||||
pub const Field = struct {
|
pub const Field = struct {
|
||||||
/// undefined until `status` is `have_field_types` or `have_layout`.
|
/// undefined until `status` is `have_field_types` or `have_layout`.
|
||||||
|
|||||||
133
src/Sema.zig
133
src/Sema.zig
@ -195,8 +195,8 @@ pub const Block = struct {
|
|||||||
try sema.errNote(ci.block, ci.src, parent, prefix ++ "it is inside a @cImport", .{});
|
try sema.errNote(ci.block, ci.src, parent, prefix ++ "it is inside a @cImport", .{});
|
||||||
},
|
},
|
||||||
.comptime_ret_ty => |rt| {
|
.comptime_ret_ty => |rt| {
|
||||||
const src_loc = if (try sema.funcDeclSrc(rt.func)) |capture| blk: {
|
const src_loc = if (try sema.funcDeclSrc(rt.func)) |fn_decl| blk: {
|
||||||
var src_loc = capture;
|
var src_loc = fn_decl.srcLoc();
|
||||||
src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 };
|
src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 };
|
||||||
break :blk src_loc;
|
break :blk src_loc;
|
||||||
} else blk: {
|
} else blk: {
|
||||||
@ -1000,7 +1000,7 @@ fn analyzeBodyInner(
|
|||||||
// These functions match the return type of analyzeBody so that we can
|
// These functions match the return type of analyzeBody so that we can
|
||||||
// tail call them here.
|
// tail call them here.
|
||||||
.compile_error => break sema.zirCompileError(block, inst),
|
.compile_error => break sema.zirCompileError(block, inst),
|
||||||
.ret_tok => break sema.zirRetTok(block, inst),
|
.ret_implicit => break sema.zirRetImplicit(block, inst),
|
||||||
.ret_node => break sema.zirRetNode(block, inst),
|
.ret_node => break sema.zirRetNode(block, inst),
|
||||||
.ret_load => break sema.zirRetLoad(block, inst),
|
.ret_load => break sema.zirRetLoad(block, inst),
|
||||||
.ret_err_value => break sema.zirRetErrValue(block, inst),
|
.ret_err_value => break sema.zirRetErrValue(block, inst),
|
||||||
@ -5745,7 +5745,7 @@ fn lookupInNamespace(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?Module.SrcLoc {
|
fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl {
|
||||||
const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null;
|
const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null;
|
||||||
if (func_val.isUndef()) return null;
|
if (func_val.isUndef()) return null;
|
||||||
const owner_decl_index = switch (func_val.tag()) {
|
const owner_decl_index = switch (func_val.tag()) {
|
||||||
@ -5754,8 +5754,7 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?Module.SrcLoc {
|
|||||||
.decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl,
|
.decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl,
|
||||||
else => return null,
|
else => return null,
|
||||||
};
|
};
|
||||||
const owner_decl = sema.mod.declPtr(owner_decl_index);
|
return sema.mod.declPtr(owner_decl_index);
|
||||||
return owner_decl.srcLoc();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref {
|
pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref {
|
||||||
@ -5933,7 +5932,7 @@ fn zirCall(
|
|||||||
break :check_args;
|
break :check_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
const decl_src = try sema.funcDeclSrc(func);
|
const maybe_decl = try sema.funcDeclSrc(func);
|
||||||
const member_str = if (bound_arg_src != null) "member function " else "";
|
const member_str = if (bound_arg_src != null) "member function " else "";
|
||||||
const variadic_str = if (func_ty_info.is_var_args) "at least " else "";
|
const variadic_str = if (func_ty_info.is_var_args) "at least " else "";
|
||||||
const msg = msg: {
|
const msg = msg: {
|
||||||
@ -5950,7 +5949,7 @@ fn zirCall(
|
|||||||
);
|
);
|
||||||
errdefer msg.destroy(sema.gpa);
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
|
||||||
if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{});
|
if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(), msg, "function declared here", .{});
|
||||||
break :msg msg;
|
break :msg msg;
|
||||||
};
|
};
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
@ -6144,7 +6143,7 @@ fn analyzeCall(
|
|||||||
const func_ty_info = func_ty.fnInfo();
|
const func_ty_info = func_ty.fnInfo();
|
||||||
const cc = func_ty_info.cc;
|
const cc = func_ty_info.cc;
|
||||||
if (cc == .Naked) {
|
if (cc == .Naked) {
|
||||||
const decl_src = try sema.funcDeclSrc(func);
|
const maybe_decl = try sema.funcDeclSrc(func);
|
||||||
const msg = msg: {
|
const msg = msg: {
|
||||||
const msg = try sema.errMsg(
|
const msg = try sema.errMsg(
|
||||||
block,
|
block,
|
||||||
@ -6154,7 +6153,7 @@ fn analyzeCall(
|
|||||||
);
|
);
|
||||||
errdefer msg.destroy(sema.gpa);
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
|
||||||
if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{});
|
if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(), msg, "function declared here", .{});
|
||||||
break :msg msg;
|
break :msg msg;
|
||||||
};
|
};
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
@ -6388,6 +6387,7 @@ fn analyzeCall(
|
|||||||
&should_memoize,
|
&should_memoize,
|
||||||
memoized_call_key,
|
memoized_call_key,
|
||||||
func_ty_info.param_types,
|
func_ty_info.param_types,
|
||||||
|
func,
|
||||||
) catch |err| switch (err) {
|
) catch |err| switch (err) {
|
||||||
error.NeededSourceLocation => {
|
error.NeededSourceLocation => {
|
||||||
_ = sema.inst_map.remove(inst);
|
_ = sema.inst_map.remove(inst);
|
||||||
@ -6404,6 +6404,7 @@ fn analyzeCall(
|
|||||||
&should_memoize,
|
&should_memoize,
|
||||||
memoized_call_key,
|
memoized_call_key,
|
||||||
func_ty_info.param_types,
|
func_ty_info.param_types,
|
||||||
|
func,
|
||||||
);
|
);
|
||||||
return error.AnalysisFail;
|
return error.AnalysisFail;
|
||||||
},
|
},
|
||||||
@ -6546,12 +6547,17 @@ fn analyzeCall(
|
|||||||
const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
|
const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
|
||||||
for (uncasted_args) |uncasted_arg, i| {
|
for (uncasted_args) |uncasted_arg, i| {
|
||||||
if (i < fn_params_len) {
|
if (i < fn_params_len) {
|
||||||
|
const opts: CoerceOpts = .{ .param_src = .{
|
||||||
|
.func_inst = func,
|
||||||
|
.param_i = @intCast(u32, i),
|
||||||
|
} };
|
||||||
const param_ty = func_ty.fnParamType(i);
|
const param_ty = func_ty.fnParamType(i);
|
||||||
args[i] = sema.analyzeCallArg(
|
args[i] = sema.analyzeCallArg(
|
||||||
block,
|
block,
|
||||||
.unneeded,
|
.unneeded,
|
||||||
param_ty,
|
param_ty,
|
||||||
uncasted_arg,
|
uncasted_arg,
|
||||||
|
opts,
|
||||||
) catch |err| switch (err) {
|
) catch |err| switch (err) {
|
||||||
error.NeededSourceLocation => {
|
error.NeededSourceLocation => {
|
||||||
const decl = sema.mod.declPtr(block.src_decl);
|
const decl = sema.mod.declPtr(block.src_decl);
|
||||||
@ -6560,6 +6566,7 @@ fn analyzeCall(
|
|||||||
Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src),
|
Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src),
|
||||||
param_ty,
|
param_ty,
|
||||||
uncasted_arg,
|
uncasted_arg,
|
||||||
|
opts,
|
||||||
);
|
);
|
||||||
return error.AnalysisFail;
|
return error.AnalysisFail;
|
||||||
},
|
},
|
||||||
@ -6641,6 +6648,7 @@ fn analyzeInlineCallArg(
|
|||||||
should_memoize: *bool,
|
should_memoize: *bool,
|
||||||
memoized_call_key: Module.MemoizedCall.Key,
|
memoized_call_key: Module.MemoizedCall.Key,
|
||||||
raw_param_types: []const Type,
|
raw_param_types: []const Type,
|
||||||
|
func_inst: Air.Inst.Ref,
|
||||||
) !void {
|
) !void {
|
||||||
const zir_tags = sema.code.instructions.items(.tag);
|
const zir_tags = sema.code.instructions.items(.tag);
|
||||||
switch (zir_tags[inst]) {
|
switch (zir_tags[inst]) {
|
||||||
@ -6665,7 +6673,13 @@ fn analyzeInlineCallArg(
|
|||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);
|
const casted_arg = sema.coerceExtra(arg_block, param_ty, uncasted_arg, arg_src, .{ .param_src = .{
|
||||||
|
.func_inst = func_inst,
|
||||||
|
.param_i = @intCast(u32, arg_i.*),
|
||||||
|
} }) catch |err| switch (err) {
|
||||||
|
error.NotCoercible => unreachable,
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
|
|
||||||
if (is_comptime_call) {
|
if (is_comptime_call) {
|
||||||
try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
|
try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
|
||||||
@ -6755,9 +6769,13 @@ fn analyzeCallArg(
|
|||||||
arg_src: LazySrcLoc,
|
arg_src: LazySrcLoc,
|
||||||
param_ty: Type,
|
param_ty: Type,
|
||||||
uncasted_arg: Air.Inst.Ref,
|
uncasted_arg: Air.Inst.Ref,
|
||||||
|
opts: CoerceOpts,
|
||||||
) !Air.Inst.Ref {
|
) !Air.Inst.Ref {
|
||||||
try sema.resolveTypeFully(param_ty);
|
try sema.resolveTypeFully(param_ty);
|
||||||
return sema.coerce(block, param_ty, uncasted_arg, arg_src);
|
return sema.coerceExtra(block, param_ty, uncasted_arg, arg_src, opts) catch |err| switch (err) {
|
||||||
|
error.NotCoercible => unreachable,
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyzeGenericCallArg(
|
fn analyzeGenericCallArg(
|
||||||
@ -16398,7 +16416,7 @@ fn zirRetErrValue(
|
|||||||
return sema.analyzeRet(block, result_inst, src);
|
return sema.analyzeRet(block, result_inst, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirRetTok(
|
fn zirRetImplicit(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
block: *Block,
|
block: *Block,
|
||||||
inst: Zir.Inst.Index,
|
inst: Zir.Inst.Index,
|
||||||
@ -16408,9 +16426,33 @@ fn zirRetTok(
|
|||||||
|
|
||||||
const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
|
const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
|
||||||
const operand = try sema.resolveInst(inst_data.operand);
|
const operand = try sema.resolveInst(inst_data.operand);
|
||||||
const src = inst_data.src();
|
|
||||||
|
|
||||||
return sema.analyzeRet(block, operand, src);
|
const r_brace_src = inst_data.src();
|
||||||
|
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
|
||||||
|
const base_tag = sema.fn_ret_ty.baseZigTypeTag();
|
||||||
|
if (base_tag == .NoReturn) {
|
||||||
|
const msg = msg: {
|
||||||
|
const msg = try sema.errMsg(block, ret_ty_src, "function declared '{}' implicitly returns", .{
|
||||||
|
sema.fn_ret_ty.fmt(sema.mod),
|
||||||
|
});
|
||||||
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{});
|
||||||
|
break :msg msg;
|
||||||
|
};
|
||||||
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
|
} else if (base_tag != .Void) {
|
||||||
|
const msg = msg: {
|
||||||
|
const msg = try sema.errMsg(block, ret_ty_src, "function with non-void return type '{}' implicitly returns", .{
|
||||||
|
sema.fn_ret_ty.fmt(sema.mod),
|
||||||
|
});
|
||||||
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{});
|
||||||
|
break :msg msg;
|
||||||
|
};
|
||||||
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sema.analyzeRet(block, operand, .unneeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
|
fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
|
||||||
@ -16677,7 +16719,7 @@ 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 bitoffset_src: LazySrcLoc = .{ .node_offset_ptr_bitoffset = extra.data.src_node };
|
||||||
const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node };
|
const hostsize_src: LazySrcLoc = .{ .node_offset_ptr_hostsize = extra.data.src_node };
|
||||||
|
|
||||||
const unresolved_elem_ty = blk: {
|
const elem_ty = blk: {
|
||||||
const air_inst = try sema.resolveInst(extra.data.elem_type);
|
const air_inst = try sema.resolveInst(extra.data.elem_type);
|
||||||
const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| {
|
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()) {
|
if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer()) {
|
||||||
@ -16706,7 +16748,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
|||||||
// Check if this happens to be the lazy alignment of our element type, in
|
// Check if this happens to be the lazy alignment of our element type, in
|
||||||
// which case we can make this 0 without resolving it.
|
// which case we can make this 0 without resolving it.
|
||||||
if (val.castTag(.lazy_align)) |payload| {
|
if (val.castTag(.lazy_align)) |payload| {
|
||||||
if (payload.data.eql(unresolved_elem_ty, sema.mod)) {
|
if (payload.data.eql(elem_ty, sema.mod)) {
|
||||||
break :blk 0;
|
break :blk 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16739,14 +16781,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
|||||||
return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{});
|
return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
const elem_ty = if (abi_align == 0)
|
|
||||||
unresolved_elem_ty
|
|
||||||
else t: {
|
|
||||||
const elem_ty = try sema.resolveTypeFields(unresolved_elem_ty);
|
|
||||||
try sema.resolveTypeLayout(elem_ty);
|
|
||||||
break :t elem_ty;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (elem_ty.zigTypeTag() == .NoReturn) {
|
if (elem_ty.zigTypeTag() == .NoReturn) {
|
||||||
return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{});
|
return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{});
|
||||||
} else if (elem_ty.zigTypeTag() == .Fn) {
|
} else if (elem_ty.zigTypeTag() == .Fn) {
|
||||||
@ -20173,7 +20207,7 @@ fn analyzeShuffle(
|
|||||||
var buf: Value.ElemValueBuffer = undefined;
|
var buf: Value.ElemValueBuffer = undefined;
|
||||||
const elem = mask.elemValueBuffer(sema.mod, i, &buf);
|
const elem = mask.elemValueBuffer(sema.mod, i, &buf);
|
||||||
if (elem.isUndef()) continue;
|
if (elem.isUndef()) continue;
|
||||||
const int = elem.toSignedInt();
|
const int = elem.toSignedInt(sema.mod.getTarget());
|
||||||
var unsigned: u32 = undefined;
|
var unsigned: u32 = undefined;
|
||||||
var chosen: u32 = undefined;
|
var chosen: u32 = undefined;
|
||||||
if (int >= 0) {
|
if (int >= 0) {
|
||||||
@ -20215,7 +20249,7 @@ fn analyzeShuffle(
|
|||||||
values[i] = Value.undef;
|
values[i] = Value.undef;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const int = mask_elem_val.toSignedInt();
|
const int = mask_elem_val.toSignedInt(sema.mod.getTarget());
|
||||||
const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int);
|
const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int);
|
||||||
if (int >= 0) {
|
if (int >= 0) {
|
||||||
values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned);
|
values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned);
|
||||||
@ -23957,6 +23991,25 @@ const CoerceOpts = struct {
|
|||||||
is_ret: bool = false,
|
is_ret: bool = false,
|
||||||
/// Should coercion to comptime_int ermit an error message.
|
/// Should coercion to comptime_int ermit an error message.
|
||||||
no_cast_to_comptime_int: bool = false,
|
no_cast_to_comptime_int: bool = false,
|
||||||
|
|
||||||
|
param_src: struct {
|
||||||
|
func_inst: Air.Inst.Ref = .none,
|
||||||
|
param_i: u32 = undefined,
|
||||||
|
|
||||||
|
fn get(info: @This(), sema: *Sema) !?Module.SrcLoc {
|
||||||
|
if (info.func_inst == .none) return null;
|
||||||
|
const fn_decl = (try sema.funcDeclSrc(info.func_inst)) orelse return null;
|
||||||
|
const param_src = Module.paramSrc(0, sema.gpa, fn_decl, info.param_i);
|
||||||
|
if (param_src == .node_offset_param) {
|
||||||
|
return Module.SrcLoc{
|
||||||
|
.file_scope = fn_decl.getFileScope(),
|
||||||
|
.parent_decl_node = fn_decl.src_node,
|
||||||
|
.lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return param_src.toSrcLoc(fn_decl);
|
||||||
|
}
|
||||||
|
} = .{},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn coerceExtra(
|
fn coerceExtra(
|
||||||
@ -24610,6 +24663,10 @@ fn coerceExtra(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (try opts.param_src.get(sema)) |param_src| {
|
||||||
|
try sema.mod.errNoteNonLazy(param_src, msg, "parameter type declared here", .{});
|
||||||
|
}
|
||||||
|
|
||||||
// TODO maybe add "cannot store an error in type '{}'" note
|
// TODO maybe add "cannot store an error in type '{}'" note
|
||||||
|
|
||||||
break :msg msg;
|
break :msg msg;
|
||||||
@ -28212,6 +28269,7 @@ fn cmpNumeric(
|
|||||||
|
|
||||||
var lhs_bits: usize = undefined;
|
var lhs_bits: usize = undefined;
|
||||||
if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| {
|
if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| {
|
||||||
|
try sema.resolveLazyValue(lhs_val);
|
||||||
if (lhs_val.isUndef())
|
if (lhs_val.isUndef())
|
||||||
return sema.addConstUndef(Type.bool);
|
return sema.addConstUndef(Type.bool);
|
||||||
if (lhs_val.isNan()) switch (op) {
|
if (lhs_val.isNan()) switch (op) {
|
||||||
@ -28265,6 +28323,7 @@ fn cmpNumeric(
|
|||||||
|
|
||||||
var rhs_bits: usize = undefined;
|
var rhs_bits: usize = undefined;
|
||||||
if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| {
|
if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| {
|
||||||
|
try sema.resolveLazyValue(rhs_val);
|
||||||
if (rhs_val.isUndef())
|
if (rhs_val.isUndef())
|
||||||
return sema.addConstUndef(Type.bool);
|
return sema.addConstUndef(Type.bool);
|
||||||
if (rhs_val.isNan()) switch (op) {
|
if (rhs_val.isNan()) switch (op) {
|
||||||
@ -29132,6 +29191,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
|
|||||||
|
|
||||||
struct_obj.status = .have_layout;
|
struct_obj.status = .have_layout;
|
||||||
_ = try sema.resolveTypeRequiresComptime(resolved_ty);
|
_ = try sema.resolveTypeRequiresComptime(resolved_ty);
|
||||||
|
|
||||||
|
if (struct_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) {
|
||||||
|
const msg = try Module.ErrorMsg.create(
|
||||||
|
sema.gpa,
|
||||||
|
struct_obj.srcLoc(sema.mod),
|
||||||
|
"struct layout depends on it having runtime bits",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// otherwise it's a tuple; no need to resolve anything
|
// otherwise it's a tuple; no need to resolve anything
|
||||||
}
|
}
|
||||||
@ -29296,6 +29365,16 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
|
|||||||
}
|
}
|
||||||
union_obj.status = .have_layout;
|
union_obj.status = .have_layout;
|
||||||
_ = try sema.resolveTypeRequiresComptime(resolved_ty);
|
_ = try sema.resolveTypeRequiresComptime(resolved_ty);
|
||||||
|
|
||||||
|
if (union_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) {
|
||||||
|
const msg = try Module.ErrorMsg.create(
|
||||||
|
sema.gpa,
|
||||||
|
union_obj.srcLoc(sema.mod),
|
||||||
|
"union layout depends on it having runtime bits",
|
||||||
|
.{},
|
||||||
|
);
|
||||||
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case of querying the ABI alignment of this struct, we will ask
|
// In case of querying the ABI alignment of this struct, we will ask
|
||||||
|
|||||||
@ -519,7 +519,7 @@ pub const Inst = struct {
|
|||||||
/// Includes an operand as the return value.
|
/// Includes an operand as the return value.
|
||||||
/// Includes a token source location.
|
/// Includes a token source location.
|
||||||
/// Uses the `un_tok` union field.
|
/// Uses the `un_tok` union field.
|
||||||
ret_tok,
|
ret_implicit,
|
||||||
/// Sends control flow back to the function's callee.
|
/// Sends control flow back to the function's callee.
|
||||||
/// The return operand is `error.foo` where `foo` is given by the string.
|
/// The return operand is `error.foo` where `foo` is given by the string.
|
||||||
/// If the current function has an inferred error set, the error given by the
|
/// If the current function has an inferred error set, the error given by the
|
||||||
@ -1256,7 +1256,7 @@ pub const Inst = struct {
|
|||||||
.compile_error,
|
.compile_error,
|
||||||
.ret_node,
|
.ret_node,
|
||||||
.ret_load,
|
.ret_load,
|
||||||
.ret_tok,
|
.ret_implicit,
|
||||||
.ret_err_value,
|
.ret_err_value,
|
||||||
.@"unreachable",
|
.@"unreachable",
|
||||||
.repeat,
|
.repeat,
|
||||||
@ -1530,7 +1530,7 @@ pub const Inst = struct {
|
|||||||
.compile_error,
|
.compile_error,
|
||||||
.ret_node,
|
.ret_node,
|
||||||
.ret_load,
|
.ret_load,
|
||||||
.ret_tok,
|
.ret_implicit,
|
||||||
.ret_err_value,
|
.ret_err_value,
|
||||||
.ret_ptr,
|
.ret_ptr,
|
||||||
.ret_type,
|
.ret_type,
|
||||||
@ -1659,7 +1659,7 @@ pub const Inst = struct {
|
|||||||
.ref = .un_tok,
|
.ref = .un_tok,
|
||||||
.ret_node = .un_node,
|
.ret_node = .un_node,
|
||||||
.ret_load = .un_node,
|
.ret_load = .un_node,
|
||||||
.ret_tok = .un_tok,
|
.ret_implicit = .un_tok,
|
||||||
.ret_err_value = .str_tok,
|
.ret_err_value = .str_tok,
|
||||||
.ret_err_value_code = .str_tok,
|
.ret_err_value_code = .str_tok,
|
||||||
.ret_ptr = .node,
|
.ret_ptr = .node,
|
||||||
|
|||||||
@ -6083,7 +6083,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
|
|||||||
if (info.bits <= 64) {
|
if (info.bits <= 64) {
|
||||||
const unsigned = switch (info.signedness) {
|
const unsigned = switch (info.signedness) {
|
||||||
.signed => blk: {
|
.signed => blk: {
|
||||||
const signed = typed_value.val.toSignedInt();
|
const signed = typed_value.val.toSignedInt(target);
|
||||||
break :blk @bitCast(u64, signed);
|
break :blk @bitCast(u64, signed);
|
||||||
},
|
},
|
||||||
.unsigned => typed_value.val.toUnsignedInt(target),
|
.unsigned => typed_value.val.toUnsignedInt(target),
|
||||||
|
|||||||
@ -6121,7 +6121,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
|
|||||||
if (info.bits <= ptr_bits) {
|
if (info.bits <= ptr_bits) {
|
||||||
const unsigned = switch (info.signedness) {
|
const unsigned = switch (info.signedness) {
|
||||||
.signed => blk: {
|
.signed => blk: {
|
||||||
const signed = @intCast(i32, typed_value.val.toSignedInt());
|
const signed = @intCast(i32, typed_value.val.toSignedInt(target));
|
||||||
break :blk @bitCast(u32, signed);
|
break :blk @bitCast(u32, signed);
|
||||||
},
|
},
|
||||||
.unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)),
|
.unsigned => @intCast(u32, typed_value.val.toUnsignedInt(target)),
|
||||||
|
|||||||
@ -3786,7 +3786,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
|
|||||||
if (info.bits <= 64) {
|
if (info.bits <= 64) {
|
||||||
const unsigned = switch (info.signedness) {
|
const unsigned = switch (info.signedness) {
|
||||||
.signed => blk: {
|
.signed => blk: {
|
||||||
const signed = typed_value.val.toSignedInt();
|
const signed = typed_value.val.toSignedInt(target);
|
||||||
break :blk @bitCast(u64, signed);
|
break :blk @bitCast(u64, signed);
|
||||||
},
|
},
|
||||||
.unsigned => typed_value.val.toUnsignedInt(target),
|
.unsigned => typed_value.val.toUnsignedInt(target),
|
||||||
|
|||||||
@ -2604,11 +2604,11 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
|
|||||||
switch (int_info.signedness) {
|
switch (int_info.signedness) {
|
||||||
.signed => switch (int_info.bits) {
|
.signed => switch (int_info.bits) {
|
||||||
0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement(
|
0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement(
|
||||||
val.toSignedInt(),
|
val.toSignedInt(target),
|
||||||
@intCast(u6, int_info.bits),
|
@intCast(u6, int_info.bits),
|
||||||
)) },
|
)) },
|
||||||
33...64 => return WValue{ .imm64 = toTwosComplement(
|
33...64 => return WValue{ .imm64 = toTwosComplement(
|
||||||
val.toSignedInt(),
|
val.toSignedInt(target),
|
||||||
@intCast(u7, int_info.bits),
|
@intCast(u7, int_info.bits),
|
||||||
) },
|
) },
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
@ -2758,15 +2758,15 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Int => switch (ty.intInfo(func.target).signedness) {
|
.Int => switch (ty.intInfo(func.target).signedness) {
|
||||||
.signed => return @truncate(i32, val.toSignedInt()),
|
.signed => return @truncate(i32, val.toSignedInt(target)),
|
||||||
.unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(target))),
|
.unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(target))),
|
||||||
},
|
},
|
||||||
.ErrorSet => {
|
.ErrorSet => {
|
||||||
const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function
|
const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function
|
||||||
return @bitCast(i32, kv.value);
|
return @bitCast(i32, kv.value);
|
||||||
},
|
},
|
||||||
.Bool => return @intCast(i32, val.toSignedInt()),
|
.Bool => return @intCast(i32, val.toSignedInt(target)),
|
||||||
.Pointer => return @intCast(i32, val.toSignedInt()),
|
.Pointer => return @intCast(i32, val.toSignedInt(target)),
|
||||||
else => unreachable, // Programmer called this function for an illegal type
|
else => unreachable, // Programmer called this function for an illegal type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7007,7 +7007,7 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
|
|||||||
.Int => {
|
.Int => {
|
||||||
const info = typed_value.ty.intInfo(self.target.*);
|
const info = typed_value.ty.intInfo(self.target.*);
|
||||||
if (info.bits <= ptr_bits and info.signedness == .signed) {
|
if (info.bits <= ptr_bits and info.signedness == .signed) {
|
||||||
return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) };
|
return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) };
|
||||||
}
|
}
|
||||||
if (!(info.bits > ptr_bits or info.signedness == .signed)) {
|
if (!(info.bits > ptr_bits or info.signedness == .signed)) {
|
||||||
return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) };
|
return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) };
|
||||||
|
|||||||
@ -459,7 +459,7 @@ pub fn generateSymbol(
|
|||||||
if (info.bits <= 8) {
|
if (info.bits <= 8) {
|
||||||
const x: u8 = switch (info.signedness) {
|
const x: u8 = switch (info.signedness) {
|
||||||
.unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)),
|
.unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)),
|
||||||
.signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt())),
|
.signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt(target))),
|
||||||
};
|
};
|
||||||
try code.append(x);
|
try code.append(x);
|
||||||
return Result{ .appended = {} };
|
return Result{ .appended = {} };
|
||||||
@ -488,13 +488,13 @@ pub fn generateSymbol(
|
|||||||
},
|
},
|
||||||
.signed => {
|
.signed => {
|
||||||
if (info.bits <= 16) {
|
if (info.bits <= 16) {
|
||||||
const x = @intCast(i16, typed_value.val.toSignedInt());
|
const x = @intCast(i16, typed_value.val.toSignedInt(target));
|
||||||
mem.writeInt(i16, try code.addManyAsArray(2), x, endian);
|
mem.writeInt(i16, try code.addManyAsArray(2), x, endian);
|
||||||
} else if (info.bits <= 32) {
|
} else if (info.bits <= 32) {
|
||||||
const x = @intCast(i32, typed_value.val.toSignedInt());
|
const x = @intCast(i32, typed_value.val.toSignedInt(target));
|
||||||
mem.writeInt(i32, try code.addManyAsArray(4), x, endian);
|
mem.writeInt(i32, try code.addManyAsArray(4), x, endian);
|
||||||
} else {
|
} else {
|
||||||
const x = typed_value.val.toSignedInt();
|
const x = typed_value.val.toSignedInt(target);
|
||||||
mem.writeInt(i64, try code.addManyAsArray(8), x, endian);
|
mem.writeInt(i64, try code.addManyAsArray(8), x, endian);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -536,13 +536,13 @@ pub fn generateSymbol(
|
|||||||
},
|
},
|
||||||
.signed => {
|
.signed => {
|
||||||
if (info.bits <= 16) {
|
if (info.bits <= 16) {
|
||||||
const x = @intCast(i16, int_val.toSignedInt());
|
const x = @intCast(i16, int_val.toSignedInt(target));
|
||||||
mem.writeInt(i16, try code.addManyAsArray(2), x, endian);
|
mem.writeInt(i16, try code.addManyAsArray(2), x, endian);
|
||||||
} else if (info.bits <= 32) {
|
} else if (info.bits <= 32) {
|
||||||
const x = @intCast(i32, int_val.toSignedInt());
|
const x = @intCast(i32, int_val.toSignedInt(target));
|
||||||
mem.writeInt(i32, try code.addManyAsArray(4), x, endian);
|
mem.writeInt(i32, try code.addManyAsArray(4), x, endian);
|
||||||
} else {
|
} else {
|
||||||
const x = int_val.toSignedInt();
|
const x = int_val.toSignedInt(target);
|
||||||
mem.writeInt(i64, try code.addManyAsArray(8), x, endian);
|
mem.writeInt(i64, try code.addManyAsArray(8), x, endian);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -8934,7 +8934,7 @@ pub const FuncGen = struct {
|
|||||||
if (elem.isUndef()) {
|
if (elem.isUndef()) {
|
||||||
val.* = llvm_i32.getUndef();
|
val.* = llvm_i32.getUndef();
|
||||||
} else {
|
} else {
|
||||||
const int = elem.toSignedInt();
|
const int = elem.toSignedInt(self.dg.module.getTarget());
|
||||||
const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len);
|
const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len);
|
||||||
val.* = llvm_i32.constInt(unsigned, .False);
|
val.* = llvm_i32.constInt(unsigned, .False);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -345,7 +345,7 @@ pub const DeclGen = struct {
|
|||||||
|
|
||||||
// Note, value is required to be sign-extended, so we don't need to mask off the upper bits.
|
// Note, value is required to be sign-extended, so we don't need to mask off the upper bits.
|
||||||
// See https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Literal
|
// See https://www.khronos.org/registry/SPIR-V/specs/unified1/SPIRV.html#Literal
|
||||||
var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt()) else val.toUnsignedInt(target);
|
var int_bits = if (ty.isSignedInt()) @bitCast(u64, val.toSignedInt(target)) else val.toUnsignedInt(target);
|
||||||
|
|
||||||
const value: spec.LiteralContextDependentNumber = switch (backing_bits) {
|
const value: spec.LiteralContextDependentNumber = switch (backing_bits) {
|
||||||
1...32 => .{ .uint32 = @truncate(u32, int_bits) },
|
1...32 => .{ .uint32 = @truncate(u32, int_bits) },
|
||||||
|
|||||||
@ -409,7 +409,7 @@ pub const DeclState = struct {
|
|||||||
// See https://github.com/ziglang/zig/issues/645
|
// See https://github.com/ziglang/zig/issues/645
|
||||||
var int_buffer: Value.Payload.U64 = undefined;
|
var int_buffer: Value.Payload.U64 = undefined;
|
||||||
const field_int_val = value.enumToInt(ty, &int_buffer);
|
const field_int_val = value.enumToInt(ty, &int_buffer);
|
||||||
break :value @bitCast(u64, field_int_val.toSignedInt());
|
break :value @bitCast(u64, field_int_val.toSignedInt(target));
|
||||||
} else @intCast(u64, field_i);
|
} else @intCast(u64, field_i);
|
||||||
mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian);
|
mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -235,7 +235,7 @@ const Writer = struct {
|
|||||||
=> try self.writeUnNode(stream, inst),
|
=> try self.writeUnNode(stream, inst),
|
||||||
|
|
||||||
.ref,
|
.ref,
|
||||||
.ret_tok,
|
.ret_implicit,
|
||||||
.closure_capture,
|
.closure_capture,
|
||||||
.switch_capture_tag,
|
.switch_capture_tag,
|
||||||
=> try self.writeUnTok(stream, inst),
|
=> try self.writeUnTok(stream, inst),
|
||||||
|
|||||||
54
src/type.zig
54
src/type.zig
@ -160,6 +160,17 @@ pub const Type = extern union {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn baseZigTypeTag(self: Type) std.builtin.TypeId {
|
||||||
|
return switch (self.zigTypeTag()) {
|
||||||
|
.ErrorUnion => self.errorUnionPayload().baseZigTypeTag(),
|
||||||
|
.Optional => {
|
||||||
|
var buf: Payload.ElemType = undefined;
|
||||||
|
return self.optionalChild(&buf).baseZigTypeTag();
|
||||||
|
},
|
||||||
|
else => |t| t,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn isSelfComparable(ty: Type, is_equality_cmp: bool) bool {
|
pub fn isSelfComparable(ty: Type, is_equality_cmp: bool) bool {
|
||||||
return switch (ty.zigTypeTag()) {
|
return switch (ty.zigTypeTag()) {
|
||||||
.Int,
|
.Int,
|
||||||
@ -2459,6 +2470,7 @@ pub const Type = extern union {
|
|||||||
if (struct_obj.status == .field_types_wip) {
|
if (struct_obj.status == .field_types_wip) {
|
||||||
// In this case, we guess that hasRuntimeBits() for this type is true,
|
// In this case, we guess that hasRuntimeBits() for this type is true,
|
||||||
// and then later if our guess was incorrect, we emit a compile error.
|
// and then later if our guess was incorrect, we emit a compile error.
|
||||||
|
struct_obj.assumed_runtime_bits = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
switch (strat) {
|
switch (strat) {
|
||||||
@ -2491,6 +2503,12 @@ pub const Type = extern union {
|
|||||||
|
|
||||||
.@"union" => {
|
.@"union" => {
|
||||||
const union_obj = ty.castTag(.@"union").?.data;
|
const union_obj = ty.castTag(.@"union").?.data;
|
||||||
|
if (union_obj.status == .field_types_wip) {
|
||||||
|
// In this case, we guess that hasRuntimeBits() for this type is true,
|
||||||
|
// and then later if our guess was incorrect, we emit a compile error.
|
||||||
|
union_obj.assumed_runtime_bits = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
switch (strat) {
|
switch (strat) {
|
||||||
.sema => |sema| _ = try sema.resolveTypeFields(ty),
|
.sema => |sema| _ = try sema.resolveTypeFields(ty),
|
||||||
.eager => assert(union_obj.haveFieldTypes()),
|
.eager => assert(union_obj.haveFieldTypes()),
|
||||||
@ -3027,8 +3045,9 @@ pub const Type = extern union {
|
|||||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||||
if (opt_sema) |sema| {
|
if (opt_sema) |sema| {
|
||||||
if (struct_obj.status == .field_types_wip) {
|
if (struct_obj.status == .field_types_wip) {
|
||||||
// We'll guess "pointer-aligned" and if we guess wrong, emit
|
// We'll guess "pointer-aligned", if the struct has an
|
||||||
// a compile error later.
|
// underaligned pointer field then some allocations
|
||||||
|
// might require explicit alignment.
|
||||||
return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
|
return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
|
||||||
}
|
}
|
||||||
_ = try sema.resolveTypeFields(ty);
|
_ = try sema.resolveTypeFields(ty);
|
||||||
@ -3153,8 +3172,9 @@ pub const Type = extern union {
|
|||||||
};
|
};
|
||||||
if (opt_sema) |sema| {
|
if (opt_sema) |sema| {
|
||||||
if (union_obj.status == .field_types_wip) {
|
if (union_obj.status == .field_types_wip) {
|
||||||
// We'll guess "pointer-aligned" and if we guess wrong, emit
|
// We'll guess "pointer-aligned", if the union has an
|
||||||
// a compile error later.
|
// underaligned pointer field then some allocations
|
||||||
|
// might require explicit alignment.
|
||||||
return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
|
return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };
|
||||||
}
|
}
|
||||||
_ = try sema.resolveTypeFields(ty);
|
_ = try sema.resolveTypeFields(ty);
|
||||||
@ -5233,7 +5253,12 @@ pub const Type = extern union {
|
|||||||
.@"struct" => {
|
.@"struct" => {
|
||||||
const struct_obj = ty.castTag(.@"struct").?.data;
|
const struct_obj = ty.castTag(.@"struct").?.data;
|
||||||
switch (struct_obj.requires_comptime) {
|
switch (struct_obj.requires_comptime) {
|
||||||
.wip, .unknown => unreachable, // This function asserts types already resolved.
|
.wip, .unknown => {
|
||||||
|
// Return false to avoid incorrect dependency loops.
|
||||||
|
// This will be handled correctly once merged with
|
||||||
|
// `Sema.typeRequiresComptime`.
|
||||||
|
return false;
|
||||||
|
},
|
||||||
.no => return false,
|
.no => return false,
|
||||||
.yes => return true,
|
.yes => return true,
|
||||||
}
|
}
|
||||||
@ -5242,7 +5267,12 @@ pub const Type = extern union {
|
|||||||
.@"union", .union_safety_tagged, .union_tagged => {
|
.@"union", .union_safety_tagged, .union_tagged => {
|
||||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
||||||
switch (union_obj.requires_comptime) {
|
switch (union_obj.requires_comptime) {
|
||||||
.wip, .unknown => unreachable, // This function asserts types already resolved.
|
.wip, .unknown => {
|
||||||
|
// Return false to avoid incorrect dependency loops.
|
||||||
|
// This will be handled correctly once merged with
|
||||||
|
// `Sema.typeRequiresComptime`.
|
||||||
|
return false;
|
||||||
|
},
|
||||||
.no => return false,
|
.no => return false,
|
||||||
.yes => return true,
|
.yes => return true,
|
||||||
}
|
}
|
||||||
@ -6454,8 +6484,16 @@ pub const Type = extern union {
|
|||||||
// type, we change it to 0 here. If this causes an assertion trip because the
|
// type, we change it to 0 here. If this causes an assertion trip because the
|
||||||
// pointee type needs to be resolved more, that needs to be done before calling
|
// pointee type needs to be resolved more, that needs to be done before calling
|
||||||
// this ptr() function.
|
// this ptr() function.
|
||||||
if (d.@"align" != 0 and d.@"align" == d.pointee_type.abiAlignment(target)) {
|
if (d.@"align" != 0) canonicalize: {
|
||||||
d.@"align" = 0;
|
if (d.pointee_type.castTag(.@"struct")) |struct_ty| {
|
||||||
|
if (!struct_ty.data.haveLayout()) break :canonicalize;
|
||||||
|
}
|
||||||
|
if (d.pointee_type.cast(Payload.Union)) |union_ty| {
|
||||||
|
if (!union_ty.data.haveLayout()) break :canonicalize;
|
||||||
|
}
|
||||||
|
if (d.@"align" == d.pointee_type.abiAlignment(target)) {
|
||||||
|
d.@"align" = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Canonicalize host_size. If it matches the bit size of the pointee type,
|
// Canonicalize host_size. If it matches the bit size of the pointee type,
|
||||||
|
|||||||
@ -187,7 +187,7 @@ pub const Value = extern union {
|
|||||||
bound_fn,
|
bound_fn,
|
||||||
/// The ABI alignment of the payload type.
|
/// The ABI alignment of the payload type.
|
||||||
lazy_align,
|
lazy_align,
|
||||||
/// The ABI alignment of the payload type.
|
/// The ABI size of the payload type.
|
||||||
lazy_size,
|
lazy_size,
|
||||||
|
|
||||||
pub const last_no_payload_tag = Tag.empty_array;
|
pub const last_no_payload_tag = Tag.empty_array;
|
||||||
@ -1201,8 +1201,8 @@ pub const Value = extern union {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts the value is an integer and it fits in a i64
|
/// Asserts the value is an integer and it fits in a i64
|
||||||
pub fn toSignedInt(self: Value) i64 {
|
pub fn toSignedInt(val: Value, target: Target) i64 {
|
||||||
switch (self.tag()) {
|
switch (val.tag()) {
|
||||||
.zero,
|
.zero,
|
||||||
.bool_false,
|
.bool_false,
|
||||||
.the_only_possible_value, // i0, u0
|
.the_only_possible_value, // i0, u0
|
||||||
@ -1212,10 +1212,19 @@ pub const Value = extern union {
|
|||||||
.bool_true,
|
.bool_true,
|
||||||
=> return 1,
|
=> return 1,
|
||||||
|
|
||||||
.int_u64 => return @intCast(i64, self.castTag(.int_u64).?.data),
|
.int_u64 => return @intCast(i64, val.castTag(.int_u64).?.data),
|
||||||
.int_i64 => return self.castTag(.int_i64).?.data,
|
.int_i64 => return val.castTag(.int_i64).?.data,
|
||||||
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
|
.int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
|
||||||
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
|
.int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
|
||||||
|
|
||||||
|
.lazy_align => {
|
||||||
|
const ty = val.castTag(.lazy_align).?.data;
|
||||||
|
return @intCast(i64, ty.abiAlignment(target));
|
||||||
|
},
|
||||||
|
.lazy_size => {
|
||||||
|
const ty = val.castTag(.lazy_size).?.data;
|
||||||
|
return @intCast(i64, ty.abiSize(target));
|
||||||
|
},
|
||||||
|
|
||||||
.undef => unreachable,
|
.undef => unreachable,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
|
|||||||
@ -90,6 +90,7 @@ test {
|
|||||||
_ = @import("behavior/bugs/12430.zig");
|
_ = @import("behavior/bugs/12430.zig");
|
||||||
_ = @import("behavior/bugs/12486.zig");
|
_ = @import("behavior/bugs/12486.zig");
|
||||||
_ = @import("behavior/bugs/12488.zig");
|
_ = @import("behavior/bugs/12488.zig");
|
||||||
|
_ = @import("behavior/bugs/12498.zig");
|
||||||
_ = @import("behavior/bugs/12551.zig");
|
_ = @import("behavior/bugs/12551.zig");
|
||||||
_ = @import("behavior/bugs/12644.zig");
|
_ = @import("behavior/bugs/12644.zig");
|
||||||
_ = @import("behavior/bugs/12680.zig");
|
_ = @import("behavior/bugs/12680.zig");
|
||||||
|
|||||||
8
test/behavior/bugs/12498.zig
Normal file
8
test/behavior/bugs/12498.zig
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const expect = std.testing.expect;
|
||||||
|
|
||||||
|
const S = struct { a: usize };
|
||||||
|
test "lazy abi size used in comparison" {
|
||||||
|
var rhs: i32 = 100;
|
||||||
|
try expect(@sizeOf(S) < rhs);
|
||||||
|
}
|
||||||
@ -1418,3 +1418,15 @@ test "address of zero-bit field is equal to address of only field" {
|
|||||||
try std.testing.expectEqual(&a, a_ptr);
|
try std.testing.expectEqual(&a, a_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "struct field has a pointer to an aligned version of itself" {
|
||||||
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
|
const E = struct {
|
||||||
|
next: *align(1) @This(),
|
||||||
|
};
|
||||||
|
var e: E = undefined;
|
||||||
|
e = .{ .next = &e };
|
||||||
|
|
||||||
|
try expect(&e == e.next);
|
||||||
|
}
|
||||||
|
|||||||
@ -2,5 +2,5 @@ pub export fn main() noreturn {}
|
|||||||
|
|
||||||
// error
|
// error
|
||||||
//
|
//
|
||||||
// :1:32: error: function declared 'noreturn' returns
|
// :1:22: error: function declared 'noreturn' implicitly returns
|
||||||
// :1:22: note: 'noreturn' declared here
|
// :1:32: note: control flow reaches end of body here
|
||||||
|
|||||||
@ -8,3 +8,4 @@ pub extern fn foo(format: *const u8, ...) void;
|
|||||||
// target=native
|
// target=native
|
||||||
//
|
//
|
||||||
// :2:16: error: expected type '*const u8', found '[5:0]u8'
|
// :2:16: error: expected type '*const u8', found '[5:0]u8'
|
||||||
|
// :4:27: note: parameter type declared here
|
||||||
|
|||||||
@ -21,3 +21,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); }
|
|||||||
// :8:16: error: expected type '*const u3', found '*align(0:3:1) const u3'
|
// :8:16: error: expected type '*const u3', found '*align(0:3:1) const u3'
|
||||||
// :8:16: note: pointer host size '1' cannot cast into pointer host size '0'
|
// :8:16: note: pointer host size '1' cannot cast into pointer host size '0'
|
||||||
// :8:16: note: pointer bit offset '3' cannot cast into pointer bit offset '0'
|
// :8:16: note: pointer bit offset '3' cannot cast into pointer bit offset '0'
|
||||||
|
// :11:11: note: parameter type declared here
|
||||||
|
|||||||
@ -22,3 +22,4 @@ pub export fn entry() void {
|
|||||||
// target=native
|
// target=native
|
||||||
//
|
//
|
||||||
// :17:25: error: expected type 'u32', found 'type'
|
// :17:25: error: expected type 'u32', found 'type'
|
||||||
|
// :3:21: note: parameter type declared here
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
fn a() i32 {}
|
|
||||||
export fn entry() void { _ = a(); }
|
|
||||||
|
|
||||||
// error
|
|
||||||
// backend=stage2
|
|
||||||
// target=native
|
|
||||||
//
|
|
||||||
// :1:13: error: expected type 'i32', found 'void'
|
|
||||||
// :1:8: note: function return type declared here
|
|
||||||
@ -11,3 +11,4 @@ pub export fn entry() void {
|
|||||||
//
|
//
|
||||||
// :5:14: error: expected type '[*:0]const u8', found '[*]const u8'
|
// :5:14: error: expected type '[*:0]const u8', found '[*]const u8'
|
||||||
// :5:14: note: destination pointer requires '0' sentinel
|
// :5:14: note: destination pointer requires '0' sentinel
|
||||||
|
// :1:20: note: parameter type declared here
|
||||||
|
|||||||
@ -24,5 +24,6 @@ pub export fn entry3() void {
|
|||||||
// :4:35: note: cannot implicitly cast double pointer '*const *const usize' to anyopaque pointer '*const anyopaque'
|
// :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: error: expected type '?*anyopaque', found '*[*:0]u8'
|
||||||
// :9:10: note: cannot implicitly cast double pointer '*[*:0]u8' to anyopaque pointer '?*anyopaque'
|
// :9:10: note: cannot implicitly cast double pointer '*[*:0]u8' to anyopaque pointer '?*anyopaque'
|
||||||
|
// :11:12: note: parameter type declared here
|
||||||
// :15:35: error: expected type '*const anyopaque', found '*?*usize'
|
// :15:35: error: expected type '*const anyopaque', found '*?*usize'
|
||||||
// :15:35: note: cannot implicitly cast double pointer '*?*usize' to anyopaque pointer '*const anyopaque'
|
// :15:35: note: cannot implicitly cast double pointer '*?*usize' to anyopaque pointer '*const anyopaque'
|
||||||
|
|||||||
@ -18,3 +18,4 @@ fn bar(x: *u32) void {
|
|||||||
//
|
//
|
||||||
// :8:9: error: expected type '*u32', found '*align(1) u32'
|
// :8:9: error: expected type '*u32', found '*align(1) u32'
|
||||||
// :8:9: note: pointer alignment '1' cannot cast into pointer alignment '4'
|
// :8:9: note: pointer alignment '1' cannot cast into pointer alignment '4'
|
||||||
|
// :11:11: note: parameter type declared here
|
||||||
|
|||||||
29
test/cases/compile_errors/invalid_compare_string.zig
Normal file
29
test/cases/compile_errors/invalid_compare_string.zig
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
comptime {
|
||||||
|
var a = "foo";
|
||||||
|
if (a == "foo") unreachable;
|
||||||
|
}
|
||||||
|
comptime {
|
||||||
|
var a = "foo";
|
||||||
|
if (a == ("foo")) unreachable; // intentionally allow
|
||||||
|
}
|
||||||
|
comptime {
|
||||||
|
var a = "foo";
|
||||||
|
switch (a) {
|
||||||
|
"foo" => unreachable,
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
comptime {
|
||||||
|
var a = "foo";
|
||||||
|
switch (a) {
|
||||||
|
("foo") => unreachable, // intentionally allow
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :3:11: error: cannot compare strings with ==
|
||||||
|
// :12:9: error: cannot switch on strings
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
comptime {
|
||||||
|
const S = struct {
|
||||||
|
const Foo = struct {
|
||||||
|
y: Bar,
|
||||||
|
};
|
||||||
|
const Bar = struct {
|
||||||
|
y: if (@sizeOf(Foo) == 0) u64 else void,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = @sizeOf(S.Foo) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :6:21: error: struct layout depends on it having runtime bits
|
||||||
|
// :4:13: note: while checking this field
|
||||||
19
test/cases/compile_errors/missing_parameter_name.zig
Normal file
19
test/cases/compile_errors/missing_parameter_name.zig
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
fn f2(u64) u64 {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
fn f3(*x) u64 {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
fn f1(x) u64 {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :1:7: error: missing parameter name
|
||||||
|
// :4:7: error: missing parameter name
|
||||||
|
// :7:7: error: missing parameter name or type
|
||||||
|
// :7:7: note: if this is a name, annotate its type 'x: T'
|
||||||
|
// :7:7: note: if this is a type, give it a name '<name>: x'
|
||||||
@ -16,3 +16,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); }
|
|||||||
//
|
//
|
||||||
// :4:19: error: expected type '*[]const u8', found '*const []const u8'
|
// :4:19: error: expected type '*[]const u8', found '*const []const u8'
|
||||||
// :4:19: note: cast discards const qualifier
|
// :4:19: note: cast discards const qualifier
|
||||||
|
// :6:14: note: parameter type declared here
|
||||||
|
|||||||
@ -12,3 +12,4 @@ export const value = hi(MyStruct{ .x = 12 });
|
|||||||
//
|
//
|
||||||
// :7:33: error: expected type 'type', found 'tmp.MyStruct'
|
// :7:33: error: expected type 'type', found 'tmp.MyStruct'
|
||||||
// :1:18: note: struct declared here
|
// :1:18: note: struct declared here
|
||||||
|
// :3:19: note: parameter type declared here
|
||||||
|
|||||||
18
test/cases/compile_errors/struct_type_mismatch_in_arg.zig
Normal file
18
test/cases/compile_errors/struct_type_mismatch_in_arg.zig
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
const Foo = struct { i: i32 };
|
||||||
|
const Bar = struct { j: i32 };
|
||||||
|
|
||||||
|
pub fn helper(_: Foo, _: Bar) void { }
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
helper(Bar { .j = 10 }, Bar { .j = 10 });
|
||||||
|
helper(Bar { .i = 10 }, Bar { .j = 10 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :7:16: error: expected type 'tmp.Foo', found 'tmp.Bar'
|
||||||
|
// :1:13: note: struct declared here
|
||||||
|
// :2:13: note: struct declared here
|
||||||
|
// :4:18: note: parameter type declared here
|
||||||
@ -1,7 +1,7 @@
|
|||||||
pub export fn entry() void {
|
pub export fn entry() void {
|
||||||
var a: [:0]const u8 = "foo";
|
var a: [:0]const u8 = "foo";
|
||||||
switch (a) {
|
switch (a) {
|
||||||
"--version", "version" => unreachable,
|
("--version"), ("version") => unreachable,
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
test/cases/compile_errors/type_error_in_implicit_return.zig
Normal file
17
test/cases/compile_errors/type_error_in_implicit_return.zig
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
fn f1(x: bool) u32 {
|
||||||
|
if (x) return 1;
|
||||||
|
}
|
||||||
|
fn f2() noreturn {}
|
||||||
|
pub export fn entry() void {
|
||||||
|
_ = f1(true);
|
||||||
|
_ = f2();
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
// backend=stage2
|
||||||
|
// target=native
|
||||||
|
//
|
||||||
|
// :1:16: error: function with non-void return type 'u32' implicitly returns
|
||||||
|
// :3:1: note: control flow reaches end of body here
|
||||||
|
// :4:9: error: function declared 'noreturn' implicitly returns
|
||||||
|
// :4:19: note: control flow reaches end of body here
|
||||||
@ -12,3 +12,4 @@ export fn foo() void {
|
|||||||
// :5:9: error: expected type '*tmp.Derp', found '*anyopaque'
|
// :5:9: error: expected type '*tmp.Derp', found '*anyopaque'
|
||||||
// :5:9: note: pointer type child 'anyopaque' cannot cast into pointer type child 'tmp.Derp'
|
// :5:9: note: pointer type child 'anyopaque' cannot cast into pointer type child 'tmp.Derp'
|
||||||
// :1:14: note: opaque declared here
|
// :1:14: note: opaque declared here
|
||||||
|
// :2:18: note: parameter type declared here
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
pub export fn _start() noreturn {}
|
pub export fn main() noreturn {}
|
||||||
|
|
||||||
// error
|
// error
|
||||||
//
|
//
|
||||||
// :1:34: error: function declared 'noreturn' returns
|
// :1:22: error: function declared 'noreturn' implicitly returns
|
||||||
// :1:24: note: 'noreturn' declared here
|
// :1:32: note: control flow reaches end of body here
|
||||||
|
|||||||
@ -2,5 +2,5 @@ pub export fn main() noreturn {}
|
|||||||
|
|
||||||
// error
|
// error
|
||||||
//
|
//
|
||||||
// :1:32: error: function declared 'noreturn' returns
|
// :1:22: error: function declared 'noreturn' implicitly returns
|
||||||
// :1:22: note: 'noreturn' declared here
|
// :1:32: note: control flow reaches end of body here
|
||||||
|
|||||||
@ -2,5 +2,5 @@ pub export fn main() noreturn {}
|
|||||||
|
|
||||||
// error
|
// error
|
||||||
//
|
//
|
||||||
// :1:32: error: function declared 'noreturn' returns
|
// :1:22: error: function declared 'noreturn' implicitly returns
|
||||||
// :1:22: note: 'noreturn' declared here
|
// :1:32: note: control flow reaches end of body here
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user