Commit f7e9d7aa5d
Changed files (8)
doc/langref.md
@@ -621,3 +621,7 @@ if there is not one specified, invokes the one provided in
### @ptrcast(comptime DestType: type, value: var) -> DestType
Converts a pointer of one type to a pointer of another type.
+
+### @intToPtr(comptime DestType: type, int: usize) -> DestType
+
+Converts an integer to a pointer. To convert the other way, use `usize(ptr)`.
src/all_types.hpp
@@ -1199,6 +1199,7 @@ enum BuiltinFnId {
BuiltinFnIdSetGlobalLinkage,
BuiltinFnIdPanic,
BuiltinFnIdPtrCast,
+ BuiltinFnIdIntToPtr,
};
struct BuiltinFnEntry {
@@ -2391,6 +2392,7 @@ struct IrInstructionPtrToInt {
struct IrInstructionIntToPtr {
IrInstruction base;
+ IrInstruction *dest_type;
IrInstruction *target;
};
src/codegen.cpp
@@ -4326,6 +4326,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);
create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1);
create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrcast", 2);
+ create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
}
static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) {
src/ir.cpp
@@ -1951,12 +1951,14 @@ static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, As
}
static IrInstruction *ir_build_int_to_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *target)
+ IrInstruction *dest_type, IrInstruction *target)
{
IrInstructionIntToPtr *instruction = ir_build_instruction<IrInstructionIntToPtr>(
irb, scope, source_node);
+ instruction->dest_type = dest_type;
instruction->target = target;
+ if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
ir_ref_instruction(target, irb->current_basic_block);
return &instruction->base;
@@ -2185,8 +2187,8 @@ static IrInstruction *ir_instruction_binop_get_dep(IrInstructionBinOp *instructi
static IrInstruction *ir_instruction_declvar_get_dep(IrInstructionDeclVar *instruction, size_t index) {
switch (index) {
- case 0: return instruction->var_type;
- case 1: return instruction->init_value;
+ case 0: return instruction->init_value;
+ case 1: return instruction->var_type;
default: return nullptr;
}
}
@@ -2670,8 +2672,8 @@ static IrInstruction *ir_instruction_ptrcast_get_dep(IrInstructionPtrCast *instr
size_t index)
{
switch (index) {
- case 0: return instruction->dest_type;
- case 1: return instruction->ptr;
+ case 0: return instruction->ptr;
+ case 1: return instruction->dest_type;
default: return nullptr;
}
}
@@ -2686,6 +2688,7 @@ static IrInstruction *ir_instruction_widenorshorten_get_dep(IrInstructionWidenOr
static IrInstruction *ir_instruction_inttoptr_get_dep(IrInstructionIntToPtr *instruction, size_t index) {
switch (index) {
case 0: return instruction->target;
+ case 1: return instruction->dest_type;
default: return nullptr;
}
}
@@ -4222,6 +4225,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
}
+ case BuiltinFnIdIntToPtr:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
+
+ return ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value);
+ }
}
zig_unreachable();
}
@@ -5821,10 +5838,19 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
}
// implicit number literal to typed number
- if ((actual_type->id == TypeTableEntryIdNumLitFloat ||
- actual_type->id == TypeTableEntryIdNumLitInt))
+ // implicit number literal to &const integer
+ if (actual_type->id == TypeTableEntryIdNumLitFloat ||
+ actual_type->id == TypeTableEntryIdNumLitInt)
{
- if (ir_num_lit_fits_in_other_type(ira, value, expected_type)) {
+ if (expected_type->id == TypeTableEntryIdPointer &&
+ expected_type->data.pointer.is_const)
+ {
+ if (ir_num_lit_fits_in_other_type(ira, value, expected_type->data.pointer.child_type)) {
+ return ImplicitCastMatchResultYes;
+ } else {
+ return ImplicitCastMatchResultReportedError;
+ }
+ } else if (ir_num_lit_fits_in_other_type(ira, value, expected_type)) {
return ImplicitCastMatchResultYes;
} else {
return ImplicitCastMatchResultReportedError;
@@ -6651,47 +6677,6 @@ static IrInstruction *ir_analyze_ptr_to_int(IrAnalyze *ira, IrInstruction *sourc
return result;
}
-static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr,
- IrInstruction *target, TypeTableEntry *wanted_type)
-{
- assert(wanted_type->id == TypeTableEntryIdPointer);
-
- if (instr_is_comptime(target)) {
- ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
- if (!val)
- return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
- result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
- result->value.data.x_ptr.data.hard_coded_addr.addr = bignum_to_twos_complement(&val->data.x_bignum);
- return result;
- }
-
- IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, source_instr->scope,
- source_instr->source_node, target);
- result->value.type = wanted_type;
- return result;
-}
-
-static IrInstruction *ir_analyze_int_lit_to_ptr(IrAnalyze *ira, IrInstruction *source_instr,
- IrInstruction *target, TypeTableEntry *wanted_type)
-{
- assert(wanted_type->id == TypeTableEntryIdPointer);
-
- ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
- if (!val)
- return ira->codegen->invalid_instruction;
-
- TypeTableEntry *usize_type = ira->codegen->builtin_types.entry_usize;
- if (!ir_num_lit_fits_in_other_type(ira, target, usize_type))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
- result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
- result->value.data.x_ptr.data.hard_coded_addr.addr = bignum_to_twos_complement(&val->data.x_bignum);
- return result;
-}
static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *target, TypeTableEntry *wanted_type)
@@ -6815,7 +6800,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
TypeTableEntry *wanted_type_canon = get_underlying_type(wanted_type);
TypeTableEntry *actual_type_canon = get_underlying_type(actual_type);
- TypeTableEntry *isize_type = ira->codegen->builtin_types.entry_isize;
TypeTableEntry *usize_type = ira->codegen->builtin_types.entry_usize;
if (type_is_invalid(wanted_type_canon) || type_is_invalid(actual_type_canon)) {
@@ -6837,28 +6821,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBoolToInt, false);
}
- // explicit cast from pointer to isize or usize
- if ((wanted_type_canon == isize_type || wanted_type_canon == usize_type) &&
- type_is_codegen_pointer(actual_type_canon))
- {
+ // explicit cast from pointer to usize
+ if (wanted_type_canon == usize_type && type_is_codegen_pointer(actual_type_canon)) {
return ir_analyze_ptr_to_int(ira, source_instr, value, wanted_type);
}
-
- // explicit cast from isize or usize to pointer
- if (wanted_type_canon->id == TypeTableEntryIdPointer &&
- (actual_type_canon == isize_type || actual_type_canon == usize_type))
- {
- return ir_analyze_int_to_ptr(ira, source_instr, value, wanted_type);
- }
-
- // explicit cast from number literal to pointer
- if (wanted_type_canon->id == TypeTableEntryIdPointer &&
- (actual_type_canon->id == TypeTableEntryIdNumLitInt))
- {
- return ir_analyze_int_lit_to_ptr(ira, source_instr, value, wanted_type);
- }
-
// explicit widening or shortening cast
if ((wanted_type_canon->id == TypeTableEntryIdInt &&
actual_type_canon->id == TypeTableEntryIdInt) ||
@@ -6970,10 +6937,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
// explicit cast from number literal to another type
+ // explicit cast from number literal to &const integer
if (actual_type->id == TypeTableEntryIdNumLitFloat ||
actual_type->id == TypeTableEntryIdNumLitInt)
{
- if (ir_num_lit_fits_in_other_type(ira, value, wanted_type_canon)) {
+ if (wanted_type->id == TypeTableEntryIdPointer &&
+ wanted_type->data.pointer.is_const)
+ {
+ IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
+ if (type_is_invalid(cast1->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
+ if (type_is_invalid(cast2->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return cast2;
+ } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type_canon)) {
CastOp op;
if ((actual_type->id == TypeTableEntryIdNumLitFloat &&
wanted_type_canon->id == TypeTableEntryIdFloat) ||
@@ -12304,12 +12284,6 @@ static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructio
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
}
-static bool is_ptr_type(TypeTableEntry *t) {
- return (t->id == TypeTableEntryIdPointer || t->id == TypeTableEntryIdFn ||
- (t->id == TypeTableEntryIdMaybe && (t->data.maybe.child_type->id == TypeTableEntryIdPointer ||
- t->data.maybe.child_type->id == TypeTableEntryIdFn)));
-}
-
static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
IrInstruction *dest_type_value = instruction->dest_type->other;
TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
@@ -12321,12 +12295,12 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc
if (type_is_invalid(src_type))
return ira->codegen->builtin_types.entry_invalid;
- if (!is_ptr_type(src_type)) {
+ if (!type_is_codegen_pointer(src_type)) {
ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
- if (!is_ptr_type(dest_type)) {
+ if (!type_is_codegen_pointer(dest_type)) {
ir_add_error(ira, dest_type_value,
buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
return ira->codegen->builtin_types.entry_invalid;
@@ -12350,6 +12324,42 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc
return dest_type;
}
+static TypeTableEntry *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) {
+ IrInstruction *dest_type_value = instruction->dest_type->other;
+ TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
+ if (type_is_invalid(dest_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (!type_is_codegen_pointer(dest_type)) {
+ ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ IrInstruction *target = instruction->target->other;
+ if (type_is_invalid(target->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *casted_int = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_usize);
+ if (type_is_invalid(casted_int->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (instr_is_comptime(casted_int)) {
+ ConstExprValue *val = ir_resolve_const(ira, casted_int, UndefBad);
+ if (!val)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
+ out_val->data.x_ptr.data.hard_coded_addr.addr = bignum_to_twos_complement(&val->data.x_bignum);
+ return dest_type;
+ }
+
+ IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, nullptr, casted_int);
+ ir_link_new_instruction(result, &instruction->base);
+ return dest_type;
+}
+
static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
IrInstructionDeclRef *instruction)
{
@@ -12424,8 +12434,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
switch (instruction->id) {
case IrInstructionIdInvalid:
case IrInstructionIdWidenOrShorten:
- case IrInstructionIdIntToPtr:
- case IrInstructionIdPtrToInt:
case IrInstructionIdIntToEnum:
case IrInstructionIdIntToErr:
case IrInstructionIdErrToInt:
@@ -12433,6 +12441,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
case IrInstructionIdStructFieldPtr:
case IrInstructionIdEnumFieldPtr:
case IrInstructionIdInitEnum:
+ case IrInstructionIdPtrToInt:
zig_unreachable();
case IrInstructionIdReturn:
return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction);
@@ -12590,6 +12599,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction);
case IrInstructionIdPtrCast:
return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction);
+ case IrInstructionIdIntToPtr:
+ return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction);
case IrInstructionIdMaybeWrap:
case IrInstructionIdErrWrapCode:
case IrInstructionIdErrWrapPayload:
std/debug.zig
@@ -68,7 +68,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
var maybe_fp: ?&const u8 = @frameAddress();
while (true) {
const fp = maybe_fp ?? break;
- const return_address = *(&const usize)(usize(fp) + @sizeOf(usize));
+ const return_address = *@intToPtr(&const usize, usize(fp) + @sizeOf(usize));
const compile_unit = findCompileUnit(st, return_address) ?? return error.MissingDebugInfo;
const name = %return compile_unit.die.getAttrString(st, DW.AT_name);
std/hash_map.zig
@@ -234,15 +234,14 @@ test "basicHashMapTest" {
var map = HashMap(i32, i32, hash_i32, eql_i32).init(&debug.global_allocator);
defer map.deinit();
- // TODO issue #311
- assert(%%map.put(1, i32(11)) == null);
- assert(%%map.put(2, i32(22)) == null);
- assert(%%map.put(3, i32(33)) == null);
- assert(%%map.put(4, i32(44)) == null);
- assert(%%map.put(5, i32(55)) == null);
-
- assert(??%%map.put(5, i32(66)) == 55);
- assert(??%%map.put(5, i32(55)) == 66);
+ assert(%%map.put(1, 11) == null);
+ assert(%%map.put(2, 22) == null);
+ assert(%%map.put(3, 33) == null);
+ assert(%%map.put(4, 44) == null);
+ assert(%%map.put(5, 55) == null);
+
+ assert(??%%map.put(5, 66) == 55);
+ assert(??%%map.put(5, 55) == 66);
assert((??map.get(2)).value == 22);
_ = map.remove(2);
test/cases/cast.zig
@@ -1,15 +1,15 @@
const assert = @import("std").debug.assert;
const mem = @import("std").mem;
-test "intToPtrCast" {
- const x = isize(13);
- const y = (&u8)(x);
+test "int to ptr cast" {
+ const x = usize(13);
+ const y = @intToPtr(&u8, x);
const z = usize(y);
assert(z == 13);
}
test "numLitIntToPtrCast" {
- const vga_mem = (&u16)(0xB8000);
+ const vga_mem = @intToPtr(&u16, 0xB8000);
assert(usize(vga_mem) == 0xB8000);
}
@@ -64,3 +64,9 @@ fn testPeerResolveArrayConstSlice(b: bool) {
assert(mem.eql(u8, value1, "aoeu"));
assert(mem.eql(u8, value2, "zz"));
}
+
+
+test "integer literal to &const int" {
+ const x: &const i32 = 3;
+ assert(*x == 3);
+}
test/cases/misc.zig
@@ -373,14 +373,6 @@ fn testTakeAddressOfParameter(f: f32) {
}
-test "intToPtrCast" {
- const x = isize(13);
- const y = (&u8)(x);
- const z = usize(y);
- assert(z == 13);
-}
-
-
test "pointerComparison" {
const a = ([]const u8)("a");
const b = &a;