pub const Index = enum(u32) {
_,
pub fn getKind(self: Index, builder: *const Builder) Kind {
return self.toStorage(builder).kind;
}
pub fn toAttribute(self: Index, builder: *const Builder) Attribute {
@setEvalBranchQuota(2_000);
const storage = self.toStorage(builder);
if (storage.kind.toString()) |kind| return .{ .string = .{
.kind = kind,
.value = @fromBackingInt(storage.value),
} } else return switch (storage.kind) {
inline else => |kind| {
const field_name, const field_type = comptime blk: {
@setEvalBranchQuota(12_000);
const info = @typeInfo(Attribute).@"union";
for (info.field_names, info.field_types) |field_name, field_type| {
if (std.mem.eql(u8, field_name, @tagName(kind))) break :blk .{ field_name, field_type };
}
unreachable;
};
comptime assert(std.mem.eql(u8, @tagName(kind), field_name));
return @unionInit(Attribute, field_name, switch (field_type) {
void => {},
u32 => storage.value,
Alignment.Lazy, String, Type, UwTable => @fromBackingInt(storage.value),
AllocKind, AllocSize, Captures, FpClass, Memory, VScaleRange => @bitCast(storage.value),
else => @compileError("bad payload type: " ++ field_name ++ ": " ++
@typeName(field_type)),
});
},
.initializes,
.dead_on_return,
.range,
=> @panic("TODO"),
.string, .none, _ => unreachable,
};
}
const FormatData = struct {
attribute_index: Index,
builder: *const Builder,
flags: Flags = .{},
const Flags = struct {
pound: bool = false,
quote: bool = false,
};
};
fn format(data: FormatData, w: *Writer) Writer.Error!void {
const attribute = data.attribute_index.toAttribute(data.builder);
switch (attribute) {
.zeroext,
.signext,
.noext,
.inreg,
.@"noalias",
.nocapture,
.nofree,
.nest,
.returned,
.nonnull,
.swiftself,
.swiftasync,
.swifterror,
.immarg,
.noundef,
.allocalign,
.allocptr,
.readnone,
.readonly,
.writeonly,
.writable,
.dead_on_unwind,
.alwaysinline,
.builtin,
.cold,
.convergent,
.disable_sanitizer_instrumentation,
.fn_ret_thunk_extern,
.hot,
.inlinehint,
.jumptable,
.minsize,
.naked,
.nobuiltin,
.nocallback,
.nodivergencesource,
.noduplicate,
.noimplicitfloat,
.@"noinline",
.nomerge,
.nonlazybind,
.noprofile,
.skipprofile,
.noredzone,
.noreturn,
.norecurse,
.willreturn,
.nosync,
.nounwind,
.nosanitize_bounds,
.nosanitize_coverage,
.null_pointer_is_valid,
.optdebug,
.optforfuzzing,
.optnone,
.optsize,
.returns_twice,
.safestack,
.sanitize_address,
.sanitize_memory,
.sanitize_thread,
.sanitize_hwaddress,
.sanitize_memtag,
.sanitize_realtime,
.sanitize_realtime_blocking,
.sanitize_alloc_token,
.speculative_load_hardening,
.speculatable,
.ssp,
.sspstrong,
.sspreq,
.strictfp,
.denormal_fpenv,
.nocf_check,
.shadowcallstack,
.mustprogress,
.nooutline,
.nocreateundeforpoison,
=> try w.print(" {s}", .{@tagName(attribute)}),
.byval,
.byref,
.preallocated,
.inalloca,
.sret,
.elementtype,
=> |ty| try w.print(" {s}({f})", .{ @tagName(attribute), ty.fmt(data.builder, .percent) }),
.@"align" => |alignment| try w.print("{f}", .{alignment.resolve(data.builder).fmt(" ")}),
.dereferenceable,
.dereferenceable_or_null,
=> |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }),
.captures => |captures| {
try w.print(" {s}(", .{@tagName(attribute)});
var need_comma = false;
if (captures == Captures.none) {
if (need_comma) try w.writeAll(", ");
try w.writeAll("none");
need_comma = true;
}
inline for (@typeInfo(Captures).@"struct".field_names) |field_name| {
if (comptime std.mem.eql(u8, field_name, "_")) continue;
const components = @field(captures, field_name);
if (components != Captures.Components.none) {
if (!comptime std.mem.eql(u8, field_name, "other")) {
if (need_comma) try w.writeAll(", ");
try w.writeAll(field_name ++ ": ");
need_comma = false;
}
if (components.address) {
if (need_comma) try w.writeAll(", ");
try w.writeAll("address");
need_comma = true;
} else if (components.address_is_null) {
if (need_comma) try w.writeAll(", ");
try w.writeAll("address_is_null");
need_comma = true;
}
if (components.provenance) {
if (need_comma) try w.writeAll(", ");
try w.writeAll("provenance");
need_comma = true;
} else if (components.read_provenance) {
if (need_comma) try w.writeAll(", ");
try w.writeAll("read_provenance");
need_comma = true;
}
}
}
try w.writeByte(')');
},
.nofpclass => |fpclass| {
const Int = @typeInfo(FpClass).@"struct".backing_integer.?;
try w.print(" {s}(", .{@tagName(attribute)});
var any = false;
var remaining: Int = @bitCast(fpclass);
inline for (@typeInfo(FpClass).@"struct".decl_names) |decl_name| {
const pattern: Int = @bitCast(@field(FpClass, decl_name));
if (remaining & pattern == pattern) {
if (!any) {
try w.writeByte(' ');
any = true;
}
try w.writeAll(decl_name);
remaining &= ~pattern;
}
}
try w.writeByte(')');
},
.alignstack => |alignment| {
try w.print(" {t}", .{attribute});
const alignment_bytes = alignment.resolve(data.builder).toByteUnits() orelse return;
if (data.flags.pound) {
try w.print("={d}", .{alignment_bytes});
} else {
try w.print("({d})", .{alignment_bytes});
}
},
.initializes => @panic("TODO"),
.dead_on_return => @panic("TODO"),
.range => @panic("TODO"),
.allockind => |allockind| {
try w.print(" {t}(\"", .{attribute});
var any = false;
inline for (@typeInfo(AllocKind).@"struct".field_names) |field_name| {
if (comptime std.mem.eql(u8, field_name, "_")) continue;
if (@field(allockind, field_name)) {
if (!any) {
try w.writeByte(',');
any = true;
}
try w.writeAll(field_name);
}
}
try w.writeAll("\")");
},
.allocsize => |allocsize| {
try w.print(" {t}({d}", .{ attribute, allocsize.elem_size });
if (allocsize.num_elems != AllocSize.none)
try w.print(",{d}", .{allocsize.num_elems});
try w.writeByte(')');
},
.memory => |memory| {
try w.print(" {t}(", .{attribute});
var any = memory.other != .none or
(memory.argmem == .none and memory.inaccessiblemem == .none);
if (any) try w.writeAll(@tagName(memory.other));
inline for (.{ "argmem", "inaccessiblemem" }) |kind| {
if (@field(memory, kind) != memory.other) {
if (any) try w.writeAll(", ");
try w.print("{s}: {s}", .{ kind, @tagName(@field(memory, kind)) });
any = true;
}
}
try w.writeByte(')');
},
.uwtable => |uwtable| if (uwtable != .none) {
try w.print(" {s}", .{@tagName(attribute)});
if (uwtable != UwTable.default) try w.print("({s})", .{@tagName(uwtable)});
},
.vscale_range => |vscale_range| try w.print(" {s}({d},{d})", .{
@tagName(attribute),
vscale_range.min.toByteUnits().?,
vscale_range.max.toByteUnits() orelse 0,
}),
.string => |string_attr| if (data.flags.quote) {
try w.print(" {f}", .{string_attr.kind.fmtQ(data.builder)});
if (string_attr.value != .empty)
try w.print("={f}", .{string_attr.value.fmtQ(data.builder)});
},
.none => unreachable,
}
}
pub fn fmt(self: Index, builder: *const Builder, flags: FormatData.Flags) std.fmt.Alt(FormatData, format) {
return .{ .data = .{ .attribute_index = self, .builder = builder, .flags = flags } };
}
fn toStorage(self: Index, builder: *const Builder) Storage {
return builder.attributes.keys()[@backingInt(self)];
}
}