Commit 3ff465e288

Andrew Kelley <superjoe30@gmail.com>
2017-09-06 00:51:07
add OpaqueType builtin
closes #326
1 parent c3362c1
src/all_types.hpp
@@ -1253,6 +1253,7 @@ enum BuiltinFnId {
     BuiltinFnIdShrExact,
     BuiltinFnIdSetEvalBranchQuota,
     BuiltinFnIdAlignCast,
+    BuiltinFnIdOpaqueType,
 };
 
 struct BuiltinFnEntry {
@@ -1858,6 +1859,7 @@ enum IrInstructionId {
     IrInstructionIdSetEvalBranchQuota,
     IrInstructionIdPtrTypeOf,
     IrInstructionIdAlignCast,
+    IrInstructionIdOpaqueType,
 };
 
 struct IrInstruction {
@@ -2648,6 +2650,10 @@ struct IrInstructionAlignCast {
     IrInstruction *target;
 };
 
+struct IrInstructionOpaqueType {
+    IrInstruction base;
+};
+
 static const size_t slice_ptr_index = 0;
 static const size_t slice_len_index = 1;
 
src/codegen.cpp
@@ -469,7 +469,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
             FnTableEntry *fn_table_entry = fn_scope->fn_entry;
             if (!fn_table_entry->proto_node)
                 return get_di_scope(g, scope->parent);
-            unsigned line_number = (unsigned)fn_table_entry->proto_node->line + 1;
+            unsigned line_number = (unsigned)(fn_table_entry->proto_node->line == 0) ?
+                0 : (fn_table_entry->proto_node->line + 1);
             unsigned scope_line = line_number;
             bool is_definition = fn_table_entry->body_node != nullptr;
             unsigned flags = 0;
@@ -3328,6 +3329,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
         case IrInstructionIdTypeId:
         case IrInstructionIdSetEvalBranchQuota:
         case IrInstructionIdPtrTypeOf:
+        case IrInstructionIdOpaqueType:
             zig_unreachable();
         case IrInstructionIdReturn:
             return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -4732,6 +4734,7 @@ static void define_builtin_fns(CodeGen *g) {
     create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
     create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1);
     create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);
+    create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0);
 }
 
 static const char *bool_to_str(bool b) {
src/ir.cpp
@@ -559,6 +559,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignCast *) {
     return IrInstructionIdAlignCast;
 }
 
+static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) {
+    return IrInstructionIdOpaqueType;
+}
+
 template<typename T>
 static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
     T *special_instruction = allocate<T>(1);
@@ -2238,6 +2242,12 @@ static IrInstruction *ir_build_align_cast(IrBuilder *irb, Scope *scope, AstNode
     return &instruction->base;
 }
 
+static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) {
+    IrInstructionOpaqueType *instruction = ir_build_instruction<IrInstructionOpaqueType>(irb, scope, source_node);
+
+    return &instruction->base;
+}
+
 static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
     return nullptr;
 }
@@ -2956,6 +2966,10 @@ static IrInstruction *ir_instruction_aligncast_get_dep(IrInstructionAlignCast *i
     }
 }
 
+static IrInstruction *ir_instruction_opaquetype_get_dep(IrInstructionOpaqueType *instruction, size_t index) {
+    return nullptr;
+}
+
 static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
     switch (instruction->id) {
         case IrInstructionIdInvalid:
@@ -3154,6 +3168,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
             return ir_instruction_ptrtypeof_get_dep((IrInstructionPtrTypeOf *) instruction, index);
         case IrInstructionIdAlignCast:
             return ir_instruction_aligncast_get_dep((IrInstructionAlignCast *) instruction, index);
+        case IrInstructionIdOpaqueType:
+            return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index);
     }
     zig_unreachable();
 }
@@ -4578,6 +4594,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
 
                 return ir_build_align_cast(irb, scope, node, arg0_value, arg1_value);
             }
+        case BuiltinFnIdOpaqueType:
+            return ir_build_opaque_type(irb, scope, node);
     }
     zig_unreachable();
 }
@@ -6044,27 +6062,30 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o
     return true;
 }
 
-static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
-    assert(node->type == NodeTypeContainerDecl);
-
-    ContainerKind kind = node->data.container_decl.kind;
-    Buf *name;
-    if (irb->exec->name) {
-        name = irb->exec->name;
+static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name, AstNode *source_node) {
+    if (exec->name) {
+        return exec->name;
     } else {
-        FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
+        FnTableEntry *fn_entry = exec_fn_entry(exec);
         if (fn_entry) {
-            name = buf_alloc();
+            Buf *name = buf_alloc();
             buf_append_buf(name, &fn_entry->symbol_name);
             buf_appendf(name, "(");
-            render_instance_name_recursive(irb->codegen, name, &fn_entry->fndef_scope->base, irb->exec->begin_scope);
+            render_instance_name_recursive(codegen, name, &fn_entry->fndef_scope->base, exec->begin_scope);
             buf_appendf(name, ")");
+            return name;
         } else {
-            name = buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", container_string(kind),
-                buf_ptr(node->owner->path), node->line + 1, node->column + 1);
+            return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,
+                buf_ptr(source_node->owner->path), source_node->line + 1, source_node->column + 1);
         }
     }
+}
 
+static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+    assert(node->type == NodeTypeContainerDecl);
+
+    ContainerKind kind = node->data.container_decl.kind;
+    Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), node);
 
     VisibMod visib_mod = VisibModPub;
     TldContainer *tld_container = allocate<TldContainer>(1);
@@ -15143,6 +15164,14 @@ static TypeTableEntry *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstr
     return result->value.type;
 }
 
+static TypeTableEntry *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInstructionOpaqueType *instruction) {
+    Buf *name = get_anon_type_name(ira->codegen, ira->new_irb.exec, "opaque", instruction->base.source_node);
+    ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+    out_val->data.x_type = get_opaque_type(ira->codegen, instruction->base.scope, instruction->base.source_node,
+            buf_ptr(name));
+    return ira->codegen->builtin_types.entry_type;
+}
+
 static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
     switch (instruction->id) {
         case IrInstructionIdInvalid:
@@ -15329,6 +15358,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
             return ir_analyze_instruction_ptr_type_of(ira, (IrInstructionPtrTypeOf *)instruction);
         case IrInstructionIdAlignCast:
             return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction);
+        case IrInstructionIdOpaqueType:
+            return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
     }
     zig_unreachable();
 }
@@ -15507,6 +15538,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdOffsetOf:
         case IrInstructionIdTypeId:
         case IrInstructionIdAlignCast:
+        case IrInstructionIdOpaqueType:
             return false;
         case IrInstructionIdAsm:
             {
src/ir_print.cpp
@@ -944,6 +944,10 @@ static void ir_print_align_cast(IrPrint *irp, IrInstructionAlignCast *instructio
     fprintf(irp->f, ")");
 }
 
+static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) {
+    fprintf(irp->f, "@OpaqueType()");
+}
+
 static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
     ir_print_prefix(irp, instruction);
     switch (instruction->id) {
@@ -1240,6 +1244,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdAlignCast:
             ir_print_align_cast(irp, (IrInstructionAlignCast *)instruction);
             break;
+        case IrInstructionIdOpaqueType:
+            ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);
+            break;
     }
     fprintf(irp->f, "\n");
 }
test/cases/misc.zig
@@ -538,3 +538,11 @@ export fn writeToVRam() {
 test "pointer child field" {
     assert((&u32).child == u32);
 }
+
+const OpaqueA = @OpaqueType();
+const OpaqueB = @OpaqueType();
+test "@OpaqueType" {
+    assert(&OpaqueA != &OpaqueB);
+    assert(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
+    assert(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
+}
test/compile_errors.zig
@@ -2079,4 +2079,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
         ".tmp_source.zig:5:5: error: @setEvalBranchQuota must be called from the top of the comptime stack",
         ".tmp_source.zig:2:8: note: called from here",
         ".tmp_source.zig:1:10: note: called from here");
+
+    cases.add("wrong pointer implicitly casted to pointer to @OpaqueType()",
+        \\const Derp = @OpaqueType();
+        \\extern fn bar(d: &Derp);
+        \\export fn foo() {
+        \\    const x = u8(1);
+        \\    bar(@ptrCast(&c_void, &x));
+        \\}
+    ,
+        ".tmp_source.zig:5:9: error: expected type '&Derp', found '&c_void'");
+
 }