diff --git a/src/Sema.zig b/src/Sema.zig index 3e8005269f..fc2a7f872a 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7720,7 +7720,6 @@ fn funcCommon( noalias_bits: u32, is_noinline: bool, ) CompileError!Air.Inst.Ref { - const fn_src = LazySrcLoc.nodeOffset(src_node_offset); const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset }; @@ -7791,13 +7790,11 @@ fn funcCommon( param_types[i] = param.ty; sema.analyzeParameter( block, - fn_src, .unneeded, param, comptime_params, i, &is_generic, - is_extern, cc_workaround, has_body, ) catch |err| switch (err) { @@ -7805,13 +7802,11 @@ fn funcCommon( const decl = sema.mod.declPtr(block.src_decl); try sema.analyzeParameter( block, - fn_src, Module.paramSrc(src_node_offset, sema.gpa, decl, i), param, comptime_params, i, &is_generic, - is_extern, cc_workaround, has_body, ); @@ -7821,9 +7816,10 @@ fn funcCommon( }; } + var is_comptime_ret = false; const ret_poison = if (!is_generic) rp: { if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| { - is_generic = ret_comptime; + is_comptime_ret = ret_comptime; break :rp bare_return_type.tag() == .generic_poison; } else |err| switch (err) { error.GenericPoison => { @@ -7920,6 +7916,8 @@ fn funcCommon( return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{}); } if (is_generic and sema.no_partial_func_ty) return error.GenericPoison; + for (comptime_params) |ct| is_generic = is_generic or ct; + is_generic = is_generic or is_comptime_ret; break :fn_ty try Type.Tag.function.create(sema.arena, .{ .param_types = param_types, @@ -8010,31 +8008,20 @@ fn funcCommon( fn analyzeParameter( sema: *Sema, block: *Block, - func_src: LazySrcLoc, param_src: LazySrcLoc, param: Block.Param, comptime_params: []bool, i: usize, is_generic: *bool, - is_extern: bool, cc: std.builtin.CallingConvention, has_body: bool, ) !void { const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty); comptime_params[i] = param.is_comptime or requires_comptime; - const this_generic = comptime_params[i] or param.ty.tag() == .generic_poison; + const this_generic = param.ty.tag() == .generic_poison; is_generic.* = is_generic.* or this_generic; - if (is_extern and this_generic) { - // TODO this check should exist somewhere for notes. - if (param_src == .unneeded) return error.NeededSourceLocation; - const msg = msg: { - const msg = try sema.errMsg(block, func_src, "extern function cannot be generic", .{}); - errdefer msg.destroy(sema.gpa); - - try sema.errNote(block, param_src, msg, "function is generic because of this parameter", .{}); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(msg); + if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(cc)) { + return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); } if (this_generic and !Type.fnCallingConventionAllowsZigTypes(cc)) { return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); diff --git a/test/behavior/typename.zig b/test/behavior/typename.zig index e0cb5ba68c..3bc8c58389 100644 --- a/test/behavior/typename.zig +++ b/test/behavior/typename.zig @@ -235,3 +235,14 @@ test "local variable" { try expectEqualStrings("behavior.typename.test.local variable.Qux", @typeName(Qux)); try expectEqualStrings("behavior.typename.test.local variable.Quux", @typeName(Quux)); } + +test "comptime parameters not converted to anytype in function type" { + if (builtin.zig_backend == .stage1) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + const T = fn (fn (type) void, void) void; + try expectEqualStrings("fn(fn(type) void, void) void", @typeName(T)); +} diff --git a/test/cases/compile_errors/export_function_with_comptime_parameter.zig b/test/cases/compile_errors/export_function_with_comptime_parameter.zig index 94c8f6de50..4491a98e9c 100644 --- a/test/cases/compile_errors/export_function_with_comptime_parameter.zig +++ b/test/cases/compile_errors/export_function_with_comptime_parameter.zig @@ -6,4 +6,4 @@ export fn foo(comptime x: anytype, y: i32) i32{ // backend=stage2 // target=native // -// :1:15: error: generic parameters not allowed in function with calling convention 'C' +// :1:15: error: comptime parameters not allowed in function with calling convention 'C' diff --git a/test/cases/compile_errors/extern_function_with_comptime_parameter.zig b/test/cases/compile_errors/extern_function_with_comptime_parameter.zig index cac4c7e5e2..de69fa409f 100644 --- a/test/cases/compile_errors/extern_function_with_comptime_parameter.zig +++ b/test/cases/compile_errors/extern_function_with_comptime_parameter.zig @@ -12,9 +12,6 @@ comptime { _ = entry2; } // backend=stage2 // target=native // -// :5:12: error: extern function cannot be generic -// :5:30: note: function is generic because of this parameter -// :6:12: error: extern function cannot be generic -// :6:30: note: function is generic because of this parameter -// :1:8: error: extern function cannot be generic -// :1:15: note: function is generic because of this parameter +// :1:15: error: comptime parameters not allowed in function with calling convention 'C' +// :5:30: error: comptime parameters not allowed in function with calling convention 'C' +// :6:30: error: generic parameters not allowed in function with calling convention 'C'