diff --git a/src/all_types.hpp b/src/all_types.hpp index a4e86c6b20..f301b724d4 100644 --- a/src/all_types.hpp +++ b/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; diff --git a/src/codegen.cpp b/src/codegen.cpp index a53174ab89..eacb303956 100644 --- a/src/codegen.cpp +++ b/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) { diff --git a/src/ir.cpp b/src/ir.cpp index 11e02d4cc7..a8c1409ef0 100644 --- a/src/ir.cpp +++ 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 static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(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(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 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(exec); + if (fn_entry) { + Buf *name = buf_alloc(); + buf_append_buf(name, &fn_entry->symbol_name); + buf_appendf(name, "("); + render_instance_name_recursive(codegen, name, &fn_entry->fndef_scope->base, exec->begin_scope); + buf_appendf(name, ")"); + return name; + } else { + 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; - if (irb->exec->name) { - name = irb->exec->name; - } else { - FnTableEntry *fn_entry = exec_fn_entry(irb->exec); - if (fn_entry) { - 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); - buf_appendf(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); - } - } - + Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), node); VisibMod visib_mod = VisibModPub; TldContainer *tld_container = allocate(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: { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 52fb675515..fccf11038a 100644 --- a/src/ir_print.cpp +++ b/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"); } diff --git a/test/cases/misc.zig b/test/cases/misc.zig index ee9833320d..a968fd213c 100644 --- a/test/cases/misc.zig +++ b/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")); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 2ab26c0078..93be0e176e 100644 --- a/test/compile_errors.zig +++ b/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'"); + }