mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
Merge remote-tracking branch 'upstream/master' into arm-support-improvement
This commit is contained in:
commit
d62f7c6b60
@ -8114,7 +8114,23 @@ pub const TypeInfo = union(TypeId) {
|
||||
This function returns a compile-time constant, which is the type of the
|
||||
expression passed as an argument. The expression is evaluated.
|
||||
</p>
|
||||
<p>{#syntax#}@typeOf{#endsyntax#} guarantees no run-time side-effects within the expression:</p>
|
||||
{#code_begin|test#}
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
test "no runtime side effects" {
|
||||
var data: i32 = 0;
|
||||
const T = @typeOf(foo(i32, &data));
|
||||
comptime assert(T == i32);
|
||||
assert(data == 0);
|
||||
}
|
||||
|
||||
fn foo(comptime T: type, ptr: *T) T {
|
||||
ptr.* += 1;
|
||||
return ptr.*;
|
||||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@unionInit#}
|
||||
|
||||
@ -627,7 +627,7 @@ struct AstNodeParamDecl {
|
||||
AstNode *type;
|
||||
Token *var_token;
|
||||
bool is_noalias;
|
||||
bool is_inline;
|
||||
bool is_comptime;
|
||||
bool is_var_args;
|
||||
};
|
||||
|
||||
@ -2104,6 +2104,7 @@ enum ScopeId {
|
||||
ScopeIdFnDef,
|
||||
ScopeIdCompTime,
|
||||
ScopeIdRuntime,
|
||||
ScopeIdTypeOf,
|
||||
};
|
||||
|
||||
struct Scope {
|
||||
@ -2244,6 +2245,13 @@ struct ScopeFnDef {
|
||||
ZigFn *fn_entry;
|
||||
};
|
||||
|
||||
// This scope is created for a @typeOf.
|
||||
// All runtime side-effects are elided within it.
|
||||
// NodeTypeFnCallExpr
|
||||
struct ScopeTypeOf {
|
||||
Scope base;
|
||||
};
|
||||
|
||||
// synchronized with code in define_builtin_compile_vars
|
||||
enum AtomicOrder {
|
||||
AtomicOrderUnordered,
|
||||
@ -2711,6 +2719,7 @@ struct IrInstructionCallSrc {
|
||||
IrInstruction *new_stack;
|
||||
FnInline fn_inline;
|
||||
bool is_async;
|
||||
bool is_async_call_builtin;
|
||||
bool is_comptime;
|
||||
};
|
||||
|
||||
@ -2727,6 +2736,7 @@ struct IrInstructionCallGen {
|
||||
IrInstruction *new_stack;
|
||||
FnInline fn_inline;
|
||||
bool is_async;
|
||||
bool is_async_call_builtin;
|
||||
};
|
||||
|
||||
struct IrInstructionConst {
|
||||
|
||||
@ -197,6 +197,12 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) {
|
||||
return &scope->base;
|
||||
}
|
||||
|
||||
Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) {
|
||||
ScopeTypeOf *scope = allocate<ScopeTypeOf>(1);
|
||||
init_scope(g, &scope->base, ScopeIdTypeOf, node, parent);
|
||||
return &scope->base;
|
||||
}
|
||||
|
||||
ZigType *get_scope_import(Scope *scope) {
|
||||
while (scope) {
|
||||
if (scope->id == ScopeIdDecls) {
|
||||
@ -209,6 +215,22 @@ ZigType *get_scope_import(Scope *scope) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
ScopeTypeOf *get_scope_typeof(Scope *scope) {
|
||||
while (scope) {
|
||||
switch (scope->id) {
|
||||
case ScopeIdTypeOf:
|
||||
return reinterpret_cast<ScopeTypeOf *>(scope);
|
||||
case ScopeIdFnDef:
|
||||
case ScopeIdDecls:
|
||||
return nullptr;
|
||||
default:
|
||||
scope = scope->parent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static ZigType *new_container_type_entry(CodeGen *g, ZigTypeId id, AstNode *source_node, Scope *parent_scope,
|
||||
Buf *bare_name)
|
||||
{
|
||||
@ -1556,7 +1578,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
|
||||
AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index);
|
||||
assert(param_node->type == NodeTypeParamDecl);
|
||||
|
||||
bool param_is_comptime = param_node->data.param_decl.is_inline;
|
||||
bool param_is_comptime = param_node->data.param_decl.is_comptime;
|
||||
bool param_is_var_args = param_node->data.param_decl.is_var_args;
|
||||
|
||||
if (param_is_comptime) {
|
||||
@ -4393,7 +4415,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
|
||||
|
||||
if (g->verbose_ir) {
|
||||
fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name));
|
||||
ir_print(g, stderr, &fn->analyzed_executable, 4);
|
||||
ir_print(g, stderr, &fn->analyzed_executable, 4, 2);
|
||||
fprintf(stderr, "}\n");
|
||||
}
|
||||
fn->anal_state = FnAnalStateComplete;
|
||||
@ -4427,7 +4449,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
|
||||
fprintf(stderr, "\n");
|
||||
ast_render(stderr, fn_table_entry->body_node, 4);
|
||||
fprintf(stderr, "\n{ // (IR)\n");
|
||||
ir_print(g, stderr, &fn_table_entry->ir_executable, 4);
|
||||
ir_print(g, stderr, &fn_table_entry->ir_executable, 4, 1);
|
||||
fprintf(stderr, "}\n");
|
||||
}
|
||||
|
||||
@ -5705,6 +5727,10 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
|
||||
|
||||
for (size_t i = 0; i < fn->call_list.length; i += 1) {
|
||||
IrInstructionCallGen *call = fn->call_list.at(i);
|
||||
if (call->new_stack != nullptr) {
|
||||
// don't need to allocate a frame for this
|
||||
continue;
|
||||
}
|
||||
ZigFn *callee = call->fn_entry;
|
||||
if (callee == nullptr) {
|
||||
add_node_error(g, call->base.source_node,
|
||||
@ -8234,6 +8260,10 @@ static void resolve_llvm_types_anyerror(CodeGen *g) {
|
||||
}
|
||||
|
||||
static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) {
|
||||
Error err;
|
||||
if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown)))
|
||||
zig_unreachable();
|
||||
|
||||
ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr;
|
||||
resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type);
|
||||
frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type;
|
||||
@ -8375,7 +8405,6 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re
|
||||
}
|
||||
|
||||
static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) {
|
||||
assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown));
|
||||
assert(wanted_resolve_status > ResolveStatusSizeKnown);
|
||||
switch (type->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
|
||||
@ -85,6 +85,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
|
||||
ZigFn *scope_fn_entry(Scope *scope);
|
||||
ZigPackage *scope_package(Scope *scope);
|
||||
ZigType *get_scope_import(Scope *scope);
|
||||
ScopeTypeOf *get_scope_typeof(Scope *scope);
|
||||
void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);
|
||||
ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
|
||||
bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type);
|
||||
@ -112,6 +113,7 @@ ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
|
||||
ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);
|
||||
Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
|
||||
Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
|
||||
Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent);
|
||||
|
||||
void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
|
||||
ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);
|
||||
|
||||
@ -448,7 +448,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
assert(param_decl->type == NodeTypeParamDecl);
|
||||
if (param_decl->data.param_decl.name != nullptr) {
|
||||
const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";
|
||||
const char *inline_str = param_decl->data.param_decl.is_inline ? "inline " : "";
|
||||
const char *inline_str = param_decl->data.param_decl.is_comptime ? "comptime " : "";
|
||||
fprintf(ar->f, "%s%s", noalias_str, inline_str);
|
||||
print_symbol(ar, param_decl->data.param_decl.name);
|
||||
fprintf(ar->f, ": ");
|
||||
|
||||
@ -645,6 +645,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
|
||||
case ScopeIdSuspend:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdRuntime:
|
||||
case ScopeIdTypeOf:
|
||||
return get_di_scope(g, scope->parent);
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -3757,6 +3758,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) {
|
||||
case ScopeIdSuspend:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdRuntime:
|
||||
case ScopeIdTypeOf:
|
||||
scope = scope->parent;
|
||||
continue;
|
||||
}
|
||||
@ -3824,17 +3826,18 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
LLVMValueRef awaiter_init_val;
|
||||
LLVMValueRef ret_ptr;
|
||||
if (callee_is_async) {
|
||||
if (instruction->is_async) {
|
||||
if (instruction->new_stack == nullptr) {
|
||||
awaiter_init_val = zero;
|
||||
if (instruction->new_stack == nullptr) {
|
||||
if (instruction->is_async) {
|
||||
frame_result_loc = result_loc;
|
||||
|
||||
if (ret_has_bits) {
|
||||
// Use the result location which is inside the frame if this is an async call.
|
||||
ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
|
||||
}
|
||||
} else if (cc == CallingConventionAsync) {
|
||||
awaiter_init_val = zero;
|
||||
} else {
|
||||
frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc);
|
||||
}
|
||||
} else {
|
||||
if (instruction->new_stack->value.type->id == ZigTypeIdPointer &&
|
||||
instruction->new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
|
||||
{
|
||||
frame_result_loc = ir_llvm_value(g, instruction->new_stack);
|
||||
} else {
|
||||
LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack);
|
||||
if (ir_want_runtime_safety(g, &instruction->base)) {
|
||||
LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, "");
|
||||
@ -3854,15 +3857,37 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
}
|
||||
LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, "");
|
||||
LLVMValueRef frame_ptr = LLVMBuildLoad(g->builder, frame_ptr_ptr, "");
|
||||
frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr,
|
||||
get_llvm_type(g, instruction->base.value.type), "");
|
||||
if (instruction->fn_entry == nullptr) {
|
||||
ZigType *anyframe_type = get_any_frame_type(g, src_return_type);
|
||||
frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, get_llvm_type(g, anyframe_type), "");
|
||||
} else {
|
||||
ZigType *ptr_frame_type = get_pointer_to_type(g,
|
||||
get_fn_frame_type(g, instruction->fn_entry), false);
|
||||
frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr,
|
||||
get_llvm_type(g, ptr_frame_type), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (instruction->is_async) {
|
||||
if (instruction->new_stack == nullptr) {
|
||||
awaiter_init_val = zero;
|
||||
|
||||
if (ret_has_bits) {
|
||||
// Use the result location provided to the @asyncCall builtin
|
||||
ret_ptr = result_loc;
|
||||
// Use the result location which is inside the frame if this is an async call.
|
||||
ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
awaiter_init_val = zero;
|
||||
|
||||
if (ret_has_bits) {
|
||||
if (result_loc != nullptr) {
|
||||
// Use the result location provided to the @asyncCall builtin
|
||||
ret_ptr = result_loc;
|
||||
} else {
|
||||
// no result location provided to @asyncCall - use the one inside the frame.
|
||||
ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// even if prefix_arg_err_ret_stack is true, let the async function do its own
|
||||
@ -3870,7 +3895,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
} else {
|
||||
// async function called as a normal function
|
||||
|
||||
frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc);
|
||||
awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer
|
||||
if (ret_has_bits) {
|
||||
if (result_loc == nullptr) {
|
||||
@ -3986,7 +4010,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type);
|
||||
|
||||
LLVMValueRef casted_frame;
|
||||
if (instruction->new_stack != nullptr) {
|
||||
if (instruction->new_stack != nullptr && instruction->fn_entry == nullptr) {
|
||||
// We need the frame type to be a pointer to a struct that includes the args
|
||||
size_t field_count = arg_start_i + gen_param_values.length;
|
||||
LLVMTypeRef *field_types = allocate_nonzero<LLVMTypeRef>(field_count);
|
||||
@ -4012,7 +4036,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
if (instruction->is_async) {
|
||||
gen_resume(g, fn_val, frame_result_loc, ResumeIdCall);
|
||||
if (instruction->new_stack != nullptr) {
|
||||
return frame_result_loc;
|
||||
return LLVMBuildBitCast(g->builder, frame_result_loc,
|
||||
get_llvm_type(g, instruction->base.value.type), "");
|
||||
}
|
||||
return nullptr;
|
||||
} else {
|
||||
@ -4039,7 +4064,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
}
|
||||
}
|
||||
|
||||
if (instruction->new_stack == nullptr) {
|
||||
if (instruction->new_stack == nullptr || instruction->is_async_call_builtin) {
|
||||
result = ZigLLVMBuildCall(g->builder, fn_val,
|
||||
gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
|
||||
} else if (instruction->is_async) {
|
||||
@ -5942,12 +5967,17 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
|
||||
|
||||
for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
|
||||
IrBasicBlock *current_block = executable->basic_block_list.at(block_i);
|
||||
if (get_scope_typeof(current_block->scope) != nullptr) {
|
||||
LLVMBuildBr(g->builder, current_block->llvm_block);
|
||||
}
|
||||
assert(current_block->llvm_block);
|
||||
LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block);
|
||||
for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) {
|
||||
IrInstruction *instruction = current_block->instruction_list.at(instr_i);
|
||||
if (instruction->ref_count == 0 && !ir_has_side_effects(instruction))
|
||||
continue;
|
||||
if (get_scope_typeof(instruction->scope) != nullptr)
|
||||
continue;
|
||||
|
||||
if (!g->strip_debug_symbols) {
|
||||
set_debug_location(g, instruction);
|
||||
@ -6340,9 +6370,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
ZigType *type_entry = const_val->type;
|
||||
assert(type_has_bits(type_entry));
|
||||
|
||||
switch (const_val->special) {
|
||||
check: switch (const_val->special) {
|
||||
case ConstValSpecialLazy:
|
||||
zig_unreachable();
|
||||
if ((err = ir_resolve_lazy(g, nullptr, const_val))) {
|
||||
report_errors_and_exit(g);
|
||||
}
|
||||
goto check;
|
||||
case ConstValSpecialRuntime:
|
||||
zig_unreachable();
|
||||
case ConstValSpecialUndef:
|
||||
|
||||
355
src/ir.cpp
355
src/ir.cpp
@ -1382,7 +1382,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast
|
||||
|
||||
static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
|
||||
bool is_comptime, FnInline fn_inline, bool is_async,
|
||||
bool is_comptime, FnInline fn_inline, bool is_async, bool is_async_call_builtin,
|
||||
IrInstruction *new_stack, ResultLoc *result_loc)
|
||||
{
|
||||
IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node);
|
||||
@ -1393,6 +1393,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s
|
||||
call_instruction->args = args;
|
||||
call_instruction->arg_count = arg_count;
|
||||
call_instruction->is_async = is_async;
|
||||
call_instruction->is_async_call_builtin = is_async_call_builtin;
|
||||
call_instruction->new_stack = new_stack;
|
||||
call_instruction->result_loc = result_loc;
|
||||
|
||||
@ -1410,7 +1411,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s
|
||||
|
||||
static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction,
|
||||
ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
|
||||
FnInline fn_inline, bool is_async, IrInstruction *new_stack,
|
||||
FnInline fn_inline, bool is_async, IrInstruction *new_stack, bool is_async_call_builtin,
|
||||
IrInstruction *result_loc, ZigType *return_type)
|
||||
{
|
||||
IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb,
|
||||
@ -1422,6 +1423,7 @@ static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *so
|
||||
call_instruction->args = args;
|
||||
call_instruction->arg_count = arg_count;
|
||||
call_instruction->is_async = is_async;
|
||||
call_instruction->is_async_call_builtin = is_async_call_builtin;
|
||||
call_instruction->new_stack = new_stack;
|
||||
call_instruction->result_loc = result_loc;
|
||||
|
||||
@ -3344,6 +3346,7 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco
|
||||
case ScopeIdSuspend:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdRuntime:
|
||||
case ScopeIdTypeOf:
|
||||
scope = scope->parent;
|
||||
continue;
|
||||
case ScopeIdDeferExpr:
|
||||
@ -3399,6 +3402,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
|
||||
case ScopeIdSuspend:
|
||||
case ScopeIdCompTime:
|
||||
case ScopeIdRuntime:
|
||||
case ScopeIdTypeOf:
|
||||
scope = scope->parent;
|
||||
continue;
|
||||
case ScopeIdDeferExpr:
|
||||
@ -4349,6 +4353,54 @@ static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *no
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_async_call(IrBuilder *irb, Scope *scope, AstNode *await_node, AstNode *call_node,
|
||||
LVal lval, ResultLoc *result_loc)
|
||||
{
|
||||
size_t arg_offset = 3;
|
||||
if (call_node->data.fn_call_expr.params.length < arg_offset) {
|
||||
add_node_error(irb->codegen, call_node,
|
||||
buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize,
|
||||
arg_offset, call_node->data.fn_call_expr.params.length));
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
AstNode *bytes_node = call_node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *bytes = ir_gen_node(irb, bytes_node, scope);
|
||||
if (bytes == irb->codegen->invalid_instruction)
|
||||
return bytes;
|
||||
|
||||
AstNode *ret_ptr_node = call_node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope);
|
||||
if (ret_ptr == irb->codegen->invalid_instruction)
|
||||
return ret_ptr;
|
||||
|
||||
AstNode *fn_ref_node = call_node->data.fn_call_expr.params.at(2);
|
||||
IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
|
||||
if (fn_ref == irb->codegen->invalid_instruction)
|
||||
return fn_ref;
|
||||
|
||||
size_t arg_count = call_node->data.fn_call_expr.params.length - arg_offset;
|
||||
|
||||
// last "arg" is return pointer
|
||||
IrInstruction **args = allocate<IrInstruction*>(arg_count + 1);
|
||||
|
||||
for (size_t i = 0; i < arg_count; i += 1) {
|
||||
AstNode *arg_node = call_node->data.fn_call_expr.params.at(i + arg_offset);
|
||||
IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
|
||||
if (arg == irb->codegen->invalid_instruction)
|
||||
return arg;
|
||||
args[i] = arg;
|
||||
}
|
||||
|
||||
args[arg_count] = ret_ptr;
|
||||
|
||||
bool is_async = await_node == nullptr;
|
||||
bool is_async_call_builtin = true;
|
||||
IrInstruction *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, false,
|
||||
FnInlineAuto, is_async, is_async_call_builtin, bytes, result_loc);
|
||||
return ir_lval_wrap(irb, scope, call, lval, result_loc);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
|
||||
ResultLoc *result_loc)
|
||||
{
|
||||
@ -4358,7 +4410,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
Buf *name = fn_ref_expr->data.symbol_expr.symbol;
|
||||
auto entry = irb->codegen->builtin_fn_table.maybe_get(name);
|
||||
|
||||
if (!entry) { // new built in not found
|
||||
if (!entry) {
|
||||
add_node_error(irb->codegen, node,
|
||||
buf_sprintf("invalid builtin function: '%s'", buf_ptr(name)));
|
||||
return irb->codegen->invalid_instruction;
|
||||
@ -4379,8 +4431,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
zig_unreachable();
|
||||
case BuiltinFnIdTypeof:
|
||||
{
|
||||
Scope *sub_scope = create_typeof_scope(irb->codegen, node, scope);
|
||||
|
||||
AstNode *arg_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
|
||||
IrInstruction *arg = ir_gen_node(irb, arg_node, sub_scope);
|
||||
if (arg == irb->codegen->invalid_instruction)
|
||||
return arg;
|
||||
|
||||
@ -5220,7 +5274,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
|
||||
|
||||
IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
|
||||
fn_inline, false, nullptr, result_loc);
|
||||
fn_inline, false, false, nullptr, result_loc);
|
||||
return ir_lval_wrap(irb, scope, call, lval, result_loc);
|
||||
}
|
||||
case BuiltinFnIdNewStackCall:
|
||||
@ -5253,53 +5307,11 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
}
|
||||
|
||||
IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
|
||||
FnInlineAuto, false, new_stack, result_loc);
|
||||
FnInlineAuto, false, false, new_stack, result_loc);
|
||||
return ir_lval_wrap(irb, scope, call, lval, result_loc);
|
||||
}
|
||||
case BuiltinFnIdAsyncCall:
|
||||
{
|
||||
size_t arg_offset = 3;
|
||||
if (node->data.fn_call_expr.params.length < arg_offset) {
|
||||
add_node_error(irb->codegen, node,
|
||||
buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize,
|
||||
arg_offset, node->data.fn_call_expr.params.length));
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
AstNode *bytes_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *bytes = ir_gen_node(irb, bytes_node, scope);
|
||||
if (bytes == irb->codegen->invalid_instruction)
|
||||
return bytes;
|
||||
|
||||
AstNode *ret_ptr_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope);
|
||||
if (ret_ptr == irb->codegen->invalid_instruction)
|
||||
return ret_ptr;
|
||||
|
||||
AstNode *fn_ref_node = node->data.fn_call_expr.params.at(2);
|
||||
IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
|
||||
if (fn_ref == irb->codegen->invalid_instruction)
|
||||
return fn_ref;
|
||||
|
||||
size_t arg_count = node->data.fn_call_expr.params.length - arg_offset;
|
||||
|
||||
// last "arg" is return pointer
|
||||
IrInstruction **args = allocate<IrInstruction*>(arg_count + 1);
|
||||
|
||||
for (size_t i = 0; i < arg_count; i += 1) {
|
||||
AstNode *arg_node = node->data.fn_call_expr.params.at(i + arg_offset);
|
||||
IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
|
||||
if (arg == irb->codegen->invalid_instruction)
|
||||
return arg;
|
||||
args[i] = arg;
|
||||
}
|
||||
|
||||
args[arg_count] = ret_ptr;
|
||||
|
||||
IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
|
||||
FnInlineAuto, true, bytes, result_loc);
|
||||
return ir_lval_wrap(irb, scope, call, lval, result_loc);
|
||||
}
|
||||
return ir_gen_async_call(irb, scope, nullptr, node, lval, result_loc);
|
||||
case BuiltinFnIdTypeId:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
@ -5603,7 +5615,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
|
||||
|
||||
bool is_async = node->data.fn_call_expr.is_async;
|
||||
IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
|
||||
FnInlineAuto, is_async, nullptr, result_loc);
|
||||
FnInlineAuto, is_async, false, nullptr, result_loc);
|
||||
return ir_lval_wrap(irb, scope, fn_call, lval, result_loc);
|
||||
}
|
||||
|
||||
@ -7896,6 +7908,19 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
|
||||
{
|
||||
assert(node->type == NodeTypeAwaitExpr);
|
||||
|
||||
AstNode *expr_node = node->data.await_expr.expr;
|
||||
if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.is_builtin) {
|
||||
AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr;
|
||||
Buf *name = fn_ref_expr->data.symbol_expr.symbol;
|
||||
auto entry = irb->codegen->builtin_fn_table.maybe_get(name);
|
||||
if (entry != nullptr) {
|
||||
BuiltinFnEntry *builtin_fn = entry->value;
|
||||
if (builtin_fn->id == BuiltinFnIdAsyncCall) {
|
||||
return ir_gen_async_call(irb, scope, node, expr_node, lval, result_loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZigFn *fn_entry = exec_fn_entry(irb->exec);
|
||||
if (!fn_entry) {
|
||||
add_node_error(irb->codegen, node, buf_sprintf("await outside function definition"));
|
||||
@ -7911,7 +7936,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.await_expr.expr, scope, LValPtr, nullptr);
|
||||
IrInstruction *target_inst = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr);
|
||||
if (target_inst == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
@ -8269,6 +8294,10 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (get_scope_typeof(instruction->scope) != nullptr) {
|
||||
// doesn't count, it's inside a @typeOf()
|
||||
continue;
|
||||
}
|
||||
exec_add_error_node(codegen, exec, instruction->source_node,
|
||||
buf_sprintf("unable to evaluate constant expression"));
|
||||
return &codegen->invalid_instruction->value;
|
||||
@ -9012,7 +9041,42 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, instruction, UndefBad);
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, instruction, LazyOkNoUndef);
|
||||
if (const_val == nullptr)
|
||||
return false;
|
||||
|
||||
if (const_val->special == ConstValSpecialLazy) {
|
||||
switch (const_val->data.x_lazy->id) {
|
||||
case LazyValueIdAlignOf: {
|
||||
// This is guaranteed to fit into a u29
|
||||
if (other_type->id == ZigTypeIdComptimeInt)
|
||||
return true;
|
||||
size_t align_bits = get_align_amt_type(ira->codegen)->data.integral.bit_count;
|
||||
if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed &&
|
||||
other_type->data.integral.bit_count >= align_bits)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LazyValueIdSizeOf: {
|
||||
// This is guaranteed to fit into a usize
|
||||
if (other_type->id == ZigTypeIdComptimeInt)
|
||||
return true;
|
||||
size_t usize_bits = ira->codegen->builtin_types.entry_usize->data.integral.bit_count;
|
||||
if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed &&
|
||||
other_type->data.integral.bit_count >= usize_bits)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const_val = ir_resolve_const(ira, instruction, UndefBad);
|
||||
if (const_val == nullptr)
|
||||
return false;
|
||||
|
||||
@ -10262,7 +10326,7 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_
|
||||
memcpy(dest, src, sizeof(ConstExprValue));
|
||||
if (!same_global_refs) {
|
||||
dest->global_refs = global_refs;
|
||||
if (src->special == ConstValSpecialUndef)
|
||||
if (src->special != ConstValSpecialStatic)
|
||||
return;
|
||||
if (dest->type->id == ZigTypeIdStruct) {
|
||||
dest->data.x_struct.fields = create_const_vals(dest->type->data.structure.src_field_count);
|
||||
@ -10803,7 +10867,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod
|
||||
fprintf(stderr, "\nSource: ");
|
||||
ast_render(stderr, node, 4);
|
||||
fprintf(stderr, "\n{ // (IR)\n");
|
||||
ir_print(codegen, stderr, ir_executable, 2);
|
||||
ir_print(codegen, stderr, ir_executable, 2, 1);
|
||||
fprintf(stderr, "}\n");
|
||||
}
|
||||
IrExecutable *analyzed_executable = allocate<IrExecutable>(1);
|
||||
@ -10824,7 +10888,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod
|
||||
|
||||
if (codegen->verbose_ir) {
|
||||
fprintf(stderr, "{ // (analyzed)\n");
|
||||
ir_print(codegen, stderr, analyzed_executable, 2);
|
||||
ir_print(codegen, stderr, analyzed_executable, 2, 2);
|
||||
fprintf(stderr, "}\n");
|
||||
}
|
||||
|
||||
@ -11213,7 +11277,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, value, UndefOk);
|
||||
ConstExprValue *val = ir_resolve_const(ira, value, LazyOk);
|
||||
if (!val)
|
||||
return ira->codegen->invalid_instruction;
|
||||
return ir_get_const_ptr(ira, source_instruction, val, value->value.type,
|
||||
@ -12125,7 +12189,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) {
|
||||
IrInstruction *result = ir_const(ira, source_instr, wanted_type);
|
||||
if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) {
|
||||
bigint_init_bigint(&result->value.data.x_bigint, &value->value.data.x_bigint);
|
||||
copy_const_val(&result->value, &value->value, false);
|
||||
result->value.type = wanted_type;
|
||||
} else {
|
||||
float_init_bigint(&result->value.data.x_bigint, &value->value);
|
||||
}
|
||||
@ -14869,7 +14934,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
|
||||
PtrLenSingle, 0, 0, 0, false);
|
||||
set_up_result_loc_for_inferred_comptime(&alloca_gen->base);
|
||||
ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
|
||||
if (fn_entry != nullptr) {
|
||||
if (fn_entry != nullptr && get_scope_typeof(suspend_source_instr->scope) == nullptr) {
|
||||
fn_entry->alloca_gen_list.append(alloca_gen);
|
||||
}
|
||||
result_loc->written = true;
|
||||
@ -15200,44 +15265,61 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst
|
||||
return ir_const_void(ira, &instruction->base);
|
||||
}
|
||||
|
||||
static IrInstruction *get_async_call_result_loc(IrAnalyze *ira, IrInstructionCallSrc *call_instruction,
|
||||
ZigType *fn_ret_type)
|
||||
{
|
||||
ir_assert(call_instruction->is_async_call_builtin, &call_instruction->base);
|
||||
IrInstruction *ret_ptr_uncasted = call_instruction->args[call_instruction->arg_count]->child;
|
||||
if (type_is_invalid(ret_ptr_uncasted->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (ret_ptr_uncasted->value.type->id == ZigTypeIdVoid) {
|
||||
// Result location will be inside the async frame.
|
||||
return nullptr;
|
||||
}
|
||||
return ir_implicit_cast(ira, ret_ptr_uncasted, get_pointer_to_type(ira->codegen, fn_ret_type, false));
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry,
|
||||
ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count,
|
||||
IrInstruction *casted_new_stack)
|
||||
{
|
||||
if (casted_new_stack != nullptr) {
|
||||
// this is an @asyncCall
|
||||
|
||||
if (fn_entry == nullptr) {
|
||||
if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) {
|
||||
ir_add_error(ira, fn_ref,
|
||||
buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
IrInstruction *ret_ptr = call_instruction->args[call_instruction->arg_count]->child;
|
||||
if (type_is_invalid(ret_ptr->value.type))
|
||||
if (casted_new_stack == nullptr) {
|
||||
ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
}
|
||||
if (casted_new_stack != nullptr) {
|
||||
ZigType *fn_ret_type = fn_type->data.fn.fn_type_id.return_type;
|
||||
IrInstruction *ret_ptr = get_async_call_result_loc(ira, call_instruction, fn_ret_type);
|
||||
if (ret_ptr != nullptr && type_is_invalid(ret_ptr->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_type->data.fn.fn_type_id.return_type);
|
||||
ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_ret_type);
|
||||
|
||||
IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, nullptr, fn_ref,
|
||||
arg_count, casted_args, FnInlineAuto, true, casted_new_stack, ret_ptr, anyframe_type);
|
||||
IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref,
|
||||
arg_count, casted_args, FnInlineAuto, true, casted_new_stack,
|
||||
call_instruction->is_async_call_builtin, ret_ptr, anyframe_type);
|
||||
return &call_gen->base;
|
||||
} else if (fn_entry == nullptr) {
|
||||
ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else {
|
||||
ZigType *frame_type = get_fn_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, false);
|
||||
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
|
||||
return result_loc;
|
||||
}
|
||||
result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false));
|
||||
if (type_is_invalid(result_loc->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count,
|
||||
casted_args, FnInlineAuto, true, casted_new_stack, call_instruction->is_async_call_builtin,
|
||||
result_loc, frame_type)->base;
|
||||
}
|
||||
|
||||
ZigType *frame_type = get_fn_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, false);
|
||||
if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) {
|
||||
return result_loc;
|
||||
}
|
||||
result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false));
|
||||
if (type_is_invalid(result_loc->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count,
|
||||
casted_args, FnInlineAuto, true, nullptr, result_loc, frame_type)->base;
|
||||
}
|
||||
static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
|
||||
IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
|
||||
@ -15301,7 +15383,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
||||
}
|
||||
}
|
||||
|
||||
bool comptime_arg = param_decl_node->data.param_decl.is_inline ||
|
||||
bool comptime_arg = param_decl_node->data.param_decl.is_comptime ||
|
||||
casted_arg->value.type->id == ZigTypeIdComptimeInt || casted_arg->value.type->id == ZigTypeIdComptimeFloat;
|
||||
|
||||
ConstExprValue *arg_val;
|
||||
@ -15746,16 +15828,27 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
|
||||
IrInstruction *casted_new_stack = nullptr;
|
||||
if (call_instruction->new_stack != nullptr) {
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false);
|
||||
ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
|
||||
IrInstruction *new_stack = call_instruction->new_stack->child;
|
||||
if (type_is_invalid(new_stack->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice);
|
||||
if (type_is_invalid(casted_new_stack->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (call_instruction->is_async_call_builtin &&
|
||||
fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer &&
|
||||
new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
|
||||
{
|
||||
ZigType *needed_frame_type = get_pointer_to_type(ira->codegen,
|
||||
get_fn_frame_type(ira->codegen, fn_entry), false);
|
||||
casted_new_stack = ir_implicit_cast(ira, new_stack, needed_frame_type);
|
||||
if (type_is_invalid(casted_new_stack->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else {
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false);
|
||||
ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
|
||||
casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice);
|
||||
if (type_is_invalid(casted_new_stack->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
}
|
||||
|
||||
if (fn_type->data.fn.is_generic) {
|
||||
@ -15965,8 +16058,24 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
}
|
||||
|
||||
FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id;
|
||||
|
||||
if (fn_type_can_fail(impl_fn_type_id)) {
|
||||
parent_fn_entry->calls_or_awaits_errorable_fn = true;
|
||||
}
|
||||
|
||||
size_t impl_param_count = impl_fn_type_id->param_count;
|
||||
if (call_instruction->is_async) {
|
||||
IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
|
||||
nullptr, casted_args, impl_param_count, casted_new_stack);
|
||||
return ir_finish_anal(ira, result);
|
||||
}
|
||||
|
||||
IrInstruction *result_loc;
|
||||
if (handle_is_ptr(impl_fn_type_id->return_type)) {
|
||||
if (call_instruction->is_async_call_builtin) {
|
||||
result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type);
|
||||
if (result_loc != nullptr && type_is_invalid(result_loc->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else 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, false);
|
||||
if (result_loc != nullptr) {
|
||||
@ -15982,17 +16091,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
result_loc = nullptr;
|
||||
}
|
||||
|
||||
if (fn_type_can_fail(impl_fn_type_id)) {
|
||||
parent_fn_entry->calls_or_awaits_errorable_fn = true;
|
||||
}
|
||||
|
||||
size_t impl_param_count = impl_fn_type_id->param_count;
|
||||
if (call_instruction->is_async) {
|
||||
IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
|
||||
nullptr, casted_args, impl_param_count, casted_new_stack);
|
||||
return ir_finish_anal(ira, result);
|
||||
}
|
||||
|
||||
if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
|
||||
parent_fn_entry->inferred_async_node = fn_ref->source_node;
|
||||
parent_fn_entry->inferred_async_fn = impl_fn;
|
||||
@ -16000,10 +16098,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
|
||||
IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,
|
||||
impl_fn, nullptr, impl_param_count, casted_args, fn_inline,
|
||||
false, casted_new_stack, result_loc,
|
||||
false, casted_new_stack, call_instruction->is_async_call_builtin, result_loc,
|
||||
impl_fn_type_id->return_type);
|
||||
|
||||
parent_fn_entry->call_list.append(new_call_instruction);
|
||||
if (get_scope_typeof(call_instruction->base.scope) == nullptr) {
|
||||
parent_fn_entry->call_list.append(new_call_instruction);
|
||||
}
|
||||
|
||||
return ir_finish_anal(ira, &new_call_instruction->base);
|
||||
}
|
||||
@ -16123,7 +16223,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
}
|
||||
|
||||
IrInstruction *result_loc;
|
||||
if (handle_is_ptr(return_type)) {
|
||||
if (call_instruction->is_async_call_builtin) {
|
||||
result_loc = get_async_call_result_loc(ira, call_instruction, return_type);
|
||||
if (result_loc != nullptr && type_is_invalid(result_loc->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else if (handle_is_ptr(return_type)) {
|
||||
result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
|
||||
return_type, nullptr, true, true, false);
|
||||
if (result_loc != nullptr) {
|
||||
@ -16141,8 +16245,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
|
||||
IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref,
|
||||
call_param_count, casted_args, fn_inline, false, casted_new_stack,
|
||||
result_loc, return_type);
|
||||
parent_fn_entry->call_list.append(new_call_instruction);
|
||||
call_instruction->is_async_call_builtin, result_loc, return_type);
|
||||
if (get_scope_typeof(call_instruction->base.scope) == nullptr) {
|
||||
parent_fn_entry->call_list.append(new_call_instruction);
|
||||
}
|
||||
return ir_finish_anal(ira, &new_call_instruction->base);
|
||||
}
|
||||
|
||||
@ -17594,6 +17700,11 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
|
||||
ConstExprValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node);
|
||||
if (child_val == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec,
|
||||
field_ptr_instruction->base.source_node, child_val, UndefBad)))
|
||||
{
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
ZigType *child_type = child_val->data.x_type;
|
||||
|
||||
if (type_is_invalid(child_type)) {
|
||||
@ -21293,8 +21404,10 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru
|
||||
src_ptr_align = get_abi_alignment(ira->codegen, target->value.type);
|
||||
}
|
||||
|
||||
if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (src_ptr_align != 0) {
|
||||
if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,
|
||||
src_ptr_const, src_ptr_volatile, PtrLenUnknown,
|
||||
@ -21337,6 +21450,8 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru
|
||||
}
|
||||
|
||||
if (have_known_len) {
|
||||
if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
uint64_t child_type_size = type_size(ira->codegen, dest_child_type);
|
||||
uint64_t remainder = known_len % child_type_size;
|
||||
if (remainder != 0) {
|
||||
@ -23963,15 +24078,23 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) {
|
||||
uint32_t align_bytes;
|
||||
IrInstruction *align_bytes_inst = instruction->align_bytes->child;
|
||||
if (!ir_resolve_align(ira, align_bytes_inst, nullptr, &align_bytes))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
IrInstruction *target = instruction->target->child;
|
||||
if (type_is_invalid(target->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
ZigType *elem_type = nullptr;
|
||||
if (is_slice(target->value.type)) {
|
||||
ZigType *slice_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
elem_type = slice_ptr_type->data.pointer.child_type;
|
||||
} else if (target->value.type->id == ZigTypeIdPointer) {
|
||||
elem_type = target->value.type->data.pointer.child_type;
|
||||
}
|
||||
|
||||
uint32_t align_bytes;
|
||||
IrInstruction *align_bytes_inst = instruction->align_bytes->child;
|
||||
if (!ir_resolve_align(ira, align_bytes_inst, elem_type, &align_bytes))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
IrInstruction *result = ir_align_cast(ira, target, align_bytes, true);
|
||||
if (type_is_invalid(result->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
@ -25644,7 +25767,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
|
||||
}
|
||||
|
||||
val->special = ConstValSpecialStatic;
|
||||
assert(val->type->id == ZigTypeIdComptimeInt);
|
||||
assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
|
||||
bigint_init_unsigned(&val->data.x_bigint, align_in_bytes);
|
||||
return ErrorNone;
|
||||
}
|
||||
@ -25699,7 +25822,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
|
||||
}
|
||||
|
||||
val->special = ConstValSpecialStatic;
|
||||
assert(val->type->id == ZigTypeIdComptimeInt);
|
||||
assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
|
||||
bigint_init_unsigned(&val->data.x_bigint, abi_size);
|
||||
return ErrorNone;
|
||||
}
|
||||
@ -25885,7 +26008,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
|
||||
Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) {
|
||||
Error err;
|
||||
if ((err = ir_resolve_lazy_raw(source_node, val))) {
|
||||
if (codegen->trace_err != nullptr && !source_node->already_traced_this_node) {
|
||||
if (codegen->trace_err != nullptr && source_node != nullptr && !source_node->already_traced_this_node) {
|
||||
source_node->already_traced_this_node = true;
|
||||
codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node,
|
||||
buf_create_from_str("referenced here"));
|
||||
|
||||
385
src/ir_print.cpp
385
src/ir_print.cpp
@ -10,27 +10,374 @@
|
||||
#include "ir_print.hpp"
|
||||
#include "os.hpp"
|
||||
|
||||
static uint32_t hash_instruction_ptr(IrInstruction* instruction) {
|
||||
return (uint32_t)(uintptr_t)instruction;
|
||||
}
|
||||
|
||||
static bool instruction_ptr_equal(IrInstruction* a, IrInstruction* b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
using InstructionSet = HashMap<IrInstruction*, uint8_t, hash_instruction_ptr, instruction_ptr_equal>;
|
||||
using InstructionList = ZigList<IrInstruction*>;
|
||||
|
||||
struct IrPrint {
|
||||
size_t pass_num;
|
||||
CodeGen *codegen;
|
||||
FILE *f;
|
||||
int indent;
|
||||
int indent_size;
|
||||
|
||||
// When printing pass 2 instructions referenced var instructions are not
|
||||
// present in the instruction list. Thus we track which instructions
|
||||
// are printed (per executable) and after each pass 2 instruction those
|
||||
// var instructions are rendered in a trailing fashion.
|
||||
InstructionSet printed;
|
||||
InstructionList pending;
|
||||
};
|
||||
|
||||
static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction);
|
||||
|
||||
static const char* ir_instruction_type_str(IrInstruction* instruction) {
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
return "Invalid";
|
||||
case IrInstructionIdDeclVarSrc:
|
||||
return "DeclVarSrc";
|
||||
case IrInstructionIdDeclVarGen:
|
||||
return "DeclVarGen";
|
||||
case IrInstructionIdBr:
|
||||
return "Br";
|
||||
case IrInstructionIdCondBr:
|
||||
return "CondBr";
|
||||
case IrInstructionIdSwitchBr:
|
||||
return "SwitchBr";
|
||||
case IrInstructionIdSwitchVar:
|
||||
return "SwitchVar";
|
||||
case IrInstructionIdSwitchElseVar:
|
||||
return "SwitchElseVar";
|
||||
case IrInstructionIdSwitchTarget:
|
||||
return "SwitchTarget";
|
||||
case IrInstructionIdPhi:
|
||||
return "Phi";
|
||||
case IrInstructionIdUnOp:
|
||||
return "UnOp";
|
||||
case IrInstructionIdBinOp:
|
||||
return "BinOp";
|
||||
case IrInstructionIdLoadPtr:
|
||||
return "LoadPtr";
|
||||
case IrInstructionIdLoadPtrGen:
|
||||
return "LoadPtrGen";
|
||||
case IrInstructionIdStorePtr:
|
||||
return "StorePtr";
|
||||
case IrInstructionIdFieldPtr:
|
||||
return "FieldPtr";
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
return "StructFieldPtr";
|
||||
case IrInstructionIdUnionFieldPtr:
|
||||
return "UnionFieldPtr";
|
||||
case IrInstructionIdElemPtr:
|
||||
return "ElemPtr";
|
||||
case IrInstructionIdVarPtr:
|
||||
return "VarPtr";
|
||||
case IrInstructionIdReturnPtr:
|
||||
return "ReturnPtr";
|
||||
case IrInstructionIdCallSrc:
|
||||
return "CallSrc";
|
||||
case IrInstructionIdCallGen:
|
||||
return "CallGen";
|
||||
case IrInstructionIdConst:
|
||||
return "Const";
|
||||
case IrInstructionIdReturn:
|
||||
return "Return";
|
||||
case IrInstructionIdCast:
|
||||
return "Cast";
|
||||
case IrInstructionIdResizeSlice:
|
||||
return "ResizeSlice";
|
||||
case IrInstructionIdContainerInitList:
|
||||
return "ContainerInitList";
|
||||
case IrInstructionIdContainerInitFields:
|
||||
return "ContainerInitFields";
|
||||
case IrInstructionIdUnreachable:
|
||||
return "Unreachable";
|
||||
case IrInstructionIdTypeOf:
|
||||
return "TypeOf";
|
||||
case IrInstructionIdSetCold:
|
||||
return "SetCold";
|
||||
case IrInstructionIdSetRuntimeSafety:
|
||||
return "SetRuntimeSafety";
|
||||
case IrInstructionIdSetFloatMode:
|
||||
return "SetFloatMode";
|
||||
case IrInstructionIdArrayType:
|
||||
return "ArrayType";
|
||||
case IrInstructionIdAnyFrameType:
|
||||
return "AnyFrameType";
|
||||
case IrInstructionIdSliceType:
|
||||
return "SliceType";
|
||||
case IrInstructionIdGlobalAsm:
|
||||
return "GlobalAsm";
|
||||
case IrInstructionIdAsm:
|
||||
return "Asm";
|
||||
case IrInstructionIdSizeOf:
|
||||
return "SizeOf";
|
||||
case IrInstructionIdTestNonNull:
|
||||
return "TestNonNull";
|
||||
case IrInstructionIdOptionalUnwrapPtr:
|
||||
return "OptionalUnwrapPtr";
|
||||
case IrInstructionIdOptionalWrap:
|
||||
return "OptionalWrap";
|
||||
case IrInstructionIdUnionTag:
|
||||
return "UnionTag";
|
||||
case IrInstructionIdClz:
|
||||
return "Clz";
|
||||
case IrInstructionIdCtz:
|
||||
return "Ctz";
|
||||
case IrInstructionIdPopCount:
|
||||
return "PopCount";
|
||||
case IrInstructionIdBswap:
|
||||
return "Bswap";
|
||||
case IrInstructionIdBitReverse:
|
||||
return "BitReverse";
|
||||
case IrInstructionIdImport:
|
||||
return "Import";
|
||||
case IrInstructionIdCImport:
|
||||
return "CImport";
|
||||
case IrInstructionIdCInclude:
|
||||
return "CInclude";
|
||||
case IrInstructionIdCDefine:
|
||||
return "CDefine";
|
||||
case IrInstructionIdCUndef:
|
||||
return "CUndef";
|
||||
case IrInstructionIdRef:
|
||||
return "Ref";
|
||||
case IrInstructionIdRefGen:
|
||||
return "RefGen";
|
||||
case IrInstructionIdCompileErr:
|
||||
return "CompileErr";
|
||||
case IrInstructionIdCompileLog:
|
||||
return "CompileLog";
|
||||
case IrInstructionIdErrName:
|
||||
return "ErrName";
|
||||
case IrInstructionIdEmbedFile:
|
||||
return "EmbedFile";
|
||||
case IrInstructionIdCmpxchgSrc:
|
||||
return "CmpxchgSrc";
|
||||
case IrInstructionIdCmpxchgGen:
|
||||
return "CmpxchgGen";
|
||||
case IrInstructionIdFence:
|
||||
return "Fence";
|
||||
case IrInstructionIdTruncate:
|
||||
return "Truncate";
|
||||
case IrInstructionIdIntCast:
|
||||
return "IntCast";
|
||||
case IrInstructionIdFloatCast:
|
||||
return "FloatCast";
|
||||
case IrInstructionIdIntToFloat:
|
||||
return "IntToFloat";
|
||||
case IrInstructionIdFloatToInt:
|
||||
return "FloatToInt";
|
||||
case IrInstructionIdBoolToInt:
|
||||
return "BoolToInt";
|
||||
case IrInstructionIdIntType:
|
||||
return "IntType";
|
||||
case IrInstructionIdVectorType:
|
||||
return "VectorType";
|
||||
case IrInstructionIdBoolNot:
|
||||
return "BoolNot";
|
||||
case IrInstructionIdMemset:
|
||||
return "Memset";
|
||||
case IrInstructionIdMemcpy:
|
||||
return "Memcpy";
|
||||
case IrInstructionIdSliceSrc:
|
||||
return "SliceSrc";
|
||||
case IrInstructionIdSliceGen:
|
||||
return "SliceGen";
|
||||
case IrInstructionIdMemberCount:
|
||||
return "MemberCount";
|
||||
case IrInstructionIdMemberType:
|
||||
return "MemberType";
|
||||
case IrInstructionIdMemberName:
|
||||
return "MemberName";
|
||||
case IrInstructionIdBreakpoint:
|
||||
return "Breakpoint";
|
||||
case IrInstructionIdReturnAddress:
|
||||
return "ReturnAddress";
|
||||
case IrInstructionIdFrameAddress:
|
||||
return "FrameAddress";
|
||||
case IrInstructionIdFrameHandle:
|
||||
return "FrameHandle";
|
||||
case IrInstructionIdFrameType:
|
||||
return "FrameType";
|
||||
case IrInstructionIdFrameSizeSrc:
|
||||
return "FrameSizeSrc";
|
||||
case IrInstructionIdFrameSizeGen:
|
||||
return "FrameSizeGen";
|
||||
case IrInstructionIdAlignOf:
|
||||
return "AlignOf";
|
||||
case IrInstructionIdOverflowOp:
|
||||
return "OverflowOp";
|
||||
case IrInstructionIdTestErrSrc:
|
||||
return "TestErrSrc";
|
||||
case IrInstructionIdTestErrGen:
|
||||
return "TestErrGen";
|
||||
case IrInstructionIdMulAdd:
|
||||
return "MulAdd";
|
||||
case IrInstructionIdFloatOp:
|
||||
return "FloatOp";
|
||||
case IrInstructionIdUnwrapErrCode:
|
||||
return "UnwrapErrCode";
|
||||
case IrInstructionIdUnwrapErrPayload:
|
||||
return "UnwrapErrPayload";
|
||||
case IrInstructionIdErrWrapCode:
|
||||
return "ErrWrapCode";
|
||||
case IrInstructionIdErrWrapPayload:
|
||||
return "ErrWrapPayload";
|
||||
case IrInstructionIdFnProto:
|
||||
return "FnProto";
|
||||
case IrInstructionIdTestComptime:
|
||||
return "TestComptime";
|
||||
case IrInstructionIdPtrCastSrc:
|
||||
return "PtrCastSrc";
|
||||
case IrInstructionIdPtrCastGen:
|
||||
return "PtrCastGen";
|
||||
case IrInstructionIdBitCastSrc:
|
||||
return "BitCastSrc";
|
||||
case IrInstructionIdBitCastGen:
|
||||
return "BitCastGen";
|
||||
case IrInstructionIdWidenOrShorten:
|
||||
return "WidenOrShorten";
|
||||
case IrInstructionIdIntToPtr:
|
||||
return "IntToPtr";
|
||||
case IrInstructionIdPtrToInt:
|
||||
return "PtrToInt";
|
||||
case IrInstructionIdIntToEnum:
|
||||
return "IntToEnum";
|
||||
case IrInstructionIdEnumToInt:
|
||||
return "EnumToInt";
|
||||
case IrInstructionIdIntToErr:
|
||||
return "IntToErr";
|
||||
case IrInstructionIdErrToInt:
|
||||
return "ErrToInt";
|
||||
case IrInstructionIdCheckSwitchProngs:
|
||||
return "CheckSwitchProngs";
|
||||
case IrInstructionIdCheckStatementIsVoid:
|
||||
return "CheckStatementIsVoid";
|
||||
case IrInstructionIdTypeName:
|
||||
return "TypeName";
|
||||
case IrInstructionIdDeclRef:
|
||||
return "DeclRef";
|
||||
case IrInstructionIdPanic:
|
||||
return "Panic";
|
||||
case IrInstructionIdTagName:
|
||||
return "TagName";
|
||||
case IrInstructionIdTagType:
|
||||
return "TagType";
|
||||
case IrInstructionIdFieldParentPtr:
|
||||
return "FieldParentPtr";
|
||||
case IrInstructionIdByteOffsetOf:
|
||||
return "ByteOffsetOf";
|
||||
case IrInstructionIdBitOffsetOf:
|
||||
return "BitOffsetOf";
|
||||
case IrInstructionIdTypeInfo:
|
||||
return "TypeInfo";
|
||||
case IrInstructionIdHasField:
|
||||
return "HasField";
|
||||
case IrInstructionIdTypeId:
|
||||
return "TypeId";
|
||||
case IrInstructionIdSetEvalBranchQuota:
|
||||
return "SetEvalBranchQuota";
|
||||
case IrInstructionIdPtrType:
|
||||
return "PtrType";
|
||||
case IrInstructionIdAlignCast:
|
||||
return "AlignCast";
|
||||
case IrInstructionIdImplicitCast:
|
||||
return "ImplicitCast";
|
||||
case IrInstructionIdResolveResult:
|
||||
return "ResolveResult";
|
||||
case IrInstructionIdResetResult:
|
||||
return "ResetResult";
|
||||
case IrInstructionIdOpaqueType:
|
||||
return "OpaqueType";
|
||||
case IrInstructionIdSetAlignStack:
|
||||
return "SetAlignStack";
|
||||
case IrInstructionIdArgType:
|
||||
return "ArgType";
|
||||
case IrInstructionIdExport:
|
||||
return "Export";
|
||||
case IrInstructionIdErrorReturnTrace:
|
||||
return "ErrorReturnTrace";
|
||||
case IrInstructionIdErrorUnion:
|
||||
return "ErrorUnion";
|
||||
case IrInstructionIdAtomicRmw:
|
||||
return "AtomicRmw";
|
||||
case IrInstructionIdAtomicLoad:
|
||||
return "AtomicLoad";
|
||||
case IrInstructionIdSaveErrRetAddr:
|
||||
return "SaveErrRetAddr";
|
||||
case IrInstructionIdAddImplicitReturnType:
|
||||
return "AddImplicitReturnType";
|
||||
case IrInstructionIdErrSetCast:
|
||||
return "ErrSetCast";
|
||||
case IrInstructionIdToBytes:
|
||||
return "ToBytes";
|
||||
case IrInstructionIdFromBytes:
|
||||
return "FromBytes";
|
||||
case IrInstructionIdCheckRuntimeScope:
|
||||
return "CheckRuntimeScope";
|
||||
case IrInstructionIdVectorToArray:
|
||||
return "VectorToArray";
|
||||
case IrInstructionIdArrayToVector:
|
||||
return "ArrayToVector";
|
||||
case IrInstructionIdAssertZero:
|
||||
return "AssertZero";
|
||||
case IrInstructionIdAssertNonNull:
|
||||
return "AssertNonNull";
|
||||
case IrInstructionIdHasDecl:
|
||||
return "HasDecl";
|
||||
case IrInstructionIdUndeclaredIdent:
|
||||
return "UndeclaredIdent";
|
||||
case IrInstructionIdAllocaSrc:
|
||||
return "AllocaSrc";
|
||||
case IrInstructionIdAllocaGen:
|
||||
return "AllocaGen";
|
||||
case IrInstructionIdEndExpr:
|
||||
return "EndExpr";
|
||||
case IrInstructionIdPtrOfArrayToSlice:
|
||||
return "PtrOfArrayToSlice";
|
||||
case IrInstructionIdUnionInitNamedField:
|
||||
return "UnionInitNamedField";
|
||||
case IrInstructionIdSuspendBegin:
|
||||
return "SuspendBegin";
|
||||
case IrInstructionIdSuspendFinish:
|
||||
return "SuspendFinish";
|
||||
case IrInstructionIdAwaitSrc:
|
||||
return "AwaitSrc";
|
||||
case IrInstructionIdAwaitGen:
|
||||
return "AwaitGen";
|
||||
case IrInstructionIdResume:
|
||||
return "Resume";
|
||||
case IrInstructionIdSpillBegin:
|
||||
return "SpillBegin";
|
||||
case IrInstructionIdSpillEnd:
|
||||
return "SpillEnd";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static void ir_print_indent(IrPrint *irp) {
|
||||
for (int i = 0; i < irp->indent; i += 1) {
|
||||
fprintf(irp->f, " ");
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) {
|
||||
static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction, bool trailing) {
|
||||
ir_print_indent(irp);
|
||||
const char mark = trailing ? ':' : '#';
|
||||
const char *type_name = instruction->value.type ? buf_ptr(&instruction->value.type->name) : "(unknown)";
|
||||
const char *ref_count = ir_has_side_effects(instruction) ?
|
||||
"-" : buf_ptr(buf_sprintf("%" ZIG_PRI_usize "", instruction->ref_count));
|
||||
fprintf(irp->f, "#%-3zu| %-12s| %-2s| ", instruction->debug_id, type_name, ref_count);
|
||||
fprintf(irp->f, "%c%-3zu| %-22s| %-12s| %-2s| ", mark, instruction->debug_id,
|
||||
ir_instruction_type_str(instruction), type_name, ref_count);
|
||||
}
|
||||
|
||||
static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) {
|
||||
@ -42,6 +389,10 @@ static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) {
|
||||
|
||||
static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
fprintf(irp->f, "#%" ZIG_PRI_usize "", instruction->debug_id);
|
||||
if (irp->pass_num == 2 && irp->printed.maybe_get(instruction) == nullptr) {
|
||||
irp->printed.put(instruction, 0);
|
||||
irp->pending.append(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
@ -49,6 +400,7 @@ static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction)
|
||||
fprintf(irp->f, "(null)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (instruction->value.special != ConstValSpecialRuntime) {
|
||||
ir_print_const_value(irp, &instruction->value);
|
||||
} else {
|
||||
@ -1550,8 +1902,8 @@ static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction)
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_prefix(irp, instruction);
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool trailing) {
|
||||
ir_print_prefix(irp, instruction, trailing);
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
zig_unreachable();
|
||||
@ -2036,31 +2388,48 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
||||
void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size) {
|
||||
void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, size_t pass_num) {
|
||||
IrPrint ir_print = {};
|
||||
IrPrint *irp = &ir_print;
|
||||
irp->pass_num = pass_num;
|
||||
irp->codegen = codegen;
|
||||
irp->f = f;
|
||||
irp->indent = indent_size;
|
||||
irp->indent_size = indent_size;
|
||||
irp->printed = {};
|
||||
irp->printed.init(64);
|
||||
irp->pending = {};
|
||||
|
||||
for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) {
|
||||
IrBasicBlock *current_block = executable->basic_block_list.at(bb_i);
|
||||
fprintf(irp->f, "%s_%" ZIG_PRI_usize ":\n", current_block->name_hint, current_block->debug_id);
|
||||
for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) {
|
||||
IrInstruction *instruction = current_block->instruction_list.at(instr_i);
|
||||
ir_print_instruction(irp, instruction);
|
||||
if (irp->pass_num == 2) {
|
||||
irp->printed.put(instruction, 0);
|
||||
irp->pending.clear();
|
||||
}
|
||||
ir_print_instruction(irp, instruction, false);
|
||||
for (size_t j = 0; j < irp->pending.length; ++j)
|
||||
ir_print_instruction(irp, irp->pending.at(j), true);
|
||||
}
|
||||
}
|
||||
|
||||
irp->pending.deinit();
|
||||
irp->printed.deinit();
|
||||
}
|
||||
|
||||
void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size) {
|
||||
void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, size_t pass_num) {
|
||||
IrPrint ir_print = {};
|
||||
IrPrint *irp = &ir_print;
|
||||
irp->pass_num = pass_num;
|
||||
irp->codegen = codegen;
|
||||
irp->f = f;
|
||||
irp->indent = indent_size;
|
||||
irp->indent_size = indent_size;
|
||||
irp->printed = {};
|
||||
irp->printed.init(4);
|
||||
irp->pending = {};
|
||||
|
||||
ir_print_instruction(irp, instruction);
|
||||
ir_print_instruction(irp, instruction, false);
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size);
|
||||
void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size);
|
||||
void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, size_t pass_num);
|
||||
void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, size_t pass_num);
|
||||
|
||||
#endif
|
||||
|
||||
30
src/os.cpp
30
src/os.cpp
@ -1125,27 +1125,29 @@ Error os_get_cwd(Buf *out_cwd) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
#define is_wprefix(s, prefix) \
|
||||
(wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0)
|
||||
bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
HANDLE handle = (HANDLE)_get_osfhandle(fd);
|
||||
|
||||
// Cygwin/msys's pty is a pipe.
|
||||
if (handle == INVALID_HANDLE_VALUE || GetFileType(handle) != FILE_TYPE_PIPE) {
|
||||
static bool is_stderr_cyg_pty(void) {
|
||||
HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (stderr_handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
|
||||
int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH;
|
||||
FILE_NAME_INFO *nameinfo;
|
||||
WCHAR *p = NULL;
|
||||
|
||||
FILE_NAME_INFO *nameinfo = (FILE_NAME_INFO *)allocate<char>(size);
|
||||
// Cygwin/msys's pty is a pipe.
|
||||
if (GetFileType(stderr_handle) != FILE_TYPE_PIPE) {
|
||||
return 0;
|
||||
}
|
||||
nameinfo = (FILE_NAME_INFO *)allocate<char>(size);
|
||||
if (nameinfo == NULL) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
// Check the name of the pipe:
|
||||
// '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master'
|
||||
if (GetFileInformationByHandleEx(handle, FileNameInfo, nameinfo, size)) {
|
||||
if (GetFileInformationByHandleEx(stderr_handle, FileNameInfo, nameinfo, size)) {
|
||||
nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0';
|
||||
p = nameinfo->FileName;
|
||||
if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */
|
||||
@ -1178,14 +1180,12 @@ bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd) {
|
||||
}
|
||||
free(nameinfo);
|
||||
return (p != NULL);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
bool os_stderr_tty(void) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
return _isatty(fileno(stderr)) != 0 || os_is_cygwin_pty(fileno(stderr));
|
||||
return _isatty(_fileno(stderr)) != 0 || is_stderr_cyg_pty();
|
||||
#elif defined(ZIG_OS_POSIX)
|
||||
return isatty(STDERR_FILENO) != 0;
|
||||
#else
|
||||
@ -1486,7 +1486,7 @@ WORD original_console_attributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BL
|
||||
|
||||
void os_stderr_set_color(TermColor color) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
if (os_stderr_tty()) {
|
||||
if (is_stderr_cyg_pty()) {
|
||||
set_color_posix(color);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include "list.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "error.hpp"
|
||||
#include "target.hpp"
|
||||
#include "zig_llvm.h"
|
||||
#include "windows_sdk.h"
|
||||
|
||||
@ -89,11 +88,6 @@ struct Termination {
|
||||
#define OsFile int
|
||||
#endif
|
||||
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
#undef fileno
|
||||
#define fileno _fileno
|
||||
#endif
|
||||
|
||||
struct OsTimeStamp {
|
||||
uint64_t sec;
|
||||
uint64_t nsec;
|
||||
@ -158,8 +152,6 @@ Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf
|
||||
Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
|
||||
|
||||
bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd);
|
||||
|
||||
Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);
|
||||
|
||||
#endif
|
||||
|
||||
@ -2075,7 +2075,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc) {
|
||||
res->column = first->start_column;
|
||||
res->data.param_decl.name = token_buf(name);
|
||||
res->data.param_decl.is_noalias = first->id == TokenIdKeywordNoAlias;
|
||||
res->data.param_decl.is_inline = first->id == TokenIdKeywordCompTime;
|
||||
res->data.param_decl.is_comptime = first->id == TokenIdKeywordCompTime;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -491,16 +491,6 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) {
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static ZigLLVM_EnvironmentType target_get_win32_abi() {
|
||||
FILE* files[] = { stdin, stdout, stderr, nullptr };
|
||||
for (int i = 0; files[i] != nullptr; i++) {
|
||||
if (os_is_cygwin_pty(fileno(files[i]))) {
|
||||
return ZigLLVM_GNU;
|
||||
}
|
||||
}
|
||||
return ZigLLVM_MSVC;
|
||||
}
|
||||
|
||||
void get_native_target(ZigTarget *target) {
|
||||
// first zero initialize
|
||||
*target = {};
|
||||
@ -515,9 +505,6 @@ void get_native_target(ZigTarget *target) {
|
||||
&target->abi,
|
||||
&oformat);
|
||||
target->os = get_zig_os_type(os_type);
|
||||
if (target->os == OsWindows) {
|
||||
target->abi = target_get_win32_abi();
|
||||
}
|
||||
target->is_native = true;
|
||||
if (target->abi == ZigLLVM_UnknownEnvironment) {
|
||||
target->abi = target_default_abi(target->arch, target->os);
|
||||
@ -1614,7 +1601,7 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) {
|
||||
return ZigLLVM_GNU;
|
||||
case OsUefi:
|
||||
case OsWindows:
|
||||
return ZigLLVM_MSVC;
|
||||
return ZigLLVM_MSVC;
|
||||
case OsLinux:
|
||||
case OsWASI:
|
||||
return ZigLLVM_Musl;
|
||||
|
||||
10
std/mem.zig
10
std/mem.zig
@ -117,7 +117,15 @@ pub const Allocator = struct {
|
||||
const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, a);
|
||||
assert(byte_slice.len == byte_count);
|
||||
@memset(byte_slice.ptr, undefined, byte_slice.len);
|
||||
return @bytesToSlice(T, @alignCast(a, byte_slice));
|
||||
if (alignment == null) {
|
||||
// TODO This is a workaround for zig not being able to successfully do
|
||||
// @bytesToSlice(T, @alignCast(a, byte_slice)) without resolving alignment of T,
|
||||
// which causes a circular dependency in async functions which try to heap-allocate
|
||||
// their own frame with @Frame(func).
|
||||
return @intToPtr([*]T, @ptrToInt(byte_slice.ptr))[0..n];
|
||||
} else {
|
||||
return @bytesToSlice(T, @alignCast(a, byte_slice));
|
||||
}
|
||||
}
|
||||
|
||||
/// This function requests a new byte size for an existing allocation,
|
||||
|
||||
@ -65,7 +65,7 @@ pub const CreateFileError = error{
|
||||
InvalidUtf8,
|
||||
|
||||
/// On Windows, file paths cannot contain these characters:
|
||||
/// '*', '?', '"', '<', '>', '|', and '/' (when the ABI is not GNU)
|
||||
/// '/', '*', '?', '"', '<', '>', '|'
|
||||
BadPathName,
|
||||
|
||||
Unexpected,
|
||||
@ -836,10 +836,11 @@ pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16)
|
||||
// > converting the name to an NT-style name, except when using the "\\?\"
|
||||
// > prefix as detailed in the following sections.
|
||||
// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
|
||||
// Because we want the larger maximum path length for absolute paths, we
|
||||
// disallow forward slashes in zig std lib file functions on Windows.
|
||||
for (s) |byte| {
|
||||
switch (byte) {
|
||||
'*', '?', '"', '<', '>', '|' => return error.BadPathName,
|
||||
'/' => if (builtin.abi == .msvc) return error.BadPathName,
|
||||
'/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,12 +38,14 @@ pub extern fn __letf2(a: f128, b: f128) c_int {
|
||||
|
||||
// If at least one of a and b is positive, we get the same result comparing
|
||||
// a and b as signed integers as we would with a floating-point compare.
|
||||
return if ((aInt & bInt) >= 0) if (aInt < bInt)
|
||||
LE_LESS
|
||||
else if (aInt == bInt)
|
||||
LE_EQUAL
|
||||
return if ((aInt & bInt) >= 0)
|
||||
if (aInt < bInt)
|
||||
LE_LESS
|
||||
else if (aInt == bInt)
|
||||
LE_EQUAL
|
||||
else
|
||||
LE_GREATER
|
||||
else
|
||||
LE_GREATER else
|
||||
// Otherwise, both are negative, so we need to flip the sense of the
|
||||
// comparison to get the correct result. (This assumes a twos- or ones-
|
||||
// complement integer representation; if integers are represented in a
|
||||
@ -73,7 +75,6 @@ pub extern fn __getf2(a: f128, b: f128) c_int {
|
||||
|
||||
if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
|
||||
if ((aAbs | bAbs) == 0) return GE_EQUAL;
|
||||
// zig fmt issue here, see https://github.com/ziglang/zig/issues/2661
|
||||
return if ((aInt & bInt) >= 0)
|
||||
if (aInt < bInt)
|
||||
GE_LESS
|
||||
|
||||
@ -482,6 +482,27 @@ test "zig fmt: if-else with comment before else" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: if nested" {
|
||||
try testCanonical(
|
||||
\\pub fn foo() void {
|
||||
\\ return if ((aInt & bInt) >= 0)
|
||||
\\ if (aInt < bInt)
|
||||
\\ GE_LESS
|
||||
\\ else if (aInt == bInt)
|
||||
\\ GE_EQUAL
|
||||
\\ else
|
||||
\\ GE_GREATER
|
||||
\\ else if (aInt > bInt)
|
||||
\\ GE_LESS
|
||||
\\ else if (aInt == bInt)
|
||||
\\ GE_EQUAL
|
||||
\\ else
|
||||
\\ GE_GREATER;
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: respect line breaks in if-else" {
|
||||
try testCanonical(
|
||||
\\comptime {
|
||||
|
||||
@ -276,7 +276,6 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i
|
||||
} else {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type,
|
||||
}
|
||||
|
||||
} else if (field.type_expr == null and field.value_expr != null) {
|
||||
try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name
|
||||
try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // =
|
||||
@ -1521,9 +1520,12 @@ fn renderExpression(
|
||||
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, if_node.condition, Space.None); // condition
|
||||
|
||||
const body_is_if_block = if_node.body.id == ast.Node.Id.If;
|
||||
const body_is_block = nodeIsBlock(if_node.body);
|
||||
|
||||
if (body_is_block) {
|
||||
if (body_is_if_block) {
|
||||
try renderExtraNewline(tree, stream, start_col, if_node.body);
|
||||
} else if (body_is_block) {
|
||||
const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space;
|
||||
try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // )
|
||||
|
||||
|
||||
@ -2,6 +2,22 @@ const tests = @import("tests.zig");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
cases.add(
|
||||
"wrong type for result ptr to @asyncCall",
|
||||
\\export fn entry() void {
|
||||
\\ _ = async amain();
|
||||
\\}
|
||||
\\fn amain() i32 {
|
||||
\\ var frame: @Frame(foo) = undefined;
|
||||
\\ return await @asyncCall(&frame, false, foo);
|
||||
\\}
|
||||
\\fn foo() i32 {
|
||||
\\ return 1234;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:6:37: error: expected type '*i32', found 'bool'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"struct depends on itself via optional field",
|
||||
\\const LhsExpr = struct {
|
||||
@ -1051,6 +1067,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\const Foo = struct {};
|
||||
\\export fn a() void {
|
||||
\\ const T = [*c]Foo;
|
||||
\\ var t: T = undefined;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:3:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",
|
||||
@ -2290,6 +2307,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
"error union operator with non error set LHS",
|
||||
\\comptime {
|
||||
\\ const z = i32!i32;
|
||||
\\ var x: z = undefined;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:15: error: expected error set type, found type 'i32'",
|
||||
|
||||
@ -331,8 +331,9 @@ test "async fn with inferred error set" {
|
||||
|
||||
fn doTheTest() void {
|
||||
var frame: [1]@Frame(middle) = undefined;
|
||||
var result: anyerror!void = undefined;
|
||||
_ = @asyncCall(@sliceToBytes(frame[0..]), &result, middle);
|
||||
var fn_ptr = middle;
|
||||
var result: @typeOf(fn_ptr).ReturnType.ErrorSet!void = undefined;
|
||||
_ = @asyncCall(@sliceToBytes(frame[0..]), &result, fn_ptr);
|
||||
resume global_frame;
|
||||
std.testing.expectError(error.Fail, result);
|
||||
}
|
||||
@ -819,6 +820,34 @@ test "struct parameter to async function is copied to the frame" {
|
||||
}
|
||||
|
||||
test "cast fn to async fn when it is inferred to be async" {
|
||||
const S = struct {
|
||||
var frame: anyframe = undefined;
|
||||
var ok = false;
|
||||
|
||||
fn doTheTest() void {
|
||||
var ptr: async fn () i32 = undefined;
|
||||
ptr = func;
|
||||
var buf: [100]u8 align(16) = undefined;
|
||||
var result: i32 = undefined;
|
||||
const f = @asyncCall(&buf, &result, ptr);
|
||||
_ = await f;
|
||||
expect(result == 1234);
|
||||
ok = true;
|
||||
}
|
||||
|
||||
fn func() i32 {
|
||||
suspend {
|
||||
frame = @frame();
|
||||
}
|
||||
return 1234;
|
||||
}
|
||||
};
|
||||
_ = async S.doTheTest();
|
||||
resume S.frame;
|
||||
expect(S.ok);
|
||||
}
|
||||
|
||||
test "cast fn to async fn when it is inferred to be async, awaited directly" {
|
||||
const S = struct {
|
||||
var frame: anyframe = undefined;
|
||||
var ok = false;
|
||||
@ -854,3 +883,151 @@ test "await does not force async if callee is blocking" {
|
||||
var x = async S.simple();
|
||||
expect(await x == 1234);
|
||||
}
|
||||
|
||||
test "recursive async function" {
|
||||
expect(recursiveAsyncFunctionTest(false).doTheTest() == 55);
|
||||
expect(recursiveAsyncFunctionTest(true).doTheTest() == 55);
|
||||
}
|
||||
|
||||
fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type {
|
||||
return struct {
|
||||
fn fib(allocator: *std.mem.Allocator, x: u32) error{OutOfMemory}!u32 {
|
||||
if (x <= 1) return x;
|
||||
|
||||
if (suspending_implementation) {
|
||||
suspend {
|
||||
resume @frame();
|
||||
}
|
||||
}
|
||||
|
||||
const f1 = try allocator.create(@Frame(fib));
|
||||
defer allocator.destroy(f1);
|
||||
|
||||
const f2 = try allocator.create(@Frame(fib));
|
||||
defer allocator.destroy(f2);
|
||||
|
||||
f1.* = async fib(allocator, x - 1);
|
||||
var f1_awaited = false;
|
||||
errdefer if (!f1_awaited) {
|
||||
_ = await f1;
|
||||
};
|
||||
|
||||
f2.* = async fib(allocator, x - 2);
|
||||
var f2_awaited = false;
|
||||
errdefer if (!f2_awaited) {
|
||||
_ = await f2;
|
||||
};
|
||||
|
||||
var sum: u32 = 0;
|
||||
|
||||
f1_awaited = true;
|
||||
const result_f1 = await f1; // TODO https://github.com/ziglang/zig/issues/3077
|
||||
sum += try result_f1;
|
||||
|
||||
f2_awaited = true;
|
||||
const result_f2 = await f2; // TODO https://github.com/ziglang/zig/issues/3077
|
||||
sum += try result_f2;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
fn doTheTest() u32 {
|
||||
if (suspending_implementation) {
|
||||
var result: u32 = undefined;
|
||||
_ = async amain(&result);
|
||||
return result;
|
||||
} else {
|
||||
return fib(std.heap.direct_allocator, 10) catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
fn amain(result: *u32) void {
|
||||
var x = async fib(std.heap.direct_allocator, 10);
|
||||
const res = await x; // TODO https://github.com/ziglang/zig/issues/3077
|
||||
result.* = res catch unreachable;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test "@asyncCall with comptime-known function, but not awaited directly" {
|
||||
const S = struct {
|
||||
var global_frame: anyframe = undefined;
|
||||
|
||||
fn doTheTest() void {
|
||||
var frame: [1]@Frame(middle) = undefined;
|
||||
var result: @typeOf(middle).ReturnType.ErrorSet!void = undefined;
|
||||
_ = @asyncCall(@sliceToBytes(frame[0..]), &result, middle);
|
||||
resume global_frame;
|
||||
std.testing.expectError(error.Fail, result);
|
||||
}
|
||||
|
||||
async fn middle() !void {
|
||||
var f = async middle2();
|
||||
return await f;
|
||||
}
|
||||
|
||||
fn middle2() !void {
|
||||
return failing();
|
||||
}
|
||||
|
||||
fn failing() !void {
|
||||
global_frame = @frame();
|
||||
suspend;
|
||||
return error.Fail;
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
}
|
||||
|
||||
test "@asyncCall with actual frame instead of byte buffer" {
|
||||
const S = struct {
|
||||
fn func() i32 {
|
||||
suspend;
|
||||
return 1234;
|
||||
}
|
||||
};
|
||||
var frame: @Frame(S.func) = undefined;
|
||||
var result: i32 = undefined;
|
||||
const ptr = @asyncCall(&frame, &result, S.func);
|
||||
resume ptr;
|
||||
expect(result == 1234);
|
||||
}
|
||||
|
||||
test "@asyncCall using the result location inside the frame" {
|
||||
const S = struct {
|
||||
async fn simple2(y: *i32) i32 {
|
||||
defer y.* += 2;
|
||||
y.* += 1;
|
||||
suspend;
|
||||
return 1234;
|
||||
}
|
||||
fn getAnswer(f: anyframe->i32, out: *i32) void {
|
||||
var res = await f; // TODO https://github.com/ziglang/zig/issues/3077
|
||||
out.* = res;
|
||||
}
|
||||
};
|
||||
var data: i32 = 1;
|
||||
const Foo = struct {
|
||||
bar: async fn (*i32) i32,
|
||||
};
|
||||
var foo = Foo{ .bar = S.simple2 };
|
||||
var bytes: [64]u8 align(16) = undefined;
|
||||
const f = @asyncCall(&bytes, {}, foo.bar, &data);
|
||||
comptime expect(@typeOf(f) == anyframe->i32);
|
||||
expect(data == 2);
|
||||
resume f;
|
||||
expect(data == 4);
|
||||
_ = async S.getAnswer(f, &data);
|
||||
expect(data == 1234);
|
||||
}
|
||||
|
||||
test "@typeOf an async function call of generic fn with error union type" {
|
||||
const S = struct {
|
||||
fn func(comptime x: var) anyerror!i32 {
|
||||
const T = @typeOf(async func(x));
|
||||
comptime expect(T == @typeOf(@frame()).Child);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
_ = async S.func(i32);
|
||||
}
|
||||
|
||||
@ -89,3 +89,29 @@ test "@sizeOf(T) == 0 doesn't force resolving struct size" {
|
||||
expect(@sizeOf(S.Foo) == 4);
|
||||
expect(@sizeOf(S.Bar) == 8);
|
||||
}
|
||||
|
||||
test "@typeOf() has no runtime side effects" {
|
||||
const S = struct {
|
||||
fn foo(comptime T: type, ptr: *T) T {
|
||||
ptr.* += 1;
|
||||
return ptr.*;
|
||||
}
|
||||
};
|
||||
var data: i32 = 0;
|
||||
const T = @typeOf(S.foo(i32, &data));
|
||||
comptime expect(T == i32);
|
||||
expect(data == 0);
|
||||
}
|
||||
|
||||
test "branching logic inside @typeOf" {
|
||||
const S = struct {
|
||||
var data: i32 = 0;
|
||||
fn foo() anyerror!i32 {
|
||||
data += 1;
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
const T = @typeOf(S.foo() catch undefined);
|
||||
comptime expect(T == i32);
|
||||
expect(S.data == 0);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user