parent
3a326d5005
commit
32821e7098
|
@ -566,6 +566,7 @@ struct AstNodeSymbolExpr {
|
|||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
VariableTableEntry *variable;
|
||||
FnTableEntry *fn_entry;
|
||||
};
|
||||
|
||||
struct AstNodeBoolLiteral {
|
||||
|
@ -720,7 +721,12 @@ struct TypeTableEntryEnum {
|
|||
struct TypeTableEntryFn {
|
||||
TypeTableEntry *return_type;
|
||||
TypeTableEntry **param_types;
|
||||
int param_count;
|
||||
int src_param_count;
|
||||
LLVMTypeRef raw_type_ref;
|
||||
bool is_var_args;
|
||||
int gen_param_count;
|
||||
LLVMCallConv calling_convention;
|
||||
bool is_naked;
|
||||
};
|
||||
|
||||
enum TypeTableEntryId {
|
||||
|
@ -784,6 +790,7 @@ struct ImportTableEntry {
|
|||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
|
||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> fn_type_table;
|
||||
};
|
||||
|
||||
struct LabelTableEntry {
|
||||
|
@ -797,17 +804,15 @@ struct FnTableEntry {
|
|||
LLVMValueRef fn_value;
|
||||
AstNode *proto_node;
|
||||
AstNode *fn_def_node;
|
||||
bool is_extern;
|
||||
bool internal_linkage;
|
||||
unsigned calling_convention;
|
||||
ImportTableEntry *import_entry;
|
||||
bool is_naked;
|
||||
bool is_inline;
|
||||
// Required to be a pre-order traversal of the AST. (parents must come before children)
|
||||
ZigList<BlockContext *> all_block_contexts;
|
||||
TypeTableEntry *member_of_struct;
|
||||
Buf symbol_name;
|
||||
TypeTableEntry *type_entry; // function type
|
||||
bool is_inline;
|
||||
bool internal_linkage;
|
||||
bool is_extern;
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
|
||||
|
|
|
@ -348,6 +348,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
|
|||
assert(node->type == NodeTypeFnProto);
|
||||
AstNodeFnProto *fn_proto = &node->data.fn_proto;
|
||||
|
||||
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
|
||||
fn_type->data.fn.calling_convention = fn_table_entry->internal_linkage ? LLVMFastCallConv : LLVMCCallConv;
|
||||
|
||||
for (int i = 0; i < fn_proto->directives->length; i += 1) {
|
||||
AstNode *directive_node = fn_proto->directives->at(i);
|
||||
Buf *name = &directive_node->data.directive.name;
|
||||
|
@ -356,7 +359,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
|
|||
Buf *attr_name = &directive_node->data.directive.param;
|
||||
if (fn_table_entry->fn_def_node) {
|
||||
if (buf_eql_str(attr_name, "naked")) {
|
||||
fn_table_entry->is_naked = true;
|
||||
fn_type->data.fn.is_naked = true;
|
||||
} else if (buf_eql_str(attr_name, "inline")) {
|
||||
fn_table_entry->is_inline = true;
|
||||
} else {
|
||||
|
@ -373,20 +376,24 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
|
|||
}
|
||||
}
|
||||
|
||||
int param_count = node->data.fn_proto.params.length;
|
||||
int src_param_count = node->data.fn_proto.params.length;
|
||||
|
||||
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
|
||||
fn_type->data.fn.param_count = param_count;
|
||||
fn_type->data.fn.param_types = allocate<TypeTableEntry*>(param_count);
|
||||
fn_type->size_in_bits = g->pointer_size_bytes * 8;
|
||||
fn_type->align_in_bits = g->pointer_size_bytes * 8;
|
||||
fn_type->data.fn.src_param_count = src_param_count;
|
||||
fn_type->data.fn.param_types = allocate<TypeTableEntry*>(src_param_count);
|
||||
|
||||
fn_table_entry->type_entry = fn_type;
|
||||
|
||||
buf_resize(&fn_type->name, 0);
|
||||
buf_appendf(&fn_type->name, "fn(");
|
||||
const char *export_str = fn_table_entry->internal_linkage ? "" : "export ";
|
||||
const char *inline_str = fn_table_entry->is_inline ? "inline " : "";
|
||||
const char *naked_str = fn_type->data.fn.is_naked ? "naked " : "";
|
||||
buf_appendf(&fn_type->name, "%s%s%sfn(", export_str, inline_str, naked_str);
|
||||
int gen_param_count = 0;
|
||||
LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(param_count);
|
||||
LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(1 + param_count);
|
||||
for (int i = 0; i < param_count; i += 1) {
|
||||
LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(src_param_count);
|
||||
LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(1 + src_param_count);
|
||||
for (int i = 0; i < src_param_count; i += 1) {
|
||||
AstNode *child = node->data.fn_proto.params.at(i);
|
||||
assert(child->type == NodeTypeParamDecl);
|
||||
TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context,
|
||||
|
@ -416,6 +423,13 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
|
|||
}
|
||||
}
|
||||
|
||||
fn_type->data.fn.gen_param_count = gen_param_count;
|
||||
fn_type->data.fn.is_var_args = fn_proto->is_var_args;
|
||||
if (fn_proto->is_var_args) {
|
||||
const char *comma = (gen_param_count == 0) ? "" : ", ";
|
||||
buf_appendf(&fn_type->name, "%s...", comma);
|
||||
}
|
||||
|
||||
TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context,
|
||||
node->data.fn_proto.return_type);
|
||||
fn_type->data.fn.return_type = return_type;
|
||||
|
@ -432,16 +446,29 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
|
|||
return;
|
||||
}
|
||||
|
||||
fn_type->type_ref = LLVMFunctionType(return_type->type_ref, gen_param_types, gen_param_count,
|
||||
fn_proto->is_var_args);
|
||||
auto table_entry = import->fn_type_table.maybe_get(&fn_type->name);
|
||||
if (table_entry) {
|
||||
fn_type = table_entry->value;
|
||||
fn_table_entry->type_entry = fn_type;
|
||||
} else {
|
||||
fn_type->data.fn.raw_type_ref = LLVMFunctionType(return_type->type_ref, gen_param_types, gen_param_count,
|
||||
fn_type->data.fn.is_var_args);
|
||||
fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
|
||||
param_di_types[0] = return_type->di_type;
|
||||
fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, import->di_file,
|
||||
param_di_types, gen_param_count + 1, 0);
|
||||
|
||||
import->fn_type_table.put(&fn_type->name, fn_type);
|
||||
}
|
||||
|
||||
|
||||
fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(&fn_table_entry->symbol_name),
|
||||
fn_table_entry->type_entry->type_ref);
|
||||
fn_type->data.fn.raw_type_ref);
|
||||
|
||||
if (fn_table_entry->is_inline) {
|
||||
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute);
|
||||
}
|
||||
if (fn_table_entry->is_naked) {
|
||||
if (fn_type->data.fn.is_naked) {
|
||||
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute);
|
||||
}
|
||||
|
||||
|
@ -451,15 +478,11 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
|
|||
if (return_type->id == TypeTableEntryIdUnreachable) {
|
||||
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
|
||||
}
|
||||
LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_table_entry->calling_convention);
|
||||
LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention);
|
||||
if (!fn_table_entry->is_extern) {
|
||||
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute);
|
||||
}
|
||||
|
||||
param_di_types[0] = return_type->di_type;
|
||||
LLVMZigDISubroutineType *di_sub_type = LLVMZigCreateSubroutineType(g->dbuilder, import->di_file,
|
||||
param_di_types, gen_param_count + 1, 0);
|
||||
|
||||
// Add debug info.
|
||||
unsigned line_number = node->line + 1;
|
||||
unsigned scope_line = line_number;
|
||||
|
@ -469,9 +492,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
|
|||
LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder,
|
||||
import->block_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
|
||||
import->di_file, line_number,
|
||||
di_sub_type, fn_table_entry->internal_linkage,
|
||||
fn_type->di_type, fn_table_entry->internal_linkage,
|
||||
is_definition, scope_line, flags, is_optimized, fn_table_entry->fn_value);
|
||||
fn_type->di_type = LLVMZigSubroutineToType(di_sub_type);
|
||||
if (fn_table_entry->fn_def_node) {
|
||||
BlockContext *context = new_block_context(fn_table_entry->fn_def_node, import->block_context);
|
||||
fn_table_entry->fn_def_node->data.fn_def.block_context = context;
|
||||
|
@ -802,7 +824,6 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
|
|||
fn_table_entry->fn_def_node = fn_def_node;
|
||||
fn_table_entry->internal_linkage = !is_c_compat;
|
||||
fn_table_entry->is_extern = extern_node;
|
||||
fn_table_entry->calling_convention = is_c_compat ? LLVMCCallConv : LLVMFastCallConv;
|
||||
fn_table_entry->label_table.init(8);
|
||||
fn_table_entry->member_of_struct = struct_type;
|
||||
|
||||
|
@ -1677,6 +1698,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
|
|||
|
||||
auto fn_table_entry = import->fn_table.maybe_get(variable_name);
|
||||
if (fn_table_entry) {
|
||||
node->data.symbol_expr.fn_entry = fn_table_entry->value;
|
||||
return resolve_expr_const_val_as_fn(g, node, fn_table_entry->value);
|
||||
}
|
||||
|
||||
|
@ -2823,15 +2845,21 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
|
|||
// otherwise we treat this as a function pointer.
|
||||
ConstExprValue *const_val = &get_resolved_expr(fn_ref_expr)->const_val;
|
||||
|
||||
if (!const_val->ok) {
|
||||
add_node_error(g, node, buf_sprintf("function pointers not yet supported"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
if (const_val->ok) {
|
||||
if (invoke_type_entry->id == TypeTableEntryIdMetaType) {
|
||||
return analyze_cast_expr(g, import, context, node);
|
||||
} else if (invoke_type_entry->id == TypeTableEntryIdFn) {
|
||||
return analyze_fn_call_raw(g, import, context, expected_type, node, const_val->data.x_fn, nullptr);
|
||||
} else {
|
||||
add_node_error(g, fn_ref_expr,
|
||||
buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
if (invoke_type_entry->id == TypeTableEntryIdMetaType) {
|
||||
return analyze_cast_expr(g, import, context, node);
|
||||
} else if (invoke_type_entry->id == TypeTableEntryIdFn) {
|
||||
return analyze_fn_call_raw(g, import, context, expected_type, node, const_val->data.x_fn, nullptr);
|
||||
// function pointer
|
||||
if (invoke_type_entry->id == TypeTableEntryIdFn) {
|
||||
return invoke_type_entry->data.fn.return_type;
|
||||
} else {
|
||||
add_node_error(g, fn_ref_expr,
|
||||
buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
|
||||
|
|
|
@ -82,24 +82,11 @@ static TypeTableEntry *get_type_for_type_node(AstNode *node) {
|
|||
return const_val->data.x_type;
|
||||
}
|
||||
|
||||
static bool type_is_unreachable(CodeGen *g, AstNode *type_node) {
|
||||
return get_type_for_type_node(type_node)->id == TypeTableEntryIdUnreachable;
|
||||
}
|
||||
|
||||
static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) {
|
||||
assert(param_decl_node->type == NodeTypeParamDecl);
|
||||
return get_type_for_type_node(param_decl_node->data.param_decl.type)->size_in_bits == 0;
|
||||
}
|
||||
|
||||
static int count_non_void_params(CodeGen *g, ZigList<AstNode *> *params) {
|
||||
int result = 0;
|
||||
for (int i = 0; i < params->length; i += 1) {
|
||||
if (!is_param_decl_type_void(g, params->at(i)))
|
||||
result += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void add_debug_source_node(CodeGen *g, AstNode *node) {
|
||||
if (!g->cur_block_context)
|
||||
return;
|
||||
|
@ -446,24 +433,25 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
|
|||
}
|
||||
}
|
||||
|
||||
assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
|
||||
AstNodeFnProto *fn_proto_data = &fn_table_entry->proto_node->data.fn_proto;
|
||||
TypeTableEntry *fn_type;
|
||||
LLVMValueRef fn_val;
|
||||
if (fn_table_entry) {
|
||||
fn_val = fn_table_entry->fn_value;
|
||||
fn_type = fn_table_entry->type_entry;
|
||||
} else {
|
||||
fn_val = gen_expr(g, fn_ref_expr);
|
||||
fn_type = get_expr_type(fn_ref_expr);
|
||||
}
|
||||
|
||||
int expected_param_count = fn_proto_data->params.length;
|
||||
int expected_param_count = fn_type->data.fn.src_param_count;
|
||||
int fn_call_param_count = node->data.fn_call_expr.params.length;
|
||||
int actual_param_count = fn_call_param_count + (struct_type ? 1 : 0);
|
||||
bool is_var_args = fn_proto_data->is_var_args;
|
||||
bool is_var_args = fn_type->data.fn.is_var_args;
|
||||
assert((is_var_args && actual_param_count >= expected_param_count) ||
|
||||
actual_param_count == expected_param_count);
|
||||
|
||||
// don't really include void values
|
||||
int gen_param_count;
|
||||
if (is_var_args) {
|
||||
gen_param_count = actual_param_count;
|
||||
} else {
|
||||
gen_param_count = count_non_void_params(g, &fn_table_entry->proto_node->data.fn_proto.params);
|
||||
}
|
||||
LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(gen_param_count);
|
||||
LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
|
||||
|
||||
int gen_param_index = 0;
|
||||
if (struct_type) {
|
||||
|
@ -474,19 +462,18 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
|
|||
for (int i = 0; i < fn_call_param_count; i += 1) {
|
||||
AstNode *expr_node = node->data.fn_call_expr.params.at(i);
|
||||
LLVMValueRef param_value = gen_expr(g, expr_node);
|
||||
if (is_var_args ||
|
||||
!is_param_decl_type_void(g, fn_table_entry->proto_node->data.fn_proto.params.at(i)))
|
||||
{
|
||||
TypeTableEntry *param_type = get_expr_type(expr_node);
|
||||
if (is_var_args || param_type->size_in_bits > 0) {
|
||||
gen_param_values[gen_param_index] = param_value;
|
||||
gen_param_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
add_debug_source_node(g, node);
|
||||
LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_table_entry->fn_value,
|
||||
gen_param_values, gen_param_count, fn_table_entry->calling_convention, "");
|
||||
LLVMValueRef result = LLVMZigBuildCall(g->builder, fn_val,
|
||||
gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");
|
||||
|
||||
if (type_is_unreachable(g, fn_table_entry->proto_node->data.fn_proto.return_type)) {
|
||||
if (fn_type->data.fn.return_type->id == TypeTableEntryIdUnreachable) {
|
||||
return LLVMBuildUnreachable(g->builder);
|
||||
} else {
|
||||
return result;
|
||||
|
@ -1243,7 +1230,7 @@ static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
|
|||
LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull");
|
||||
LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull");
|
||||
LLVMBasicBlockRef end_block;
|
||||
|
||||
|
||||
bool non_null_reachable = get_expr_type(op1_node)->id != TypeTableEntryIdUnreachable;
|
||||
bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable;
|
||||
bool end_reachable = non_null_reachable || null_reachable;
|
||||
|
@ -1951,27 +1938,31 @@ static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
|
|||
}
|
||||
|
||||
static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
|
||||
VariableTableEntry *variable = find_variable(
|
||||
get_resolved_expr(node)->block_context,
|
||||
&node->data.symbol_expr.symbol);
|
||||
assert(variable);
|
||||
if (variable->type->size_in_bits == 0) {
|
||||
return nullptr;
|
||||
} else if (variable->is_ptr) {
|
||||
assert(variable->value_ref);
|
||||
if (variable->type->id == TypeTableEntryIdArray) {
|
||||
return variable->value_ref;
|
||||
} else if (variable->type->id == TypeTableEntryIdStruct ||
|
||||
variable->type->id == TypeTableEntryIdMaybe)
|
||||
{
|
||||
return variable->value_ref;
|
||||
assert(node->type == NodeTypeSymbol);
|
||||
VariableTableEntry *variable = node->data.symbol_expr.variable;
|
||||
if (variable) {
|
||||
if (variable->type->size_in_bits == 0) {
|
||||
return nullptr;
|
||||
} else if (variable->is_ptr) {
|
||||
assert(variable->value_ref);
|
||||
if (variable->type->id == TypeTableEntryIdArray) {
|
||||
return variable->value_ref;
|
||||
} else if (variable->type->id == TypeTableEntryIdStruct ||
|
||||
variable->type->id == TypeTableEntryIdMaybe)
|
||||
{
|
||||
return variable->value_ref;
|
||||
} else {
|
||||
add_debug_source_node(g, node);
|
||||
return LLVMBuildLoad(g->builder, variable->value_ref, "");
|
||||
}
|
||||
} else {
|
||||
add_debug_source_node(g, node);
|
||||
return LLVMBuildLoad(g->builder, variable->value_ref, "");
|
||||
return variable->value_ref;
|
||||
}
|
||||
} else {
|
||||
return variable->value_ref;
|
||||
}
|
||||
|
||||
FnTableEntry *fn_entry = node->data.symbol_expr.fn_entry;
|
||||
assert(fn_entry);
|
||||
return fn_entry->fn_value;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
||||
|
@ -2714,6 +2705,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
|
|||
import_entry->line_offsets = tokenization.line_offsets;
|
||||
import_entry->path = full_path;
|
||||
import_entry->fn_table.init(32);
|
||||
import_entry->fn_type_table.init(32);
|
||||
|
||||
import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color,
|
||||
&g->next_node_index);
|
||||
|
@ -3098,7 +3090,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
|
|||
// invoke `ar`
|
||||
// example:
|
||||
// # static link into libfoo.a
|
||||
// ar rcs libfoo.a foo1.o foo2.o
|
||||
// ar rcs libfoo.a foo1.o foo2.o
|
||||
zig_panic("TODO invoke ar");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -284,7 +284,7 @@ void LLVMZigReplaceDebugArrays(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type,
|
|||
reinterpret_cast<DIBuilder*>(dibuilder)->getOrCreateArray(fields));
|
||||
}
|
||||
|
||||
LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
|
||||
LLVMZigDIType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
|
||||
LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags)
|
||||
{
|
||||
SmallVector<Metadata *, 8> types;
|
||||
|
@ -297,7 +297,8 @@ LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder
|
|||
reinterpret_cast<DIFile*>(file),
|
||||
dibuilder->getOrCreateTypeArray(types),
|
||||
flags);
|
||||
return reinterpret_cast<LLVMZigDISubroutineType*>(subroutine_type);
|
||||
DIType *ditype = subroutine_type;
|
||||
return reinterpret_cast<LLVMZigDIType*>(ditype);
|
||||
}
|
||||
|
||||
unsigned LLVMZigEncoding_DW_ATE_unsigned(void) {
|
||||
|
@ -388,11 +389,6 @@ LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram) {
|
|||
return reinterpret_cast<LLVMZigDIScope*>(scope);
|
||||
}
|
||||
|
||||
LLVMZigDIType *LLVMZigSubroutineToType(LLVMZigDISubroutineType *subrtype) {
|
||||
DIType *di_type = reinterpret_cast<DISubroutineType*>(subrtype);
|
||||
return reinterpret_cast<LLVMZigDIType*>(di_type);
|
||||
}
|
||||
|
||||
LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type) {
|
||||
DIScope *scope = reinterpret_cast<DIType*>(type);
|
||||
return reinterpret_cast<LLVMZigDIScope*>(scope);
|
||||
|
@ -416,16 +412,17 @@ LLVMZigDIFile *LLVMZigCreateFile(LLVMZigDIBuilder *dibuilder, const char *filena
|
|||
|
||||
LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope,
|
||||
const char *name, const char *linkage_name, LLVMZigDIFile *file, unsigned lineno,
|
||||
LLVMZigDISubroutineType *ty, bool is_local_to_unit, bool is_definition, unsigned scope_line,
|
||||
LLVMZigDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line,
|
||||
unsigned flags, bool is_optimized, LLVMValueRef function)
|
||||
{
|
||||
Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(function));
|
||||
DISubroutineType *di_sub_type = static_cast<DISubroutineType*>(reinterpret_cast<DIType*>(fn_di_type));
|
||||
DISubprogram *result = reinterpret_cast<DIBuilder*>(dibuilder)->createFunction(
|
||||
reinterpret_cast<DIScope*>(scope),
|
||||
name, linkage_name,
|
||||
reinterpret_cast<DIFile*>(file),
|
||||
lineno,
|
||||
reinterpret_cast<DISubroutineType*>(ty),
|
||||
di_sub_type,
|
||||
is_local_to_unit, is_definition, scope_line, flags, is_optimized, unwrapped_function);
|
||||
return reinterpret_cast<LLVMZigDISubprogram*>(result);
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ void LLVMZigReplaceTemporary(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type,
|
|||
void LLVMZigReplaceDebugArrays(LLVMZigDIBuilder *dibuilder, LLVMZigDIType *type,
|
||||
LLVMZigDIType **types_array, int types_array_len);
|
||||
|
||||
LLVMZigDISubroutineType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
|
||||
LLVMZigDIType *LLVMZigCreateSubroutineType(LLVMZigDIBuilder *dibuilder_wrapped,
|
||||
LLVMZigDIFile *file, LLVMZigDIType **types_array, int types_array_len, unsigned flags);
|
||||
|
||||
unsigned LLVMZigEncoding_DW_ATE_unsigned(void);
|
||||
|
@ -101,7 +101,6 @@ LLVMZigDIScope *LLVMZigCompileUnitToScope(LLVMZigDICompileUnit *compile_unit);
|
|||
LLVMZigDIScope *LLVMZigFileToScope(LLVMZigDIFile *difile);
|
||||
LLVMZigDIScope *LLVMZigSubprogramToScope(LLVMZigDISubprogram *subprogram);
|
||||
LLVMZigDIScope *LLVMZigTypeToScope(LLVMZigDIType *type);
|
||||
LLVMZigDIType *LLVMZigSubroutineToType(LLVMZigDISubroutineType *subrtype);
|
||||
|
||||
LLVMZigDILocalVariable *LLVMZigCreateLocalVariable(LLVMZigDIBuilder *dbuilder, unsigned tag,
|
||||
LLVMZigDIScope *scope, const char *name, LLVMZigDIFile *file, unsigned line_no,
|
||||
|
@ -119,7 +118,7 @@ LLVMZigDIFile *LLVMZigCreateFile(LLVMZigDIBuilder *dibuilder, const char *filena
|
|||
|
||||
LLVMZigDISubprogram *LLVMZigCreateFunction(LLVMZigDIBuilder *dibuilder, LLVMZigDIScope *scope,
|
||||
const char *name, const char *linkage_name, LLVMZigDIFile *file, unsigned lineno,
|
||||
LLVMZigDISubroutineType *ty, bool is_local_to_unit, bool is_definition, unsigned scope_line,
|
||||
LLVMZigDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line,
|
||||
unsigned flags, bool is_optimized, LLVMValueRef function);
|
||||
|
||||
void LLVMZigDIBuilderFinalize(LLVMZigDIBuilder *dibuilder);
|
||||
|
|
|
@ -15,7 +15,7 @@ export fn _start() unreachable => {
|
|||
call_main()
|
||||
}
|
||||
|
||||
fn strlen(ptr: &u8) usize => {
|
||||
fn strlen(ptr: &const u8) usize => {
|
||||
var count: usize = 0;
|
||||
while (ptr[count] != 0) {
|
||||
count += 1;
|
||||
|
|
|
@ -1162,6 +1162,24 @@ pub fn main(args: [][]u8) i32 => {
|
|||
return 0;
|
||||
}
|
||||
)SOURCE", "9\n8\n7\n6\n0\n1\n2\n3\n9\n8\n7\n6\n0\n1\n2\n3\n");
|
||||
|
||||
add_simple_case("function pointers", R"SOURCE(
|
||||
import "std.zig";
|
||||
|
||||
pub fn main(args: [][]u8) i32 => {
|
||||
const fns = []@typeof(fn1) { fn1, fn2, fn3, fn4, };
|
||||
for (f, fns) {
|
||||
print_u64(f());
|
||||
print_str("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn fn1() u32 => {5}
|
||||
fn fn2() u32 => {6}
|
||||
fn fn3() u32 => {7}
|
||||
fn fn4() u32 => {8}
|
||||
)SOURCE", "5\n6\n7\n8\n");
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue