authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-07 15:34:13-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-07 15:35:38-04:00
logf7e9d7aa5d115a6a8158625cd1aceb7e8dafe880
treea6a7ef8030a4b44d4b87b8e04fe7002c006ce381
parentffb4852012509327c646c9899259e894965b2259

ability to implicitly cast integer literal to &const Int

where Int is an integer type also introduce `@intToPtr` builtin for converting a usize to a pointer. users now have to use this instead of `(&T)(int)`. closes #311

8 files changed, 117 insertions(+), 102 deletions(-)

doc/langref.md+4
......@@ -621,3 +621,7 @@ if there is not one specified, invokes the one provided in
621621### @ptrcast(comptime DestType: type, value: var) -> DestType
622622
623623Converts a pointer of one type to a pointer of another type.
624
625### @intToPtr(comptime DestType: type, int: usize) -> DestType
626
627Converts an integer to a pointer. To convert the other way, use `usize(ptr)`.
src/all_types.hpp+2
......@@ -1199,6 +1199,7 @@ enum BuiltinFnId {
11991199 BuiltinFnIdSetGlobalLinkage,
12001200 BuiltinFnIdPanic,
12011201 BuiltinFnIdPtrCast,
1202 BuiltinFnIdIntToPtr,
12021203};
12031204
12041205struct BuiltinFnEntry {
......@@ -2391,6 +2392,7 @@ struct IrInstructionPtrToInt {
23912392struct IrInstructionIntToPtr {
23922393 IrInstruction base;
23932394
2395 IrInstruction *dest_type;
23942396 IrInstruction *target;
23952397};
23962398
src/codegen.cpp+1
......@@ -4326,6 +4326,7 @@ static void define_builtin_fns(CodeGen *g) {
43264326 create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);
43274327 create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1);
43284328 create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrcast", 2);
4329 create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
43294330}
43304331
43314332static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) {
src/ir.cpp+91-80
......@@ -1951,12 +1951,14 @@ static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, As
19511951}
19521952
19531953static IrInstruction *ir_build_int_to_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
1954 IrInstruction *target)
1954 IrInstruction *dest_type, IrInstruction *target)
19551955{
19561956 IrInstructionIntToPtr *instruction = ir_build_instruction<IrInstructionIntToPtr>(
19571957 irb, scope, source_node);
1958 instruction->dest_type = dest_type;
19581959 instruction->target = target;
19591960
1961 if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
19601962 ir_ref_instruction(target, irb->current_basic_block);
19611963
19621964 return &instruction->base;
......@@ -2185,8 +2187,8 @@ static IrInstruction *ir_instruction_binop_get_dep(IrInstructionBinOp *instructi
21852187
21862188static IrInstruction *ir_instruction_declvar_get_dep(IrInstructionDeclVar *instruction, size_t index) {
21872189 switch (index) {
2188 case 0: return instruction->var_type;
2189 case 1: return instruction->init_value;
2190 case 0: return instruction->init_value;
2191 case 1: return instruction->var_type;
21902192 default: return nullptr;
21912193 }
21922194}
......@@ -2670,8 +2672,8 @@ static IrInstruction *ir_instruction_ptrcast_get_dep(IrInstructionPtrCast *instr
26702672 size_t index)
26712673{
26722674 switch (index) {
2673 case 0: return instruction->dest_type;
2674 case 1: return instruction->ptr;
2675 case 0: return instruction->ptr;
2676 case 1: return instruction->dest_type;
26752677 default: return nullptr;
26762678 }
26772679}
......@@ -2686,6 +2688,7 @@ static IrInstruction *ir_instruction_widenorshorten_get_dep(IrInstructionWidenOr
26862688static IrInstruction *ir_instruction_inttoptr_get_dep(IrInstructionIntToPtr *instruction, size_t index) {
26872689 switch (index) {
26882690 case 0: return instruction->target;
2691 case 1: return instruction->dest_type;
26892692 default: return nullptr;
26902693 }
26912694}
......@@ -4222,6 +4225,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
42224225
42234226 return ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
42244227 }
4228 case BuiltinFnIdIntToPtr:
4229 {
4230 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4231 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4232 if (arg0_value == irb->codegen->invalid_instruction)
4233 return arg0_value;
4234
4235 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4236 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4237 if (arg1_value == irb->codegen->invalid_instruction)
4238 return arg1_value;
4239
4240 return ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value);
4241 }
42254242 }
42264243 zig_unreachable();
42274244}
......@@ -5821,10 +5838,19 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
58215838 }
58225839
58235840 // implicit number literal to typed number
5824 if ((actual_type->id == TypeTableEntryIdNumLitFloat ||
5825 actual_type->id == TypeTableEntryIdNumLitInt))
5841 // implicit number literal to &const integer
5842 if (actual_type->id == TypeTableEntryIdNumLitFloat ||
5843 actual_type->id == TypeTableEntryIdNumLitInt)
58265844 {
5827 if (ir_num_lit_fits_in_other_type(ira, value, expected_type)) {
5845 if (expected_type->id == TypeTableEntryIdPointer &&
5846 expected_type->data.pointer.is_const)
5847 {
5848 if (ir_num_lit_fits_in_other_type(ira, value, expected_type->data.pointer.child_type)) {
5849 return ImplicitCastMatchResultYes;
5850 } else {
5851 return ImplicitCastMatchResultReportedError;
5852 }
5853 } else if (ir_num_lit_fits_in_other_type(ira, value, expected_type)) {
58285854 return ImplicitCastMatchResultYes;
58295855 } else {
58305856 return ImplicitCastMatchResultReportedError;
......@@ -6651,47 +6677,6 @@ static IrInstruction *ir_analyze_ptr_to_int(IrAnalyze *ira, IrInstruction *sourc
66516677 return result;
66526678}
66536679
6654static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr,
6655 IrInstruction *target, TypeTableEntry *wanted_type)
6656{
6657 assert(wanted_type->id == TypeTableEntryIdPointer);
6658
6659 if (instr_is_comptime(target)) {
6660 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
6661 if (!val)
6662 return ira->codegen->invalid_instruction;
6663 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
6664 source_instr->source_node, wanted_type);
6665 result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
6666 result->value.data.x_ptr.data.hard_coded_addr.addr = bignum_to_twos_complement(&val->data.x_bignum);
6667 return result;
6668 }
6669
6670 IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, source_instr->scope,
6671 source_instr->source_node, target);
6672 result->value.type = wanted_type;
6673 return result;
6674}
6675
6676static IrInstruction *ir_analyze_int_lit_to_ptr(IrAnalyze *ira, IrInstruction *source_instr,
6677 IrInstruction *target, TypeTableEntry *wanted_type)
6678{
6679 assert(wanted_type->id == TypeTableEntryIdPointer);
6680
6681 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
6682 if (!val)
6683 return ira->codegen->invalid_instruction;
6684
6685 TypeTableEntry *usize_type = ira->codegen->builtin_types.entry_usize;
6686 if (!ir_num_lit_fits_in_other_type(ira, target, usize_type))
6687 return ira->codegen->invalid_instruction;
6688
6689 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
6690 source_instr->source_node, wanted_type);
6691 result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
6692 result->value.data.x_ptr.data.hard_coded_addr.addr = bignum_to_twos_complement(&val->data.x_bignum);
6693 return result;
6694}
66956680
66966681static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *source_instr,
66976682 IrInstruction *target, TypeTableEntry *wanted_type)
......@@ -6815,7 +6800,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
68156800 TypeTableEntry *wanted_type_canon = get_underlying_type(wanted_type);
68166801 TypeTableEntry *actual_type_canon = get_underlying_type(actual_type);
68176802
6818 TypeTableEntry *isize_type = ira->codegen->builtin_types.entry_isize;
68196803 TypeTableEntry *usize_type = ira->codegen->builtin_types.entry_usize;
68206804
68216805 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
68376821 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBoolToInt, false);
68386822 }
68396823
6840 // explicit cast from pointer to isize or usize
6841 if ((wanted_type_canon == isize_type || wanted_type_canon == usize_type) &&
6842 type_is_codegen_pointer(actual_type_canon))
6843 {
6824 // explicit cast from pointer to usize
6825 if (wanted_type_canon == usize_type && type_is_codegen_pointer(actual_type_canon)) {
68446826 return ir_analyze_ptr_to_int(ira, source_instr, value, wanted_type);
68456827 }
68466828
6847
6848 // explicit cast from isize or usize to pointer
6849 if (wanted_type_canon->id == TypeTableEntryIdPointer &&
6850 (actual_type_canon == isize_type || actual_type_canon == usize_type))
6851 {
6852 return ir_analyze_int_to_ptr(ira, source_instr, value, wanted_type);
6853 }
6854
6855 // explicit cast from number literal to pointer
6856 if (wanted_type_canon->id == TypeTableEntryIdPointer &&
6857 (actual_type_canon->id == TypeTableEntryIdNumLitInt))
6858 {
6859 return ir_analyze_int_lit_to_ptr(ira, source_instr, value, wanted_type);
6860 }
6861
68626829 // explicit widening or shortening cast
68636830 if ((wanted_type_canon->id == TypeTableEntryIdInt &&
68646831 actual_type_canon->id == TypeTableEntryIdInt) ||
......@@ -6970,10 +6937,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
69706937 }
69716938
69726939 // explicit cast from number literal to another type
6940 // explicit cast from number literal to &const integer
69736941 if (actual_type->id == TypeTableEntryIdNumLitFloat ||
69746942 actual_type->id == TypeTableEntryIdNumLitInt)
69756943 {
6976 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type_canon)) {
6944 if (wanted_type->id == TypeTableEntryIdPointer &&
6945 wanted_type->data.pointer.is_const)
6946 {
6947 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
6948 if (type_is_invalid(cast1->value.type))
6949 return ira->codegen->invalid_instruction;
6950
6951 IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
6952 if (type_is_invalid(cast2->value.type))
6953 return ira->codegen->invalid_instruction;
6954
6955 return cast2;
6956 } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type_canon)) {
69776957 CastOp op;
69786958 if ((actual_type->id == TypeTableEntryIdNumLitFloat &&
69796959 wanted_type_canon->id == TypeTableEntryIdFloat) ||
......@@ -12304,12 +12284,6 @@ static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructio
1230412284 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
1230512285}
1230612286
12307static bool is_ptr_type(TypeTableEntry *t) {
12308 return (t->id == TypeTableEntryIdPointer || t->id == TypeTableEntryIdFn ||
12309 (t->id == TypeTableEntryIdMaybe && (t->data.maybe.child_type->id == TypeTableEntryIdPointer ||
12310 t->data.maybe.child_type->id == TypeTableEntryIdFn)));
12311}
12312
1231312287static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
1231412288 IrInstruction *dest_type_value = instruction->dest_type->other;
1231512289 TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
......@@ -12321,12 +12295,12 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc
1232112295 if (type_is_invalid(src_type))
1232212296 return ira->codegen->builtin_types.entry_invalid;
1232312297
12324 if (!is_ptr_type(src_type)) {
12298 if (!type_is_codegen_pointer(src_type)) {
1232512299 ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
1232612300 return ira->codegen->builtin_types.entry_invalid;
1232712301 }
1232812302
12329 if (!is_ptr_type(dest_type)) {
12303 if (!type_is_codegen_pointer(dest_type)) {
1233012304 ir_add_error(ira, dest_type_value,
1233112305 buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
1233212306 return ira->codegen->builtin_types.entry_invalid;
......@@ -12350,6 +12324,42 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc
1235012324 return dest_type;
1235112325}
1235212326
12327static TypeTableEntry *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) {
12328 IrInstruction *dest_type_value = instruction->dest_type->other;
12329 TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
12330 if (type_is_invalid(dest_type))
12331 return ira->codegen->builtin_types.entry_invalid;
12332
12333 if (!type_is_codegen_pointer(dest_type)) {
12334 ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
12335 return ira->codegen->builtin_types.entry_invalid;
12336 }
12337
12338 IrInstruction *target = instruction->target->other;
12339 if (type_is_invalid(target->value.type))
12340 return ira->codegen->builtin_types.entry_invalid;
12341
12342 IrInstruction *casted_int = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_usize);
12343 if (type_is_invalid(casted_int->value.type))
12344 return ira->codegen->builtin_types.entry_invalid;
12345
12346 if (instr_is_comptime(casted_int)) {
12347 ConstExprValue *val = ir_resolve_const(ira, casted_int, UndefBad);
12348 if (!val)
12349 return ira->codegen->builtin_types.entry_invalid;
12350
12351 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
12352 out_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
12353 out_val->data.x_ptr.data.hard_coded_addr.addr = bignum_to_twos_complement(&val->data.x_bignum);
12354 return dest_type;
12355 }
12356
12357 IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, instruction->base.scope,
12358 instruction->base.source_node, nullptr, casted_int);
12359 ir_link_new_instruction(result, &instruction->base);
12360 return dest_type;
12361}
12362
1235312363static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
1235412364 IrInstructionDeclRef *instruction)
1235512365{
......@@ -12424,8 +12434,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1242412434 switch (instruction->id) {
1242512435 case IrInstructionIdInvalid:
1242612436 case IrInstructionIdWidenOrShorten:
12427 case IrInstructionIdIntToPtr:
12428 case IrInstructionIdPtrToInt:
1242912437 case IrInstructionIdIntToEnum:
1243012438 case IrInstructionIdIntToErr:
1243112439 case IrInstructionIdErrToInt:
......@@ -12433,6 +12441,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1243312441 case IrInstructionIdStructFieldPtr:
1243412442 case IrInstructionIdEnumFieldPtr:
1243512443 case IrInstructionIdInitEnum:
12444 case IrInstructionIdPtrToInt:
1243612445 zig_unreachable();
1243712446 case IrInstructionIdReturn:
1243812447 return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction);
......@@ -12590,6 +12599,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1259012599 return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction);
1259112600 case IrInstructionIdPtrCast:
1259212601 return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction);
12602 case IrInstructionIdIntToPtr:
12603 return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction);
1259312604 case IrInstructionIdMaybeWrap:
1259412605 case IrInstructionIdErrWrapCode:
1259512606 case IrInstructionIdErrWrapPayload:
std/debug.zig+1-1
......@@ -68,7 +68,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
6868 var maybe_fp: ?&const u8 = @frameAddress();
6969 while (true) {
7070 const fp = maybe_fp ?? break;
71 const return_address = *(&const usize)(usize(fp) + @sizeOf(usize));
71 const return_address = *@intToPtr(&const usize, usize(fp) + @sizeOf(usize));
7272
7373 const compile_unit = findCompileUnit(st, return_address) ?? return error.MissingDebugInfo;
7474 const name = %return compile_unit.die.getAttrString(st, DW.AT_name);
std/hash_map.zig+8-9
......@@ -234,15 +234,14 @@ test "basicHashMapTest" {
234234 var map = HashMap(i32, i32, hash_i32, eql_i32).init(&debug.global_allocator);
235235 defer map.deinit();
236236
237 // TODO issue #311
238 assert(%%map.put(1, i32(11)) == null);
239 assert(%%map.put(2, i32(22)) == null);
240 assert(%%map.put(3, i32(33)) == null);
241 assert(%%map.put(4, i32(44)) == null);
242 assert(%%map.put(5, i32(55)) == null);
243
244 assert(??%%map.put(5, i32(66)) == 55);
245 assert(??%%map.put(5, i32(55)) == 66);
237 assert(%%map.put(1, 11) == null);
238 assert(%%map.put(2, 22) == null);
239 assert(%%map.put(3, 33) == null);
240 assert(%%map.put(4, 44) == null);
241 assert(%%map.put(5, 55) == null);
242
243 assert(??%%map.put(5, 66) == 55);
244 assert(??%%map.put(5, 55) == 66);
246245
247246 assert((??map.get(2)).value == 22);
248247 _ = map.remove(2);
test/cases/cast.zig+10-4
......@@ -1,15 +1,15 @@
11const assert = @import("std").debug.assert;
22const mem = @import("std").mem;
33
4test "intToPtrCast" {
5 const x = isize(13);
6 const y = (&u8)(x);
4test "int to ptr cast" {
5 const x = usize(13);
6 const y = @intToPtr(&u8, x);
77 const z = usize(y);
88 assert(z == 13);
99}
1010
1111test "numLitIntToPtrCast" {
12 const vga_mem = (&u16)(0xB8000);
12 const vga_mem = @intToPtr(&u16, 0xB8000);
1313 assert(usize(vga_mem) == 0xB8000);
1414}
1515
......@@ -64,3 +64,9 @@ fn testPeerResolveArrayConstSlice(b: bool) {
6464 assert(mem.eql(u8, value1, "aoeu"));
6565 assert(mem.eql(u8, value2, "zz"));
6666}
67
68
69test "integer literal to &const int" {
70 const x: &const i32 = 3;
71 assert(*x == 3);
72}
test/cases/misc.zig-8
......@@ -373,14 +373,6 @@ fn testTakeAddressOfParameter(f: f32) {
373373}
374374
375375
376test "intToPtrCast" {
377 const x = isize(13);
378 const y = (&u8)(x);
379 const z = usize(y);
380 assert(z == 13);
381}
382
383
384376test "pointerComparison" {
385377 const a = ([]const u8)("a");
386378 const b = &a;