diff --git a/src/analyze.cpp b/src/analyze.cpp index 58fe9e739223f84e00b3da12b59ea2b9923dafc3..aa4fda76242e59a99a9e8f63ff2be6967bb5f529 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1013,7 +1013,7 @@ bool calling_convention_does_first_arg_return(CallingConvention cc) { return cc == CallingConventionUnspecified; } -static const char *calling_convention_name(CallingConvention cc) { +const char *calling_convention_name(CallingConvention cc) { switch (cc) { case CallingConventionUnspecified: return "undefined"; case CallingConventionC: return "ccc"; @@ -1037,7 +1037,7 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) { zig_unreachable(); } -static bool calling_convention_allows_zig_types(CallingConvention cc) { +bool calling_convention_allows_zig_types(CallingConvention cc) { switch (cc) { case CallingConventionUnspecified: case CallingConventionAsync: diff --git a/src/analyze.hpp b/src/analyze.hpp index 357312f2dc0c0c870bda1358ad589ad9b609b2e9..41cc50916eac81e690343b6dbf960335f9b796ec 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -207,4 +207,7 @@ AstNode *type_decl_node(ZigType *type_entry); ZigType *get_primitive_type(CodeGen *g, Buf *name); +bool calling_convention_allows_zig_types(CallingConvention cc); +const char *calling_convention_name(CallingConvention cc); + #endif diff --git a/src/ir.cpp b/src/ir.cpp index 4e9c8d2bc750c8cd398df9a76d6bcc2ff0fda5dd..0269c29b1aa1459ce03d972aa8981109cea3ee81 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19595,6 +19595,7 @@ static ZigType *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, } static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) { + Error err; AstNode *proto_node = instruction->base.source_node; assert(proto_node->type == NodeTypeFnProto); @@ -19636,9 +19637,25 @@ static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnP IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other; if (type_is_invalid(param_type_value->value.type)) return ira->codegen->builtin_types.entry_invalid; - param_info->type = ir_resolve_type(ira, param_type_value); - if (type_is_invalid(param_info->type)) + ZigType *param_type = ir_resolve_type(ira, param_type_value); + if (type_is_invalid(param_type)) return ira->codegen->builtin_types.entry_invalid; + if ((err = type_ensure_zero_bits_known(ira->codegen, param_type))) + return ira->codegen->builtin_types.entry_invalid; + if (type_requires_comptime(param_type)) { + if (!calling_convention_allows_zig_types(fn_type_id.cc)) { + ir_add_error(ira, &instruction->base, + buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", + buf_ptr(¶m_type->name), calling_convention_name(fn_type_id.cc))); + return ira->codegen->builtin_types.entry_invalid; + } + param_info->type = param_type; + fn_type_id.next_param_index += 1; + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); + out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id); + return ira->codegen->builtin_types.entry_type; + } + param_info->type = param_type; } } diff --git a/test/cases/eval.zig b/test/cases/eval.zig index 695cd4df77522b98d816acd06e824f3a3ac2fbca..b8d80bda020a4866beca5c758086bb74c1d3d4b3 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -674,3 +674,11 @@ test "inline for with same type but different values" { } assert(res == 5); } + +test "refer to the type of a generic function" { + const Func = fn (type) void; + const f: Func = doNothingWithType; + f(i32); +} + +fn doNothingWithType(comptime T: type) void {} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 24d977c218c6a90f473d461d89f49c3b68cbd0d4..faf17d2c059e55a07ada18db95d18846206db1e5 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,17 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "refer to the type of a generic function", + \\export fn entry() void { + \\ const Func = fn (type) void; + \\ const f: Func = undefined; + \\ f(i32); + \\} + , + ".tmp_source.zig:4:5: error: use of undefined value", + ); + cases.add( "accessing runtime parameter from outer function", \\fn outer(y: u32) fn (u32) u32 {