Commit 0f047337ac

Andrew Kelley <superjoe30@gmail.com>
2016-12-18 02:47:35
IR: fix `this` expression
Previously it returned a block instead of a function when a function had any arguments.
1 parent a07d7ee
src/analyze.cpp
@@ -145,12 +145,12 @@ ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *con
     return scope;
 }
 
-Scope *create_block_scope(AstNode *node, Scope *parent) {
+ScopeBlock *create_block_scope(AstNode *node, Scope *parent) {
     assert(node->type == NodeTypeBlock);
     ScopeBlock *scope = allocate<ScopeBlock>(1);
     init_scope(&scope->base, ScopeIdBlock, node, parent);
     scope->label_table.init(1);
-    return &scope->base;
+    return scope;
 }
 
 ScopeDefer *create_defer_scope(AstNode *node, Scope *parent) {
@@ -1446,7 +1446,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
         if (is_main_fn)
             g->main_fn = fn_table_entry;
 
-        if (is_main_fn && !g->link_libc) {
+        if (is_main_fn && !g->link_libc && tld_fn->base.visib_mod != VisibModExport) {
             TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
             TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
             if (actual_return_type != err_void) {
@@ -2049,6 +2049,29 @@ FnTableEntry *scope_fn_entry(Scope *scope) {
     return nullptr;
 }
 
+FnTableEntry *scope_get_fn_if_root(Scope *scope) {
+    assert(scope);
+    scope = scope->parent;
+    while (scope) {
+        switch (scope->id) {
+            case ScopeIdBlock:
+                return nullptr;
+            case ScopeIdDecls:
+            case ScopeIdDefer:
+            case ScopeIdVarDecl:
+            case ScopeIdCImport:
+            case ScopeIdLoop:
+                scope = scope->parent;
+                continue;
+            case ScopeIdFnDef:
+                ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
+                return fn_scope->fn_entry;
+        }
+        zig_unreachable();
+    }
+    return nullptr;
+}
+
 TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name) {
     for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
         TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
@@ -2392,9 +2415,9 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
             assert(proto_node->type == NodeTypeFnProto);
             Buf *proto_name = proto_node->data.fn_proto.name;
 
-            bool is_private = (proto_node->data.fn_proto.visib_mod == VisibModPrivate);
+            bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub);
 
-            if (buf_eql_str(proto_name, "main") && !is_private) {
+            if (buf_eql_str(proto_name, "main") && is_pub) {
                 g->have_exported_main = true;
             }
         }
src/analyze.hpp
@@ -74,8 +74,9 @@ FnTableEntry *create_fn(AstNode *proto_node);
 FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage);
 void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node);
 AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index);
+FnTableEntry *scope_get_fn_if_root(Scope *scope);
 
-Scope *create_block_scope(AstNode *node, Scope *parent);
+ScopeBlock *create_block_scope(AstNode *node, Scope *parent);
 ScopeDefer *create_defer_scope(AstNode *node, Scope *parent);
 Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var);
 ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent);
src/ir.cpp
@@ -2051,9 +2051,15 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s
 static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
     assert(block_node->type == NodeTypeBlock);
 
-    Scope *outer_block_scope = create_block_scope(block_node, parent_scope);
+    ScopeBlock *scope_block = create_block_scope(block_node, parent_scope);
+    Scope *outer_block_scope = &scope_block->base;
     Scope *child_scope = outer_block_scope;
 
+    FnTableEntry *fn_entry = scope_fn_entry(parent_scope);
+    if (fn_entry && fn_entry->child_scope == parent_scope) {
+        fn_entry->def_scope = scope_block;
+    }
+
     IrInstruction *return_value = nullptr;
     for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
         AstNode *statement_node = block_node->data.block.statements.at(i);
@@ -3270,12 +3276,9 @@ static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode
     if (!scope->parent)
         return ir_build_const_import(irb, scope, node, node->owner);
 
-    FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
-    if (fn_entry && scope->parent && scope->parent->parent &&
-        !scope_fn_entry(scope->parent->parent))
-    {
+    FnTableEntry *fn_entry = scope_get_fn_if_root(scope);
+    if (fn_entry)
         return ir_build_const_fn(irb, scope, node, fn_entry);
-    }
 
     if (scope->id == ScopeIdDecls) {
         ScopeDecls *decls_scope = (ScopeDecls *)scope;
@@ -4379,6 +4382,7 @@ static bool is_u8(TypeTableEntry *type) {
 static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb) {
     if (old_bb->other)
         return old_bb->other;
+
     IrBasicBlock *new_bb = ir_build_bb_from(&ira->new_irb, old_bb);
 
     // We are about to enqueue old_bb for analysis. Before we do so, check old_bb
@@ -4391,7 +4395,8 @@ static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb) {
         IrInstructionPhi *phi_instruction = (IrInstructionPhi *)instruction;
         for (size_t incoming_i = 0; incoming_i < phi_instruction->incoming_count; incoming_i += 1) {
             IrBasicBlock *predecessor = phi_instruction->incoming_blocks[incoming_i];
-            ir_get_new_bb(ira, predecessor);
+            IrBasicBlock *new_predecessor = ir_get_new_bb(ira, predecessor);
+            ir_ref_bb(new_predecessor);
         }
     }
     ira->old_bb_queue.append(old_bb);
@@ -4404,7 +4409,7 @@ static void ir_start_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrBasicBlock *cons
     ira->old_irb.current_basic_block = old_bb;
     ira->const_predecessor_bb = const_predecessor_bb;
 
-    if (old_bb->other)
+    if (!const_predecessor_bb && old_bb->other)
         ira->new_irb.exec->basic_block_list.append(old_bb->other);
 }
 
@@ -6478,7 +6483,7 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
         IrInstruction *old_value = phi_instruction->incoming_values[i];
         assert(old_value);
         IrInstruction *new_value = old_value->other;
-        if (new_value->type_entry->id == TypeTableEntryIdInvalid)
+        if (!new_value || new_value->type_entry->id == TypeTableEntryIdInvalid)
             return ira->codegen->builtin_types.entry_invalid;
         new_incoming_values.append(new_value);
     }
@@ -7704,7 +7709,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
 
     IrBasicBlock *new_else_block = ir_get_new_bb(ira, switch_br_instruction->else_block);
     ir_build_switch_br_from(&ira->new_irb, &switch_br_instruction->base,
-            target_value, new_else_block, case_count, cases, is_inline);
+            target_value, new_else_block, case_count, cases, false);
     return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
 }
 
std/bootstrap.zig
@@ -16,7 +16,7 @@ var argv: &&u8 = undefined;
 export nakedcc fn _start() -> unreachable {
     @setFnVisible(this, want_start_symbol);
 
-    switch (@compileVar("arch")) {
+    inline switch (@compileVar("arch")) {
         Arch.x86_64 => {
             argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> usize));
             argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
@@ -32,7 +32,7 @@ export nakedcc fn _start() -> unreachable {
 
 fn callMain() -> %void {
     const args = @alloca([]u8, argc);
-    for (args) |arg, i| {
+    for (args) |_, i| {
         const ptr = argv[i];
         args[i] = ptr[0...cstr.len(ptr)];
     }