Merge remote-tracking branch 'origin/master' into rewrite-coroutines
This commit is contained in:
commit
b3b6a98451
|
@ -209,7 +209,7 @@ else()
|
|||
else()
|
||||
set(ZIG_LLD_COMPILE_FLAGS "-std=c++11 -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -Wno-comment")
|
||||
if(MINGW)
|
||||
set(ZIG_LLD_COMPILE_FLAGS "${ZIG_LLD_COMPILE_FLAGS} -D__STDC_FORMAT_MACROS -D__USE_MINGW_ANSI_STDIO -Wno-pedantic-ms-format")
|
||||
set(ZIG_LLD_COMPILE_FLAGS "${ZIG_LLD_COMPILE_FLAGS} -D__STDC_FORMAT_MACROS -D__USE_MINGW_ANSI_STDIO")
|
||||
endif()
|
||||
endif()
|
||||
set_target_properties(embedded_lld_lib PROPERTIES
|
||||
|
@ -511,19 +511,23 @@ set(OPTIMIZED_C_FLAGS "-std=c99 -O3")
|
|||
|
||||
set(EXE_LDFLAGS " ")
|
||||
if(MSVC)
|
||||
set(EXE_LDFLAGS "/STACK:16777216")
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} /STACK:16777216")
|
||||
elseif(MINGW)
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -Wl,--stack,16777216")
|
||||
endif()
|
||||
|
||||
if(ZIG_STATIC)
|
||||
if(APPLE)
|
||||
set(EXE_LDFLAGS "-static-libgcc -static-libstdc++")
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -static-libgcc -static-libstdc++")
|
||||
elseif(MINGW)
|
||||
set(EXE_LDFLAGS "-static-libgcc -static-libstdc++ -Wl,-Bstatic,--whole-archive -lwinpthread -lz3 -lz -lgomp -Wl,--no-whole-archive")
|
||||
else()
|
||||
set(EXE_LDFLAGS "-static")
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -static-libgcc -static-libstdc++ -Wl,-Bstatic, -lwinpthread -lz3 -lz -lgomp")
|
||||
elseif(NOT MSVC)
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -static")
|
||||
endif()
|
||||
else()
|
||||
if(MINGW)
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -lz3")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ZIG_TEST_COVERAGE)
|
||||
|
@ -559,11 +563,6 @@ if(NOT MSVC)
|
|||
target_link_libraries(compiler LINK_PUBLIC ${LIBXML2})
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
find_library(Z3_LIBRARIES NAMES z3 z3.dll)
|
||||
target_link_libraries(compiler LINK_PUBLIC ${Z3_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(ZIG_DIA_GUIDS_LIB)
|
||||
target_link_libraries(compiler LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB})
|
||||
endif()
|
||||
|
|
|
@ -2529,6 +2529,7 @@ struct IrInstructionLoadPtrGen {
|
|||
struct IrInstructionStorePtr {
|
||||
IrInstruction base;
|
||||
|
||||
bool allow_write_through_const;
|
||||
IrInstruction *ptr;
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
@ -3630,6 +3631,7 @@ enum ResultLocId {
|
|||
struct ResultLoc {
|
||||
ResultLocId id;
|
||||
bool written;
|
||||
bool allow_write_through_const;
|
||||
IrInstruction *resolved_loc; // result ptr
|
||||
IrInstruction *source_instruction;
|
||||
IrInstruction *gen_instruction; // value to store to the result loc
|
||||
|
|
|
@ -4355,8 +4355,14 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn
|
|||
return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, "");
|
||||
}
|
||||
|
||||
// When the cmpxchg is discarded, the result location will have no bits.
|
||||
if (!type_has_bits(instruction->result_loc->value.type)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
|
||||
assert(type_has_bits(child_type));
|
||||
src_assert(result_loc != nullptr, instruction->base.source_node);
|
||||
src_assert(type_has_bits(child_type), instruction->base.source_node);
|
||||
|
||||
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
|
||||
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, "");
|
||||
|
|
129
src/ir.cpp
129
src/ir.cpp
|
@ -188,7 +188,8 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_
|
|||
static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr,
|
||||
ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, bool non_null_comptime);
|
||||
static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr,
|
||||
ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, bool non_null_comptime);
|
||||
ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime,
|
||||
bool non_null_comptime, bool allow_discard);
|
||||
static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *base_ptr, bool safety_check_on, bool initializing);
|
||||
static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
|
@ -196,7 +197,7 @@ static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruct
|
|||
static IrInstruction *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *base_ptr, bool initializing);
|
||||
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *ptr, IrInstruction *uncasted_value);
|
||||
IrInstruction *ptr, IrInstruction *uncasted_value, bool allow_write_through_const);
|
||||
static IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *union_type, IrInstruction *field_name, AstNode *expr_node,
|
||||
LVal lval, ResultLoc *parent_result_loc);
|
||||
|
@ -1564,7 +1565,7 @@ static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode
|
|||
return &unreachable_instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
static IrInstructionStorePtr *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *ptr, IrInstruction *value)
|
||||
{
|
||||
IrInstructionStorePtr *instruction = ir_build_instruction<IrInstructionStorePtr>(irb, scope, source_node);
|
||||
|
@ -1576,7 +1577,7 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *
|
|||
ir_ref_instruction(ptr, irb->current_basic_block);
|
||||
ir_ref_instruction(value, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
return instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
|
@ -3792,12 +3793,20 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *no
|
|||
|
||||
static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) {
|
||||
IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
|
||||
IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
|
||||
|
||||
if (lvalue == irb->codegen->invalid_instruction || rvalue == irb->codegen->invalid_instruction)
|
||||
if (lvalue == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1);
|
||||
result_loc_inst->base.id = ResultLocIdInstruction;
|
||||
result_loc_inst->base.source_instruction = lvalue;
|
||||
ir_ref_instruction(lvalue, irb->current_basic_block);
|
||||
ir_build_reset_result(irb, scope, node, &result_loc_inst->base);
|
||||
|
||||
IrInstruction *rvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op2, scope, LValNone,
|
||||
&result_loc_inst->base);
|
||||
if (rvalue == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
ir_build_store_ptr(irb, scope, node, lvalue, rvalue);
|
||||
return ir_build_const_void(irb, scope, node);
|
||||
}
|
||||
|
||||
|
@ -5836,6 +5845,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
|
|||
ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1);
|
||||
result_loc_inst->base.id = ResultLocIdInstruction;
|
||||
result_loc_inst->base.source_instruction = field_ptr;
|
||||
result_loc_inst->base.allow_write_through_const = true;
|
||||
ir_ref_instruction(field_ptr, irb->current_basic_block);
|
||||
ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base);
|
||||
|
||||
|
@ -5874,6 +5884,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
|
|||
ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1);
|
||||
result_loc_inst->base.id = ResultLocIdInstruction;
|
||||
result_loc_inst->base.source_instruction = elem_ptr;
|
||||
result_loc_inst->base.allow_write_through_const = true;
|
||||
ir_ref_instruction(elem_ptr, irb->current_basic_block);
|
||||
ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base);
|
||||
|
||||
|
@ -6431,7 +6442,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
|
|||
|
||||
ir_set_cursor_at_end_and_append_block(irb, continue_block);
|
||||
IrInstruction *new_index_val = ir_build_bin_op(irb, child_scope, node, IrBinOpAdd, index_val, one, false);
|
||||
ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val));
|
||||
ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val)->allow_write_through_const = true;
|
||||
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
|
||||
|
||||
IrInstruction *else_result = nullptr;
|
||||
|
@ -10344,7 +10355,8 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
|
|||
}
|
||||
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true,
|
||||
false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
|
@ -10804,7 +10816,7 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so
|
|||
}
|
||||
IrInstruction *result_loc_inst = nullptr;
|
||||
if (result_loc != nullptr) {
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
|
@ -10847,7 +10859,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
|
|||
IrInstruction *result_loc_inst;
|
||||
if (handle_is_ptr(wanted_type)) {
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
|
@ -10959,7 +10971,7 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
|
|||
IrInstruction *result_loc_inst;
|
||||
if (handle_is_ptr(wanted_type)) {
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
|
||||
result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
|
@ -11032,7 +11044,8 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
|
|||
|
||||
IrInstruction *result_loc;
|
||||
if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) {
|
||||
result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true, false);
|
||||
result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true,
|
||||
false, true);
|
||||
} else {
|
||||
result_loc = nullptr;
|
||||
}
|
||||
|
@ -11076,7 +11089,8 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
|
|||
if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false);
|
||||
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false);
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr,
|
||||
true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
|
@ -11732,7 +11746,8 @@ static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction *
|
|||
if (result_loc == nullptr) {
|
||||
result_loc = no_result_loc();
|
||||
}
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr, true, false);
|
||||
IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr,
|
||||
true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
|
@ -12334,7 +12349,8 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
|
|||
IrInstruction *result_loc_inst;
|
||||
if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
|
||||
if (result_loc == nullptr) result_loc = no_result_loc();
|
||||
result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr, true, false);
|
||||
result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr,
|
||||
true, false, true);
|
||||
if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) {
|
||||
return result_loc_inst;
|
||||
}
|
||||
|
@ -14072,7 +14088,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
|
|||
// instruction.
|
||||
assert(deref->value.special != ConstValSpecialRuntime);
|
||||
var_ptr->value.special = ConstValSpecialRuntime;
|
||||
ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref);
|
||||
ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref, false);
|
||||
}
|
||||
|
||||
if (var_ptr->value.special == ConstValSpecialStatic && var->mem_slot_index != SIZE_MAX) {
|
||||
|
@ -14556,7 +14572,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
|||
|
||||
if (peer_parent->peers.length == 1) {
|
||||
IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
|
||||
value_type, value, force_runtime, non_null_comptime);
|
||||
value_type, value, force_runtime, non_null_comptime, true);
|
||||
result_peer->suspend_pos.basic_block_index = SIZE_MAX;
|
||||
result_peer->suspend_pos.instruction_index = SIZE_MAX;
|
||||
if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
|
||||
|
@ -14576,7 +14592,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
|||
if (peer_parent->skipped) {
|
||||
if (non_null_comptime) {
|
||||
return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
|
||||
value_type, value, force_runtime, non_null_comptime);
|
||||
value_type, value, force_runtime, non_null_comptime, true);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -14594,7 +14610,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
|||
}
|
||||
|
||||
IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent,
|
||||
peer_parent->resolved_type, nullptr, force_runtime, non_null_comptime);
|
||||
peer_parent->resolved_type, nullptr, force_runtime, non_null_comptime, true);
|
||||
if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
|
||||
parent_result_loc->value.type->id == ZigTypeIdUnreachable)
|
||||
{
|
||||
|
@ -14644,7 +14660,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
|||
}
|
||||
|
||||
IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent,
|
||||
dest_type, bitcasted_value, force_runtime, non_null_comptime);
|
||||
dest_type, bitcasted_value, force_runtime, non_null_comptime, true);
|
||||
if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
|
||||
parent_result_loc->value.type->id == ZigTypeIdUnreachable)
|
||||
{
|
||||
|
@ -14673,8 +14689,15 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
|||
|
||||
static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr,
|
||||
ResultLoc *result_loc_pass1, ZigType *value_type, IrInstruction *value, bool force_runtime,
|
||||
bool non_null_comptime)
|
||||
bool non_null_comptime, bool allow_discard)
|
||||
{
|
||||
if (!allow_discard && result_loc_pass1->id == ResultLocIdInstruction &&
|
||||
instr_is_comptime(result_loc_pass1->source_instruction) &&
|
||||
result_loc_pass1->source_instruction->value.type->id == ZigTypeIdPointer &&
|
||||
result_loc_pass1->source_instruction->value.data.x_ptr.special == ConstPtrSpecialDiscard)
|
||||
{
|
||||
result_loc_pass1 = no_result_loc();
|
||||
}
|
||||
IrInstruction *result_loc = ir_resolve_result_raw(ira, suspend_source_instr, result_loc_pass1, value_type,
|
||||
value, force_runtime, non_null_comptime);
|
||||
if (result_loc == nullptr || (instr_is_unreachable(result_loc) || type_is_invalid(result_loc->value.type)))
|
||||
|
@ -14729,7 +14752,7 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn
|
|||
if (type_is_invalid(implicit_elem_type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
implicit_elem_type, nullptr, false, true);
|
||||
implicit_elem_type, nullptr, false, true, true);
|
||||
if (result_loc != nullptr)
|
||||
return result_loc;
|
||||
|
||||
|
@ -14738,7 +14761,7 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn
|
|||
instruction->result_loc->id == ResultLocIdReturn)
|
||||
{
|
||||
result_loc = ir_resolve_result(ira, &instruction->base, no_result_loc(),
|
||||
implicit_elem_type, nullptr, false, true);
|
||||
implicit_elem_type, nullptr, false, true, true);
|
||||
if (result_loc != nullptr &&
|
||||
(type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)))
|
||||
{
|
||||
|
@ -14800,7 +14823,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc
|
|||
|
||||
ZigType *frame_type = get_coro_frame_type(ira->codegen, fn_entry);
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
|
||||
frame_type, nullptr, true, true);
|
||||
frame_type, nullptr, true, true, false);
|
||||
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
|
||||
return result_loc;
|
||||
}
|
||||
|
@ -15015,7 +15038,7 @@ no_mem_slot:
|
|||
}
|
||||
|
||||
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *ptr, IrInstruction *uncasted_value)
|
||||
IrInstruction *ptr, IrInstruction *uncasted_value, bool allow_write_through_const)
|
||||
{
|
||||
assert(ptr->value.type->id == ZigTypeIdPointer);
|
||||
|
||||
|
@ -15031,7 +15054,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
|
|||
|
||||
ZigType *child_type = ptr->value.type->data.pointer.child_type;
|
||||
|
||||
if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
|
||||
if (ptr->value.type->data.pointer.is_const && !allow_write_through_const) {
|
||||
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
@ -15110,10 +15133,9 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
|
|||
break;
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
|
||||
ptr, value);
|
||||
result->value.type = ira->codegen->builtin_types.entry_void;
|
||||
return result;
|
||||
IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, ptr, value);
|
||||
return &store_ptr->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction,
|
||||
|
@ -15518,7 +15540,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
|||
IrInstruction *result_loc;
|
||||
if (handle_is_ptr(impl_fn_type_id->return_type)) {
|
||||
result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
|
||||
impl_fn_type_id->return_type, nullptr, true, true);
|
||||
impl_fn_type_id->return_type, nullptr, true, true, false);
|
||||
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) ||
|
||||
instr_is_unreachable(result_loc)))
|
||||
{
|
||||
|
@ -15635,7 +15657,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
|||
IrInstruction *result_loc;
|
||||
if (handle_is_ptr(return_type)) {
|
||||
result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
|
||||
return_type, nullptr, true, true);
|
||||
return_type, nullptr, true, true, false);
|
||||
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
|
||||
return result_loc;
|
||||
}
|
||||
|
@ -16154,7 +16176,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
|
|||
|
||||
// In case resolving the parent activates a suspend, do it now
|
||||
IrInstruction *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent,
|
||||
peer_parent->resolved_type, nullptr, false, false);
|
||||
peer_parent->resolved_type, nullptr, false, false, true);
|
||||
if (parent_result_loc != nullptr &&
|
||||
(type_is_invalid(parent_result_loc->value.type) || instr_is_unreachable(parent_result_loc)))
|
||||
{
|
||||
|
@ -16611,6 +16633,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
|
|||
return result;
|
||||
} else if (is_slice(array_type)) {
|
||||
ConstExprValue *ptr_field = &array_ptr_val->data.x_struct.fields[slice_ptr_index];
|
||||
ir_assert(ptr_field != nullptr, &elem_ptr_instruction->base);
|
||||
if (ptr_field->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
|
||||
IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope,
|
||||
elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, false,
|
||||
|
@ -16797,7 +16820,7 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction
|
|||
return ira->codegen->invalid_instruction;
|
||||
if (type_is_invalid(struct_val->type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (struct_val->special == ConstValSpecialUndef && initializing) {
|
||||
if (initializing && struct_val->special == ConstValSpecialUndef) {
|
||||
struct_val->data.x_struct.fields = create_const_vals(struct_type->data.structure.src_field_count);
|
||||
struct_val->special = ConstValSpecialStatic;
|
||||
for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {
|
||||
|
@ -17395,7 +17418,7 @@ static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstruc
|
|||
if (type_is_invalid(value->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
|
||||
return ir_analyze_store_ptr(ira, &instruction->base, ptr, value, instruction->allow_write_through_const);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) {
|
||||
|
@ -17899,7 +17922,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
|
|||
if (optional_val == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (initializing && optional_val->special == ConstValSpecialUndef) {
|
||||
if (initializing) {
|
||||
switch (type_has_one_possible_value(ira->codegen, child_type)) {
|
||||
case OnePossibleValueInvalid:
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
@ -18805,7 +18828,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
|
|||
|
||||
IrInstruction *field_ptr = ir_analyze_struct_field_ptr(ira, instruction, field, result_loc,
|
||||
container_type, true);
|
||||
ir_analyze_store_ptr(ira, instruction, field_ptr, runtime_inst);
|
||||
ir_analyze_store_ptr(ira, instruction, field_ptr, runtime_inst, false);
|
||||
if (instr_is_comptime(field_ptr) && field_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) {
|
||||
const_ptrs.append(field_ptr);
|
||||
} else {
|
||||
|
@ -18822,7 +18845,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
|
|||
IrInstruction *field_result_loc = const_ptrs.at(i);
|
||||
IrInstruction *deref = ir_get_deref(ira, field_result_loc, field_result_loc, nullptr);
|
||||
field_result_loc->value.special = ConstValSpecialRuntime;
|
||||
ir_analyze_store_ptr(ira, field_result_loc, field_result_loc, deref);
|
||||
ir_analyze_store_ptr(ira, field_result_loc, field_result_loc, deref, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18949,7 +18972,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
|
|||
assert(elem_result_loc->value.special == ConstValSpecialStatic);
|
||||
IrInstruction *deref = ir_get_deref(ira, elem_result_loc, elem_result_loc, nullptr);
|
||||
elem_result_loc->value.special = ConstValSpecialRuntime;
|
||||
ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref);
|
||||
ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20646,7 +20669,7 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
|
|||
IrInstruction *result_loc;
|
||||
if (handle_is_ptr(result_type)) {
|
||||
result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
result_type, nullptr, true, false);
|
||||
result_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
|
||||
return result_loc;
|
||||
}
|
||||
|
@ -20903,7 +20926,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru
|
|||
}
|
||||
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
dest_slice_type, nullptr, true, false);
|
||||
dest_slice_type, nullptr, true, false, true);
|
||||
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) {
|
||||
return result_loc;
|
||||
}
|
||||
|
@ -20980,7 +21003,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct
|
|||
}
|
||||
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
dest_slice_type, nullptr, true, false);
|
||||
dest_slice_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
|
||||
return result_loc;
|
||||
}
|
||||
|
@ -21722,7 +21745,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
|
|||
}
|
||||
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
return_type, nullptr, true, false);
|
||||
return_type, nullptr, true, false, true);
|
||||
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
|
||||
return result_loc;
|
||||
}
|
||||
|
@ -22405,7 +22428,7 @@ static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruct
|
|||
ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node);
|
||||
if (err_union_val == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (err_union_val->special == ConstValSpecialUndef && initializing) {
|
||||
if (initializing && err_union_val->special == ConstValSpecialUndef) {
|
||||
ConstExprValue *vals = create_const_vals(2);
|
||||
ConstExprValue *err_set_val = &vals[0];
|
||||
ConstExprValue *payload_val = &vals[1];
|
||||
|
@ -23700,10 +23723,11 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op
|
|||
operand_type->data.integral.bit_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (operand_type->data.integral.bit_count > ira->codegen->pointer_size_bytes * 8) {
|
||||
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
|
||||
if (operand_type->data.integral.bit_count > max_atomic_bits) {
|
||||
ir_add_error(ira, op,
|
||||
buf_sprintf("expected integer type pointer size or smaller, found %" PRIu32 "-bit integer type",
|
||||
operand_type->data.integral.bit_count));
|
||||
buf_sprintf("expected %" PRIu32 "-bit integer type or smaller, found %" PRIu32 "-bit integer type",
|
||||
max_atomic_bits, operand_type->data.integral.bit_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
if (!is_power_of_2(operand_type->data.integral.bit_count)) {
|
||||
|
@ -24293,7 +24317,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
|
|||
|
||||
bool was_written = instruction->result_loc->written;
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc,
|
||||
value->value.type, value, false, false);
|
||||
value->value.type, value, false, false, true);
|
||||
if (result_loc != nullptr) {
|
||||
if (type_is_invalid(result_loc->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
@ -24301,7 +24325,8 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
|
|||
return result_loc;
|
||||
|
||||
if (!was_written) {
|
||||
IrInstruction *store_ptr = ir_analyze_store_ptr(ira, &instruction->base, result_loc, value);
|
||||
IrInstruction *store_ptr = ir_analyze_store_ptr(ira, &instruction->base, result_loc, value,
|
||||
instruction->result_loc->allow_write_through_const);
|
||||
if (type_is_invalid(store_ptr->value.type)) {
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
@ -24325,7 +24350,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInst
|
|||
return operand;
|
||||
|
||||
IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base,
|
||||
&instruction->result_loc_bit_cast->base, operand->value.type, operand, false, false);
|
||||
&instruction->result_loc_bit_cast->base, operand->value.type, operand, false, false, true);
|
||||
if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)))
|
||||
return result_loc;
|
||||
|
||||
|
|
|
@ -863,6 +863,71 @@ uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch) {
|
|||
zig_unreachable();
|
||||
}
|
||||
|
||||
uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch) {
|
||||
switch (arch) {
|
||||
case ZigLLVM_UnknownArch:
|
||||
zig_unreachable();
|
||||
|
||||
case ZigLLVM_avr:
|
||||
case ZigLLVM_msp430:
|
||||
return 16;
|
||||
|
||||
case ZigLLVM_arc:
|
||||
case ZigLLVM_arm:
|
||||
case ZigLLVM_armeb:
|
||||
case ZigLLVM_hexagon:
|
||||
case ZigLLVM_le32:
|
||||
case ZigLLVM_mips:
|
||||
case ZigLLVM_mipsel:
|
||||
case ZigLLVM_nvptx:
|
||||
case ZigLLVM_ppc:
|
||||
case ZigLLVM_r600:
|
||||
case ZigLLVM_riscv32:
|
||||
case ZigLLVM_sparc:
|
||||
case ZigLLVM_sparcel:
|
||||
case ZigLLVM_tce:
|
||||
case ZigLLVM_tcele:
|
||||
case ZigLLVM_thumb:
|
||||
case ZigLLVM_thumbeb:
|
||||
case ZigLLVM_x86:
|
||||
case ZigLLVM_xcore:
|
||||
case ZigLLVM_amdil:
|
||||
case ZigLLVM_hsail:
|
||||
case ZigLLVM_spir:
|
||||
case ZigLLVM_kalimba:
|
||||
case ZigLLVM_lanai:
|
||||
case ZigLLVM_shave:
|
||||
case ZigLLVM_wasm32:
|
||||
case ZigLLVM_renderscript32:
|
||||
return 32;
|
||||
|
||||
case ZigLLVM_aarch64:
|
||||
case ZigLLVM_aarch64_be:
|
||||
case ZigLLVM_amdgcn:
|
||||
case ZigLLVM_bpfel:
|
||||
case ZigLLVM_bpfeb:
|
||||
case ZigLLVM_le64:
|
||||
case ZigLLVM_mips64:
|
||||
case ZigLLVM_mips64el:
|
||||
case ZigLLVM_nvptx64:
|
||||
case ZigLLVM_ppc64:
|
||||
case ZigLLVM_ppc64le:
|
||||
case ZigLLVM_riscv64:
|
||||
case ZigLLVM_sparcv9:
|
||||
case ZigLLVM_systemz:
|
||||
case ZigLLVM_amdil64:
|
||||
case ZigLLVM_hsail64:
|
||||
case ZigLLVM_spir64:
|
||||
case ZigLLVM_wasm64:
|
||||
case ZigLLVM_renderscript64:
|
||||
return 64;
|
||||
|
||||
case ZigLLVM_x86_64:
|
||||
return 128;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
|
||||
switch (target->os) {
|
||||
case OsFreestanding:
|
||||
|
@ -1693,3 +1758,4 @@ bool target_supports_libunwind(const ZigTarget *target) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -192,6 +192,7 @@ const char *target_arch_musl_name(ZigLLVM_ArchType arch);
|
|||
bool target_supports_libunwind(const ZigTarget *target);
|
||||
|
||||
uint32_t target_arch_pointer_bit_width(ZigLLVM_ArchType arch);
|
||||
uint32_t target_arch_largest_atomic_bits(ZigLLVM_ArchType arch);
|
||||
|
||||
size_t target_libc_count(void);
|
||||
void target_libc_enum(size_t index, ZigTarget *out_target);
|
||||
|
|
|
@ -1802,7 +1802,7 @@ pub const LibExeObjStep = struct {
|
|||
try zig_args.append("--bundle-compiler-rt");
|
||||
}
|
||||
if (self.disable_stack_probing) {
|
||||
try zig_args.append("--disable-stack-probing");
|
||||
try zig_args.append("-fno-stack-check");
|
||||
}
|
||||
|
||||
switch (self.target) {
|
||||
|
|
52
std/coff.zig
52
std/coff.zig
|
@ -19,6 +19,7 @@ const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
|
|||
const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
|
||||
|
||||
const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
|
||||
const IMAGE_DEBUG_TYPE_CODEVIEW = 2;
|
||||
const DEBUG_DIRECTORY = 6;
|
||||
|
||||
pub const CoffError = error{
|
||||
|
@ -28,6 +29,7 @@ pub const CoffError = error{
|
|||
MissingCoffSection,
|
||||
};
|
||||
|
||||
// Official documentation of the format: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||
pub const Coff = struct {
|
||||
in_file: File,
|
||||
allocator: *mem.Allocator,
|
||||
|
@ -120,16 +122,43 @@ pub const Coff = struct {
|
|||
|
||||
pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
|
||||
try self.loadSections();
|
||||
const header = (self.getSection(".rdata") orelse return error.MissingCoffSection).header;
|
||||
|
||||
// The linker puts a chunk that contains the .pdb path right after the
|
||||
// debug_directory.
|
||||
const header = blk: {
|
||||
if (self.getSection(".buildid")) |section| {
|
||||
break :blk section.header;
|
||||
} else if (self.getSection(".rdata")) |section| {
|
||||
break :blk section.header;
|
||||
} else {
|
||||
return error.MissingCoffSection;
|
||||
}
|
||||
};
|
||||
|
||||
const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];
|
||||
const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
|
||||
try self.in_file.seekTo(file_offset + debug_dir.size);
|
||||
|
||||
var file_stream = self.in_file.inStream();
|
||||
const in = &file_stream.stream;
|
||||
try self.in_file.seekTo(file_offset);
|
||||
|
||||
// Find the correct DebugDirectoryEntry, and where its data is stored.
|
||||
// It can be in any section.
|
||||
const debug_dir_entry_count = debug_dir.size / @sizeOf(DebugDirectoryEntry);
|
||||
var i: u32 = 0;
|
||||
blk: while (i < debug_dir_entry_count) : (i += 1) {
|
||||
const debug_dir_entry = try in.readStruct(DebugDirectoryEntry);
|
||||
if (debug_dir_entry.type == IMAGE_DEBUG_TYPE_CODEVIEW) {
|
||||
for (self.sections.toSlice()) |*section| {
|
||||
const section_start = section.header.virtual_address;
|
||||
const section_size = section.header.misc.virtual_size;
|
||||
const rva = debug_dir_entry.address_of_raw_data;
|
||||
const offset = rva - section_start;
|
||||
if (section_start <= rva and offset < section_size and debug_dir_entry.size_of_data <= section_size - offset) {
|
||||
try self.in_file.seekTo(section.header.pointer_to_raw_data + offset);
|
||||
break :blk;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cv_signature: [4]u8 = undefined; // CodeView signature
|
||||
try in.readNoEof(cv_signature[0..]);
|
||||
|
@ -141,7 +170,7 @@ pub const Coff = struct {
|
|||
|
||||
// Finally read the null-terminated string.
|
||||
var byte = try in.readByte();
|
||||
var i: usize = 0;
|
||||
i = 0;
|
||||
while (byte != 0 and i < buffer.len) : (i += 1) {
|
||||
buffer[i] = byte;
|
||||
byte = try in.readByte();
|
||||
|
@ -170,7 +199,7 @@ pub const Coff = struct {
|
|||
try self.sections.append(Section{
|
||||
.header = SectionHeader{
|
||||
.name = name,
|
||||
.misc = SectionHeader.Misc{ .physical_address = try in.readIntLittle(u32) },
|
||||
.misc = SectionHeader.Misc{ .virtual_size = try in.readIntLittle(u32) },
|
||||
.virtual_address = try in.readIntLittle(u32),
|
||||
.size_of_raw_data = try in.readIntLittle(u32),
|
||||
.pointer_to_raw_data = try in.readIntLittle(u32),
|
||||
|
@ -214,6 +243,17 @@ const OptionalHeader = struct {
|
|||
data_directory: [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]DataDirectory,
|
||||
};
|
||||
|
||||
const DebugDirectoryEntry = packed struct {
|
||||
characteristiccs: u32,
|
||||
time_date_stamp: u32,
|
||||
major_version: u16,
|
||||
minor_version: u16,
|
||||
@"type": u32,
|
||||
size_of_data: u32,
|
||||
address_of_raw_data: u32,
|
||||
pointer_to_raw_data: u32,
|
||||
};
|
||||
|
||||
pub const Section = struct {
|
||||
header: SectionHeader,
|
||||
};
|
||||
|
|
|
@ -375,7 +375,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
|
|||
const obj_basename = fs.path.basename(mod.obj_file_name);
|
||||
|
||||
var symbol_i: usize = 0;
|
||||
const symbol_name = while (symbol_i != mod.symbols.len) {
|
||||
const symbol_name = if (!mod.populated) "???" else while (symbol_i != mod.symbols.len) {
|
||||
const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
|
||||
if (prefix.RecordLen < 2)
|
||||
return error.InvalidDebugInfo;
|
||||
|
@ -858,8 +858,10 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
|||
const age = try pdb_stream.stream.readIntLittle(u32);
|
||||
var guid: [16]u8 = undefined;
|
||||
try pdb_stream.stream.readNoEof(guid[0..]);
|
||||
if (version != 20000404) // VC70, only value observed by LLVM team
|
||||
return error.UnknownPDBVersion;
|
||||
if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
|
||||
return error.InvalidDebugInfo;
|
||||
return error.PDBMismatch;
|
||||
// We validated the executable and pdb match.
|
||||
|
||||
const string_table_index = str_tab_index: {
|
||||
|
@ -903,13 +905,18 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
|
|||
return error.MissingDebugInfo;
|
||||
};
|
||||
|
||||
di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
|
||||
di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.MissingDebugInfo;
|
||||
di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
|
||||
|
||||
const dbi = di.pdb.dbi;
|
||||
|
||||
// Dbi Header
|
||||
const dbi_stream_header = try dbi.stream.readStruct(pdb.DbiStreamHeader);
|
||||
if (dbi_stream_header.VersionHeader != 19990903) // V70, only value observed by LLVM team
|
||||
return error.UnknownPDBVersion;
|
||||
if (dbi_stream_header.Age != age)
|
||||
return error.UnmatchingPDB;
|
||||
|
||||
const mod_info_size = dbi_stream_header.ModInfoSize;
|
||||
const section_contrib_size = dbi_stream_header.SectionContributionSize;
|
||||
|
||||
|
|
21
std/fmt.zig
21
std/fmt.zig
|
@ -371,9 +371,10 @@ pub fn formatType(
|
|||
return output(context, "{ ... }");
|
||||
}
|
||||
comptime var field_i = 0;
|
||||
try output(context, "{");
|
||||
inline while (field_i < @memberCount(T)) : (field_i += 1) {
|
||||
if (field_i == 0) {
|
||||
try output(context, "{ .");
|
||||
try output(context, " .");
|
||||
} else {
|
||||
try output(context, ", .");
|
||||
}
|
||||
|
@ -422,6 +423,9 @@ pub fn formatType(
|
|||
if (info.child == u8) {
|
||||
return formatText(value, fmt, options, context, Errors, output);
|
||||
}
|
||||
if (value.len == 0) {
|
||||
return format(context, Errors, output, "[0]{}", @typeName(T.Child));
|
||||
}
|
||||
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
|
||||
},
|
||||
.Fn => {
|
||||
|
@ -1436,6 +1440,21 @@ test "struct.self-referential" {
|
|||
try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);
|
||||
}
|
||||
|
||||
test "struct.zero-size" {
|
||||
const A = struct {
|
||||
fn foo() void {}
|
||||
};
|
||||
const B = struct {
|
||||
a: A,
|
||||
c: i32,
|
||||
};
|
||||
|
||||
const a = A{};
|
||||
const b = B{ .a = a, .c = 0 };
|
||||
|
||||
try testFmt("B{ .a = A{ }, .c = 0 }", "{}", b);
|
||||
}
|
||||
|
||||
test "bytes.hex" {
|
||||
const some_bytes = "\xCA\xFE\xBA\xBE";
|
||||
try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
|
||||
|
|
16
std/os.zig
16
std/os.zig
|
@ -2053,6 +2053,22 @@ pub fn accessC(path: [*]const u8, mode: u32) AccessError!void {
|
|||
}
|
||||
}
|
||||
|
||||
/// Call from Windows-specific code if you already have a UTF-16LE encoded, null terminated string.
|
||||
/// Otherwise use `access` or `accessC`.
|
||||
/// TODO currently this ignores `mode`.
|
||||
pub fn accessW(path: [*]const u16, mode: u32) windows.GetFileAttributesError!void {
|
||||
const ret = try windows.GetFileAttributesW(path);
|
||||
if (ret != windows.INVALID_FILE_ATTRIBUTES) {
|
||||
return;
|
||||
}
|
||||
switch (windows.kernel32.GetLastError()) {
|
||||
windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
|
||||
windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
|
||||
windows.ERROR.ACCESS_DENIED => return error.PermissionDenied,
|
||||
else => |err| return windows.unexpectedError(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub const PipeError = error{
|
||||
SystemFdQuotaExceeded,
|
||||
ProcessFdQuotaExceeded,
|
||||
|
|
117
std/pdb.zig
117
std/pdb.zig
|
@ -499,45 +499,78 @@ const Msf = struct {
|
|||
|
||||
const superblock = try in.readStruct(SuperBlock);
|
||||
|
||||
// Sanity checks
|
||||
if (!mem.eql(u8, superblock.FileMagic, SuperBlock.file_magic))
|
||||
return error.InvalidDebugInfo;
|
||||
|
||||
if (superblock.FreeBlockMapBlock != 1 and superblock.FreeBlockMapBlock != 2)
|
||||
return error.InvalidDebugInfo;
|
||||
if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
|
||||
return error.InvalidDebugInfo;
|
||||
switch (superblock.BlockSize) {
|
||||
// llvm only supports 4096 but we can handle any of these values
|
||||
512, 1024, 2048, 4096 => {},
|
||||
else => return error.InvalidDebugInfo,
|
||||
}
|
||||
|
||||
if (superblock.NumBlocks * superblock.BlockSize != try file.getEndPos())
|
||||
return error.InvalidDebugInfo;
|
||||
const dir_block_count = blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize);
|
||||
if (dir_block_count > superblock.BlockSize / @sizeOf(u32))
|
||||
return error.UnhandledBigDirectoryStream; // cf. BlockMapAddr comment.
|
||||
|
||||
self.directory = try MsfStream.init(
|
||||
try file.seekTo(superblock.BlockSize * superblock.BlockMapAddr);
|
||||
var dir_blocks = try allocator.alloc(u32, dir_block_count);
|
||||
for (dir_blocks) |*b| {
|
||||
b.* = try in.readIntLittle(u32);
|
||||
}
|
||||
self.directory = MsfStream.init(
|
||||
superblock.BlockSize,
|
||||
blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize),
|
||||
superblock.BlockSize * superblock.BlockMapAddr,
|
||||
file,
|
||||
allocator,
|
||||
dir_blocks,
|
||||
);
|
||||
|
||||
const begin = self.directory.pos;
|
||||
const stream_count = try self.directory.stream.readIntLittle(u32);
|
||||
|
||||
const stream_sizes = try allocator.alloc(u32, stream_count);
|
||||
for (stream_sizes) |*s| {
|
||||
defer allocator.free(stream_sizes);
|
||||
|
||||
// Microsoft's implementation uses u32(-1) for inexistant streams.
|
||||
// These streams are not used, but still participate in the file
|
||||
// and must be taken into account when resolving stream indices.
|
||||
const Nil = 0xFFFFFFFF;
|
||||
for (stream_sizes) |*s, i| {
|
||||
const size = try self.directory.stream.readIntLittle(u32);
|
||||
s.* = blockCountFromSize(size, superblock.BlockSize);
|
||||
s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.BlockSize);
|
||||
}
|
||||
|
||||
self.streams = try allocator.alloc(MsfStream, stream_count);
|
||||
for (self.streams) |*stream, i| {
|
||||
stream.* = try MsfStream.init(
|
||||
superblock.BlockSize,
|
||||
stream_sizes[i],
|
||||
// MsfStream.init expects the file to be at the part where it reads [N]u32
|
||||
try file.getPos(),
|
||||
file,
|
||||
allocator,
|
||||
);
|
||||
const size = stream_sizes[i];
|
||||
if (size == 0) {
|
||||
stream.* = MsfStream{
|
||||
.blocks = [_]u32{},
|
||||
};
|
||||
} else {
|
||||
var blocks = try allocator.alloc(u32, size);
|
||||
var j: u32 = 0;
|
||||
while (j < size) : (j += 1) {
|
||||
const block_id = try self.directory.stream.readIntLittle(u32);
|
||||
const n = (block_id % superblock.BlockSize);
|
||||
// 0 is for SuperBlock, 1 and 2 for FPMs.
|
||||
if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.BlockSize > try file.getEndPos())
|
||||
return error.InvalidBlockIndex;
|
||||
blocks[j] = block_id;
|
||||
}
|
||||
|
||||
stream.* = MsfStream.init(
|
||||
superblock.BlockSize,
|
||||
file,
|
||||
blocks,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const end = self.directory.pos;
|
||||
if (end - begin != superblock.NumDirectoryBytes)
|
||||
return error.InvalidStreamDirectory;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -574,7 +607,6 @@ const SuperBlock = packed struct {
|
|||
NumDirectoryBytes: u32,
|
||||
|
||||
Unknown: u32,
|
||||
|
||||
/// The index of a block within the MSF file. At this block is an array of
|
||||
/// ulittle32_t’s listing the blocks that the stream directory resides on.
|
||||
/// For large MSF files, the stream directory (which describes the block
|
||||
|
@ -584,45 +616,41 @@ const SuperBlock = packed struct {
|
|||
/// and the stream directory itself can be stitched together accordingly.
|
||||
/// The number of ulittle32_t’s in this array is given by
|
||||
/// ceil(NumDirectoryBytes / BlockSize).
|
||||
// Note: microsoft-pdb code actually suggests this is a variable-length
|
||||
// array. If the indices of blocks occupied by the Stream Directory didn't
|
||||
// fit in one page, there would be other u32 following it.
|
||||
// This would mean the Stream Directory is bigger than BlockSize / sizeof(u32)
|
||||
// blocks. We're not even close to this with a 1GB pdb file, and LLVM didn't
|
||||
// implement it so we're kind of safe making this assumption for now.
|
||||
BlockMapAddr: u32,
|
||||
};
|
||||
|
||||
const MsfStream = struct {
|
||||
in_file: File,
|
||||
pos: u64,
|
||||
blocks: []u32,
|
||||
block_size: u32,
|
||||
in_file: File = undefined,
|
||||
pos: u64 = undefined,
|
||||
blocks: []u32 = undefined,
|
||||
block_size: u32 = undefined,
|
||||
|
||||
/// Implementation of InStream trait for Pdb.MsfStream
|
||||
stream: Stream,
|
||||
stream: Stream = undefined,
|
||||
|
||||
pub const Error = @typeOf(read).ReturnType.ErrorSet;
|
||||
pub const Stream = io.InStream(Error);
|
||||
|
||||
fn init(block_size: u32, block_count: u32, pos: u64, file: File, allocator: *mem.Allocator) !MsfStream {
|
||||
var stream = MsfStream{
|
||||
fn init(block_size: u32, file: File, blocks: []u32) MsfStream {
|
||||
const stream = MsfStream{
|
||||
.in_file = file,
|
||||
.pos = 0,
|
||||
.blocks = try allocator.alloc(u32, block_count),
|
||||
.blocks = blocks,
|
||||
.block_size = block_size,
|
||||
.stream = Stream{ .readFn = readFn },
|
||||
};
|
||||
|
||||
var file_stream = file.inStream();
|
||||
const in = &file_stream.stream;
|
||||
try file.seekTo(pos);
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < block_count) : (i += 1) {
|
||||
stream.blocks[i] = try in.readIntLittle(u32);
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
|
||||
var list = ArrayList(u8).init(allocator);
|
||||
defer list.deinit();
|
||||
while (true) {
|
||||
const byte = try self.stream.readByte();
|
||||
if (byte == 0) {
|
||||
|
@ -642,11 +670,12 @@ const MsfStream = struct {
|
|||
const in = &file_stream.stream;
|
||||
|
||||
var size: usize = 0;
|
||||
for (buffer) |*byte| {
|
||||
byte.* = try in.readByte();
|
||||
|
||||
offset += 1;
|
||||
size += 1;
|
||||
var rem_buffer = buffer;
|
||||
while (size < buffer.len) {
|
||||
const size_to_read = math.min(self.block_size - offset, rem_buffer.len);
|
||||
size += try in.read(rem_buffer[0..size_to_read]);
|
||||
rem_buffer = buffer[size..];
|
||||
offset += size_to_read;
|
||||
|
||||
// If we're at the end of a block, go to the next one.
|
||||
if (offset == self.block_size) {
|
||||
|
@ -657,8 +686,8 @@ const MsfStream = struct {
|
|||
}
|
||||
}
|
||||
|
||||
self.pos += size;
|
||||
return size;
|
||||
self.pos += buffer.len;
|
||||
return buffer.len;
|
||||
}
|
||||
|
||||
fn seekBy(self: *MsfStream, len: i64) !void {
|
||||
|
|
|
@ -93,7 +93,8 @@ pub const Node = struct {
|
|||
comptime {
|
||||
assert(@alignOf(*Node) >= 2);
|
||||
}
|
||||
return @intToPtr(*Node, node.parent_and_color & ~mask);
|
||||
const maybe_ptr = node.parent_and_color & ~mask;
|
||||
return if (maybe_ptr == 0) null else @intToPtr(*Node, maybe_ptr);
|
||||
}
|
||||
|
||||
fn setColor(node: *Node, color: Color) void {
|
||||
|
|
|
@ -77,16 +77,20 @@ const Allocator = std.mem.Allocator;
|
|||
pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
const prealloc_exp = blk: {
|
||||
// we don't use the prealloc_exp constant when prealloc_item_count is 0.
|
||||
assert(prealloc_item_count != 0);
|
||||
assert(std.math.isPowerOfTwo(prealloc_item_count));
|
||||
|
||||
const value = std.math.log2_int(usize, prealloc_item_count);
|
||||
break :blk @typeOf(1)(value);
|
||||
};
|
||||
const ShelfIndex = std.math.Log2Int(usize);
|
||||
|
||||
const prealloc_exp: ShelfIndex = blk: {
|
||||
// we don't use the prealloc_exp constant when prealloc_item_count is 0
|
||||
// but lazy-init may still be triggered by other code so supply a value
|
||||
if (prealloc_item_count == 0) {
|
||||
break :blk 0;
|
||||
} else {
|
||||
assert(std.math.isPowerOfTwo(prealloc_item_count));
|
||||
const value = std.math.log2_int(usize, prealloc_item_count);
|
||||
break :blk value;
|
||||
}
|
||||
};
|
||||
|
||||
prealloc_segment: [prealloc_item_count]T,
|
||||
dynamic_segments: [][*]T,
|
||||
allocator: *Allocator,
|
||||
|
@ -157,11 +161,12 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
|
|||
|
||||
/// Grows or shrinks capacity to match usage.
|
||||
pub fn setCapacity(self: *Self, new_capacity: usize) !void {
|
||||
if (new_capacity <= usize(1) << (prealloc_exp + self.dynamic_segments.len)) {
|
||||
return self.shrinkCapacity(new_capacity);
|
||||
} else {
|
||||
return self.growCapacity(new_capacity);
|
||||
if (prealloc_item_count != 0) {
|
||||
if (new_capacity <= usize(1) << (prealloc_exp + @intCast(ShelfIndex, self.dynamic_segments.len))) {
|
||||
return self.shrinkCapacity(new_capacity);
|
||||
}
|
||||
}
|
||||
return self.growCapacity(new_capacity);
|
||||
}
|
||||
|
||||
/// Only grows capacity, or retains current capacity
|
||||
|
@ -399,4 +404,6 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void {
|
|||
testing.expect(item == i);
|
||||
list.shrinkCapacity(list.len);
|
||||
}
|
||||
|
||||
try list.setCapacity(0);
|
||||
}
|
||||
|
|
|
@ -35,13 +35,13 @@ nakedcc fn _start() noreturn {
|
|||
|
||||
switch (builtin.arch) {
|
||||
.x86_64 => {
|
||||
argc_ptr = asm ("lea (%%rsp), %[argc]"
|
||||
: [argc] "=r" (-> [*]usize)
|
||||
argc_ptr = asm (""
|
||||
: [argc] "={rsp}" (-> [*]usize)
|
||||
);
|
||||
},
|
||||
.i386 => {
|
||||
argc_ptr = asm ("lea (%%esp), %[argc]"
|
||||
: [argc] "=r" (-> [*]usize)
|
||||
argc_ptr = asm (""
|
||||
: [argc] "={esp}" (-> [*]usize)
|
||||
);
|
||||
},
|
||||
.aarch64, .aarch64_be => {
|
||||
|
|
|
@ -105,6 +105,7 @@ test "std" {
|
|||
_ = @import("packed_int_array.zig");
|
||||
_ = @import("priority_queue.zig");
|
||||
_ = @import("rand.zig");
|
||||
_ = @import("rb.zig");
|
||||
_ = @import("sort.zig");
|
||||
_ = @import("testing.zig");
|
||||
_ = @import("thread.zig");
|
||||
|
|
|
@ -219,7 +219,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
\\ return error.OutOfMemory;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:7: error: error is discarded",
|
||||
"tmp.zig:2:12: error: error is discarded",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
@ -2758,7 +2758,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
\\ 3 = 3;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:7: error: cannot assign to constant",
|
||||
"tmp.zig:2:9: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
@ -2768,7 +2768,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
\\ a = 4;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:3:7: error: cannot assign to constant",
|
||||
"tmp.zig:3:9: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
@ -2838,7 +2838,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
\\}
|
||||
\\export fn entry() void { f(); }
|
||||
,
|
||||
"tmp.zig:3:7: error: cannot assign to constant",
|
||||
"tmp.zig:3:9: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
@ -3901,7 +3901,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
\\
|
||||
\\export fn entry() usize { return @sizeOf(@typeOf(a)); }
|
||||
,
|
||||
"tmp.zig:6:24: error: unable to evaluate constant expression",
|
||||
"tmp.zig:6:26: error: unable to evaluate constant expression",
|
||||
"tmp.zig:4:17: note: called from here",
|
||||
);
|
||||
|
||||
|
@ -4151,7 +4151,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
\\ cstr[0] = 'W';
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:3:11: error: cannot assign to constant",
|
||||
"tmp.zig:3:13: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
@ -4161,7 +4161,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
\\ cstr[0] = 'W';
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:3:11: error: cannot assign to constant",
|
||||
"tmp.zig:3:13: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
@ -4309,7 +4309,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||
\\ f.field = 0;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:6:13: error: cannot assign to constant",
|
||||
"tmp.zig:6:15: error: cannot assign to constant",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const builtin = @import("builtin");
|
||||
const AtomicRmwOp = builtin.AtomicRmwOp;
|
||||
const AtomicOrder = builtin.AtomicOrder;
|
||||
|
@ -69,3 +70,33 @@ test "cmpxchg with ptr" {
|
|||
expect(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
|
||||
expect(x == &data2);
|
||||
}
|
||||
|
||||
// TODO this test is disabled until this issue is resolved:
|
||||
// https://github.com/ziglang/zig/issues/2883
|
||||
// otherwise cross compiling will result in:
|
||||
// lld: error: undefined symbol: __sync_val_compare_and_swap_16
|
||||
//test "128-bit cmpxchg" {
|
||||
// var x: u128 align(16) = 1234; // TODO: https://github.com/ziglang/zig/issues/2987
|
||||
// if (@cmpxchgWeak(u128, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
|
||||
// expect(x1 == 1234);
|
||||
// } else {
|
||||
// @panic("cmpxchg should have failed");
|
||||
// }
|
||||
//
|
||||
// while (@cmpxchgWeak(u128, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| {
|
||||
// expect(x1 == 1234);
|
||||
// }
|
||||
// expect(x == 5678);
|
||||
//
|
||||
// expect(@cmpxchgStrong(u128, &x, 5678, 42, .SeqCst, .SeqCst) == null);
|
||||
// expect(x == 42);
|
||||
//}
|
||||
|
||||
test "cmpxchg with ignored result" {
|
||||
var x: i32 = 1234;
|
||||
var ptr = &x;
|
||||
|
||||
_ = @cmpxchgStrong(i32, &x, 1234, 5678, .Monotonic, .Monotonic);
|
||||
|
||||
expectEqual(i32(5678), x);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
test "compile time recursion" {
|
||||
|
@ -794,3 +795,12 @@ test "no undeclared identifier error in unanalyzed branches" {
|
|||
lol_this_doesnt_exist = nonsense;
|
||||
}
|
||||
}
|
||||
|
||||
test "comptime assign int to optional int" {
|
||||
comptime {
|
||||
var x: ?i32 = null;
|
||||
x = 2;
|
||||
x.? *= 10;
|
||||
expectEqual(20, x.?);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,3 +228,22 @@ test "implicit cast fn call result to optional in field result" {
|
|||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
test "discard the result of a function that returns a struct" {
|
||||
const S = struct {
|
||||
fn entry() void {
|
||||
_ = func();
|
||||
}
|
||||
|
||||
fn func() Foo {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const Foo = struct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
};
|
||||
};
|
||||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user