| ... | ... | @@ -155,6 +155,8 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 155 | 155 | static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val); |
| 156 | 156 | static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node, |
| 157 | 157 | ConstExprValue *out_val, ConstExprValue *ptr_val); |
| 158 | static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, |
| 159 | ZigType *dest_type, IrInstruction *dest_type_src); |
| 158 | 160 | |
| 159 | 161 | static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { |
| 160 | 162 | assert(get_src_ptr_type(const_val->type) != nullptr); |
| ... | ... | @@ -8573,17 +8575,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted |
| 8573 | 8575 | return result; |
| 8574 | 8576 | } |
| 8575 | 8577 | |
| 8576 | | // *T and [*]T can always cast to *c_void |
| 8577 | | if (wanted_type->id == ZigTypeIdPointer && |
| 8578 | | wanted_type->data.pointer.ptr_len == PtrLenSingle && |
| 8579 | | wanted_type->data.pointer.child_type == g->builtin_types.entry_c_void && |
| 8580 | | actual_type->id == ZigTypeIdPointer && |
| 8581 | | (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && |
| 8582 | | (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) |
| 8583 | | { |
| 8584 | | return result; |
| 8585 | | } |
| 8586 | | |
| 8587 | 8578 | // pointer const |
| 8588 | 8579 | if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) { |
| 8589 | 8580 | ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, |
| ... | ... | @@ -11156,6 +11147,33 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 11156 | 11147 | } |
| 11157 | 11148 | } |
| 11158 | 11149 | |
| 11150 | // cast from *T and [*]T to *c_void and ?*c_void |
| 11151 | // but don't do it if the actual type is a double pointer |
| 11152 | if (actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.child_type->id != ZigTypeIdPointer) { |
| 11153 | ZigType *dest_ptr_type = nullptr; |
| 11154 | if (wanted_type->id == ZigTypeIdPointer && |
| 11155 | wanted_type->data.pointer.ptr_len == PtrLenSingle && |
| 11156 | wanted_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void) |
| 11157 | { |
| 11158 | dest_ptr_type = wanted_type; |
| 11159 | } else if (wanted_type->id == ZigTypeIdOptional && |
| 11160 | wanted_type->data.maybe.child_type->id == ZigTypeIdPointer && |
| 11161 | wanted_type->data.maybe.child_type->data.pointer.ptr_len == PtrLenSingle && |
| 11162 | wanted_type->data.maybe.child_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void) |
| 11163 | { |
| 11164 | dest_ptr_type = wanted_type->data.maybe.child_type; |
| 11165 | } |
| 11166 | if (dest_ptr_type != nullptr && |
| 11167 | (!actual_type->data.pointer.is_const || dest_ptr_type->data.pointer.is_const) && |
| 11168 | (!actual_type->data.pointer.is_volatile || dest_ptr_type->data.pointer.is_volatile) && |
| 11169 | actual_type->data.pointer.bit_offset == dest_ptr_type->data.pointer.bit_offset && |
| 11170 | actual_type->data.pointer.unaligned_bit_count == dest_ptr_type->data.pointer.unaligned_bit_count && |
| 11171 | get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, dest_ptr_type)) |
| 11172 | { |
| 11173 | return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr); |
| 11174 | } |
| 11175 | } |
| 11176 | |
| 11159 | 11177 | // cast from T to *T where T is zero bits |
| 11160 | 11178 | if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle && |
| 11161 | 11179 | types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, |
| ... | ... | @@ -20234,79 +20252,75 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 |
| 20234 | 20252 | return result; |
| 20235 | 20253 | } |
| 20236 | 20254 | |
| 20237 | | static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { |
| 20255 | static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, |
| 20256 | ZigType *dest_type, IrInstruction *dest_type_src) |
| 20257 | { |
| 20238 | 20258 | Error err; |
| 20239 | 20259 | |
| 20240 | | IrInstruction *dest_type_value = instruction->dest_type->other; |
| 20241 | | ZigType *dest_type = ir_resolve_type(ira, dest_type_value); |
| 20242 | | if (type_is_invalid(dest_type)) |
| 20243 | | return ira->codegen->builtin_types.entry_invalid; |
| 20244 | | |
| 20245 | | IrInstruction *ptr = instruction->ptr->other; |
| 20246 | 20260 | ZigType *src_type = ptr->value.type; |
| 20247 | | if (type_is_invalid(src_type)) |
| 20248 | | return ira->codegen->builtin_types.entry_invalid; |
| 20261 | assert(!type_is_invalid(src_type)); |
| 20249 | 20262 | |
| 20250 | 20263 | // We have a check for zero bits later so we use get_src_ptr_type to |
| 20251 | 20264 | // validate src_type and dest_type. |
| 20252 | 20265 | |
| 20253 | 20266 | if (get_src_ptr_type(src_type) == nullptr) { |
| 20254 | 20267 | ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); |
| 20255 | | return ira->codegen->builtin_types.entry_invalid; |
| 20268 | return ira->codegen->invalid_instruction; |
| 20256 | 20269 | } |
| 20257 | 20270 | |
| 20258 | 20271 | if (get_src_ptr_type(dest_type) == nullptr) { |
| 20259 | | ir_add_error(ira, dest_type_value, |
| 20272 | ir_add_error(ira, dest_type_src, |
| 20260 | 20273 | buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); |
| 20261 | | return ira->codegen->builtin_types.entry_invalid; |
| 20274 | return ira->codegen->invalid_instruction; |
| 20262 | 20275 | } |
| 20263 | 20276 | |
| 20264 | 20277 | if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) { |
| 20265 | | ir_add_error(ira, &instruction->base, buf_sprintf("cast discards const qualifier")); |
| 20266 | | return ira->codegen->builtin_types.entry_invalid; |
| 20278 | ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier")); |
| 20279 | return ira->codegen->invalid_instruction; |
| 20267 | 20280 | } |
| 20268 | 20281 | |
| 20269 | 20282 | if (instr_is_comptime(ptr)) { |
| 20270 | 20283 | ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk); |
| 20271 | 20284 | if (!val) |
| 20272 | | return ira->codegen->builtin_types.entry_invalid; |
| 20285 | return ira->codegen->invalid_instruction; |
| 20273 | 20286 | |
| 20274 | | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 20275 | | copy_const_val(out_val, val, false); |
| 20276 | | out_val->type = dest_type; |
| 20277 | | return dest_type; |
| 20287 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, |
| 20288 | dest_type); |
| 20289 | copy_const_val(&result->value, val, false); |
| 20290 | result->value.type = dest_type; |
| 20291 | return result; |
| 20278 | 20292 | } |
| 20279 | 20293 | |
| 20280 | 20294 | uint32_t src_align_bytes; |
| 20281 | 20295 | if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes))) |
| 20282 | | return ira->codegen->builtin_types.entry_invalid; |
| 20296 | return ira->codegen->invalid_instruction; |
| 20283 | 20297 | |
| 20284 | 20298 | uint32_t dest_align_bytes; |
| 20285 | 20299 | if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes))) |
| 20286 | | return ira->codegen->builtin_types.entry_invalid; |
| 20300 | return ira->codegen->invalid_instruction; |
| 20287 | 20301 | |
| 20288 | 20302 | if (dest_align_bytes > src_align_bytes) { |
| 20289 | | ErrorMsg *msg = ir_add_error(ira, &instruction->base, buf_sprintf("cast increases pointer alignment")); |
| 20303 | ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment")); |
| 20290 | 20304 | add_error_note(ira->codegen, msg, ptr->source_node, |
| 20291 | 20305 | buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_type->name), src_align_bytes)); |
| 20292 | | add_error_note(ira->codegen, msg, dest_type_value->source_node, |
| 20306 | add_error_note(ira->codegen, msg, dest_type_src->source_node, |
| 20293 | 20307 | buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_type->name), dest_align_bytes)); |
| 20294 | | return ira->codegen->builtin_types.entry_invalid; |
| 20308 | return ira->codegen->invalid_instruction; |
| 20295 | 20309 | } |
| 20296 | 20310 | |
| 20297 | | IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, instruction->base.scope, |
| 20298 | | instruction->base.source_node, nullptr, ptr); |
| 20311 | IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope, |
| 20312 | source_instr->source_node, nullptr, ptr); |
| 20299 | 20313 | casted_ptr->value.type = dest_type; |
| 20300 | 20314 | |
| 20301 | 20315 | if (type_has_bits(dest_type) && !type_has_bits(src_type)) { |
| 20302 | | ErrorMsg *msg = ir_add_error(ira, &instruction->base, |
| 20316 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| 20303 | 20317 | buf_sprintf("'%s' and '%s' do not have the same in-memory representation", |
| 20304 | 20318 | buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); |
| 20305 | 20319 | add_error_note(ira->codegen, msg, ptr->source_node, |
| 20306 | 20320 | buf_sprintf("'%s' has no in-memory bits", buf_ptr(&src_type->name))); |
| 20307 | | add_error_note(ira->codegen, msg, dest_type_value->source_node, |
| 20321 | add_error_note(ira->codegen, msg, dest_type_src->source_node, |
| 20308 | 20322 | buf_sprintf("'%s' has in-memory bits", buf_ptr(&dest_type->name))); |
| 20309 | | return ira->codegen->builtin_types.entry_invalid; |
| 20323 | return ira->codegen->invalid_instruction; |
| 20310 | 20324 | } |
| 20311 | 20325 | |
| 20312 | 20326 | // Keep the bigger alignment, it can only help- |
| ... | ... | @@ -20315,10 +20329,28 @@ static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtr |
| 20315 | 20329 | if (src_align_bytes > dest_align_bytes && type_has_bits(dest_type)) { |
| 20316 | 20330 | result = ir_align_cast(ira, casted_ptr, src_align_bytes, false); |
| 20317 | 20331 | if (type_is_invalid(result->value.type)) |
| 20318 | | return ira->codegen->builtin_types.entry_invalid; |
| 20332 | return ira->codegen->invalid_instruction; |
| 20319 | 20333 | } else { |
| 20320 | 20334 | result = casted_ptr; |
| 20321 | 20335 | } |
| 20336 | return result; |
| 20337 | } |
| 20338 | |
| 20339 | static ZigType *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) { |
| 20340 | IrInstruction *dest_type_value = instruction->dest_type->other; |
| 20341 | ZigType *dest_type = ir_resolve_type(ira, dest_type_value); |
| 20342 | if (type_is_invalid(dest_type)) |
| 20343 | return ira->codegen->builtin_types.entry_invalid; |
| 20344 | |
| 20345 | IrInstruction *ptr = instruction->ptr->other; |
| 20346 | ZigType *src_type = ptr->value.type; |
| 20347 | if (type_is_invalid(src_type)) |
| 20348 | return ira->codegen->builtin_types.entry_invalid; |
| 20349 | |
| 20350 | IrInstruction *result = ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value); |
| 20351 | if (type_is_invalid(result->value.type)) |
| 20352 | return ira->codegen->builtin_types.entry_invalid; |
| 20353 | |
| 20322 | 20354 | ir_link_new_instruction(result, &instruction->base); |
| 20323 | 20355 | return result->value.type; |
| 20324 | 20356 | } |