| author | |
| committer | |
| log | b55a5007faad1de054e86e00bfdc9a58e5fc4ff8 |
| tree | e0c0713b6056b24f48e614805225739e8069f420 |
| parent | b2f02a820f1ed46721ed55243cead52efed055d7 |
Closes #12519
Closes #1250514 files changed, 51 insertions(+), 22 deletions(-)
doc/langref.html.in+2-2| ... | @@ -5023,8 +5023,8 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 { | ... | @@ -5023,8 +5023,8 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 { |
| 5023 | // Another file can use @import and call sub2 | 5023 | // Another file can use @import and call sub2 |
| 5024 | pub fn sub2(a: i8, b: i8) i8 { return a - b; } | 5024 | pub fn sub2(a: i8, b: i8) i8 { return a - b; } |
| 5025 | 5025 | ||
| 5026 | // Functions can be used as values and are equivalent to pointers. | 5026 | // Function pointers are prefixed with `*const `. |
| 5027 | const call2_op = fn (a: i8, b: i8) i8; | 5027 | const call2_op = *const fn (a: i8, b: i8) i8; |
| 5028 | fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 { | 5028 | fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 { |
| 5029 | return fn_call(op1, op2); | 5029 | return fn_call(op1, op2); |
| 5030 | } | 5030 | } |
lib/std/fs/path.zig+1-1| ... | @@ -42,7 +42,7 @@ pub fn isSep(byte: u8) bool { | ... | @@ -42,7 +42,7 @@ pub fn isSep(byte: u8) bool { |
| 42 | 42 | ||
| 43 | /// This is different from mem.join in that the separator will not be repeated if | 43 | /// This is different from mem.join in that the separator will not be repeated if |
| 44 | /// it is found at the end or beginning of a pair of consecutive paths. | 44 | /// it is found at the end or beginning of a pair of consecutive paths. |
| 45 | fn joinSepMaybeZ(allocator: Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 { | 45 | fn joinSepMaybeZ(allocator: Allocator, separator: u8, comptime sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 { |
| 46 | if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{}; | 46 | if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{}; |
| 47 | 47 | ||
| 48 | // Find first non-empty path index. | 48 | // Find first non-empty path index. |
lib/std/math.zig+1-1| ... | @@ -1548,7 +1548,7 @@ test "boolMask" { | ... | @@ -1548,7 +1548,7 @@ test "boolMask" { |
| 1548 | } | 1548 | } |
| 1549 | 1549 | ||
| 1550 | /// Return the mod of `num` with the smallest integer type | 1550 | /// Return the mod of `num` with the smallest integer type |
| 1551 | pub fn comptimeMod(num: anytype, denom: comptime_int) IntFittingRange(0, denom - 1) { | 1551 | pub fn comptimeMod(num: anytype, comptime denom: comptime_int) IntFittingRange(0, denom - 1) { |
| 1552 | return @intCast(IntFittingRange(0, denom - 1), @mod(num, denom)); | 1552 | return @intCast(IntFittingRange(0, denom - 1), @mod(num, denom)); |
| 1553 | } | 1553 | } |
| 1554 | 1554 |
lib/std/math/float.zig+1-1| ... | @@ -8,7 +8,7 @@ inline fn mantissaOne(comptime T: type) comptime_int { | ... | @@ -8,7 +8,7 @@ inline fn mantissaOne(comptime T: type) comptime_int { |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | /// Creates floating point type T from an unbiased exponent and raw mantissa. | 10 | /// Creates floating point type T from an unbiased exponent and raw mantissa. |
| 11 | inline fn reconstructFloat(comptime T: type, exponent: comptime_int, mantissa: comptime_int) T { | 11 | inline fn reconstructFloat(comptime T: type, comptime exponent: comptime_int, comptime mantissa: comptime_int) T { |
| 12 | const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); | 12 | const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); |
| 13 | const biased_exponent = @as(TBits, exponent + floatExponentMax(T)); | 13 | const biased_exponent = @as(TBits, exponent + floatExponentMax(T)); |
| 14 | return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa)); | 14 | return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa)); |
lib/std/zig/c_translation.zig+1-1| ... | @@ -349,7 +349,7 @@ test "shuffleVectorIndex" { | ... | @@ -349,7 +349,7 @@ test "shuffleVectorIndex" { |
| 349 | 349 | ||
| 350 | /// Constructs a [*c] pointer with the const and volatile annotations | 350 | /// Constructs a [*c] pointer with the const and volatile annotations |
| 351 | /// from SelfType for pointing to a C flexible array of ElementType. | 351 | /// from SelfType for pointing to a C flexible array of ElementType. |
| 352 | pub fn FlexibleArrayType(comptime SelfType: type, ElementType: type) type { | 352 | pub fn FlexibleArrayType(comptime SelfType: type, comptime ElementType: type) type { |
| 353 | switch (@typeInfo(SelfType)) { | 353 | switch (@typeInfo(SelfType)) { |
| 354 | .Pointer => |ptr| { | 354 | .Pointer => |ptr| { |
| 355 | return @Type(.{ .Pointer = .{ | 355 | return @Type(.{ .Pointer = .{ |
lib/std/zig/parse.zig+1-1| ... | @@ -3670,7 +3670,7 @@ const Parser = struct { | ... | @@ -3670,7 +3670,7 @@ const Parser = struct { |
| 3670 | } | 3670 | } |
| 3671 | 3671 | ||
| 3672 | /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)? | 3672 | /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)? |
| 3673 | fn parseIf(p: *Parser, bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index { | 3673 | fn parseIf(p: *Parser, comptime bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index { |
| 3674 | const if_token = p.eatToken(.keyword_if) orelse return null_node; | 3674 | const if_token = p.eatToken(.keyword_if) orelse return null_node; |
| 3675 | _ = try p.expectToken(.l_paren); | 3675 | _ = try p.expectToken(.l_paren); |
| 3676 | const condition = try p.expectExpr(); | 3676 | const condition = try p.expectExpr(); |
src/Module.zig+4-4| ... | @@ -6072,17 +6072,17 @@ pub fn paramSrc( | ... | @@ -6072,17 +6072,17 @@ pub fn paramSrc( |
| 6072 | else => unreachable, | 6072 | else => unreachable, |
| 6073 | }; | 6073 | }; |
| 6074 | var it = full.iterate(tree); | 6074 | var it = full.iterate(tree); |
| 6075 | while (true) { | 6075 | var i: usize = 0; |
| 6076 | if (it.param_i == param_i) { | 6076 | while (it.next()) |param| : (i += 1) { |
| 6077 | const param = it.next().?; | 6077 | if (i == param_i) { |
| 6078 | if (param.anytype_ellipsis3) |some| { | 6078 | if (param.anytype_ellipsis3) |some| { |
| 6079 | const main_token = tree.nodes.items(.main_token)[decl.src_node]; | 6079 | const main_token = tree.nodes.items(.main_token)[decl.src_node]; |
| 6080 | return .{ .token_offset_param = @bitCast(i32, some) - @bitCast(i32, main_token) }; | 6080 | return .{ .token_offset_param = @bitCast(i32, some) - @bitCast(i32, main_token) }; |
| 6081 | } | 6081 | } |
| 6082 | return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) }; | 6082 | return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) }; |
| 6083 | } | 6083 | } |
| 6084 | _ = it.next(); | ||
| 6085 | } | 6084 | } |
| 6085 | unreachable; | ||
| 6086 | } | 6086 | } |
| 6087 | 6087 | ||
| 6088 | pub fn argSrc( | 6088 | pub fn argSrc( |
src/Sema.zig+12-6| ... | @@ -76,6 +76,8 @@ types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{}, | ... | @@ -76,6 +76,8 @@ types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{}, |
| 76 | post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{}, | 76 | post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{}, |
| 77 | /// Populated with the last compile error created. | 77 | /// Populated with the last compile error created. |
| 78 | err: ?*Module.ErrorMsg = null, | 78 | err: ?*Module.ErrorMsg = null, |
| 79 | /// True when analyzing a generic instantiation. Used to suppress some errors. | ||
| 80 | is_generic_instantiation: bool = false, | ||
| 79 | 81 | ||
| 80 | const std = @import("std"); | 82 | const std = @import("std"); |
| 81 | const math = std.math; | 83 | const math = std.math; |
| ... | @@ -6495,6 +6497,7 @@ fn instantiateGenericCall( | ... | @@ -6495,6 +6497,7 @@ fn instantiateGenericCall( |
| 6495 | .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len), | 6497 | .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len), |
| 6496 | .comptime_args_fn_inst = module_fn.zir_body_inst, | 6498 | .comptime_args_fn_inst = module_fn.zir_body_inst, |
| 6497 | .preallocated_new_func = new_module_func, | 6499 | .preallocated_new_func = new_module_func, |
| 6500 | .is_generic_instantiation = true, | ||
| 6498 | }; | 6501 | }; |
| 6499 | defer child_sema.deinit(); | 6502 | defer child_sema.deinit(); |
| 6500 | 6503 | ||
| ... | @@ -7789,6 +7792,7 @@ fn funcCommon( | ... | @@ -7789,6 +7792,7 @@ fn funcCommon( |
| 7789 | &is_generic, | 7792 | &is_generic, |
| 7790 | is_extern, | 7793 | is_extern, |
| 7791 | cc_workaround, | 7794 | cc_workaround, |
| 7795 | has_body, | ||
| 7792 | ) catch |err| switch (err) { | 7796 | ) catch |err| switch (err) { |
| 7793 | error.NeededSourceLocation => { | 7797 | error.NeededSourceLocation => { |
| 7794 | const decl = sema.mod.declPtr(block.src_decl); | 7798 | const decl = sema.mod.declPtr(block.src_decl); |
| ... | @@ -7802,6 +7806,7 @@ fn funcCommon( | ... | @@ -7802,6 +7806,7 @@ fn funcCommon( |
| 7802 | &is_generic, | 7806 | &is_generic, |
| 7803 | is_extern, | 7807 | is_extern, |
| 7804 | cc_workaround, | 7808 | cc_workaround, |
| 7809 | has_body, | ||
| 7805 | ); | 7810 | ); |
| 7806 | return error.AnalysisFail; | 7811 | return error.AnalysisFail; |
| 7807 | }, | 7812 | }, |
| ... | @@ -8005,6 +8010,7 @@ fn analyzeParameter( | ... | @@ -8005,6 +8010,7 @@ fn analyzeParameter( |
| 8005 | is_generic: *bool, | 8010 | is_generic: *bool, |
| 8006 | is_extern: bool, | 8011 | is_extern: bool, |
| 8007 | cc: std.builtin.CallingConvention, | 8012 | cc: std.builtin.CallingConvention, |
| 8013 | has_body: bool, | ||
| 8008 | ) !void { | 8014 | ) !void { |
| 8009 | const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty); | 8015 | const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty); |
| 8010 | comptime_params[i] = param.is_comptime or requires_comptime; | 8016 | comptime_params[i] = param.is_comptime or requires_comptime; |
| ... | @@ -8053,9 +8059,9 @@ fn analyzeParameter( | ... | @@ -8053,9 +8059,9 @@ fn analyzeParameter( |
| 8053 | }; | 8059 | }; |
| 8054 | return sema.failWithOwnedErrorMsg(msg); | 8060 | return sema.failWithOwnedErrorMsg(msg); |
| 8055 | } | 8061 | } |
| 8056 | if (requires_comptime and !param.is_comptime) { | 8062 | if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) { |
| 8057 | const msg = msg: { | 8063 | const msg = msg: { |
| 8058 | const msg = try sema.errMsg(block, param_src, "parametter of type '{}' must be declared comptime", .{ | 8064 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{ |
| 8059 | param.ty.fmt(sema.mod), | 8065 | param.ty.fmt(sema.mod), |
| 8060 | }); | 8066 | }); |
| 8061 | errdefer msg.destroy(sema.gpa); | 8067 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -8153,7 +8159,7 @@ fn zirParam( | ... | @@ -8153,7 +8159,7 @@ fn zirParam( |
| 8153 | 8159 | ||
| 8154 | try block.params.append(sema.gpa, .{ | 8160 | try block.params.append(sema.gpa, .{ |
| 8155 | .ty = param_ty, | 8161 | .ty = param_ty, |
| 8156 | .is_comptime = is_comptime, | 8162 | .is_comptime = comptime_syntax, |
| 8157 | .name = param_name, | 8163 | .name = param_name, |
| 8158 | }); | 8164 | }); |
| 8159 | const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison)); | 8165 | const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison)); |
| ... | @@ -16318,7 +16324,7 @@ fn zirUnaryMath( | ... | @@ -16318,7 +16324,7 @@ fn zirUnaryMath( |
| 16318 | block: *Block, | 16324 | block: *Block, |
| 16319 | inst: Zir.Inst.Index, | 16325 | inst: Zir.Inst.Index, |
| 16320 | air_tag: Air.Inst.Tag, | 16326 | air_tag: Air.Inst.Tag, |
| 16321 | eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value, | 16327 | comptime eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value, |
| 16322 | ) CompileError!Air.Inst.Ref { | 16328 | ) CompileError!Air.Inst.Ref { |
| 16323 | const tracy = trace(@src()); | 16329 | const tracy = trace(@src()); |
| 16324 | defer tracy.end(); | 16330 | defer tracy.end(); |
| ... | @@ -17777,7 +17783,7 @@ fn zirBitCount( | ... | @@ -17777,7 +17783,7 @@ fn zirBitCount( |
| 17777 | block: *Block, | 17783 | block: *Block, |
| 17778 | inst: Zir.Inst.Index, | 17784 | inst: Zir.Inst.Index, |
| 17779 | air_tag: Air.Inst.Tag, | 17785 | air_tag: Air.Inst.Tag, |
| 17780 | comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64, | 17786 | comptime comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64, |
| 17781 | ) CompileError!Air.Inst.Ref { | 17787 | ) CompileError!Air.Inst.Ref { |
| 17782 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 17788 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 17783 | const src = inst_data.src(); | 17789 | const src = inst_data.src(); |
| ... | @@ -29491,7 +29497,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ | ... | @@ -29491,7 +29497,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29491 | => { | 29497 | => { |
| 29492 | const child_ty = ty.childType(); | 29498 | const child_ty = ty.childType(); |
| 29493 | if (child_ty.zigTypeTag() == .Fn) { | 29499 | if (child_ty.zigTypeTag() == .Fn) { |
| 29494 | return false; | 29500 | return child_ty.fnInfo().is_generic; |
| 29495 | } else { | 29501 | } else { |
| 29496 | return sema.typeRequiresComptime(block, src, child_ty); | 29502 | return sema.typeRequiresComptime(block, src, child_ty); |
| 29497 | } | 29503 | } |
src/type.zig+1-1| ... | @@ -2394,7 +2394,7 @@ pub const Type = extern union { | ... | @@ -2394,7 +2394,7 @@ pub const Type = extern union { |
| 2394 | if (ignore_comptime_only) { | 2394 | if (ignore_comptime_only) { |
| 2395 | return true; | 2395 | return true; |
| 2396 | } else if (ty.childType().zigTypeTag() == .Fn) { | 2396 | } else if (ty.childType().zigTypeTag() == .Fn) { |
| 2397 | return true; | 2397 | return !ty.childType().fnInfo().is_generic; |
| 2398 | } else if (sema_kit) |sk| { | 2398 | } else if (sema_kit) |sk| { |
| 2399 | return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty)); | 2399 | return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty)); |
| 2400 | } else { | 2400 | } else { |
test/behavior/cast.zig+1-1| ... | @@ -1281,7 +1281,7 @@ test "*const [N]null u8 to ?[]const u8" { | ... | @@ -1281,7 +1281,7 @@ test "*const [N]null u8 to ?[]const u8" { |
| 1281 | test "cast between [*c]T and ?[*:0]T on fn parameter" { | 1281 | test "cast between [*c]T and ?[*:0]T on fn parameter" { |
| 1282 | const S = struct { | 1282 | const S = struct { |
| 1283 | const Handler = ?fn ([*c]const u8) callconv(.C) void; | 1283 | const Handler = ?fn ([*c]const u8) callconv(.C) void; |
| 1284 | fn addCallback(handler: Handler) void { | 1284 | fn addCallback(comptime handler: Handler) void { |
| 1285 | _ = handler; | 1285 | _ = handler; |
| 1286 | } | 1286 | } |
| 1287 | 1287 |
test/behavior/error.zig+1-1| ... | @@ -168,7 +168,7 @@ fn entryPtr() void { | ... | @@ -168,7 +168,7 @@ fn entryPtr() void { |
| 168 | fooPtr(ptr); | 168 | fooPtr(ptr); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | fn foo2(f: fn () anyerror!void) void { | 171 | fn foo2(comptime f: fn () anyerror!void) void { |
| 172 | const x = f(); | 172 | const x = f(); |
| 173 | x catch { | 173 | x catch { |
| 174 | @panic("fail"); | 174 | @panic("fail"); |
test/behavior/fn.zig+1-1| ... | @@ -137,7 +137,7 @@ test "implicit cast function unreachable return" { | ... | @@ -137,7 +137,7 @@ test "implicit cast function unreachable return" { |
| 137 | wantsFnWithVoid(fnWithUnreachable); | 137 | wantsFnWithVoid(fnWithUnreachable); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | fn wantsFnWithVoid(f: fn () void) void { | 140 | fn wantsFnWithVoid(comptime f: fn () void) void { |
| 141 | _ = f; | 141 | _ = f; |
| 142 | } | 142 | } |
| 143 | 143 |
test/behavior/struct.zig+1-1| ... | @@ -147,7 +147,7 @@ test "fn call of struct field" { | ... | @@ -147,7 +147,7 @@ test "fn call of struct field" { |
| 147 | return 13; | 147 | return 13; |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | fn callStructField(foo: Foo) i32 { | 150 | fn callStructField(comptime foo: Foo) i32 { |
| 151 | return foo.ptr(); | 151 | return foo.ptr(); |
| 152 | } | 152 | } |
| 153 | }; | 153 | }; |
test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig created+23| ... | @@ -0,0 +1,23 @@ | ||
| 1 | fn f(_: anytype) void {} | ||
| 2 | fn g(h: *const fn (anytype) void) void { | ||
| 3 | h({}); | ||
| 4 | } | ||
| 5 | pub export fn entry() void { | ||
| 6 | g(f); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub fn comptimeMod(num: anytype, denom: comptime_int) void { | ||
| 10 | _ = num; | ||
| 11 | _ = denom; | ||
| 12 | } | ||
| 13 | |||
| 14 | pub export fn entry1() void { | ||
| 15 | _ = comptimeMod(1, 2); | ||
| 16 | } | ||
| 17 | |||
| 18 | // error | ||
| 19 | // backend=stage2 | ||
| 20 | // target=native | ||
| 21 | // | ||
| 22 | // :2:6: error: parameter of type '*const fn(anytype) void' must be declared comptime | ||
| 23 | // :9:34: error: parameter of type 'comptime_int' must be declared comptime | ||