diff options
| -rw-r--r-- | src/analyze.cpp | 93 | ||||
| -rw-r--r-- | src/analyze.hpp | 2 | ||||
| -rw-r--r-- | src/ast_render.cpp | 33 | ||||
| -rw-r--r-- | src/codegen.cpp | 15 | ||||
| -rw-r--r-- | src/ir.cpp | 66 | ||||
| -rw-r--r-- | src/ir.hpp | 2 | ||||
| -rw-r--r-- | src/ir_print.cpp | 64 | ||||
| -rw-r--r-- | src/ir_print.hpp | 3 | ||||
| -rw-r--r-- | src/parseh.cpp | 24 | ||||
| -rw-r--r-- | test/run_tests.cpp | 13 |
10 files changed, 176 insertions, 139 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index 8bd83826d9..8f02185790 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -193,7 +193,7 @@ Scope *create_loop_scope(AstNode *node, Scope *parent) { } ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry) { - assert(node->type == NodeTypeFnDef); + assert(!node || node->type == NodeTypeFnDef); ScopeFnDef *scope = allocate<ScopeFnDef>(1); init_scope(&scope->base, ScopeIdFnDef, node, parent); scope->fn_entry = fn_entry; @@ -2341,31 +2341,20 @@ bool type_is_codegen_pointer(TypeTableEntry *type) { AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index) { if (fn_entry->param_source_nodes) return fn_entry->param_source_nodes[index]; - else + else if (fn_entry->proto_node) return fn_entry->proto_node->data.fn_proto.params.at(index); + else + return nullptr; } -static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { - assert(fn_table_entry->anal_state != FnAnalStateProbing); - if (fn_table_entry->anal_state != FnAnalStateReady) - return; - - fn_table_entry->anal_state = FnAnalStateProbing; - - AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; - - assert(fn_table_entry->fndef_scope); - if (!fn_table_entry->child_scope) - fn_table_entry->child_scope = &fn_table_entry->fndef_scope->base; - - // define local variables for parameters +void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars) { TypeTableEntry *fn_type = fn_table_entry->type_entry; assert(!fn_type->data.fn.is_generic); FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; for (size_t i = 0; i < fn_type_id->param_count; i += 1) { FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i); - AstNodeParamDecl *param_decl = ¶m_decl_node->data.param_decl; + Buf *param_name = param_decl_node ? param_decl_node->data.param_decl.name : buf_sprintf("arg%zu", i); TypeTableEntry *param_type = param_info->type; bool is_noalias = param_info->is_noalias; @@ -2380,7 +2369,7 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { } VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, - param_decl->name, true, create_const_runtime(param_type)); + param_name, true, create_const_runtime(param_type)); var->src_arg_index = i; fn_table_entry->child_scope = var->child_scope; @@ -2391,30 +2380,20 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { if (fn_type->data.fn.gen_param_info) { var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index; } - } - - TypeTableEntry *expected_type = fn_type_id->return_type; - if (fn_type_id->is_extern && handle_is_ptr(expected_type)) { - add_node_error(g, fn_proto->return_type, - buf_sprintf("byvalue types not yet supported on extern function return values")); + if (arg_vars) { + arg_vars[i] = var; + } } +} - ir_gen_fn(g, fn_table_entry); - if (fn_table_entry->ir_executable.invalid) { - fn_table_entry->anal_state = FnAnalStateInvalid; - return; - } - if (g->verbose) { - fprintf(stderr, "\n"); - ast_render(stderr, fn_table_entry->fn_def_node, 4); - fprintf(stderr, "\n{ // (IR)\n"); - ir_print(stderr, &fn_table_entry->ir_executable, 4); - fprintf(stderr, "}\n"); - } +void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node) { + TypeTableEntry *fn_type = fn_table_entry->type_entry; + assert(!fn_type->data.fn.is_generic); + FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable, - &fn_table_entry->analyzed_executable, expected_type, fn_proto->return_type); + &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node); fn_table_entry->implicit_return_type = block_return_type; if (block_return_type->id == TypeTableEntryIdInvalid || @@ -2434,6 +2413,46 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { fn_table_entry->anal_state = FnAnalStateComplete; } +static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { + assert(fn_table_entry->anal_state != FnAnalStateProbing); + if (fn_table_entry->anal_state != FnAnalStateReady) + return; + + fn_table_entry->anal_state = FnAnalStateProbing; + + AstNode *return_type_node = fn_table_entry->proto_node->data.fn_proto.return_type; + + assert(fn_table_entry->fndef_scope); + if (!fn_table_entry->child_scope) + fn_table_entry->child_scope = &fn_table_entry->fndef_scope->base; + + define_local_param_variables(g, fn_table_entry, nullptr); + + TypeTableEntry *fn_type = fn_table_entry->type_entry; + assert(!fn_type->data.fn.is_generic); + FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; + + if (fn_type_id->is_extern && handle_is_ptr(fn_type_id->return_type)) { + add_node_error(g, return_type_node, + buf_sprintf("byvalue types not yet supported on extern function return values")); + } + + ir_gen_fn(g, fn_table_entry); + if (fn_table_entry->ir_executable.invalid) { + fn_table_entry->anal_state = FnAnalStateInvalid; + return; + } + if (g->verbose) { + fprintf(stderr, "\n"); + ast_render(stderr, fn_table_entry->fn_def_node, 4); + fprintf(stderr, "\n{ // (IR)\n"); + ir_print(stderr, &fn_table_entry->ir_executable, 4); + fprintf(stderr, "}\n"); + } + + analyze_fn_ir(g, fn_table_entry, return_type_node); +} + static void add_symbols_from_import(CodeGen *g, AstNode *dst_use_node) { IrInstruction *use_target_value = dst_use_node->data.use.value; if (use_target_value->value.type->id == TypeTableEntryIdInvalid) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 4132f463f0..2fef9cc0d8 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -83,6 +83,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b); void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max); void render_const_value(Buf *buf, ConstExprValue *const_val); +void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars); +void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_type_node); ScopeBlock *create_block_scope(AstNode *node, Scope *parent); ScopeDefer *create_defer_scope(AstNode *node, Scope *parent); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index acec9d05c4..2b5eb7f890 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -908,7 +908,8 @@ static void ast_render_tld_fn(AstRender *ar, Buf *name, TldFn *tld_fn) { if (param_info->is_noalias) { fprintf(ar->f, "noalias "); } - fprintf(ar->f, "%s: %s", buf_ptr(tld_fn->fn_entry->param_names[i]), buf_ptr(¶m_info->type->name)); + Buf *param_name = tld_fn->fn_entry->param_names ? tld_fn->fn_entry->param_names[i] : buf_sprintf("arg%zu", i); + fprintf(ar->f, "%s: %s", buf_ptr(param_name), buf_ptr(¶m_info->type->name)); } if (fn_type_id->return_type->id == TypeTableEntryIdVoid) { fprintf(ar->f, ");\n"); @@ -947,24 +948,28 @@ static void ast_render_tld_var(AstRender *ar, Buf *name, TldVar *tld_var) { if (type_entry->id == TypeTableEntryIdStruct) { const char *extern_str = extern_string(type_entry->data.structure.is_extern); fprintf(ar->f, "%sstruct {\n", extern_str); - for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { - TypeStructField *field = &type_entry->data.structure.fields[i]; - fprintf(ar->f, " "); - print_symbol(ar, field->name); - fprintf(ar->f, ": %s,\n", buf_ptr(&field->type_entry->name)); + if (type_entry->data.structure.complete) { + for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { + TypeStructField *field = &type_entry->data.structure.fields[i]; + fprintf(ar->f, " "); + print_symbol(ar, field->name); + fprintf(ar->f, ": %s,\n", buf_ptr(&field->type_entry->name)); + } } fprintf(ar->f, "}"); } else if (type_entry->id == TypeTableEntryIdEnum) { const char *extern_str = extern_string(type_entry->data.enumeration.is_extern); fprintf(ar->f, "%senum {\n", extern_str); - for (size_t i = 0; i < type_entry->data.enumeration.src_field_count; i += 1) { - TypeEnumField *field = &type_entry->data.enumeration.fields[i]; - fprintf(ar->f, " "); - print_symbol(ar, field->name); - if (field->type_entry->id == TypeTableEntryIdVoid) { - fprintf(ar->f, ",\n"); - } else { - fprintf(ar->f, ": %s,\n", buf_ptr(&field->type_entry->name)); + if (type_entry->data.enumeration.complete) { + for (size_t i = 0; i < type_entry->data.enumeration.src_field_count; i += 1) { + TypeEnumField *field = &type_entry->data.enumeration.fields[i]; + fprintf(ar->f, " "); + print_symbol(ar, field->name); + if (field->type_entry->id == TypeTableEntryIdVoid) { + fprintf(ar->f, ",\n"); + } else { + fprintf(ar->f, ": %s,\n", buf_ptr(&field->type_entry->name)); + } } } fprintf(ar->f, "}"); diff --git a/src/codegen.cpp b/src/codegen.cpp index a87a77f33b..cbaf974cd4 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -287,6 +287,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { assert(scope->parent); ScopeFnDef *fn_scope = (ScopeFnDef *)scope; FnTableEntry *fn_table_entry = fn_scope->fn_entry; + if (!fn_table_entry->proto_node) + return get_di_scope(g, scope->parent); unsigned line_number = fn_table_entry->proto_node->line + 1; unsigned scope_line = line_number; bool is_definition = fn_table_entry->fn_def_node != nullptr; @@ -2808,7 +2810,6 @@ static void do_code_gen(CodeGen *g) { continue; assert(var->decl_node); - assert(var->decl_node->type == NodeTypeVariableDeclaration); LLVMValueRef global_value; if (var->is_extern) { @@ -3033,9 +3034,11 @@ static void do_code_gen(CodeGen *g) { unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->value.type->type_ref); LLVMSetAlignment(var->value_ref, align_bytes); } - var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), - buf_ptr(&var->name), import->di_file, var->decl_node->line + 1, - gen_type->di_type, !g->strip_debug_symbols, 0, var->gen_arg_index + 1); + if (var->decl_node) { + var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), + buf_ptr(&var->name), import->di_file, var->decl_node->line + 1, + gen_type->di_type, !g->strip_debug_symbols, 0, var->gen_arg_index + 1); + } } } @@ -3062,7 +3065,9 @@ static void do_code_gen(CodeGen *g) { LLVMBuildStore(g->builder, LLVMGetParam(fn, variable->gen_arg_index), variable->value_ref); } - gen_var_debug_decl(g, variable); + if (variable->decl_node) { + gen_var_debug_decl(g, variable); + } } ir_render(g, fn_table_entry); diff --git a/src/ir.cpp b/src/ir.cpp index c5d647cdca..c5293e2af1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -500,7 +500,6 @@ static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_no template<typename T> static T *ir_build_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { - assert(source_node); T *special_instruction = ir_create_instruction<T>(irb, scope, source_node); ir_instruction_append(irb->current_basic_block, &special_instruction->base); return special_instruction; @@ -10120,7 +10119,7 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc find_libc_include_path(ira->codegen); ImportTableEntry *child_import = allocate<ImportTableEntry>(1); - child_import->decls_scope = create_decls_scope(child_import->root, nullptr, nullptr, child_import); + child_import->decls_scope = create_decls_scope(node, nullptr, nullptr, child_import); child_import->c_import_node = node; ZigList<ErrorMsg *> errors = {0}; @@ -10143,7 +10142,7 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc if (ira->codegen->verbose) { fprintf(stderr, "\nC imports:\n"); fprintf(stderr, "-----------\n"); - ir_print_decls(stderr, child_import); + ast_render_decls(stderr, 4, child_import); } // TODO to get fewer false negatives on this, we would need to track this value in @@ -11546,3 +11545,64 @@ bool ir_has_side_effects(IrInstruction *instruction) { zig_unreachable(); } +FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableEntry *var, Scope *parent_scope) { + FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, true); + buf_init_from_buf(&fn_entry->symbol_name, fn_name); + + fn_entry->fndef_scope = create_fndef_scope(nullptr, parent_scope, fn_entry); + fn_entry->child_scope = &fn_entry->fndef_scope->base; + + assert(var->value.type->id == TypeTableEntryIdMaybe); + TypeTableEntry *src_fn_type = var->value.type->data.maybe.child_type; + assert(src_fn_type->id == TypeTableEntryIdFn); + + FnTypeId new_fn_type = src_fn_type->data.fn.fn_type_id; + new_fn_type.is_extern = false; + + fn_entry->type_entry = get_fn_type(codegen, &new_fn_type); + + IrBuilder ir_builder = {0}; + IrBuilder *irb = &ir_builder; + + irb->codegen = codegen; + irb->exec = &fn_entry->ir_executable; + + AstNode *source_node = parent_scope->source_node; + + size_t arg_count = fn_entry->type_entry->data.fn.fn_type_id.param_count; + IrInstruction **args = allocate<IrInstruction *>(arg_count); + VariableTableEntry **arg_vars = allocate<VariableTableEntry *>(arg_count); + + define_local_param_variables(codegen, fn_entry, arg_vars); + Scope *scope = fn_entry->child_scope; + + irb->current_basic_block = ir_build_basic_block(irb, scope, "Entry"); + // Entry block gets a reference because we enter it to begin. + ir_ref_bb(irb->current_basic_block); + + IrInstruction *maybe_fn_ptr = ir_build_var_ptr(irb, scope, source_node, var, true); + IrInstruction *unwrapped_fn_ptr = ir_build_unwrap_maybe(irb, scope, source_node, maybe_fn_ptr, true); + IrInstruction *fn_ref_instruction = ir_build_load_ptr(irb, scope, source_node, unwrapped_fn_ptr); + + for (size_t i = 0; i < arg_count; i += 1) { + IrInstruction *var_ptr_instruction = ir_build_var_ptr(irb, scope, source_node, arg_vars[i], true); + args[i] = ir_build_load_ptr(irb, scope, source_node, var_ptr_instruction); + } + + IrInstruction *call_instruction = ir_build_call(irb, scope, source_node, nullptr, fn_ref_instruction, + arg_count, args, false); + ir_build_return(irb, scope, source_node, call_instruction); + + if (codegen->verbose) { + fprintf(stderr, "{\n"); + ir_print(stderr, &fn_entry->ir_executable, 4); + fprintf(stderr, "}\n"); + } + + analyze_fn_ir(codegen, fn_entry, nullptr); + + codegen->fn_defs.append(fn_entry); + + return fn_entry; +} + diff --git a/src/ir.hpp b/src/ir.hpp index b00ccd8130..8df905e872 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -24,4 +24,6 @@ TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutabl bool ir_has_side_effects(IrInstruction *instruction); ConstExprValue *const_ptr_pointee(ConstExprValue *const_val); +FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableEntry *var, Scope *parent_scope); + #endif diff --git a/src/ir_print.cpp b/src/ir_print.cpp index c05e51cf1a..1598d69491 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1093,67 +1093,3 @@ void ir_print(FILE *f, IrExecutable *executable, int indent_size) { } } } - -static void print_tld_var(IrPrint *irp, TldVar *tld_var) { - const char *const_or_var = tld_var->var->src_is_const ? "const" : "var"; - fprintf(irp->f, "%s %s", const_or_var, buf_ptr(tld_var->base.name)); - bool omit_type = (tld_var->var->value.type->id == TypeTableEntryIdNumLitFloat || - tld_var->var->value.type->id == TypeTableEntryIdNumLitInt); - if (!omit_type) { - fprintf(irp->f, ": %s", buf_ptr(&tld_var->var->value.type->name)); - } - if (tld_var->var->value.special != ConstValSpecialRuntime) { - fprintf(irp->f, " = "); - ir_print_const_value(irp, &tld_var->var->value); - } - fprintf(irp->f, ";\n"); -} - -static void print_tld_fn(IrPrint *irp, TldFn *tld_fn) { - fprintf(irp->f, "// %s = TODO (function)\n", buf_ptr(tld_fn->base.name)); -} - -static void print_tld_container(IrPrint *irp, TldContainer *tld_container) { - fprintf(irp->f, "// %s = TODO (container)\n", buf_ptr(tld_container->base.name)); -} - -static void print_tld_typedef(IrPrint *irp, TldTypeDef *tld_typedef) { - fprintf(irp->f, "// %s = TODO (typedef)\n", buf_ptr(tld_typedef->base.name)); -} - -void ir_print_decls(FILE *f, ImportTableEntry *import) { - IrPrint ir_print = {}; - IrPrint *irp = &ir_print; - irp->f = f; - irp->indent = 0; - irp->indent_size = 2; - - auto it = import->decls_scope->decl_table.entry_iterator(); - for (;;) { - auto *entry = it.next(); - if (!entry) - break; - - Tld *tld = entry->value; - if (!buf_eql_buf(entry->key, tld->name)) { - fprintf(f, "// alias: %s = %s\n", buf_ptr(entry->key), buf_ptr(tld->name)); - continue; - } - - switch (tld->id) { - case TldIdVar: - print_tld_var(irp, (TldVar *)tld); - continue; - case TldIdFn: - print_tld_fn(irp, (TldFn *)tld); - continue; - case TldIdContainer: - print_tld_container(irp, (TldContainer *)tld); - continue; - case TldIdTypeDef: - print_tld_typedef(irp, (TldTypeDef *)tld); - continue; - } - zig_unreachable(); - } -} diff --git a/src/ir_print.hpp b/src/ir_print.hpp index 3510187476..7126b1e57f 100644 --- a/src/ir_print.hpp +++ b/src/ir_print.hpp @@ -14,7 +14,4 @@ void ir_print(FILE *f, IrExecutable *executable, int indent_size); -void ir_print_decls(FILE *f, ImportTableEntry *import); - - #endif diff --git a/src/parseh.cpp b/src/parseh.cpp index b4ad039020..c2546765e4 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -5,14 +5,15 @@ * See http://opensource.org/licenses/MIT */ -#include "parseh.hpp" +#include "all_types.hpp" +#include "analyze.hpp" +#include "c_tokenizer.hpp" #include "config.h" -#include "os.hpp" #include "error.hpp" +#include "ir.hpp" +#include "os.hpp" +#include "parseh.hpp" #include "parser.hpp" -#include "all_types.hpp" -#include "c_tokenizer.hpp" -#include "analyze.hpp" #include <clang/Frontend/ASTUnit.h> #include <clang/Frontend/CompilerInstance.h> @@ -133,6 +134,13 @@ static void parseh_init_tld(Context *c, Tld *tld, TldId id, Buf *name) { tld->resolution = TldResolutionOk; } +static Tld *create_inline_fn_tld(Context *c, Buf *fn_name, TldVar *tld_var) { + TldFn *tld_fn = allocate<TldFn>(1); + parseh_init_tld(c, &tld_fn->base, TldIdFn, fn_name); + tld_fn->fn_entry = ir_create_inline_fn(c->codegen, fn_name, tld_var->var, &c->import->decls_scope->base); + return &tld_fn->base; +} + static TldVar *create_global_var(Context *c, Buf *name, ConstExprValue *var_value, bool is_const) { auto entry = c->import->decls_scope->decl_table.maybe_get(name); if (entry) { @@ -143,6 +151,7 @@ static TldVar *create_global_var(Context *c, Buf *name, ConstExprValue *var_valu TldVar *tld_var = allocate<TldVar>(1); parseh_init_tld(c, &tld_var->base, TldIdVar, name); tld_var->var = add_variable(c->codegen, c->source_node, &c->import->decls_scope->base, name, is_const, var_value); + c->codegen->global_vars.append(tld_var->var); return tld_var; } @@ -1229,9 +1238,8 @@ static void process_symbol_macros(Context *c) { if (var_type->id == TypeTableEntryIdMaybe && !tld_var->var->src_is_const) { TypeTableEntry *child_type = var_type->data.maybe.child_type; if (child_type->id == TypeTableEntryIdFn) { - zig_panic("TODO macro alias of function pointer in .h file"); - //Tld *fn_tld = create_inline_fn_alias(c, ms.name, tld_var->var); - //c->macro_table.put(ms.name, fn_tld); + Tld *tld = create_inline_fn_tld(c, ms.name, tld_var); + c->macro_table.put(ms.name, tld); continue; } } diff --git a/test/run_tests.cpp b/test/run_tests.cpp index cc61a2a684..e5badea1c8 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -202,7 +202,7 @@ static TestCase *add_parseh_case(const char *case_name, AllowWarnings allow_warn test_case->compiler_args.append("parseh"); test_case->compiler_args.append(tmp_h_path); - test_case->compiler_args.append("--verbose"); + //test_case->compiler_args.append("--verbose"); test_cases.append(test_case); @@ -1883,11 +1883,14 @@ Foo fun(Foo *a); R"SOURCE( extern void (*fn_ptr)(void); #define foo fn_ptr - )SOURCE", 2, + +extern char (*fn_ptr2)(int, float); +#define bar fn_ptr2 + )SOURCE", 4, "pub extern var fn_ptr: ?extern fn();", - R"SOURCE(pub inline fn foo() { - (??fn_ptr)(); -})SOURCE"); + "pub fn foo();", + "pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8;", + "pub fn bar(arg0: c_int, arg1: f32) -> u8;"); add_parseh_case("#define string", AllowWarningsNo, R"SOURCE( |
