diff --git a/build.zig b/build.zig index 205eab12..da28e7ae 100644 --- a/build.zig +++ b/build.zig @@ -83,6 +83,7 @@ pub fn build(b: *Build) !void { exe.addModule("aro", aro_module); GenerateDef.add(b, "src/Builtins/Builtin.def", exe, aro_module); + GenerateDef.add(b, "src/Attribute/Attribute.def", exe, aro_module); system_defaults.addOption(bool, "enable_linker_build_id", enable_linker_build_id); system_defaults.addOption([]const u8, "linker", default_linker); diff --git a/src/Attribute.zig b/src/Attribute.zig index 85c169a4..c6c1a3d2 100644 --- a/src/Attribute.zig +++ b/src/Attribute.zig @@ -90,17 +90,13 @@ pub const CallingConvention = enum { vectorcall, }; -fn getArguments(comptime descriptor: type) []const ZigType.StructField { - return if (@hasDecl(descriptor, "Args")) std.meta.fields(descriptor.Args) else &.{}; -} - /// number of required arguments pub fn requiredArgCount(attr: Tag) u32 { switch (attr) { inline else => |tag| { comptime var needed = 0; comptime { - const fields = getArguments(@field(attributes, @tagName(tag))); + const fields = std.meta.fields(@field(attributes, @tagName(tag))); for (fields) |arg_field| { if (!mem.eql(u8, arg_field.name, "__name_tok") and @typeInfo(arg_field.type) != .Optional) needed += 1; } @@ -116,7 +112,7 @@ pub fn maxArgCount(attr: Tag) u32 { inline else => |tag| { comptime var max = 0; comptime { - const fields = getArguments(@field(attributes, @tagName(tag))); + const fields = std.meta.fields(@field(attributes, @tagName(tag))); for (fields) |arg_field| { if (!mem.eql(u8, arg_field.name, "__name_tok")) max += 1; } @@ -135,13 +131,13 @@ fn UnwrapOptional(comptime T: type) type { pub const Formatting = struct { /// The quote char (single or double) to use when printing identifiers/strings corresponding - /// to the enum in the first field of the Args of `attr`. Identifier enums use single quotes, string enums + /// to the enum in the first field of the `attr`. Identifier enums use single quotes, string enums /// use double quotes fn quoteChar(attr: Tag) []const u8 { switch (attr) { .calling_convention => unreachable, inline else => |tag| { - const fields = getArguments(@field(attributes, @tagName(tag))); + const fields = std.meta.fields(@field(attributes, @tagName(tag))); if (fields.len == 0) unreachable; const Unwrapped = UnwrapOptional(fields[0].type); @@ -153,12 +149,12 @@ pub const Formatting = struct { } /// returns a comma-separated string of quoted enum values, representing the valid - /// choices for the string or identifier enum of the first field of the Args of `attr`. + /// choices for the string or identifier enum of the first field of the `attr`. pub fn choices(attr: Tag) []const u8 { switch (attr) { .calling_convention => unreachable, inline else => |tag| { - const fields = getArguments(@field(attributes, @tagName(tag))); + const fields = std.meta.fields(@field(attributes, @tagName(tag))); if (fields.len == 0) unreachable; const Unwrapped = UnwrapOptional(fields[0].type); @@ -183,7 +179,7 @@ pub fn wantsIdentEnum(attr: Tag) bool { switch (attr) { .calling_convention => return false, inline else => |tag| { - const fields = getArguments(@field(attributes, @tagName(tag))); + const fields = std.meta.fields(@field(attributes, @tagName(tag))); if (fields.len == 0) return false; const Unwrapped = UnwrapOptional(fields[0].type); @@ -197,7 +193,7 @@ pub fn wantsIdentEnum(attr: Tag) bool { pub fn diagnoseIdent(attr: Tag, arguments: *Arguments, ident: []const u8) ?Diagnostics.Message { switch (attr) { inline else => |tag| { - const fields = getArguments(@field(attributes, @tagName(tag))); + const fields = std.meta.fields(@field(attributes, @tagName(tag))); if (fields.len == 0) unreachable; const Unwrapped = UnwrapOptional(fields[0].type); if (@typeInfo(Unwrapped) != .Enum) unreachable; @@ -216,7 +212,7 @@ pub fn diagnoseIdent(attr: Tag, arguments: *Arguments, ident: []const u8) ?Diagn pub fn wantsAlignment(attr: Tag, idx: usize) bool { switch (attr) { inline else => |tag| { - const fields = getArguments(@field(attributes, @tagName(tag))); + const fields = std.meta.fields(@field(attributes, @tagName(tag))); if (fields.len == 0) return false; return switch (idx) { @@ -230,7 +226,7 @@ pub fn wantsAlignment(attr: Tag, idx: usize) bool { pub fn diagnoseAlignment(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Value, ty: Type, comp: *Compilation) ?Diagnostics.Message { switch (attr) { inline else => |tag| { - const arg_fields = getArguments(@field(attributes, @tagName(tag))); + const arg_fields = std.meta.fields(@field(attributes, @tagName(tag))); if (arg_fields.len == 0) unreachable; switch (arg_idx) { @@ -312,7 +308,7 @@ pub fn diagnose(attr: Tag, arguments: *Arguments, arg_idx: u32, val: Value, node .tag = .attribute_too_many_args, .extra = .{ .attr_arg_count = .{ .attribute = attr, .expected = max_arg_count } }, }; - const arg_fields = getArguments(@field(attributes, decl.name)); + const arg_fields = std.meta.fields(@field(attributes, decl.name)); switch (arg_idx) { inline 0...arg_fields.len - 1 => |arg_i| { return diagnoseField(decl, arg_fields[arg_i], UnwrapOptional(arg_fields[arg_i].type), arguments, val, node, strings); @@ -337,212 +333,107 @@ pub const Identifier = struct { const attributes = struct { pub const access = struct { - const gnu = "access"; - - const Args = struct { - access_mode: enum { - read_only, - read_write, - write_only, - none, - - const opts = struct { - const enum_kind = .identifier; - }; - }, - ref_index: u32, - size_index: ?u32 = null, - }; + access_mode: enum { + read_only, + read_write, + write_only, + none, + + const opts = struct { + const enum_kind = .identifier; + }; + }, + ref_index: u32, + size_index: ?u32 = null, }; pub const alias = struct { - const gnu = "alias"; - const Args = struct { - alias: Value.ByteRange, - }; + alias: Value.ByteRange, }; pub const aligned = struct { - const gnu = "aligned"; - const declspec = "align"; - - const Args = struct { - alignment: ?Alignment = null, - __name_tok: TokenIndex, - }; + alignment: ?Alignment = null, + __name_tok: TokenIndex, }; pub const alloc_align = struct { - const gnu = "alloc_align"; - - const Args = struct { - position: u32, - }; + position: u32, }; pub const alloc_size = struct { - const gnu = "alloc_size"; - - const Args = struct { - position_1: u32, - position_2: ?u32 = null, - }; + position_1: u32, + position_2: ?u32 = null, }; pub const allocate = struct { - const declspec = "allocate"; - - const Args = struct { - segname: Value.ByteRange, - }; - }; - pub const allocator = struct { - const declspec = "allocator"; - }; - pub const always_inline = struct { - const gnu = "always_inline"; - }; - pub const appdomain = struct { - const declspec = "appdomain"; - }; - pub const artificial = struct { - const gnu = "artificial"; + segname: Value.ByteRange, }; + pub const allocator = struct {}; + pub const always_inline = struct {}; + pub const appdomain = struct {}; + pub const artificial = struct {}; pub const assume_aligned = struct { - const gnu = "assume_aligned"; - const Args = struct { - alignment: Alignment, - offset: ?u32 = null, - }; + alignment: Alignment, + offset: ?u32 = null, }; pub const cleanup = struct { - const gnu = "cleanup"; - const Args = struct { - function: Identifier, - }; + function: Identifier, }; pub const code_seg = struct { - const declspec = "code_seg"; - const Args = struct { - segname: Value.ByteRange, - }; - }; - pub const cold = struct { - const gnu = "cold"; - }; - pub const common = struct { - const gnu = "common"; - }; - pub const @"const" = struct { - const gnu = "const"; + segname: Value.ByteRange, }; + pub const cold = struct {}; + pub const common = struct {}; + pub const @"const" = struct {}; pub const constructor = struct { - const gnu = "constructor"; - const Args = struct { - priority: ?u32 = null, - }; + priority: ?u32 = null, }; pub const copy = struct { - const gnu = "copy"; - const Args = struct { - function: Identifier, - }; + function: Identifier, }; pub const deprecated = struct { - const gnu = "deprecated"; - const declspec = "deprecated"; - const c2x = "deprecated"; - - const Args = struct { - msg: ?Value.ByteRange = null, - __name_tok: TokenIndex, - }; - }; - pub const designated_init = struct { - const gnu = "designated_init"; + msg: ?Value.ByteRange = null, + __name_tok: TokenIndex, }; + pub const designated_init = struct {}; pub const destructor = struct { - const gnu = "destructor"; - const Args = struct { - priority: ?u32 = null, - }; - }; - pub const dllexport = struct { - const declspec = "dllexport"; - }; - pub const dllimport = struct { - const declspec = "dllimport"; + priority: ?u32 = null, }; + pub const dllexport = struct {}; + pub const dllimport = struct {}; pub const @"error" = struct { - const gnu = "error"; - const Args = struct { - msg: Value.ByteRange, - __name_tok: TokenIndex, - }; - }; - pub const externally_visible = struct { - const gnu = "externally_visible"; - }; - pub const fallthrough = struct { - const gnu = "fallthrough"; - const c2x = "fallthrough"; - }; - pub const flatten = struct { - const gnu = "flatten"; + msg: Value.ByteRange, + __name_tok: TokenIndex, }; + pub const externally_visible = struct {}; + pub const fallthrough = struct {}; + pub const flatten = struct {}; pub const format = struct { - const gnu = "format"; - const Args = struct { - archetype: enum { - printf, - scanf, - strftime, - strfmon, - - const opts = struct { - const enum_kind = .identifier; - }; - }, - string_index: u32, - first_to_check: u32, - }; + archetype: enum { + printf, + scanf, + strftime, + strfmon, + + const opts = struct { + const enum_kind = .identifier; + }; + }, + string_index: u32, + first_to_check: u32, }; pub const format_arg = struct { - const gnu = "format_arg"; - const Args = struct { - string_index: u32, - }; - }; - pub const gnu_inline = struct { - const gnu = "gnu_inline"; - }; - pub const hot = struct { - const gnu = "hot"; + string_index: u32, }; + pub const gnu_inline = struct {}; + pub const hot = struct {}; pub const ifunc = struct { - const gnu = "ifunc"; - const Args = struct { - resolver: Value.ByteRange, - }; - }; - pub const interrupt = struct { - const gnu = "interrupt"; - }; - pub const interrupt_handler = struct { - const gnu = "interrupt_handler"; - }; - pub const jitintrinsic = struct { - const declspec = "jitintrinsic"; - }; - pub const leaf = struct { - const gnu = "leaf"; - }; - pub const malloc = struct { - const gnu = "malloc"; - }; - pub const may_alias = struct { - const gnu = "may_alias"; - }; + resolver: Value.ByteRange, + }; + pub const interrupt = struct {}; + pub const interrupt_handler = struct {}; + pub const jitintrinsic = struct {}; + pub const leaf = struct {}; + pub const malloc = struct {}; + pub const may_alias = struct {}; pub const mode = struct { - const gnu = "mode"; - const Args = struct { - mode: enum { - // zig fmt: off + mode: enum { + // zig fmt: off byte, word, pointer, BI, QI, HI, PSI, SI, PDI, @@ -565,336 +456,184 @@ const attributes = struct { BND32, BND64, // zig fmt: on - const opts = struct { - const enum_kind = .identifier; - }; - }, - }; - }; - pub const naked = struct { - const declspec = "naked"; - }; - pub const no_address_safety_analysis = struct { - const gnu = "no_address_safety_analysise"; - }; - pub const no_icf = struct { - const gnu = "no_icf"; - }; - pub const no_instrument_function = struct { - const gnu = "no_instrument_function"; - }; - pub const no_profile_instrument_function = struct { - const gnu = "no_profile_instrument_function"; - }; - pub const no_reorder = struct { - const gnu = "no_reorder"; + const opts = struct { + const enum_kind = .identifier; + }; + }, }; + pub const naked = struct {}; + pub const no_address_safety_analysis = struct {}; + pub const no_icf = struct {}; + pub const no_instrument_function = struct {}; + pub const no_profile_instrument_function = struct {}; + pub const no_reorder = struct {}; pub const no_sanitize = struct { - const gnu = "no_sanitize"; /// Todo: represent args as union? - const Args = struct { - alignment: Value.ByteRange, - object_size: ?Value.ByteRange = null, - }; - }; - pub const no_sanitize_address = struct { - const gnu = "no_sanitize_address"; - const declspec = "no_sanitize_address"; - }; - pub const no_sanitize_coverage = struct { - const gnu = "no_sanitize_coverage"; - }; - pub const no_sanitize_thread = struct { - const gnu = "no_sanitize_thread"; - }; - pub const no_sanitize_undefined = struct { - const gnu = "no_sanitize_undefined"; - }; - pub const no_split_stack = struct { - const gnu = "no_split_stack"; - }; - pub const no_stack_limit = struct { - const gnu = "no_stack_limit"; - }; - pub const no_stack_protector = struct { - const gnu = "no_stack_protector"; - }; - pub const @"noalias" = struct { - const declspec = "noalias"; - }; - pub const noclone = struct { - const gnu = "noclone"; - }; - pub const nocommon = struct { - const gnu = "nocommon"; - }; - pub const nodiscard = struct { - const c2x = "nodiscard"; - }; - pub const noinit = struct { - const gnu = "noinit"; - }; - pub const @"noinline" = struct { - const gnu = "noinline"; - const declspec = "noinline"; - }; - pub const noipa = struct { - const gnu = "noipa"; - }; + alignment: Value.ByteRange, + object_size: ?Value.ByteRange = null, + }; + pub const no_sanitize_address = struct {}; + pub const no_sanitize_coverage = struct {}; + pub const no_sanitize_thread = struct {}; + pub const no_sanitize_undefined = struct {}; + pub const no_split_stack = struct {}; + pub const no_stack_limit = struct {}; + pub const no_stack_protector = struct {}; + pub const @"noalias" = struct {}; + pub const noclone = struct {}; + pub const nocommon = struct {}; + pub const nodiscard = struct {}; + pub const noinit = struct {}; + pub const @"noinline" = struct {}; + pub const noipa = struct {}; // TODO: arbitrary number of arguments // const nonnull = struct { - // const gnu = "nonnull"; - // const Args = struct { - // arg_index: []const u32, + // // arg_index: []const u32, // }; // }; - pub const nonstring = struct { - const gnu = "nonstring"; - }; - pub const noplt = struct { - const gnu = "noplt"; - }; - pub const @"noreturn" = struct { - const gnu = "noreturn"; - const c2x = "noreturn"; - const declspec = "noreturn"; - }; + pub const nonstring = struct {}; + pub const noplt = struct {}; + pub const @"noreturn" = struct {}; // TODO: union args ? // const optimize = struct { - // const gnu = "optimize"; - // const Args = struct { - // optimize, // u32 | []const u8 -- optimize? + // // optimize, // u32 | []const u8 -- optimize? // }; // }; - pub const @"packed" = struct { - const gnu = "packed"; - }; - pub const patchable_function_entry = struct { - const gnu = "patchable_function_entry"; - }; - pub const persistent = struct { - const gnu = "persistent"; - }; - pub const process = struct { - const declspec = "process"; - }; - pub const pure = struct { - const gnu = "pure"; - }; - pub const reproducible = struct { - const c2x = "reproducible"; - }; - pub const restrict = struct { - const declspec = "restrict"; - }; - pub const retain = struct { - const gnu = "retain"; - }; - pub const returns_nonnull = struct { - const gnu = "returns_nonnull"; - }; - pub const returns_twice = struct { - const gnu = "returns_twice"; - }; - pub const safebuffers = struct { - const declspec = "safebuffers"; - }; + pub const @"packed" = struct {}; + pub const patchable_function_entry = struct {}; + pub const persistent = struct {}; + pub const process = struct {}; + pub const pure = struct {}; + pub const reproducible = struct {}; + pub const restrict = struct {}; + pub const retain = struct {}; + pub const returns_nonnull = struct {}; + pub const returns_twice = struct {}; + pub const safebuffers = struct {}; pub const scalar_storage_order = struct { - const gnu = "scalar_storage_order"; - const Args = struct { - order: enum { - @"little-endian", - @"big-endian", - - const opts = struct { - const enum_kind = .string; - }; - }, - }; + order: enum { + @"little-endian", + @"big-endian", + + const opts = struct { + const enum_kind = .string; + }; + }, }; pub const section = struct { - const gnu = "section"; - const Args = struct { - name: Value.ByteRange, - }; - }; - pub const selectany = struct { - const declspec = "selectany"; + name: Value.ByteRange, }; + pub const selectany = struct {}; pub const sentinel = struct { - const gnu = "sentinel"; - const Args = struct { - position: ?u32 = null, - }; + position: ?u32 = null, }; pub const simd = struct { - const gnu = "simd"; - const Args = struct { - mask: ?enum { - notinbranch, - inbranch, - - const opts = struct { - const enum_kind = .string; - }; - } = null, - }; + mask: ?enum { + notinbranch, + inbranch, + + const opts = struct { + const enum_kind = .string; + }; + } = null, }; pub const spectre = struct { - const declspec = "spectre"; - const Args = struct { - arg: enum { - nomitigation, - - const opts = struct { - const enum_kind = .identifier; - }; - }, - }; - }; - pub const stack_protect = struct { - const gnu = "stack_protect"; + arg: enum { + nomitigation, + + const opts = struct { + const enum_kind = .identifier; + }; + }, }; + pub const stack_protect = struct {}; pub const symver = struct { - const gnu = "symver"; - const Args = struct { - version: Value.ByteRange, // TODO: validate format "name2@nodename" - }; + version: Value.ByteRange, // TODO: validate format "name2@nodename" + }; pub const target = struct { - const gnu = "target"; - const Args = struct { - options: Value.ByteRange, // TODO: multiple arguments - }; + options: Value.ByteRange, // TODO: multiple arguments + }; pub const target_clones = struct { - const gnu = "target_clones"; - const Args = struct { - options: Value.ByteRange, // TODO: multiple arguments - }; - }; - pub const thread = struct { - const declspec = "thread"; + options: Value.ByteRange, // TODO: multiple arguments + }; + pub const thread = struct {}; pub const tls_model = struct { - const gnu = "tls_model"; - const Args = struct { - model: enum { - @"global-dynamic", - @"local-dynamic", - @"initial-exec", - @"local-exec", - - const opts = struct { - const enum_kind = .string; - }; - }, - }; - }; - pub const transparent_union = struct { - const gnu = "transparent_union"; + model: enum { + @"global-dynamic", + @"local-dynamic", + @"initial-exec", + @"local-exec", + + const opts = struct { + const enum_kind = .string; + }; + }, }; + pub const transparent_union = struct {}; pub const unavailable = struct { - const gnu = "unavailable"; - const Args = struct { - msg: ?Value.ByteRange = null, - __name_tok: TokenIndex, - }; - }; - pub const uninitialized = struct { - const gnu = "uninitialized"; - }; - pub const unsequenced = struct { - const c2x = "unsequenced"; - }; - pub const unused = struct { - const gnu = "unused"; - const c2x = "maybe_unused"; - }; - pub const used = struct { - const gnu = "used"; + msg: ?Value.ByteRange = null, + __name_tok: TokenIndex, }; + pub const uninitialized = struct {}; + pub const unsequenced = struct {}; + pub const unused = struct {}; + pub const used = struct {}; pub const uuid = struct { - const declspec = "uuid"; - const Args = struct { - uuid: Value.ByteRange, - }; + uuid: Value.ByteRange, }; pub const vector_size = struct { - const gnu = "vector_size"; - const Args = struct { - bytes: u32, // TODO: validate "The bytes argument must be a positive power-of-two multiple of the base type size" - }; + bytes: u32, // TODO: validate "The bytes argument must be a positive power-of-two multiple of the base type size" + }; pub const visibility = struct { - const gnu = "visibility"; - const Args = struct { - visibility_type: enum { - default, - hidden, - internal, - protected, - - const opts = struct { - const enum_kind = .string; - }; - }, - }; + visibility_type: enum { + default, + hidden, + internal, + protected, + + const opts = struct { + const enum_kind = .string; + }; + }, }; pub const warn_if_not_aligned = struct { - const gnu = "warn_if_not_aligned"; - const Args = struct { - alignment: Alignment, - }; - }; - pub const warn_unused_result = struct { - const gnu = "warn_unused_result"; + alignment: Alignment, }; + pub const warn_unused_result = struct {}; pub const warning = struct { - const gnu = "warning"; - const Args = struct { - msg: Value.ByteRange, - __name_tok: TokenIndex, - }; - }; - pub const weak = struct { - const gnu = "weak"; + msg: Value.ByteRange, + __name_tok: TokenIndex, }; + pub const weak = struct {}; pub const weakref = struct { - const gnu = "weakref"; - const Args = struct { - target: ?Value.ByteRange = null, - }; + target: ?Value.ByteRange = null, }; pub const zero_call_used_regs = struct { - const gnu = "zero_call_used_regs"; - const Args = struct { - choice: enum { - skip, - used, - @"used-gpr", - @"used-arg", - @"used-gpr-arg", - all, - @"all-gpr", - @"all-arg", - @"all-gpr-arg", - - const opts = struct { - const enum_kind = .string; - }; - }, - }; + choice: enum { + skip, + used, + @"used-gpr", + @"used-arg", + @"used-gpr-arg", + all, + @"all-gpr", + @"all-arg", + @"all-gpr-arg", + + const opts = struct { + const enum_kind = .string; + }; + }, }; pub const asm_label = struct { - const Args = struct { - name: Value.ByteRange, - }; + name: Value.ByteRange, }; pub const calling_convention = struct { - const Args = struct { - cc: CallingConvention, - }; + cc: CallingConvention, }; }; @@ -906,7 +645,7 @@ pub const Arguments = blk: { inline for (decls, &union_fields) |decl, *field| { field.* = .{ .name = decl.name, - .type = if (@hasDecl(@field(attributes, decl.name), "Args")) @field(attributes, decl.name).Args else void, + .type = @field(attributes, decl.name), .alignment = 0, }; } @@ -923,17 +662,16 @@ pub const Arguments = blk: { pub fn ArgumentsForTag(comptime tag: Tag) type { const decl = @typeInfo(attributes).Struct.decls[@intFromEnum(tag)]; - return if (@hasDecl(@field(attributes, decl.name), "Args")) @field(attributes, decl.name).Args else void; + return @field(attributes, decl.name); } pub fn initArguments(tag: Tag, name_tok: TokenIndex) Arguments { switch (tag) { inline else => |arg_tag| { const union_element = @field(attributes, @tagName(arg_tag)); - const has_args = @hasDecl(union_element, "Args"); - const init = if (has_args) std.mem.zeroInit(union_element.Args, .{}) else {}; + const init = std.mem.zeroInit(union_element, .{}); var args = @unionInit(Arguments, @tagName(arg_tag), init); - if (has_args and @hasField(@field(attributes, @tagName(arg_tag)).Args, "__name_tok")) { + if (@hasField(@field(attributes, @tagName(arg_tag)), "__name_tok")) { @field(args, @tagName(arg_tag)).__name_tok = name_tok; } return args; @@ -942,56 +680,23 @@ pub fn initArguments(tag: Tag, name_tok: TokenIndex) Arguments { } pub fn fromString(kind: Kind, namespace: ?[]const u8, name: []const u8) ?Tag { - return switch (kind) { - .c2x => fromStringC2X(namespace, name), - .declspec => fromStringDeclspec(name), - .gnu => fromStringGnu(name), - }; -} + const attribute_map = @import("Attribute.def"); -fn fromStringGnu(name: []const u8) ?Tag { const normalized = normalize(name); - const decls = @typeInfo(attributes).Struct.decls; - @setEvalBranchQuota(3000); - inline for (decls, 0..) |decl, i| { - if (@hasDecl(@field(attributes, decl.name), "gnu")) { - if (mem.eql(u8, @field(attributes, decl.name).gnu, normalized)) { - return @enumFromInt(i); - } - } - } - return null; -} - -fn fromStringC2X(namespace: ?[]const u8, name: []const u8) ?Tag { - const normalized = normalize(name); - if (namespace) |ns| { + const actual_kind: Kind = if (namespace) |ns| blk: { const normalized_ns = normalize(ns); if (mem.eql(u8, normalized_ns, "gnu")) { - return fromStringGnu(normalized); + break :blk .gnu; } return null; - } - const decls = @typeInfo(attributes).Struct.decls; - inline for (decls, 0..) |decl, i| { - if (@hasDecl(@field(attributes, decl.name), "c2x")) { - if (mem.eql(u8, @field(attributes, decl.name).c2x, normalized)) { - return @enumFromInt(i); - } - } - } - return null; -} + } else kind; -fn fromStringDeclspec(name: []const u8) ?Tag { - const normalized = normalize(name); - const decls = @typeInfo(attributes).Struct.decls; - inline for (decls, 0..) |decl, i| { - if (@hasDecl(@field(attributes, decl.name), "declspec")) { - if (mem.eql(u8, @field(attributes, decl.name).declspec, normalized)) { - return @enumFromInt(i); - } - } + const tag_and_opts = attribute_map.fromName(normalized) orelse return null; + switch (actual_kind) { + inline else => |tag| { + if (@field(tag_and_opts.properties, @tagName(tag))) + return tag_and_opts.properties.tag; + }, } return null; } diff --git a/src/Attribute/Attribute.def b/src/Attribute/Attribute.def new file mode 100644 index 00000000..65f92d49 --- /dev/null +++ b/src/Attribute/Attribute.def @@ -0,0 +1,434 @@ +const aro = @import("aro"); +const Properties = struct { tag: aro.Attribute.Tag, gnu: bool = false, declspec: bool = false, c2x: bool = false }; + +# multiple +deprecated + .tag = .deprecated + .c2x = true + .gnu = true + .declspec = true + +fallthrough + .tag = .fallthrough + .c2x = true + .gnu = true + +noreturn + .tag = .@"noreturn" + .c2x = true + .gnu = true + .declspec = true + +no_sanitize_address + .tag = .no_sanitize_address + .gnu = true + .declspec = true + +noinline + .tag = .@"noinline" + .gnu = true + .declspec = true + +# c2x only +nodiscard + .tag = .nodiscard + .c2x = true + +reproducible + .tag = .reproducible + .c2x = true + +unsequenced + .tag = .unsequenced + .c2x = true + +maybe_unused + .tag = .unused + .c2x = true + +# gnu only +access + .tag = .access + .gnu = true + +alias + .tag = .alias + .gnu = true + +aligned + .tag = .aligned + .gnu = true + +alloc_align + .tag = .alloc_align + .gnu = true + +alloc_size + .tag = .alloc_size + .gnu = true + +always_inline + .tag = .always_inline + .gnu = true + +artificial + .tag = .artificial + .gnu = true + +assume_aligned + .tag = .assume_aligned + .gnu = true + +cleanup + .tag = .cleanup + .gnu = true + +cold + .tag = .cold + .gnu = true + +common + .tag = .common + .gnu = true + +const + .tag = .@"const" + .gnu = true + +constructor + .tag = .constructor + .gnu = true + +copy + .tag = .copy + .gnu = true + +designated_init + .tag = .designated_init + .gnu = true + +destructor + .tag = .destructor + .gnu = true + +error + .tag = .@"error" + .gnu = true + +externally_visible + .tag = .externally_visible + .gnu = true + +flatten + .tag = .flatten + .gnu = true + +format + .tag = .format + .gnu = true + +format_arg + .tag = .format_arg + .gnu = true + +gnu_inline + .tag = .gnu_inline + .gnu = true + +hot + .tag = .hot + .gnu = true + +ifunc + .tag = .ifunc + .gnu = true + +interrupt + .tag = .interrupt + .gnu = true + +interrupt_handler + .tag = .interrupt_handler + .gnu = true + +leaf + .tag = .leaf + .gnu = true + +malloc + .tag = .malloc + .gnu = true + +may_alias + .tag = .may_alias + .gnu = true + +mode + .tag = .mode + .gnu = true + +no_address_safety_analysis + .tag = .no_address_safety_analysis + .gnu = true + +no_icf + .tag = .no_icf + .gnu = true + +no_instrument_function + .tag = .no_instrument_function + .gnu = true + +no_profile_instrument_function + .tag = .no_profile_instrument_function + .gnu = true + +no_reorder + .tag = .no_reorder + .gnu = true + +no_sanitize + .tag = .no_sanitize + .gnu = true + +no_sanitize_coverage + .tag = .no_sanitize_coverage + .gnu = true + +no_sanitize_thread + .tag = .no_sanitize_thread + .gnu = true + +no_sanitize_undefined + .tag = .no_sanitize_undefined + .gnu = true + +no_split_stack + .tag = .no_split_stack + .gnu = true + +no_stack_limit + .tag = .no_stack_limit + .gnu = true + +no_stack_protector + .tag = .no_stack_protector + .gnu = true + +noclone + .tag = .noclone + .gnu = true + +nocommon + .tag = .nocommon + .gnu = true + +noinit + .tag = .noinit + .gnu = true + +noipa + .tag = .noipa + .gnu = true + +# nonnull +# .tag = .nonnull +# .gnu = true + +nonstring + .tag = .nonstring + .gnu = true + +noplt + .tag = .noplt + .gnu = true + +# optimize +# .tag = .optimize +# .gnu = true + +packed + .tag = .@"packed" + .gnu = true + +patchable_function_entry + .tag = .patchable_function_entry + .gnu = true + +persistent + .tag = .persistent + .gnu = true + +pure + .tag = .pure + .gnu = true + +retain + .tag = .retain + .gnu = true + +returns_nonnull + .tag = .returns_nonnull + .gnu = true + +returns_twice + .tag = .returns_twice + .gnu = true + +scalar_storage_order + .tag = .scalar_storage_order + .gnu = true + +section + .tag = .section + .gnu = true + +sentinel + .tag = .sentinel + .gnu = true + +simd + .tag = .simd + .gnu = true + +stack_protect + .tag = .stack_protect + .gnu = true + +symver + .tag = .symver + .gnu = true + +target + .tag = .target + .gnu = true + +target_clones + .tag = .target_clones + .gnu = true + +tls_model + .tag = .tls_model + .gnu = true + +transparent_union + .tag = .transparent_union + .gnu = true + +unavailable + .tag = .unavailable + .gnu = true + +uninitialized + .tag = .uninitialized + .gnu = true + +unused + .tag = .unused + .gnu = true + +used + .tag = .used + .gnu = true + +vector_size + .tag = .vector_size + .gnu = true + +visibility + .tag = .visibility + .gnu = true + +warn_if_not_aligned + .tag = .warn_if_not_aligned + .gnu = true + +warn_unused_result + .tag = .warn_unused_result + .gnu = true + +warning + .tag = .warning + .gnu = true + +weak + .tag = .weak + .gnu = true + +weakref + .tag = .weakref + .gnu = true + +zero_call_used_regs + .tag = .zero_call_used_regs + .gnu = true + +# declspec only +align + .tag = .aligned + .declspec = true + +allocate + .tag = .allocate + .declspec = true + +allocator + .tag = .allocator + .declspec = true + +appdomain + .tag = .appdomain + .declspec = true + +code_seg + .tag = .code_seg + .declspec = true + +dllexport + .tag = .dllexport + .declspec = true + +dllimport + .tag = .dllimport + .declspec = true + +jitintrinsic + .tag = .jitintrinsic + .declspec = true + +naked + .tag = .naked + .declspec = true + +noalias + .tag = .@"noalias" + .declspec = true + +process + .tag = .process + .declspec = true + +restrict + .tag = .restrict + .declspec = true + +safebuffers + .tag = .safebuffers + .declspec = true + +selectany + .tag = .selectany + .declspec = true + +spectre + .tag = .spectre + .declspec = true + +thread + .tag = .thread + .declspec = true + +uuid + .tag = .uuid + .declspec = true + diff --git a/src/Diagnostics.zig b/src/Diagnostics.zig index af7a5178..c7954316 100644 --- a/src/Diagnostics.zig +++ b/src/Diagnostics.zig @@ -2,11 +2,11 @@ const std = @import("std"); const mem = std.mem; const Allocator = mem.Allocator; const aro = @import("aro"); +const Attribute = aro.Attribute; const Compilation = aro.Compilation; const Header = aro.Builtins.Properties.Header; const Source = aro.Source; const Tree = aro.Tree; -const Attribute = @import("Attribute.zig"); const Builtin = @import("Builtin.def"); const util = @import("util.zig"); const is_windows = @import("builtin").os.tag == .windows; diff --git a/src/Parser.zig b/src/Parser.zig index 3d1e28fa..87b09ac4 100644 --- a/src/Parser.zig +++ b/src/Parser.zig @@ -4,6 +4,7 @@ const Allocator = mem.Allocator; const assert = std.debug.assert; const big = std.math.big; const aro = @import("aro"); +const Attribute = aro.Attribute; const Compilation = aro.Compilation; const Diagnostics = aro.Diagnostics; const NodeIndex = Tree.NodeIndex; @@ -14,7 +15,6 @@ const Token = Tree.Token; const TokenIndex = Tree.TokenIndex; const Tokenizer = aro.Tokenizer; const Type = aro.Type; -const Attribute = @import("Attribute.zig"); const Builtin = @import("Builtin.def"); const StringId = @import("StringInterner.zig").StringId; const target_util = aro.target_util; @@ -903,7 +903,7 @@ fn decl(p: *Parser) Error!bool { break :blk DeclSpec{ .ty = try spec.finish(p) }; }; if (decl_spec.noreturn) |tok| { - const attr = Attribute{ .tag = .noreturn, .args = .{ .noreturn = {} }, .syntax = .keyword }; + const attr = Attribute{ .tag = .noreturn, .args = .{ .noreturn = .{} }, .syntax = .keyword }; try p.attr_buf.append(p.gpa, .{ .attr = attr, .tok = tok }); } var init_d = (try p.initDeclarator(&decl_spec, attr_buf_top)) orelse { diff --git a/src/Preprocessor.zig b/src/Preprocessor.zig index a4046cc1..0e6b0c78 100644 --- a/src/Preprocessor.zig +++ b/src/Preprocessor.zig @@ -3,6 +3,7 @@ const mem = std.mem; const Allocator = mem.Allocator; const assert = std.debug.assert; const aro = @import("aro"); +const Attribute = aro.Attribute; const Compilation = aro.Compilation; const Diagnostics = aro.Diagnostics; const Error = Compilation.Error; @@ -11,7 +12,6 @@ const RawToken = Tokenizer.Token; const Source = aro.Source; const Token = aro.Tree.Token; const Tokenizer = aro.Tokenizer; -const Attribute = @import("Attribute.zig"); const features = @import("features.zig"); const Preprocessor = @This(); diff --git a/src/Tree.zig b/src/Tree.zig index c7c0e08f..91d1035b 100644 --- a/src/Tree.zig +++ b/src/Tree.zig @@ -1,10 +1,10 @@ const std = @import("std"); const aro = @import("aro"); +const Attribute = aro.Attribute; const Compilation = aro.Compilation; const Source = aro.Source; const Tokenizer = aro.Tokenizer; const Type = aro.Type; -const Attribute = @import("Attribute.zig"); const StringInterner = @import("StringInterner.zig"); const Value = @import("Value.zig"); diff --git a/src/Type.zig b/src/Type.zig index c339211b..a8271347 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -1,12 +1,12 @@ const std = @import("std"); const aro = @import("aro"); +const Attribute = aro.Attribute; const Compilation = aro.Compilation; const NodeIndex = Tree.NodeIndex; const Parser = aro.Parser; const TokenIndex = Tree.TokenIndex; const Tree = aro.Tree; const target_util = aro.target_util; -const Attribute = @import("Attribute.zig"); const LangOpts = @import("LangOpts.zig"); const StringInterner = @import("StringInterner.zig"); const StringId = StringInterner.StringId; diff --git a/src/lib.zig b/src/lib.zig index d5175c0a..35424428 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -1,3 +1,4 @@ +pub const Attribute = @import("Attribute.zig"); pub const Builtins = @import("Builtins.zig"); /// Deprecated pub const Codegen = @import("Codegen_legacy.zig"); diff --git a/src/record_layout.zig b/src/record_layout.zig index 52b40509..27fb6c6e 100644 --- a/src/record_layout.zig +++ b/src/record_layout.zig @@ -3,6 +3,7 @@ const std = @import("std"); const aro = @import("aro"); +const Attribute = aro.Attribute; const Compilation = aro.Compilation; const Field = Record.Field; const FieldLayout = Type.FieldLayout; @@ -11,7 +12,6 @@ const Record = Type.Record; const target_util = aro.target_util; const Type = aro.Type; const TypeLayout = Type.TypeLayout; -const Attribute = @import("Attribute.zig"); const BITS_PER_BYTE = 8;