| author | |
| committer | |
| log | 49a270b2038709a6a0c1f4de604696278769257b |
| tree | 61c938338f48de60fb50c00fa2d0cf33833e4209 |
| parent | 85a3f9b0544c1b90a77ce26f99f9fc26116d756b |
| parent | b757a96d5c885442c38e217006d75c85a28daf09 |
| signature |
stage2: generate call arguments in separate blocks14 files changed, 270 insertions(+), 133 deletions(-)
lib/std/crypto/25519/ed25519.zig+3-1| ... | ... | @@ -355,7 +355,9 @@ test "ed25519 batch verification" { |
| 355 | 355 | try Ed25519.verifyBatch(2, signature_batch); |
| 356 | 356 | |
| 357 | 357 | signature_batch[1].sig = sig1; |
| 358 | try std.testing.expectError(error.SignatureVerificationFailed, Ed25519.verifyBatch(signature_batch.len, signature_batch)); | |
| 358 | // TODO https://github.com/ziglang/zig/issues/12240 | |
| 359 | const sig_len = signature_batch.len; | |
| 360 | try std.testing.expectError(error.SignatureVerificationFailed, Ed25519.verifyBatch(sig_len, signature_batch)); | |
| 359 | 361 | } |
| 360 | 362 | } |
| 361 | 363 |
src/AstGen.zig+36-16| ... | ... | @@ -2500,7 +2500,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2500 | 2500 | .closure_get, |
| 2501 | 2501 | .array_base_ptr, |
| 2502 | 2502 | .field_base_ptr, |
| 2503 | .param_type, | |
| 2504 | 2503 | .ret_ptr, |
| 2505 | 2504 | .ret_type, |
| 2506 | 2505 | .@"try", |
| ... | ... | @@ -8228,6 +8227,33 @@ fn callExpr( |
| 8228 | 8227 | assert(callee != .none); |
| 8229 | 8228 | assert(node != 0); |
| 8230 | 8229 | |
| 8230 | const call_index = @intCast(Zir.Inst.Index, astgen.instructions.len); | |
| 8231 | const call_inst = Zir.indexToRef(call_index); | |
| 8232 | try gz.astgen.instructions.append(astgen.gpa, undefined); | |
| 8233 | try gz.instructions.append(astgen.gpa, call_index); | |
| 8234 | ||
| 8235 | const scratch_top = astgen.scratch.items.len; | |
| 8236 | defer astgen.scratch.items.len = scratch_top; | |
| 8237 | ||
| 8238 | var scratch_index = scratch_top; | |
| 8239 | try astgen.scratch.resize(astgen.gpa, scratch_top + call.ast.params.len); | |
| 8240 | ||
| 8241 | for (call.ast.params) |param_node| { | |
| 8242 | var arg_block = gz.makeSubBlock(scope); | |
| 8243 | defer arg_block.unstack(); | |
| 8244 | ||
| 8245 | // `call_inst` is reused to provide the param type. | |
| 8246 | const arg_ref = try expr(&arg_block, &arg_block.base, .{ .coerced_ty = call_inst }, param_node); | |
| 8247 | _ = try arg_block.addBreak(.break_inline, call_index, arg_ref); | |
| 8248 | ||
| 8249 | const body = arg_block.instructionsSlice(); | |
| 8250 | try astgen.scratch.ensureUnusedCapacity(astgen.gpa, countBodyLenAfterFixups(astgen, body)); | |
| 8251 | appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body); | |
| 8252 | ||
| 8253 | astgen.scratch.items[scratch_index] = @intCast(u32, astgen.scratch.items.len - scratch_top); | |
| 8254 | scratch_index += 1; | |
| 8255 | } | |
| 8256 | ||
| 8231 | 8257 | const payload_index = try addExtra(astgen, Zir.Inst.Call{ |
| 8232 | 8258 | .callee = callee, |
| 8233 | 8259 | .flags = .{ |
| ... | ... | @@ -8235,22 +8261,16 @@ fn callExpr( |
| 8235 | 8261 | .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len), |
| 8236 | 8262 | }, |
| 8237 | 8263 | }); |
| 8238 | var extra_index = try reserveExtra(astgen, call.ast.params.len); | |
| 8239 | ||
| 8240 | for (call.ast.params) |param_node, i| { | |
| 8241 | const param_type = try gz.add(.{ | |
| 8242 | .tag = .param_type, | |
| 8243 | .data = .{ .param_type = .{ | |
| 8244 | .callee = callee, | |
| 8245 | .param_index = @intCast(u32, i), | |
| 8246 | } }, | |
| 8247 | }); | |
| 8248 | const arg_ref = try expr(gz, scope, .{ .coerced_ty = param_type }, param_node); | |
| 8249 | astgen.extra.items[extra_index] = @enumToInt(arg_ref); | |
| 8250 | extra_index += 1; | |
| 8264 | if (call.ast.params.len != 0) { | |
| 8265 | try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]); | |
| 8251 | 8266 | } |
| 8252 | ||
| 8253 | const call_inst = try gz.addPlNodePayloadIndex(.call, node, payload_index); | |
| 8267 | gz.astgen.instructions.set(call_index, .{ | |
| 8268 | .tag = .call, | |
| 8269 | .data = .{ .pl_node = .{ | |
| 8270 | .src_node = gz.nodeIndexToRelative(node), | |
| 8271 | .payload_index = payload_index, | |
| 8272 | } }, | |
| 8273 | }); | |
| 8254 | 8274 | return rvalue(gz, rl, call_inst, node); // TODO function call with result location |
| 8255 | 8275 | } |
| 8256 | 8276 |
src/Autodoc.zig+8-3| ... | ... | @@ -2078,14 +2078,19 @@ fn walkInstruction( |
| 2078 | 2078 | |
| 2079 | 2079 | const args_len = extra.data.flags.args_len; |
| 2080 | 2080 | var args = try self.arena.alloc(DocData.Expr, args_len); |
| 2081 | const arg_refs = file.zir.refSlice(extra.end, args_len); | |
| 2082 | for (arg_refs) |ref, idx| { | |
| 2081 | const body = file.zir.extra[extra.end..]; | |
| 2082 | ||
| 2083 | var i: usize = 0; | |
| 2084 | while (i < args_len) : (i += 1) { | |
| 2085 | const arg_end = file.zir.extra[extra.end + i]; | |
| 2086 | const break_index = body[arg_end - 1]; | |
| 2087 | const ref = data[break_index].@"break".operand; | |
| 2083 | 2088 | // TODO: consider toggling need_type to true if we ever want |
| 2084 | 2089 | // to show discrepancies between the types of provided |
| 2085 | 2090 | // arguments and the types declared in the function |
| 2086 | 2091 | // signature for its parameters. |
| 2087 | 2092 | const wr = try self.walkRef(file, parent_scope, ref, false); |
| 2088 | args[idx] = wr.expr; | |
| 2093 | args[i] = wr.expr; | |
| 2089 | 2094 | } |
| 2090 | 2095 | |
| 2091 | 2096 | const cte_slot_index = self.comptime_exprs.items.len; |
src/Sema.zig+129-55| ... | ... | @@ -772,7 +772,6 @@ fn analyzeBodyInner( |
| 772 | 772 | .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), |
| 773 | 773 | .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), |
| 774 | 774 | .optional_type => try sema.zirOptionalType(block, inst), |
| 775 | .param_type => try sema.zirParamType(block, inst), | |
| 776 | 775 | .ptr_type => try sema.zirPtrType(block, inst), |
| 777 | 776 | .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst), |
| 778 | 777 | .ref => try sema.zirRef(block, inst), |
| ... | ... | @@ -4441,43 +4440,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v |
| 4441 | 4440 | return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store); |
| 4442 | 4441 | } |
| 4443 | 4442 | |
| 4444 | fn zirParamType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 4445 | const callee_src = sema.src; | |
| 4446 | ||
| 4447 | const inst_data = sema.code.instructions.items(.data)[inst].param_type; | |
| 4448 | const callee = try sema.resolveInst(inst_data.callee); | |
| 4449 | const callee_ty = sema.typeOf(callee); | |
| 4450 | var param_index = inst_data.param_index; | |
| 4451 | ||
| 4452 | const fn_ty = if (callee_ty.tag() == .bound_fn) fn_ty: { | |
| 4453 | const bound_fn_val = try sema.resolveConstValue(block, .unneeded, callee, undefined); | |
| 4454 | const bound_fn = bound_fn_val.castTag(.bound_fn).?.data; | |
| 4455 | const fn_ty = sema.typeOf(bound_fn.func_inst); | |
| 4456 | param_index += 1; | |
| 4457 | break :fn_ty fn_ty; | |
| 4458 | } else callee_ty; | |
| 4459 | ||
| 4460 | const fn_info = if (fn_ty.zigTypeTag() == .Pointer) | |
| 4461 | fn_ty.childType().fnInfo() | |
| 4462 | else | |
| 4463 | fn_ty.fnInfo(); | |
| 4464 | ||
| 4465 | if (param_index >= fn_info.param_types.len) { | |
| 4466 | if (fn_info.is_var_args) { | |
| 4467 | return sema.addType(Type.initTag(.var_args_param)); | |
| 4468 | } | |
| 4469 | // TODO implement begin_call/end_call Zir instructions and check | |
| 4470 | // argument count before casting arguments to parameter types. | |
| 4471 | return sema.fail(block, callee_src, "wrong number of arguments", .{}); | |
| 4472 | } | |
| 4473 | ||
| 4474 | if (fn_info.param_types[param_index].tag() == .generic_poison) { | |
| 4475 | return sema.addType(Type.initTag(.var_args_param)); | |
| 4476 | } | |
| 4477 | ||
| 4478 | return sema.addType(fn_info.param_types[param_index]); | |
| 4479 | } | |
| 4480 | ||
| 4481 | 4443 | fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 4482 | 4444 | const tracy = trace(@src()); |
| 4483 | 4445 | defer tracy.end(); |
| ... | ... | @@ -5447,6 +5409,19 @@ fn lookupInNamespace( |
| 5447 | 5409 | return null; |
| 5448 | 5410 | } |
| 5449 | 5411 | |
| 5412 | fn funcDeclSrc(sema: *Sema, block: *Block, src: LazySrcLoc, func_inst: Air.Inst.Ref) !?Module.SrcLoc { | |
| 5413 | const func_val = (try sema.resolveMaybeUndefVal(block, src, func_inst)) orelse return null; | |
| 5414 | if (func_val.isUndef()) return null; | |
| 5415 | const owner_decl_index = switch (func_val.tag()) { | |
| 5416 | .extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl, | |
| 5417 | .function => func_val.castTag(.function).?.data.owner_decl, | |
| 5418 | .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl, | |
| 5419 | else => return null, | |
| 5420 | }; | |
| 5421 | const owner_decl = sema.mod.declPtr(owner_decl_index); | |
| 5422 | return owner_decl.srcLoc(); | |
| 5423 | } | |
| 5424 | ||
| 5450 | 5425 | fn zirCall( |
| 5451 | 5426 | sema: *Sema, |
| 5452 | 5427 | block: *Block, |
| ... | ... | @@ -5459,13 +5434,14 @@ fn zirCall( |
| 5459 | 5434 | const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; |
| 5460 | 5435 | const call_src = inst_data.src(); |
| 5461 | 5436 | const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index); |
| 5462 | const args = sema.code.refSlice(extra.end, extra.data.flags.args_len); | |
| 5437 | const args_len = extra.data.flags.args_len; | |
| 5463 | 5438 | |
| 5464 | 5439 | const modifier = @intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier); |
| 5465 | 5440 | const ensure_result_used = extra.data.flags.ensure_result_used; |
| 5466 | 5441 | |
| 5467 | 5442 | var func = try sema.resolveInst(extra.data.callee); |
| 5468 | 5443 | var resolved_args: []Air.Inst.Ref = undefined; |
| 5444 | var arg_index: u32 = 0; | |
| 5469 | 5445 | |
| 5470 | 5446 | const func_type = sema.typeOf(func); |
| 5471 | 5447 | |
| ... | ... | @@ -5476,16 +5452,93 @@ fn zirCall( |
| 5476 | 5452 | const bound_func = try sema.resolveValue(block, .unneeded, func, undefined); |
| 5477 | 5453 | const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data; |
| 5478 | 5454 | func = bound_data.func_inst; |
| 5479 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len + 1); | |
| 5480 | resolved_args[0] = bound_data.arg0_inst; | |
| 5481 | for (args) |zir_arg, i| { | |
| 5482 | resolved_args[i + 1] = try sema.resolveInst(zir_arg); | |
| 5483 | } | |
| 5455 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1); | |
| 5456 | resolved_args[arg_index] = bound_data.arg0_inst; | |
| 5457 | arg_index += 1; | |
| 5484 | 5458 | } else { |
| 5485 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len); | |
| 5486 | for (args) |zir_arg, i| { | |
| 5487 | resolved_args[i] = try sema.resolveInst(zir_arg); | |
| 5459 | resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len); | |
| 5460 | } | |
| 5461 | const total_args = args_len + @boolToInt(bound_arg_src != null); | |
| 5462 | ||
| 5463 | const callee_ty = sema.typeOf(func); | |
| 5464 | const func_ty = func_ty: { | |
| 5465 | switch (callee_ty.zigTypeTag()) { | |
| 5466 | .Fn => break :func_ty callee_ty, | |
| 5467 | .Pointer => { | |
| 5468 | const ptr_info = callee_ty.ptrInfo().data; | |
| 5469 | if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) { | |
| 5470 | break :func_ty ptr_info.pointee_type; | |
| 5471 | } | |
| 5472 | }, | |
| 5473 | else => {}, | |
| 5474 | } | |
| 5475 | return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)}); | |
| 5476 | }; | |
| 5477 | const func_ty_info = func_ty.fnInfo(); | |
| 5478 | ||
| 5479 | const fn_params_len = func_ty_info.param_types.len; | |
| 5480 | check_args: { | |
| 5481 | if (func_ty_info.is_var_args) { | |
| 5482 | assert(func_ty_info.cc == .C); | |
| 5483 | if (total_args >= fn_params_len) break :check_args; | |
| 5484 | } else if (fn_params_len == total_args) { | |
| 5485 | break :check_args; | |
| 5486 | } | |
| 5487 | ||
| 5488 | const decl_src = try sema.funcDeclSrc(block, func_src, func); | |
| 5489 | const member_str = if (bound_arg_src != null) "member function " else ""; | |
| 5490 | const variadic_str = if (func_ty_info.is_var_args) "at least " else ""; | |
| 5491 | const msg = msg: { | |
| 5492 | const msg = try sema.errMsg( | |
| 5493 | block, | |
| 5494 | func_src, | |
| 5495 | "{s}expected {s}{d} argument(s), found {d}", | |
| 5496 | .{ | |
| 5497 | member_str, | |
| 5498 | variadic_str, | |
| 5499 | fn_params_len - @boolToInt(bound_arg_src != null), | |
| 5500 | args_len, | |
| 5501 | }, | |
| 5502 | ); | |
| 5503 | errdefer msg.destroy(sema.gpa); | |
| 5504 | ||
| 5505 | if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{}); | |
| 5506 | break :msg msg; | |
| 5507 | }; | |
| 5508 | return sema.failWithOwnedErrorMsg(msg); | |
| 5509 | } | |
| 5510 | ||
| 5511 | const args_body = sema.code.extra[extra.end..]; | |
| 5512 | ||
| 5513 | const parent_comptime = block.is_comptime; | |
| 5514 | // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument. | |
| 5515 | var extra_index: usize = 0; | |
| 5516 | var arg_start: u32 = args_len; | |
| 5517 | while (extra_index < args_len) : ({ | |
| 5518 | extra_index += 1; | |
| 5519 | arg_index += 1; | |
| 5520 | }) { | |
| 5521 | const arg_end = sema.code.extra[extra.end + extra_index]; | |
| 5522 | defer arg_start = arg_end; | |
| 5523 | ||
| 5524 | const param_ty = if (arg_index >= fn_params_len or | |
| 5525 | func_ty_info.param_types[arg_index].tag() == .generic_poison) | |
| 5526 | Type.initTag(.var_args_param) | |
| 5527 | else | |
| 5528 | func_ty_info.param_types[arg_index]; | |
| 5529 | ||
| 5530 | const old_comptime = block.is_comptime; | |
| 5531 | defer block.is_comptime = old_comptime; | |
| 5532 | // Generate args to comptime params in comptime block. | |
| 5533 | block.is_comptime = parent_comptime; | |
| 5534 | if (arg_index < fn_params_len and func_ty_info.comptime_params[arg_index]) { | |
| 5535 | block.is_comptime = true; | |
| 5488 | 5536 | } |
| 5537 | ||
| 5538 | const param_ty_inst = try sema.addType(param_ty); | |
| 5539 | try sema.inst_map.put(sema.gpa, inst, param_ty_inst); | |
| 5540 | ||
| 5541 | resolved_args[arg_index] = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); | |
| 5489 | 5542 | } |
| 5490 | 5543 | |
| 5491 | 5544 | return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src); |
| ... | ... | @@ -5579,13 +5632,20 @@ fn analyzeCall( |
| 5579 | 5632 | const func_ty_info = func_ty.fnInfo(); |
| 5580 | 5633 | const cc = func_ty_info.cc; |
| 5581 | 5634 | if (cc == .Naked) { |
| 5582 | // TODO add error note: declared here | |
| 5583 | return sema.fail( | |
| 5584 | block, | |
| 5585 | func_src, | |
| 5586 | "unable to call function with naked calling convention", | |
| 5587 | .{}, | |
| 5588 | ); | |
| 5635 | const decl_src = try sema.funcDeclSrc(block, func_src, func); | |
| 5636 | const msg = msg: { | |
| 5637 | const msg = try sema.errMsg( | |
| 5638 | block, | |
| 5639 | func_src, | |
| 5640 | "unable to call function with naked calling convention", | |
| 5641 | .{}, | |
| 5642 | ); | |
| 5643 | errdefer msg.destroy(sema.gpa); | |
| 5644 | ||
| 5645 | if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{}); | |
| 5646 | break :msg msg; | |
| 5647 | }; | |
| 5648 | return sema.failWithOwnedErrorMsg(msg); | |
| 5589 | 5649 | } |
| 5590 | 5650 | const fn_params_len = func_ty_info.param_types.len; |
| 5591 | 5651 | if (func_ty_info.is_var_args) { |
| ... | ... | @@ -5964,7 +6024,18 @@ fn analyzeCall( |
| 5964 | 6024 | else => |e| return e, |
| 5965 | 6025 | }; |
| 5966 | 6026 | } else { |
| 5967 | args[i] = uncasted_arg; | |
| 6027 | args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) { | |
| 6028 | error.NeededSourceLocation => { | |
| 6029 | const decl = sema.mod.declPtr(block.src_decl); | |
| 6030 | _ = try sema.coerceVarArgParam( | |
| 6031 | block, | |
| 6032 | uncasted_arg, | |
| 6033 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src), | |
| 6034 | ); | |
| 6035 | return error.AnalysisFail; | |
| 6036 | }, | |
| 6037 | else => |e| return e, | |
| 6038 | }; | |
| 5968 | 6039 | } |
| 5969 | 6040 | } |
| 5970 | 6041 | |
| ... | ... | @@ -23534,7 +23605,10 @@ fn coerceVarArgParam( |
| 23534 | 23605 | inst_src: LazySrcLoc, |
| 23535 | 23606 | ) !Air.Inst.Ref { |
| 23536 | 23607 | const inst_ty = sema.typeOf(inst); |
| 23608 | if (block.is_typeof) return inst; | |
| 23609 | ||
| 23537 | 23610 | switch (inst_ty.zigTypeTag()) { |
| 23611 | // TODO consider casting to c_int/f64 if they fit | |
| 23538 | 23612 | .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}), |
| 23539 | 23613 | else => {}, |
| 23540 | 23614 | } |
src/Zir.zig+3-17| ... | ... | @@ -490,14 +490,6 @@ pub const Inst = struct { |
| 490 | 490 | /// Merge two error sets into one, `E1 || E2`. |
| 491 | 491 | /// Uses the `pl_node` field with payload `Bin`. |
| 492 | 492 | merge_error_sets, |
| 493 | /// Given a reference to a function and a parameter index, returns the | |
| 494 | /// type of the parameter. The only usage of this instruction is for the | |
| 495 | /// result location of parameters of function calls. In the case of a function's | |
| 496 | /// parameter type being `anytype`, it is the type coercion's job to detect this | |
| 497 | /// scenario and skip the coercion, so that semantic analysis of this instruction | |
| 498 | /// is not in a position where it must create an invalid type. | |
| 499 | /// Uses the `param_type` union field. | |
| 500 | param_type, | |
| 501 | 493 | /// Turns an R-Value into a const L-Value. In other words, it takes a value, |
| 502 | 494 | /// stores it in a memory location, and returns a const pointer to it. If the value |
| 503 | 495 | /// is `comptime`, the memory location is global static constant data. Otherwise, |
| ... | ... | @@ -1095,7 +1087,6 @@ pub const Inst = struct { |
| 1095 | 1087 | .mul, |
| 1096 | 1088 | .mulwrap, |
| 1097 | 1089 | .mul_sat, |
| 1098 | .param_type, | |
| 1099 | 1090 | .ref, |
| 1100 | 1091 | .shl, |
| 1101 | 1092 | .shl_sat, |
| ... | ... | @@ -1397,7 +1388,6 @@ pub const Inst = struct { |
| 1397 | 1388 | .mul, |
| 1398 | 1389 | .mulwrap, |
| 1399 | 1390 | .mul_sat, |
| 1400 | .param_type, | |
| 1401 | 1391 | .ref, |
| 1402 | 1392 | .shl, |
| 1403 | 1393 | .shl_sat, |
| ... | ... | @@ -1569,7 +1559,6 @@ pub const Inst = struct { |
| 1569 | 1559 | .mulwrap = .pl_node, |
| 1570 | 1560 | .mul_sat = .pl_node, |
| 1571 | 1561 | |
| 1572 | .param_type = .param_type, | |
| 1573 | 1562 | .param = .pl_tok, |
| 1574 | 1563 | .param_comptime = .pl_tok, |
| 1575 | 1564 | .param_anytype = .str_tok, |
| ... | ... | @@ -2540,10 +2529,6 @@ pub const Inst = struct { |
| 2540 | 2529 | /// Points to a `Block`. |
| 2541 | 2530 | payload_index: u32, |
| 2542 | 2531 | }, |
| 2543 | param_type: struct { | |
| 2544 | callee: Ref, | |
| 2545 | param_index: u32, | |
| 2546 | }, | |
| 2547 | 2532 | @"unreachable": struct { |
| 2548 | 2533 | /// Offset from Decl AST node index. |
| 2549 | 2534 | /// `Tag` determines which kind of AST node this points to. |
| ... | ... | @@ -2614,7 +2599,6 @@ pub const Inst = struct { |
| 2614 | 2599 | ptr_type, |
| 2615 | 2600 | int_type, |
| 2616 | 2601 | bool_br, |
| 2617 | param_type, | |
| 2618 | 2602 | @"unreachable", |
| 2619 | 2603 | @"break", |
| 2620 | 2604 | switch_capture, |
| ... | ... | @@ -2794,7 +2778,9 @@ pub const Inst = struct { |
| 2794 | 2778 | }; |
| 2795 | 2779 | |
| 2796 | 2780 | /// Stored inside extra, with trailing arguments according to `args_len`. |
| 2797 | /// Each argument is a `Ref`. | |
| 2781 | /// Implicit 0. arg_0_start: u32, // always same as `args_len` | |
| 2782 | /// 1. arg_end: u32, // for each `args_len` | |
| 2783 | /// arg_N_start is the same as arg_N-1_end | |
| 2798 | 2784 | pub const Call = struct { |
| 2799 | 2785 | // Note: Flags *must* come first so that unusedResultExpr |
| 2800 | 2786 | // can find it when it goes to modify them. |
src/print_zir.zig+22-15| ... | ... | @@ -246,7 +246,6 @@ const Writer = struct { |
| 246 | 246 | |
| 247 | 247 | .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst), |
| 248 | 248 | .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), |
| 249 | .param_type => try self.writeParamType(stream, inst), | |
| 250 | 249 | .ptr_type => try self.writePtrType(stream, inst), |
| 251 | 250 | .int => try self.writeInt(stream, inst), |
| 252 | 251 | .int_big => try self.writeIntBig(stream, inst), |
| ... | ... | @@ -605,16 +604,6 @@ const Writer = struct { |
| 605 | 604 | try self.writeSrc(stream, inst_data.src()); |
| 606 | 605 | } |
| 607 | 606 | |
| 608 | fn writeParamType( | |
| 609 | self: *Writer, | |
| 610 | stream: anytype, | |
| 611 | inst: Zir.Inst.Index, | |
| 612 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | |
| 613 | const inst_data = self.code.instructions.items(.data)[inst].param_type; | |
| 614 | try self.writeInstRef(stream, inst_data.callee); | |
| 615 | try stream.print(", {d})", .{inst_data.param_index}); | |
| 616 | } | |
| 617 | ||
| 618 | 607 | fn writePtrType( |
| 619 | 608 | self: *Writer, |
| 620 | 609 | stream: anytype, |
| ... | ... | @@ -1158,7 +1147,8 @@ const Writer = struct { |
| 1158 | 1147 | fn writeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { |
| 1159 | 1148 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 1160 | 1149 | const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index); |
| 1161 | const args = self.code.refSlice(extra.end, extra.data.flags.args_len); | |
| 1150 | const args_len = extra.data.flags.args_len; | |
| 1151 | const body = self.code.extra[extra.end..]; | |
| 1162 | 1152 | |
| 1163 | 1153 | if (extra.data.flags.ensure_result_used) { |
| 1164 | 1154 | try stream.writeAll("nodiscard "); |
| ... | ... | @@ -1166,10 +1156,27 @@ const Writer = struct { |
| 1166 | 1156 | try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier))}); |
| 1167 | 1157 | try self.writeInstRef(stream, extra.data.callee); |
| 1168 | 1158 | try stream.writeAll(", ["); |
| 1169 | for (args) |arg, i| { | |
| 1170 | if (i != 0) try stream.writeAll(", "); | |
| 1171 | try self.writeInstRef(stream, arg); | |
| 1159 | ||
| 1160 | self.indent += 2; | |
| 1161 | if (args_len != 0) { | |
| 1162 | try stream.writeAll("\n"); | |
| 1163 | } | |
| 1164 | var i: usize = 0; | |
| 1165 | var arg_start: u32 = args_len; | |
| 1166 | while (i < args_len) : (i += 1) { | |
| 1167 | try stream.writeByteNTimes(' ', self.indent); | |
| 1168 | const arg_end = self.code.extra[extra.end + i]; | |
| 1169 | defer arg_start = arg_end; | |
| 1170 | const arg_body = body[arg_start..arg_end]; | |
| 1171 | try self.writeBracedBody(stream, arg_body); | |
| 1172 | ||
| 1173 | try stream.writeAll(",\n"); | |
| 1172 | 1174 | } |
| 1175 | self.indent -= 2; | |
| 1176 | if (args_len != 0) { | |
| 1177 | try stream.writeByteNTimes(' ', self.indent); | |
| 1178 | } | |
| 1179 | ||
| 1173 | 1180 | try stream.writeAll("]) "); |
| 1174 | 1181 | try self.writeSrc(stream, inst_data.src()); |
| 1175 | 1182 | } |
test/behavior/call.zig+15| ... | ... | @@ -246,3 +246,18 @@ test "function call with 40 arguments" { |
| 246 | 246 | }; |
| 247 | 247 | try S.doTheTest(39); |
| 248 | 248 | } |
| 249 | ||
| 250 | test "arguments to comptime parameters generated in comptime blocks" { | |
| 251 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 252 | ||
| 253 | const S = struct { | |
| 254 | fn fortyTwo() i32 { | |
| 255 | return 42; | |
| 256 | } | |
| 257 | ||
| 258 | fn foo(comptime x: i32) void { | |
| 259 | if (x != 42) @compileError("bad"); | |
| 260 | } | |
| 261 | }; | |
| 262 | S.foo(S.fortyTwo()); | |
| 263 | } |
test/cases/compile_errors/calling_function_with_naked_calling_convention.zig created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | export fn entry() void { | |
| 2 | foo(); | |
| 3 | } | |
| 4 | fn foo() callconv(.Naked) void { } | |
| 5 | ||
| 6 | // error | |
| 7 | // backend=llvm | |
| 8 | // target=native | |
| 9 | // | |
| 10 | // :2:5: error: unable to call function with naked calling convention | |
| 11 | // :4:1: note: function declared here |
test/cases/compile_errors/int_literal_passed_as_variadic_arg.zig created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | extern fn printf([*:0]const u8, ...) c_int; | |
| 2 | ||
| 3 | pub export fn entry() void { | |
| 4 | _ = printf("%d %d %d %d\n", 1, 2, 3, 4); | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // backend=stage2 | |
| 9 | // target=native | |
| 10 | // | |
| 11 | // :4:33: error: integer and float literals in var args function must be casted |
test/cases/compile_errors/member_function_arg_mismatch.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | const S = struct { | |
| 2 | a: u32, | |
| 3 | fn foo(_: *S, _: u32, _: bool) void {} | |
| 4 | }; | |
| 5 | pub export fn entry() void { | |
| 6 | var s: S = undefined; | |
| 7 | s.foo(true); | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // :7:6: error: member function expected 2 argument(s), found 1 | |
| 15 | // :3:5: note: function declared here |
test/cases/compile_errors/stage1/obj/calling_function_with_naked_calling_convention.zig deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | export fn entry() void { | |
| 2 | foo(); | |
| 3 | } | |
| 4 | fn foo() callconv(.Naked) void { } | |
| 5 | ||
| 6 | // error | |
| 7 | // backend=stage1 | |
| 8 | // target=native | |
| 9 | // | |
| 10 | // tmp.zig:2:5: error: unable to call function with naked calling convention | |
| 11 | // tmp.zig:4:1: note: declared here |
test/cases/compile_errors/stage1/obj/wrong_number_of_arguments_for_method_fn_call.zig deleted-14| ... | ... | @@ -1,14 +0,0 @@ |
| 1 | const Foo = struct { | |
| 2 | fn method(self: *const Foo, a: i32) void {_ = self; _ = a;} | |
| 3 | }; | |
| 4 | fn f(foo: *const Foo) void { | |
| 5 | ||
| 6 | foo.method(1, 2); | |
| 7 | } | |
| 8 | export fn entry() usize { return @sizeOf(@TypeOf(f)); } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage1 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // tmp.zig:6:15: error: expected 2 argument(s), found 3 |
test/cases/compile_errors/wrong_number_of_arguments.zig+2-1| ... | ... | @@ -7,4 +7,5 @@ fn c(d: i32, e: i32, f: i32) void { _ = d; _ = e; _ = f; } |
| 7 | 7 | // backend=stage2 |
| 8 | 8 | // target=native |
| 9 | 9 | // |
| 10 | // :2:6: error: expected 3 argument(s), found 1 | |
| 10 | // :2:5: error: expected 3 argument(s), found 1 | |
| 11 | // :4:1: note: function declared here |
test/cases/compile_errors/wrong_number_of_arguments_for_method_fn_call.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | const Foo = struct { | |
| 2 | fn method(self: *const Foo, a: i32) void {_ = self; _ = a;} | |
| 3 | }; | |
| 4 | fn f(foo: *const Foo) void { | |
| 5 | ||
| 6 | foo.method(1, 2); | |
| 7 | } | |
| 8 | export fn entry() usize { return @sizeOf(@TypeOf(&f)); } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // :6:8: error: member function expected 1 argument(s), found 2 | |
| 15 | // :2:5: note: function declared here |