mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
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
This commit is contained in:
parent
ffb4852012
commit
f7e9d7aa5d
@ -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)`.
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
171
src/ir.cpp
171
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:
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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(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, i32(66)) == 55);
|
||||
assert(??%%map.put(5, i32(55)) == 66);
|
||||
assert(??%%map.put(5, 66) == 55);
|
||||
assert(??%%map.put(5, 55) == 66);
|
||||
|
||||
assert((??map.get(2)).value == 22);
|
||||
_ = map.remove(2);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user