Code Monkey home page Code Monkey logo

arocc's People

Contributors

andrewrk avatar bingcicle avatar danielsan901998 avatar doppioandante avatar ehaas avatar f-cozzocrea avatar happyfacade avatar iddev5 avatar marler8997 avatar misilelab avatar mlugg avatar moosichu avatar rexicon226 avatar sagehane avatar squeek502 avatar twoclocks avatar vexu avatar wrongnull avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arocc's Issues

Unreachable code when preprocessor invokes parser with undefined division argument

(clang errors with error: division by zero in preprocessor expression for this snippet)

#if 1/q
#endif
thread 18069770 panic: reached unreachable code
/Users/ehaas/source/zig/build/lib/zig/std/debug.zig:226:14: 0x104f172f8 in std.debug.assert (arocc)
    if (!ok) unreachable; // assertion failure
             ^
/Users/ehaas/source/arocc/src/Parser.zig:3631:15: 0x104fe0607 in Parser.Result.saveValue (arocc)
        assert(!p.in_macro);
              ^
/Users/ehaas/source/arocc/src/Parser.zig:3625:24: 0x1050419ae in Parser.Result.shouldEval (arocc)
        try a.saveValue(p);
                       ^
/Users/ehaas/source/arocc/src/Parser.zig:3362:32: 0x105009235 in Parser.Result.adjustTypes (arocc)
            return a.shouldEval(b, p);
                               ^
/Users/ehaas/source/arocc/src/Parser.zig:4238:32: 0x105078204 in Parser.mulExpr (arocc)
        if (try lhs.adjustTypes(percent.?, &rhs, p, if (tag == .mod_expr) .integer else .arithmetic)) {
                               ^
/Users/ehaas/source/arocc/src/Parser.zig:4196:28: 0x105077734 in Parser.addExpr (arocc)
    var lhs = try p.mulExpr();
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4164:28: 0x105076cc4 in Parser.shiftExpr (arocc)
    var lhs = try p.addExpr();
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4135:30: 0x105076374 in Parser.compExpr (arocc)
    var lhs = try p.shiftExpr();
                             ^
/Users/ehaas/source/arocc/src/Parser.zig:4110:29: 0x1050758f4 in Parser.eqExpr (arocc)
    var lhs = try p.compExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:4090:27: 0x1050739d4 in Parser.andExpr (arocc)
    var lhs = try p.eqExpr();
                          ^
/Users/ehaas/source/arocc/src/Parser.zig:4070:28: 0x10506c7c4 in Parser.xorExpr (arocc)
    var lhs = try p.andExpr();
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4050:28: 0x10505ff34 in Parser.orExpr (arocc)
    var lhs = try p.xorExpr();
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4028:27: 0x105040744 in Parser.landExpr (arocc)
    var lhs = try p.orExpr();
                          ^
/Users/ehaas/source/arocc/src/Parser.zig:4006:29: 0x1050085b4 in Parser.lorExpr (arocc)
    var lhs = try p.landExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:3968:29: 0x104fd6dd4 in Parser.condExpr (arocc)
    var cond = try p.lorExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:3199:27: 0x104f7dc4e in Parser.macroExpr (arocc)
    const res = p.condExpr() catch |e| switch (e) {
                          ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:465:28: 0x104f4e192 in Preprocessor.expr (arocc)
    return parser.macroExpr();
                           ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:181:40: 0x104f428b9 in Preprocessor.preprocess (arocc)
                        if (try pp.expr(&tokenizer)) {
                                       ^
/Users/ehaas/source/arocc/src/main.zig:237:22: 0x104f27818 in processSource (arocc)
    try pp.preprocess(source);
                     ^
/Users/ehaas/source/arocc/src/main.zig:223:22: 0x104f1c151 in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:41:15: 0x104f192dd in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x104f96b0c in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x104f1d257 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x104f1d195 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x1 in ??? (???)
[1]    71375 abort      ~/source/arocc/zig-out/bin/arocc test.c

Validate attribute context in `decl()` after parsing

decl() allows any leading attribute since we don't know if we're parsing a function or variable declaration. Once we know what we've parsed we should retroactively validate those attributes for the relevant context.

Preprocessor: Token pasting in function-like macro with no LHS causes crash

#define bar(a) ## i
thread 14036537 panic: integer overflow
/Users/ehaas/source/arocc/src/Preprocessor.zig:1253:63: 0x1013ad8e6 in Preprocessor.defineFn (arocc)
                if (pp.token_buf.items[pp.token_buf.items.len - 1].id == .macro_param) {
                                                              ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:1143:53: 0x10137d24b in Preprocessor.define (arocc)
        if (first.id == .l_paren) return pp.defineFn(tokenizer, macro_name, first);
                                                    ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:264:53: 0x101371576 in Preprocessor.preprocess (arocc)
                    .keyword_define => try pp.define(&tokenizer),
                                                    ^
/Users/ehaas/source/arocc/src/main.zig:237:22: 0x1013557a8 in processSource (arocc)
    try pp.preprocess(source);
                     ^
/Users/ehaas/source/arocc/src/main.zig:223:22: 0x10134a161 in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:41:15: 0x1013472ed in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x1013c4d7c in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x10134b267 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x10134b1a5 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x1 in ??? (???)
[1]    19263 abort      ./zig-out/bin/arocc test/cases/tokenpaste.c

Turning off `unknown-warning-option` after using an unknown warning causes unreachable code to be reached

To reproduce compile any file with -Wfoo -Wno-unknown-warning-option in that order. Switching the order results in expected behavior.

➜  ~ ~/source/arocc/zig-out/bin/arocc -Wfoo -Wno-unknown-warning-option test.c
thread 1633389 panic: reached unreachable code
/Users/ehaas/source/arocc/src/Diagnostics.zig:372:21: 0x103804142 in Diagnostics.renderExtra (arocc)
            .off => unreachable,
                    ^
/Users/ehaas/source/arocc/src/Diagnostics.zig:360:16: 0x1037ce427 in Diagnostics.render (arocc)
    renderExtra(comp, &m);
               ^
/Users/ehaas/source/arocc/src/main.zig:259:22: 0x1037ddd7e in processSource (arocc)
    comp.renderErrors();
                     ^
/Users/ehaas/source/arocc/src/main.zig:216:22: 0x1037d2e3e in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:34:15: 0x1037d0554 in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x103846dcc in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x1037d40e7 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x1037d4025 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x3 in ??? (???)
[1]    39972 abort      ~/source/arocc/zig-out/bin/arocc -Wfoo -Wno-unknown-warning-option test.c

Comparing unsigned constants results in access of inactive union field

int foo(void) {
    return 1U < 2U;
}
thread 10956225 panic: access of inactive union field
/Users/ehaas/source/arocc/src/Parser.zig:2674:68: 0x10d0b9670 in Parser.Result.compare (arocc)
            .signed => |val| return std.math.compare(val, op, b.val.signed),
                                                                   ^
/Users/ehaas/source/arocc/src/Parser.zig:3115:47: 0x10d125d6e in Parser.compExpr (arocc)
                .less_than_expr => lhs.compare(.lt, rhs),
                                              ^
/Users/ehaas/source/arocc/src/Parser.zig:3077:29: 0x10d123f54 in Parser.eqExpr (arocc)
    var lhs = try p.compExpr();
...

Null pointer dereference if no semicolon after old-style function decl

(This is invalid syntax but it crashes the parser):

foo(X)
➜  ~ ./source/arocc/zig-out/bin/arocc test.c
thread 930248 panic: attempt to use null value
/Users/ehaas/source/arocc/src/Parser.zig:662:70: 0x10b39fb9f in Parser.decl (arocc)
            .data = .{ .decl = .{ .name = init_d.d.name, .node = body.? } },
                                                                     ^
/Users/ehaas/source/arocc/src/Parser.zig:436:19: 0x10b38bc56 in Parser.parse (arocc)
        if (p.decl() catch |er| switch (er) {
                  ^
/Users/ehaas/source/arocc/src/main.zig:249:32: 0x10b36ec45 in processSource (arocc)
    var tree = try Parser.parse(&pp);
                               ^
/Users/ehaas/source/arocc/src/main.zig:216:22: 0x10b363e3e in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:34:15: 0x10b361554 in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x10b3d7d3c in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x10b3650e7 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x10b365025 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x1 in ??? (???)
[1]    75758 abort      ./source/arocc/zig-out/bin/arocc test.c

Have test runner check for leaks caused by `error.OutOfMemory`

The Zig parser test uses a clever technique to check for correct memory handling during error conditions. Parse once using unlimited memory, measure how much was actually used, then parse again N times using FailingAllocator, once for each size up to the actual amount of memory used. Each of those should fail (if not, memory usage is unexpectedly non-deterministic) and should free the same number of bytes as were allocated.

Spurious warning when assignment increases qualifiers

I believe this is the opposite of #25

void foo(void) {
   char *bar = 0;
   const char *baz = bar;
}
/Users/ehaas/source/c/test.c:3:22: warning: initializing 'const char *' from incompatible type 'char *' discards qualifiers
   const char *baz = bar;
                     ^
1 warning generated.
fn_def: 'fn () void'
 name: foo
 body:
  compound_stmt: 'void'
    var: '*char'
     name: bar
     init:
      null_to_pointer: '*char'
        int_literal: 'int'
         value: 0

    var: '*const char'
     name: baz
     init:
      lval_to_rval: '*char'
        decl_ref_expr: '*char' lvalue
         name: bar

    implicit_return: 'void'

Preprocessor memory leak - unterminated function-like macro invocation

This only manifests on Linux, I wasn't able to reproduce it on MacOS. Zig version 0.9.0-dev.1561+5ebdc8c46

#define foo(X) X
foo(1,
root@006bbb66b04e:/arocc# ./zig-out/bin/arocc -E test/cases/leak.c
test/cases/leak.c:2:1: error: unterminated function macro argument list
foo(1,
^
1 error generated.
foo ( 1 ,
error(gpa): memory address 0x7fd5a77e0380 leaked:
/zig-linux-x86_64-0.9.0-dev.1561+5ebdc8c46/lib/std/array_list.zig:340:69: 0x349579 in std.array_list.ArrayListAligned([]const Tree.Token,null).ensureTotalCapacityPrecise (arocc)
                const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), new_capacity);
                                                                    ^
/zig-linux-x86_64-0.9.0-dev.1561+5ebdc8c46/lib/std/array_list.zig:325:55: 0x27babe in std.array_list.ArrayListAligned([]const Tree.Token,null).ensureTotalCapacity (arocc)
                return self.ensureTotalCapacityPrecise(better_capacity);
                                                      ^
/zig-linux-x86_64-0.9.0-dev.1561+5ebdc8c46/lib/std/array_list.zig:364:41: 0x376b78 in std.array_list.ArrayListAligned([]const Tree.Token,null).addOne (arocc)
            try self.ensureTotalCapacity(newlen);
                                        ^
/zig-linux-x86_64-0.9.0-dev.1561+5ebdc8c46/lib/std/array_list.zig:175:49: 0x3491c6 in std.array_list.ArrayListAligned([]const Tree.Token,null).append (arocc)
            const new_item_ptr = try self.addOne();
                                                ^


error(gpa): memory address 0x7fd5a77e2500 leaked:
/zig-linux-x86_64-0.9.0-dev.1561+5ebdc8c46/lib/std/array_list.zig:340:69: 0x321489 in std.array_list.ArrayListAligned(Tree.Token,null).ensureTotalCapacityPrecise (arocc)
                const new_memory = try self.allocator.reallocAtLeast(self.allocatedSlice(), new_capacity);
                                                                    ^
/zig-linux-x86_64-0.9.0-dev.1561+5ebdc8c46/lib/std/array_list.zig:325:55: 0x27bbde in std.array_list.ArrayListAligned(Tree.Token,null).ensureTotalCapacity (arocc)
                return self.ensureTotalCapacityPrecise(better_capacity);
                                                      ^
/zig-linux-x86_64-0.9.0-dev.1561+5ebdc8c46/lib/std/array_list.zig:364:41: 0x321328 in std.array_list.ArrayListAligned(Tree.Token,null).addOne (arocc)
            try self.ensureTotalCapacity(newlen);
                                        ^
/zig-linux-x86_64-0.9.0-dev.1561+5ebdc8c46/lib/std/array_list.zig:175:49: 0x2fa4c6 in std.array_list.ArrayListAligned(Tree.Token,null).append (arocc)
            const new_item_ptr = try self.addOne();
                                                ^

Parser: Initializing incomplete array with non-array accesses inactive field of union

int x;
int j[] = x;
➜  ~/source/arocc/zig-out/bin/arocc test.c
thread 18204944 panic: access of inactive union field
/Users/ehaas/source/arocc/src/Parser.zig:1210:64: 0x10671f5cb in Parser.initDeclarator (arocc)
            init_d.d.ty.data.array.len = init_list_expr.ty.data.array.len;
                                                               ^
/Users/ehaas/source/arocc/src/Parser.zig:585:39: 0x1066ed429 in Parser.decl (arocc)
    var init_d = (try p.initDeclarator(&decl_spec)) orelse {
                                      ^
/Users/ehaas/source/arocc/src/Parser.zig:462:19: 0x1066d922a in Parser.parse (arocc)
        if (p.decl() catch |er| switch (er) {
                  ^
/Users/ehaas/source/arocc/src/main.zig:257:32: 0x1066bbbb9 in processSource (arocc)
    var tree = try Parser.parse(&pp);
                               ^
/Users/ehaas/source/arocc/src/main.zig:223:22: 0x1066b0151 in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:41:15: 0x1066ad2dd in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x10672ab0c in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x1066b1257 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x1066b1195 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x1 in ??? (???)
[1]    79148 abort      ~/source/arocc/zig-out/bin/arocc test.c

arocc doesn't follow subtle rules in preprocessing expansion

Hello, I'm opening this issue mostly to clear up my understanding of these issues. Consider

#define f(a) a
#define z z[0]

f(f(z))

with gcc -E this expands to z[0]. With #29 , this expands to z[0][0][0].
From the current C standard draft, 6.10.3.4 (Rescanning and further replacement)

If the name of the macro being replaced is found during this scan of the replacement list (not
including the rest of the source file’s preprocessing tokens), it is not replaced. Furthermore, if any
nested replacements encounter the name of the macro being replaced, it is not replaced. These
nonreplaced macro name preprocessing tokens are no longer available for further replacement even
if they are later (re)examined in contexts in which that macro name preprocessing token would
otherwise have been replaced.

I guess the last sentence is what makes the difference in this case.
I would like to try to fix this myself.

Unary operator in `#if` causes index out of bounds in Tree.isLvalExtra

The following C code crashes the preprocessor:

#if c--
#endif

clang reports error: token is not a valid binary operator in a preprocessor subexpression, pointing to the --

Partial trace:

/Users/ehaas/source/arocc/src/Tree.zig:463:30: 0x108972a7c in Tree.isLvalExtra (arocc)
    switch (nodes.items(.tag)[@enumToInt(node)]) {
                             ^
/Users/ehaas/source/arocc/src/Tree.zig:458:23: 0x10891086f in Tree.isLval (arocc)
    return isLvalExtra(nodes, extra, value_map, node, &is_const);
                      ^
/Users/ehaas/source/arocc/src/Parser.zig:4660:29: 0x108a01572 in Parser.suffixExpr (arocc)
            if (!Tree.isLval(p.nodes.slice(), p.data.items, p.value_map, operand.node) or operand.ty.isConst()) {
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:4579:48: 0x1089fad86 in Parser.unExpr (arocc)
                const suffix = try p.suffixExpr(lhs);
                                               ^
/Users/ehaas/source/arocc/src/Parser.zig:4327:20: 0x1089f99e1 in Parser.castExpr (arocc)
    return p.unExpr();

Preprocessor: index out of bounds in macro expansion of malformed macro

Smallest example I could come up with:

#define f(a) a
#define g f
#define h g( f
g(1) h 5)
thread 18378322 panic: index out of bounds
/Users/ehaas/source/arocc/src/Preprocessor.zig:802:25: 0x10467dd1b in Preprocessor.nextBufToken (arocc)
        return buf.items[start_idx.*];
                        ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:845:35: 0x10464b76d in Preprocessor.collectMacroFuncArguments (arocc)
        var tok = try nextBufToken(pp, tokenizer, buf, start_idx, end_idx, extend_buf);
                                  ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:919:67: 0x1045f3902 in Preprocessor.expandMacroExhaustive (arocc)
                    const args = (try pp.collectMacroFuncArguments(tokenizer, buf, &macro_scan_idx, &moving_end_idx, extend_buf, macro.is_builtin)) orelse {
                                                                  ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:1011:33: 0x1045c4c7c in Preprocessor.expandMacro (arocc)
    try pp.expandMacroExhaustive(tokenizer, &buf, 0, 1, true);
                                ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:308:35: 0x1045ba4ef in Preprocessor.preprocess (arocc)
                try pp.expandMacro(&tokenizer, tok);
                                  ^
/Users/ehaas/source/arocc/src/main.zig:237:22: 0x10459f818 in processSource (arocc)
    try pp.preprocess(source);
                     ^
/Users/ehaas/source/arocc/src/main.zig:223:22: 0x104594151 in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:41:15: 0x1045912dd in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x10460ec4c in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x104595257 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x104595195 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x1 in ??? (???)
[1]    94782 abort      ~/source/arocc/zig-out/bin/arocc test.c

segfault trying to initialize empty incomplete struct

Following code produces a segfault:

struct A b = {};

lldb backtrace:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
  * frame #0: 0x00007fff2051404d libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 77
    frame #1: 0x0000000100117b0c arocc`Parser.convertInitList(p=0x00007ffeefbfcd40, il=InitList @ 0x00007ffeefbfb6a8, init_ty=Type @ 0x00007ffeefbfbfd0) at Parser.zig:2556:45
    frame #2: 0x00000001000cf32d arocc`Parser.initializer(p=0x00007ffeefbfcd40, init_ty=Type @ 0x00007ffeefbfbfd0) at Parser.zig:2150:38
    frame #3: 0x0000000100074a78 arocc`Parser.initDeclarator(p=0x00007ffeefbfcd40, decl_spec=0x00007ffeefbfc8c8) at Parser.zig:1206:47
    frame #4: 0x000000010004349a arocc`Parser.decl(p=0x00007ffeefbfcd40) at Parser.zig:585:39
    frame #5: 0x000000010002f22b arocc`Parser.parse(pp=0x00007ffeefbfd5b8) at Parser.zig:462:19

Enum & Struct Declarations don't seem to be parsed correctly

When feeding in a source file containing an enum, it seems to be treated as an int var?

With the following input:

int IntTest;

enum EnumTest
{
    Begin,
    End,
};

struct StructTest{
    int MemberTest;
};

You get the following output:

var: 'int'
 name: IntTest

var: 'int'
 name: EnumTest

var: 'int'
 name: StructTest

[Source.zig] Change Source.Location from linked list to array

A future improvement will be to convert the source location mechanism into using contiguous arrays instead of linked lists now that they are being iterated upon a lot more.

Originally posted by @Vexu in #33 (comment)

Source.Location is a linked list that works like this:

  • the first item is always the original source location where the current token has been originally found, if any
  • the following items are the source locations of the macro expansions used to form the current token, the first one being the latest and the last one being the first expansion

assertion failure if initializing incomplete enum with self-type

enum Foo A = 13, B = A + 4;

truncated trace:

thread 18245272 panic: reached unreachable code
/Users/ehaas/source/arocc/src/Type.zig:452:21: 0x109ce1329 in Type.integerPromotion (arocc)
            else => unreachable, // not an integer type
                    ^
/Users/ehaas/source/arocc/src/Parser.zig:3583:49: 0x109cf053b in Parser.Result.usualArithmeticConversion (arocc)
        const a_promoted = a.ty.integerPromotion(p.pp.comp);
                                                ^
/Users/ehaas/source/arocc/src/Parser.zig:3364:44: 0x109cb8366 in Parser.Result.adjustTypes (arocc)
            try a.usualArithmeticConversion(b, p);
                                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4208:32: 0x109d26ef0 in Parser.addExpr (arocc)
        if (try lhs.adjustTypes(minus.?, &rhs, p, if (plus != null) .add else .sub)) {
                               ^
/Users/ehaas/source/arocc/src/Parser.zig:4167:28: 0x109d261b4 in Parser.shiftExpr (arocc)
    var lhs = try p.addExpr();

Indexing array with itself outside of a function accesses inactive union field in Type.eql

int arr[1];
arr[arr] = 2;
thread 15122780 panic: access of inactive union field
/Users/ehaas/source/arocc/src/Type.zig:759:43: 0x1039f2148 in Type.eql (arocc)
            if (a.data.array.len != b.data.array.len) return false;
                                          ^
/Users/ehaas/source/arocc/src/Parser.zig:1232:35: 0x103996a53 in Parser.initDeclarator (arocc)
        .decl => |s| if (!s.ty.eql(init_d.d.ty, true)) {
                                  ^
/Users/ehaas/source/arocc/src/Parser.zig:576:39: 0x1039635b9 in Parser.decl (arocc)
    var init_d = (try p.initDeclarator(&decl_spec)) orelse {
                                      ^
/Users/ehaas/source/arocc/src/Parser.zig:461:19: 0x10394f3ba in Parser.parse (arocc)
        if (p.decl() catch |er| switch (er) {
                  ^
/Users/ehaas/source/arocc/src/main.zig:257:32: 0x103931c69 in processSource (arocc)
    var tree = try Parser.parse(&pp);
                               ^
/Users/ehaas/source/arocc/src/main.zig:223:22: 0x103926211 in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:41:15: 0x10392339d in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x1039a25fc in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x103927317 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x103927255 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x1 in ??? (???)
[1]    92724 abort      ./zig-out/bin/arocc test/cases/crash.c

Trailing comma in expression crashes `Tree.dump`

Found using fuzz testing

void foo(void) {
    1,;
}

Compile with --verbose-ast:

thread 14001920 panic: reached unreachable code
/Users/ehaas/source/zig/build/lib/zig/std/debug.zig:226:14: 0x10a4dc2f8 in std.debug.assert (arocc)
    if (!ok) unreachable; // assertion failure
             ^
/Users/ehaas/source/arocc/src/Tree.zig:557:21: 0x10a52235b in Tree.dumpNode (arocc)
    std.debug.assert(node != .none);
                    ^
/Users/ehaas/source/arocc/src/Tree.zig:905:30: 0x10a52a0c9 in Tree.dumpNode (arocc)
            try tree.dumpNode(data.bin.rhs, level + delta, w);
                             ^
/Users/ehaas/source/arocc/src/Tree.zig:688:57: 0x10a528297 in Tree.dumpNode (arocc)
            if (data.bin.lhs != .none) try tree.dumpNode(data.bin.lhs, level + delta, w);
                                                        ^
/Users/ehaas/source/arocc/src/Tree.zig:628:30: 0x10a527bf9 in Tree.dumpNode (arocc)
            try tree.dumpNode(data.decl.node, level + delta, w);
                             ^
/Users/ehaas/source/arocc/src/Tree.zig:541:26: 0x10a50ae64 in Tree.dump (arocc)
        try tree.dumpNode(i, 0, writer);
                         ^
/Users/ehaas/source/arocc/src/main.zig:262:18: 0x10a4ecc2d in processSource (arocc)
        tree.dump(buf_writer.writer()) catch {};
                 ^
/Users/ehaas/source/arocc/src/main.zig:223:22: 0x10a4e1161 in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:41:15: 0x10a4de2ed in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x10a55bd7c in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x10a4e2267 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x10a4e21a5 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });

[Preprocessor] Simplify the Macro union

const Macro = union(enum) {
/// #define FOO
empty,
/// #define FOO a + b
simple: Simple,
/// #define FOO(a,b) ((a)+(b))
func: Func,
const Simple = struct {
tokens: []const RawToken,
loc: Source.Location,
};
const Func = struct {
params: []const []const u8,
tokens: []const RawToken,
var_args: bool,
loc: Source.Location,
};

The Macro enum stores the info about a #define clause, and currently has three possible type:

  1. simple, for object macros
  2. func, for func macros
  3. empty, for object macros with no replacement list

The third possibility, empty, is a residue of the old code and shall be unified with simple.
On the other hand, if left with just two possibilities, Macro could be further simplified as of #33 (comment):

empty special case could also be removed in favor of simple with 0 tokens. And while we're at it Macro could be replaced entirely with Func by adding a is_func flag that would fit in the padding.

Invalid universal character names can crash parser

char *foo = "\UA0110000";

The offending line appears to be:

    const c = std.fmt.parseInt(u21, slice[i.* + 1 ..][0..count], 16) catch unreachable; // Validated by tokenizer

So perhaps the tokenizer is too lenient?

Question: Alignment storage

Note: this may be irrelevant if the plan is to move alignment out of the type itself and into an attributed type

Currently a u29 is used to store the alignment but we could get away with a u5 since the alignment must be a power of 2. 0 could be reserved for "no alignment specified", so we'd actually want to store log_2(alignment) + 1. In this way a user-provided alignment of up to 2**30 could be supported.

alignment: u29 = 0,

Improve the diagnostics system

Currently the diagnostics system is a bit messy and verbose, some things that could improve it are:

  • print the messages to strings when they are added to reduce the amount of tags and switches
  • store info regarding the options in an array to avoid duplication in switches like tagKind and tagOption
  • colored printing on Windows will need to be done eventually
  • something else?

Parser confusion about current pragma

int foo,
#pragma bar bar
int baz;
#pragma qux
thread 14693625 panic: index out of bounds
/Users/ehaas/source/arocc/src/Parser.zig:109:18: 0x101592c32 in Parser.eatToken (arocc)
    if (p.tok_ids[p.tok_i] == id) {
                 ^
/Users/ehaas/source/arocc/src/Parser.zig:396:22: 0x101592cae in Parser.pragma (arocc)
    while (p.eatToken(.keyword_pragma) != null) {
                     ^
/Users/ehaas/source/arocc/src/Parser.zig:454:25: 0x1015802ae in Parser.parse (arocc)
        if (try p.pragma()) continue;
                        ^
/Users/ehaas/source/arocc/src/main.zig:257:32: 0x101562b49 in processSource (arocc)
    var tree = try Parser.parse(&pp);
                               ^
/Users/ehaas/source/arocc/src/main.zig:223:22: 0x101557161 in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:41:15: 0x1015542ed in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x1015d290c in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x101558267 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x1015581a5 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x1 in ??? (???)
[1]    63839 abort      ./zig-out/bin/arocc test/cases/crash.c

_Static_assert failure displays incorrect message

_Static_assert(1 == 0, "They are not equal!");

Output:

/Users/ehaas/source/c/test.c:1:1: error: static assertion failed "\xaa\xaa\xaa\xaa\xaa\x00\x00 \x00\x00\x00\x00\x00\x00\x00 \x05\x00\xaa"
_Static_assert(1 == 0, "They are not equal!");
^
1 error generated.
static_assert: 'void'
 condition:
  equal_expr: 'int' (value: 0)
   lhs:
    int_literal: 'int'
     value: 1
   rhs:
    int_literal: 'int'
     value: 0
 diagnostic:
  string_literal_expr: '[20]char' lvalue
   data: "They are not equal!"

underflow in preprocessor if macro starts with `##`

#define a##
a

We already check this for function-like macros

thread 18232445 panic: integer overflow
/Users/ehaas/source/zig/build/lib/zig/std/array_list.zig:405:51: 0x10e992850 in std.array_list.ArrayListAligned(Tree.Token,null).pop (arocc)
            const val = self.items[self.items.len - 1];
                                                  ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:553:32: 0x10e963a45 in Preprocessor.expandObjMacro (arocc)
            const lhs = buf.pop();
                               ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:976:54: 0x10e909b82 in Preprocessor.expandMacroExhaustive (arocc)
                    const res = try pp.expandObjMacro(macro);
                                                     ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:1011:33: 0x10e8d9c7c in Preprocessor.expandMacro (arocc)
    try pp.expandMacroExhaustive(tokenizer, &buf, 0, 1, true);
                                ^
/Users/ehaas/source/arocc/src/Preprocessor.zig:308:35: 0x10e8cf4ef in Preprocessor.preprocess (arocc)
                try pp.expandMacro(&tokenizer, tok);
                                  ^
/Users/ehaas/source/arocc/src/main.zig:237:22: 0x10e8b4818 in processSource (arocc)
    try pp.preprocess(source);
                     ^
/Users/ehaas/source/arocc/src/main.zig:223:22: 0x10e8a9151 in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:41:15: 0x10e8a62dd in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x10e923c4c in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x10e8aa257 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x10e8aa195 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x1 in ??? (???)
[1]    82004 abort      ~/source/arocc/zig-out/bin/arocc test.c

Diagnostics which print a type name crash when used with attributed types

void foo(void) {
    int d __attribute__((aligned(4)));
    d(4);
}

Should print error: cannot call non function type 'int' but it crashes

/Users/ehaas/source/arocc/src/Type.zig:1354:58: 0x10a047751 in Type.printPrologue (arocc)
        else => try w.writeAll(Builder.fromType(ty).str().?),
                                                         ^
/Users/ehaas/source/arocc/src/Type.zig:1296:29: 0x10a04660a in Type.print (arocc)
    _ = try ty.printPrologue(w);
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:212:17: 0x10a0ec3e2 in Parser.typeStr (arocc)
    try ty.print(p.strings.writer());
                ^
/Users/ehaas/source/arocc/src/Parser.zig:4769:59: 0x10a18ecec in Parser.callExpr (arocc)
        try p.errStr(.not_callable, l_paren, try p.typeStr(lhs.ty));

Parser: address-of rvalue can trigger access of inactive union field

int foo = 6u + &2;
thread 15096939 panic: access of inactive union field
/Users/ehaas/source/arocc/src/Parser.zig:3690:69: 0x10fc42695 in Parser.Result.add (arocc)
                    8 => overflow = @addWithOverflow(u64, v.*, b.val.unsigned, v),
                                                                    ^
/Users/ehaas/source/arocc/src/Parser.zig:4188:28: 0x10fc4157e in Parser.addExpr (arocc)
                try lhs.add(plus.?, rhs, p);
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4145:28: 0x10fc40794 in Parser.shiftExpr (arocc)
    var lhs = try p.addExpr();
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4116:30: 0x10fc3ffb4 in Parser.compExpr (arocc)
    var lhs = try p.shiftExpr();
                             ^
/Users/ehaas/source/arocc/src/Parser.zig:4091:29: 0x10fc3f534 in Parser.eqExpr (arocc)
    var lhs = try p.compExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:4071:27: 0x10fc3d614 in Parser.andExpr (arocc)
    var lhs = try p.eqExpr();
                          ^
/Users/ehaas/source/arocc/src/Parser.zig:4051:28: 0x10fc36404 in Parser.xorExpr (arocc)
    var lhs = try p.andExpr();
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4031:28: 0x10fc29b74 in Parser.orExpr (arocc)
    var lhs = try p.xorExpr();
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4009:27: 0x10fc0a3c4 in Parser.landExpr (arocc)
    var lhs = try p.orExpr();
                          ^
/Users/ehaas/source/arocc/src/Parser.zig:3987:29: 0x10fbd2424 in Parser.lorExpr (arocc)
    var lhs = try p.landExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:3949:29: 0x10fba0b94 in Parser.condExpr (arocc)
    var cond = try p.lorExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:3804:29: 0x10fbf02a4 in Parser.assignExpr (arocc)
    var lhs = try p.condExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:2126:35: 0x10fbaebc7 in Parser.initializer (arocc)
        var res = try p.assignExpr();
                                  ^
/Users/ehaas/source/arocc/src/Parser.zig:1197:47: 0x10fb54447 in Parser.initDeclarator (arocc)
        var init_list_expr = try p.initializer(init_d.d.ty);
                                              ^
/Users/ehaas/source/arocc/src/Parser.zig:576:39: 0x10fb215b9 in Parser.decl (arocc)
    var init_d = (try p.initDeclarator(&decl_spec)) orelse {
                                      ^
/Users/ehaas/source/arocc/src/Parser.zig:461:19: 0x10fb0d3ba in Parser.parse (arocc)
        if (p.decl() catch |er| switch (er) {
                  ^
/Users/ehaas/source/arocc/src/main.zig:257:32: 0x10faefc69 in processSource (arocc)
    var tree = try Parser.parse(&pp);
                               ^
/Users/ehaas/source/arocc/src/main.zig:223:22: 0x10fae4211 in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:41:15: 0x10fae139d in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x10fb605fc in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x10fae5317 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x10fae5255 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x1 in ??? (???)
[1]    90940 abort      ./zig-out/bin/arocc test/cases/crash.c

Add -pedantic flag and issue warnings

Currently arocc doesn't issues appropriate warnings in many cases like:

  1. Binary constant literals
  2. _Static_assert is lower than c11
  3. Return type of main being non-int

etc. which are activated by -pedantic flag in gcc and clang

No warning when assignment discards qualifiers

Following does not issue a warning:

void foo(void) {
    const int *y = 0;
    int *z;
    z = y;
}

In Type.eql, for pointer types, should we be unconditionally passing true for check_qualifiers when recursing into the elemType?

Parser: assertion failure in `usualArithmeticConversion`

The following code triggers an assertion failure:

int foo = 0xFFFFFFFFFF + 1u;
thread 15090414 panic: reached unreachable code
/Users/ehaas/source/zig/build/lib/zig/std/debug.zig:226:14: 0x10705a2f8 in std.debug.assert (arocc)
    if (!ok) unreachable; // assertion failure
             ^
/Users/ehaas/source/arocc/src/Parser.zig:3590:19: 0x107186309 in Parser.Result.usualArithmeticConversion (arocc)
            assert(b_unsigned and (@enumToInt(b_promoted.specifier) >= @enumToInt(a_promoted.specifier)));
                  ^
/Users/ehaas/source/arocc/src/Parser.zig:3345:44: 0x10714e016 in Parser.Result.adjustTypes (arocc)
            try a.usualArithmeticConversion(b, p);
                                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4186:32: 0x1071bc2f0 in Parser.addExpr (arocc)
        if (try lhs.adjustTypes(minus.?, &rhs, p, if (plus != null) .add else .sub)) {
                               ^
/Users/ehaas/source/arocc/src/Parser.zig:4145:28: 0x1071bb794 in Parser.shiftExpr (arocc)
    var lhs = try p.addExpr();
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4116:30: 0x1071bafb4 in Parser.compExpr (arocc)
    var lhs = try p.shiftExpr();
                             ^
/Users/ehaas/source/arocc/src/Parser.zig:4091:29: 0x1071ba534 in Parser.eqExpr (arocc)
    var lhs = try p.compExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:4071:27: 0x1071b8614 in Parser.andExpr (arocc)
    var lhs = try p.eqExpr();
                          ^
/Users/ehaas/source/arocc/src/Parser.zig:4051:28: 0x1071b1404 in Parser.xorExpr (arocc)
    var lhs = try p.andExpr();
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4031:28: 0x1071a4b74 in Parser.orExpr (arocc)
    var lhs = try p.xorExpr();
                           ^
/Users/ehaas/source/arocc/src/Parser.zig:4009:27: 0x1071853c4 in Parser.landExpr (arocc)
    var lhs = try p.orExpr();
                          ^
/Users/ehaas/source/arocc/src/Parser.zig:3987:29: 0x10714d424 in Parser.lorExpr (arocc)
    var lhs = try p.landExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:3949:29: 0x10711bb94 in Parser.condExpr (arocc)
    var cond = try p.lorExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:3804:29: 0x10716b2a4 in Parser.assignExpr (arocc)
    var lhs = try p.condExpr();
                            ^
/Users/ehaas/source/arocc/src/Parser.zig:2126:35: 0x107129bc7 in Parser.initializer (arocc)
        var res = try p.assignExpr();
                                  ^
/Users/ehaas/source/arocc/src/Parser.zig:1197:47: 0x1070cf447 in Parser.initDeclarator (arocc)
        var init_list_expr = try p.initializer(init_d.d.ty);
                                              ^
/Users/ehaas/source/arocc/src/Parser.zig:576:39: 0x10709c5b9 in Parser.decl (arocc)
    var init_d = (try p.initDeclarator(&decl_spec)) orelse {
                                      ^
/Users/ehaas/source/arocc/src/Parser.zig:461:19: 0x1070883ba in Parser.parse (arocc)
        if (p.decl() catch |er| switch (er) {
                  ^
/Users/ehaas/source/arocc/src/main.zig:257:32: 0x10706ac69 in processSource (arocc)
    var tree = try Parser.parse(&pp);
                               ^
/Users/ehaas/source/arocc/src/main.zig:223:22: 0x10705f211 in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/Users/ehaas/source/arocc/src/main.zig:41:15: 0x10705c39d in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:524:29: 0x1070db5fc in std.start.callMain (arocc)
            return root.main();
                            ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:469:12: 0x107060317 in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/Users/ehaas/source/zig/build/lib/zig/std/start.zig:434:12: 0x107060255 in std.start.main (arocc)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
???:?:?: 0x7fff204ecf3c in ??? (???)
???:?:?: 0x1 in ??? (???)
[1]    89704 abort      ./zig-out/bin/arocc test/cases/crash.c

Add __func__ support

The identifier __func__ is implicitly declared by the translator as if, immediately following the opening brace of each function definition, the declaration

static const char __func__[] = "function-name";

appeared, where function-name is the name of the lexically-enclosing function

As an extension, at file scope, __func__ evaluates to the empty string. It should generate a warning warning: predefined identifier is only valid inside function controlled by -Wpredefined-identifier-outside-function (default on)

__FUNCTION__ is another name for __func__

__PRETTY_FUNCTION__ is yet another name for __func__, except that at file scope, it evaluates to the string "top level"

These identifiers are variables, not preprocessor macros, and may not be used to initialize char arrays or be concatenated with string literals.

Compiling a simple hello world program

❯ arocc test.c -o test
thread 12150 panic: integer cast truncated bits
/home/varlad/arocc/src/Parser.zig:226:19: 0x2b86bc in Parser.addList (arocc)
    const start = @intCast(u32, p.data.items.len);
                  ^
/home/varlad/arocc/src/Parser.zig:3275:71: 0x2a317c in Parser.condExpr (arocc)
        .data = .{ .if3 = .{ .cond = cond.node, .body = (try p.addList(&.{ then_expr.node, else_expr.node })).start } },
                                                                      ^
/home/varlad/arocc/src/Parser.zig:2491:27: 0x28a5c0 in Parser.macroExpr (arocc)
    const res = p.condExpr() catch |e| switch (e) {
                          ^
/home/varlad/arocc/src/Preprocessor.zig:415:28: 0x26ef1f in Preprocessor.expr (arocc)
    return parser.macroExpr();
                           ^
/home/varlad/arocc/src/Preprocessor.zig:121:40: 0x267f80 in Preprocessor.preprocess (arocc)
                        if (try pp.expr(&tokenizer)) {
                                       ^
/home/varlad/arocc/src/Preprocessor.zig:1098:22: 0x26fecb in Preprocessor.include (arocc)
    try pp.preprocess(new_source);
                     ^
/home/varlad/arocc/src/Preprocessor.zig:205:55: 0x268a8a in Preprocessor.preprocess (arocc)
                    .keyword_include => try pp.include(&tokenizer),
                                                      ^
/home/varlad/arocc/src/Preprocessor.zig:1098:22: 0x26fecb in Preprocessor.include (arocc)
    try pp.preprocess(new_source);
                     ^
/home/varlad/arocc/src/Preprocessor.zig:205:55: 0x268a8a in Preprocessor.preprocess (arocc)
                    .keyword_include => try pp.include(&tokenizer),
                                                      ^
/home/varlad/arocc/src/Preprocessor.zig:1098:22: 0x26fecb in Preprocessor.include (arocc)
    try pp.preprocess(new_source);
                     ^
/home/varlad/arocc/src/Preprocessor.zig:205:55: 0x268a8a in Preprocessor.preprocess (arocc)
                    .keyword_include => try pp.include(&tokenizer),
                                                      ^
/home/varlad/arocc/src/main.zig:209:22: 0x25f5ac in processSource (arocc)
    try pp.preprocess(source);
                     ^
/home/varlad/arocc/src/main.zig:196:22: 0x25884e in handleArgs (arocc)
        processSource(comp, source, builtin, user_macros) catch |e| switch (e) {
                     ^
/home/varlad/arocc/src/main.zig:33:15: 0x24f8c2 in main (arocc)
    handleArgs(&comp, args) catch |err| switch (err) {
              ^
/home/varlad/zig-master/lib/std/start.zig:507:29: 0x2481cc in std.start.callMain (arocc)
            return root.main();
                            ^
/home/varlad/zig-master/lib/std/start.zig:452:12: 0x22c1ce in std.start.callMainWithArgs (arocc)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/home/varlad/zig-master/lib/std/start.zig:366:17: 0x22b1f6 in std.start.posixCallMainAndExit (arocc)
    std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
                ^
/home/varlad/zig-master/lib/std/start.zig:279:5: 0x22b002 in std.start._start (arocc)
    @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    ^
fish: Job 1, 'arocc test.c -o test' terminated by signal SIGABRT (Abort)

where test.c reads

#include "stdio.h"

int main()
{
	printf("Well, heck");
	return 0;
}

Built with Zig v0.9.0-dev.861+311797f68 via zig build

Don't always use nodes to store attribute arguments

Using nodes is wasteful since we usually don't need to explicitly store the tag or type (it's known from the attribute name + arg position)

Attribute arguments can be of the following types:

  1. Identifier (store using TokenIndex)
  2. string literal (question: store with index+len or []const u8?)
  3. signed or unsigned integer (some may have further restrictions, e.g. aligned requires a power of 2)
  4. expression (this is used by the copy attribute https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#index-copy-type-attribute) - in this case we'll probably need a NodeIndex. We may also need to special-case the parser so it doesn't try to evaluate the expression.

Parser.EatToken() can end-up out of bounds - not sure why

Specifically p.tok_i can end-up out of bounds in this conditional

if (p.tok_ids[p.tok_i] == id)

I've been able to workaround this issue locally by changing the condition of the while loop in Parser.zig to:

 while ((p.tok_i < p.tok_ids.len) and (p.eatToken(.eof) == null))

I've been using a small amount of macro-trickery (in an attempt) to use arocc for build-time reflection on C-style enums, whilst still supporting C++ style enums for the actual C++ side of things. So the code that is being parsed is a little idiosyncratic:

#pragma once

#include "Reflection/Enum.meta.h"

DECLARE_ENUM(LogChannel, uint16_t)
{
    Default = 0,
    Rendering = 1,
    Vulkan = 2,
    VulkanInternal = 3,
    Import = 4,
    JobSystem = 5,
    Containers = 6,
    Engine = 7,
};

Where Enum.meta.h is defined as:

#pragma once

#ifdef __cplusplus
#include "cstdint_wrapper.hpp"
#define DECLARE_ENUM(EnumName, EnumType) \
    enum class EnumName : EnumType
#else
#define DECLARE_ENUM(EnumName, EnumType) \
    enum EnumName
#endif

I've done a little bit of debugging to try and track down the cause - but I don't want to spend too much time being side-tracked by this problem. So I will leave it for now - so thought I would at least make the issue. I might come back to it later but I need to dedicate some time to properly understanding how arocc is structured in order to debug this issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.