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.
This commit is contained in:
Jacob Young 2024-03-16 16:46:45 +01:00
parent f88a971e4f
commit d10c52c194
30 changed files with 259 additions and 312 deletions

View File

@ -2780,10 +2780,16 @@ fn noop4() align(4) void {}
test "function alignment" { test "function alignment" {
try expect(derp() == 1234); try expect(derp() == 1234);
try expect(@TypeOf(noop1) == fn () align(1) void); try expect(@TypeOf(derp) == fn () i32);
try expect(@TypeOf(noop4) == fn () align(4) void); try expect(@TypeOf(&derp) == *align(@sizeOf(usize) * 2) const fn () i32);
noop1(); noop1();
try expect(@TypeOf(noop1) == fn () void);
try expect(@TypeOf(&noop1) == *align(1) const fn () void);
noop4(); noop4();
try expect(@TypeOf(noop4) == fn () void);
try expect(@TypeOf(&noop4) == *align(4) const fn () void);
} }
{#code_end#} {#code_end#}
<p> <p>

View File

@ -420,7 +420,6 @@ pub const Type = union(enum) {
/// therefore must be kept in sync with the compiler implementation. /// therefore must be kept in sync with the compiler implementation.
pub const Fn = struct { pub const Fn = struct {
calling_convention: CallingConvention, calling_convention: CallingConvention,
alignment: comptime_int,
is_generic: bool, is_generic: bool,
is_var_args: bool, is_var_args: bool,
/// TODO change the language spec to make this not optional. /// TODO change the language spec to make this not optional.

View File

@ -1053,10 +1053,10 @@ pub const sigset_t = u32;
pub const empty_sigset: sigset_t = 0; pub const empty_sigset: sigset_t = 0;
pub const SIG = struct { pub const SIG = struct {
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(5)); pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(5);
/// block specified signal set /// block specified signal set
pub const BLOCK = 1; 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. /// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
pub const Sigaction = extern struct { 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; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
handler: extern union { handler: extern union {

View File

@ -616,9 +616,9 @@ pub const S = struct {
pub const BADSIG = SIG.ERR; pub const BADSIG = SIG.ERR;
pub const SIG = struct { pub const SIG = struct {
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const BLOCK = 1; pub const BLOCK = 1;
pub const UNBLOCK = 2; 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 sig_atomic_t = c_int;
pub const Sigaction = extern struct { 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; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
/// signal handler /// signal handler

View File

@ -695,9 +695,9 @@ pub const SIG = struct {
pub const UNBLOCK = 2; pub const UNBLOCK = 2;
pub const SETMASK = 3; pub const SETMASK = 3;
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const WORDS = 4; pub const WORDS = 4;
pub const MAXSIG = 128; pub const MAXSIG = 128;
@ -1171,7 +1171,7 @@ const NSIG = 32;
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct { 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; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
/// signal handler /// signal handler

View File

@ -441,9 +441,9 @@ pub const SA = struct {
}; };
pub const SIG = struct { pub const SIG = struct {
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
pub const HUP = 1; pub const HUP = 1;
pub const INT = 2; pub const INT = 2;
@ -690,7 +690,7 @@ const NSIG = 32;
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct { 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 /// signal handler
__sigaction_u: extern union { __sigaction_u: extern union {

View File

@ -800,9 +800,9 @@ pub const winsize = extern struct {
const NSIG = 32; const NSIG = 32;
pub const SIG = struct { pub const SIG = struct {
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const WORDS = 4; pub const WORDS = 4;
pub const MAXSIG = 128; pub const MAXSIG = 128;
@ -864,7 +864,7 @@ pub const SIG = struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct { 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; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
/// signal handler /// signal handler

View File

@ -795,11 +795,11 @@ pub const winsize = extern struct {
const NSIG = 33; const NSIG = 33;
pub const SIG = struct { pub const SIG = struct {
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const CATCH = @as(?Sigaction.handler_fn, @ptrFromInt(2)); pub const CATCH: ?Sigaction.handler_fn = @ptrFromInt(2);
pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(3)); pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(3);
pub const HUP = 1; pub const HUP = 1;
pub const INT = 2; pub const INT = 2;
@ -842,7 +842,7 @@ pub const SIG = struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct { 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; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
/// signal handler /// signal handler

View File

@ -798,10 +798,10 @@ pub const winsize = extern struct {
const NSIG = 75; const NSIG = 75;
pub const SIG = struct { pub const SIG = struct {
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(2)); pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(2);
pub const WORDS = 4; pub const WORDS = 4;
pub const MAXSIG = 75; pub const MAXSIG = 75;
@ -874,7 +874,7 @@ pub const SIG = struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct { 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; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
/// signal options /// signal options

View File

@ -57,10 +57,9 @@ test stringToEnum {
} }
/// Returns the alignment of type T. /// Returns the alignment of type T.
/// Note that if T is a pointer or function type the result is different than /// Note that if T is a pointer type the result is different than the one
/// the one returned by @alignOf(T). /// returned by @alignOf(T).
/// If T is a pointer type the alignment of the type it points to is returned. /// 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 { pub fn alignment(comptime T: type) comptime_int {
return switch (@typeInfo(T)) { return switch (@typeInfo(T)) {
.Optional => |info| switch (@typeInfo(info.child)) { .Optional => |info| switch (@typeInfo(info.child)) {
@ -68,7 +67,6 @@ pub fn alignment(comptime T: type) comptime_int {
else => @alignOf(T), else => @alignOf(T),
}, },
.Pointer => |info| info.alignment, .Pointer => |info| info.alignment,
.Fn => |info| info.alignment,
else => @alignOf(T), else => @alignOf(T),
}; };
} }
@ -80,7 +78,8 @@ test alignment {
try testing.expect(alignment([]align(1) u8) == 1); try testing.expect(alignment([]align(1) u8) == 1);
try testing.expect(alignment([]align(2) u8) == 2); try testing.expect(alignment([]align(2) u8) == 2);
try testing.expect(alignment(fn () void) > 0); 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". /// Given a parameterized type (array, vector, pointer, optional), returns the "child type".

View File

@ -689,13 +689,13 @@ pub const SIG = struct {
pub const SYS = 31; pub const SYS = 31;
pub const UNUSED = SIG.SYS; pub const UNUSED = SIG.SYS;
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(std.math.maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(std.math.maxInt(usize));
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
}; };
pub const Sigaction = extern struct { 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; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
handler: extern union { handler: extern union {

View File

@ -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)))); 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 // 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 { pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
if (@hasDecl(VDSO, "CGT_SYM")) { if (@hasDecl(VDSO, "CGT_SYM")) {
const ptr = @atomicLoad(?*const anyopaque, &vdso_clock_gettime, .unordered); const ptr = @atomicLoad(?VdsoClockGettime, &vdso_clock_gettime, .unordered);
if (ptr) |fn_ptr| { if (ptr) |f| {
const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr));
const rc = f(clk_id, tp); const rc = f(clk_id, tp);
switch (rc) { switch (rc) {
0, @as(usize, @bitCast(-@as(isize, @intFromEnum(E.INVAL)))) => return 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 { 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 // 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 // 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 // Call into the VDSO if available
if (ptr) |fn_ptr| { if (ptr) |f| return f(clk, ts);
const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr));
return f(clk, ts);
}
return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.NOSYS)))); 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 SYS = 31;
pub const UNUSED = SIG.SYS; pub const UNUSED = SIG.SYS;
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
} else if (is_sparc) struct { } else if (is_sparc) struct {
pub const BLOCK = 1; pub const BLOCK = 1;
pub const UNBLOCK = 2; pub const UNBLOCK = 2;
@ -2560,9 +2555,9 @@ pub const SIG = if (is_mips) struct {
pub const PWR = LOST; pub const PWR = LOST;
pub const IO = SIG.POLL; pub const IO = SIG.POLL;
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
} else struct { } else struct {
pub const BLOCK = 0; pub const BLOCK = 0;
pub const UNBLOCK = 1; pub const UNBLOCK = 1;
@ -2603,9 +2598,9 @@ pub const SIG = if (is_mips) struct {
pub const SYS = 31; pub const SYS = 31;
pub const UNUSED = SIG.SYS; pub const UNUSED = SIG.SYS;
pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
}; };
pub const kernel_rwf = u32; 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; pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30;
const k_sigaction_funcs = struct { 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; 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. /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct { 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; pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
handler: extern union { handler: extern union {

View File

@ -1369,16 +1369,16 @@ fn fnProtoExpr(
break :is_var_args false; break :is_var_args false;
}; };
const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { if (fn_proto.ast.align_expr != 0) {
break :inst try expr(&block_scope, scope, coerced_align_ri, fn_proto.ast.align_expr); return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{});
}; }
if (fn_proto.ast.addrspace_expr != 0) { 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) { 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) 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 maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
const is_inferred_error = token_tags[maybe_bang] == .bang; const is_inferred_error = token_tags[maybe_bang] == .bang;
if (is_inferred_error) { 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); 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_ref = cc,
.cc_gz = null, .cc_gz = null,
.align_ref = align_ref, .align_ref = .none,
.align_gz = null, .align_gz = null,
.ret_ref = ret_ty, .ret_ref = ret_ty,
.ret_gz = null, .ret_gz = null,

View File

@ -765,16 +765,10 @@ pub const Key = union(enum) {
/// Tells whether a parameter is noalias. See `paramIsNoalias` helper /// Tells whether a parameter is noalias. See `paramIsNoalias` helper
/// method for accessing this. /// method for accessing this.
noalias_bits: u32, 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, cc: std.builtin.CallingConvention,
is_var_args: bool, is_var_args: bool,
is_generic: bool, is_generic: bool,
is_noinline: bool, is_noinline: bool,
align_is_generic: bool,
cc_is_generic: bool, cc_is_generic: bool,
section_is_generic: bool, section_is_generic: bool,
addrspace_is_generic: bool, addrspace_is_generic: bool,
@ -794,7 +788,6 @@ pub const Key = union(enum) {
a.return_type == b.return_type and a.return_type == b.return_type and
a.comptime_bits == b.comptime_bits and a.comptime_bits == b.comptime_bits and
a.noalias_bits == b.noalias_bits and a.noalias_bits == b.noalias_bits and
a.alignment == b.alignment and
a.cc == b.cc and a.cc == b.cc and
a.is_var_args == b.is_var_args and a.is_var_args == b.is_var_args and
a.is_generic == b.is_generic 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.return_type);
std.hash.autoHash(hasher, self.comptime_bits); std.hash.autoHash(hasher, self.comptime_bits);
std.hash.autoHash(hasher, self.noalias_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.cc);
std.hash.autoHash(hasher, self.is_var_args); std.hash.autoHash(hasher, self.is_var_args);
std.hash.autoHash(hasher, self.is_generic); std.hash.autoHash(hasher, self.is_generic);
@ -3587,18 +3579,16 @@ pub const Tag = enum(u8) {
flags: Flags, flags: Flags,
pub const Flags = packed struct(u32) { pub const Flags = packed struct(u32) {
alignment: Alignment,
cc: std.builtin.CallingConvention, cc: std.builtin.CallingConvention,
is_var_args: bool, is_var_args: bool,
is_generic: bool, is_generic: bool,
has_comptime_bits: bool, has_comptime_bits: bool,
has_noalias_bits: bool, has_noalias_bits: bool,
is_noinline: bool, is_noinline: bool,
align_is_generic: bool,
cc_is_generic: bool, cc_is_generic: bool,
section_is_generic: bool, section_is_generic: bool,
addrspace_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, .return_type = type_function.data.return_type,
.comptime_bits = comptime_bits, .comptime_bits = comptime_bits,
.noalias_bits = noalias_bits, .noalias_bits = noalias_bits,
.alignment = type_function.data.flags.alignment,
.cc = type_function.data.flags.cc, .cc = type_function.data.flags.cc,
.is_var_args = type_function.data.flags.is_var_args, .is_var_args = type_function.data.flags.is_var_args,
.is_noinline = type_function.data.flags.is_noinline, .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, .cc_is_generic = type_function.data.flags.cc_is_generic,
.section_is_generic = type_function.data.flags.section_is_generic, .section_is_generic = type_function.data.flags.section_is_generic,
.addrspace_is_generic = type_function.data.flags.addrspace_is_generic, .addrspace_is_generic = type_function.data.flags.addrspace_is_generic,
@ -6211,8 +6199,6 @@ pub const GetFuncTypeKey = struct {
comptime_bits: u32 = 0, comptime_bits: u32 = 0,
noalias_bits: u32 = 0, noalias_bits: u32 = 0,
/// `null` means generic. /// `null` means generic.
alignment: ?Alignment = .none,
/// `null` means generic.
cc: ?std.builtin.CallingConvention = .Unspecified, cc: ?std.builtin.CallingConvention = .Unspecified,
is_var_args: bool = false, is_var_args: bool = false,
is_generic: bool = false, is_generic: bool = false,
@ -6242,14 +6228,12 @@ pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocat
.params_len = params_len, .params_len = params_len,
.return_type = key.return_type, .return_type = key.return_type,
.flags = .{ .flags = .{
.alignment = key.alignment orelse .none,
.cc = key.cc orelse .Unspecified, .cc = key.cc orelse .Unspecified,
.is_var_args = key.is_var_args, .is_var_args = key.is_var_args,
.has_comptime_bits = key.comptime_bits != 0, .has_comptime_bits = key.comptime_bits != 0,
.has_noalias_bits = key.noalias_bits != 0, .has_noalias_bits = key.noalias_bits != 0,
.is_generic = key.is_generic, .is_generic = key.is_generic,
.is_noinline = key.is_noinline, .is_noinline = key.is_noinline,
.align_is_generic = key.alignment == null,
.cc_is_generic = key.cc == null, .cc_is_generic = key.cc == null,
.section_is_generic = key.section_is_generic, .section_is_generic = key.section_is_generic,
.addrspace_is_generic = key.addrspace_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, .params_len = params_len,
.return_type = @enumFromInt(ip.items.len - 2), .return_type = @enumFromInt(ip.items.len - 2),
.flags = .{ .flags = .{
.alignment = key.alignment orelse .none,
.cc = key.cc orelse .Unspecified, .cc = key.cc orelse .Unspecified,
.is_var_args = key.is_var_args, .is_var_args = key.is_var_args,
.has_comptime_bits = key.comptime_bits != 0, .has_comptime_bits = key.comptime_bits != 0,
.has_noalias_bits = key.noalias_bits != 0, .has_noalias_bits = key.noalias_bits != 0,
.is_generic = key.is_generic, .is_generic = key.is_generic,
.is_noinline = key.is_noinline, .is_noinline = key.is_noinline,
.align_is_generic = key.alignment == null,
.cc_is_generic = key.cc == null, .cc_is_generic = key.cc == null,
.section_is_generic = key.section_is_generic, .section_is_generic = key.section_is_generic,
.addrspace_is_generic = key.addrspace_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, .param_types = arg.param_types,
.return_type = arg.bare_return_type, .return_type = arg.bare_return_type,
.noalias_bits = arg.noalias_bits, .noalias_bits = arg.noalias_bits,
.alignment = arg.alignment,
.cc = arg.cc, .cc = arg.cc,
.is_noinline = arg.is_noinline, .is_noinline = arg.is_noinline,
}); });
@ -6610,6 +6591,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
func_index, func_index,
func_extra_index, func_extra_index,
func_ty, func_ty,
arg.alignment,
arg.section, arg.section,
); );
} }
@ -6673,14 +6655,12 @@ pub fn getFuncInstanceIes(
.params_len = params_len, .params_len = params_len,
.return_type = error_union_type, .return_type = error_union_type,
.flags = .{ .flags = .{
.alignment = arg.alignment,
.cc = arg.cc, .cc = arg.cc,
.is_var_args = false, .is_var_args = false,
.has_comptime_bits = false, .has_comptime_bits = false,
.has_noalias_bits = arg.noalias_bits != 0, .has_noalias_bits = arg.noalias_bits != 0,
.is_generic = false, .is_generic = false,
.is_noinline = arg.is_noinline, .is_noinline = arg.is_noinline,
.align_is_generic = false,
.cc_is_generic = false, .cc_is_generic = false,
.section_is_generic = false, .section_is_generic = false,
.addrspace_is_generic = false, .addrspace_is_generic = false,
@ -6741,6 +6721,7 @@ pub fn getFuncInstanceIes(
func_index, func_index,
func_extra_index, func_extra_index,
func_ty, func_ty,
arg.alignment,
arg.section, arg.section,
); );
} }
@ -6752,6 +6733,7 @@ fn finishFuncInstance(
func_index: Index, func_index: Index,
func_extra_index: u32, func_extra_index: u32,
func_ty: Index, func_ty: Index,
alignment: Alignment,
section: OptionalNullTerminatedString, section: OptionalNullTerminatedString,
) Allocator.Error!Index { ) Allocator.Error!Index {
const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner)); const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner));
@ -6764,7 +6746,7 @@ fn finishFuncInstance(
.owns_tv = true, .owns_tv = true,
.ty = @import("type.zig").Type.fromInterned(func_ty), .ty = @import("type.zig").Type.fromInterned(func_ty),
.val = @import("Value.zig").fromInterned(func_index), .val = @import("Value.zig").fromInterned(func_index),
.alignment = .none, .alignment = alignment,
.@"linksection" = section, .@"linksection" = section,
.@"addrspace" = fn_owner_decl.@"addrspace", .@"addrspace" = fn_owner_decl.@"addrspace",
.analysis = .complete, .analysis = .complete,

View File

@ -3596,6 +3596,18 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)}); 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 decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip);
const gpa = mod.gpa; const gpa = mod.gpa;
@ -3733,85 +3745,39 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
}; };
} }
switch (ip.indexToKey(decl_tv.val.toIntern())) { var queue_linker_work = true;
.func => |func| { var is_func = false;
const owns_tv = func.owner_decl == decl_index; var is_inline = false;
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;
switch (decl_tv.val.toIntern()) { switch (decl_tv.val.toIntern()) {
.generic_poison => unreachable, .generic_poison => unreachable,
.unreachable_value => unreachable, .unreachable_value => unreachable,
else => switch (ip.indexToKey(decl_tv.val.toIntern())) { else => switch (ip.indexToKey(decl_tv.val.toIntern())) {
.variable => |variable| if (variable.decl == decl_index) { .variable => |variable| {
decl.owns_tv = true; decl.owns_tv = variable.decl == decl_index;
queue_linker_work = true; queue_linker_work = decl.owns_tv;
}, },
.extern_func => |extern_fn| if (extern_fn.decl == decl_index) { .extern_func => |extern_func| {
decl.owns_tv = true; decl.owns_tv = extern_func.decl == decl_index;
queue_linker_work = true; queue_linker_work = decl.owns_tv;
is_extern = true; is_func = decl.owns_tv;
}, },
.func => {}, .func => |func| {
decl.owns_tv = func.owner_decl == decl_index;
else => { queue_linker_work = false;
queue_linker_work = true; 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.ty = decl_tv.ty;
decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
// Function linksection, align, and addrspace were already set by Sema
if (!is_func) {
decl.alignment = blk: { decl.alignment = blk: {
const align_body = decl_bodies.align_body orelse break :blk .none; const align_body = decl_bodies.align_body orelse break :blk .none;
const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst); const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst);
@ -3849,25 +3815,26 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst); 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); break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
}; };
}
decl.has_tv = true; decl.has_tv = true;
decl.analysis = .complete; decl.analysis = .complete;
const result: SemaDeclResult = if (old_has_tv) .{ 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 .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or
decl.alignment != old_align or decl.alignment != old_align or
decl.@"linksection" != old_linksection or decl.@"linksection" != old_linksection or
decl.@"addrspace" != old_addrspace, decl.@"addrspace" != old_addrspace or
is_inline != old_is_inline,
} else .{ } else .{
.invalidate_decl_val = true, .invalidate_decl_val = true,
.invalidate_decl_ref = true, .invalidate_decl_ref = true,
}; };
const has_runtime_bits = is_extern or const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl.ty));
(queue_linker_work and try sema.typeHasRuntimeBits(decl.ty));
if (has_runtime_bits) { if (has_runtime_bits) {
// Needed for codegen_decl which will call updateDecl and then the // Needed for codegen_decl which will call updateDecl and then the
// codegen backend wants full access to the Decl Type. // codegen backend wants full access to the Decl Type.
try sema.resolveTypeFully(decl.ty); try sema.resolveTypeFully(decl.ty);
@ -3881,6 +3848,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
if (decl.is_exported) { if (decl.is_exported) {
const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) }; 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. // The scope needs to have the decl in it.
try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
} }

View File

@ -7605,7 +7605,6 @@ fn analyzeCall(
.param_types = new_param_types, .param_types = new_param_types,
.return_type = owner_info.return_type, .return_type = owner_info.return_type,
.noalias_bits = owner_info.noalias_bits, .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, .cc = if (owner_info.cc_is_generic) null else owner_info.cc,
.is_var_args = owner_info.is_var_args, .is_var_args = owner_info.is_var_args,
.is_noinline = owner_info.is_noinline, .is_noinline = owner_info.is_noinline,
@ -9629,7 +9628,6 @@ fn funcCommon(
.comptime_bits = comptime_bits, .comptime_bits = comptime_bits,
.return_type = bare_return_type.toIntern(), .return_type = bare_return_type.toIntern(),
.cc = cc, .cc = cc,
.alignment = alignment,
.section_is_generic = section == .generic, .section_is_generic = section == .generic,
.addrspace_is_generic = address_space == null, .addrspace_is_generic = address_space == null,
.is_var_args = var_args, .is_var_args = var_args,
@ -9640,6 +9638,7 @@ fn funcCommon(
if (is_extern) { if (is_extern) {
assert(comptime_bits == 0); assert(comptime_bits == 0);
assert(cc != null); assert(cc != null);
assert(alignment != null);
assert(section != .generic); assert(section != .generic);
assert(address_space != null); assert(address_space != null);
assert(!is_generic); assert(!is_generic);
@ -17623,8 +17622,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const field_values = .{ const field_values = .{
// calling_convention: CallingConvention, // calling_convention: CallingConvention,
(try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(), (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, // is_generic: bool,
Value.makeBool(func_ty_info.is_generic).toIntern(), Value.makeBool(func_ty_info.is_generic).toIntern(),
// is_var_args: bool, // 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) { if (inst_data.size != .One) {
return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{}); 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) { } 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", .{}); return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});
} else if (inst_data.size == .C) { } else if (inst_data.size == .C) {
@ -21030,7 +21021,6 @@ fn zirReify(
.needed_comptime_reason = "operand to @Type must be comptime-known", .needed_comptime_reason = "operand to @Type must be comptime-known",
}); });
const union_val = ip.indexToKey(val.toIntern()).un; 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); 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).?; const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?;
switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {
@ -21171,12 +21161,6 @@ fn zirReify(
if (ptr_size != .One) { if (ptr_size != .One) {
return sema.fail(block, src, "function pointers must be single pointers", .{}); 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) { } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});
} else if (ptr_size == .C) { } else if (ptr_size == .C) {
@ -21429,10 +21413,6 @@ fn zirReify(
ip, ip,
try ip.getOrPutString(gpa, "calling_convention"), 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( const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip, ip,
try ip.getOrPutString(gpa, "is_generic"), try ip.getOrPutString(gpa, "is_generic"),
@ -21461,11 +21441,6 @@ fn zirReify(
try sema.checkCallConvSupportsVarArgs(block, src, cc); 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 const return_type = return_type_val.optionalValue(mod) orelse
return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); 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, .param_types = param_types,
.noalias_bits = noalias_bits, .noalias_bits = noalias_bits,
.return_type = return_type.toIntern(), .return_type = return_type.toIntern(),
.alignment = alignment,
.cc = cc, .cc = cc,
.is_var_args = is_var_args, .is_var_args = is_var_args,
}); });
@ -32536,16 +32510,21 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
const mod = sema.mod; const mod = sema.mod;
try sema.ensureDeclAnalyzed(decl_index); try sema.ensureDeclAnalyzed(decl_index);
const decl = mod.declPtr(decl_index); const decl_tv = try mod.declPtr(decl_index).typedValue();
const decl_tv = try decl.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 // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type
try sema.declareDependency(.{ .decl_val = decl_index }); try sema.declareDependency(.{ .decl_val = decl_index });
const ptr_ty = try sema.ptrType(.{ const ptr_ty = try sema.ptrType(.{
.child = decl_tv.ty.toIntern(), .child = decl_tv.ty.toIntern(),
.flags = .{ .flags = .{
.alignment = decl.alignment, .alignment = owner_decl.alignment,
.is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true, .is_const = if (decl_tv.val.getVariable(mod)) |variable| variable.is_const else true,
.address_space = decl.@"addrspace", .address_space = owner_decl.@"addrspace",
}, },
}); });
if (analyze_fn_body) { if (analyze_fn_body) {

View File

@ -1635,7 +1635,7 @@ pub const DeclGen = struct {
switch (kind) { switch (kind) {
.forward => {}, .forward => {},
.complete => if (fn_info.alignment.toByteUnitsOptional()) |a| { .complete => if (fn_decl.alignment.toByteUnitsOptional()) |a| {
try w.print("{}zig_align_fn({})", .{ trailing, a }); try w.print("{}zig_align_fn({})", .{ trailing, a });
trailing = .maybe_space; trailing = .maybe_space;
}, },
@ -1666,7 +1666,7 @@ pub const DeclGen = struct {
switch (kind) { switch (kind) {
.forward => { .forward => {
if (fn_info.alignment.toByteUnitsOptional()) |a| { if (fn_decl.alignment.toByteUnitsOptional()) |a| {
try w.print(" zig_align_fn({})", .{a}); try w.print(" zig_align_fn({})", .{a});
} }
switch (name) { switch (name) {

View File

@ -2949,8 +2949,8 @@ pub const Object = struct {
else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder), else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),
} }
if (fn_info.alignment != .none) if (decl.alignment != .none)
function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder); function_index.setAlignment(decl.alignment.toLlvm(), &o.builder);
// Function attributes that are independent of analysis results of the function body. // Function attributes that are independent of analysis results of the function body.
try o.addCommonFnAttributes(&attributes, owner_mod); try o.addCommonFnAttributes(&attributes, owner_mod);

View File

@ -396,9 +396,6 @@ pub const Type = struct {
try writer.writeAll("..."); try writer.writeAll("...");
} }
try writer.writeAll(") "); try writer.writeAll(") ");
if (fn_info.alignment.toByteUnitsOptional()) |a| {
try writer.print("align({d}) ", .{a});
}
if (fn_info.cc != .Unspecified) { if (fn_info.cc != .Unspecified) {
try writer.writeAll("callconv(."); try writer.writeAll("callconv(.");
try writer.writeAll(@tagName(fn_info.cc)); try writer.writeAll(@tagName(fn_info.cc));
@ -949,12 +946,7 @@ pub const Type = struct {
}, },
// represents machine code; not a pointer // represents machine code; not a pointer
.func_type => |func_type| return .{ .func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) },
.scalar = if (func_type.alignment != .none)
func_type.alignment
else
target_util.defaultFunctionAlignment(target),
},
.simple_type => |t| switch (t) { .simple_type => |t| switch (t) {
.bool, .bool,

View File

@ -311,12 +311,6 @@ test "page aligned array on stack" {
try expect(number2 == 43); 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" { test "function alignment" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) 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 // function alignment is a compile error on wasm32/wasm64
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
try expect(derp() == 1234); const S = struct {
try expect(@TypeOf(noop1) == fn () align(1) void); fn alignExpr() align(@sizeOf(usize) * 2) i32 {
try expect(@TypeOf(noop4) == fn () align(4) void); return 1234;
noop1(); }
noop4(); 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" { test "implicitly decreasing fn alignment" {
@ -345,7 +353,7 @@ test "implicitly decreasing fn alignment" {
try testImplicitlyDecreaseFnAlign(alignedBig, 5678); 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); try expect(ptr() == answer);
} }
@ -368,10 +376,10 @@ test "@alignCast functions" {
try expect(fnExpectsOnly1(simple4) == 0x19); 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)); return fnExpects4(@alignCast(ptr));
} }
fn fnExpects4(ptr: *const fn () align(4) i32) i32 { fn fnExpects4(ptr: *align(4) const fn () i32) i32 {
return ptr(); return ptr();
} }
fn simple4() align(4) i32 { fn simple4() align(4) i32 {

View File

@ -527,7 +527,6 @@ test "Type.Fn" {
{ {
const fn_info = std.builtin.Type{ .Fn = .{ const fn_info = std.builtin.Type{ .Fn = .{
.calling_convention = .C, .calling_convention = .C,
.alignment = 0,
.is_generic = false, .is_generic = false,
.is_var_args = false, .is_var_args = false,
.return_type = void, .return_type = void,
@ -643,7 +642,6 @@ test "reified function type params initialized with field pointer" {
const Bar = @Type(.{ const Bar = @Type(.{
.Fn = .{ .Fn = .{
.calling_convention = .Unspecified, .calling_convention = .Unspecified,
.alignment = 0,
.is_generic = false, .is_generic = false,
.is_var_args = false, .is_var_args = false,
.return_type = void, .return_type = void,

View File

@ -356,16 +356,38 @@ test "type info: function type info" {
} }
fn testFunction() !void { fn testFunction() !void {
const fn_info = @typeInfo(@TypeOf(typeInfoFoo)); const foo_fn_type = @TypeOf(typeInfoFoo);
try expect(fn_info == .Fn); const foo_fn_info = @typeInfo(foo_fn_type);
try expect(fn_info.Fn.alignment > 0); try expect(foo_fn_info.Fn.calling_convention == .C);
try expect(fn_info.Fn.calling_convention == .C); try expect(!foo_fn_info.Fn.is_generic);
try expect(!fn_info.Fn.is_generic); try expect(foo_fn_info.Fn.params.len == 2);
try expect(fn_info.Fn.params.len == 2); try expect(foo_fn_info.Fn.is_var_args);
try expect(fn_info.Fn.is_var_args); try expect(foo_fn_info.Fn.return_type.? == usize);
try expect(fn_info.Fn.return_type.? == usize); const foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFoo));
const fn_aligned_info = @typeInfo(@TypeOf(typeInfoFooAligned)); try expect(foo_ptr_fn_info.Pointer.size == .One);
try expect(fn_aligned_info.Fn.alignment == 4); 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; extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.C) usize;

View File

@ -78,11 +78,9 @@ test "basic" {
try expectEqualStrings("fn (comptime u32) void", @typeName(fn (comptime u32) void)); 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 (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 () 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 (...) 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 (u32, ...) callconv(.C) void", @typeName(fn (u32, ...) callconv(.C) void));
try expectEqualStrings("fn (u32, ...) align(32) callconv(.C) void", @typeName(fn (u32, ...) align(32) callconv(.C) void));
} }
test "top level decl" { test "top level decl" {

View File

@ -1,28 +1,16 @@
comptime { fn align1() align(1) void {}
var a: *align(2) @TypeOf(foo) = undefined; fn align2() align(2) void {}
_ = &a;
}
fn foo() void {}
comptime { comptime {
var a: *align(1) fn () void = undefined; _ = @as(*align(1) const fn () void, &align2);
_ = &a; _ = @as(*align(1) const fn () void, &align1);
} _ = @as(*align(2) const fn () void, &align2);
comptime { _ = @as(*align(2) const fn () void, &align1);
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;
} }
// error // error
// backend=stage2 // backend=stage2
// target=native // 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'

View File

@ -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

View File

@ -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

View File

@ -1,7 +1,7 @@
export fn entry() void { export fn entry() void {
testImplicitlyDecreaseFnAlign(alignedSmall, 1234); 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; if (ptr() != answer) unreachable;
} }
fn alignedSmall() align(4) i32 { fn alignedSmall() align(4) i32 {
@ -12,5 +12,5 @@ fn alignedSmall() align(4) i32 {
// backend=stage2 // backend=stage2
// target=x86_64-linux // 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' // :2:35: note: pointer alignment '4' cannot cast into pointer alignment '8'

View File

@ -1,7 +1,6 @@
const Foo = @Type(.{ const Foo = @Type(.{
.Fn = .{ .Fn = .{
.calling_convention = .Unspecified, .calling_convention = .Unspecified,
.alignment = 0,
.is_generic = true, .is_generic = true,
.is_var_args = false, .is_var_args = false,
.return_type = u0, .return_type = u0,

View File

@ -1,7 +1,6 @@
const Foo = @Type(.{ const Foo = @Type(.{
.Fn = .{ .Fn = .{
.calling_convention = .Unspecified, .calling_convention = .Unspecified,
.alignment = 0,
.is_generic = false, .is_generic = false,
.is_var_args = true, .is_var_args = true,
.return_type = u0, .return_type = u0,

View File

@ -1,7 +1,6 @@
const Foo = @Type(.{ const Foo = @Type(.{
.Fn = .{ .Fn = .{
.calling_convention = .Unspecified, .calling_convention = .Unspecified,
.alignment = 0,
.is_generic = false, .is_generic = false,
.is_var_args = false, .is_var_args = false,
.return_type = null, .return_type = null,