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" {
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#}
<p>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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))));
}
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 {

View file

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

View file

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

View file

@ -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,85 +3745,39 @@ 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)));
// 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);
@ -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);
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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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 {
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'

View file

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

View file

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

View file

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