diff --git a/doc/langref.html.in b/doc/langref.html.in index 9247d3bc43..04d736609a 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5023,8 +5023,8 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 { // Another file can use @import and call sub2 pub fn sub2(a: i8, b: i8) i8 { return a - b; } -// Functions can be used as values and are equivalent to pointers. -const call2_op = fn (a: i8, b: i8) i8; +// Function pointers are prefixed with `*const `. +const call2_op = *const fn (a: i8, b: i8) i8; fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 { return fn_call(op1, op2); } diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index d5583dcc80..9dc3367688 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -42,7 +42,7 @@ pub fn isSep(byte: u8) bool { /// This is different from mem.join in that the separator will not be repeated if /// it is found at the end or beginning of a pair of consecutive paths. -fn joinSepMaybeZ(allocator: Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 { +fn joinSepMaybeZ(allocator: Allocator, separator: u8, comptime sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 { if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{}; // Find first non-empty path index. diff --git a/lib/std/math.zig b/lib/std/math.zig index 40b5eb9204..1ed9604612 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -1548,7 +1548,7 @@ test "boolMask" { } /// Return the mod of `num` with the smallest integer type -pub fn comptimeMod(num: anytype, denom: comptime_int) IntFittingRange(0, denom - 1) { +pub fn comptimeMod(num: anytype, comptime denom: comptime_int) IntFittingRange(0, denom - 1) { return @intCast(IntFittingRange(0, denom - 1), @mod(num, denom)); } diff --git a/lib/std/math/float.zig b/lib/std/math/float.zig index 30e456fcbd..768cc03285 100644 --- a/lib/std/math/float.zig +++ b/lib/std/math/float.zig @@ -8,7 +8,7 @@ inline fn mantissaOne(comptime T: type) comptime_int { } /// Creates floating point type T from an unbiased exponent and raw mantissa. -inline fn reconstructFloat(comptime T: type, exponent: comptime_int, mantissa: comptime_int) T { +inline fn reconstructFloat(comptime T: type, comptime exponent: comptime_int, comptime mantissa: comptime_int) T { const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); const biased_exponent = @as(TBits, exponent + floatExponentMax(T)); return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa)); diff --git a/lib/std/zig/c_translation.zig b/lib/std/zig/c_translation.zig index 8a2086e9ad..348e3a7133 100644 --- a/lib/std/zig/c_translation.zig +++ b/lib/std/zig/c_translation.zig @@ -349,7 +349,7 @@ test "shuffleVectorIndex" { /// Constructs a [*c] pointer with the const and volatile annotations /// from SelfType for pointing to a C flexible array of ElementType. -pub fn FlexibleArrayType(comptime SelfType: type, ElementType: type) type { +pub fn FlexibleArrayType(comptime SelfType: type, comptime ElementType: type) type { switch (@typeInfo(SelfType)) { .Pointer => |ptr| { return @Type(.{ .Pointer = .{ diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index a03764a91c..fda6ad98b9 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -3670,7 +3670,7 @@ const Parser = struct { } /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)? - fn parseIf(p: *Parser, bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index { + fn parseIf(p: *Parser, comptime bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index { const if_token = p.eatToken(.keyword_if) orelse return null_node; _ = try p.expectToken(.l_paren); const condition = try p.expectExpr(); diff --git a/src/Module.zig b/src/Module.zig index 3577115ded..45e0779c54 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -6072,17 +6072,17 @@ pub fn paramSrc( else => unreachable, }; var it = full.iterate(tree); - while (true) { - if (it.param_i == param_i) { - const param = it.next().?; + var i: usize = 0; + while (it.next()) |param| : (i += 1) { + if (i == param_i) { if (param.anytype_ellipsis3) |some| { const main_token = tree.nodes.items(.main_token)[decl.src_node]; return .{ .token_offset_param = @bitCast(i32, some) - @bitCast(i32, main_token) }; } return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) }; } - _ = it.next(); } + unreachable; } pub fn argSrc( diff --git a/src/Sema.zig b/src/Sema.zig index 582299bc9e..a3207b8539 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -76,6 +76,8 @@ types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{}, post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{}, /// Populated with the last compile error created. err: ?*Module.ErrorMsg = null, +/// True when analyzing a generic instantiation. Used to suppress some errors. +is_generic_instantiation: bool = false, const std = @import("std"); const math = std.math; @@ -6495,6 +6497,7 @@ fn instantiateGenericCall( .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len), .comptime_args_fn_inst = module_fn.zir_body_inst, .preallocated_new_func = new_module_func, + .is_generic_instantiation = true, }; defer child_sema.deinit(); @@ -7789,6 +7792,7 @@ fn funcCommon( &is_generic, is_extern, cc_workaround, + has_body, ) catch |err| switch (err) { error.NeededSourceLocation => { const decl = sema.mod.declPtr(block.src_decl); @@ -7802,6 +7806,7 @@ fn funcCommon( &is_generic, is_extern, cc_workaround, + has_body, ); return error.AnalysisFail; }, @@ -8005,6 +8010,7 @@ fn analyzeParameter( 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; @@ -8053,9 +8059,9 @@ fn analyzeParameter( }; return sema.failWithOwnedErrorMsg(msg); } - if (requires_comptime and !param.is_comptime) { + if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) { const msg = msg: { - const msg = try sema.errMsg(block, param_src, "parametter of type '{}' must be declared comptime", .{ + const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{ param.ty.fmt(sema.mod), }); errdefer msg.destroy(sema.gpa); @@ -8153,7 +8159,7 @@ fn zirParam( try block.params.append(sema.gpa, .{ .ty = param_ty, - .is_comptime = is_comptime, + .is_comptime = comptime_syntax, .name = param_name, }); const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison)); @@ -16318,7 +16324,7 @@ fn zirUnaryMath( block: *Block, inst: Zir.Inst.Index, air_tag: Air.Inst.Tag, - eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value, + comptime eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value, ) CompileError!Air.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); @@ -17777,7 +17783,7 @@ fn zirBitCount( block: *Block, inst: Zir.Inst.Index, air_tag: Air.Inst.Tag, - comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64, + comptime comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64, ) CompileError!Air.Inst.Ref { const inst_data = sema.code.instructions.items(.data)[inst].un_node; const src = inst_data.src(); @@ -29491,7 +29497,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ => { const child_ty = ty.childType(); if (child_ty.zigTypeTag() == .Fn) { - return false; + return child_ty.fnInfo().is_generic; } else { return sema.typeRequiresComptime(block, src, child_ty); } diff --git a/src/type.zig b/src/type.zig index d2885f537f..1592dcf469 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2394,7 +2394,7 @@ pub const Type = extern union { if (ignore_comptime_only) { return true; } else if (ty.childType().zigTypeTag() == .Fn) { - return true; + return !ty.childType().fnInfo().is_generic; } else if (sema_kit) |sk| { return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty)); } else { diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index ac3a4daeab..fa0877258c 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1281,7 +1281,7 @@ test "*const [N]null u8 to ?[]const u8" { test "cast between [*c]T and ?[*:0]T on fn parameter" { const S = struct { const Handler = ?fn ([*c]const u8) callconv(.C) void; - fn addCallback(handler: Handler) void { + fn addCallback(comptime handler: Handler) void { _ = handler; } diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 84b18a2738..b355c85819 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -168,7 +168,7 @@ fn entryPtr() void { fooPtr(ptr); } -fn foo2(f: fn () anyerror!void) void { +fn foo2(comptime f: fn () anyerror!void) void { const x = f(); x catch { @panic("fail"); diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 044e4ff049..d68cd89210 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -137,7 +137,7 @@ test "implicit cast function unreachable return" { wantsFnWithVoid(fnWithUnreachable); } -fn wantsFnWithVoid(f: fn () void) void { +fn wantsFnWithVoid(comptime f: fn () void) void { _ = f; } diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index eb29c9038d..12c874f8ba 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -147,7 +147,7 @@ test "fn call of struct field" { return 13; } - fn callStructField(foo: Foo) i32 { + fn callStructField(comptime foo: Foo) i32 { return foo.ptr(); } }; diff --git a/test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig b/test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig new file mode 100644 index 0000000000..e4d9eed079 --- /dev/null +++ b/test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig @@ -0,0 +1,23 @@ +fn f(_: anytype) void {} +fn g(h: *const fn (anytype) void) void { + h({}); +} +pub export fn entry() void { + g(f); +} + +pub fn comptimeMod(num: anytype, denom: comptime_int) void { + _ = num; + _ = denom; +} + +pub export fn entry1() void { + _ = comptimeMod(1, 2); +} + +// error +// backend=stage2 +// target=native +// +// :2:6: error: parameter of type '*const fn(anytype) void' must be declared comptime +// :9:34: error: parameter of type 'comptime_int' must be declared comptime