From d10c52c194a093f58df40bc6122f24380f0cc097 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 16 Mar 2024 16:46:45 +0100 Subject: [PATCH] AstGen: disallow alignment on function types A pointer type already has an alignment, so this information does not need to be duplicated on the function type. This already has precedence with addrspace which is already disallowed on function types for this reason. Also fixes `@TypeOf(&func)` to have the correct addrspace and alignment. --- doc/langref.html.in | 10 +- lib/std/builtin.zig | 1 - lib/std/c/darwin.zig | 10 +- lib/std/c/dragonfly.zig | 8 +- lib/std/c/freebsd.zig | 8 +- lib/std/c/haiku.zig | 8 +- lib/std/c/netbsd.zig | 8 +- lib/std/c/openbsd.zig | 12 +- lib/std/c/solaris.zig | 10 +- lib/std/meta.zig | 9 +- lib/std/os/emscripten.zig | 8 +- lib/std/os/linux.zig | 41 ++-- lib/std/zig/AstGen.zig | 14 +- src/InternPool.zig | 28 +-- src/Module.zig | 176 +++++++----------- src/Sema.zig | 43 ++--- src/codegen/c.zig | 4 +- src/codegen/llvm.zig | 4 +- src/type.zig | 10 +- test/behavior/align.zig | 36 ++-- test/behavior/type.zig | 2 - test/behavior/type_info.zig | 42 ++++- test/behavior/typename.zig | 6 +- .../compile_errors/function_ptr_alignment.zig | 28 +-- ...nferring_error_set_of_function_pointer.zig | 9 - .../compile_errors/invalid_function_types.zig | 25 +++ ...sing_an_under-aligned_function_pointer.zig | 4 +- .../reify_type.Fn_with_is_generic_true.zig | 1 - ...th_is_var_args_true_and_non-C_callconv.zig | 1 - .../reify_type.Fn_with_return_type_null.zig | 1 - 30 files changed, 257 insertions(+), 310 deletions(-) delete mode 100644 test/cases/compile_errors/inferring_error_set_of_function_pointer.zig create mode 100644 test/cases/compile_errors/invalid_function_types.zig diff --git a/doc/langref.html.in b/doc/langref.html.in index 9d48238843032a0cd0dc286b2494ae9141de19ac..7ffbcc01108669087224d943b3fc9a36ceaa98ea 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -2780,10 +2780,16 @@ fn noop4() align(4) void {} test "function alignment" { try expect(derp() == 1234); - try expect(@TypeOf(noop1) == fn () align(1) void); - try expect(@TypeOf(noop4) == fn () align(4) void); + try expect(@TypeOf(derp) == fn () i32); + try expect(@TypeOf(&derp) == *align(@sizeOf(usize) * 2) const fn () i32); + noop1(); + try expect(@TypeOf(noop1) == fn () void); + try expect(@TypeOf(&noop1) == *align(1) const fn () void); + noop4(); + try expect(@TypeOf(noop4) == fn () void); + try expect(@TypeOf(&noop4) == *align(4) const fn () void); } {#code_end#}

diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index d9e72f2019a6fc5e20b85a287a08d43785f9270a..0238d35c7d9dc2fec6b54cab2411a1bfd5ae1bd9 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -420,7 +420,6 @@ pub const Type = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const Fn = struct { calling_convention: CallingConvention, - alignment: comptime_int, is_generic: bool, is_var_args: bool, /// TODO change the language spec to make this not optional. diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index 8dd122c3ba676e4654ce746120e5ed43d1a6c533..8442ac9fe00ce1374a0a0f4a06f5b9bd8a26dd6a 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -1053,10 +1053,10 @@ pub const sigset_t = u32; pub const empty_sigset: sigset_t = 0; pub const SIG = struct { - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); - pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(5)); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); + pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(5); /// block specified signal set pub const BLOCK = 1; @@ -1150,7 +1150,7 @@ pub const siginfo_t = extern struct { /// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name. pub const Sigaction = extern struct { - pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; + pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; handler: extern union { diff --git a/lib/std/c/dragonfly.zig b/lib/std/c/dragonfly.zig index 8cbdd22c401f122b19294fa3844af3b83519c03c..183a81bba2a273a30f277b990d5d6ad93263a125 100644 --- a/lib/std/c/dragonfly.zig +++ b/lib/std/c/dragonfly.zig @@ -616,9 +616,9 @@ pub const S = struct { pub const BADSIG = SIG.ERR; pub const SIG = struct { - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); pub const BLOCK = 1; pub const UNBLOCK = 2; @@ -690,7 +690,7 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS }; pub const sig_atomic_t = c_int; pub const Sigaction = extern struct { - pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; + pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; /// signal handler diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig index 94854cf09005431900d44b10be3d6231c253ec03..a89ca30968fc8423760f8b5be273bdddf3a0d7fb 100644 --- a/lib/std/c/freebsd.zig +++ b/lib/std/c/freebsd.zig @@ -695,9 +695,9 @@ pub const SIG = struct { pub const UNBLOCK = 2; pub const SETMASK = 3; - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); pub const WORDS = 4; pub const MAXSIG = 128; @@ -1171,7 +1171,7 @@ const NSIG = 32; /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. pub const Sigaction = extern struct { - pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; + pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; /// signal handler diff --git a/lib/std/c/haiku.zig b/lib/std/c/haiku.zig index 723d953d2d76c8c43e999361a1b4c3f649e4469c..12b5201acd864e2785daaa593ccdc8390ee0edad 100644 --- a/lib/std/c/haiku.zig +++ b/lib/std/c/haiku.zig @@ -441,9 +441,9 @@ pub const SA = struct { }; pub const SIG = struct { - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); pub const HUP = 1; pub const INT = 2; @@ -690,7 +690,7 @@ const NSIG = 32; /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. pub const Sigaction = extern struct { - pub const handler_fn = *const fn (i32) align(1) callconv(.C) void; + pub const handler_fn = *align(1) const fn (i32) callconv(.C) void; /// signal handler __sigaction_u: extern union { diff --git a/lib/std/c/netbsd.zig b/lib/std/c/netbsd.zig index 475fd55e22bfa5a44e0bf653f8b3aec5d9c6bcf7..c06857787ae46885e804cc51629f525ccde9bfc7 100644 --- a/lib/std/c/netbsd.zig +++ b/lib/std/c/netbsd.zig @@ -800,9 +800,9 @@ pub const winsize = extern struct { const NSIG = 32; pub const SIG = struct { - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); pub const WORDS = 4; pub const MAXSIG = 128; @@ -864,7 +864,7 @@ pub const SIG = struct { /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. pub const Sigaction = extern struct { - pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; + pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; /// signal handler diff --git a/lib/std/c/openbsd.zig b/lib/std/c/openbsd.zig index 75a4d6e0e8ee2c444431be2d803b4067350e03c4..4fd450cd5ce465fa6f76135060cf58786b8a4b58 100644 --- a/lib/std/c/openbsd.zig +++ b/lib/std/c/openbsd.zig @@ -795,11 +795,11 @@ pub const winsize = extern struct { const NSIG = 33; pub const SIG = struct { - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); - pub const CATCH = @as(?Sigaction.handler_fn, @ptrFromInt(2)); - pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(3)); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); + pub const CATCH: ?Sigaction.handler_fn = @ptrFromInt(2); + pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(3); pub const HUP = 1; pub const INT = 2; @@ -842,7 +842,7 @@ pub const SIG = struct { /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. pub const Sigaction = extern struct { - pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; + pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; /// signal handler diff --git a/lib/std/c/solaris.zig b/lib/std/c/solaris.zig index ef64acd43b931a65a01fc57b2649906e10569172..838b6985cc0873a86ea8451a6b70733cf9e7ce5d 100644 --- a/lib/std/c/solaris.zig +++ b/lib/std/c/solaris.zig @@ -798,10 +798,10 @@ pub const winsize = extern struct { const NSIG = 75; pub const SIG = struct { - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); - pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(2)); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); + pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(2); pub const WORDS = 4; pub const MAXSIG = 75; @@ -874,7 +874,7 @@ pub const SIG = struct { /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. pub const Sigaction = extern struct { - pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; + pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; /// signal options diff --git a/lib/std/meta.zig b/lib/std/meta.zig index f7b418d71d3104abfa82ff0e54ac70e650fc56d8..da0f629748ed53794585a27bba17f743802f6062 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -57,10 +57,9 @@ test stringToEnum { } /// Returns the alignment of type T. -/// Note that if T is a pointer or function type the result is different than -/// the one returned by @alignOf(T). +/// Note that if T is a pointer type the result is different than the one +/// returned by @alignOf(T). /// If T is a pointer type the alignment of the type it points to is returned. -/// If T is a function type the alignment a target-dependent value is returned. pub fn alignment(comptime T: type) comptime_int { return switch (@typeInfo(T)) { .Optional => |info| switch (@typeInfo(info.child)) { @@ -68,7 +67,6 @@ pub fn alignment(comptime T: type) comptime_int { else => @alignOf(T), }, .Pointer => |info| info.alignment, - .Fn => |info| info.alignment, else => @alignOf(T), }; } @@ -80,7 +78,8 @@ test alignment { try testing.expect(alignment([]align(1) u8) == 1); try testing.expect(alignment([]align(2) u8) == 2); try testing.expect(alignment(fn () void) > 0); - try testing.expect(alignment(fn () align(128) void) == 128); + try testing.expect(alignment(*const fn () void) > 0); + try testing.expect(alignment(*align(128) const fn () void) == 128); } /// Given a parameterized type (array, vector, pointer, optional), returns the "child type". diff --git a/lib/std/os/emscripten.zig b/lib/std/os/emscripten.zig index 04c3996f152f2087b8da8c90b5b01fcdba26539d..924b2dd0b21daee49444fee993176758d5e47fc6 100644 --- a/lib/std/os/emscripten.zig +++ b/lib/std/os/emscripten.zig @@ -689,13 +689,13 @@ pub const SIG = struct { pub const SYS = 31; pub const UNUSED = SIG.SYS; - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(std.math.maxInt(usize))); - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(std.math.maxInt(usize)); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); }; pub const Sigaction = extern struct { - pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; + pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; handler: extern union { diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 3892e4326a558deae3c14e9ff4df6ea8ebbf4de9..a5cdab18ce8103a60c56b99994a22fe632fb15a2 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1327,16 +1327,14 @@ pub fn flock(fd: fd_t, operation: i32) usize { return syscall2(.flock, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, operation)))); } -var vdso_clock_gettime = @as(?*const anyopaque, @ptrCast(&init_vdso_clock_gettime)); - // We must follow the C calling convention when we call into the VDSO -const vdso_clock_gettime_ty = *align(1) const fn (i32, *timespec) callconv(.C) usize; +const VdsoClockGettime = *align(1) const fn (i32, *timespec) callconv(.C) usize; +var vdso_clock_gettime: ?VdsoClockGettime = &init_vdso_clock_gettime; pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { if (@hasDecl(VDSO, "CGT_SYM")) { - const ptr = @atomicLoad(?*const anyopaque, &vdso_clock_gettime, .unordered); - if (ptr) |fn_ptr| { - const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr)); + const ptr = @atomicLoad(?VdsoClockGettime, &vdso_clock_gettime, .unordered); + if (ptr) |f| { const rc = f(clk_id, tp); switch (rc) { 0, @as(usize, @bitCast(-@as(isize, @intFromEnum(E.INVAL)))) => return rc, @@ -1348,15 +1346,12 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { } fn init_vdso_clock_gettime(clk: i32, ts: *timespec) callconv(.C) usize { - const ptr = @as(?*const anyopaque, @ptrFromInt(vdso.lookup(VDSO.CGT_VER, VDSO.CGT_SYM))); + const ptr: ?VdsoClockGettime = @ptrFromInt(vdso.lookup(VDSO.CGT_VER, VDSO.CGT_SYM)); // Note that we may not have a VDSO at all, update the stub address anyway // so that clock_gettime will fall back on the good old (and slow) syscall - @atomicStore(?*const anyopaque, &vdso_clock_gettime, ptr, .monotonic); + @atomicStore(?VdsoClockGettime, &vdso_clock_gettime, ptr, .monotonic); // Call into the VDSO if available - if (ptr) |fn_ptr| { - const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr)); - return f(clk, ts); - } + if (ptr) |f| return f(clk, ts); return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.NOSYS)))); } @@ -2516,9 +2511,9 @@ pub const SIG = if (is_mips) struct { pub const SYS = 31; pub const UNUSED = SIG.SYS; - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); } else if (is_sparc) struct { pub const BLOCK = 1; pub const UNBLOCK = 2; @@ -2560,9 +2555,9 @@ pub const SIG = if (is_mips) struct { pub const PWR = LOST; pub const IO = SIG.POLL; - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); } else struct { pub const BLOCK = 0; pub const UNBLOCK = 1; @@ -2603,9 +2598,9 @@ pub const SIG = if (is_mips) struct { pub const SYS = 31; pub const UNUSED = SIG.SYS; - pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); - pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); - pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); + pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); + pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); + pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); }; pub const kernel_rwf = u32; @@ -3709,7 +3704,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30; const k_sigaction_funcs = struct { - const handler = ?*const fn (c_int) align(1) callconv(.C) void; + const handler = ?*align(1) const fn (c_int) callconv(.C) void; const restorer = *const fn () callconv(.C) void; }; @@ -3736,7 +3731,7 @@ pub const k_sigaction = switch (native_arch) { /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. pub const Sigaction = extern struct { - pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; + pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; handler: extern union { diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index 364e49ae8fba5fdea98e35009e9422efccded89f..54efe22b8d623c06bdd5b682354436bc766ba371 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -1369,16 +1369,16 @@ fn fnProtoExpr( break :is_var_args false; }; - const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { - break :inst try expr(&block_scope, scope, coerced_align_ri, fn_proto.ast.align_expr); - }; + if (fn_proto.ast.align_expr != 0) { + return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{}); + } if (fn_proto.ast.addrspace_expr != 0) { - return astgen.failNode(fn_proto.ast.addrspace_expr, "addrspace not allowed on function prototypes", .{}); + return astgen.failNode(fn_proto.ast.addrspace_expr, "function type cannot have an addrspace", .{}); } if (fn_proto.ast.section_expr != 0) { - return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{}); + return astgen.failNode(fn_proto.ast.section_expr, "function type cannot have a linksection", .{}); } const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) @@ -1394,7 +1394,7 @@ fn fnProtoExpr( const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; const is_inferred_error = token_tags[maybe_bang] == .bang; if (is_inferred_error) { - return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); + return astgen.failTok(maybe_bang, "function type cannot have an inferred error set", .{}); } const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type); @@ -1403,7 +1403,7 @@ fn fnProtoExpr( .cc_ref = cc, .cc_gz = null, - .align_ref = align_ref, + .align_ref = .none, .align_gz = null, .ret_ref = ret_ty, .ret_gz = null, diff --git a/src/InternPool.zig b/src/InternPool.zig index 832927071e24bd66bdb609752ff7e82efff20adf..8611a6756476cd92a728254c3319b2c07706e3c7 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -765,16 +765,10 @@ pub const Key = union(enum) { /// Tells whether a parameter is noalias. See `paramIsNoalias` helper /// method for accessing this. noalias_bits: u32, - /// `none` indicates the function has the default alignment for - /// function code on the target. In this case, this field *must* be set - /// to `none`, otherwise the `InternPool` equality and hashing - /// functions will return incorrect results. - alignment: Alignment, cc: std.builtin.CallingConvention, is_var_args: bool, is_generic: bool, is_noinline: bool, - align_is_generic: bool, cc_is_generic: bool, section_is_generic: bool, addrspace_is_generic: bool, @@ -794,7 +788,6 @@ pub const Key = union(enum) { a.return_type == b.return_type and a.comptime_bits == b.comptime_bits and a.noalias_bits == b.noalias_bits and - a.alignment == b.alignment and a.cc == b.cc and a.is_var_args == b.is_var_args and a.is_generic == b.is_generic and @@ -808,7 +801,6 @@ pub const Key = union(enum) { std.hash.autoHash(hasher, self.return_type); std.hash.autoHash(hasher, self.comptime_bits); std.hash.autoHash(hasher, self.noalias_bits); - std.hash.autoHash(hasher, self.alignment); std.hash.autoHash(hasher, self.cc); std.hash.autoHash(hasher, self.is_var_args); std.hash.autoHash(hasher, self.is_generic); @@ -3587,18 +3579,16 @@ pub const Tag = enum(u8) { flags: Flags, pub const Flags = packed struct(u32) { - alignment: Alignment, cc: std.builtin.CallingConvention, is_var_args: bool, is_generic: bool, has_comptime_bits: bool, has_noalias_bits: bool, is_noinline: bool, - align_is_generic: bool, cc_is_generic: bool, section_is_generic: bool, addrspace_is_generic: bool, - _: u9 = 0, + _: u16 = 0, }; }; @@ -4918,11 +4908,9 @@ fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType { .return_type = type_function.data.return_type, .comptime_bits = comptime_bits, .noalias_bits = noalias_bits, - .alignment = type_function.data.flags.alignment, .cc = type_function.data.flags.cc, .is_var_args = type_function.data.flags.is_var_args, .is_noinline = type_function.data.flags.is_noinline, - .align_is_generic = type_function.data.flags.align_is_generic, .cc_is_generic = type_function.data.flags.cc_is_generic, .section_is_generic = type_function.data.flags.section_is_generic, .addrspace_is_generic = type_function.data.flags.addrspace_is_generic, @@ -6211,8 +6199,6 @@ pub const GetFuncTypeKey = struct { comptime_bits: u32 = 0, noalias_bits: u32 = 0, /// `null` means generic. - alignment: ?Alignment = .none, - /// `null` means generic. cc: ?std.builtin.CallingConvention = .Unspecified, is_var_args: bool = false, is_generic: bool = false, @@ -6242,14 +6228,12 @@ pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocat .params_len = params_len, .return_type = key.return_type, .flags = .{ - .alignment = key.alignment orelse .none, .cc = key.cc orelse .Unspecified, .is_var_args = key.is_var_args, .has_comptime_bits = key.comptime_bits != 0, .has_noalias_bits = key.noalias_bits != 0, .is_generic = key.is_generic, .is_noinline = key.is_noinline, - .align_is_generic = key.alignment == null, .cc_is_generic = key.cc == null, .section_is_generic = key.section_is_generic, .addrspace_is_generic = key.addrspace_is_generic, @@ -6433,14 +6417,12 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A .params_len = params_len, .return_type = @enumFromInt(ip.items.len - 2), .flags = .{ - .alignment = key.alignment orelse .none, .cc = key.cc orelse .Unspecified, .is_var_args = key.is_var_args, .has_comptime_bits = key.comptime_bits != 0, .has_noalias_bits = key.noalias_bits != 0, .is_generic = key.is_generic, .is_noinline = key.is_noinline, - .align_is_generic = key.alignment == null, .cc_is_generic = key.cc == null, .section_is_generic = key.section_is_generic, .addrspace_is_generic = key.addrspace_is_generic, @@ -6553,7 +6535,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) .param_types = arg.param_types, .return_type = arg.bare_return_type, .noalias_bits = arg.noalias_bits, - .alignment = arg.alignment, .cc = arg.cc, .is_noinline = arg.is_noinline, }); @@ -6610,6 +6591,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) func_index, func_extra_index, func_ty, + arg.alignment, arg.section, ); } @@ -6673,14 +6655,12 @@ pub fn getFuncInstanceIes( .params_len = params_len, .return_type = error_union_type, .flags = .{ - .alignment = arg.alignment, .cc = arg.cc, .is_var_args = false, .has_comptime_bits = false, .has_noalias_bits = arg.noalias_bits != 0, .is_generic = false, .is_noinline = arg.is_noinline, - .align_is_generic = false, .cc_is_generic = false, .section_is_generic = false, .addrspace_is_generic = false, @@ -6741,6 +6721,7 @@ pub fn getFuncInstanceIes( func_index, func_extra_index, func_ty, + arg.alignment, arg.section, ); } @@ -6752,6 +6733,7 @@ fn finishFuncInstance( func_index: Index, func_extra_index: u32, func_ty: Index, + alignment: Alignment, section: OptionalNullTerminatedString, ) Allocator.Error!Index { const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner)); @@ -6764,7 +6746,7 @@ fn finishFuncInstance( .owns_tv = true, .ty = @import("type.zig").Type.fromInterned(func_ty), .val = @import("Value.zig").fromInterned(func_index), - .alignment = .none, + .alignment = alignment, .@"linksection" = section, .@"addrspace" = fn_owner_decl.@"addrspace", .analysis = .complete, diff --git a/src/Module.zig b/src/Module.zig index 8f6def21ae6d04d05c6152c6450cfbc1ad0b0c6f..bfc5a35e101ae6f3a0c099369e32f235fc42b81d 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3596,6 +3596,18 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)}); + const old_has_tv = decl.has_tv; + // The following values are ignored if `!old_has_tv` + const old_ty = decl.ty; + const old_val = decl.val; + const old_align = decl.alignment; + const old_linksection = decl.@"linksection"; + const old_addrspace = decl.@"addrspace"; + const old_is_inline = if (decl.getOwnedFunction(mod)) |prev_func| + prev_func.analysis(ip).state == .inline_only + else + false; + const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip); const gpa = mod.gpa; @@ -3733,141 +3745,96 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { }; } - switch (ip.indexToKey(decl_tv.val.toIntern())) { - .func => |func| { - const owns_tv = func.owner_decl == decl_index; - if (owns_tv) { - var prev_type_has_bits = false; - var prev_is_inline = false; - var type_changed = true; - - if (decl.has_tv) { - prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(mod); - type_changed = !decl.ty.eql(decl_tv.ty, mod); - if (decl.getOwnedFunction(mod)) |prev_func| { - prev_is_inline = prev_func.analysis(ip).state == .inline_only; - } - } - - decl.ty = decl_tv.ty; - decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); - // linksection, align, and addrspace were already set by Sema - decl.has_tv = true; - decl.owns_tv = owns_tv; - decl.analysis = .complete; - - const is_inline = decl.ty.fnCallingConvention(mod) == .Inline; - if (decl.is_exported) { - const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) }; - if (is_inline) { - return sema.fail(&block_scope, export_src, "export of inline function", .{}); - } - // The scope needs to have the decl in it. - try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); - } - // TODO: align, linksection, addrspace? - const changed = type_changed or is_inline != prev_is_inline; - return .{ - .invalidate_decl_val = changed, - .invalidate_decl_ref = changed, - }; - } - }, - else => {}, - } - - decl.owns_tv = false; - var queue_linker_work = false; - var is_extern = false; + var queue_linker_work = true; + var is_func = false; + var is_inline = false; switch (decl_tv.val.toIntern()) { .generic_poison => unreachable, .unreachable_value => unreachable, else => switch (ip.indexToKey(decl_tv.val.toIntern())) { - .variable => |variable| if (variable.decl == decl_index) { - decl.owns_tv = true; - queue_linker_work = true; + .variable => |variable| { + decl.owns_tv = variable.decl == decl_index; + queue_linker_work = decl.owns_tv; }, - .extern_func => |extern_fn| if (extern_fn.decl == decl_index) { - decl.owns_tv = true; - queue_linker_work = true; - is_extern = true; + .extern_func => |extern_func| { + decl.owns_tv = extern_func.decl == decl_index; + queue_linker_work = decl.owns_tv; + is_func = decl.owns_tv; }, - .func => {}, - - else => { - queue_linker_work = true; + .func => |func| { + decl.owns_tv = func.owner_decl == decl_index; + queue_linker_work = false; + is_inline = decl.owns_tv and decl_tv.ty.fnCallingConvention(mod) == .Inline; + is_func = decl.owns_tv; }, + + else => {}, }, } - const old_has_tv = decl.has_tv; - // The following values are ignored if `!old_has_tv` - const old_ty = decl.ty; - const old_val = decl.val; - const old_align = decl.alignment; - const old_linksection = decl.@"linksection"; - const old_addrspace = decl.@"addrspace"; - decl.ty = decl_tv.ty; decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); - decl.alignment = blk: { - const align_body = decl_bodies.align_body orelse break :blk .none; - const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst); - break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref); - }; - decl.@"linksection" = blk: { - const linksection_body = decl_bodies.linksection_body orelse break :blk .none; - const linksection_ref = try sema.resolveInlineBody(&block_scope, linksection_body, decl_inst); - const bytes = try sema.toConstString(&block_scope, section_src, linksection_ref, .{ - .needed_comptime_reason = "linksection must be comptime-known", - }); - if (mem.indexOfScalar(u8, bytes, 0) != null) { - return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); - } else if (bytes.len == 0) { - return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); - } - const section = try ip.getOrPutString(gpa, bytes); - break :blk section.toOptional(); - }; - decl.@"addrspace" = blk: { - const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) { - .variable => .variable, - .extern_func, .func => .function, - else => .constant, + // Function linksection, align, and addrspace were already set by Sema + if (!is_func) { + decl.alignment = blk: { + const align_body = decl_bodies.align_body orelse break :blk .none; + const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst); + break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref); }; + decl.@"linksection" = blk: { + const linksection_body = decl_bodies.linksection_body orelse break :blk .none; + const linksection_ref = try sema.resolveInlineBody(&block_scope, linksection_body, decl_inst); + const bytes = try sema.toConstString(&block_scope, section_src, linksection_ref, .{ + .needed_comptime_reason = "linksection must be comptime-known", + }); + if (mem.indexOfScalar(u8, bytes, 0) != null) { + return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); + } else if (bytes.len == 0) { + return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); + } + const section = try ip.getOrPutString(gpa, bytes); + break :blk section.toOptional(); + }; + decl.@"addrspace" = blk: { + const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) { + .variable => .variable, + .extern_func, .func => .function, + else => .constant, + }; - const target = sema.mod.getTarget(); + const target = sema.mod.getTarget(); - const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) { - .function => target_util.defaultAddressSpace(target, .function), - .variable => target_util.defaultAddressSpace(target, .global_mutable), - .constant => target_util.defaultAddressSpace(target, .global_constant), - else => unreachable, + const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) { + .function => target_util.defaultAddressSpace(target, .function), + .variable => target_util.defaultAddressSpace(target, .global_mutable), + .constant => target_util.defaultAddressSpace(target, .global_constant), + else => unreachable, + }; + const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst); + break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx); }; - const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst); - break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx); - }; + } decl.has_tv = true; decl.analysis = .complete; const result: SemaDeclResult = if (old_has_tv) .{ - .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or !decl.val.eql(old_val, decl.ty, mod), + .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or + !decl.val.eql(old_val, decl.ty, mod) or + is_inline != old_is_inline, .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or decl.alignment != old_align or decl.@"linksection" != old_linksection or - decl.@"addrspace" != old_addrspace, + decl.@"addrspace" != old_addrspace or + is_inline != old_is_inline, } else .{ .invalidate_decl_val = true, .invalidate_decl_ref = true, }; - const has_runtime_bits = is_extern or - (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty)); - + const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl.ty)); if (has_runtime_bits) { - // Needed for codegen_decl which will call updateDecl and then the // codegen backend wants full access to the Decl Type. try sema.resolveTypeFully(decl.ty); @@ -3881,6 +3848,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { if (decl.is_exported) { const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) }; + if (is_inline) return sema.fail(&block_scope, export_src, "export of inline function", .{}); // The scope needs to have the decl in it. try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); } diff --git a/src/Sema.zig b/src/Sema.zig index 54d5e6df7dae06ab5b8a75b3059caa4ad7350aab..cf103e7230915b248b42e519c230f275b31c62a8 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7605,7 +7605,6 @@ fn analyzeCall( .param_types = new_param_types, .return_type = owner_info.return_type, .noalias_bits = owner_info.noalias_bits, - .alignment = if (owner_info.align_is_generic) null else owner_info.alignment, .cc = if (owner_info.cc_is_generic) null else owner_info.cc, .is_var_args = owner_info.is_var_args, .is_noinline = owner_info.is_noinline, @@ -9629,7 +9628,6 @@ fn funcCommon( .comptime_bits = comptime_bits, .return_type = bare_return_type.toIntern(), .cc = cc, - .alignment = alignment, .section_is_generic = section == .generic, .addrspace_is_generic = address_space == null, .is_var_args = var_args, @@ -9640,6 +9638,7 @@ fn funcCommon( if (is_extern) { assert(comptime_bits == 0); assert(cc != null); + assert(alignment != null); assert(section != .generic); assert(address_space != null); assert(!is_generic); @@ -17623,8 +17622,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const field_values = .{ // calling_convention: CallingConvention, (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(), - // alignment: comptime_int, - (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod).toByteUnits(0))).toIntern(), // is_generic: bool, Value.makeBool(func_ty_info.is_generic).toIntern(), // is_var_args: bool, @@ -19701,12 +19698,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (inst_data.size != .One) { return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{}); } - const fn_align = mod.typeToFunc(elem_ty).?.alignment; - if (inst_data.flags.has_align and abi_align != .none and fn_align != .none and - abi_align != fn_align) - { - return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{}); - } } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); } else if (inst_data.size == .C) { @@ -21030,7 +21021,6 @@ fn zirReify( .needed_comptime_reason = "operand to @Type must be comptime-known", }); const union_val = ip.indexToKey(val.toIntern()).un; - const target = mod.getTarget(); if (try Value.fromInterned(union_val.val).anyUndef(mod)) return sema.failWithUseOfUndef(block, src); const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?; switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { @@ -21171,12 +21161,6 @@ fn zirReify( if (ptr_size != .One) { return sema.fail(block, src, "function pointers must be single pointers", .{}); } - const fn_align = mod.typeToFunc(elem_ty).?.alignment; - if (abi_align != .none and fn_align != .none and - abi_align != fn_align) - { - return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{}); - } } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); } else if (ptr_size == .C) { @@ -21429,10 +21413,6 @@ fn zirReify( ip, try ip.getOrPutString(gpa, "calling_convention"), ).?); - const alignment_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex( - ip, - try ip.getOrPutString(gpa, "alignment"), - ).?); const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex( ip, try ip.getOrPutString(gpa, "is_generic"), @@ -21461,11 +21441,6 @@ fn zirReify( try sema.checkCallConvSupportsVarArgs(block, src, cc); } - const alignment = alignment: { - const alignment = try sema.validateAlignAllowZero(block, src, try alignment_val.toUnsignedIntAdvanced(sema)); - const default = target_util.defaultFunctionAlignment(target); - break :alignment if (alignment == default) .none else alignment; - }; const return_type = return_type_val.optionalValue(mod) orelse return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); @@ -21510,7 +21485,6 @@ fn zirReify( .param_types = param_types, .noalias_bits = noalias_bits, .return_type = return_type.toIntern(), - .alignment = alignment, .cc = cc, .is_var_args = is_var_args, }); @@ -32536,16 +32510,21 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn const mod = sema.mod; try sema.ensureDeclAnalyzed(decl_index); - const decl = mod.declPtr(decl_index); - const decl_tv = try decl.typedValue(); + const decl_tv = try mod.declPtr(decl_index).typedValue(); + const owner_decl = mod.declPtr(switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) { + .variable => |variable| variable.decl, + .extern_func => |extern_func| extern_func.decl, + .func => |func| func.owner_decl, + else => decl_index, + }); // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type try sema.declareDependency(.{ .decl_val = decl_index }); const ptr_ty = try sema.ptrType(.{ .child = decl_tv.ty.toIntern(), .flags = .{ - .alignment = decl.alignment, - .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true, - .address_space = decl.@"addrspace", + .alignment = owner_decl.alignment, + .is_const = if (decl_tv.val.getVariable(mod)) |variable| variable.is_const else true, + .address_space = owner_decl.@"addrspace", }, }); if (analyze_fn_body) { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 8d630480e2e65080abacb9029610fd632d91d6cc..928cc995dc67595e951bd34d9c5bf04f4ae48cb1 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1635,7 +1635,7 @@ pub const DeclGen = struct { switch (kind) { .forward => {}, - .complete => if (fn_info.alignment.toByteUnitsOptional()) |a| { + .complete => if (fn_decl.alignment.toByteUnitsOptional()) |a| { try w.print("{}zig_align_fn({})", .{ trailing, a }); trailing = .maybe_space; }, @@ -1666,7 +1666,7 @@ pub const DeclGen = struct { switch (kind) { .forward => { - if (fn_info.alignment.toByteUnitsOptional()) |a| { + if (fn_decl.alignment.toByteUnitsOptional()) |a| { try w.print(" zig_align_fn({})", .{a}); } switch (name) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 2a5a187e0d8b2d4af88377d5bd97ae4818b1bcef..909f5b056fcf2a2365413b05406146ae170f9724 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2949,8 +2949,8 @@ pub const Object = struct { else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder), } - if (fn_info.alignment != .none) - function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder); + if (decl.alignment != .none) + function_index.setAlignment(decl.alignment.toLlvm(), &o.builder); // Function attributes that are independent of analysis results of the function body. try o.addCommonFnAttributes(&attributes, owner_mod); diff --git a/src/type.zig b/src/type.zig index 664498e353d6e6902bc0d65437b5f15a65bc872d..9ea16d6224f6196a48315544fd3b80fe023b22c8 100644 --- a/src/type.zig +++ b/src/type.zig @@ -396,9 +396,6 @@ pub const Type = struct { try writer.writeAll("..."); } try writer.writeAll(") "); - if (fn_info.alignment.toByteUnitsOptional()) |a| { - try writer.print("align({d}) ", .{a}); - } if (fn_info.cc != .Unspecified) { try writer.writeAll("callconv(."); try writer.writeAll(@tagName(fn_info.cc)); @@ -949,12 +946,7 @@ pub const Type = struct { }, // represents machine code; not a pointer - .func_type => |func_type| return .{ - .scalar = if (func_type.alignment != .none) - func_type.alignment - else - target_util.defaultFunctionAlignment(target), - }, + .func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) }, .simple_type => |t| switch (t) { .bool, diff --git a/test/behavior/align.zig b/test/behavior/align.zig index e00fbe67443f0bf13281cc15d06f69653beaead3..671e46501a130f565c9a6a362b9f85acdb1decb1 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -311,12 +311,6 @@ test "page aligned array on stack" { try expect(number2 == 43); } -fn derp() align(@sizeOf(usize) * 2) i32 { - return 1234; -} -fn noop1() align(1) void {} -fn noop4() align(4) void {} - test "function alignment" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -325,11 +319,25 @@ test "function alignment" { // function alignment is a compile error on wasm32/wasm64 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; - try expect(derp() == 1234); - try expect(@TypeOf(noop1) == fn () align(1) void); - try expect(@TypeOf(noop4) == fn () align(4) void); - noop1(); - noop4(); + const S = struct { + fn alignExpr() align(@sizeOf(usize) * 2) i32 { + return 1234; + } + fn align1() align(1) void {} + fn align4() align(4) void {} + }; + + try expect(S.alignExpr() == 1234); + try expect(@TypeOf(S.alignExpr) == fn () i32); + try expect(@TypeOf(&S.alignExpr) == *align(@sizeOf(usize) * 2) const fn () i32); + + S.align1(); + try expect(@TypeOf(S.align1) == fn () void); + try expect(@TypeOf(&S.align1) == *align(1) const fn () void); + + S.align4(); + try expect(@TypeOf(S.align4) == fn () void); + try expect(@TypeOf(&S.align4) == *align(4) const fn () void); } test "implicitly decreasing fn alignment" { @@ -345,7 +353,7 @@ test "implicitly decreasing fn alignment" { try testImplicitlyDecreaseFnAlign(alignedBig, 5678); } -fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(1) i32, answer: i32) !void { +fn testImplicitlyDecreaseFnAlign(ptr: *align(1) const fn () i32, answer: i32) !void { try expect(ptr() == answer); } @@ -368,10 +376,10 @@ test "@alignCast functions" { try expect(fnExpectsOnly1(simple4) == 0x19); } -fn fnExpectsOnly1(ptr: *const fn () align(1) i32) i32 { +fn fnExpectsOnly1(ptr: *align(1) const fn () i32) i32 { return fnExpects4(@alignCast(ptr)); } -fn fnExpects4(ptr: *const fn () align(4) i32) i32 { +fn fnExpects4(ptr: *align(4) const fn () i32) i32 { return ptr(); } fn simple4() align(4) i32 { diff --git a/test/behavior/type.zig b/test/behavior/type.zig index da42672be6d7473a9db8c3d707549cc14ef51c19..c9290ecc31ec877f00d9f9d3895d86dccbfb98b8 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -527,7 +527,6 @@ test "Type.Fn" { { const fn_info = std.builtin.Type{ .Fn = .{ .calling_convention = .C, - .alignment = 0, .is_generic = false, .is_var_args = false, .return_type = void, @@ -643,7 +642,6 @@ test "reified function type params initialized with field pointer" { const Bar = @Type(.{ .Fn = .{ .calling_convention = .Unspecified, - .alignment = 0, .is_generic = false, .is_var_args = false, .return_type = void, diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index d4e3eb3b833cedb0ed96d2477a25323dc933d97f..0d54b14c390c9aaabeb20d04a4876ad7ba282fd4 100644 --- a/test/behavior/type_info.zig +++ b/test/behavior/type_info.zig @@ -356,16 +356,38 @@ test "type info: function type info" { } fn testFunction() !void { - const fn_info = @typeInfo(@TypeOf(typeInfoFoo)); - try expect(fn_info == .Fn); - try expect(fn_info.Fn.alignment > 0); - try expect(fn_info.Fn.calling_convention == .C); - try expect(!fn_info.Fn.is_generic); - try expect(fn_info.Fn.params.len == 2); - try expect(fn_info.Fn.is_var_args); - try expect(fn_info.Fn.return_type.? == usize); - const fn_aligned_info = @typeInfo(@TypeOf(typeInfoFooAligned)); - try expect(fn_aligned_info.Fn.alignment == 4); + const foo_fn_type = @TypeOf(typeInfoFoo); + const foo_fn_info = @typeInfo(foo_fn_type); + try expect(foo_fn_info.Fn.calling_convention == .C); + try expect(!foo_fn_info.Fn.is_generic); + try expect(foo_fn_info.Fn.params.len == 2); + try expect(foo_fn_info.Fn.is_var_args); + try expect(foo_fn_info.Fn.return_type.? == usize); + const foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFoo)); + try expect(foo_ptr_fn_info.Pointer.size == .One); + try expect(foo_ptr_fn_info.Pointer.is_const); + try expect(!foo_ptr_fn_info.Pointer.is_volatile); + try expect(foo_ptr_fn_info.Pointer.address_space == .generic); + try expect(foo_ptr_fn_info.Pointer.child == foo_fn_type); + try expect(!foo_ptr_fn_info.Pointer.is_allowzero); + try expect(foo_ptr_fn_info.Pointer.sentinel == null); + + const aligned_foo_fn_type = @TypeOf(typeInfoFooAligned); + const aligned_foo_fn_info = @typeInfo(aligned_foo_fn_type); + try expect(aligned_foo_fn_info.Fn.calling_convention == .C); + try expect(!aligned_foo_fn_info.Fn.is_generic); + try expect(aligned_foo_fn_info.Fn.params.len == 2); + try expect(aligned_foo_fn_info.Fn.is_var_args); + try expect(aligned_foo_fn_info.Fn.return_type.? == usize); + const aligned_foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFooAligned)); + try expect(aligned_foo_ptr_fn_info.Pointer.size == .One); + try expect(aligned_foo_ptr_fn_info.Pointer.is_const); + try expect(!aligned_foo_ptr_fn_info.Pointer.is_volatile); + try expect(aligned_foo_ptr_fn_info.Pointer.alignment == 4); + try expect(aligned_foo_ptr_fn_info.Pointer.address_space == .generic); + try expect(aligned_foo_ptr_fn_info.Pointer.child == aligned_foo_fn_type); + try expect(!aligned_foo_ptr_fn_info.Pointer.is_allowzero); + try expect(aligned_foo_ptr_fn_info.Pointer.sentinel == null); } extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.C) usize; diff --git a/test/behavior/typename.zig b/test/behavior/typename.zig index 80c9a0619ea11087bad517150aac39f9e0beed75..c3eefc8de775064b5137fb85dcb4be017fa4ba71 100644 --- a/test/behavior/typename.zig +++ b/test/behavior/typename.zig @@ -78,11 +78,9 @@ test "basic" { try expectEqualStrings("fn (comptime u32) void", @typeName(fn (comptime u32) void)); try expectEqualStrings("fn (noalias []u8) void", @typeName(fn (noalias []u8) void)); - try expectEqualStrings("fn () align(32) void", @typeName(fn () align(32) void)); try expectEqualStrings("fn () callconv(.C) void", @typeName(fn () callconv(.C) void)); - try expectEqualStrings("fn () align(32) callconv(.C) void", @typeName(fn () align(32) callconv(.C) void)); - try expectEqualStrings("fn (...) align(32) callconv(.C) void", @typeName(fn (...) align(32) callconv(.C) void)); - try expectEqualStrings("fn (u32, ...) align(32) callconv(.C) void", @typeName(fn (u32, ...) align(32) callconv(.C) void)); + try expectEqualStrings("fn (...) callconv(.C) void", @typeName(fn (...) callconv(.C) void)); + try expectEqualStrings("fn (u32, ...) callconv(.C) void", @typeName(fn (u32, ...) callconv(.C) void)); } test "top level decl" { diff --git a/test/cases/compile_errors/function_ptr_alignment.zig b/test/cases/compile_errors/function_ptr_alignment.zig index 995ef8d9b1cbf8035e36a3745287146d5fe416f1..cf97e61f40147ef636bd7536d9a6cab0783a6b71 100644 --- a/test/cases/compile_errors/function_ptr_alignment.zig +++ b/test/cases/compile_errors/function_ptr_alignment.zig @@ -1,28 +1,16 @@ -comptime { - var a: *align(2) @TypeOf(foo) = undefined; - _ = &a; -} -fn foo() void {} +fn align1() align(1) void {} +fn align2() align(2) void {} comptime { - var a: *align(1) fn () void = undefined; - _ = &a; -} -comptime { - var a: *align(2) fn () align(2) void = undefined; - _ = &a; -} -comptime { - var a: *align(2) fn () void = undefined; - _ = &a; -} -comptime { - var a: *align(1) fn () align(2) void = undefined; - _ = &a; + _ = @as(*align(1) const fn () void, &align2); + _ = @as(*align(1) const fn () void, &align1); + _ = @as(*align(2) const fn () void, &align2); + _ = @as(*align(2) const fn () void, &align1); } // error // backend=stage2 // target=native // -// :20:19: error: function pointer alignment disagrees with function alignment +// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void' +// :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2' diff --git a/test/cases/compile_errors/inferring_error_set_of_function_pointer.zig b/test/cases/compile_errors/inferring_error_set_of_function_pointer.zig deleted file mode 100644 index ce1b2763609a599e8597db7d91c5eb92250109f2..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/inferring_error_set_of_function_pointer.zig +++ /dev/null @@ -1,9 +0,0 @@ -comptime { - const z: ?fn () !void = null; -} - -// error -// backend=stage2 -// target=native -// -// :2:21: error: function prototype may not have inferred error set diff --git a/test/cases/compile_errors/invalid_function_types.zig b/test/cases/compile_errors/invalid_function_types.zig new file mode 100644 index 0000000000000000000000000000000000000000..e4553d22f12d2a14a5483d17605ca448dc0af863 --- /dev/null +++ b/test/cases/compile_errors/invalid_function_types.zig @@ -0,0 +1,25 @@ +comptime { + _ = fn name() void; +} +comptime { + _ = fn () align(128) void; +} +comptime { + _ = fn () addrspace(.generic) void; +} +comptime { + _ = fn () linksection("section") void; +} +comptime { + _ = fn () !void; +} + +// error +// backend=stage2 +// target=native +// +// :2:12: error: function type cannot have a name +// :5:21: error: function type cannot have an alignment +// :8:26: error: function type cannot have an addrspace +// :11:27: error: function type cannot have a linksection +// :14:15: error: function type cannot have an inferred error set diff --git a/test/cases/compile_errors/passing_an_under-aligned_function_pointer.zig b/test/cases/compile_errors/passing_an_under-aligned_function_pointer.zig index c6b06f7329a9a6f17cd909f054ffe4fc4c505908..e37441563b07b77cee89c438bbbb8fb3c1c05549 100644 --- a/test/cases/compile_errors/passing_an_under-aligned_function_pointer.zig +++ b/test/cases/compile_errors/passing_an_under-aligned_function_pointer.zig @@ -1,7 +1,7 @@ export fn entry() void { testImplicitlyDecreaseFnAlign(alignedSmall, 1234); } -fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(8) i32, answer: i32) void { +fn testImplicitlyDecreaseFnAlign(ptr: *align(8) const fn () i32, answer: i32) void { if (ptr() != answer) unreachable; } fn alignedSmall() align(4) i32 { @@ -12,5 +12,5 @@ fn alignedSmall() align(4) i32 { // backend=stage2 // target=x86_64-linux // -// :2:35: error: expected type '*const fn () align(8) i32', found '*const fn () align(4) i32' +// :2:35: error: expected type '*align(8) const fn () i32', found '*align(4) const fn () i32' // :2:35: note: pointer alignment '4' cannot cast into pointer alignment '8' diff --git a/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig b/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig index bb2c4bbe628278de38d5ebc2c4731930a9ee7fcb..4ac1312440bba2e8fa69c3c1de8ed09927025c20 100644 --- a/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig +++ b/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig @@ -1,7 +1,6 @@ const Foo = @Type(.{ .Fn = .{ .calling_convention = .Unspecified, - .alignment = 0, .is_generic = true, .is_var_args = false, .return_type = u0, diff --git a/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig index 678fbe3ed7be8a3110b5a8e73fb5a55b174cd7bc..23ea4f209521c2c69f38662e63d8cf9c0586e878 100644 --- a/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig +++ b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig @@ -1,7 +1,6 @@ const Foo = @Type(.{ .Fn = .{ .calling_convention = .Unspecified, - .alignment = 0, .is_generic = false, .is_var_args = true, .return_type = u0, diff --git a/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig b/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig index d348a0c908a042ae3ba3cfb17ee70f49d0d2fd95..073cf0f4ccf7ed617b6514bae74e9850dd6c8301 100644 --- a/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig +++ b/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig @@ -1,7 +1,6 @@ const Foo = @Type(.{ .Fn = .{ .calling_convention = .Unspecified, - .alignment = 0, .is_generic = false, .is_var_args = false, .return_type = null, -- 2.54.0