vnmakarov / mir

A lightweight JIT compiler based on MIR (Medium Internal Representation) and C11 JIT compiler and interpreter based on MIR
MIT License
2.31k stars 148 forks source link

Output of RawParser.c built by xcc differ from gcc #287

Open mingodad opened 2 years ago

mingodad commented 2 years ago

While testing xcc with https://github.com/FransFaase/RawParser/blob/master/src/RawParser.c I noticed that it gives a different output than gcc:

./rawparser.gcc
OK: parsed white space
OK: parsed white space
OK: parsed value 0 from '0'
OK: parsed value 123 from '123'
OK: parsed ident 'aBc' from 'aBc'
OK: parsed ident '_123' from '_123'

./rawparser.chibicc
OK: parsed white space
OK: parsed white space
OK: parsed value 0 from '0'
OK: parsed value 123 from '123'
OK: parsed ident 'aBc' from 'aBc'
OK: parsed ident '_123' from '_123'

./rawparser.xcc
OK: parsed white space
OK: parsed white space
OK: parsed value 0 from '0'
OK: parsed value 123 from '123'
ERROR: failed to parse ident from 'aBc'
ERROR: failed to parse ident from '_123'

c2m rawparser.c -ei
OK: parsed white space
OK: parsed white space
OK: parsed value 0 from '0'
OK: parsed value 123 from '123'
ERROR: failed to parse ident from 'aBc'
ERROR: failed to parse ident from '_123'
mingodad commented 2 years ago

See this comment https://github.com/tyfkda/xcc/issues/96#issuecomment-1236076743 for the reason.

mingodad commented 2 years ago

I've been looking at c2mir.c to find a way to emit error/warning for function that doesn't return a value when declared to do so but couldn't find my way so far.

mingodad commented 2 years ago

After diving a bit more on c2mit.c code I found a way to start checking for function missing return:

diff --git a/c2mir/c2mir.c b/c2mir/c2mir.c
index 818d526..b60770f 100644
--- a/c2mir/c2mir.c
+++ b/c2mir/c2mir.c
@@ -5738,7 +5738,7 @@ struct node_scope {

 struct decl {
   /* true if address is taken, reg can be used or is used: */
-  unsigned addr_p : 1, reg_p : 1, used_p : 1;
+  unsigned addr_p : 1, reg_p : 1, used_p : 1, has_return:1;
   int bit_offset, width; /* for bitfields, -1 bit_offset for non bitfields. */
   mir_size_t offset;     /* var offset in frame or bss */
   node_t scope;          /* declaration scope */
@@ -7713,7 +7713,7 @@ static void init_decl (c2m_ctx_t c2m_ctx, decl_t decl) {
   check_ctx_t check_ctx = c2m_ctx->check_ctx;

   decl->addr_p = FALSE;
-  decl->reg_p = decl->used_p = FALSE;
+  decl->reg_p = decl->used_p = decl->has_return = FALSE;
   decl->offset = 0;
   decl->bit_offset = -1;
   decl->param_args_start = decl->param_args_num = 0;
@@ -9357,6 +9357,10 @@ static void check (c2m_ctx_t c2m_ctx, node_t r, node_t context) {
     ns = block->attr;
     ns->size = round_size (ns->size, MAX_ALIGNMENT);
     ns->size += ns->call_arg_area_size;
+    decl_t decl = r->attr;
+    if(decl->decl_spec.type->u.func_type->ret_type->u.basic_type != TP_VOID && !decl->has_return) {
+        error (c2m_ctx, POS (r), "no return in function returning non-void");
+    }
     break;
   }
   case N_TYPE: {
@@ -9627,6 +9631,7 @@ static void check (c2m_ctx_t c2m_ctx, node_t r, node_t context) {
     check_labels (c2m_ctx, labels, r);
     check (c2m_ctx, expr, r);
     ret_type = type->u.func_type->ret_type;
+    decl->has_return = TRUE;
     if (expr->code != N_IGNORE && void_type_p (ret_type)) {
       error (c2m_ctx, POS (r), "return with a value in function returning void");
     } else if (expr->code == N_IGNORE

And now when trying to compile/interpret the outdated RawParser.c attached here https://github.com/tyfkda/xcc/files/9482248/rawparser.c.zip I'm getting the desired output:

c2m rawparser.c -ei 
rawparser.c:1486:1: no return in function returning non-void
rawparser.c:1494:1: no return in function returning non-void
rawparser.c:1511:1: no return in function returning non-void
rawparser.c:1519:1: no return in function returning non-void

See also similar solution here https://github.com/tyfkda/xcc/issues/62 .