From d2a8660d0467c024790c7dcdeb9366d993723fd7 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 20 Nov 2023 11:19:52 +0200 Subject: [PATCH 1/2] sync Aro dependency ref: 9d538ea0253bb63c0b35ec907a3a734d1e22fc32 --- deps/aro/aro/Builtins/Builtin.def | 152 ++++++++ deps/aro/aro/Compilation.zig | 75 +++- deps/aro/aro/Diagnostics.zig | 7 +- deps/aro/aro/Driver.zig | 16 + deps/aro/aro/Driver/Filesystem.zig | 20 +- deps/aro/aro/Driver/GCCDetector.zig | 2 +- deps/aro/aro/Parser.zig | 111 ++++-- deps/aro/aro/Preprocessor.zig | 85 +++-- deps/aro/aro/SymbolStack.zig | 387 +++++++++++---------- deps/aro/aro/Tokenizer.zig | 49 +-- deps/aro/aro/Toolchain.zig | 13 +- deps/aro/aro/Tree.zig | 11 +- deps/aro/aro/{ => Tree}/number_affixes.zig | 26 +- deps/aro/aro/Type.zig | 369 +++++++++----------- deps/aro/aro/Value.zig | 2 +- deps/aro/aro/target.zig | 1 - 16 files changed, 815 insertions(+), 511 deletions(-) rename deps/aro/aro/{ => Tree}/number_affixes.zig (87%) diff --git a/deps/aro/aro/Builtins/Builtin.def b/deps/aro/aro/Builtins/Builtin.def index a924102a4fe774963300d87dbb258ac9d9f697f7..98c58848362dd6e3264e93dad2878c7cd464f596 100644 --- a/deps/aro/aro/Builtins/Builtin.def +++ b/deps/aro/aro/Builtins/Builtin.def @@ -17008,3 +17008,155 @@ wmemmove .param_str = "w*w*wC*z" .header = .wchar .attributes = .{ .lib_function_without_prefix = true, .const_evaluable = true } + +__c11_atomic_init + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_load + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_store + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_exchange + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_compare_exchange_strong + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_compare_exchange_weak + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_fetch_add + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_fetch_sub + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_fetch_and + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_fetch_or + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_fetch_xor + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_fetch_nand + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_fetch_max + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__c11_atomic_fetch_min + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_load + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_load_n + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_store + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_store_n + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_exchange + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_exchange_n + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_compare_exchange + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_compare_exchange_n + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_fetch_add + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_fetch_sub + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_fetch_and + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_fetch_or + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_fetch_xor + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_fetch_nand + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_add_fetch + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_sub_fetch + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_and_fetch + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_or_fetch + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_xor_fetch + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_max_fetch + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_min_fetch + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_nand_fetch + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_fetch_min + .param_str = "v." + .attributes = .{ .custom_typecheck = true } + +__atomic_fetch_max + .param_str = "v." + .attributes = .{ .custom_typecheck = true } diff --git a/deps/aro/aro/Compilation.zig b/deps/aro/aro/Compilation.zig index 8aba7880bcd78456f5366c5856e60a0e74725731..56ba1bb6802bec10ddb5e1519221e493396ae538 100644 --- a/deps/aro/aro/Compilation.zig +++ b/deps/aro/aro/Compilation.zig @@ -408,6 +408,17 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void { \\ ); + // atomics + try w.writeAll( + \\#define __ATOMIC_RELAXED 0 + \\#define __ATOMIC_CONSUME 1 + \\#define __ATOMIC_ACQUIRE 2 + \\#define __ATOMIC_RELEASE 3 + \\#define __ATOMIC_ACQ_REL 4 + \\#define __ATOMIC_SEQ_CST 5 + \\ + ); + // types if (comp.getCharSignedness() == .unsigned) try w.writeAll("#define __CHAR_UNSIGNED__ 1\n"); try w.writeAll("#define __CHAR_BIT__ 8\n"); @@ -445,6 +456,10 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void { try comp.generateSizeofType(w, "__SIZEOF_WCHAR_T__", comp.types.wchar); // try comp.generateSizeofType(w, "__SIZEOF_WINT_T__", .{ .specifier = .pointer }); + if (target_util.hasInt128(comp.target)) { + try comp.generateSizeofType(w, "__SIZEOF_INT128__", .{ .specifier = .int128 }); + } + // various int types const mapper = comp.string_interner.getSlowTypeMapper(); try generateTypeMacro(w, mapper, "__INTPTR_TYPE__", comp.types.intptr, comp.langopts); @@ -461,6 +476,7 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void { try generateTypeMacro(w, mapper, "__WCHAR_TYPE__", comp.types.wchar, comp.langopts); try comp.generateExactWidthTypes(w, mapper); + try comp.generateFastAndLeastWidthTypes(w, mapper); if (target_util.FPSemantics.halfPrecisionType(comp.target)) |half| { try generateFloatMacros(w, "FLT16", half, "F16"); @@ -497,10 +513,11 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi ); } + try buf.appendSlice("#define __STDC__ 1\n"); + try buf.writer().print("#define __STDC_HOSTED__ {d}\n", .{@intFromBool(comp.target.os.tag != .freestanding)}); + // standard macros try buf.appendSlice( - \\#define __STDC__ 1 - \\#define __STDC_HOSTED__ 1 \\#define __STDC_NO_ATOMICS__ 1 \\#define __STDC_NO_COMPLEX__ 1 \\#define __STDC_NO_THREADS__ 1 @@ -678,6 +695,14 @@ fn generateBuiltinTypes(comp: *Compilation) !void { /// Smallest integer type with at least N bits fn intLeastN(comp: *const Compilation, bits: usize, signedness: std.builtin.Signedness) Type { + if (bits == 64 and (comp.target.isDarwin() or comp.target.isWasm())) { + // WebAssembly and Darwin use `long long` for `int_least64_t` and `int_fast64_t`. + return .{ .specifier = if (signedness == .signed) .long_long else .ulong_long }; + } + if (bits == 16 and comp.target.cpu.arch == .avr) { + // AVR uses int for int_least16_t and int_fast16_t. + return .{ .specifier = if (signedness == .signed) .int else .uint }; + } const candidates = switch (signedness) { .signed => &[_]Type.Specifier{ .schar, .short, .int, .long, .long_long }, .unsigned => &[_]Type.Specifier{ .uchar, .ushort, .uint, .ulong, .ulong_long }, @@ -693,6 +718,52 @@ fn intSize(comp: *const Compilation, specifier: Type.Specifier) u64 { return ty.sizeof(comp).?; } +fn generateFastOrLeastType( + comp: *Compilation, + bits: usize, + kind: enum { least, fast }, + signedness: std.builtin.Signedness, + w: anytype, + mapper: StrInt.TypeMapper, +) !void { + const ty = comp.intLeastN(bits, signedness); // defining the fast types as the least types is permitted + + var buf: [32]u8 = undefined; + const suffix = "_TYPE__"; + const base_name = switch (signedness) { + .signed => "__INT_", + .unsigned => "__UINT_", + }; + const kind_str = switch (kind) { + .fast => "FAST", + .least => "LEAST", + }; + + const full = std.fmt.bufPrint(&buf, "{s}{s}{d}{s}", .{ + base_name, kind_str, bits, suffix, + }) catch return error.OutOfMemory; + + try generateTypeMacro(w, mapper, full, ty, comp.langopts); + + const prefix = full[2 .. full.len - suffix.len]; // remove "__" and "_TYPE__" + + switch (signedness) { + .signed => try comp.generateIntMaxAndWidth(w, prefix, ty), + .unsigned => try comp.generateIntMax(w, prefix, ty), + } + try comp.generateFmt(prefix, w, ty); +} + +fn generateFastAndLeastWidthTypes(comp: *Compilation, w: anytype, mapper: StrInt.TypeMapper) !void { + const sizes = [_]usize{ 8, 16, 32, 64 }; + for (sizes) |size| { + try comp.generateFastOrLeastType(size, .least, .signed, w, mapper); + try comp.generateFastOrLeastType(size, .least, .unsigned, w, mapper); + try comp.generateFastOrLeastType(size, .fast, .signed, w, mapper); + try comp.generateFastOrLeastType(size, .fast, .unsigned, w, mapper); + } +} + fn generateExactWidthTypes(comp: *const Compilation, w: anytype, mapper: StrInt.TypeMapper) !void { try comp.generateExactWidthType(w, mapper, .schar); diff --git a/deps/aro/aro/Diagnostics.zig b/deps/aro/aro/Diagnostics.zig index 0e7bc30864d58f9de3c168343631797c44e23183..f0c08a36ca05bb1988a7a175121c0172d7af6e7a 100644 --- a/deps/aro/aro/Diagnostics.zig +++ b/deps/aro/aro/Diagnostics.zig @@ -236,7 +236,7 @@ pub fn set(d: *Diagnostics, name: []const u8, to: Kind) !void { try d.addExtra(.{}, .{ .tag = .unknown_warning, .extra = .{ .str = name }, - }, &.{}); + }, &.{}, true); } pub fn init(gpa: Allocator) Diagnostics { @@ -251,7 +251,7 @@ pub fn deinit(d: *Diagnostics) void { } pub fn add(comp: *Compilation, msg: Message, expansion_locs: []const Source.Location) Compilation.Error!void { - return comp.diagnostics.addExtra(comp.langopts, msg, expansion_locs); + return comp.diagnostics.addExtra(comp.langopts, msg, expansion_locs, true); } pub fn addExtra( @@ -259,6 +259,7 @@ pub fn addExtra( langopts: LangOpts, msg: Message, expansion_locs: []const Source.Location, + note_msg_loc: bool, ) Compilation.Error!void { const kind = d.tagKind(msg.tag, langopts); if (kind == .off) return; @@ -301,7 +302,7 @@ pub fn addExtra( } } - d.list.appendAssumeCapacity(.{ + if (note_msg_loc) d.list.appendAssumeCapacity(.{ .tag = .expanded_from_here, .kind = .note, .loc = msg.loc, diff --git a/deps/aro/aro/Driver.zig b/deps/aro/aro/Driver.zig index d1b32b9c15eaf08547a9446689b4265b747cf973..18a24b86a7ed0343aab92cf3c9b3e868987b2cfc 100644 --- a/deps/aro/aro/Driver.zig +++ b/deps/aro/aro/Driver.zig @@ -98,8 +98,10 @@ pub const usage = \\ -fno-declspec Disable support for __declspec attributes \\ -ffp-eval-method=[source|double|extended] \\ Evaluation method to use for floating-point arithmetic + \\ -ffreestanding Compilation in a freestanding environment \\ -fgnu-inline-asm Enable GNU style inline asm (default: enabled) \\ -fno-gnu-inline-asm Disable GNU style inline asm + \\ -fhosted Compilation in a hosted environment \\ -fms-extensions Enable support for Microsoft extensions \\ -fno-ms-extensions Disable support for Microsoft extensions \\ -fdollars-in-identifiers @@ -177,6 +179,7 @@ pub fn parseArgs( ) !bool { var i: usize = 1; var comment_arg: []const u8 = ""; + var hosted: ?bool = null; while (i < args.len) : (i += 1) { const arg = args[i]; if (mem.startsWith(u8, arg, "-") and arg.len > 1) { @@ -277,6 +280,10 @@ pub fn parseArgs( d.comp.langopts.declspec_attrs = true; } else if (mem.eql(u8, arg, "-fno-declspec")) { d.comp.langopts.declspec_attrs = false; + } else if (mem.eql(u8, arg, "-ffreestanding")) { + hosted = false; + } else if (mem.eql(u8, arg, "-fhosted")) { + hosted = true; } else if (mem.eql(u8, arg, "-fms-extensions")) { d.comp.langopts.enableMSExtensions(); } else if (mem.eql(u8, arg, "-fno-ms-extensions")) { @@ -440,6 +447,15 @@ pub fn parseArgs( if (d.comp.langopts.preserve_comments and !d.only_preprocess) { return d.fatal("invalid argument '{s}' only allowed with '-E'", .{comment_arg}); } + if (hosted) |is_hosted| { + if (is_hosted) { + if (d.comp.target.os.tag == .freestanding) { + return d.fatal("Cannot use freestanding target with `-fhosted`", .{}); + } + } else { + d.comp.target.os.tag = .freestanding; + } + } return false; } diff --git a/deps/aro/aro/Driver/Filesystem.zig b/deps/aro/aro/Driver/Filesystem.zig index c5b855927ffd389e82939ff4e0153063858869fe..f9a652ac76e11ac83466ea63d7a3db7483036133 100644 --- a/deps/aro/aro/Driver/Filesystem.zig +++ b/deps/aro/aro/Driver/Filesystem.zig @@ -121,7 +121,7 @@ pub const Filesystem = union(enum) { base: []const u8, i: usize = 0, - fn next(self: *@This()) !?std.fs.IterableDir.Entry { + fn next(self: *@This()) !?std.fs.Dir.Entry { while (self.i < self.entries.len) { const entry = self.entries[self.i]; self.i += 1; @@ -130,7 +130,7 @@ pub const Filesystem = union(enum) { const remaining = entry.path[self.base.len + 1 ..]; if (std.mem.indexOfScalar(u8, remaining, std.fs.path.sep) != null) continue; const extension = std.fs.path.extension(remaining); - const kind: std.fs.IterableDir.Entry.Kind = if (extension.len == 0) .directory else .file; + const kind: std.fs.Dir.Entry.Kind = if (extension.len == 0) .directory else .file; return .{ .name = remaining, .kind = kind }; } } @@ -139,18 +139,18 @@ pub const Filesystem = union(enum) { }; }; - const IterableDir = union(enum) { - dir: std.fs.IterableDir, + const Dir = union(enum) { + dir: std.fs.Dir, fake: FakeDir, - pub fn iterate(self: IterableDir) Iterator { + pub fn iterate(self: Dir) Iterator { return switch (self) { .dir => |dir| .{ .iterator = dir.iterate() }, .fake => |fake| .{ .fake = fake.iterate() }, }; } - pub fn close(self: *IterableDir) void { + pub fn close(self: *Dir) void { switch (self.*) { .dir => |*d| d.close(), .fake => {}, @@ -159,10 +159,10 @@ pub const Filesystem = union(enum) { }; const Iterator = union(enum) { - iterator: std.fs.IterableDir.Iterator, + iterator: std.fs.Dir.Iterator, fake: FakeDir.Iterator, - pub fn next(self: *Iterator) std.fs.IterableDir.Iterator.Error!?std.fs.IterableDir.Entry { + pub fn next(self: *Iterator) std.fs.Dir.Iterator.Error!?std.fs.Dir.Entry { return switch (self.*) { .iterator => |*it| it.next(), .fake => |*it| it.next(), @@ -221,9 +221,9 @@ pub const Filesystem = union(enum) { }; } - pub fn openIterableDir(fs: Filesystem, dir_name: []const u8) std.fs.Dir.OpenError!IterableDir { + pub fn openDir(fs: Filesystem, dir_name: []const u8) std.fs.Dir.OpenError!Dir { return switch (fs) { - .real => .{ .dir = try std.fs.cwd().openIterableDir(dir_name, .{ .access_sub_paths = false }) }, + .real => .{ .dir = try std.fs.cwd().openDir(dir_name, .{ .access_sub_paths = false, .iterate = true }) }, .fake => |entries| .{ .fake = .{ .entries = entries, .path = dir_name } }, }; } diff --git a/deps/aro/aro/Driver/GCCDetector.zig b/deps/aro/aro/Driver/GCCDetector.zig index 79576270cd4aba95ef134e540bf7c23d6d684bd2..4524fcade8e4f8538f19fb9706c42b713e46507f 100644 --- a/deps/aro/aro/Driver/GCCDetector.zig +++ b/deps/aro/aro/Driver/GCCDetector.zig @@ -602,7 +602,7 @@ fn scanLibDirForGCCTriple( const lib_suffix = std.fs.path.join(suffix_buf_fib.allocator(), &.{ base, candidate_triple }) catch continue; const dir_name = std.fs.path.join(fib.allocator(), &.{ lib_dir, lib_suffix }) catch continue; - var parent_dir = tc.filesystem.openIterableDir(dir_name) catch continue; + var parent_dir = tc.filesystem.openDir(dir_name) catch continue; defer parent_dir.close(); var it = parent_dir.iterate(); diff --git a/deps/aro/aro/Parser.zig b/deps/aro/aro/Parser.zig index 13469da734597dad37155beae515e842e24c876f..99f5ef7b6ad9054bf937f516c919127e04ce1a97 100644 --- a/deps/aro/aro/Parser.zig +++ b/deps/aro/aro/Parser.zig @@ -9,6 +9,8 @@ const Tokenizer = @import("Tokenizer.zig"); const Preprocessor = @import("Preprocessor.zig"); const Tree = @import("Tree.zig"); const Token = Tree.Token; +const NumberPrefix = Token.NumberPrefix; +const NumberSuffix = Token.NumberSuffix; const TokenIndex = Tree.TokenIndex; const NodeIndex = Tree.NodeIndex; const Type = @import("Type.zig"); @@ -24,9 +26,6 @@ const Symbol = SymbolStack.Symbol; const record_layout = @import("record_layout.zig"); const StrInt = @import("StringInterner.zig"); const StringId = StrInt.StringId; -const number_affixes = @import("number_affixes.zig"); -const NumberPrefix = number_affixes.Prefix; -const NumberSuffix = number_affixes.Suffix; const Builtins = @import("Builtins.zig"); const Builtin = Builtins.Builtin; const target_util = @import("target.zig"); @@ -323,7 +322,7 @@ fn expectIdentifier(p: *Parser) Error!TokenIndex { return p.errExpectedToken(.identifier, actual); } - return (try p.eatIdentifier()) orelse unreachable; + return (try p.eatIdentifier()) orelse error.ParsingFailed; } fn eatToken(p: *Parser, id: Token.Id) ?TokenIndex { @@ -347,7 +346,7 @@ pub fn tokSlice(p: *Parser, tok: TokenIndex) []const u8 { const loc = p.pp.tokens.items(.loc)[tok]; var tmp_tokenizer = Tokenizer{ .buf = p.comp.getSource(loc.id).buf, - .comp = p.comp, + .langopts = p.comp.langopts, .index = loc.byte_offset, .source = .generated, }; @@ -715,6 +714,9 @@ pub fn parse(pp: *Preprocessor) Compilation.Error!Tree { p.field_attr_buf.deinit(); } + try p.syms.pushScope(&p); + defer p.syms.popScope(); + // NodeIndex 0 must be invalid _ = try p.addNode(.{ .tag = .invalid, .ty = undefined, .data = undefined }); @@ -1010,7 +1012,7 @@ fn decl(p: *Parser) Error!bool { // Collect old style parameter declarations. if (init_d.d.old_style_func != null) { const attrs = init_d.d.ty.getAttributes(); - var base_ty = if (init_d.d.ty.specifier == .attributed) init_d.d.ty.elemType() else init_d.d.ty; + var base_ty = if (init_d.d.ty.specifier == .attributed) init_d.d.ty.data.attributed.base else init_d.d.ty; base_ty.specifier = .func; init_d.d.ty = try base_ty.withAttributes(p.arena, attrs); @@ -1066,7 +1068,7 @@ fn decl(p: *Parser) Error!bool { d.ty = try Attribute.applyParameterAttributes(p, d.ty, attr_buf_top_declarator, .alignas_on_param); // bypass redefinition check to avoid duplicate errors - try p.syms.syms.append(p.gpa, .{ + try p.syms.define(p.gpa, .{ .kind = .def, .name = interned_name, .tok = d.name, @@ -1088,7 +1090,7 @@ fn decl(p: *Parser) Error!bool { } // bypass redefinition check to avoid duplicate errors - try p.syms.syms.append(p.gpa, .{ + try p.syms.define(p.gpa, .{ .kind = .def, .name = param.name, .tok = param.name_tok, @@ -1428,12 +1430,14 @@ fn typeof(p: *Parser) Error!?Type { .data = typeof_expr.ty.data, .qual = if (unqual) .{} else typeof_expr.ty.qual.inheritFromTypeof(), .specifier = typeof_expr.ty.specifier, + .decayed = typeof_expr.ty.decayed, }, }; return Type{ .data = .{ .expr = inner }, .specifier = .typeof_expr, + .decayed = typeof_expr.ty.decayed, }; } @@ -1814,6 +1818,7 @@ fn initDeclarator(p: *Parser, decl_spec: *DeclSpec, attr_buf_top: usize) Error!? } else { init_d.d.ty.specifier = init_d.initializer.ty.specifier; init_d.d.ty.data = init_d.initializer.ty.data; + init_d.d.ty.decayed = init_d.initializer.ty.decayed; } } if (apply_var_attributes) { @@ -2105,7 +2110,7 @@ fn recordSpec(p: *Parser) Error!Type { .specifier = if (is_struct) .@"struct" else .@"union", .data = .{ .record = record_ty }, }, attr_buf_top, null); - try p.syms.syms.append(p.gpa, .{ + try p.syms.define(p.gpa, .{ .kind = if (is_struct) .@"struct" else .@"union", .name = interned_name, .tok = ident, @@ -2151,10 +2156,8 @@ fn recordSpec(p: *Parser) Error!Type { // declare a symbol for the type // We need to replace the symbol's type if it has attributes - var symbol_index: ?usize = null; if (maybe_ident != null and !defined) { - symbol_index = p.syms.syms.len; - try p.syms.syms.append(p.gpa, .{ + try p.syms.define(p.gpa, .{ .kind = if (is_struct) .@"struct" else .@"union", .name = record_ty.name, .tok = maybe_ident.?, @@ -2216,8 +2219,11 @@ fn recordSpec(p: *Parser) Error!Type { .specifier = if (is_struct) .@"struct" else .@"union", .data = .{ .record = record_ty }, }, attr_buf_top, null); - if (ty.specifier == .attributed and symbol_index != null) { - p.syms.syms.items(.ty)[symbol_index.?] = ty; + if (ty.specifier == .attributed and maybe_ident != null) { + const ident_str = p.tokSlice(maybe_ident.?); + const interned_name = try StrInt.intern(p.comp, ident_str); + const ptr = p.syms.getPtr(interned_name, .tags); + ptr.ty = ty; } if (!ty.hasIncompleteSize()) { @@ -2474,7 +2480,7 @@ fn enumSpec(p: *Parser) Error!Type { .specifier = .@"enum", .data = .{ .@"enum" = enum_ty }, }, attr_buf_top, null); - try p.syms.syms.append(p.gpa, .{ + try p.syms.define(p.gpa, .{ .kind = .@"enum", .name = interned_name, .tok = ident, @@ -2525,7 +2531,6 @@ fn enumSpec(p: *Parser) Error!Type { p.enum_buf.items.len = enum_buf_top; } - const sym_stack_top = p.syms.syms.len; var e = Enumerator.init(fixed_ty); while (try p.enumerator(&e)) |field_and_node| { try p.enum_buf.append(field_and_node.field); @@ -2551,13 +2556,12 @@ fn enumSpec(p: *Parser) Error!Type { const field_nodes = p.list_buf.items[list_buf_top..]; if (fixed_ty == null) { - const vals = p.syms.syms.items(.val)[sym_stack_top..]; - const types = p.syms.syms.items(.ty)[sym_stack_top..]; - for (enum_fields, 0..) |*field, i| { if (field.ty.eql(Type.int, p.comp, false)) continue; - var res = Result{ .node = field.node, .ty = field.ty, .val = vals[i] }; + const sym = p.syms.get(field.name, .vars) orelse continue; + + var res = Result{ .node = field.node, .ty = field.ty, .val = sym.val }; const dest_ty = if (p.comp.fixedEnumTagSpecifier()) |some| Type{ .specifier = some } else if (try res.intFitsInType(p, Type.int)) @@ -2567,8 +2571,9 @@ fn enumSpec(p: *Parser) Error!Type { else continue; - try vals[i].intCast(dest_ty, p.comp); - types[i] = dest_ty; + const symbol = p.syms.getPtr(field.name, .vars); + try symbol.val.intCast(dest_ty, p.comp); + symbol.ty = dest_ty; p.nodes.items(.ty)[@intFromEnum(field_nodes[i])] = dest_ty; field.ty = dest_ty; res.ty = dest_ty; @@ -2585,7 +2590,7 @@ fn enumSpec(p: *Parser) Error!Type { // declare a symbol for the type if (maybe_ident != null and !defined) { - try p.syms.syms.append(p.gpa, .{ + try p.syms.define(p.gpa, .{ .kind = .@"enum", .name = enum_ty.name, .ty = ty, @@ -2885,7 +2890,7 @@ fn declarator( try res.ty.combine(outer); try res.ty.validateCombinedType(p, suffix_start); res.old_style_func = d.old_style_func; - res.func_declarator = d.func_declarator; + if (d.func_declarator) |some| res.func_declarator = some; return res; } @@ -4376,7 +4381,7 @@ fn stmt(p: *Parser) Error!NodeIndex { /// | keyword_default ':' stmt fn labeledStmt(p: *Parser) Error!?NodeIndex { if ((p.tok_ids[p.tok_i] == .identifier or p.tok_ids[p.tok_i] == .extended_identifier) and p.tok_ids[p.tok_i + 1] == .colon) { - const name_tok = p.expectIdentifier() catch unreachable; + const name_tok = try p.expectIdentifier(); const str = p.tokSlice(name_tok); if (p.findLabel(str)) |some| { try p.errStr(.duplicate_label, name_tok, str); @@ -4814,10 +4819,23 @@ const CallExpr = union(enum) { /// of arguments, `paramCountOverride` is used to tell us how many arguments we should actually expect to see for /// these custom-typechecked functions. fn paramCountOverride(self: CallExpr) ?u32 { + @setEvalBranchQuota(10_000); return switch (self) { .standard => null, .builtin => |builtin| switch (builtin.tag) { Builtin.tagFromName("__builtin_complex").? => 2, + + Builtin.tagFromName("__atomic_fetch_add").?, + Builtin.tagFromName("__atomic_fetch_sub").?, + Builtin.tagFromName("__atomic_fetch_and").?, + Builtin.tagFromName("__atomic_fetch_xor").?, + Builtin.tagFromName("__atomic_fetch_or").?, + Builtin.tagFromName("__atomic_fetch_nand").?, + => 3, + + Builtin.tagFromName("__atomic_compare_exchange").?, + Builtin.tagFromName("__atomic_compare_exchange_n").?, + => 6, else => null, }, }; @@ -4827,10 +4845,25 @@ const CallExpr = union(enum) { return switch (self) { .standard => callable_ty.returnType(), .builtin => |builtin| switch (builtin.tag) { + Builtin.tagFromName("__atomic_fetch_add").?, + Builtin.tagFromName("__atomic_fetch_sub").?, + Builtin.tagFromName("__atomic_fetch_and").?, + Builtin.tagFromName("__atomic_fetch_xor").?, + Builtin.tagFromName("__atomic_fetch_or").?, + Builtin.tagFromName("__atomic_fetch_nand").?, + => { + if (p.list_buf.items.len < 2) return Type.invalid; // not enough arguments; already an error + const second_param = p.list_buf.items[p.list_buf.items.len - 2]; + return p.nodes.items(.ty)[@intFromEnum(second_param)]; + }, Builtin.tagFromName("__builtin_complex").? => { + if (p.list_buf.items.len < 1) return Type.invalid; // not enough arguments; already an error const last_param = p.list_buf.items[p.list_buf.items.len - 1]; return p.nodes.items(.ty)[@intFromEnum(last_param)].makeComplex(); }, + Builtin.tagFromName("__atomic_compare_exchange").?, + Builtin.tagFromName("__atomic_compare_exchange_n").?, + => .{ .specifier = .bool }, else => callable_ty.returnType(), }, }; @@ -7458,7 +7491,7 @@ fn primaryExpr(p: *Parser) Error!Result { } switch (p.tok_ids[p.tok_i]) { .identifier, .extended_identifier => { - const name_tok = p.expectIdentifier() catch unreachable; + const name_tok = try p.expectIdentifier(); const name = p.tokSlice(name_tok); const interned_name = try StrInt.intern(p.comp, name); if (p.syms.findSymbol(interned_name)) |sym| { @@ -7938,6 +7971,8 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result { .F, .IF => .float, .F16 => .float16, .L, .IL => .long_double, + .W, .IW => .float80, + .Q, .IQ, .F128, .IF128 => .float128, else => unreachable, } }; const val = try Value.intern(p.comp, key: { @@ -7946,7 +7981,7 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result { const strings_top = p.strings.items.len; defer p.strings.items.len = strings_top; for (buf) |c| { - if (c != '_') p.strings.appendAssumeCapacity(c); + if (c != '\'') p.strings.appendAssumeCapacity(c); } const float = std.fmt.parseFloat(f128, p.strings.items[strings_top..]) catch unreachable; @@ -7971,6 +8006,8 @@ fn parseFloat(p: *Parser, buf: []const u8, suffix: NumberSuffix) !Result { .I => .complex_double, .IF => .complex_float, .IL => .complex_long_double, + .IW => .complex_float80, + .IQ, .IF128 => .complex_float128, else => unreachable, } }; res.val = .{}; // TODO add complex values @@ -8123,11 +8160,21 @@ fn bitInt(p: *Parser, base: u8, buf: []const u8, suffix: NumberSuffix, tok_i: To var managed = try big.int.Managed.init(p.gpa); defer managed.deinit(); - managed.setString(base, buf) catch |e| switch (e) { - error.InvalidBase => unreachable, // `base` is one of 2, 8, 10, 16 - error.InvalidCharacter => unreachable, // digits validated by Tokenizer - else => |er| return er, - }; + { + try p.strings.ensureUnusedCapacity(buf.len); + + const strings_top = p.strings.items.len; + defer p.strings.items.len = strings_top; + for (buf) |c| { + if (c != '\'') p.strings.appendAssumeCapacity(c); + } + + managed.setString(base, p.strings.items[strings_top..]) catch |e| switch (e) { + error.InvalidBase => unreachable, // `base` is one of 2, 8, 10, 16 + error.InvalidCharacter => unreachable, // digits validated by Tokenizer + else => |er| return er, + }; + } const c = managed.toConst(); const bits_needed: std.math.IntFittingRange(0, Compilation.bit_int_max_bits) = blk: { // Literal `0` requires at least 1 bit diff --git a/deps/aro/aro/Preprocessor.zig b/deps/aro/aro/Preprocessor.zig index f28153d6ee370666540de1e2e49333b584e11840..58af2099afb380119e72893ca06333507be0e1fd 100644 --- a/deps/aro/aro/Preprocessor.zig +++ b/deps/aro/aro/Preprocessor.zig @@ -315,7 +315,7 @@ fn invalidTokenDiagnostic(tok_id: Token.Id) Diagnostics.Tag { fn findIncludeGuard(pp: *Preprocessor, source: Source) ?[]const u8 { var tokenizer = Tokenizer{ .buf = source.buf, - .comp = pp.comp, + .langopts = pp.comp.langopts, .source = source.id, }; var hash = tokenizer.nextNoWS(); @@ -334,7 +334,7 @@ fn preprocessExtra(pp: *Preprocessor, source: Source) MacroError!Token { pp.preprocess_count += 1; var tokenizer = Tokenizer{ .buf = source.buf, - .comp = pp.comp, + .langopts = pp.comp.langopts, .source = source.id, }; @@ -747,6 +747,17 @@ fn fatal(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anyty return error.FatalError; } +fn fatalNotFound(pp: *Preprocessor, tok: Token, filename: []const u8) Compilation.Error { + const old = pp.comp.diagnostics.fatal_errors; + pp.comp.diagnostics.fatal_errors = true; + defer pp.comp.diagnostics.fatal_errors = old; + + try pp.comp.diagnostics.addExtra(pp.comp.langopts, .{ .tag = .cli_error, .loc = tok.loc, .extra = .{ + .str = try std.fmt.allocPrint(pp.comp.diagnostics.arena.allocator(), "'{s}' not found", .{filename}), + } }, tok.expansionSlice(), false); + unreachable; // addExtra should've returned FatalError +} + fn verboseLog(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: anytype) void { const source = pp.comp.getSource(raw.source); const line_col = source.lineCol(.{ .id = raw.source, .line = raw.line, .byte_offset = raw.start }); @@ -1185,7 +1196,7 @@ fn pragmaOperator(pp: *Preprocessor, arg_tok: Token, operator_loc: Source.Locati try pp.comp.generated_buf.appendSlice(pp.gpa, pp.char_buf.items); var tmp_tokenizer = Tokenizer{ .buf = pp.comp.generated_buf.items, - .comp = pp.comp, + .langopts = pp.comp.langopts, .index = @intCast(start), .source = .generated, .line = pp.generated_line, @@ -1864,7 +1875,7 @@ fn expandVaOpt( .buf = source.buf, .index = raw.start, .source = raw.source, - .comp = pp.comp, + .langopts = pp.comp.langopts, .line = raw.line, }; while (tokenizer.index < raw.end) { @@ -2282,11 +2293,11 @@ fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, raw: RawToken) MacroErr fn expandedSliceExtra(pp: *const Preprocessor, tok: Token, macro_ws_handling: enum { single_macro_ws, preserve_macro_ws }) []const u8 { if (tok.id.lexeme()) |some| { - if (!tok.id.allowsDigraphs(pp.comp) and !(tok.id == .macro_ws and macro_ws_handling == .preserve_macro_ws)) return some; + if (!tok.id.allowsDigraphs(pp.comp.langopts) and !(tok.id == .macro_ws and macro_ws_handling == .preserve_macro_ws)) return some; } var tmp_tokenizer = Tokenizer{ .buf = pp.comp.getSource(tok.loc.id).buf, - .comp = pp.comp, + .langopts = pp.comp.langopts, .index = tok.loc.byte_offset, .source = .generated, }; @@ -2340,7 +2351,7 @@ fn pasteTokens(pp: *Preprocessor, lhs_toks: *ExpandBuf, rhs_toks: []const Token) // Try to tokenize the result. var tmp_tokenizer = Tokenizer{ .buf = pp.comp.generated_buf.items, - .comp = pp.comp, + .langopts = pp.comp.langopts, .index = @intCast(start), .source = .generated, }; @@ -2703,6 +2714,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void { error.InvalidInclude => return, else => |e| return e, }; + defer Token.free(filename_tok.expansion_locs, pp.gpa); // Check for empty filename. const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws); @@ -2836,7 +2848,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void { } const embed_bytes = (try pp.comp.findEmbed(filename, first.source, include_type, limit)) orelse - return pp.fatal(first, "'{s}' not found", .{filename}); + return pp.fatalNotFound(filename_tok, filename); defer pp.comp.gpa.free(embed_bytes); try Range.expand(prefix, pp, tokenizer); @@ -2984,8 +2996,6 @@ fn findIncludeFilenameToken( tokenizer: *Tokenizer, trailing_token_behavior: enum { ignore_trailing_tokens, expect_nl_eof }, ) !Token { - const start = pp.tokens.len; - defer pp.tokens.len = start; var first = first_token; if (first.id == .angle_bracket_left) to_end: { @@ -3008,35 +3018,60 @@ fn findIncludeFilenameToken( }, &.{}); try pp.err(first, .header_str_match); } - // Try to expand if the argument is a macro. - try pp.expandMacro(tokenizer, first); - // Check that we actually got a string. - const filename_tok = pp.tokens.get(start); - switch (filename_tok.id) { - .string_literal, .macro_string => {}, - else => { - try pp.err(first, .expected_filename); - try pp.expectNl(tokenizer); - return error.InvalidInclude; + const source_tok = tokFromRaw(first); + const filename_tok, const expanded_trailing = switch (source_tok.id) { + .string_literal, .macro_string => .{ source_tok, false }, + else => expanded: { + // Try to expand if the argument is a macro. + pp.top_expansion_buf.items.len = 0; + defer for (pp.top_expansion_buf.items) |tok| Token.free(tok.expansion_locs, pp.gpa); + try pp.top_expansion_buf.append(source_tok); + pp.expansion_source_loc = source_tok.loc; + + try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, 1, true, .non_expr); + var trailing_toks: []const Token = &.{}; + const include_str = (try pp.reconstructIncludeString(pp.top_expansion_buf.items, &trailing_toks)) orelse { + try pp.err(first, .expected_filename); + try pp.expectNl(tokenizer); + return error.InvalidInclude; + }; + const start = pp.comp.generated_buf.items.len; + try pp.comp.generated_buf.appendSlice(pp.gpa, include_str); + + break :expanded .{ try pp.makeGeneratedToken(start, switch (include_str[0]) { + '"' => .string_literal, + '<' => .macro_string, + else => unreachable, + }, pp.top_expansion_buf.items[0]), trailing_toks.len != 0 }; }, - } + }; + switch (trailing_token_behavior) { .expect_nl_eof => { // Error on extra tokens. const nl = tokenizer.nextNoWS(); - if ((nl.id != .nl and nl.id != .eof) or pp.tokens.len > start + 1) { + if ((nl.id != .nl and nl.id != .eof) or expanded_trailing) { skipToNl(tokenizer); - try pp.err(first, .extra_tokens_directive_end); + try pp.comp.diagnostics.addExtra(pp.comp.langopts, .{ + .tag = .extra_tokens_directive_end, + .loc = filename_tok.loc, + }, filename_tok.expansionSlice(), false); } }, - .ignore_trailing_tokens => {}, + .ignore_trailing_tokens => if (expanded_trailing) { + try pp.comp.diagnostics.addExtra(pp.comp.langopts, .{ + .tag = .extra_tokens_directive_end, + .loc = filename_tok.loc, + }, filename_tok.expansionSlice(), false); + }, } return filename_tok; } fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken, which: Compilation.WhichInclude) !Source { const filename_tok = try pp.findIncludeFilenameToken(first, tokenizer, .expect_nl_eof); + defer Token.free(filename_tok.expansion_locs, pp.gpa); // Check for empty filename. const tok_slice = pp.expandedSliceExtra(filename_tok, .single_macro_ws); @@ -3054,7 +3089,7 @@ fn findIncludeSource(pp: *Preprocessor, tokenizer: *Tokenizer, first: RawToken, }; return (try pp.comp.findInclude(filename, first, include_type, which)) orelse - pp.fatal(first, "'{s}' not found", .{filename}); + return pp.fatalNotFound(filename_tok, filename); } fn printLinemarker( diff --git a/deps/aro/aro/SymbolStack.zig b/deps/aro/aro/SymbolStack.zig index 77c6e2f3b239a54e56848684c782239f301d6061..dba722344701325cd516c4304d5a800002623bd4 100644 --- a/deps/aro/aro/SymbolStack.zig +++ b/deps/aro/aro/SymbolStack.zig @@ -11,6 +11,8 @@ const Parser = @import("Parser.zig"); const Value = @import("Value.zig"); const StringId = @import("StringInterner.zig").StringId; +const SymbolStack = @This(); + pub const Symbol = struct { name: StringId, ty: Type, @@ -31,72 +33,74 @@ pub const Kind = enum { constexpr, }; -const SymbolStack = @This(); +scopes: std.ArrayListUnmanaged(Scope) = .{}, +/// allocations from nested scopes are retained after popping; `active_len` is the number +/// of currently-active items in `scopes`. +active_len: usize = 0, -syms: std.MultiArrayList(Symbol) = .{}, -scopes: std.ArrayListUnmanaged(u32) = .{}, +const Scope = struct { + vars: std.AutoHashMapUnmanaged(StringId, Symbol) = .{}, + tags: std.AutoHashMapUnmanaged(StringId, Symbol) = .{}, + + fn deinit(self: *Scope, allocator: Allocator) void { + self.vars.deinit(allocator); + self.tags.deinit(allocator); + } + + fn clearRetainingCapacity(self: *Scope) void { + self.vars.clearRetainingCapacity(); + self.tags.clearRetainingCapacity(); + } +}; pub fn deinit(s: *SymbolStack, gpa: Allocator) void { - s.syms.deinit(gpa); + std.debug.assert(s.active_len == 0); // all scopes should have been popped + for (s.scopes.items) |*scope| { + scope.deinit(gpa); + } s.scopes.deinit(gpa); s.* = undefined; } -pub fn scopeEnd(s: SymbolStack) u32 { - if (s.scopes.items.len == 0) return 0; - return s.scopes.items[s.scopes.items.len - 1]; -} - pub fn pushScope(s: *SymbolStack, p: *Parser) !void { - try s.scopes.append(p.gpa, @intCast(s.syms.len)); + if (s.active_len + 1 > s.scopes.items.len) { + try s.scopes.append(p.gpa, .{}); + s.active_len = s.scopes.items.len; + } else { + s.scopes.items[s.active_len].clearRetainingCapacity(); + s.active_len += 1; + } } pub fn popScope(s: *SymbolStack) void { - s.syms.len = s.scopes.pop(); + s.active_len -= 1; } pub fn findTypedef(s: *SymbolStack, p: *Parser, name: StringId, name_tok: TokenIndex, no_type_yet: bool) !?Symbol { - const kinds = s.syms.items(.kind); - const names = s.syms.items(.name); - var i = s.syms.len; - while (i > 0) { - i -= 1; - switch (kinds[i]) { - .typedef => if (names[i] == name) return s.syms.get(i), - .@"struct" => if (names[i] == name) { - if (no_type_yet) return null; - try p.errStr(.must_use_struct, name_tok, p.tokSlice(name_tok)); - return s.syms.get(i); - }, - .@"union" => if (names[i] == name) { - if (no_type_yet) return null; - try p.errStr(.must_use_union, name_tok, p.tokSlice(name_tok)); - return s.syms.get(i); - }, - .@"enum" => if (names[i] == name) { - if (no_type_yet) return null; - try p.errStr(.must_use_enum, name_tok, p.tokSlice(name_tok)); - return s.syms.get(i); - }, - .def, .decl, .constexpr => if (names[i] == name) return null, - else => {}, - } + const prev = s.lookup(name, .vars) orelse s.lookup(name, .tags) orelse return null; + switch (prev.kind) { + .typedef => return prev, + .@"struct" => { + if (no_type_yet) return null; + try p.errStr(.must_use_struct, name_tok, p.tokSlice(name_tok)); + return prev; + }, + .@"union" => { + if (no_type_yet) return null; + try p.errStr(.must_use_union, name_tok, p.tokSlice(name_tok)); + return prev; + }, + .@"enum" => { + if (no_type_yet) return null; + try p.errStr(.must_use_enum, name_tok, p.tokSlice(name_tok)); + return prev; + }, + else => return null, } - return null; } pub fn findSymbol(s: *SymbolStack, name: StringId) ?Symbol { - const kinds = s.syms.items(.kind); - const names = s.syms.items(.name); - var i = s.syms.len; - while (i > 0) { - i -= 1; - switch (kinds[i]) { - .def, .decl, .enumeration, .constexpr => if (names[i] == name) return s.syms.get(i), - else => {}, - } - } - return null; + return s.lookup(name, .vars); } pub fn findTag( @@ -107,36 +111,62 @@ pub fn findTag( name_tok: TokenIndex, next_tok_id: Token.Id, ) !?Symbol { - const kinds = s.syms.items(.kind); - const names = s.syms.items(.name); // `tag Name;` should always result in a new type if in a new scope. - const end = if (next_tok_id == .semicolon) s.scopeEnd() else 0; - var i = s.syms.len; - while (i > end) { - i -= 1; - switch (kinds[i]) { - .@"enum" => if (names[i] == name) { - if (kind == .keyword_enum) return s.syms.get(i); - break; - }, - .@"struct" => if (names[i] == name) { - if (kind == .keyword_struct) return s.syms.get(i); - break; - }, - .@"union" => if (names[i] == name) { - if (kind == .keyword_union) return s.syms.get(i); - break; - }, - else => {}, - } - } else return null; - - if (i < s.scopeEnd()) return null; + const prev = (if (next_tok_id == .semicolon) s.get(name, .tags) else s.lookup(name, .tags)) orelse return null; + switch (prev.kind) { + .@"enum" => if (kind == .keyword_enum) return prev, + .@"struct" => if (kind == .keyword_struct) return prev, + .@"union" => if (kind == .keyword_union) return prev, + else => unreachable, + } + if (s.get(name, .tags) == null) return null; try p.errStr(.wrong_tag, name_tok, p.tokSlice(name_tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); + try p.errTok(.previous_definition, prev.tok); return null; } +const ScopeKind = enum { + /// structs, enums, unions + tags, + /// everything else + vars, +}; + +/// Return the Symbol for `name` (or null if not found) in the innermost scope +pub fn get(s: *SymbolStack, name: StringId, kind: ScopeKind) ?Symbol { + return switch (kind) { + .vars => s.scopes.items[s.active_len - 1].vars.get(name), + .tags => s.scopes.items[s.active_len - 1].tags.get(name), + }; +} + +/// Return the Symbol for `name` (or null if not found) in the nearest active scope, +/// starting at the innermost. +fn lookup(s: *SymbolStack, name: StringId, kind: ScopeKind) ?Symbol { + var i = s.active_len; + while (i > 0) { + i -= 1; + switch (kind) { + .vars => if (s.scopes.items[i].vars.get(name)) |sym| return sym, + .tags => if (s.scopes.items[i].tags.get(name)) |sym| return sym, + } + } + return null; +} + +/// Define a symbol in the innermost scope. Does not issue diagnostics or check correctness +/// with regard to the C standard. +pub fn define(s: *SymbolStack, allocator: Allocator, symbol: Symbol) !void { + switch (symbol.kind) { + .constexpr, .def, .decl, .enumeration, .typedef => { + try s.scopes.items[s.active_len - 1].vars.put(allocator, symbol.name, symbol); + }, + .@"struct", .@"union", .@"enum" => { + try s.scopes.items[s.active_len - 1].tags.put(allocator, symbol.name, symbol); + }, + } +} + pub fn defineTypedef( s: *SymbolStack, p: *Parser, @@ -145,25 +175,22 @@ pub fn defineTypedef( tok: TokenIndex, node: NodeIndex, ) !void { - const kinds = s.syms.items(.kind); - const names = s.syms.items(.name); - const end = s.scopeEnd(); - var i = s.syms.len; - while (i > end) { - i -= 1; - switch (kinds[i]) { - .typedef => if (names[i] == name) { - const prev_ty = s.syms.items(.ty)[i]; - if (ty.eql(prev_ty, p.comp, true)) break; - try p.errStr(.redefinition_of_typedef, tok, try p.typePairStrExtra(ty, " vs ", prev_ty)); - const previous_tok = s.syms.items(.tok)[i]; - if (previous_tok != 0) try p.errTok(.previous_definition, previous_tok); - break; + if (s.get(name, .vars)) |prev| { + switch (prev.kind) { + .typedef => { + if (!ty.eql(prev.ty, p.comp, true)) { + try p.errStr(.redefinition_of_typedef, tok, try p.typePairStrExtra(ty, " vs ", prev.ty)); + if (prev.tok != 0) try p.errTok(.previous_definition, prev.tok); + } }, - else => {}, + .enumeration, .decl, .def, .constexpr => { + try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok)); + try p.errTok(.previous_definition, prev.tok); + }, + else => unreachable, } } - try s.syms.append(p.gpa, .{ + try s.define(p.gpa, .{ .kind = .typedef, .name = name, .tok = tok, @@ -183,35 +210,31 @@ pub fn defineSymbol( val: Value, constexpr: bool, ) !void { - const kinds = s.syms.items(.kind); - const names = s.syms.items(.name); - const end = s.scopeEnd(); - var i = s.syms.len; - while (i > end) { - i -= 1; - switch (kinds[i]) { - .enumeration => if (names[i] == name) { + if (s.get(name, .vars)) |prev| { + switch (prev.kind) { + .enumeration => { try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); - break; + try p.errTok(.previous_definition, prev.tok); }, - .decl => if (names[i] == name) { - const prev_ty = s.syms.items(.ty)[i]; - if (!ty.eql(prev_ty, p.comp, true)) { + .decl => { + if (!ty.eql(prev.ty, p.comp, true)) { try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); + try p.errTok(.previous_definition, prev.tok); } - break; }, - .def, .constexpr => if (names[i] == name) { + .def, .constexpr => { try p.errStr(.redefinition, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); - break; + try p.errTok(.previous_definition, prev.tok); }, - else => {}, + .typedef => { + try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok)); + try p.errTok(.previous_definition, prev.tok); + }, + else => unreachable, } } - try s.syms.append(p.gpa, .{ + + try s.define(p.gpa, .{ .kind = if (constexpr) .constexpr else .def, .name = name, .tok = tok, @@ -221,6 +244,15 @@ pub fn defineSymbol( }); } +/// Get a pointer to the named symbol in the innermost scope. +/// Asserts that a symbol with the name exists. +pub fn getPtr(s: *SymbolStack, name: StringId, kind: ScopeKind) *Symbol { + return switch (kind) { + .tags => s.scopes.items[s.active_len - 1].tags.getPtr(name).?, + .vars => s.scopes.items[s.active_len - 1].vars.getPtr(name).?, + }; +} + pub fn declareSymbol( s: *SymbolStack, p: *Parser, @@ -229,39 +261,34 @@ pub fn declareSymbol( tok: TokenIndex, node: NodeIndex, ) !void { - const kinds = s.syms.items(.kind); - const names = s.syms.items(.name); - const end = s.scopeEnd(); - var i = s.syms.len; - while (i > end) { - i -= 1; - switch (kinds[i]) { - .enumeration => if (names[i] == name) { + if (s.get(name, .vars)) |prev| { + switch (prev.kind) { + .enumeration => { try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); - break; + try p.errTok(.previous_definition, prev.tok); }, - .decl => if (names[i] == name) { - const prev_ty = s.syms.items(.ty)[i]; - if (!ty.eql(prev_ty, p.comp, true)) { + .decl => { + if (!ty.eql(prev.ty, p.comp, true)) { try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); + try p.errTok(.previous_definition, prev.tok); } - break; }, - .def, .constexpr => if (names[i] == name) { - const prev_ty = s.syms.items(.ty)[i]; - if (!ty.eql(prev_ty, p.comp, true)) { + .def, .constexpr => { + if (!ty.eql(prev.ty, p.comp, true)) { try p.errStr(.redefinition_incompatible, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); - break; + try p.errTok(.previous_definition, prev.tok); + } else { + return; } - return; }, - else => {}, + .typedef => { + try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok)); + try p.errTok(.previous_definition, prev.tok); + }, + else => unreachable, } } - try s.syms.append(p.gpa, .{ + try s.define(p.gpa, .{ .kind = .decl, .name = name, .tok = tok, @@ -272,25 +299,23 @@ pub fn declareSymbol( } pub fn defineParam(s: *SymbolStack, p: *Parser, name: StringId, ty: Type, tok: TokenIndex) !void { - const kinds = s.syms.items(.kind); - const names = s.syms.items(.name); - const end = s.scopeEnd(); - var i = s.syms.len; - while (i > end) { - i -= 1; - switch (kinds[i]) { - .enumeration, .decl, .def, .constexpr => if (names[i] == name) { + if (s.get(name, .vars)) |prev| { + switch (prev.kind) { + .enumeration, .decl, .def, .constexpr => { try p.errStr(.redefinition_of_parameter, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); - break; + try p.errTok(.previous_definition, prev.tok); }, - else => {}, + .typedef => { + try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok)); + try p.errTok(.previous_definition, prev.tok); + }, + else => unreachable, } } if (ty.is(.fp16) and !p.comp.hasHalfPrecisionFloatABI()) { try p.errStr(.suggest_pointer_for_invalid_fp16, tok, "parameters"); } - try s.syms.append(p.gpa, .{ + try s.define(p.gpa, .{ .kind = .def, .name = name, .tok = tok, @@ -306,35 +331,28 @@ pub fn defineTag( kind: Token.Id, tok: TokenIndex, ) !?Symbol { - const kinds = s.syms.items(.kind); - const names = s.syms.items(.name); - const end = s.scopeEnd(); - var i = s.syms.len; - while (i > end) { - i -= 1; - switch (kinds[i]) { - .@"enum" => if (names[i] == name) { - if (kind == .keyword_enum) return s.syms.get(i); - try p.errStr(.wrong_tag, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); - return null; - }, - .@"struct" => if (names[i] == name) { - if (kind == .keyword_struct) return s.syms.get(i); - try p.errStr(.wrong_tag, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); - return null; - }, - .@"union" => if (names[i] == name) { - if (kind == .keyword_union) return s.syms.get(i); - try p.errStr(.wrong_tag, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); - return null; - }, - else => {}, - } + const prev = s.get(name, .tags) orelse return null; + switch (prev.kind) { + .@"enum" => { + if (kind == .keyword_enum) return prev; + try p.errStr(.wrong_tag, tok, p.tokSlice(tok)); + try p.errTok(.previous_definition, prev.tok); + return null; + }, + .@"struct" => { + if (kind == .keyword_struct) return prev; + try p.errStr(.wrong_tag, tok, p.tokSlice(tok)); + try p.errTok(.previous_definition, prev.tok); + return null; + }, + .@"union" => { + if (kind == .keyword_union) return prev; + try p.errStr(.wrong_tag, tok, p.tokSlice(tok)); + try p.errTok(.previous_definition, prev.tok); + return null; + }, + else => unreachable, } - return null; } pub fn defineEnumeration( @@ -345,27 +363,26 @@ pub fn defineEnumeration( tok: TokenIndex, val: Value, ) !void { - const kinds = s.syms.items(.kind); - const names = s.syms.items(.name); - const end = s.scopeEnd(); - var i = s.syms.len; - while (i > end) { - i -= 1; - switch (kinds[i]) { - .enumeration => if (names[i] == name) { + if (s.get(name, .vars)) |prev| { + switch (prev.kind) { + .enumeration => { try p.errStr(.redefinition, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); + try p.errTok(.previous_definition, prev.tok); return; }, - .decl, .def, .constexpr => if (names[i] == name) { + .decl, .def, .constexpr => { try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok)); - try p.errTok(.previous_definition, s.syms.items(.tok)[i]); + try p.errTok(.previous_definition, prev.tok); return; }, - else => {}, + .typedef => { + try p.errStr(.redefinition_different_sym, tok, p.tokSlice(tok)); + try p.errTok(.previous_definition, prev.tok); + }, + else => unreachable, } } - try s.syms.append(p.gpa, .{ + try s.define(p.gpa, .{ .kind = .enumeration, .name = name, .tok = tok, diff --git a/deps/aro/aro/Tokenizer.zig b/deps/aro/aro/Tokenizer.zig index ca281ff93636214e40228eff388e840d5bb0cff0..0f2b2ac4b7eb956b069789531c92d802d49bb048 100644 --- a/deps/aro/aro/Tokenizer.zig +++ b/deps/aro/aro/Tokenizer.zig @@ -749,12 +749,15 @@ pub const Token = struct { .string_literal_utf_8, .string_literal_utf_32, .string_literal_wide, + .unterminated_string_literal, => "a string literal", .char_literal, .char_literal_utf_8, .char_literal_utf_16, .char_literal_utf_32, .char_literal_wide, + .unterminated_char_literal, + .empty_char_literal, => "a character literal", .pp_num, .embed_byte => "A number", else => id.lexeme().?, @@ -798,7 +801,7 @@ pub const Token = struct { }; } - pub fn allowsDigraphs(id: Id, comp: *const Compilation) bool { + pub fn allowsDigraphs(id: Id, langopts: LangOpts) bool { return switch (id) { .l_bracket, .r_bracket, @@ -806,7 +809,7 @@ pub const Token = struct { .r_brace, .hash, .hash_hash, - => comp.langopts.hasDigraphs(), + => langopts.hasDigraphs(), else => false, }; } @@ -829,15 +832,15 @@ pub const Token = struct { /// double underscore and underscore + capital letter identifiers /// belong to the implementation namespace, so we always convert them /// to keywords. - pub fn getTokenId(comp: *const Compilation, str: []const u8) Token.Id { + pub fn getTokenId(langopts: LangOpts, str: []const u8) Token.Id { const kw = all_kws.get(str) orelse return .identifier; - const standard = comp.langopts.standard; + const standard = langopts.standard; return switch (kw) { .keyword_inline => if (standard.isGNU() or standard.atLeast(.c99)) kw else .identifier, .keyword_restrict => if (standard.atLeast(.c99)) kw else .identifier, .keyword_typeof => if (standard.isGNU() or standard.atLeast(.c23)) kw else .identifier, .keyword_asm => if (standard.isGNU()) kw else .identifier, - .keyword_declspec => if (comp.langopts.declspec_attrs) kw else .identifier, + .keyword_declspec => if (langopts.declspec_attrs) kw else .identifier, .keyword_c23_alignas, .keyword_c23_alignof, @@ -864,7 +867,7 @@ pub const Token = struct { .keyword_stdcall2, .keyword_thiscall2, .keyword_vectorcall2, - => if (comp.langopts.ms_extensions) kw else .identifier, + => if (langopts.ms_extensions) kw else .identifier, else => kw, }; } @@ -1023,7 +1026,7 @@ const Tokenizer = @This(); buf: []const u8, index: u32 = 0, source: Source.Id, -comp: *const Compilation, +langopts: LangOpts, line: u32 = 1, pub fn next(self: *Tokenizer) Token { @@ -1162,14 +1165,14 @@ pub fn next(self: *Tokenizer) Token { '#' => state = .hash, '0'...'9' => state = .pp_num, '\t', '\x0B', '\x0C', ' ' => state = .whitespace, - '$' => if (self.comp.langopts.dollars_in_identifiers) { + '$' => if (self.langopts.dollars_in_identifiers) { state = .extended_identifier; } else { id = .invalid; self.index += 1; break; }, - 0x1A => if (self.comp.langopts.ms_extensions) { + 0x1A => if (self.langopts.ms_extensions) { id = .eof; break; } else { @@ -1306,15 +1309,15 @@ pub fn next(self: *Tokenizer) Token { }, .identifier, .extended_identifier => switch (c) { 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, - '$' => if (self.comp.langopts.dollars_in_identifiers) { + '$' => if (self.langopts.dollars_in_identifiers) { state = .extended_identifier; } else { - id = if (state == .identifier) Token.getTokenId(self.comp, self.buf[start..self.index]) else .extended_identifier; + id = if (state == .identifier) Token.getTokenId(self.langopts, self.buf[start..self.index]) else .extended_identifier; break; }, 0x80...0xFF => state = .extended_identifier, else => { - id = if (state == .identifier) Token.getTokenId(self.comp, self.buf[start..self.index]) else .extended_identifier; + id = if (state == .identifier) Token.getTokenId(self.langopts, self.buf[start..self.index]) else .extended_identifier; break; }, }, @@ -1358,7 +1361,7 @@ pub fn next(self: *Tokenizer) Token { }, .colon => switch (c) { '>' => { - if (self.comp.langopts.hasDigraphs()) { + if (self.langopts.hasDigraphs()) { id = .r_bracket; self.index += 1; } else { @@ -1367,7 +1370,7 @@ pub fn next(self: *Tokenizer) Token { break; }, ':' => { - if (self.comp.langopts.standard.atLeast(.c23)) { + if (self.langopts.standard.atLeast(.c23)) { id = .colon_colon; self.index += 1; break; @@ -1388,7 +1391,7 @@ pub fn next(self: *Tokenizer) Token { break; }, '>' => { - if (self.comp.langopts.hasDigraphs()) { + if (self.langopts.hasDigraphs()) { id = .r_brace; self.index += 1; } else { @@ -1397,7 +1400,7 @@ pub fn next(self: *Tokenizer) Token { break; }, ':' => { - if (self.comp.langopts.hasDigraphs()) { + if (self.langopts.hasDigraphs()) { state = .hash_digraph; } else { id = .percent; @@ -1444,7 +1447,7 @@ pub fn next(self: *Tokenizer) Token { break; }, ':' => { - if (self.comp.langopts.hasDigraphs()) { + if (self.langopts.hasDigraphs()) { id = .l_bracket; self.index += 1; } else { @@ -1453,7 +1456,7 @@ pub fn next(self: *Tokenizer) Token { break; }, '%' => { - if (self.comp.langopts.hasDigraphs()) { + if (self.langopts.hasDigraphs()) { id = .l_brace; self.index += 1; } else { @@ -1613,7 +1616,7 @@ pub fn next(self: *Tokenizer) Token { }, .line_comment => switch (c) { '\n' => { - if (self.comp.langopts.preserve_comments) { + if (self.langopts.preserve_comments) { id = .comment; break; } @@ -1629,7 +1632,7 @@ pub fn next(self: *Tokenizer) Token { }, .multi_line_comment_asterisk => switch (c) { '/' => { - if (self.comp.langopts.preserve_comments) { + if (self.langopts.preserve_comments) { self.index += 1; id = .comment; break; @@ -1673,7 +1676,7 @@ pub fn next(self: *Tokenizer) Token { '.', => {}, 'e', 'E', 'p', 'P' => state = .pp_num_exponent, - '\'' => if (self.comp.langopts.standard.atLeast(.c23)) { + '\'' => if (self.langopts.standard.atLeast(.c23)) { state = .pp_num_digit_separator; } else { id = .pp_num; @@ -1721,7 +1724,7 @@ pub fn next(self: *Tokenizer) Token { } else if (self.index == self.buf.len) { switch (state) { .start, .line_comment => {}, - .u, .u8, .U, .L, .identifier => id = Token.getTokenId(self.comp, self.buf[start..self.index]), + .u, .u8, .U, .L, .identifier => id = Token.getTokenId(self.langopts, self.buf[start..self.index]), .extended_identifier => id = .extended_identifier, .period2 => { @@ -2149,7 +2152,7 @@ fn expectTokensExtra(contents: []const u8, expected_tokens: []const Token.Id, st var tokenizer = Tokenizer{ .buf = source.buf, .source = source.id, - .comp = &comp, + .langopts = comp.langopts, }; var i: usize = 0; while (i < expected_tokens.len) { diff --git a/deps/aro/aro/Toolchain.zig b/deps/aro/aro/Toolchain.zig index fb4472e5ae4fce3f6ed5b532105de34762af010c..913432f997f960e9fa8a91972a58ad0a2b3da107 100644 --- a/deps/aro/aro/Toolchain.zig +++ b/deps/aro/aro/Toolchain.zig @@ -183,18 +183,15 @@ pub fn getLinkerPath(tc: *const Toolchain, buf: []u8) ![]const u8 { return tc.getProgramPath(default_linker, buf); } -const TargetSpecificToolName = std.BoundedArray(u8, 64); - /// If an explicit target is provided, also check the prefixed tool-specific name /// TODO: this isn't exactly right since our target names don't necessarily match up /// with GCC's. /// For example the Zig target `arm-freestanding-eabi` would need the `arm-none-eabi` tools -fn possibleProgramNames(raw_triple: ?[]const u8, name: []const u8, target_specific: *TargetSpecificToolName) std.BoundedArray([]const u8, 2) { +fn possibleProgramNames(raw_triple: ?[]const u8, name: []const u8, buf: *[64]u8) std.BoundedArray([]const u8, 2) { var possible_names: std.BoundedArray([]const u8, 2) = .{}; if (raw_triple) |triple| { - const w = target_specific.writer(); - if (w.print("{s}-{s}", .{ triple, name })) { - possible_names.appendAssumeCapacity(target_specific.constSlice()); + if (std.fmt.bufPrint(buf, "{s}-{s}", .{ triple, name })) |res| { + possible_names.appendAssumeCapacity(res); } else |_| {} } possible_names.appendAssumeCapacity(name); @@ -227,8 +224,8 @@ fn getProgramPath(tc: *const Toolchain, name: []const u8, buf: []u8) []const u8 var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; var fib = std.heap.FixedBufferAllocator.init(&path_buf); - var tool_specific_name: TargetSpecificToolName = .{}; - const possible_names = possibleProgramNames(tc.driver.raw_target_triple, name, &tool_specific_name); + var tool_specific_buf: [64]u8 = undefined; + const possible_names = possibleProgramNames(tc.driver.raw_target_triple, name, &tool_specific_buf); for (possible_names.constSlice()) |tool_name| { for (tc.program_paths.items) |program_path| { diff --git a/deps/aro/aro/Tree.zig b/deps/aro/aro/Tree.zig index 86426de85f738eb524fcb47ca142068cd526b66d..20c639fb893c2a4544fad2b3c3b28973f6afd305 100644 --- a/deps/aro/aro/Tree.zig +++ b/deps/aro/aro/Tree.zig @@ -1,11 +1,12 @@ const std = @import("std"); const Interner = @import("backend").Interner; -const Type = @import("Type.zig"); -const Tokenizer = @import("Tokenizer.zig"); +const Attribute = @import("Attribute.zig"); const CodeGen = @import("CodeGen.zig"); const Compilation = @import("Compilation.zig"); +const number_affixes = @import("Tree/number_affixes.zig"); const Source = @import("Source.zig"); -const Attribute = @import("Attribute.zig"); +const Tokenizer = @import("Tokenizer.zig"); +const Type = @import("Type.zig"); const Value = @import("Value.zig"); const StringInterner = @import("StringInterner.zig"); @@ -92,6 +93,8 @@ pub const Token = struct { pub const List = std.MultiArrayList(Token); pub const Id = Tokenizer.Token.Id; + pub const NumberPrefix = number_affixes.Prefix; + pub const NumberSuffix = number_affixes.Suffix; }; pub const TokenIndex = u32; @@ -669,7 +672,7 @@ pub fn tokSlice(tree: *const Tree, tok_i: TokenIndex) []const u8 { const loc = tree.tokens.items(.loc)[tok_i]; var tmp_tokenizer = Tokenizer{ .buf = tree.comp.getSource(loc.id).buf, - .comp = tree.comp, + .langopts = tree.comp.langopts, .index = loc.byte_offset, .source = .generated, }; diff --git a/deps/aro/aro/number_affixes.zig b/deps/aro/aro/Tree/number_affixes.zig similarity index 87% rename from deps/aro/aro/number_affixes.zig rename to deps/aro/aro/Tree/number_affixes.zig index e987934bd214c6e8ba0a3ecfac7e4fde9e92b3ff..7f01e9f2e7ef3b04c0c7dbfdb34322a56acfb3a3 100644 --- a/deps/aro/aro/number_affixes.zig +++ b/deps/aro/aro/Tree/number_affixes.zig @@ -77,6 +77,18 @@ pub const Suffix = enum { // _Float16 F16, + // __float80 + W, + + // Imaginary __float80 + IW, + + // _Float128 + Q, F128, + + // Imaginary _Float128 + IQ, IF128, + // Imaginary _Bitint IWB, IUWB, @@ -111,10 +123,16 @@ pub const Suffix = enum { .{ .F16, &.{"F16"} }, .{ .F, &.{"F"} }, .{ .L, &.{"L"} }, + .{ .W, &.{"W"} }, + .{ .F128, &.{"F128"} }, + .{ .Q, &.{"Q"} }, .{ .I, &.{"I"} }, .{ .IL, &.{ "I", "L" } }, .{ .IF, &.{ "I", "F" } }, + .{ .IW, &.{ "I", "W" } }, + .{ .IF128, &.{ "I", "F128" } }, + .{ .IQ, &.{ "I", "Q" } }, }; pub fn fromString(buf: []const u8, suffix_kind: enum { int, float }) ?Suffix { @@ -124,7 +142,7 @@ pub const Suffix = enum { .float => FloatSuffixes, .int => IntSuffixes, }; - var scratch: [3]u8 = undefined; + var scratch: [4]u8 = undefined; top: for (suffixes) |candidate| { const tag = candidate[0]; const parts = candidate[1]; @@ -143,8 +161,8 @@ pub const Suffix = enum { pub fn isImaginary(suffix: Suffix) bool { return switch (suffix) { - .I, .IL, .IF, .IU, .IUL, .ILL, .IULL, .IWB, .IUWB => true, - .None, .L, .F16, .F, .U, .UL, .LL, .ULL, .WB, .UWB => false, + .I, .IL, .IF, .IU, .IUL, .ILL, .IULL, .IWB, .IUWB, .IF128, .IQ, .IW => true, + .None, .L, .F16, .F, .U, .UL, .LL, .ULL, .WB, .UWB, .F128, .Q, .W => false, }; } @@ -152,7 +170,7 @@ pub const Suffix = enum { return switch (suffix) { .None, .L, .LL, .I, .IL, .ILL, .WB, .IWB => true, .U, .UL, .ULL, .IU, .IUL, .IULL, .UWB, .IUWB => false, - .F, .IF, .F16 => unreachable, + .F, .IF, .F16, .F128, .IF128, .Q, .IQ, .W, .IW => unreachable, }; } diff --git a/deps/aro/aro/Type.zig b/deps/aro/aro/Type.zig index ef6e99cdd41fd7e633782001cdb4271744848e64..1369d7bbe5f7cad741366bbad4b66767bc8f21b8 100644 --- a/deps/aro/aro/Type.zig +++ b/deps/aro/aro/Type.zig @@ -363,7 +363,6 @@ pub const Specifier = enum { // data.sub_type pointer, unspecified_variable_len_array, - decayed_unspecified_variable_len_array, // data.func /// int foo(int bar, char baz) and int (void) func, @@ -375,15 +374,11 @@ pub const Specifier = enum { // data.array array, - decayed_array, static_array, - decayed_static_array, incomplete_array, - decayed_incomplete_array, vector, // data.expr variable_len_array, - decayed_variable_len_array, // data.record @"struct", @@ -394,13 +389,9 @@ pub const Specifier = enum { /// typeof(type-name) typeof_type, - /// decayed array created with typeof(type-name) - decayed_typeof_type, /// typeof(expression) typeof_expr, - /// decayed array created with typeof(expression) - decayed_typeof_expr, /// data.attributed attributed, @@ -428,6 +419,7 @@ data: union { } = .{ .none = {} }, specifier: Specifier, qual: Qualifiers = .{}, +decayed: bool = false, pub const int = Type{ .specifier = .int }; pub const invalid = Type{ .specifier = .invalid }; @@ -442,7 +434,7 @@ pub fn is(ty: Type, specifier: Specifier) bool { pub fn withAttributes(self: Type, allocator: std.mem.Allocator, attributes: []const Attribute) !Type { if (attributes.len == 0) return self; const attributed_type = try Type.Attributed.create(allocator, self, self.getAttributes(), attributes); - return Type{ .specifier = .attributed, .data = .{ .attributed = attributed_type } }; + return Type{ .specifier = .attributed, .data = .{ .attributed = attributed_type }, .decayed = self.decayed }; } pub fn isCallable(ty: Type) ?Type { @@ -468,10 +460,10 @@ pub fn isFunc(ty: Type) bool { pub fn isArray(ty: Type) bool { return switch (ty.specifier) { - .array, .static_array, .incomplete_array, .variable_len_array, .unspecified_variable_len_array => true, - .typeof_type => ty.data.sub_type.isArray(), - .typeof_expr => ty.data.expr.ty.isArray(), - .attributed => ty.data.attributed.base.isArray(), + .array, .static_array, .incomplete_array, .variable_len_array, .unspecified_variable_len_array => !ty.isDecayed(), + .typeof_type => !ty.isDecayed() and ty.data.sub_type.isArray(), + .typeof_expr => !ty.isDecayed() and ty.data.expr.ty.isArray(), + .attributed => !ty.isDecayed() and ty.data.attributed.base.isArray(), else => false, }; } @@ -502,35 +494,22 @@ pub fn isScalarNonInt(ty: Type) bool { } pub fn isDecayed(ty: Type) bool { - const decayed = switch (ty.specifier) { - .decayed_array, - .decayed_static_array, - .decayed_incomplete_array, - .decayed_variable_len_array, - .decayed_unspecified_variable_len_array, - .decayed_typeof_type, - .decayed_typeof_expr, - => true, - else => false, - }; - std.debug.assert(decayed or !std.mem.startsWith(u8, @tagName(ty.specifier), "decayed")); - return decayed; + return ty.decayed; } pub fn isPtr(ty: Type) bool { return switch (ty.specifier) { - .pointer, - .decayed_array, - .decayed_static_array, - .decayed_incomplete_array, - .decayed_variable_len_array, - .decayed_unspecified_variable_len_array, - .decayed_typeof_type, - .decayed_typeof_expr, - => true, - .typeof_type => ty.data.sub_type.isPtr(), - .typeof_expr => ty.data.expr.ty.isPtr(), - .attributed => ty.data.attributed.base.isPtr(), + .pointer => true, + + .array, + .static_array, + .incomplete_array, + .variable_len_array, + .unspecified_variable_len_array, + => ty.isDecayed(), + .typeof_type => ty.isDecayed() or ty.data.sub_type.isPtr(), + .typeof_expr => ty.isDecayed() or ty.data.expr.ty.isPtr(), + .attributed => ty.isDecayed() or ty.data.attributed.base.isPtr(), else => false, }; } @@ -608,15 +587,15 @@ pub fn isVoidStar(ty: Type) bool { pub fn isTypeof(ty: Type) bool { return switch (ty.specifier) { - .typeof_type, .typeof_expr, .decayed_typeof_type, .decayed_typeof_expr => true, + .typeof_type, .typeof_expr => true, else => false, }; } pub fn isConst(ty: Type) bool { return switch (ty.specifier) { - .typeof_type, .decayed_typeof_type => ty.qual.@"const" or ty.data.sub_type.isConst(), - .typeof_expr, .decayed_typeof_expr => ty.qual.@"const" or ty.data.expr.ty.isConst(), + .typeof_type => ty.qual.@"const" or ty.data.sub_type.isConst(), + .typeof_expr => ty.qual.@"const" or ty.data.expr.ty.isConst(), .attributed => ty.data.attributed.base.isConst(), else => ty.qual.@"const", }; @@ -630,7 +609,7 @@ pub fn signedness(ty: Type, comp: *const Compilation) std.builtin.Signedness { return switch (ty.specifier) { // zig fmt: off .char, .complex_char => return comp.getCharSignedness(), - .uchar, .ushort, .uint, .ulong, .ulong_long, .bool, .complex_uchar, .complex_ushort, + .uchar, .ushort, .uint, .ulong, .ulong_long, .uint128, .bool, .complex_uchar, .complex_ushort, .complex_uint, .complex_ulong, .complex_ulong_long, .complex_uint128 => .unsigned, // zig fmt: on .bit_int, .complex_bit_int => ty.data.int.signedness, @@ -678,16 +657,16 @@ pub fn isAnonymousRecord(ty: Type, comp: *const Compilation) bool { pub fn elemType(ty: Type) Type { return switch (ty.specifier) { - .pointer, .unspecified_variable_len_array, .decayed_unspecified_variable_len_array => ty.data.sub_type.*, - .array, .static_array, .incomplete_array, .decayed_array, .decayed_static_array, .decayed_incomplete_array, .vector => ty.data.array.elem, - .variable_len_array, .decayed_variable_len_array => ty.data.expr.ty, - .typeof_type, .decayed_typeof_type, .typeof_expr, .decayed_typeof_expr => { + .pointer, .unspecified_variable_len_array => ty.data.sub_type.*, + .array, .static_array, .incomplete_array, .vector => ty.data.array.elem, + .variable_len_array => ty.data.expr.ty, + .typeof_type, .typeof_expr => { const unwrapped = ty.canonicalize(.preserve_quals); var elem = unwrapped.elemType(); elem.qual = elem.qual.mergeAll(unwrapped.qual); return elem; }, - .attributed => ty.data.attributed.base, + .attributed => ty.data.attributed.base.elemType(), .invalid => Type.invalid, // zig fmt: off .complex_float, .complex_double, .complex_long_double, .complex_float80, @@ -703,8 +682,8 @@ pub fn elemType(ty: Type) Type { pub fn returnType(ty: Type) Type { return switch (ty.specifier) { .func, .var_args_func, .old_style_func => ty.data.func.return_type, - .typeof_type, .decayed_typeof_type => ty.data.sub_type.returnType(), - .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.returnType(), + .typeof_type => ty.data.sub_type.returnType(), + .typeof_expr => ty.data.expr.ty.returnType(), .attributed => ty.data.attributed.base.returnType(), .invalid => Type.invalid, else => unreachable, @@ -714,8 +693,8 @@ pub fn returnType(ty: Type) Type { pub fn params(ty: Type) []Func.Param { return switch (ty.specifier) { .func, .var_args_func, .old_style_func => ty.data.func.params, - .typeof_type, .decayed_typeof_type => ty.data.sub_type.params(), - .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.params(), + .typeof_type => ty.data.sub_type.params(), + .typeof_expr => ty.data.expr.ty.params(), .attributed => ty.data.attributed.base.params(), .invalid => &.{}, else => unreachable, @@ -724,9 +703,9 @@ pub fn params(ty: Type) []Func.Param { pub fn arrayLen(ty: Type) ?u64 { return switch (ty.specifier) { - .array, .static_array, .decayed_array, .decayed_static_array => ty.data.array.len, - .typeof_type, .decayed_typeof_type => ty.data.sub_type.arrayLen(), - .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.arrayLen(), + .array, .static_array => ty.data.array.len, + .typeof_type => ty.data.sub_type.arrayLen(), + .typeof_expr => ty.data.expr.ty.arrayLen(), .attributed => ty.data.attributed.base.arrayLen(), else => null, }; @@ -748,8 +727,8 @@ pub fn anyQual(ty: Type) bool { pub fn getAttributes(ty: Type) []const Attribute { return switch (ty.specifier) { .attributed => ty.data.attributed.attributes, - .typeof_type, .decayed_typeof_type => ty.data.sub_type.getAttributes(), - .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.getAttributes(), + .typeof_type => ty.data.sub_type.getAttributes(), + .typeof_expr => ty.data.expr.ty.getAttributes(), else => &.{}, }; } @@ -757,8 +736,8 @@ pub fn getAttributes(ty: Type) []const Attribute { pub fn getRecord(ty: Type) ?*const Type.Record { return switch (ty.specifier) { .attributed => ty.data.attributed.base.getRecord(), - .typeof_type, .decayed_typeof_type => ty.data.sub_type.getRecord(), - .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.getRecord(), + .typeof_type => ty.data.sub_type.getRecord(), + .typeof_expr => ty.data.expr.ty.getRecord(), .@"struct", .@"union" => ty.data.record, else => null, }; @@ -901,6 +880,7 @@ pub fn bitfieldPromotion(ty: Type, comp: *Compilation, width: u32) ?Type { } pub fn hasIncompleteSize(ty: Type) bool { + if (ty.isDecayed()) return false; return switch (ty.specifier) { .void, .incomplete_array => true, .@"enum" => ty.data.@"enum".isIncomplete() and !ty.data.@"enum".fixed, @@ -917,20 +897,14 @@ pub fn hasUnboundVLA(ty: Type) bool { var cur = ty; while (true) { switch (cur.specifier) { - .unspecified_variable_len_array, - .decayed_unspecified_variable_len_array, - => return true, + .unspecified_variable_len_array => return true, .array, .static_array, .incomplete_array, .variable_len_array, - .decayed_array, - .decayed_static_array, - .decayed_incomplete_array, - .decayed_variable_len_array, => cur = cur.elemType(), - .typeof_type, .decayed_typeof_type => cur = cur.data.sub_type.*, - .typeof_expr, .decayed_typeof_expr => cur = cur.data.expr.ty, + .typeof_type => cur = cur.data.sub_type.*, + .typeof_expr => cur = cur.data.expr.ty, .attributed => cur = cur.data.attributed.base, else => return false, } @@ -1006,9 +980,11 @@ pub fn sizeCompare(a: Type, b: Type, comp: *Compilation) TypeSizeOrder { /// Size of type as reported by sizeof pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 { + if (ty.isPtr()) return comp.target.ptrBitWidth() / 8; + return switch (ty.specifier) { .auto_type, .c23_auto => unreachable, - .variable_len_array, .unspecified_variable_len_array => return null, + .variable_len_array, .unspecified_variable_len_array => null, .incomplete_array => return if (comp.langopts.emulate == .msvc) @as(?u64, 0) else null, .func, .var_args_func, .old_style_func, .void, .bool => 1, .char, .schar, .uchar => 1, @@ -1037,14 +1013,7 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 { .complex_long_double, .complex_float80, .complex_float128, .complex_bit_int, => return 2 * ty.makeReal().sizeof(comp).?, // zig fmt: on - .pointer, - .decayed_array, - .decayed_static_array, - .decayed_incomplete_array, - .decayed_variable_len_array, - .decayed_unspecified_variable_len_array, - .decayed_typeof_type, - .decayed_typeof_expr, + .pointer => unreachable, .static_array, .nullptr_t, => comp.target.ptrBitWidth() / 8, @@ -1073,8 +1042,8 @@ pub fn sizeof(ty: Type, comp: *const Compilation) ?u64 { pub fn bitSizeof(ty: Type, comp: *const Compilation) ?u64 { return switch (ty.specifier) { .bool => if (comp.langopts.emulate == .msvc) @as(u64, 8) else 1, - .typeof_type, .decayed_typeof_type => ty.data.sub_type.bitSizeof(comp), - .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.bitSizeof(comp), + .typeof_type => ty.data.sub_type.bitSizeof(comp), + .typeof_expr => ty.data.expr.ty.bitSizeof(comp), .attributed => ty.data.attributed.base.bitSizeof(comp), .bit_int => return ty.data.int.bits, .long_double => comp.target.c_type_bit_size(.longdouble), @@ -1117,7 +1086,10 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 { .unspecified_variable_len_array, .array, .vector, - => ty.elemType().alignof(comp), + => if (ty.isPtr()) switch (comp.target.cpu.arch) { + .avr => 1, + else => comp.target.ptrBitWidth() / 8, + } else ty.elemType().alignof(comp), .func, .var_args_func, .old_style_func => target_util.defaultFunctionAlignment(comp.target), .char, .schar, .uchar, .void, .bool => 1, @@ -1153,11 +1125,6 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 { .float80, .float128 => 16, .pointer, - .decayed_array, - .decayed_static_array, - .decayed_incomplete_array, - .decayed_variable_len_array, - .decayed_unspecified_variable_len_array, .static_array, .nullptr_t, => switch (comp.target.cpu.arch) { @@ -1166,8 +1133,8 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 { }, .@"struct", .@"union" => if (ty.data.record.isIncomplete()) 0 else @intCast(ty.data.record.type_layout.field_alignment_bits / 8), .@"enum" => if (ty.data.@"enum".isIncomplete() and !ty.data.@"enum".fixed) 0 else ty.data.@"enum".tag_ty.alignof(comp), - .typeof_type, .decayed_typeof_type => ty.data.sub_type.alignof(comp), - .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.alignof(comp), + .typeof_type => ty.data.sub_type.alignof(comp), + .typeof_expr => ty.data.expr.ty.alignof(comp), .attributed => ty.data.attributed.base.alignof(comp), }; } @@ -1179,7 +1146,10 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 { /// arrays and pointers. pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals }) Type { var cur = ty; - if (cur.specifier == .attributed) cur = cur.data.attributed.base; + if (cur.specifier == .attributed) { + cur = cur.data.attributed.base; + cur.decayed = ty.decayed; + } if (!cur.isTypeof()) return cur; var qual = cur.qual; @@ -1187,14 +1157,6 @@ pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals }) switch (cur.specifier) { .typeof_type => cur = cur.data.sub_type.*, .typeof_expr => cur = cur.data.expr.ty, - .decayed_typeof_type => { - cur = cur.data.sub_type.*; - cur.decayArray(); - }, - .decayed_typeof_expr => { - cur = cur.data.expr.ty; - cur.decayArray(); - }, else => break, } qual = qual.mergeAll(cur.qual); @@ -1204,6 +1166,7 @@ pub fn canonicalize(ty: Type, qual_handling: enum { standard, preserve_quals }) } else { cur.qual = qual; } + cur.decayed = ty.decayed; return cur; } @@ -1219,8 +1182,8 @@ pub fn get(ty: *const Type, specifier: Specifier) ?*const Type { pub fn requestedAlignment(ty: Type, comp: *const Compilation) ?u29 { return switch (ty.specifier) { - .typeof_type, .decayed_typeof_type => ty.data.sub_type.requestedAlignment(comp), - .typeof_expr, .decayed_typeof_expr => ty.data.expr.ty.requestedAlignment(comp), + .typeof_type => ty.data.sub_type.requestedAlignment(comp), + .typeof_expr => ty.data.expr.ty.requestedAlignment(comp), .attributed => annotationAlignment(comp, ty.data.attributed.attributes), else => null, }; @@ -1265,14 +1228,11 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi if (a.qual.@"volatile" != b.qual.@"volatile") return false; } + if (a.isPtr()) { + return a_param.elemType().eql(b_param.elemType(), comp, check_qualifiers); + } switch (a.specifier) { - .pointer, - .decayed_array, - .decayed_static_array, - .decayed_incomplete_array, - .decayed_variable_len_array, - .decayed_unspecified_variable_len_array, - => if (!a_param.elemType().eql(b_param.elemType(), comp, check_qualifiers)) return false, + .pointer => unreachable, .func, .var_args_func, @@ -1293,8 +1253,9 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi } if (!a.elemType().eql(b.elemType(), comp, false)) return false; }, - .variable_len_array => if (!a.elemType().eql(b.elemType(), comp, check_qualifiers)) return false, - + .variable_len_array => { + if (!a.elemType().eql(b.elemType(), comp, check_qualifiers)) return false; + }, .@"struct", .@"union" => if (a.data.record != b.data.record) return false, .@"enum" => if (a.data.@"enum" != b.data.@"enum") return false, .bit_int, .complex_bit_int => return a.data.int.bits == b.data.int.bits and a.data.int.signedness == b.data.int.signedness, @@ -1306,14 +1267,14 @@ pub fn eql(a_param: Type, b_param: Type, comp: *const Compilation, check_qualifi /// Decays an array to a pointer pub fn decayArray(ty: *Type) void { - // the decayed array type is the current specifier +1 - ty.specifier = @enumFromInt(@intFromEnum(ty.specifier) + 1); + std.debug.assert(ty.isArray()); + ty.decayed = true; } pub fn originalTypeOfDecayedArray(ty: Type) Type { std.debug.assert(ty.isDecayed()); var copy = ty; - copy.specifier = @enumFromInt(@intFromEnum(ty.specifier) - 1); + copy.decayed = false; return copy; } @@ -1405,25 +1366,23 @@ pub fn combine(inner: *Type, outer: Type) Parser.Error!void { switch (inner.specifier) { .pointer => return inner.data.sub_type.combine(outer), .unspecified_variable_len_array => { + std.debug.assert(!inner.isDecayed()); try inner.data.sub_type.combine(outer); }, .variable_len_array => { + std.debug.assert(!inner.isDecayed()); try inner.data.expr.ty.combine(outer); }, .array, .static_array, .incomplete_array => { + std.debug.assert(!inner.isDecayed()); try inner.data.array.elem.combine(outer); }, .func, .var_args_func, .old_style_func => { try inner.data.func.return_type.combine(outer); }, - .decayed_array, - .decayed_static_array, - .decayed_incomplete_array, - .decayed_variable_len_array, - .decayed_unspecified_variable_len_array, - .decayed_typeof_type, - .decayed_typeof_expr, - => unreachable, // type should not be able to decay before being combined + .typeof_type, + .typeof_expr, + => std.debug.assert(!inner.isDecayed()), .void, .invalid => inner.* = outer, else => unreachable, } @@ -1474,8 +1433,8 @@ pub fn validateCombinedType(ty: Type, p: *Parser, source_tok: TokenIndex) Parser try p.errStr(.suggest_pointer_for_invalid_fp16, source_tok, "function return value"); } }, - .typeof_type, .decayed_typeof_type => return ty.data.sub_type.validateCombinedType(p, source_tok), - .typeof_expr, .decayed_typeof_expr => return ty.data.expr.ty.validateCombinedType(p, source_tok), + .typeof_type => return ty.data.sub_type.validateCombinedType(p, source_tok), + .typeof_expr => return ty.data.expr.ty.validateCombinedType(p, source_tok), .attributed => return ty.data.attributed.base.validateCombinedType(p, source_tok), else => {}, } @@ -1610,6 +1569,7 @@ pub const Builder = struct { decayed_typeof_expr: *Expr, attributed: *Attributed, + decayed_attributed: *Attributed, pub fn str(spec: Builder.Specifier, langopts: LangOpts) ?[]const u8 { return switch (spec) { @@ -1835,13 +1795,10 @@ pub const Builder = struct { ty.specifier = .pointer; ty.data = .{ .sub_type = data }; }, - .unspecified_variable_len_array => |data| { + .unspecified_variable_len_array, .decayed_unspecified_variable_len_array => |data| { ty.specifier = .unspecified_variable_len_array; ty.data = .{ .sub_type = data }; - }, - .decayed_unspecified_variable_len_array => |data| { - ty.specifier = .decayed_unspecified_variable_len_array; - ty.data = .{ .sub_type = data }; + ty.decayed = b.specifier == .decayed_unspecified_variable_len_array; }, .func => |data| { ty.specifier = .func; @@ -1855,41 +1812,29 @@ pub const Builder = struct { ty.specifier = .old_style_func; ty.data = .{ .func = data }; }, - .array => |data| { + .array, .decayed_array => |data| { ty.specifier = .array; ty.data = .{ .array = data }; + ty.decayed = b.specifier == .decayed_array; }, - .decayed_array => |data| { - ty.specifier = .decayed_array; - ty.data = .{ .array = data }; - }, - .static_array => |data| { + .static_array, .decayed_static_array => |data| { ty.specifier = .static_array; ty.data = .{ .array = data }; + ty.decayed = b.specifier == .decayed_static_array; }, - .decayed_static_array => |data| { - ty.specifier = .decayed_static_array; - ty.data = .{ .array = data }; - }, - .incomplete_array => |data| { + .incomplete_array, .decayed_incomplete_array => |data| { ty.specifier = .incomplete_array; ty.data = .{ .array = data }; - }, - .decayed_incomplete_array => |data| { - ty.specifier = .decayed_incomplete_array; - ty.data = .{ .array = data }; + ty.decayed = b.specifier == .decayed_incomplete_array; }, .vector => |data| { ty.specifier = .vector; ty.data = .{ .array = data }; }, - .variable_len_array => |data| { + .variable_len_array, .decayed_variable_len_array => |data| { ty.specifier = .variable_len_array; ty.data = .{ .expr = data }; - }, - .decayed_variable_len_array => |data| { - ty.specifier = .decayed_variable_len_array; - ty.data = .{ .expr = data }; + ty.decayed = b.specifier == .decayed_variable_len_array; }, .@"struct" => |data| { ty.specifier = .@"struct"; @@ -1903,25 +1848,20 @@ pub const Builder = struct { ty.specifier = .@"enum"; ty.data = .{ .@"enum" = data }; }, - .typeof_type => |data| { + .typeof_type, .decayed_typeof_type => |data| { ty.specifier = .typeof_type; ty.data = .{ .sub_type = data }; + ty.decayed = b.specifier == .decayed_typeof_type; }, - .decayed_typeof_type => |data| { - ty.specifier = .decayed_typeof_type; - ty.data = .{ .sub_type = data }; - }, - .typeof_expr => |data| { + .typeof_expr, .decayed_typeof_expr => |data| { ty.specifier = .typeof_expr; ty.data = .{ .expr = data }; + ty.decayed = b.specifier == .decayed_typeof_expr; }, - .decayed_typeof_expr => |data| { - ty.specifier = .decayed_typeof_expr; - ty.data = .{ .expr = data }; - }, - .attributed => |data| { + .attributed, .decayed_attributed => |data| { ty.specifier = .attributed; ty.data = .{ .attributed = data }; + ty.decayed = b.specifier == .decayed_attributed; }, } if (!ty.isReal() and ty.isInt()) { @@ -2359,30 +2299,47 @@ pub const Builder = struct { .complex_float128 => .complex_float128, .pointer => .{ .pointer = ty.data.sub_type }, - .unspecified_variable_len_array => .{ .unspecified_variable_len_array = ty.data.sub_type }, - .decayed_unspecified_variable_len_array => .{ .decayed_unspecified_variable_len_array = ty.data.sub_type }, + .unspecified_variable_len_array => if (ty.isDecayed()) + .{ .decayed_unspecified_variable_len_array = ty.data.sub_type } + else + .{ .unspecified_variable_len_array = ty.data.sub_type }, .func => .{ .func = ty.data.func }, .var_args_func => .{ .var_args_func = ty.data.func }, .old_style_func => .{ .old_style_func = ty.data.func }, - .array => .{ .array = ty.data.array }, - .decayed_array => .{ .decayed_array = ty.data.array }, - .static_array => .{ .static_array = ty.data.array }, - .decayed_static_array => .{ .decayed_static_array = ty.data.array }, - .incomplete_array => .{ .incomplete_array = ty.data.array }, - .decayed_incomplete_array => .{ .decayed_incomplete_array = ty.data.array }, + .array => if (ty.isDecayed()) + .{ .decayed_array = ty.data.array } + else + .{ .array = ty.data.array }, + .static_array => if (ty.isDecayed()) + .{ .decayed_static_array = ty.data.array } + else + .{ .static_array = ty.data.array }, + .incomplete_array => if (ty.isDecayed()) + .{ .decayed_incomplete_array = ty.data.array } + else + .{ .incomplete_array = ty.data.array }, .vector => .{ .vector = ty.data.array }, - .variable_len_array => .{ .variable_len_array = ty.data.expr }, - .decayed_variable_len_array => .{ .decayed_variable_len_array = ty.data.expr }, + .variable_len_array => if (ty.isDecayed()) + .{ .decayed_variable_len_array = ty.data.expr } + else + .{ .variable_len_array = ty.data.expr }, .@"struct" => .{ .@"struct" = ty.data.record }, .@"union" => .{ .@"union" = ty.data.record }, .@"enum" => .{ .@"enum" = ty.data.@"enum" }, - .typeof_type => .{ .typeof_type = ty.data.sub_type }, - .decayed_typeof_type => .{ .decayed_typeof_type = ty.data.sub_type }, - .typeof_expr => .{ .typeof_expr = ty.data.expr }, - .decayed_typeof_expr => .{ .decayed_typeof_expr = ty.data.expr }, + .typeof_type => if (ty.isDecayed()) + .{ .decayed_typeof_type = ty.data.sub_type } + else + .{ .typeof_type = ty.data.sub_type }, + .typeof_expr => if (ty.isDecayed()) + .{ .decayed_typeof_expr = ty.data.expr } + else + .{ .typeof_expr = ty.data.expr }, - .attributed => .{ .attributed = ty.data.attributed }, + .attributed => if (ty.isDecayed()) + .{ .decayed_attributed = ty.data.attributed } + else + .{ .attributed = ty.data.attributed }, else => unreachable, }; } @@ -2472,24 +2429,17 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts try w.writeAll(")"); return true; } + if (ty.isPtr()) { + const elem_ty = ty.elemType(); + const simple = try elem_ty.printPrologue(mapper, langopts, w); + if (simple) try w.writeByte(' '); + if (elem_ty.isFunc() or elem_ty.isArray()) try w.writeByte('('); + try w.writeByte('*'); + try ty.qual.dump(w); + return false; + } switch (ty.specifier) { - .pointer, - .decayed_array, - .decayed_static_array, - .decayed_incomplete_array, - .decayed_variable_len_array, - .decayed_unspecified_variable_len_array, - .decayed_typeof_type, - .decayed_typeof_expr, - => { - const elem_ty = ty.elemType(); - const simple = try elem_ty.printPrologue(mapper, langopts, w); - if (simple) try w.writeByte(' '); - if (elem_ty.isFunc() or elem_ty.isArray()) try w.writeByte('('); - try w.writeByte('*'); - try ty.qual.dump(w); - return false; - }, + .pointer => unreachable, .func, .var_args_func, .old_style_func => { const ret_ty = ty.data.func.return_type; const simple = try ret_ty.printPrologue(mapper, langopts, w); @@ -2541,20 +2491,14 @@ fn printPrologue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts fn printEpilogue(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: anytype) @TypeOf(w).Error!void { if (ty.qual.atomic) return; + if (ty.isPtr()) { + const elem_ty = ty.elemType(); + if (elem_ty.isFunc() or elem_ty.isArray()) try w.writeByte(')'); + try elem_ty.printEpilogue(mapper, langopts, w); + return; + } switch (ty.specifier) { - .pointer, - .decayed_array, - .decayed_static_array, - .decayed_incomplete_array, - .decayed_variable_len_array, - .decayed_unspecified_variable_len_array, - .decayed_typeof_type, - .decayed_typeof_expr, - => { - const elem_ty = ty.elemType(); - if (elem_ty.isFunc() or elem_ty.isArray()) try w.writeByte(')'); - try elem_ty.printEpilogue(mapper, langopts, w); - }, + .pointer => unreachable, // handled above .func, .var_args_func, .old_style_func => { try w.writeByte('('); for (ty.data.func.params, 0..) |param, i| { @@ -2637,10 +2581,10 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: try w.writeAll(") "); try ty.data.func.return_type.dump(mapper, langopts, w); }, - .array, .static_array, .decayed_array, .decayed_static_array => { - if (ty.specifier == .decayed_array or ty.specifier == .decayed_static_array) try w.writeAll("*d"); + .array, .static_array => { + if (ty.isDecayed()) try w.writeAll("*d"); try w.writeByte('['); - if (ty.specifier == .static_array or ty.specifier == .decayed_static_array) try w.writeAll("static "); + if (ty.specifier == .static_array) try w.writeAll("static "); try w.print("{d}]", .{ty.data.array.len}); try ty.data.array.elem.dump(mapper, langopts, w); }, @@ -2649,8 +2593,8 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: try ty.data.array.elem.dump(mapper, langopts, w); try w.writeAll(")"); }, - .incomplete_array, .decayed_incomplete_array => { - if (ty.specifier == .decayed_incomplete_array) try w.writeAll("*d"); + .incomplete_array => { + if (ty.isDecayed()) try w.writeAll("*d"); try w.writeAll("[]"); try ty.data.array.elem.dump(mapper, langopts, w); }, @@ -2672,27 +2616,28 @@ pub fn dump(ty: Type, mapper: StringInterner.TypeMapper, langopts: LangOpts, w: try w.print("union {s}", .{mapper.lookup(ty.data.record.name)}); if (dump_detailed_containers) try dumpRecord(ty.data.record, mapper, langopts, w); }, - .unspecified_variable_len_array, .decayed_unspecified_variable_len_array => { - if (ty.specifier == .decayed_unspecified_variable_len_array) try w.writeAll("*d"); + .unspecified_variable_len_array => { + if (ty.isDecayed()) try w.writeAll("*d"); try w.writeAll("[*]"); try ty.data.sub_type.dump(mapper, langopts, w); }, - .variable_len_array, .decayed_variable_len_array => { - if (ty.specifier == .decayed_variable_len_array) try w.writeAll("*d"); + .variable_len_array => { + if (ty.isDecayed()) try w.writeAll("*d"); try w.writeAll("[]"); try ty.data.expr.ty.dump(mapper, langopts, w); }, - .typeof_type, .decayed_typeof_type => { + .typeof_type => { try w.writeAll("typeof("); try ty.data.sub_type.dump(mapper, langopts, w); try w.writeAll(")"); }, - .typeof_expr, .decayed_typeof_expr => { + .typeof_expr => { try w.writeAll("typeof(: "); try ty.data.expr.ty.dump(mapper, langopts, w); try w.writeAll(")"); }, .attributed => { + if (ty.isDecayed()) try w.writeAll("*d:"); try w.writeAll("attributed("); try ty.data.attributed.base.dump(mapper, langopts, w); try w.writeAll(")"); diff --git a/deps/aro/aro/Value.zig b/deps/aro/aro/Value.zig index ea97125b765c2af046bee178555fbc3ed94896aa..f2793555ddf19ec2198a2bbc56c563d0bc79ae3f 100644 --- a/deps/aro/aro/Value.zig +++ b/deps/aro/aro/Value.zig @@ -215,7 +215,7 @@ pub fn intCast(v: *Value, dest_ty: Type, comp: *Compilation) !void { const limbs = try comp.gpa.alloc( std.math.big.Limb, - std.math.big.int.calcTwosCompLimbCount(bits), + std.math.big.int.calcTwosCompLimbCount(@max(big.bitCountTwosComp(), bits)), ); defer comp.gpa.free(limbs); var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; diff --git a/deps/aro/aro/target.zig b/deps/aro/aro/target.zig index 1e55f4bc5b2dec690d4d0ce7904934d87febe549..f05e64d5a6baedc6aecebae91ab524e5d56f7945 100644 --- a/deps/aro/aro/target.zig +++ b/deps/aro/aro/target.zig @@ -1,7 +1,6 @@ const std = @import("std"); const LangOpts = @import("LangOpts.zig"); const Type = @import("Type.zig"); -const llvm = @import("root").codegen.llvm; const TargetSet = @import("Builtins/Properties.zig").TargetSet; /// intmax_t for this target -- 2.54.0 From 74010fecc7bbeaf9de77c28dda5906c3c1f4a6df Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 24 Nov 2023 20:11:11 +0200 Subject: [PATCH 2/2] translate-c: use Aro's tokenizer --- CMakeLists.txt | 1 - lib/std/c.zig | 8 - lib/std/c/tokenizer.zig | 1585 --------------------------------- lib/std/zig/c_translation.zig | 6 +- src/Compilation.zig | 2 +- src/main.zig | 2 +- src/stubs/aro_builtins.zig | 4 +- src/translate_c.zig | 564 ++++++------ test/translate_c.zig | 14 +- 9 files changed, 319 insertions(+), 1867 deletions(-) delete mode 100644 lib/std/c/tokenizer.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index b53ab0a2b5b0c9a5b4d65a28ac5bd5be3ed3be7e..897bfde7598cbd0e98e302da7b9e8594ec0abdbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,7 +218,6 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/builtin.zig" "${CMAKE_SOURCE_DIR}/lib/std/c.zig" "${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig" - "${CMAKE_SOURCE_DIR}/lib/std/c/tokenizer.zig" "${CMAKE_SOURCE_DIR}/lib/std/child_process.zig" "${CMAKE_SOURCE_DIR}/lib/std/coff.zig" "${CMAKE_SOURCE_DIR}/lib/std/comptime_string_map.zig" diff --git a/lib/std/c.zig b/lib/std/c.zig index 7d4a9b782fd095f390aad0719cee48551bc36862..6b7fac985c32342ce1a458f6e282a1aff40a6790 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -5,14 +5,6 @@ const page_size = std.mem.page_size; const iovec = std.os.iovec; const iovec_const = std.os.iovec_const; -test { - _ = tokenizer; -} - -pub const tokenizer = @import("c/tokenizer.zig"); -pub const Token = tokenizer.Token; -pub const Tokenizer = tokenizer.Tokenizer; - /// The return type is `type` to force comptime function call execution. /// TODO: https://github.com/ziglang/zig/issues/425 /// If not linking libc, returns struct{pub const ok = false;} diff --git a/lib/std/c/tokenizer.zig b/lib/std/c/tokenizer.zig deleted file mode 100644 index 2e7722d0259e6d671a7d630edcbac9615705e5f4..0000000000000000000000000000000000000000 --- a/lib/std/c/tokenizer.zig +++ /dev/null @@ -1,1585 +0,0 @@ -const std = @import("std"); - -pub const Token = struct { - id: Id, - start: usize, - end: usize, - - pub const Id = union(enum) { - Invalid, - Eof, - Nl, - Identifier, - - /// special case for #include <...> - MacroString, - StringLiteral: StrKind, - CharLiteral: StrKind, - IntegerLiteral: NumSuffix, - FloatLiteral: NumSuffix, - Bang, - BangEqual, - Pipe, - PipePipe, - PipeEqual, - Equal, - EqualEqual, - LParen, - RParen, - LBrace, - RBrace, - LBracket, - RBracket, - Period, - Ellipsis, - Caret, - CaretEqual, - Plus, - PlusPlus, - PlusEqual, - Minus, - MinusMinus, - MinusEqual, - Asterisk, - AsteriskEqual, - Percent, - PercentEqual, - Arrow, - Colon, - Semicolon, - Slash, - SlashEqual, - Comma, - Ampersand, - AmpersandAmpersand, - AmpersandEqual, - QuestionMark, - AngleBracketLeft, - AngleBracketLeftEqual, - AngleBracketAngleBracketLeft, - AngleBracketAngleBracketLeftEqual, - AngleBracketRight, - AngleBracketRightEqual, - AngleBracketAngleBracketRight, - AngleBracketAngleBracketRightEqual, - Tilde, - LineComment, - MultiLineComment, - Hash, - HashHash, - - Keyword_auto, - Keyword_break, - Keyword_case, - Keyword_char, - Keyword_const, - Keyword_continue, - Keyword_default, - Keyword_do, - Keyword_double, - Keyword_else, - Keyword_enum, - Keyword_extern, - Keyword_float, - Keyword_for, - Keyword_goto, - Keyword_if, - Keyword_int, - Keyword_long, - Keyword_register, - Keyword_return, - Keyword_short, - Keyword_signed, - Keyword_sizeof, - Keyword_static, - Keyword_struct, - Keyword_switch, - Keyword_typedef, - Keyword_union, - Keyword_unsigned, - Keyword_void, - Keyword_volatile, - Keyword_while, - - // ISO C99 - Keyword_bool, - Keyword_complex, - Keyword_imaginary, - Keyword_inline, - Keyword_restrict, - - // ISO C11 - Keyword_alignas, - Keyword_alignof, - Keyword_atomic, - Keyword_generic, - Keyword_noreturn, - Keyword_static_assert, - Keyword_thread_local, - - // Preprocessor directives - Keyword_include, - Keyword_define, - Keyword_ifdef, - Keyword_ifndef, - Keyword_error, - Keyword_pragma, - - pub fn symbol(id: Id) []const u8 { - return symbolName(id); - } - - pub fn symbolName(id: std.meta.Tag(Id)) []const u8 { - return switch (id) { - .Invalid => "Invalid", - .Eof => "Eof", - .Nl => "NewLine", - .Identifier => "Identifier", - .MacroString => "MacroString", - .StringLiteral => "StringLiteral", - .CharLiteral => "CharLiteral", - .IntegerLiteral => "IntegerLiteral", - .FloatLiteral => "FloatLiteral", - .LineComment => "LineComment", - .MultiLineComment => "MultiLineComment", - - .Bang => "!", - .BangEqual => "!=", - .Pipe => "|", - .PipePipe => "||", - .PipeEqual => "|=", - .Equal => "=", - .EqualEqual => "==", - .LParen => "(", - .RParen => ")", - .LBrace => "{", - .RBrace => "}", - .LBracket => "[", - .RBracket => "]", - .Period => ".", - .Ellipsis => "...", - .Caret => "^", - .CaretEqual => "^=", - .Plus => "+", - .PlusPlus => "++", - .PlusEqual => "+=", - .Minus => "-", - .MinusMinus => "--", - .MinusEqual => "-=", - .Asterisk => "*", - .AsteriskEqual => "*=", - .Percent => "%", - .PercentEqual => "%=", - .Arrow => "->", - .Colon => ":", - .Semicolon => ";", - .Slash => "/", - .SlashEqual => "/=", - .Comma => ",", - .Ampersand => "&", - .AmpersandAmpersand => "&&", - .AmpersandEqual => "&=", - .QuestionMark => "?", - .AngleBracketLeft => "<", - .AngleBracketLeftEqual => "<=", - .AngleBracketAngleBracketLeft => "<<", - .AngleBracketAngleBracketLeftEqual => "<<=", - .AngleBracketRight => ">", - .AngleBracketRightEqual => ">=", - .AngleBracketAngleBracketRight => ">>", - .AngleBracketAngleBracketRightEqual => ">>=", - .Tilde => "~", - .Hash => "#", - .HashHash => "##", - .Keyword_auto => "auto", - .Keyword_break => "break", - .Keyword_case => "case", - .Keyword_char => "char", - .Keyword_const => "const", - .Keyword_continue => "continue", - .Keyword_default => "default", - .Keyword_do => "do", - .Keyword_double => "double", - .Keyword_else => "else", - .Keyword_enum => "enum", - .Keyword_extern => "extern", - .Keyword_float => "float", - .Keyword_for => "for", - .Keyword_goto => "goto", - .Keyword_if => "if", - .Keyword_int => "int", - .Keyword_long => "long", - .Keyword_register => "register", - .Keyword_return => "return", - .Keyword_short => "short", - .Keyword_signed => "signed", - .Keyword_sizeof => "sizeof", - .Keyword_static => "static", - .Keyword_struct => "struct", - .Keyword_switch => "switch", - .Keyword_typedef => "typedef", - .Keyword_union => "union", - .Keyword_unsigned => "unsigned", - .Keyword_void => "void", - .Keyword_volatile => "volatile", - .Keyword_while => "while", - .Keyword_bool => "_Bool", - .Keyword_complex => "_Complex", - .Keyword_imaginary => "_Imaginary", - .Keyword_inline => "inline", - .Keyword_restrict => "restrict", - .Keyword_alignas => "_Alignas", - .Keyword_alignof => "_Alignof", - .Keyword_atomic => "_Atomic", - .Keyword_generic => "_Generic", - .Keyword_noreturn => "_Noreturn", - .Keyword_static_assert => "_Static_assert", - .Keyword_thread_local => "_Thread_local", - .Keyword_include => "include", - .Keyword_define => "define", - .Keyword_ifdef => "ifdef", - .Keyword_ifndef => "ifndef", - .Keyword_error => "error", - .Keyword_pragma => "pragma", - }; - } - }; - - // TODO extensions - pub const keywords = std.ComptimeStringMap(Id, .{ - .{ "auto", .Keyword_auto }, - .{ "break", .Keyword_break }, - .{ "case", .Keyword_case }, - .{ "char", .Keyword_char }, - .{ "const", .Keyword_const }, - .{ "continue", .Keyword_continue }, - .{ "default", .Keyword_default }, - .{ "do", .Keyword_do }, - .{ "double", .Keyword_double }, - .{ "else", .Keyword_else }, - .{ "enum", .Keyword_enum }, - .{ "extern", .Keyword_extern }, - .{ "float", .Keyword_float }, - .{ "for", .Keyword_for }, - .{ "goto", .Keyword_goto }, - .{ "if", .Keyword_if }, - .{ "int", .Keyword_int }, - .{ "long", .Keyword_long }, - .{ "register", .Keyword_register }, - .{ "return", .Keyword_return }, - .{ "short", .Keyword_short }, - .{ "signed", .Keyword_signed }, - .{ "sizeof", .Keyword_sizeof }, - .{ "static", .Keyword_static }, - .{ "struct", .Keyword_struct }, - .{ "switch", .Keyword_switch }, - .{ "typedef", .Keyword_typedef }, - .{ "union", .Keyword_union }, - .{ "unsigned", .Keyword_unsigned }, - .{ "void", .Keyword_void }, - .{ "volatile", .Keyword_volatile }, - .{ "while", .Keyword_while }, - - // ISO C99 - .{ "_Bool", .Keyword_bool }, - .{ "_Complex", .Keyword_complex }, - .{ "_Imaginary", .Keyword_imaginary }, - .{ "inline", .Keyword_inline }, - .{ "restrict", .Keyword_restrict }, - - // ISO C11 - .{ "_Alignas", .Keyword_alignas }, - .{ "_Alignof", .Keyword_alignof }, - .{ "_Atomic", .Keyword_atomic }, - .{ "_Generic", .Keyword_generic }, - .{ "_Noreturn", .Keyword_noreturn }, - .{ "_Static_assert", .Keyword_static_assert }, - .{ "_Thread_local", .Keyword_thread_local }, - - // Preprocessor directives - .{ "include", .Keyword_include }, - .{ "define", .Keyword_define }, - .{ "ifdef", .Keyword_ifdef }, - .{ "ifndef", .Keyword_ifndef }, - .{ "error", .Keyword_error }, - .{ "pragma", .Keyword_pragma }, - }); - - // TODO do this in the preprocessor - pub fn getKeyword(bytes: []const u8, pp_directive: bool) ?Id { - if (keywords.get(bytes)) |id| { - switch (id) { - .Keyword_include, - .Keyword_define, - .Keyword_ifdef, - .Keyword_ifndef, - .Keyword_error, - .Keyword_pragma, - => if (!pp_directive) return null, - else => {}, - } - return id; - } - return null; - } - - pub const NumSuffix = enum { - none, - f, - l, - u, - lu, - ll, - llu, - }; - - pub const StrKind = enum { - none, - wide, - utf_8, - utf_16, - utf_32, - }; -}; - -pub const Tokenizer = struct { - buffer: []const u8, - index: usize = 0, - prev_tok_id: std.meta.Tag(Token.Id) = .Invalid, - pp_directive: bool = false, - - pub fn next(self: *Tokenizer) Token { - var result = Token{ - .id = .Eof, - .start = self.index, - .end = undefined, - }; - var state: enum { - Start, - Cr, - BackSlash, - BackSlashCr, - u, - u8, - U, - L, - StringLiteral, - CharLiteralStart, - CharLiteral, - EscapeSequence, - CrEscape, - OctalEscape, - HexEscape, - UnicodeEscape, - Identifier, - Equal, - Bang, - Pipe, - Percent, - Asterisk, - Plus, - - /// special case for #include <...> - MacroString, - AngleBracketLeft, - AngleBracketAngleBracketLeft, - AngleBracketRight, - AngleBracketAngleBracketRight, - Caret, - Period, - Period2, - Minus, - Slash, - Ampersand, - Hash, - LineComment, - MultiLineComment, - MultiLineCommentAsterisk, - Zero, - IntegerLiteralOct, - IntegerLiteralBinary, - IntegerLiteralBinaryFirst, - IntegerLiteralHex, - IntegerLiteralHexFirst, - IntegerLiteral, - IntegerSuffix, - IntegerSuffixU, - IntegerSuffixL, - IntegerSuffixLL, - IntegerSuffixUL, - FloatFraction, - FloatFractionHex, - FloatExponent, - FloatExponentDigits, - FloatSuffix, - } = .Start; - var string = false; - var counter: u32 = 0; - while (self.index < self.buffer.len) : (self.index += 1) { - const c = self.buffer[self.index]; - switch (state) { - .Start => switch (c) { - '\n' => { - self.pp_directive = false; - result.id = .Nl; - self.index += 1; - break; - }, - '\r' => { - state = .Cr; - }, - '"' => { - result.id = .{ .StringLiteral = .none }; - state = .StringLiteral; - }, - '\'' => { - result.id = .{ .CharLiteral = .none }; - state = .CharLiteralStart; - }, - 'u' => { - state = .u; - }, - 'U' => { - state = .U; - }, - 'L' => { - state = .L; - }, - 'a'...'t', 'v'...'z', 'A'...'K', 'M'...'T', 'V'...'Z', '_', '$' => { - state = .Identifier; - }, - '=' => { - state = .Equal; - }, - '!' => { - state = .Bang; - }, - '|' => { - state = .Pipe; - }, - '(' => { - result.id = .LParen; - self.index += 1; - break; - }, - ')' => { - result.id = .RParen; - self.index += 1; - break; - }, - '[' => { - result.id = .LBracket; - self.index += 1; - break; - }, - ']' => { - result.id = .RBracket; - self.index += 1; - break; - }, - ';' => { - result.id = .Semicolon; - self.index += 1; - break; - }, - ',' => { - result.id = .Comma; - self.index += 1; - break; - }, - '?' => { - result.id = .QuestionMark; - self.index += 1; - break; - }, - ':' => { - result.id = .Colon; - self.index += 1; - break; - }, - '%' => { - state = .Percent; - }, - '*' => { - state = .Asterisk; - }, - '+' => { - state = .Plus; - }, - '<' => { - if (self.prev_tok_id == .Keyword_include) - state = .MacroString - else - state = .AngleBracketLeft; - }, - '>' => { - state = .AngleBracketRight; - }, - '^' => { - state = .Caret; - }, - '{' => { - result.id = .LBrace; - self.index += 1; - break; - }, - '}' => { - result.id = .RBrace; - self.index += 1; - break; - }, - '~' => { - result.id = .Tilde; - self.index += 1; - break; - }, - '.' => { - state = .Period; - }, - '-' => { - state = .Minus; - }, - '/' => { - state = .Slash; - }, - '&' => { - state = .Ampersand; - }, - '#' => { - state = .Hash; - }, - '0' => { - state = .Zero; - }, - '1'...'9' => { - state = .IntegerLiteral; - }, - '\\' => { - state = .BackSlash; - }, - '\t', '\x0B', '\x0C', ' ' => { - result.start = self.index + 1; - }, - else => { - // TODO handle invalid bytes better - result.id = .Invalid; - self.index += 1; - break; - }, - }, - .Cr => switch (c) { - '\n' => { - self.pp_directive = false; - result.id = .Nl; - self.index += 1; - break; - }, - else => { - result.id = .Invalid; - break; - }, - }, - .BackSlash => switch (c) { - '\n' => { - result.start = self.index + 1; - state = .Start; - }, - '\r' => { - state = .BackSlashCr; - }, - '\t', '\x0B', '\x0C', ' ' => { - // TODO warn - }, - else => { - result.id = .Invalid; - break; - }, - }, - .BackSlashCr => switch (c) { - '\n' => { - result.start = self.index + 1; - state = .Start; - }, - else => { - result.id = .Invalid; - break; - }, - }, - .u => switch (c) { - '8' => { - state = .u8; - }, - '\'' => { - result.id = .{ .CharLiteral = .utf_16 }; - state = .CharLiteralStart; - }, - '\"' => { - result.id = .{ .StringLiteral = .utf_16 }; - state = .StringLiteral; - }, - else => { - self.index -= 1; - state = .Identifier; - }, - }, - .u8 => switch (c) { - '\"' => { - result.id = .{ .StringLiteral = .utf_8 }; - state = .StringLiteral; - }, - else => { - self.index -= 1; - state = .Identifier; - }, - }, - .U => switch (c) { - '\'' => { - result.id = .{ .CharLiteral = .utf_32 }; - state = .CharLiteralStart; - }, - '\"' => { - result.id = .{ .StringLiteral = .utf_32 }; - state = .StringLiteral; - }, - else => { - self.index -= 1; - state = .Identifier; - }, - }, - .L => switch (c) { - '\'' => { - result.id = .{ .CharLiteral = .wide }; - state = .CharLiteralStart; - }, - '\"' => { - result.id = .{ .StringLiteral = .wide }; - state = .StringLiteral; - }, - else => { - self.index -= 1; - state = .Identifier; - }, - }, - .StringLiteral => switch (c) { - '\\' => { - string = true; - state = .EscapeSequence; - }, - '"' => { - self.index += 1; - break; - }, - '\n', '\r' => { - result.id = .Invalid; - break; - }, - else => {}, - }, - .CharLiteralStart => switch (c) { - '\\' => { - string = false; - state = .EscapeSequence; - }, - '\'', '\n' => { - result.id = .Invalid; - break; - }, - else => { - state = .CharLiteral; - }, - }, - .CharLiteral => switch (c) { - '\\' => { - string = false; - state = .EscapeSequence; - }, - '\'' => { - self.index += 1; - break; - }, - '\n' => { - result.id = .Invalid; - break; - }, - else => {}, - }, - .EscapeSequence => switch (c) { - '\'', '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v', '\n' => { - state = if (string) .StringLiteral else .CharLiteral; - }, - '\r' => { - state = .CrEscape; - }, - '0'...'7' => { - counter = 1; - state = .OctalEscape; - }, - 'x' => { - state = .HexEscape; - }, - 'u' => { - counter = 4; - state = .OctalEscape; - }, - 'U' => { - counter = 8; - state = .OctalEscape; - }, - else => { - result.id = .Invalid; - break; - }, - }, - .CrEscape => switch (c) { - '\n' => { - state = if (string) .StringLiteral else .CharLiteral; - }, - else => { - result.id = .Invalid; - break; - }, - }, - .OctalEscape => switch (c) { - '0'...'7' => { - counter += 1; - if (counter == 3) { - state = if (string) .StringLiteral else .CharLiteral; - } - }, - else => { - self.index -= 1; - state = if (string) .StringLiteral else .CharLiteral; - }, - }, - .HexEscape => switch (c) { - '0'...'9', 'a'...'f', 'A'...'F' => {}, - else => { - self.index -= 1; - state = if (string) .StringLiteral else .CharLiteral; - }, - }, - .UnicodeEscape => switch (c) { - '0'...'9', 'a'...'f', 'A'...'F' => { - counter -= 1; - if (counter == 0) { - state = if (string) .StringLiteral else .CharLiteral; - } - }, - else => { - if (counter != 0) { - result.id = .Invalid; - break; - } - self.index -= 1; - state = if (string) .StringLiteral else .CharLiteral; - }, - }, - .Identifier => switch (c) { - 'a'...'z', 'A'...'Z', '_', '0'...'9', '$' => {}, - else => { - result.id = Token.getKeyword(self.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier; - if (self.prev_tok_id == .Hash) - self.pp_directive = true; - break; - }, - }, - .Equal => switch (c) { - '=' => { - result.id = .EqualEqual; - self.index += 1; - break; - }, - else => { - result.id = .Equal; - break; - }, - }, - .Bang => switch (c) { - '=' => { - result.id = .BangEqual; - self.index += 1; - break; - }, - else => { - result.id = .Bang; - break; - }, - }, - .Pipe => switch (c) { - '=' => { - result.id = .PipeEqual; - self.index += 1; - break; - }, - '|' => { - result.id = .PipePipe; - self.index += 1; - break; - }, - else => { - result.id = .Pipe; - break; - }, - }, - .Percent => switch (c) { - '=' => { - result.id = .PercentEqual; - self.index += 1; - break; - }, - else => { - result.id = .Percent; - break; - }, - }, - .Asterisk => switch (c) { - '=' => { - result.id = .AsteriskEqual; - self.index += 1; - break; - }, - else => { - result.id = .Asterisk; - break; - }, - }, - .Plus => switch (c) { - '=' => { - result.id = .PlusEqual; - self.index += 1; - break; - }, - '+' => { - result.id = .PlusPlus; - self.index += 1; - break; - }, - else => { - result.id = .Plus; - break; - }, - }, - .MacroString => switch (c) { - '>' => { - result.id = .MacroString; - self.index += 1; - break; - }, - else => {}, - }, - .AngleBracketLeft => switch (c) { - '<' => { - state = .AngleBracketAngleBracketLeft; - }, - '=' => { - result.id = .AngleBracketLeftEqual; - self.index += 1; - break; - }, - else => { - result.id = .AngleBracketLeft; - break; - }, - }, - .AngleBracketAngleBracketLeft => switch (c) { - '=' => { - result.id = .AngleBracketAngleBracketLeftEqual; - self.index += 1; - break; - }, - else => { - result.id = .AngleBracketAngleBracketLeft; - break; - }, - }, - .AngleBracketRight => switch (c) { - '>' => { - state = .AngleBracketAngleBracketRight; - }, - '=' => { - result.id = .AngleBracketRightEqual; - self.index += 1; - break; - }, - else => { - result.id = .AngleBracketRight; - break; - }, - }, - .AngleBracketAngleBracketRight => switch (c) { - '=' => { - result.id = .AngleBracketAngleBracketRightEqual; - self.index += 1; - break; - }, - else => { - result.id = .AngleBracketAngleBracketRight; - break; - }, - }, - .Caret => switch (c) { - '=' => { - result.id = .CaretEqual; - self.index += 1; - break; - }, - else => { - result.id = .Caret; - break; - }, - }, - .Period => switch (c) { - '.' => { - state = .Period2; - }, - '0'...'9' => { - state = .FloatFraction; - }, - else => { - result.id = .Period; - break; - }, - }, - .Period2 => switch (c) { - '.' => { - result.id = .Ellipsis; - self.index += 1; - break; - }, - else => { - result.id = .Period; - self.index -= 1; - break; - }, - }, - .Minus => switch (c) { - '>' => { - result.id = .Arrow; - self.index += 1; - break; - }, - '=' => { - result.id = .MinusEqual; - self.index += 1; - break; - }, - '-' => { - result.id = .MinusMinus; - self.index += 1; - break; - }, - else => { - result.id = .Minus; - break; - }, - }, - .Slash => switch (c) { - '/' => { - state = .LineComment; - }, - '*' => { - state = .MultiLineComment; - }, - '=' => { - result.id = .SlashEqual; - self.index += 1; - break; - }, - else => { - result.id = .Slash; - break; - }, - }, - .Ampersand => switch (c) { - '&' => { - result.id = .AmpersandAmpersand; - self.index += 1; - break; - }, - '=' => { - result.id = .AmpersandEqual; - self.index += 1; - break; - }, - else => { - result.id = .Ampersand; - break; - }, - }, - .Hash => switch (c) { - '#' => { - result.id = .HashHash; - self.index += 1; - break; - }, - else => { - result.id = .Hash; - break; - }, - }, - .LineComment => switch (c) { - '\n' => { - result.id = .LineComment; - break; - }, - else => {}, - }, - .MultiLineComment => switch (c) { - '*' => { - state = .MultiLineCommentAsterisk; - }, - else => {}, - }, - .MultiLineCommentAsterisk => switch (c) { - '/' => { - result.id = .MultiLineComment; - self.index += 1; - break; - }, - else => { - state = .MultiLineComment; - }, - }, - .Zero => switch (c) { - '0'...'9' => { - state = .IntegerLiteralOct; - }, - 'b', 'B' => { - state = .IntegerLiteralBinaryFirst; - }, - 'x', 'X' => { - state = .IntegerLiteralHexFirst; - }, - '.' => { - state = .FloatFraction; - }, - else => { - state = .IntegerSuffix; - self.index -= 1; - }, - }, - .IntegerLiteralOct => switch (c) { - '0'...'7' => {}, - else => { - state = .IntegerSuffix; - self.index -= 1; - }, - }, - .IntegerLiteralBinaryFirst => switch (c) { - '0'...'7' => state = .IntegerLiteralBinary, - else => { - result.id = .Invalid; - break; - }, - }, - .IntegerLiteralBinary => switch (c) { - '0', '1' => {}, - else => { - state = .IntegerSuffix; - self.index -= 1; - }, - }, - .IntegerLiteralHexFirst => switch (c) { - '0'...'9', 'a'...'f', 'A'...'F' => state = .IntegerLiteralHex, - '.' => { - state = .FloatFractionHex; - }, - 'p', 'P' => { - state = .FloatExponent; - }, - else => { - result.id = .Invalid; - break; - }, - }, - .IntegerLiteralHex => switch (c) { - '0'...'9', 'a'...'f', 'A'...'F' => {}, - '.' => { - state = .FloatFractionHex; - }, - 'p', 'P' => { - state = .FloatExponent; - }, - else => { - state = .IntegerSuffix; - self.index -= 1; - }, - }, - .IntegerLiteral => switch (c) { - '0'...'9' => {}, - '.' => { - state = .FloatFraction; - }, - 'e', 'E' => { - state = .FloatExponent; - }, - else => { - state = .IntegerSuffix; - self.index -= 1; - }, - }, - .IntegerSuffix => switch (c) { - 'u', 'U' => { - state = .IntegerSuffixU; - }, - 'l', 'L' => { - state = .IntegerSuffixL; - }, - else => { - result.id = .{ .IntegerLiteral = .none }; - break; - }, - }, - .IntegerSuffixU => switch (c) { - 'l', 'L' => { - state = .IntegerSuffixUL; - }, - else => { - result.id = .{ .IntegerLiteral = .u }; - break; - }, - }, - .IntegerSuffixL => switch (c) { - 'l', 'L' => { - state = .IntegerSuffixLL; - }, - 'u', 'U' => { - result.id = .{ .IntegerLiteral = .lu }; - self.index += 1; - break; - }, - else => { - result.id = .{ .IntegerLiteral = .l }; - break; - }, - }, - .IntegerSuffixLL => switch (c) { - 'u', 'U' => { - result.id = .{ .IntegerLiteral = .llu }; - self.index += 1; - break; - }, - else => { - result.id = .{ .IntegerLiteral = .ll }; - break; - }, - }, - .IntegerSuffixUL => switch (c) { - 'l', 'L' => { - result.id = .{ .IntegerLiteral = .llu }; - self.index += 1; - break; - }, - else => { - result.id = .{ .IntegerLiteral = .lu }; - break; - }, - }, - .FloatFraction => switch (c) { - '0'...'9' => {}, - 'e', 'E' => { - state = .FloatExponent; - }, - else => { - self.index -= 1; - state = .FloatSuffix; - }, - }, - .FloatFractionHex => switch (c) { - '0'...'9', 'a'...'f', 'A'...'F' => {}, - 'p', 'P' => { - state = .FloatExponent; - }, - else => { - result.id = .Invalid; - break; - }, - }, - .FloatExponent => switch (c) { - '+', '-' => { - state = .FloatExponentDigits; - }, - else => { - self.index -= 1; - state = .FloatExponentDigits; - }, - }, - .FloatExponentDigits => switch (c) { - '0'...'9' => { - counter += 1; - }, - else => { - if (counter == 0) { - result.id = .Invalid; - break; - } - self.index -= 1; - state = .FloatSuffix; - }, - }, - .FloatSuffix => switch (c) { - 'l', 'L' => { - result.id = .{ .FloatLiteral = .l }; - self.index += 1; - break; - }, - 'f', 'F' => { - result.id = .{ .FloatLiteral = .f }; - self.index += 1; - break; - }, - else => { - result.id = .{ .FloatLiteral = .none }; - break; - }, - }, - } - } else if (self.index == self.buffer.len) { - switch (state) { - .Start => {}, - .u, .u8, .U, .L, .Identifier => { - result.id = Token.getKeyword(self.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier; - }, - - .Cr, - .BackSlash, - .BackSlashCr, - .Period2, - .StringLiteral, - .CharLiteralStart, - .CharLiteral, - .EscapeSequence, - .CrEscape, - .OctalEscape, - .HexEscape, - .UnicodeEscape, - .MultiLineComment, - .MultiLineCommentAsterisk, - .FloatExponent, - .MacroString, - .IntegerLiteralBinaryFirst, - .IntegerLiteralHexFirst, - => result.id = .Invalid, - - .FloatExponentDigits => result.id = if (counter == 0) .Invalid else .{ .FloatLiteral = .none }, - - .FloatFraction, - .FloatFractionHex, - => result.id = .{ .FloatLiteral = .none }, - - .IntegerLiteralOct, - .IntegerLiteralBinary, - .IntegerLiteralHex, - .IntegerLiteral, - .IntegerSuffix, - .Zero, - => result.id = .{ .IntegerLiteral = .none }, - .IntegerSuffixU => result.id = .{ .IntegerLiteral = .u }, - .IntegerSuffixL => result.id = .{ .IntegerLiteral = .l }, - .IntegerSuffixLL => result.id = .{ .IntegerLiteral = .ll }, - .IntegerSuffixUL => result.id = .{ .IntegerLiteral = .lu }, - - .FloatSuffix => result.id = .{ .FloatLiteral = .none }, - .Equal => result.id = .Equal, - .Bang => result.id = .Bang, - .Minus => result.id = .Minus, - .Slash => result.id = .Slash, - .Ampersand => result.id = .Ampersand, - .Hash => result.id = .Hash, - .Period => result.id = .Period, - .Pipe => result.id = .Pipe, - .AngleBracketAngleBracketRight => result.id = .AngleBracketAngleBracketRight, - .AngleBracketRight => result.id = .AngleBracketRight, - .AngleBracketAngleBracketLeft => result.id = .AngleBracketAngleBracketLeft, - .AngleBracketLeft => result.id = .AngleBracketLeft, - .Plus => result.id = .Plus, - .Percent => result.id = .Percent, - .Caret => result.id = .Caret, - .Asterisk => result.id = .Asterisk, - .LineComment => result.id = .LineComment, - } - } - - self.prev_tok_id = result.id; - result.end = self.index; - return result; - } -}; - -test "operators" { - try expectTokens( - \\ ! != | || |= = == - \\ ( ) { } [ ] . .. ... - \\ ^ ^= + ++ += - -- -= - \\ * *= % %= -> : ; / /= - \\ , & && &= ? < <= << - \\ <<= > >= >> >>= ~ # ## - \\ - , &[_]Token.Id{ - .Bang, - .BangEqual, - .Pipe, - .PipePipe, - .PipeEqual, - .Equal, - .EqualEqual, - .Nl, - .LParen, - .RParen, - .LBrace, - .RBrace, - .LBracket, - .RBracket, - .Period, - .Period, - .Period, - .Ellipsis, - .Nl, - .Caret, - .CaretEqual, - .Plus, - .PlusPlus, - .PlusEqual, - .Minus, - .MinusMinus, - .MinusEqual, - .Nl, - .Asterisk, - .AsteriskEqual, - .Percent, - .PercentEqual, - .Arrow, - .Colon, - .Semicolon, - .Slash, - .SlashEqual, - .Nl, - .Comma, - .Ampersand, - .AmpersandAmpersand, - .AmpersandEqual, - .QuestionMark, - .AngleBracketLeft, - .AngleBracketLeftEqual, - .AngleBracketAngleBracketLeft, - .Nl, - .AngleBracketAngleBracketLeftEqual, - .AngleBracketRight, - .AngleBracketRightEqual, - .AngleBracketAngleBracketRight, - .AngleBracketAngleBracketRightEqual, - .Tilde, - .Hash, - .HashHash, - .Nl, - }); -} - -test "keywords" { - try expectTokens( - \\auto break case char const continue default do - \\double else enum extern float for goto if int - \\long register return short signed sizeof static - \\struct switch typedef union unsigned void volatile - \\while _Bool _Complex _Imaginary inline restrict _Alignas - \\_Alignof _Atomic _Generic _Noreturn _Static_assert _Thread_local - \\ - , &[_]Token.Id{ - .Keyword_auto, - .Keyword_break, - .Keyword_case, - .Keyword_char, - .Keyword_const, - .Keyword_continue, - .Keyword_default, - .Keyword_do, - .Nl, - .Keyword_double, - .Keyword_else, - .Keyword_enum, - .Keyword_extern, - .Keyword_float, - .Keyword_for, - .Keyword_goto, - .Keyword_if, - .Keyword_int, - .Nl, - .Keyword_long, - .Keyword_register, - .Keyword_return, - .Keyword_short, - .Keyword_signed, - .Keyword_sizeof, - .Keyword_static, - .Nl, - .Keyword_struct, - .Keyword_switch, - .Keyword_typedef, - .Keyword_union, - .Keyword_unsigned, - .Keyword_void, - .Keyword_volatile, - .Nl, - .Keyword_while, - .Keyword_bool, - .Keyword_complex, - .Keyword_imaginary, - .Keyword_inline, - .Keyword_restrict, - .Keyword_alignas, - .Nl, - .Keyword_alignof, - .Keyword_atomic, - .Keyword_generic, - .Keyword_noreturn, - .Keyword_static_assert, - .Keyword_thread_local, - .Nl, - }); -} - -test "preprocessor keywords" { - try expectTokens( - \\#include - \\#define #include <1 - \\#ifdef - \\#ifndef - \\#error - \\#pragma - \\ - , &[_]Token.Id{ - .Hash, - .Keyword_include, - .MacroString, - .Nl, - .Hash, - .Keyword_define, - .Hash, - .Identifier, - .AngleBracketLeft, - .{ .IntegerLiteral = .none }, - .Nl, - .Hash, - .Keyword_ifdef, - .Nl, - .Hash, - .Keyword_ifndef, - .Nl, - .Hash, - .Keyword_error, - .Nl, - .Hash, - .Keyword_pragma, - .Nl, - }); -} - -test "line continuation" { - try expectTokens( - \\#define foo \ - \\ bar - \\"foo\ - \\ bar" - \\#define "foo" - \\ "bar" - \\#define "foo" \ - \\ "bar" - , &[_]Token.Id{ - .Hash, - .Keyword_define, - .Identifier, - .Identifier, - .Nl, - .{ .StringLiteral = .none }, - .Nl, - .Hash, - .Keyword_define, - .{ .StringLiteral = .none }, - .Nl, - .{ .StringLiteral = .none }, - .Nl, - .Hash, - .Keyword_define, - .{ .StringLiteral = .none }, - .{ .StringLiteral = .none }, - }); -} - -test "string prefix" { - try expectTokens( - \\"foo" - \\u"foo" - \\u8"foo" - \\U"foo" - \\L"foo" - \\'foo' - \\u'foo' - \\U'foo' - \\L'foo' - \\ - , &[_]Token.Id{ - .{ .StringLiteral = .none }, - .Nl, - .{ .StringLiteral = .utf_16 }, - .Nl, - .{ .StringLiteral = .utf_8 }, - .Nl, - .{ .StringLiteral = .utf_32 }, - .Nl, - .{ .StringLiteral = .wide }, - .Nl, - .{ .CharLiteral = .none }, - .Nl, - .{ .CharLiteral = .utf_16 }, - .Nl, - .{ .CharLiteral = .utf_32 }, - .Nl, - .{ .CharLiteral = .wide }, - .Nl, - }); -} - -test "num suffixes" { - try expectTokens( - \\ 1.0f 1.0L 1.0 .0 1. - \\ 0l 0lu 0ll 0llu 0 - \\ 1u 1ul 1ull 1 - \\ 0x 0b - \\ - , &[_]Token.Id{ - .{ .FloatLiteral = .f }, - .{ .FloatLiteral = .l }, - .{ .FloatLiteral = .none }, - .{ .FloatLiteral = .none }, - .{ .FloatLiteral = .none }, - .Nl, - .{ .IntegerLiteral = .l }, - .{ .IntegerLiteral = .lu }, - .{ .IntegerLiteral = .ll }, - .{ .IntegerLiteral = .llu }, - .{ .IntegerLiteral = .none }, - .Nl, - .{ .IntegerLiteral = .u }, - .{ .IntegerLiteral = .lu }, - .{ .IntegerLiteral = .llu }, - .{ .IntegerLiteral = .none }, - .Nl, - .Invalid, - .Invalid, - .Nl, - }); -} - -fn expectTokens(source: []const u8, expected_tokens: []const Token.Id) !void { - var tokenizer = Tokenizer{ - .buffer = source, - }; - for (expected_tokens) |expected_token_id| { - const token = tokenizer.next(); - if (!std.meta.eql(token.id, expected_token_id)) { - std.debug.panic("expected {s}, found {s}\n", .{ @tagName(expected_token_id), @tagName(token.id) }); - } - } - const last_token = tokenizer.next(); - try std.testing.expect(last_token.id == .Eof); -} diff --git a/lib/std/zig/c_translation.zig b/lib/std/zig/c_translation.zig index e9581b9e412113c3ceaf28ec67eeced646c2c6bf..dfa888e94b6f85a5a7885614fcbddd58c181eea4 100644 --- a/lib/std/zig/c_translation.zig +++ b/lib/std/zig/c_translation.zig @@ -252,7 +252,7 @@ test "sizeof" { try testing.expect(sizeof(anyopaque) == 1); } -pub const CIntLiteralBase = enum { decimal, octal, hexadecimal }; +pub const CIntLiteralBase = enum { decimal, octal, hex }; /// Deprecated: use `CIntLiteralBase` pub const CIntLiteralRadix = CIntLiteralBase; @@ -289,13 +289,13 @@ pub fn promoteIntLiteral( } test "promoteIntLiteral" { - const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hexadecimal); + const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hex); try testing.expectEqual(c_uint, @TypeOf(signed_hex)); if (math.maxInt(c_longlong) == math.maxInt(c_int)) return; const signed_decimal = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .decimal); - const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hexadecimal); + const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hex); if (math.maxInt(c_long) > math.maxInt(c_int)) { try testing.expectEqual(c_long, @TypeOf(signed_decimal)); diff --git a/src/Compilation.zig b/src/Compilation.zig index 4917f40b29ce3e59c0432264d177eb454803de86..380e7f7b5701312518919b62ed6045eef184c837 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -4194,7 +4194,7 @@ pub const CImportResult = struct { /// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked /// a bit when we want to start using it from self-hosted. pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { - if (build_options.only_c) unreachable; // @cImport is not needed for bootstrapping + if (build_options.only_core_functionality) @panic("@cImport is not available in a zig2.c build"); const tracy_trace = trace(@src()); defer tracy_trace.end(); diff --git a/src/main.zig b/src/main.zig index 641dd04164adeb8884f56f9bc48877d629dbaca5..c073b1d8e93f01ac8671ba535f7d2628302c6e1a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4286,7 +4286,7 @@ fn updateModule(comp: *Compilation) !void { } fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilation.CImportResult) !void { - if (build_options.only_c) unreachable; // translate-c is not needed for bootstrapping + if (build_options.only_core_functionality) @panic("@translate-c is not available in a zig2.c build"); assert(comp.c_source_files.len == 1); const c_source_file = comp.c_source_files[0]; diff --git a/src/stubs/aro_builtins.zig b/src/stubs/aro_builtins.zig index f6deaef4ad6d5126c13238759d04b79d16439f98..8e643b83070e8b6df132fb90610ba3ab9321d313 100644 --- a/src/stubs/aro_builtins.zig +++ b/src/stubs/aro_builtins.zig @@ -22,7 +22,9 @@ pub fn with(comptime Properties: type) type { return .{}; } pub fn tagFromName(name: []const u8) ?Tag { - return @enumFromInt(name.len); + var res: u16 = 0; + for (name) |c| res +%= c; + return @enumFromInt(res); } pub const NameBuf = struct { pub fn span(_: *const NameBuf) []const u8 { diff --git a/src/translate_c.zig b/src/translate_c.zig index cd8ba8c5fc69f4185953b4224c3d29764f7b183c..a40f788ed6e051af64c8e316eb018352e2ccc69c 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -1,13 +1,13 @@ const std = @import("std"); const testing = std.testing; const assert = std.debug.assert; -const clang = @import("clang.zig"); -const ctok = std.c.tokenizer; -const CToken = std.c.Token; const mem = std.mem; const math = std.math; const meta = std.meta; const CallingConvention = std.builtin.CallingConvention; +const clang = @import("clang.zig"); +const aro = @import("aro"); +const CToken = aro.Tokenizer.Token; const ast = @import("translate_c/ast.zig"); const Node = ast.Node; const Tag = Node.Tag; @@ -190,19 +190,21 @@ pub fn translate( /// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens) /// Macros of this form will not be translated. -fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) bool { - const source = getMacroText(unit, c, macro); - var tokenizer = std.c.Tokenizer{ - .buffer = source, +fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) !bool { + const source = try getMacroText(unit, c, macro); + var tokenizer: aro.Tokenizer = .{ + .buf = source, + .source = .unused, + .langopts = .{}, }; - const name_tok = tokenizer.next(); + const name_tok = tokenizer.nextNoWS(); const name = source[name_tok.start..name_tok.end]; - const first_tok = tokenizer.next(); + const first_tok = tokenizer.nextNoWS(); // We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by // the tokenizer. // In other words we would miss `#define inline inline` (`inline` is a valid c89 identifier) - if (first_tok.id == .Eof) return false; + if (first_tok.id == .eof) return false; return mem.eql(u8, name, source[first_tok.start..first_tok.end]); } @@ -223,7 +225,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void { const raw_name = macro.getName_getNameStart(); const name = try c.str(raw_name); - if (!isSelfDefinedMacro(ast_unit, c, macro)) { + if (!try isSelfDefinedMacro(ast_unit, c, macro)) { try c.global_names.put(c.gpa, name, {}); } }, @@ -5159,16 +5161,16 @@ pub const PatternList = struct { /// Assumes that `ms` represents a tokenized function-like macro. fn buildArgsHash(allocator: mem.Allocator, ms: MacroSlicer, hash: *ArgsPositionMap) MacroProcessingError!void { assert(ms.tokens.len > 2); - assert(ms.tokens[0].id == .Identifier); - assert(ms.tokens[1].id == .LParen); + assert(ms.tokens[0].id == .identifier or ms.tokens[0].id == .extended_identifier); + assert(ms.tokens[1].id == .l_paren); var i: usize = 2; while (true) : (i += 1) { const token = ms.tokens[i]; switch (token.id) { - .RParen => break, - .Comma => continue, - .Identifier => { + .r_paren => break, + .comma => continue, + .identifier, .extended_identifier => { const identifier = ms.slice(token); try hash.put(allocator, identifier, i); }, @@ -5220,18 +5222,18 @@ pub const PatternList = struct { if (args_hash.count() != self.args_hash.count()) return false; var i: usize = 2; - while (self.tokens[i].id != .RParen) : (i += 1) {} + while (self.tokens[i].id != .r_paren) : (i += 1) {} const pattern_slicer = MacroSlicer{ .source = self.source, .tokens = self.tokens }; while (i < self.tokens.len) : (i += 1) { const pattern_token = self.tokens[i]; const macro_token = ms.tokens[i]; - if (meta.activeTag(pattern_token.id) != meta.activeTag(macro_token.id)) return false; + if (pattern_token.id != macro_token.id) return false; const pattern_bytes = pattern_slicer.slice(pattern_token); const macro_bytes = ms.slice(macro_token); switch (pattern_token.id) { - .Identifier => { + .identifier, .extended_identifier => { const pattern_arg_index = self.args_hash.get(pattern_bytes); const macro_arg_index = args_hash.get(macro_bytes); @@ -5243,7 +5245,7 @@ pub const PatternList = struct { return false; } }, - .MacroString, .StringLiteral, .CharLiteral, .IntegerLiteral, .FloatLiteral => { + .string_literal, .char_literal, .pp_num => { if (!mem.eql(u8, pattern_bytes, macro_bytes)) return false; }, else => { @@ -5359,13 +5361,13 @@ const MacroCtx = struct { return self.list[self.i].id; } - fn skip(self: *MacroCtx, c: *Context, expected_id: std.meta.Tag(CToken.Id)) ParseError!void { + fn skip(self: *MacroCtx, c: *Context, expected_id: CToken.Id) ParseError!void { const next_id = self.next().?; - if (next_id != expected_id) { + if (next_id != expected_id and !(expected_id == .identifier and next_id == .extended_identifier)) { try self.fail( c, "unable to translate C expr: expected '{s}' instead got '{s}'", - .{ CToken.Id.symbolName(expected_id), next_id.symbol() }, + .{ expected_id.symbol(), next_id.symbol() }, ); return error.ParseError; } @@ -5396,12 +5398,12 @@ const MacroCtx = struct { while (i < self.list.len) : (i += 1) { const token = self.list[i]; switch (token.id) { - .Period, .Arrow => i += 1, // skip next token since field identifiers can be unknown - .Keyword_struct, .Keyword_union, .Keyword_enum => if (!last_is_type_kw) { + .period, .arrow => i += 1, // skip next token since field identifiers can be unknown + .keyword_struct, .keyword_union, .keyword_enum => if (!last_is_type_kw) { last_is_type_kw = true; continue; }, - .Identifier => { + .identifier, .extended_identifier => { const identifier = slicer.slice(token); const is_param = for (params) |param| { if (param.name != null and mem.eql(u8, identifier, param.name.?)) break true; @@ -5422,31 +5424,38 @@ const MacroCtx = struct { }; fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!void { - var tokenizer = std.c.Tokenizer{ - .buffer = source, + var tokenizer: aro.Tokenizer = .{ + .buf = source, + .source = .unused, + .langopts = .{}, }; while (true) { const tok = tokenizer.next(); switch (tok.id) { - .Nl, .Eof => { + .whitespace => continue, + .nl, .eof => { try tok_list.append(tok); break; }, - .LineComment, .MultiLineComment => continue, else => {}, } try tok_list.append(tok); } } -fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) []const u8 { +fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) ![]const u8 { const begin_loc = macro.getSourceRange_getBegin(); const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit); const begin_c = c.source_manager.getCharacterData(begin_loc); const end_c = c.source_manager.getCharacterData(end_loc); const slice_len = @intFromPtr(end_c) - @intFromPtr(begin_c); - return begin_c[0..slice_len]; + + var comp = aro.Compilation.init(c.gpa); + defer comp.deinit(); + const result = comp.addSourceFromBuffer("", begin_c[0..slice_len]) catch return error.OutOfMemory; + + return c.arena.dupe(u8, result.buf); } fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { @@ -5471,7 +5480,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { continue; } - const source = getMacroText(unit, c, macro); + const source = try getMacroText(unit, c, macro); try tokenizeMacro(source, &tok_list); @@ -5485,7 +5494,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { var macro_fn = false; switch (macro_ctx.peek().?) { - .Identifier => { + .identifier, .extended_identifier => { // if it equals itself, ignore. for example, from stdio.h: // #define stdin stdin const tok = macro_ctx.list[1]; @@ -5494,7 +5503,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { continue; } }, - .Nl, .Eof => { + .nl, .eof => { // this means it is a macro without a value // We define it as an empty string so that it can still be used with ++ const str_node = try Tag.string_literal.create(c.arena, "\"\""); @@ -5503,7 +5512,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { try c.global_scope.blank_macros.put(name, {}); continue; }, - .LParen => { + .l_paren => { // if the name is immediately followed by a '(' then it is a function macro_fn = macro_ctx.list[0].end == macro_ctx.list[1].start; }, @@ -5534,7 +5543,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { // Check if the macro only uses other blank macros. while (true) { switch (m.peek().?) { - .Identifier => { + .identifier, .extended_identifier => { const tok = m.list[m.i + 1]; const slice = m.source[tok.start..tok.end]; if (c.global_scope.blank_macros.contains(slice)) { @@ -5542,7 +5551,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { continue; } }, - .Eof, .Nl => { + .eof, .nl => { try c.global_scope.blank_macros.put(m.name, {}); const init_node = try Tag.string_literal.create(c.arena, "\"\""); const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); @@ -5556,7 +5565,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { const init_node = try parseCExpr(c, m, scope); const last = m.next().?; - if (last != .Eof and last != .Nl) + if (last != .eof and last != .nl) return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()}); const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); @@ -5578,14 +5587,16 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { defer block_scope.deinit(); const scope = &block_scope.base; - try m.skip(c, .LParen); + try m.skip(c, .l_paren); var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa); defer fn_params.deinit(); while (true) { - if (m.peek().? != .Identifier) break; - _ = m.next(); + switch (m.peek().?) { + .identifier, .extended_identifier => _ = m.next(), + else => break, + } const mangled_name = try block_scope.makeMangledName(c, m.slice()); try fn_params.append(.{ @@ -5594,11 +5605,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { .type = Tag.@"anytype".init(), }); try block_scope.discardVariable(c, mangled_name); - if (m.peek().? != .Comma) break; + if (m.peek().? != .comma) break; _ = m.next(); } - try m.skip(c, .RParen); + try m.skip(c, .r_paren); if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) { .undefined_identifier => |ident| return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}), @@ -5607,7 +5618,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { const expr = try parseCExpr(c, m, scope); const last = m.next().?; - if (last != .Eof and last != .Nl) + if (last != .eof and last != .nl) return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()}); const typeof_arg = if (expr.castTag(.block)) |some| blk: { @@ -5644,7 +5655,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { defer block_scope.deinit(); const node = try parseCCondExpr(c, m, &block_scope.base); - if (m.next().? != .Comma) { + if (m.next().? != .comma) { m.i -= 1; return node; } @@ -5656,7 +5667,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { try block_scope.statements.append(ignore); last = try parseCCondExpr(c, m, &block_scope.base); - if (m.next().? != .Comma) { + if (m.next().? != .comma) { m.i -= 1; break; } @@ -5670,118 +5681,135 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { return try block_scope.complete(c); } -fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { - var lit_bytes = m.slice(); +fn parseCNumLit(ctx: *Context, m: *MacroCtx) ParseError!Node { + const lit_bytes = m.slice(); + var bytes = try std.ArrayListUnmanaged(u8).initCapacity(ctx.arena, lit_bytes.len + 3); - switch (m.list[m.i].id) { - .IntegerLiteral => |suffix| { - var base: []const u8 = "decimal"; - if (lit_bytes.len >= 2 and lit_bytes[0] == '0') { - switch (lit_bytes[1]) { - '0'...'7' => { - // Octal - lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes[1..]}); - base = "octal"; - }, - 'X' => { - // Hexadecimal with capital X, valid in C but not in Zig - lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]}); - base = "hexadecimal"; - }, - 'x' => { - base = "hexadecimal"; - }, - else => {}, - } - } - - const type_node = try Tag.type.create(c.arena, switch (suffix) { - .none => "c_int", - .u => "c_uint", - .l => "c_long", - .lu => "c_ulong", - .ll => "c_longlong", - .llu => "c_ulonglong", - .f => unreachable, - }); - lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (suffix) { - .none => @as(u8, 0), - .u, .l => 1, - .lu, .ll => 2, - .llu => 3, - .f => unreachable, - }]; + const prefix = aro.Tree.Token.NumberPrefix.fromString(lit_bytes); + switch (prefix) { + .binary => bytes.appendSliceAssumeCapacity("0b"), + .octal => bytes.appendSliceAssumeCapacity("0o"), + .hex => bytes.appendSliceAssumeCapacity("0x"), + .decimal => {}, + } - const value = std.fmt.parseInt(i128, lit_bytes, 0) catch math.maxInt(i128); + const after_prefix = lit_bytes[prefix.stringLen()..]; + const after_int = for (after_prefix, 0..) |c, i| switch (c) { + '.' => { + if (i == 0) { + bytes.appendAssumeCapacity('0'); + } + break after_prefix[i..]; + }, + 'e', 'E' => { + if (prefix != .hex) break after_prefix[i..]; + bytes.appendAssumeCapacity(c); + }, + 'p', 'P' => break after_prefix[i..], + '0'...'9', 'a'...'d', 'A'...'D', 'f', 'F' => { + if (!prefix.digitAllowed(c)) break after_prefix[i..]; + bytes.appendAssumeCapacity(c); + }, + '\'' => { + bytes.appendAssumeCapacity('_'); + }, + else => break after_prefix[i..], + } else ""; - // make the output less noisy by skipping promoteIntLiteral where - // it's guaranteed to not be required because of C standard type constraints - const guaranteed_to_fit = switch (suffix) { - .none => math.cast(i16, value) != null, - .u => math.cast(u16, value) != null, - .l => math.cast(i32, value) != null, - .lu => math.cast(u32, value) != null, - .ll => math.cast(i64, value) != null, - .llu => math.cast(u64, value) != null, - .f => unreachable, - }; + const after_frac = frac: { + if (after_int.len == 0 or after_int[0] != '.') break :frac after_int; + bytes.appendAssumeCapacity('.'); + for (after_int[1..], 1..) |c, i| { + if (c == '\'') { + bytes.appendAssumeCapacity('_'); + continue; + } + if (!prefix.digitAllowed(c)) break :frac after_int[i..]; + bytes.appendAssumeCapacity(c); + } + break :frac ""; + }; - const literal_node = try transCreateNodeNumber(c, lit_bytes, .int); + const suffix_str = exponent: { + if (after_frac.len == 0) break :exponent after_frac; + switch (after_frac[0]) { + 'e', 'E' => {}, + 'p', 'P' => if (prefix != .hex) break :exponent after_frac, + else => break :exponent after_frac, + } + bytes.appendAssumeCapacity(after_frac[0]); + for (after_frac[1..], 1..) |c, i| switch (c) { + '+', '-', '0'...'9' => { + bytes.appendAssumeCapacity(c); + }, + '\'' => { + bytes.appendAssumeCapacity('_'); + }, + else => break :exponent after_frac[i..], + }; + break :exponent ""; + }; - if (guaranteed_to_fit) { - return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = literal_node }); - } else { - return Tag.helpers_promoteIntLiteral.create(c.arena, .{ - .type = type_node, - .value = literal_node, - .base = try Tag.enum_literal.create(c.arena, base), - }); - } - }, - .FloatLiteral => |suffix| { - if (suffix != .none) lit_bytes = lit_bytes[0 .. lit_bytes.len - 1]; + const is_float = after_int.len != suffix_str.len; + const suffix = aro.Tree.Token.NumberSuffix.fromString(suffix_str, if (is_float) .float else .int) orelse { + try m.fail(ctx, "invalid number suffix: '{s}'", .{suffix_str}); + return error.ParseError; + }; + if (suffix.isImaginary()) { + try m.fail(ctx, "TODO: imaginary literals", .{}); + return error.ParseError; + } + if (suffix.isBitInt()) { + try m.fail(ctx, "TODO: _BitInt literals", .{}); + return error.ParseError; + } - if (lit_bytes.len >= 2 and std.ascii.eqlIgnoreCase(lit_bytes[0..2], "0x")) { - if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| { - if (dot_index == 2) { - lit_bytes = try std.fmt.allocPrint(c.arena, "0x0{s}", .{lit_bytes[2..]}); - } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isHex(lit_bytes[dot_index + 1])) { - // If the literal lacks a digit after the `.`, we need to - // add one since `0x1.p10` would be invalid syntax in Zig. - lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}0{s}", .{ - lit_bytes[2 .. dot_index + 1], - lit_bytes[dot_index + 1 ..], - }); - } - } + if (is_float) { + const type_node = try Tag.type.create(ctx.arena, switch (suffix) { + .F16 => "f16", + .F => "f32", + .None => "f64", + .L => "c_longdouble", + .W => "f80", + .Q, .F128 => "f128", + else => unreachable, + }); + const rhs = try Tag.float_literal.create(ctx.arena, bytes.items); + return Tag.as.create(ctx.arena, .{ .lhs = type_node, .rhs = rhs }); + } else { + const type_node = try Tag.type.create(ctx.arena, switch (suffix) { + .None => "c_int", + .U => "c_uint", + .L => "c_long", + .UL => "c_ulong", + .LL => "c_longlong", + .ULL => "c_ulonglong", + else => unreachable, + }); + const value = std.fmt.parseInt(i128, bytes.items, 0) catch math.maxInt(i128); - if (lit_bytes[1] == 'X') { - // Hexadecimal with capital X, valid in C but not in Zig - lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]}); - } - } else if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| { - if (dot_index == 0) { - lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes}); - } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isDigit(lit_bytes[dot_index + 1])) { - // If the literal lacks a digit after the `.`, we need to - // add one since `1.` or `1.e10` would be invalid syntax in Zig. - lit_bytes = try std.fmt.allocPrint(c.arena, "{s}0{s}", .{ - lit_bytes[0 .. dot_index + 1], - lit_bytes[dot_index + 1 ..], - }); - } - } + // make the output less noisy by skipping promoteIntLiteral where + // it's guaranteed to not be required because of C standard type constraints + const guaranteed_to_fit = switch (suffix) { + .None => math.cast(i16, value) != null, + .U => math.cast(u16, value) != null, + .L => math.cast(i32, value) != null, + .UL => math.cast(u32, value) != null, + .LL => math.cast(i64, value) != null, + .ULL => math.cast(u64, value) != null, + else => unreachable, + }; - const type_node = try Tag.type.create(c.arena, switch (suffix) { - .f => "f32", - .none => "f64", - .l => "c_longdouble", - else => unreachable, + const literal_node = try Tag.integer_literal.create(ctx.arena, bytes.items); + if (guaranteed_to_fit) { + return Tag.as.create(ctx.arena, .{ .lhs = type_node, .rhs = literal_node }); + } else { + return Tag.helpers_promoteIntLiteral.create(ctx.arena, .{ + .type = type_node, + .value = literal_node, + .base = try Tag.enum_literal.create(ctx.arena, @tagName(prefix)), }); - const rhs = try transCreateNodeNumber(c, lit_bytes, .float); - return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs }); - }, - else => unreachable, + } } } @@ -5800,17 +5828,17 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { } else return source; var bytes = try ctx.arena.alloc(u8, source.len * 2); var state: enum { - Start, - Escape, - Hex, - Octal, - } = .Start; + start, + escape, + hex, + octal, + } = .start; var i: usize = 0; var count: u8 = 0; var num: u8 = 0; for (source) |c| { switch (state) { - .Escape => { + .escape => { switch (c) { 'n', 'r', 't', '\\', '\'', '\"' => { bytes[i] = c; @@ -5818,11 +5846,11 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { '0'...'7' => { count += 1; num += c - '0'; - state = .Octal; + state = .octal; bytes[i] = 'x'; }, 'x' => { - state = .Hex; + state = .hex; bytes[i] = 'x'; }, 'a' => { @@ -5867,10 +5895,10 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { }, } i += 1; - if (state == .Escape) - state = .Start; + if (state == .escape) + state = .start; }, - .Start => { + .start => { if (c == '\t') { bytes[i] = '\\'; i += 1; @@ -5879,12 +5907,12 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { continue; } if (c == '\\') { - state = .Escape; + state = .escape; } bytes[i] = c; i += 1; }, - .Hex => { + .hex => { switch (c) { '0'...'9' => { num = std.math.mul(u8, num, 16) catch { @@ -5911,15 +5939,15 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); num = 0; if (c == '\\') - state = .Escape + state = .escape else - state = .Start; + state = .start; bytes[i] = c; i += 1; }, } }, - .Octal => { + .octal => { const accept_digit = switch (c) { // The maximum length of a octal literal is 3 digits '0'...'7' => count < 3, @@ -5938,16 +5966,16 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { num = 0; count = 0; if (c == '\\') - state = .Escape + state = .escape else - state = .Start; + state = .start; bytes[i] = c; i += 1; } }, } } - if (state == .Hex or state == .Octal) + if (state == .hex or state == .octal) i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); return bytes[0..i]; } @@ -5972,7 +6000,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N const tok = m.next().?; const slice = m.slice(); switch (tok) { - .CharLiteral => { + .char_literal, + .char_literal_utf_8, + .char_literal_utf_16, + .char_literal_utf_32, + .char_literal_wide, + => { if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) { return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m)); } else { @@ -5980,13 +6013,18 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N return Tag.integer_literal.create(c.arena, str); } }, - .StringLiteral => { + .string_literal, + .string_literal_utf_16, + .string_literal_utf_8, + .string_literal_utf_32, + .string_literal_wide, + => { return Tag.string_literal.create(c.arena, try escapeUnprintables(c, m)); }, - .IntegerLiteral, .FloatLiteral => { + .pp_num => { return parseCNumLit(c, m); }, - .Identifier => { + .identifier, .extended_identifier => { if (c.global_scope.blank_macros.contains(slice)) { return parseCPrimaryExprInner(c, m, scope); } @@ -5996,10 +6034,10 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N scope.skipVariableDiscard(identifier.castTag(.identifier).?.data); return identifier; }, - .LParen => { + .l_paren => { const inner_node = try parseCExpr(c, m, scope); - try m.skip(c, .RParen); + try m.skip(c, .r_paren); return inner_node; }, else => { @@ -6022,8 +6060,13 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { // after a primary expression. while (true) { switch (m.peek().?) { - .StringLiteral => {}, - .Identifier => { + .string_literal, + .string_literal_utf_16, + .string_literal_utf_8, + .string_literal_utf_32, + .string_literal_wide, + => {}, + .identifier, .extended_identifier => { const tok = m.list[m.i + 1]; const slice = m.source[tok.start..tok.end]; if (c.global_scope.blank_macros.contains(slice)) { @@ -6057,20 +6100,20 @@ fn macroIntToBool(c: *Context, node: Node) !Node { fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { const node = try parseCOrExpr(c, m, scope); - if (m.peek().? != .QuestionMark) { + if (m.peek().? != .question_mark) { return node; } _ = m.next(); const then_body = try parseCOrExpr(c, m, scope); - try m.skip(c, .Colon); + try m.skip(c, .colon); const else_body = try parseCCondExpr(c, m, scope); return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body }); } fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var node = try parseCAndExpr(c, m, scope); - while (m.next().? == .PipePipe) { + while (m.next().? == .pipe_pipe) { const lhs = try macroIntToBool(c, node); const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope)); node = try Tag.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs }); @@ -6081,7 +6124,7 @@ fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var node = try parseCBitOrExpr(c, m, scope); - while (m.next().? == .AmpersandAmpersand) { + while (m.next().? == .ampersand_ampersand) { const lhs = try macroIntToBool(c, node); const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope)); node = try Tag.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs }); @@ -6092,7 +6135,7 @@ fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var node = try parseCBitXorExpr(c, m, scope); - while (m.next().? == .Pipe) { + while (m.next().? == .pipe) { const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCBitXorExpr(c, m, scope)); node = try Tag.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); @@ -6103,7 +6146,7 @@ fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var node = try parseCBitAndExpr(c, m, scope); - while (m.next().? == .Caret) { + while (m.next().? == .caret) { const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCBitAndExpr(c, m, scope)); node = try Tag.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); @@ -6114,7 +6157,7 @@ fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var node = try parseCEqExpr(c, m, scope); - while (m.next().? == .Ampersand) { + while (m.next().? == .ampersand) { const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCEqExpr(c, m, scope)); node = try Tag.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); @@ -6127,13 +6170,13 @@ fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var node = try parseCRelExpr(c, m, scope); while (true) { switch (m.peek().?) { - .BangEqual => { + .bang_equal => { _ = m.next(); const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope)); node = try Tag.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, - .EqualEqual => { + .equal_equal => { _ = m.next(); const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope)); @@ -6148,25 +6191,25 @@ fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var node = try parseCShiftExpr(c, m, scope); while (true) { switch (m.peek().?) { - .AngleBracketRight => { + .angle_bracket_right => { _ = m.next(); const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope)); node = try Tag.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, - .AngleBracketRightEqual => { + .angle_bracket_right_equal => { _ = m.next(); const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope)); node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, - .AngleBracketLeft => { + .angle_bracket_left => { _ = m.next(); const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope)); node = try Tag.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, - .AngleBracketLeftEqual => { + .angle_bracket_left_equal => { _ = m.next(); const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope)); @@ -6181,13 +6224,13 @@ fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var node = try parseCAddSubExpr(c, m, scope); while (true) { switch (m.peek().?) { - .AngleBracketAngleBracketLeft => { + .angle_bracket_angle_bracket_left => { _ = m.next(); const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope)); node = try Tag.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, - .AngleBracketAngleBracketRight => { + .angle_bracket_angle_bracket_right => { _ = m.next(); const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope)); @@ -6202,13 +6245,13 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var node = try parseCMulExpr(c, m, scope); while (true) { switch (m.peek().?) { - .Plus => { + .plus => { _ = m.next(); const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope)); node = try Tag.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, - .Minus => { + .minus => { _ = m.next(); const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope)); @@ -6223,17 +6266,17 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var node = try parseCCastExpr(c, m, scope); while (true) { switch (m.next().?) { - .Asterisk => { + .asterisk => { const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope)); node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, - .Slash => { + .slash => { const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope)); node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .div, .lhs = lhs, .rhs = rhs }); }, - .Percent => { + .percent => { const lhs = try macroIntFromBool(c, node); const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope)); node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .rem, .lhs = lhs, .rhs = rhs }); @@ -6248,17 +6291,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { switch (m.next().?) { - .LParen => { + .l_paren => { if (try parseCTypeName(c, m, scope, true)) |type_name| { while (true) { const next_token = m.next().?; switch (next_token) { - .RParen => break, + .r_paren => break, else => |next_tag| { // Skip trailing blank defined before the RParen. - if (next_tag == .Identifier and c.global_scope.blank_macros.contains(m.slice())) { + if ((next_tag == .identifier or next_tag == .extended_identifier) and + c.global_scope.blank_macros.contains(m.slice())) continue; - } + try m.fail( c, "unable to translate C expr: expected ')' instead got '{s}'", @@ -6268,7 +6312,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { }, } } - if (m.peek().? == .LBrace) { + if (m.peek().? == .l_brace) { // initializer list return parseCPostfixExpr(c, m, scope, type_name); } @@ -6294,7 +6338,7 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node { const tok = m.next().?; switch (tok) { - .Identifier => { + .identifier, .extended_identifier => { if (c.global_scope.blank_macros.contains(m.slice())) { return try parseCSpecifierQualifierList(c, m, scope, allow_fail); } @@ -6304,25 +6348,25 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_ return try Tag.identifier.create(c.arena, mangled_name); } }, - .Keyword_void => return try Tag.type.create(c.arena, "anyopaque"), - .Keyword_bool => return try Tag.type.create(c.arena, "bool"), - .Keyword_char, - .Keyword_int, - .Keyword_short, - .Keyword_long, - .Keyword_float, - .Keyword_double, - .Keyword_signed, - .Keyword_unsigned, - .Keyword_complex, + .keyword_void => return try Tag.type.create(c.arena, "anyopaque"), + .keyword_bool => return try Tag.type.create(c.arena, "bool"), + .keyword_char, + .keyword_int, + .keyword_short, + .keyword_long, + .keyword_float, + .keyword_double, + .keyword_signed, + .keyword_unsigned, + .keyword_complex, => { m.i -= 1; return try parseCNumericType(c, m); }, - .Keyword_enum, .Keyword_struct, .Keyword_union => { + .keyword_enum, .keyword_struct, .keyword_union => { // struct Foo will be declared as struct_Foo by transRecordDecl const slice = m.slice(); - try m.skip(c, .Identifier); + try m.skip(c, .identifier); const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() }); return try Tag.identifier.create(c.arena, name); @@ -6364,15 +6408,15 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node { var i: u8 = 0; while (i < math.maxInt(u8)) : (i += 1) { switch (m.next().?) { - .Keyword_double => kw.double += 1, - .Keyword_long => kw.long += 1, - .Keyword_int => kw.int += 1, - .Keyword_float => kw.float += 1, - .Keyword_short => kw.short += 1, - .Keyword_char => kw.char += 1, - .Keyword_unsigned => kw.unsigned += 1, - .Keyword_signed => kw.signed += 1, - .Keyword_complex => kw.complex += 1, + .keyword_double => kw.double += 1, + .keyword_long => kw.long += 1, + .keyword_int => kw.int += 1, + .keyword_float => kw.float += 1, + .keyword_short => kw.short += 1, + .keyword_char => kw.char += 1, + .keyword_unsigned => kw.unsigned += 1, + .keyword_signed => kw.signed += 1, + .keyword_complex => kw.complex += 1, else => { m.i -= 1; break; @@ -6442,11 +6486,11 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node { fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, node: Node) ParseError!Node { switch (m.next().?) { - .Asterisk => { + .asterisk => { // last token of `node` const prev_id = m.list[m.i - 1].id; - if (prev_id == .Keyword_void) { + if (prev_id == .keyword_void) { const ptr = try Tag.single_pointer.create(c.arena, .{ .is_const = false, .is_volatile = false, @@ -6472,28 +6516,28 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) var node = type_name orelse try parseCPrimaryExpr(c, m, scope); while (true) { switch (m.next().?) { - .Period => { - try m.skip(c, .Identifier); + .period => { + try m.skip(c, .identifier); node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() }); }, - .Arrow => { - try m.skip(c, .Identifier); + .arrow => { + try m.skip(c, .identifier); const deref = try Tag.deref.create(c.arena, node); node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() }); }, - .LBracket => { + .l_bracket => { const index_val = try macroIntFromBool(c, try parseCExpr(c, m, scope)); const index = try Tag.as.create(c.arena, .{ .lhs = try Tag.type.create(c.arena, "usize"), .rhs = try Tag.int_cast.create(c.arena, index_val), }); node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index }); - try m.skip(c, .RBracket); + try m.skip(c, .r_bracket); }, - .LParen => { - if (m.peek().? == .RParen) { + .l_paren => { + if (m.peek().? == .r_paren) { m.i += 1; node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &[0]Node{} }); } else { @@ -6504,8 +6548,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) try args.append(arg); const next_id = m.next().?; switch (next_id) { - .Comma => {}, - .RParen => break, + .comma => {}, + .r_paren => break, else => { try m.fail(c, "unable to translate C expr: expected ',' or ')' instead got '{s}'", .{next_id.symbol()}); return error.ParseError; @@ -6515,24 +6559,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) }); } }, - .LBrace => { + .l_brace => { // Check for designated field initializers - if (m.peek().? == .Period) { + if (m.peek().? == .period) { var init_vals = std.ArrayList(ast.Payload.ContainerInitDot.Initializer).init(c.gpa); defer init_vals.deinit(); while (true) { - try m.skip(c, .Period); - try m.skip(c, .Identifier); + try m.skip(c, .period); + try m.skip(c, .identifier); const name = m.slice(); - try m.skip(c, .Equal); + try m.skip(c, .equal); const val = try parseCCondExpr(c, m, scope); try init_vals.append(.{ .name = name, .value = val }); const next_id = m.next().?; switch (next_id) { - .Comma => {}, - .RBrace => break, + .comma => {}, + .r_brace => break, else => { try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()}); return error.ParseError; @@ -6552,8 +6596,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) try init_vals.append(val); const next_id = m.next().?; switch (next_id) { - .Comma => {}, - .RBrace => break, + .comma => {}, + .r_brace => break, else => { try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()}); return error.ParseError; @@ -6563,7 +6607,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items)); node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node }); }, - .PlusPlus, .MinusMinus => { + .plus_plus, .minus_minus => { try m.fail(c, "TODO postfix inc/dec expr", .{}); return error.ParseError; }, @@ -6577,47 +6621,47 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { switch (m.next().?) { - .Bang => { + .bang => { const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope)); return Tag.not.create(c.arena, operand); }, - .Minus => { + .minus => { const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope)); return Tag.negate.create(c.arena, operand); }, - .Plus => return try parseCCastExpr(c, m, scope), - .Tilde => { + .plus => return try parseCCastExpr(c, m, scope), + .tilde => { const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope)); return Tag.bit_not.create(c.arena, operand); }, - .Asterisk => { + .asterisk => { const operand = try parseCCastExpr(c, m, scope); return Tag.deref.create(c.arena, operand); }, - .Ampersand => { + .ampersand => { const operand = try parseCCastExpr(c, m, scope); return Tag.address_of.create(c.arena, operand); }, - .Keyword_sizeof => { - const operand = if (m.peek().? == .LParen) blk: { + .keyword_sizeof => { + const operand = if (m.peek().? == .l_paren) blk: { _ = m.next(); const inner = (try parseCTypeName(c, m, scope, false)).?; - try m.skip(c, .RParen); + try m.skip(c, .r_paren); break :blk inner; } else try parseCUnaryExpr(c, m, scope); return Tag.helpers_sizeof.create(c.arena, operand); }, - .Keyword_alignof => { + .keyword_alignof => { // TODO this won't work if using 's // #define alignof _Alignof - try m.skip(c, .LParen); + try m.skip(c, .l_paren); const operand = (try parseCTypeName(c, m, scope, false)).?; - try m.skip(c, .RParen); + try m.skip(c, .r_paren); return Tag.alignof.create(c.arena, operand); }, - .PlusPlus, .MinusMinus => { + .plus_plus, .minus_minus => { try m.fail(c, "TODO unary inc/dec expr", .{}); return error.ParseError; }, diff --git a/test/translate_c.zig b/test/translate_c.zig index a8045cbf1fe41bb72836d1596728de27ae5d4570..2b87da4067555f19f785c96643398838d4959d41 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -424,7 +424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ }); \\} , - \\pub const B = A(@as(f32, 0.0)); + \\pub const B = A(@as(f32, 0)); }); cases.add("complex switch", @@ -633,7 +633,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("#define hex literal with capital X", \\#define VAL 0XF00D , &[_][]const u8{ - \\pub const VAL = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF00D, .hexadecimal); + \\pub const VAL = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF00D, .hex); }); cases.add("anonymous struct & unions", @@ -1243,12 +1243,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l; , &([_][]const u8{ "pub const foo = @as(f32, 3.14);", - "pub const bar = @as(c_longdouble, 16.0e-2);", + "pub const bar = @as(c_longdouble, 16.e-2);", "pub const FOO = @as(f64, 0.12345);", "pub const BAR = @as(f64, 0.12345);", "pub const baz = @as(f64, 1e1);", "pub const BAZ = @as(f32, 42e-3);", - "pub const foobar = -@as(c_longdouble, 73.0);", + "pub const foobar = -@as(c_longdouble, 73);", "pub export const my_float: f32 = 1.0;", "pub export const my_double: f64 = 1.0;", "pub export const my_longdouble: c_longdouble = 1.0;", @@ -1272,7 +1272,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { "pub const BAR = -@as(f32, 0x8F.BP5);", "pub const FOOBAR = @as(f64, 0x0P+0);", "pub const BAZ = -@as(f64, 0x0.0a5dp+12);", - "pub const FOOBAZ = @as(c_longdouble, 0xfE.0P-1);", + "pub const FOOBAZ = @as(c_longdouble, 0xfE.P-1);", }); cases.add("comments", @@ -3730,7 +3730,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , &[_][]const u8{ \\pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0)); , - \\pub const FOO = @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hexadecimal)); + \\pub const FOO = @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hex)); }); if (builtin.abi == .msvc) { @@ -3812,7 +3812,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const MAY_NEED_PROMOTION_1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 10241024, .decimal); \\pub const MAY_NEED_PROMOTION_2 = @import("std").zig.c_translation.promoteIntLiteral(c_long, 307230723072, .decimal); \\pub const MAY_NEED_PROMOTION_3 = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 819281928192, .decimal); - \\pub const MAY_NEED_PROMOTION_HEX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000000, .hexadecimal); + \\pub const MAY_NEED_PROMOTION_HEX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000000, .hex); \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal); }); -- 2.54.0