From 1fdebc1dc4881a00766f7c2b4b2d8ee6ad6e79b6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 18 Dec 2017 09:59:57 -0500 Subject: [PATCH 1/4] wip export rewrite --- doc/langref.html.in | 8 +- example/hello_world/hello_libc.zig | 8 +- example/mix_o_files/base64.zig | 5 +- example/shared_library/mathtest.zig | 5 +- src/all_types.hpp | 61 +- src/analyze.cpp | 129 ++-- src/analyze.hpp | 2 + src/ast_render.cpp | 21 +- src/codegen.cpp | 106 ++-- src/ir.cpp | 459 ++++++++------ src/ir_print.cpp | 40 +- src/parser.cpp | 28 +- src/tokenizer.cpp | 4 +- src/tokenizer.hpp | 2 +- src/translate_c.cpp | 6 +- std/debug.zig | 2 - std/elf.zig | 62 +- std/mem.zig | 1 + std/os/linux.zig | 22 - std/os/linux_i386.zig | 10 - std/special/bootstrap.zig | 35 +- std/special/bootstrap_lib.zig | 6 +- std/special/builtin.zig | 36 +- std/special/compiler_rt/aulldiv.zig | 119 ++-- std/special/compiler_rt/aullrem.zig | 121 ++-- std/special/compiler_rt/comparetf2.zig | 45 +- std/special/compiler_rt/fixunsdfdi.zig | 4 +- std/special/compiler_rt/fixunsdfsi.zig | 4 +- std/special/compiler_rt/fixunsdfti.zig | 4 +- std/special/compiler_rt/fixunssfdi.zig | 4 +- std/special/compiler_rt/fixunssfsi.zig | 4 +- std/special/compiler_rt/fixunssfti.zig | 4 +- std/special/compiler_rt/fixunstfdi.zig | 4 +- std/special/compiler_rt/fixunstfsi.zig | 4 +- std/special/compiler_rt/fixunstfti.zig | 4 +- std/special/compiler_rt/index.zig | 343 +++++------ std/special/compiler_rt/udivmoddi4.zig | 4 +- std/special/compiler_rt/udivmodti4.zig | 4 +- std/special/compiler_rt/udivti3.zig | 4 +- std/special/compiler_rt/umodti3.zig | 4 +- test/cases/asm.zig | 13 +- test/cases/misc.zig | 23 +- test/compare_output.zig | 16 +- test/compile_errors.zig | 822 ++++++++++++++++--------- test/standalone/issue_339/test.zig | 5 +- test/translate_c.zig | 64 +- 46 files changed, 1487 insertions(+), 1194 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index e5b896410d..f302cbec5d 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5815,13 +5815,13 @@ TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestD TestDecl = "test" String Block -TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl) +TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) ErrorValueDecl = "error" Symbol ";" GlobalVarDecl = VariableDeclaration ";" -VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression +VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression ContainerMember = (ContainerField | FnDef | GlobalVarDecl) @@ -5831,9 +5831,7 @@ UseDecl = "use" Expression ";" ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" -FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("->" TypeExpr) - -VisibleMod = "pub" | "export" +FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("->" TypeExpr) FnDef = option("inline" | "extern") FnProto Block diff --git a/example/hello_world/hello_libc.zig b/example/hello_world/hello_libc.zig index ea8aec1e4f..16d0f303cc 100644 --- a/example/hello_world/hello_libc.zig +++ b/example/hello_world/hello_libc.zig @@ -5,9 +5,13 @@ const c = @cImport({ @cInclude("string.h"); }); -const msg = c"Hello, world!\n"; +comptime { + @export("main", main); +} + +extern fn main(argc: c_int, argv: &&u8) -> c_int { + const msg = c"Hello, world!\n"; -export fn main(argc: c_int, argv: &&u8) -> c_int { if (c.printf(msg) != c_int(c.strlen(msg))) return -1; diff --git a/example/mix_o_files/base64.zig b/example/mix_o_files/base64.zig index 49c9bc6012..a8358e9685 100644 --- a/example/mix_o_files/base64.zig +++ b/example/mix_o_files/base64.zig @@ -1,6 +1,9 @@ const base64 = @import("std").base64; -export fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { +comptime { + @export("decode_base_64", decode_base_64); +} +extern fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { const src = source_ptr[0..source_len]; const dest = dest_ptr[0..dest_len]; const base64_decoder = base64.standard_decoder_unsafe; diff --git a/example/shared_library/mathtest.zig b/example/shared_library/mathtest.zig index a11642554f..f6d0a61c90 100644 --- a/example/shared_library/mathtest.zig +++ b/example/shared_library/mathtest.zig @@ -1,3 +1,6 @@ -export fn add(a: i32, b: i32) -> i32 { +comptime { + @export("add", add); +} +extern fn add(a: i32, b: i32) -> i32 { a + b } diff --git a/src/all_types.hpp b/src/all_types.hpp index c86b99d35c..9256777428 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -37,6 +37,7 @@ struct IrBasicBlock; struct ScopeDecls; struct ZigWindowsSDK; struct Tld; +struct TldExport; struct IrGotoItem { AstNode *source_node; @@ -272,7 +273,6 @@ enum ReturnKnowledge { enum VisibMod { VisibModPrivate, VisibModPub, - VisibModExport, }; enum GlobalLinkageId { @@ -313,11 +313,14 @@ struct TldVar { Tld base; VariableTableEntry *var; - AstNode *set_global_section_node; - Buf *section_name; - AstNode *set_global_linkage_node; - GlobalLinkageId linkage; Buf *extern_lib_name; + Buf *section_name; + + size_t export_count; + union { + TldExport *tld; // if export_count == 1 + TldExport **tld_list; // if export_count > 1 + } export_data; }; struct TldFn { @@ -432,6 +435,8 @@ struct AstNodeFnProto { Buf *lib_name; // populated if the "align A" is present AstNode *align_expr; + // populated if the "section(S)" is present + AstNode *section_expr; }; struct AstNodeFnDef { @@ -487,8 +492,10 @@ struct AstNodeVariableDeclaration { AstNode *expr; // populated if this is an extern declaration Buf *lib_name; - // populated if the "align A" is present + // populated if the "align(A)" is present AstNode *align_expr; + // populated if the "section(S)" is present + AstNode *section_expr; }; struct AstNodeErrorValueDecl { @@ -1177,6 +1184,12 @@ enum FnInline { FnInlineNever, }; +struct FnExport { + Buf name; + GlobalLinkageId linkage; + AstNode *source_node; +}; + struct FnTableEntry { LLVMValueRef llvm_value; const char *llvm_name; @@ -1204,12 +1217,11 @@ struct FnTableEntry { ZigList alloca_list; ZigList variable_list; - AstNode *set_global_section_node; Buf *section_name; - AstNode *set_global_linkage_node; - GlobalLinkageId linkage; AstNode *set_alignstack_node; uint32_t alignstack_value; + + ZigList export_list; }; uint32_t fn_table_entry_hash(FnTableEntry*); @@ -1258,8 +1270,6 @@ enum BuiltinFnId { BuiltinFnIdSetFloatMode, BuiltinFnIdTypeName, BuiltinFnIdCanImplicitCast, - BuiltinFnIdSetGlobalSection, - BuiltinFnIdSetGlobalLinkage, BuiltinFnIdPanic, BuiltinFnIdPtrCast, BuiltinFnIdBitCast, @@ -1279,6 +1289,8 @@ enum BuiltinFnId { BuiltinFnIdOpaqueType, BuiltinFnIdSetAlignStack, BuiltinFnIdArgType, + BuiltinFnIdExport, + BuiltinFnIdExportWithLinkage, }; struct BuiltinFnEntry { @@ -1425,7 +1437,7 @@ struct CodeGen { HashMap generic_table; HashMap memoized_fn_eval_table; HashMap llvm_fn_table; - HashMap exported_symbol_names; + HashMap exported_symbol_names; HashMap external_prototypes; @@ -1886,8 +1898,6 @@ enum IrInstructionId { IrInstructionIdCheckStatementIsVoid, IrInstructionIdTypeName, IrInstructionIdCanImplicitCast, - IrInstructionIdSetGlobalSection, - IrInstructionIdSetGlobalLinkage, IrInstructionIdDeclRef, IrInstructionIdPanic, IrInstructionIdTagName, @@ -1901,6 +1911,7 @@ enum IrInstructionId { IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, IrInstructionIdArgType, + IrInstructionIdExport, }; struct IrInstruction { @@ -2626,20 +2637,6 @@ struct IrInstructionCanImplicitCast { IrInstruction *target_value; }; -struct IrInstructionSetGlobalSection { - IrInstruction base; - - Tld *tld; - IrInstruction *value; -}; - -struct IrInstructionSetGlobalLinkage { - IrInstruction base; - - Tld *tld; - IrInstruction *value; -}; - struct IrInstructionDeclRef { IrInstruction base; @@ -2728,6 +2725,14 @@ struct IrInstructionArgType { IrInstruction *arg_index; }; +struct IrInstructionExport { + IrInstruction base; + + IrInstruction *name; + IrInstruction *linkage; + IrInstruction *target; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 1d5d5e4790..84d9b9feaf 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1062,7 +1062,7 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; if (fn_proto->cc == CallingConventionUnspecified) { - bool extern_abi = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport); + bool extern_abi = fn_proto->is_extern; fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified; } else { fn_type_id->cc = fn_proto->cc; @@ -1093,6 +1093,38 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_ return true; } +static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) { + TypeTableEntry *ptr_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); + TypeTableEntry *str_type = get_slice_type(g, ptr_type); + IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr); + if (type_is_invalid(instr->value.type)) + return false; + + ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index]; + ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index]; + + assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); + ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; + expand_undef_array(g, array_val); + size_t len = bigint_as_unsigned(&len_field->data.x_bigint); + Buf *result = buf_alloc(); + buf_resize(result, len); + for (size_t i = 0; i < len; i += 1) { + size_t new_index = ptr_field->data.x_ptr.data.base_array.elem_index + i; + ConstExprValue *char_val = &array_val->data.x_array.s_none.elements[new_index]; + if (char_val->special == ConstValSpecialUndef) { + add_node_error(g, node, buf_sprintf("use of undefined value")); + return false; + } + uint64_t big_c = bigint_as_unsigned(&char_val->data.x_bigint); + assert(big_c <= UINT8_MAX); + uint8_t c = (uint8_t)big_c; + buf_ptr(result)[i] = c; + } + *out_buffer = result; + return true; +} + static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope) { assert(proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; @@ -2472,7 +2504,7 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { buf_append_buf(buf, tld->name); } -FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) { +FnTableEntry *create_fn_raw(FnInline inline_value) { FnTableEntry *fn_entry = allocate(1); fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc; @@ -2480,7 +2512,6 @@ FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) { fn_entry->analyzed_executable.fn_entry = fn_entry; fn_entry->ir_executable.fn_entry = fn_entry; fn_entry->fn_inline = inline_value; - fn_entry->linkage = linkage; return fn_entry; } @@ -2490,9 +2521,7 @@ FnTableEntry *create_fn(AstNode *proto_node) { AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; FnInline inline_value = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; - GlobalLinkageId linkage = (fn_proto->visib_mod == VisibModExport || proto_node->data.fn_proto.is_extern) ? - GlobalLinkageIdStrong : GlobalLinkageIdInternal; - FnTableEntry *fn_entry = create_fn_raw(inline_value, linkage); + FnTableEntry *fn_entry = create_fn_raw(inline_value); fn_entry->proto_node = proto_node; fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : @@ -2572,7 +2601,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { add_node_error(g, param_node, buf_sprintf("missing parameter name")); } } - } else if (fn_table_entry->linkage != GlobalLinkageIdInternal) { + } else { g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base); } @@ -2580,6 +2609,15 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { fn_table_entry->type_entry = analyze_fn_type(g, source_node, child_scope); + if (fn_proto->section_expr != nullptr) { + if (fn_table_entry->body_node == nullptr) { + add_node_error(g, fn_proto->section_expr, + buf_sprintf("cannot set section of external function '%s'", buf_ptr(&fn_table_entry->symbol_name))); + } else { + analyze_const_string(g, child_scope, fn_proto->section_expr, &fn_table_entry->section_name); + } + } + if (fn_table_entry->type_entry->id == TypeTableEntryIdInvalid) { tld_fn->base.resolution = TldResolutionInvalid; return; @@ -2594,15 +2632,12 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { { if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) { g->main_fn = fn_table_entry; - - if (tld_fn->base.visib_mod != VisibModExport) { - TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); - TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; - if (actual_return_type != err_void) { - add_node_error(g, fn_proto->return_type, - buf_sprintf("expected return type of main to be '%%void', instead is '%s'", - buf_ptr(&actual_return_type->name))); - } + TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void); + TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type; + if (actual_return_type != err_void) { + add_node_error(g, fn_proto->return_type, + buf_sprintf("expected return type of main to be '%%void', instead is '%s'", + buf_ptr(&actual_return_type->name))); } } else if ((import->package == g->panic_package || g->have_pub_panic) && buf_eql_str(&fn_table_entry->symbol_name, "panic")) @@ -2613,7 +2648,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { } } } else if (source_node->type == NodeTypeTestDecl) { - FnTableEntry *fn_table_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdStrong); + FnTableEntry *fn_table_entry = create_fn_raw(FnInlineAuto); get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); @@ -2640,20 +2675,6 @@ static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { } static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { - if (tld->visib_mod == VisibModExport) { - g->resolve_queue.append(tld); - } - - if (tld->visib_mod == VisibModExport) { - auto entry = g->exported_symbol_names.put_unique(tld->name, tld); - if (entry) { - Tld *other_tld = entry->value; - ErrorMsg *msg = add_node_error(g, tld->source_node, - buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name))); - add_error_note(g, msg, other_tld->source_node, buf_sprintf("other symbol is here")); - } - } - { auto entry = decls_scope->decl_table.put_unique(tld->name, tld); if (entry) { @@ -2729,7 +2750,6 @@ static void preview_comptime_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_s g->resolve_queue.append(&tld_comptime->base); } - void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope) { @@ -2985,7 +3005,6 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; bool is_const = var_decl->is_const; - bool is_export = (tld_var->base.visib_mod == VisibModExport); bool is_extern = var_decl->is_extern; TypeTableEntry *explicit_type = nullptr; @@ -2994,20 +3013,13 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { explicit_type = validate_var_type(g, var_decl->type, proposed_type); } - if (is_export && is_extern) { - add_node_error(g, source_node, buf_sprintf("variable is both export and extern")); - } - VarLinkage linkage; - if (is_export) { - linkage = VarLinkageExport; - } else if (is_extern) { + if (is_extern) { linkage = VarLinkageExternal; } else { linkage = VarLinkageInternal; } - IrInstruction *init_value = nullptr; // TODO more validation for types that can't be used for export/extern variables @@ -3056,6 +3068,15 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { } } + if (var_decl->section_expr != nullptr) { + if (var_decl->is_extern) { + add_node_error(g, var_decl->section_expr, + buf_sprintf("cannot set section of external variable '%s'", buf_ptr(var_decl->symbol))); + } else if (!analyze_const_string(g, tld_var->base.parent_scope, var_decl->section_expr, &tld_var->section_name)) { + tld_var->section_name = nullptr; + } + } + g->global_vars.append(tld_var); } @@ -3724,8 +3745,10 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a Buf *proto_name = proto_node->data.fn_proto.name; bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub); + bool ok_cc = (proto_node->data.fn_proto.cc == CallingConventionUnspecified || + proto_node->data.fn_proto.cc == CallingConventionCold); - if (is_pub) { + if (is_pub && ok_cc) { if (buf_eql_str(proto_name, "main")) { g->have_pub_main = true; g->windows_subsystem_windows = false; @@ -3733,28 +3756,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a } else if (buf_eql_str(proto_name, "panic")) { g->have_pub_panic = true; } - } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && buf_eql_str(proto_name, "main") && - g->libc_link_lib != nullptr) - { - g->have_c_main = true; - g->windows_subsystem_windows = false; - g->windows_subsystem_console = true; - } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && buf_eql_str(proto_name, "WinMain") && - g->zig_target.os == ZigLLVM_Win32) - { - g->have_winmain = true; - g->windows_subsystem_windows = true; - g->windows_subsystem_console = false; - } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && - buf_eql_str(proto_name, "WinMainCRTStartup") && g->zig_target.os == ZigLLVM_Win32) - { - g->have_winmain_crt_startup = true; - } else if (proto_node->data.fn_proto.visib_mod == VisibModExport && - buf_eql_str(proto_name, "DllMainCRTStartup") && g->zig_target.os == ZigLLVM_Win32) - { - g->have_dllmain_crt_startup = true; } - } } @@ -5445,3 +5447,4 @@ uint32_t type_ptr_hash(const TypeTableEntry *ptr) { bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) { return a == b; } + diff --git a/src/analyze.hpp b/src/analyze.hpp index e12c4cda44..0e727568c6 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -182,4 +182,6 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry); TypeTableEntry *get_align_amt_type(CodeGen *g); PackageTableEntry *new_anonymous_package(void); +Buf *const_value_to_buffer(ConstExprValue *const_val); + #endif diff --git a/src/ast_render.cpp b/src/ast_render.cpp index d6a23e5f85..fc01c79ca6 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -78,7 +78,6 @@ static const char *visib_mod_string(VisibMod mod) { switch (mod) { case VisibModPub: return "pub "; case VisibModPrivate: return ""; - case VisibModExport: return "export "; } zig_unreachable(); } @@ -440,6 +439,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } } fprintf(ar->f, ")"); + if (node->data.fn_proto.align_expr) { + fprintf(ar->f, " align("); + render_node_grouped(ar, node->data.fn_proto.align_expr); + fprintf(ar->f, ")"); + } + if (node->data.fn_proto.section_expr) { + fprintf(ar->f, " section("); + render_node_grouped(ar, node->data.fn_proto.section_expr); + fprintf(ar->f, ")"); + } AstNode *return_type_node = node->data.fn_proto.return_type; if (return_type_node != nullptr) { @@ -526,6 +535,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, ": "); render_node_grouped(ar, node->data.variable_declaration.type); } + if (node->data.variable_declaration.align_expr) { + fprintf(ar->f, "align("); + render_node_grouped(ar, node->data.variable_declaration.align_expr); + fprintf(ar->f, ") "); + } + if (node->data.variable_declaration.section_expr) { + fprintf(ar->f, "section("); + render_node_grouped(ar, node->data.variable_declaration.section_expr); + fprintf(ar->f, ") "); + } if (node->data.variable_declaration.expr) { fprintf(ar->f, " = "); render_node_grouped(ar, node->data.variable_declaration.expr); diff --git a/src/codegen.cpp b/src/codegen.cpp index 44b3df3526..5be26eb445 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -391,24 +391,51 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { } } +static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) { + switch (id) { + case GlobalLinkageIdInternal: + return LLVMInternalLinkage; + case GlobalLinkageIdStrong: + return LLVMExternalLinkage; + case GlobalLinkageIdWeak: + return LLVMWeakODRLinkage; + case GlobalLinkageIdLinkOnce: + return LLVMLinkOnceODRLinkage; + } + zig_unreachable(); +} + static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { if (fn_table_entry->llvm_value) return fn_table_entry->llvm_value; - bool external_linkage = (fn_table_entry->linkage != GlobalLinkageIdInternal); - Buf *symbol_name = get_mangled_name(g, &fn_table_entry->symbol_name, external_linkage); + Buf *unmangled_name = &fn_table_entry->symbol_name; + Buf *symbol_name; + GlobalLinkageId linkage; + if (fn_table_entry->body_node == nullptr) { + symbol_name = unmangled_name; + linkage = GlobalLinkageIdStrong; + } else if (fn_table_entry->export_list.length == 0) { + symbol_name = get_mangled_name(g, unmangled_name, false); + linkage = GlobalLinkageIdInternal; + } else { + FnExport *fn_export = &fn_table_entry->export_list.items[0]; + symbol_name = &fn_export->name; + linkage = fn_export->linkage; + } + bool external_linkage = linkage != GlobalLinkageIdInternal; if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall && external_linkage && g->zig_target.arch.arch == ZigLLVM_x86) { - // prevent name mangling + // prevent llvm name mangling symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name)); } TypeTableEntry *fn_type = fn_table_entry->type_entry; LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref; - if (external_linkage && fn_table_entry->body_node == nullptr) { + if (fn_table_entry->body_node == nullptr) { LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name)); if (existing_llvm_fn) { fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0)); @@ -418,6 +445,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { } } else { fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type); + + for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) { + FnExport *fn_export = &fn_table_entry->export_list.items[i]; + LLVMAddAlias(g->module, LLVMTypeOf(fn_table_entry->llvm_value), + fn_table_entry->llvm_value, buf_ptr(&fn_export->name)); + } } fn_table_entry->llvm_name = LLVMGetValueName(fn_table_entry->llvm_value); @@ -445,20 +478,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { } } - switch (fn_table_entry->linkage) { - case GlobalLinkageIdInternal: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMInternalLinkage); - LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true); - break; - case GlobalLinkageIdStrong: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMExternalLinkage); - break; - case GlobalLinkageIdWeak: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMWeakODRLinkage); - break; - case GlobalLinkageIdLinkOnce: - LLVMSetLinkage(fn_table_entry->llvm_value, LLVMLinkOnceODRLinkage); - break; + LLVMSetLinkage(fn_table_entry->llvm_value, to_llvm_linkage(linkage)); + + if (linkage == GlobalLinkageIdInternal) { + LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true); } if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) { @@ -565,7 +588,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { bool is_definition = fn_table_entry->body_node != nullptr; unsigned flags = 0; bool is_optimized = g->build_mode != BuildModeDebug; - bool is_internal_linkage = (fn_table_entry->linkage == GlobalLinkageIdInternal); + bool is_internal_linkage = (fn_table_entry->body_node != nullptr && + fn_table_entry->export_list.length == 0); ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "", import->di_file, line_number, @@ -3487,8 +3511,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdCheckStatementIsVoid: case IrInstructionIdTypeName: case IrInstructionIdCanImplicitCast: - case IrInstructionIdSetGlobalSection: - case IrInstructionIdSetGlobalLinkage: case IrInstructionIdDeclRef: case IrInstructionIdSwitchVar: case IrInstructionIdOffsetOf: @@ -3499,6 +3521,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdSetAlignStack: case IrInstructionIdArgType: case IrInstructionIdTagType: + case IrInstructionIdExport: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); @@ -4969,8 +4992,6 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2); - create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); - create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2); create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1); create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2); create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2); @@ -4995,6 +5016,8 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2); + create_builtin_fn(g, BuiltinFnIdExport, "export", 2); + create_builtin_fn(g, BuiltinFnIdExportWithLinkage, "exportWithLinkage", 3); } static const char *bool_to_str(bool b) { @@ -5433,6 +5456,27 @@ static void gen_root_source(CodeGen *g) { assert(g->root_out_name); assert(g->out_type != OutTypeUnknown); + { + // Zig has lazy top level definitions. Here we semantically analyze the panic function. + ImportTableEntry *import_with_panic; + if (g->have_pub_panic) { + import_with_panic = g->root_import; + } else { + g->panic_package = create_panic_pkg(g); + import_with_panic = add_special_code(g, g->panic_package, "panic.zig"); + } + scan_import(g, import_with_panic); + Tld *panic_tld = find_decl(g, &import_with_panic->decls_scope->base, buf_create_from_str("panic")); + assert(panic_tld != nullptr); + resolve_top_level_decl(g, panic_tld, false, nullptr); + } + + + if (!g->error_during_imports) { + semantic_analyze(g); + } + report_errors_and_maybe_exit(g); + if (!g->is_test_build && g->zig_target.os != ZigLLVM_UnknownOS && !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) @@ -5442,20 +5486,6 @@ static void gen_root_source(CodeGen *g) { if (g->zig_target.os == ZigLLVM_Win32 && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib) { g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); } - ImportTableEntry *import_with_panic; - if (g->have_pub_panic) { - import_with_panic = g->root_import; - } else { - g->panic_package = create_panic_pkg(g); - import_with_panic = add_special_code(g, g->panic_package, "panic.zig"); - } - // Zig has lazy top level definitions. Here we semantically analyze the panic function. - { - scan_import(g, import_with_panic); - Tld *panic_tld = find_decl(g, &import_with_panic->decls_scope->base, buf_create_from_str("panic")); - assert(panic_tld != nullptr); - resolve_top_level_decl(g, panic_tld, false, nullptr); - } if (!g->error_during_imports) { semantic_analyze(g); @@ -5682,7 +5712,7 @@ static void gen_h_file(CodeGen *g) { for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) { FnTableEntry *fn_table_entry = g->fn_defs.at(fn_def_i); - if (fn_table_entry->linkage == GlobalLinkageIdInternal) + if (fn_table_entry->export_list.length == 0) continue; FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; diff --git a/src/ir.cpp b/src/ir.cpp index ce7d8dcedd..81b64a318d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -207,6 +207,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) { return IrInstructionIdDeclVar; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) { + return IrInstructionIdExport; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtr *) { return IrInstructionIdLoadPtr; } @@ -523,14 +527,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast return IrInstructionIdCanImplicitCast; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalSection *) { - return IrInstructionIdSetGlobalSection; -} - -static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalLinkage *) { - return IrInstructionIdSetGlobalLinkage; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) { return IrInstructionIdDeclRef; } @@ -1205,6 +1201,24 @@ static IrInstruction *ir_build_var_decl_from(IrBuilder *irb, IrInstruction *old_ return new_instruction; } +static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *name, IrInstruction *target, IrInstruction *linkage) +{ + IrInstructionExport *export_instruction = ir_build_instruction( + irb, scope, source_node); + export_instruction->base.value.special = ConstValSpecialStatic; + export_instruction->base.value.type = irb->codegen->builtin_types.entry_void; + export_instruction->name = name; + export_instruction->target = target; + export_instruction->linkage = linkage; + + ir_ref_instruction(name, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + if (linkage) ir_ref_instruction(linkage, irb->current_basic_block); + + return &export_instruction->base; +} + static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { IrInstructionLoadPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->ptr = ptr; @@ -2159,32 +2173,6 @@ static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, A return &instruction->base; } -static IrInstruction *ir_build_set_global_section(IrBuilder *irb, Scope *scope, AstNode *source_node, - Tld *tld, IrInstruction *value) -{ - IrInstructionSetGlobalSection *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->tld = tld; - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstruction *ir_build_set_global_linkage(IrBuilder *irb, Scope *scope, AstNode *source_node, - Tld *tld, IrInstruction *value) -{ - IrInstructionSetGlobalLinkage *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->tld = tld; - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, Tld *tld, LVal lval) { @@ -2396,6 +2384,21 @@ static IrInstruction *ir_instruction_declvar_get_dep(IrInstructionDeclVar *instr return nullptr; } +static IrInstruction *ir_instruction_export_get_dep(IrInstructionExport *instruction, size_t index) { + if (index < 1) return instruction->name; + index -= 1; + + if (index < 1) return instruction->target; + index -= 1; + + if (instruction->linkage != nullptr) { + if (index < 1) return instruction->linkage; + index -= 1; + } + + return nullptr; +} + static IrInstruction *ir_instruction_loadptr_get_dep(IrInstructionLoadPtr *instruction, size_t index) { switch (index) { case 0: return instruction->ptr; @@ -2979,20 +2982,6 @@ static IrInstruction *ir_instruction_canimplicitcast_get_dep(IrInstructionCanImp } } -static IrInstruction *ir_instruction_setglobalsection_get_dep(IrInstructionSetGlobalSection *instruction, size_t index) { - switch (index) { - case 0: return instruction->value; - default: return nullptr; - } -} - -static IrInstruction *ir_instruction_setgloballinkage_get_dep(IrInstructionSetGlobalLinkage *instruction, size_t index) { - switch (index) { - case 0: return instruction->value; - default: return nullptr; - } -} - static IrInstruction *ir_instruction_declref_get_dep(IrInstructionDeclRef *instruction, size_t index) { return nullptr; } @@ -3106,6 +3095,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_binop_get_dep((IrInstructionBinOp *) instruction, index); case IrInstructionIdDeclVar: return ir_instruction_declvar_get_dep((IrInstructionDeclVar *) instruction, index); + case IrInstructionIdExport: + return ir_instruction_export_get_dep((IrInstructionExport *) instruction, index); case IrInstructionIdLoadPtr: return ir_instruction_loadptr_get_dep((IrInstructionLoadPtr *) instruction, index); case IrInstructionIdStorePtr: @@ -3264,10 +3255,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_typename_get_dep((IrInstructionTypeName *) instruction, index); case IrInstructionIdCanImplicitCast: return ir_instruction_canimplicitcast_get_dep((IrInstructionCanImplicitCast *) instruction, index); - case IrInstructionIdSetGlobalSection: - return ir_instruction_setglobalsection_get_dep((IrInstructionSetGlobalSection *) instruction, index); - case IrInstructionIdSetGlobalLinkage: - return ir_instruction_setgloballinkage_get_dep((IrInstructionSetGlobalLinkage *) instruction, index); case IrInstructionIdDeclRef: return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index); case IrInstructionIdPanic: @@ -4528,39 +4515,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value); } - case BuiltinFnIdSetGlobalSection: - case BuiltinFnIdSetGlobalLinkage: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - if (arg0_node->type != NodeTypeSymbol) { - add_node_error(irb->codegen, arg0_node, buf_sprintf("expected identifier")); - return irb->codegen->invalid_instruction; - } - Buf *variable_name = arg0_node->data.symbol_expr.symbol; - Tld *tld = find_decl(irb->codegen, scope, variable_name); - if (!tld) { - add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", - buf_ptr(variable_name))); - return irb->codegen->invalid_instruction; - } - if (tld->id != TldIdVar && tld->id != TldIdFn) { - add_node_error(irb->codegen, node, buf_sprintf("'%s' must be global variable or function", - buf_ptr(variable_name))); - return irb->codegen->invalid_instruction; - } - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_instruction) - return arg1_value; - - if (builtin_fn->id == BuiltinFnIdSetGlobalSection) { - return ir_build_set_global_section(irb, scope, node, tld, arg1_value); - } else if (builtin_fn->id == BuiltinFnIdSetGlobalLinkage) { - return ir_build_set_global_linkage(irb, scope, node, tld, arg1_value); - } else { - zig_unreachable(); - } - } case BuiltinFnIdPanic: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -4784,6 +4738,31 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value); } + case BuiltinFnIdExport: + case BuiltinFnIdExportWithLinkage: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + IrInstruction *arg2_value; + if (builtin_fn->id == BuiltinFnIdExportWithLinkage) { + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_instruction) + return arg2_value; + } else { + arg2_value = nullptr; + } + + return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value); + } } zig_unreachable(); } @@ -5106,6 +5085,11 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod return align_value; } + if (variable_declaration->section_expr != nullptr) { + add_node_error(irb->codegen, variable_declaration->section_expr, + buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); + } + IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope); if (init_value == irb->codegen->invalid_instruction) return init_value; @@ -6355,6 +6339,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeSwitchRange: case NodeTypeStructField: case NodeTypeLabel: + case NodeTypeFnDef: + case NodeTypeFnDecl: + case NodeTypeErrorValueDecl: + case NodeTypeTestDecl: zig_unreachable(); case NodeTypeBlock: return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); @@ -6436,14 +6424,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); case NodeTypeFnProto: return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); - case NodeTypeFnDef: - zig_panic("TODO IR gen NodeTypeFnDef"); - case NodeTypeFnDecl: - zig_panic("TODO IR gen NodeTypeFnDecl"); - case NodeTypeErrorValueDecl: - zig_panic("TODO IR gen NodeTypeErrorValueDecl"); - case NodeTypeTestDecl: - zig_panic("TODO IR gen NodeTypeTestDecl"); } zig_unreachable(); } @@ -10481,6 +10461,194 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc return ira->codegen->builtin_types.entry_void; } +static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) { + IrInstruction *name = instruction->name->other; + Buf *symbol_name = ir_resolve_str(ira, name); + if (symbol_name == nullptr) { + return ira->codegen->builtin_types.entry_invalid; + } + + IrInstruction *target = instruction->target->other; + if (type_is_invalid(target->value.type)) { + return ira->codegen->builtin_types.entry_invalid; + } + + GlobalLinkageId global_linkage_id = GlobalLinkageIdStrong; + if (instruction->linkage != nullptr) { + IrInstruction *linkage_value = instruction->linkage->other; + if (!ir_resolve_global_linkage(ira, linkage_value, &global_linkage_id)) { + return ira->codegen->builtin_types.entry_invalid; + } + } + + auto entry = ira->codegen->exported_symbol_names.put_unique(symbol_name, instruction->base.source_node); + if (entry) { + AstNode *other_export_node = entry->value; + ErrorMsg *msg = ir_add_error(ira, &instruction->base, + buf_sprintf("exported symbol collision: '%s'", buf_ptr(symbol_name))); + add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here")); + } + + switch (target->value.type->id) { + case TypeTableEntryIdInvalid: + case TypeTableEntryIdVar: + case TypeTableEntryIdUnreachable: + zig_unreachable(); + case TypeTableEntryIdFn: { + FnTableEntry *fn_entry = target->value.data.x_fn.fn_entry; + CallingConvention cc = fn_entry->type_entry->data.fn.fn_type_id.cc; + switch (cc) { + case CallingConventionUnspecified: { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported function must specify calling convention")); + add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); + } break; + case CallingConventionC: + if (buf_eql_str(symbol_name, "main") && ira->codegen->libc_link_lib != nullptr) { + ira->codegen->have_c_main = true; + ira->codegen->windows_subsystem_windows = false; + ira->codegen->windows_subsystem_console = true; + } else if (buf_eql_str(symbol_name, "WinMain") && + ira->codegen->zig_target.os == ZigLLVM_Win32) + { + ira->codegen->have_winmain = true; + ira->codegen->windows_subsystem_windows = true; + ira->codegen->windows_subsystem_console = false; + } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && + ira->codegen->zig_target.os == ZigLLVM_Win32) + { + ira->codegen->have_winmain_crt_startup = true; + } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") && + ira->codegen->zig_target.os == ZigLLVM_Win32) + { + ira->codegen->have_dllmain_crt_startup = true; + } + // fallthrough + case CallingConventionNaked: + case CallingConventionCold: + case CallingConventionStdcall: { + FnExport *fn_export = fn_entry->export_list.add_one(); + memset(fn_export, 0, sizeof(FnExport)); + buf_init_from_buf(&fn_export->name, symbol_name); + fn_export->linkage = global_linkage_id; + fn_export->source_node = instruction->base.source_node; + } break; + } + } break; + case TypeTableEntryIdStruct: + if (is_slice(target->value.type)) { + ir_add_error(ira, target, + buf_sprintf("unable to export value of type '%s'", buf_ptr(&target->value.type->name))); + } else if (target->value.type->data.structure.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported struct value must be declared extern")); + add_error_note(ira->codegen, msg, target->value.type->data.structure.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdUnion: + if (target->value.type->data.unionation.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported union value must be declared extern")); + add_error_note(ira->codegen, msg, target->value.type->data.unionation.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdEnum: + if (target->value.type->data.enumeration.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported enum value must be declared extern")); + add_error_note(ira->codegen, msg, target->value.type->data.enumeration.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdMetaType: { + TypeTableEntry *type_value = target->value.data.x_type; + switch (type_value->id) { + case TypeTableEntryIdInvalid: + case TypeTableEntryIdVar: + zig_unreachable(); + case TypeTableEntryIdStruct: + if (is_slice(type_value)) { + ir_add_error(ira, target, + buf_sprintf("unable to export type '%s'", buf_ptr(&type_value->name))); + } else if (type_value->data.structure.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported struct must be declared extern")); + add_error_note(ira->codegen, msg, type_value->data.structure.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdUnion: + if (type_value->data.unionation.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported union must be declared extern")); + add_error_note(ira->codegen, msg, type_value->data.unionation.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdEnum: + if (type_value->data.enumeration.layout != ContainerLayoutExtern) { + ErrorMsg *msg = ir_add_error(ira, target, + buf_sprintf("exported enum must be declared extern")); + add_error_note(ira->codegen, msg, type_value->data.enumeration.decl_node, buf_sprintf("declared here")); + } + break; + case TypeTableEntryIdFn: { + if (type_value->data.fn.fn_type_id.cc == CallingConventionUnspecified) { + ir_add_error(ira, target, + buf_sprintf("exported function type must specify calling convention")); + } + } break; + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdBool: + break; + case TypeTableEntryIdMetaType: + case TypeTableEntryIdVoid: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdBoundFn: + case TypeTableEntryIdArgTuple: + case TypeTableEntryIdOpaque: + ir_add_error(ira, target, + buf_sprintf("invalid export target '%s'", buf_ptr(&type_value->name))); + break; + } + } break; + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdBoundFn: + case TypeTableEntryIdArgTuple: + case TypeTableEntryIdOpaque: + ir_add_error(ira, target, + buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name))); + break; + } + + ir_build_const_from(ira, &instruction->base); + return ira->codegen->builtin_types.entry_void; +} + static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) { @@ -12399,102 +12567,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, return ira->codegen->builtin_types.entry_type; } -static TypeTableEntry *ir_analyze_instruction_set_global_section(IrAnalyze *ira, - IrInstructionSetGlobalSection *instruction) -{ - Tld *tld = instruction->tld; - IrInstruction *section_value = instruction->value->other; - - resolve_top_level_decl(ira->codegen, tld, true, instruction->base.source_node); - if (tld->resolution == TldResolutionInvalid) - return ira->codegen->builtin_types.entry_invalid; - - Buf *section_name = ir_resolve_str(ira, section_value); - if (!section_name) - return ira->codegen->builtin_types.entry_invalid; - - AstNode **set_global_section_node; - Buf **section_name_ptr; - if (tld->id == TldIdVar) { - TldVar *tld_var = (TldVar *)tld; - set_global_section_node = &tld_var->set_global_section_node; - section_name_ptr = &tld_var->section_name; - - if (tld_var->var->linkage == VarLinkageExternal) { - ErrorMsg *msg = ir_add_error(ira, &instruction->base, - buf_sprintf("cannot set section of external variable '%s'", buf_ptr(&tld_var->var->name))); - add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); - return ira->codegen->builtin_types.entry_invalid; - } - } else if (tld->id == TldIdFn) { - TldFn *tld_fn = (TldFn *)tld; - FnTableEntry *fn_entry = tld_fn->fn_entry; - set_global_section_node = &fn_entry->set_global_section_node; - section_name_ptr = &fn_entry->section_name; - - if (fn_entry->def_scope == nullptr) { - ErrorMsg *msg = ir_add_error(ira, &instruction->base, - buf_sprintf("cannot set section of external function '%s'", buf_ptr(&fn_entry->symbol_name))); - add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("declared here")); - return ira->codegen->builtin_types.entry_invalid; - } - } else { - // error is caught in pass1 IR gen - zig_unreachable(); - } - - AstNode *source_node = instruction->base.source_node; - if (*set_global_section_node) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("section set twice")); - add_error_note(ira->codegen, msg, *set_global_section_node, buf_sprintf("first set here")); - return ira->codegen->builtin_types.entry_invalid; - } - *set_global_section_node = source_node; - *section_name_ptr = section_name; - - ir_build_const_from(ira, &instruction->base); - return ira->codegen->builtin_types.entry_void; -} - -static TypeTableEntry *ir_analyze_instruction_set_global_linkage(IrAnalyze *ira, - IrInstructionSetGlobalLinkage *instruction) -{ - Tld *tld = instruction->tld; - IrInstruction *linkage_value = instruction->value->other; - - GlobalLinkageId linkage_scalar; - if (!ir_resolve_global_linkage(ira, linkage_value, &linkage_scalar)) - return ira->codegen->builtin_types.entry_invalid; - - AstNode **set_global_linkage_node; - GlobalLinkageId *dest_linkage_ptr; - if (tld->id == TldIdVar) { - TldVar *tld_var = (TldVar *)tld; - set_global_linkage_node = &tld_var->set_global_linkage_node; - dest_linkage_ptr = &tld_var->linkage; - } else if (tld->id == TldIdFn) { - TldFn *tld_fn = (TldFn *)tld; - FnTableEntry *fn_entry = tld_fn->fn_entry; - set_global_linkage_node = &fn_entry->set_global_linkage_node; - dest_linkage_ptr = &fn_entry->linkage; - } else { - // error is caught in pass1 IR gen - zig_unreachable(); - } - - AstNode *source_node = instruction->base.source_node; - if (*set_global_linkage_node) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("linkage set twice")); - add_error_note(ira->codegen, msg, *set_global_linkage_node, buf_sprintf("first set here")); - return ira->codegen->builtin_types.entry_invalid; - } - *set_global_linkage_node = source_node; - *dest_linkage_ptr = linkage_scalar; - - ir_build_const_from(ira, &instruction->base); - return ira->codegen->builtin_types.entry_void; -} - static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, IrInstructionSetDebugSafety *set_debug_safety_instruction) { @@ -16165,10 +16237,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction); case IrInstructionIdPtrTypeChild: return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction); - case IrInstructionIdSetGlobalSection: - return ir_analyze_instruction_set_global_section(ira, (IrInstructionSetGlobalSection *)instruction); - case IrInstructionIdSetGlobalLinkage: - return ir_analyze_instruction_set_global_linkage(ira, (IrInstructionSetGlobalLinkage *)instruction); case IrInstructionIdSetDebugSafety: return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction); case IrInstructionIdSetFloatMode: @@ -16311,6 +16379,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction); case IrInstructionIdTagType: return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction); + case IrInstructionIdExport: + return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction); } zig_unreachable(); } @@ -16418,12 +16488,11 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free case IrInstructionIdCheckSwitchProngs: case IrInstructionIdCheckStatementIsVoid: - case IrInstructionIdSetGlobalSection: - case IrInstructionIdSetGlobalLinkage: case IrInstructionIdPanic: case IrInstructionIdSetEvalBranchQuota: case IrInstructionIdPtrTypeOf: case IrInstructionIdSetAlignStack: + case IrInstructionIdExport: return true; case IrInstructionIdPhi: case IrInstructionIdUnOp: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index b6a7c32dfc..f5aba2a45d 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -899,19 +899,6 @@ static void ir_print_ptr_type_of(IrPrint *irp, IrInstructionPtrTypeOf *instructi ir_print_other_instruction(irp, instruction->child_type); } -static void ir_print_set_global_section(IrPrint *irp, IrInstructionSetGlobalSection *instruction) { - fprintf(irp->f, "@setGlobalSection(%s,", buf_ptr(instruction->tld->name)); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); -} - -static void ir_print_set_global_linkage(IrPrint *irp, IrInstructionSetGlobalLinkage *instruction) { - fprintf(irp->f, "@setGlobalLinkage(%s,", buf_ptr(instruction->tld->name)); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); -} - - static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) { const char *ptr_str = instruction->lval.is_ptr ? "ptr " : ""; const char *const_str = instruction->lval.is_const ? "const " : ""; @@ -991,6 +978,24 @@ static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionTagType *instructi fprintf(irp->f, ")"); } +static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) { + if (instruction->linkage == nullptr) { + fprintf(irp->f, "@export("); + ir_print_other_instruction(irp, instruction->name); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->target); + fprintf(irp->f, ")"); + } else { + fprintf(irp->f, "@exportWithLinkage("); + ir_print_other_instruction(irp, instruction->name); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->target); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->linkage); + fprintf(irp->f, ")"); + } +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); @@ -1267,12 +1272,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdPtrTypeOf: ir_print_ptr_type_of(irp, (IrInstructionPtrTypeOf *)instruction); break; - case IrInstructionIdSetGlobalSection: - ir_print_set_global_section(irp, (IrInstructionSetGlobalSection *)instruction); - break; - case IrInstructionIdSetGlobalLinkage: - ir_print_set_global_linkage(irp, (IrInstructionSetGlobalLinkage *)instruction); - break; case IrInstructionIdDeclRef: ir_print_decl_ref(irp, (IrInstructionDeclRef *)instruction); break; @@ -1306,6 +1305,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTagType: ir_print_enum_tag_type(irp, (IrInstructionTagType *)instruction); break; + case IrInstructionIdExport: + ir_print_export(irp, (IrInstructionExport *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/src/parser.cpp b/src/parser.cpp index 26ca7da31a..07c221e287 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1600,6 +1600,14 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to next_token = &pc->tokens->at(*token_index); } + if (next_token->id == TokenIdKeywordSection) { + *token_index += 1; + ast_eat_token(pc, token_index, TokenIdLParen); + node->data.variable_declaration.section_expr = ast_parse_expression(pc, token_index, true); + ast_eat_token(pc, token_index, TokenIdRParen); + next_token = &pc->tokens->at(*token_index); + } + if (next_token->id == TokenIdEq) { *token_index += 1; node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); @@ -2144,7 +2152,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) { /* Block = "{" many(Statement) option(Expression) "}" -Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" +Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" | ExportDecl */ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mandatory) { Token *last_token = &pc->tokens->at(*token_index); @@ -2205,7 +2213,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand } /* -FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("->" TypeExpr) +FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("->" TypeExpr) */ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { Token *first_token = &pc->tokens->at(*token_index); @@ -2259,6 +2267,14 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m ast_eat_token(pc, token_index, TokenIdRParen); next_token = &pc->tokens->at(*token_index); } + if (next_token->id == TokenIdKeywordSection) { + *token_index += 1; + ast_eat_token(pc, token_index, TokenIdLParen); + + node->data.fn_proto.section_expr = ast_parse_expression(pc, token_index, true); + ast_eat_token(pc, token_index, TokenIdRParen); + next_token = &pc->tokens->at(*token_index); + } if (next_token->id == TokenIdArrow) { *token_index += 1; node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, false); @@ -2447,9 +2463,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, if (visib_tok->id == TokenIdKeywordPub) { *token_index += 1; visib_mod = VisibModPub; - } else if (visib_tok->id == TokenIdKeywordExport) { - *token_index += 1; - visib_mod = VisibModExport; } else { visib_mod = VisibModPrivate; } @@ -2580,9 +2593,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig if (visib_tok->id == TokenIdKeywordPub) { *token_index += 1; visib_mod = VisibModPub; - } else if (visib_tok->id == TokenIdKeywordExport) { - *token_index += 1; - visib_mod = VisibModExport; } else { visib_mod = VisibModPrivate; } @@ -2669,6 +2679,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.fn_proto.return_type, visit, context); visit_node_list(&node->data.fn_proto.params, visit, context); visit_field(&node->data.fn_proto.align_expr, visit, context); + visit_field(&node->data.fn_proto.section_expr, visit, context); break; case NodeTypeFnDef: visit_field(&node->data.fn_def.fn_proto, visit, context); @@ -2696,6 +2707,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.variable_declaration.type, visit, context); visit_field(&node->data.variable_declaration.expr, visit, context); visit_field(&node->data.variable_declaration.align_expr, visit, context); + visit_field(&node->data.variable_declaration.section_expr, visit, context); break; case NodeTypeErrorValueDecl: // none diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 77d74c52ee..a14f709744 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -119,7 +119,6 @@ static const struct ZigKeyword zig_keywords[] = { {"else", TokenIdKeywordElse}, {"enum", TokenIdKeywordEnum}, {"error", TokenIdKeywordError}, - {"export", TokenIdKeywordExport}, {"extern", TokenIdKeywordExtern}, {"false", TokenIdKeywordFalse}, {"fn", TokenIdKeywordFn}, @@ -134,6 +133,7 @@ static const struct ZigKeyword zig_keywords[] = { {"packed", TokenIdKeywordPacked}, {"pub", TokenIdKeywordPub}, {"return", TokenIdKeywordReturn}, + {"section", TokenIdKeywordSection}, {"stdcallcc", TokenIdKeywordStdcallCC}, {"struct", TokenIdKeywordStruct}, {"switch", TokenIdKeywordSwitch}, @@ -1518,7 +1518,6 @@ const char * token_name(TokenId id) { case TokenIdKeywordElse: return "else"; case TokenIdKeywordEnum: return "enum"; case TokenIdKeywordError: return "error"; - case TokenIdKeywordExport: return "export"; case TokenIdKeywordExtern: return "extern"; case TokenIdKeywordFalse: return "false"; case TokenIdKeywordFn: return "fn"; @@ -1533,6 +1532,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordPacked: return "packed"; case TokenIdKeywordPub: return "pub"; case TokenIdKeywordReturn: return "return"; + case TokenIdKeywordSection: return "section"; case TokenIdKeywordStdcallCC: return "stdcallcc"; case TokenIdKeywordStruct: return "struct"; case TokenIdKeywordSwitch: return "switch"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index bcad977864..b0444b9c3b 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -47,6 +47,7 @@ enum TokenId { TokenIdFloatLiteral, TokenIdIntLiteral, TokenIdKeywordAlign, + TokenIdKeywordSection, TokenIdKeywordAnd, TokenIdKeywordAsm, TokenIdKeywordBreak, @@ -58,7 +59,6 @@ enum TokenId { TokenIdKeywordElse, TokenIdKeywordEnum, TokenIdKeywordError, - TokenIdKeywordExport, TokenIdKeywordExtern, TokenIdKeywordFalse, TokenIdKeywordFn, diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 4575d4ee56..77afc38a51 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -73,7 +73,6 @@ struct Context { ImportTableEntry *import; ZigList *errors; VisibMod visib_mod; - VisibMod export_visib_mod; AstNode *root; HashMap decl_table; HashMap macro_table; @@ -3251,7 +3250,8 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { StorageClass sc = fn_decl->getStorageClass(); if (sc == SC_None) { - proto_node->data.fn_proto.visib_mod = fn_decl->hasBody() ? c->export_visib_mod : c->visib_mod; + // TODO add export decl + proto_node->data.fn_proto.visib_mod = c->visib_mod; } else if (sc == SC_Extern || sc == SC_Static) { proto_node->data.fn_proto.visib_mod = c->visib_mod; } else if (sc == SC_PrivateExtern) { @@ -4274,10 +4274,8 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch c->errors = errors; if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { c->visib_mod = VisibModPub; - c->export_visib_mod = VisibModPub; } else { c->visib_mod = VisibModPub; - c->export_visib_mod = VisibModExport; } c->decl_table.init(8); c->macro_table.init(8); diff --git a/std/debug.zig b/std/debug.zig index a6229f88da..1035948e3e 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -96,8 +96,6 @@ const WHITE = "\x1b[37;1m"; const DIM = "\x1b[2m"; const RESET = "\x1b[0m"; -pub var user_main_fn: ?fn() -> %void = null; - error PathNotFound; error InvalidDebugInfo; diff --git a/std/elf.zig b/std/elf.zig index f7be236d15..2c5b10b3f2 100644 --- a/std/elf.zig +++ b/std/elf.zig @@ -188,39 +188,39 @@ pub const Elf = struct { if (elf.is_64) { if (sh_entry_size != 64) return error.InvalidFormat; - for (elf.section_headers) |*section| { - section.name = %return in.readInt(elf.endian, u32); - section.sh_type = %return in.readInt(elf.endian, u32); - section.flags = %return in.readInt(elf.endian, u64); - section.addr = %return in.readInt(elf.endian, u64); - section.offset = %return in.readInt(elf.endian, u64); - section.size = %return in.readInt(elf.endian, u64); - section.link = %return in.readInt(elf.endian, u32); - section.info = %return in.readInt(elf.endian, u32); - section.addr_align = %return in.readInt(elf.endian, u64); - section.ent_size = %return in.readInt(elf.endian, u64); + for (elf.section_headers) |*elf_section| { + elf_section.name = %return in.readInt(elf.endian, u32); + elf_section.sh_type = %return in.readInt(elf.endian, u32); + elf_section.flags = %return in.readInt(elf.endian, u64); + elf_section.addr = %return in.readInt(elf.endian, u64); + elf_section.offset = %return in.readInt(elf.endian, u64); + elf_section.size = %return in.readInt(elf.endian, u64); + elf_section.link = %return in.readInt(elf.endian, u32); + elf_section.info = %return in.readInt(elf.endian, u32); + elf_section.addr_align = %return in.readInt(elf.endian, u64); + elf_section.ent_size = %return in.readInt(elf.endian, u64); } } else { if (sh_entry_size != 40) return error.InvalidFormat; - for (elf.section_headers) |*section| { + for (elf.section_headers) |*elf_section| { // TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ? - section.name = %return in.readInt(elf.endian, u32); - section.sh_type = %return in.readInt(elf.endian, u32); - section.flags = u64(%return in.readInt(elf.endian, u32)); - section.addr = u64(%return in.readInt(elf.endian, u32)); - section.offset = u64(%return in.readInt(elf.endian, u32)); - section.size = u64(%return in.readInt(elf.endian, u32)); - section.link = %return in.readInt(elf.endian, u32); - section.info = %return in.readInt(elf.endian, u32); - section.addr_align = u64(%return in.readInt(elf.endian, u32)); - section.ent_size = u64(%return in.readInt(elf.endian, u32)); + elf_section.name = %return in.readInt(elf.endian, u32); + elf_section.sh_type = %return in.readInt(elf.endian, u32); + elf_section.flags = u64(%return in.readInt(elf.endian, u32)); + elf_section.addr = u64(%return in.readInt(elf.endian, u32)); + elf_section.offset = u64(%return in.readInt(elf.endian, u32)); + elf_section.size = u64(%return in.readInt(elf.endian, u32)); + elf_section.link = %return in.readInt(elf.endian, u32); + elf_section.info = %return in.readInt(elf.endian, u32); + elf_section.addr_align = u64(%return in.readInt(elf.endian, u32)); + elf_section.ent_size = u64(%return in.readInt(elf.endian, u32)); } } - for (elf.section_headers) |*section| { - if (section.sh_type != SHT_NOBITS) { - const file_end_offset = %return math.add(u64, section.offset, section.size); + for (elf.section_headers) |*elf_section| { + if (elf_section.sh_type != SHT_NOBITS) { + const file_end_offset = %return math.add(u64, elf_section.offset, elf_section.size); if (stream_end < file_end_offset) return error.InvalidFormat; } } @@ -243,10 +243,10 @@ pub const Elf = struct { var file_stream = io.FileInStream.init(elf.in_file); const in = &file_stream.stream; - for (elf.section_headers) |*section| { - if (section.sh_type == SHT_NULL) continue; + for (elf.section_headers) |*elf_section| { + if (elf_section.sh_type == SHT_NULL) continue; - const name_offset = elf.string_section.offset + section.name; + const name_offset = elf.string_section.offset + elf_section.name; %return elf.in_file.seekTo(name_offset); for (name) |expected_c| { @@ -256,7 +256,7 @@ pub const Elf = struct { { const null_byte = %return in.readByte(); - if (null_byte == 0) return section; + if (null_byte == 0) return elf_section; } next_section: @@ -265,7 +265,7 @@ pub const Elf = struct { return null; } - pub fn seekToSection(elf: &Elf, section: &SectionHeader) -> %void { - %return elf.in_file.seekTo(section.offset); + pub fn seekToSection(elf: &Elf, elf_section: &SectionHeader) -> %void { + %return elf.in_file.seekTo(elf_section.offset); } }; diff --git a/std/mem.zig b/std/mem.zig index 10d2221f9a..e9883afd39 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -4,6 +4,7 @@ const math = @import("math/index.zig"); const builtin = @import("builtin"); pub const Cmp = math.Cmp; +error OutOfMemory; pub const Allocator = struct { /// Allocate byte_count bytes and return them in a slice, with the diff --git a/std/os/linux.zig b/std/os/linux.zig index 5951f9d7bc..4ba4db603f 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -651,28 +651,6 @@ pub const iovec = extern struct { iov_len: usize, }; -// -//const IF_NAMESIZE = 16; -// -//export struct ifreq { -// ifrn_name: [IF_NAMESIZE]u8, -// union { -// ifru_addr: sockaddr, -// ifru_dstaddr: sockaddr, -// ifru_broadaddr: sockaddr, -// ifru_netmask: sockaddr, -// ifru_hwaddr: sockaddr, -// ifru_flags: i16, -// ifru_ivalue: i32, -// ifru_mtu: i32, -// ifru_map: ifmap, -// ifru_slave: [IF_NAMESIZE]u8, -// ifru_newname: [IF_NAMESIZE]u8, -// ifru_data: &u8, -// } ifr_ifru; -//} -// - pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize { arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len)) } diff --git a/std/os/linux_i386.zig b/std/os/linux_i386.zig index 215670e3a9..ed49e33c2b 100644 --- a/std/os/linux_i386.zig +++ b/std/os/linux_i386.zig @@ -502,13 +502,3 @@ pub nakedcc fn restore_rt() { : [number] "{eax}" (usize(SYS_rt_sigreturn)) : "rcx", "r11") } - -export struct msghdr { - msg_name: &u8, - msg_namelen: socklen_t, - msg_iov: &iovec, - msg_iovlen: i32, - msg_control: &u8, - msg_controllen: socklen_t, - msg_flags: i32, -} diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 99bea09726..ee63467305 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -5,20 +5,19 @@ const root = @import("@root"); const std = @import("std"); const builtin = @import("builtin"); -const is_windows = builtin.os == builtin.Os.windows; -const want_main_symbol = builtin.link_libc; -const want_start_symbol = !want_main_symbol and !is_windows; -const want_WinMainCRTStartup = is_windows and !builtin.link_libc; - var argc_ptr: &usize = undefined; - -export nakedcc fn _start() -> noreturn { - if (!want_start_symbol) { - @setGlobalLinkage(_start, builtin.GlobalLinkage.Internal); - unreachable; +comptime { + if (builtin.link_libc) { + @export("main", main); + } else if (builtin.os == builtin.Os.windows) { + @export("WinMainCRTStartup", WinMainCRTStartup); + } else { + @export("_start", _start); } +} +nakedcc fn _start() -> noreturn { switch (builtin.arch) { builtin.Arch.x86_64 => { argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize)); @@ -33,14 +32,9 @@ export nakedcc fn _start() -> noreturn { @noInlineCall(posixCallMainAndExit); } -export fn WinMainCRTStartup() -> noreturn { - if (!want_WinMainCRTStartup) { - @setGlobalLinkage(WinMainCRTStartup, builtin.GlobalLinkage.Internal); - unreachable; - } +extern fn WinMainCRTStartup() -> noreturn { @setAlignStack(16); - std.debug.user_main_fn = root.main; root.main() %% std.os.windows.ExitProcess(1); std.os.windows.ExitProcess(0); } @@ -60,17 +54,10 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { while (envp[env_count] != null) : (env_count += 1) {} std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count]; - std.debug.user_main_fn = root.main; - return root.main(); } -export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { - if (!want_main_symbol) { - @setGlobalLinkage(main, builtin.GlobalLinkage.Internal); - unreachable; - } - +extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { callMain(usize(c_argc), c_argv, c_envp) %% return 1; return 0; } diff --git a/std/special/bootstrap_lib.zig b/std/special/bootstrap_lib.zig index 7412d64fa6..3c7789f30a 100644 --- a/std/special/bootstrap_lib.zig +++ b/std/special/bootstrap_lib.zig @@ -2,7 +2,11 @@ const std = @import("std"); -export stdcallcc fn _DllMainCRTStartup(hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD, +comptime { + @export("_DllMainCRTStartup", _DllMainCRTStartup); +} + +stdcallcc fn _DllMainCRTStartup(hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD, lpReserved: std.os.windows.LPVOID) -> std.os.windows.BOOL { return std.os.windows.TRUE; diff --git a/std/special/builtin.zig b/std/special/builtin.zig index 51e6646574..9ace9b46ca 100644 --- a/std/special/builtin.zig +++ b/std/special/builtin.zig @@ -13,10 +13,24 @@ pub coldcc fn panic(msg: []const u8) -> noreturn { } } +comptime { + @export("memset", memset); + @export("memcpy", memcpy); + @export("fmodf", fmodf); + @export("fmod", fmod); + @export("floorf", floorf); + @export("ceilf", ceilf); + @export("floor", floor); + @export("ceil", ceil); + if (builtin.mode != builtin.Mode.ReleaseFast and builtin.os != builtin.Os.windows) { + @export("__stack_chk_fail", __stack_chk_fail); + } +} + // Note that memset does not return `dest`, like the libc API. // The semantics of memset is dictated by the corresponding // LLVM intrinsics, not by the libc API. -export fn memset(dest: ?&u8, c: u8, n: usize) { +extern fn memset(dest: ?&u8, c: u8, n: usize) { @setDebugSafety(this, false); var index: usize = 0; @@ -27,7 +41,7 @@ export fn memset(dest: ?&u8, c: u8, n: usize) { // Note that memcpy does not return `dest`, like the libc API. // The semantics of memcpy is dictated by the corresponding // LLVM intrinsics, not by the libc API. -export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { +extern fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { @setDebugSafety(this, false); var index: usize = 0; @@ -35,25 +49,21 @@ export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { (??dest)[index] = (??src)[index]; } -export fn __stack_chk_fail() -> noreturn { - if (builtin.mode == builtin.Mode.ReleaseFast or builtin.os == builtin.Os.windows) { - @setGlobalLinkage(__stack_chk_fail, builtin.GlobalLinkage.Internal); - unreachable; - } +extern fn __stack_chk_fail() -> noreturn { @panic("stack smashing detected"); } const math = @import("../math/index.zig"); -export fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) } -export fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) } +extern fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) } +extern fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) } // TODO add intrinsics for these (and probably the double version too) // and have the math stuff use the intrinsic. same as @mod and @rem -export fn floorf(x: f32) -> f32 { math.floor(x) } -export fn ceilf(x: f32) -> f32 { math.ceil(x) } -export fn floor(x: f64) -> f64 { math.floor(x) } -export fn ceil(x: f64) -> f64 { math.ceil(x) } +extern fn floorf(x: f32) -> f32 { math.floor(x) } +extern fn ceilf(x: f32) -> f32 { math.ceil(x) } +extern fn floor(x: f64) -> f64 { math.floor(x) } +extern fn ceil(x: f64) -> f64 { math.ceil(x) } fn generic_fmod(comptime T: type, x: T, y: T) -> T { @setDebugSafety(this, false); diff --git a/std/special/compiler_rt/aulldiv.zig b/std/special/compiler_rt/aulldiv.zig index 511aa91f80..9d4faf95b9 100644 --- a/std/special/compiler_rt/aulldiv.zig +++ b/std/special/compiler_rt/aulldiv.zig @@ -1,66 +1,55 @@ -const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; -const is_win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386; - -export nakedcc fn _aulldiv() { - if (is_win32) { - @setDebugSafety(this, false); - @setGlobalLinkage(_aulldiv, linkage); - asm volatile ( - \\.intel_syntax noprefix - \\ - \\ push ebx - \\ push esi - \\ mov eax,dword ptr [esp+18h] - \\ or eax,eax - \\ jne L1 - \\ mov ecx,dword ptr [esp+14h] - \\ mov eax,dword ptr [esp+10h] - \\ xor edx,edx - \\ div ecx - \\ mov ebx,eax - \\ mov eax,dword ptr [esp+0Ch] - \\ div ecx - \\ mov edx,ebx - \\ jmp L2 - \\ L1: - \\ mov ecx,eax - \\ mov ebx,dword ptr [esp+14h] - \\ mov edx,dword ptr [esp+10h] - \\ mov eax,dword ptr [esp+0Ch] - \\ L3: - \\ shr ecx,1 - \\ rcr ebx,1 - \\ shr edx,1 - \\ rcr eax,1 - \\ or ecx,ecx - \\ jne L3 - \\ div ebx - \\ mov esi,eax - \\ mul dword ptr [esp+18h] - \\ mov ecx,eax - \\ mov eax,dword ptr [esp+14h] - \\ mul esi - \\ add edx,ecx - \\ jb L4 - \\ cmp edx,dword ptr [esp+10h] - \\ ja L4 - \\ jb L5 - \\ cmp eax,dword ptr [esp+0Ch] - \\ jbe L5 - \\ L4: - \\ dec esi - \\ L5: - \\ xor edx,edx - \\ mov eax,esi - \\ L2: - \\ pop esi - \\ pop ebx - \\ ret 10h - ); - unreachable; - } - - @setGlobalLinkage(_aulldiv, builtin.GlobalLinkage.Internal); - unreachable; +pub nakedcc fn _aulldiv() { + @setDebugSafety(this, false); + asm volatile ( + \\.intel_syntax noprefix + \\ + \\ push ebx + \\ push esi + \\ mov eax,dword ptr [esp+18h] + \\ or eax,eax + \\ jne L1 + \\ mov ecx,dword ptr [esp+14h] + \\ mov eax,dword ptr [esp+10h] + \\ xor edx,edx + \\ div ecx + \\ mov ebx,eax + \\ mov eax,dword ptr [esp+0Ch] + \\ div ecx + \\ mov edx,ebx + \\ jmp L2 + \\ L1: + \\ mov ecx,eax + \\ mov ebx,dword ptr [esp+14h] + \\ mov edx,dword ptr [esp+10h] + \\ mov eax,dword ptr [esp+0Ch] + \\ L3: + \\ shr ecx,1 + \\ rcr ebx,1 + \\ shr edx,1 + \\ rcr eax,1 + \\ or ecx,ecx + \\ jne L3 + \\ div ebx + \\ mov esi,eax + \\ mul dword ptr [esp+18h] + \\ mov ecx,eax + \\ mov eax,dword ptr [esp+14h] + \\ mul esi + \\ add edx,ecx + \\ jb L4 + \\ cmp edx,dword ptr [esp+10h] + \\ ja L4 + \\ jb L5 + \\ cmp eax,dword ptr [esp+0Ch] + \\ jbe L5 + \\ L4: + \\ dec esi + \\ L5: + \\ xor edx,edx + \\ mov eax,esi + \\ L2: + \\ pop esi + \\ pop ebx + \\ ret 10h + ); } diff --git a/std/special/compiler_rt/aullrem.zig b/std/special/compiler_rt/aullrem.zig index e218890959..b6c54d33ae 100644 --- a/std/special/compiler_rt/aullrem.zig +++ b/std/special/compiler_rt/aullrem.zig @@ -1,67 +1,56 @@ -const builtin = @import("builtin"); -const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; -const is_win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386; - -export nakedcc fn _aullrem() { - if (is_win32) { - @setDebugSafety(this, false); - @setGlobalLinkage(_aullrem, linkage); - asm volatile ( - \\.intel_syntax noprefix - \\ - \\ push ebx - \\ mov eax,dword ptr [esp+14h] - \\ or eax,eax - \\ jne L1a - \\ mov ecx,dword ptr [esp+10h] - \\ mov eax,dword ptr [esp+0Ch] - \\ xor edx,edx - \\ div ecx - \\ mov eax,dword ptr [esp+8] - \\ div ecx - \\ mov eax,edx - \\ xor edx,edx - \\ jmp L2a - \\ L1a: - \\ mov ecx,eax - \\ mov ebx,dword ptr [esp+10h] - \\ mov edx,dword ptr [esp+0Ch] - \\ mov eax,dword ptr [esp+8] - \\ L3a: - \\ shr ecx,1 - \\ rcr ebx,1 - \\ shr edx,1 - \\ rcr eax,1 - \\ or ecx,ecx - \\ jne L3a - \\ div ebx - \\ mov ecx,eax - \\ mul dword ptr [esp+14h] - \\ xchg eax,ecx - \\ mul dword ptr [esp+10h] - \\ add edx,ecx - \\ jb L4a - \\ cmp edx,dword ptr [esp+0Ch] - \\ ja L4a - \\ jb L5a - \\ cmp eax,dword ptr [esp+8] - \\ jbe L5a - \\ L4a: - \\ sub eax,dword ptr [esp+10h] - \\ sbb edx,dword ptr [esp+14h] - \\ L5a: - \\ sub eax,dword ptr [esp+8] - \\ sbb edx,dword ptr [esp+0Ch] - \\ neg edx - \\ neg eax - \\ sbb edx,0 - \\ L2a: - \\ pop ebx - \\ ret 10h - ); - unreachable; - } - - @setGlobalLinkage(_aullrem, builtin.GlobalLinkage.Internal); - unreachable; +pub nakedcc fn _aullrem() { + @setDebugSafety(this, false); + asm volatile ( + \\.intel_syntax noprefix + \\ + \\ push ebx + \\ mov eax,dword ptr [esp+14h] + \\ or eax,eax + \\ jne L1a + \\ mov ecx,dword ptr [esp+10h] + \\ mov eax,dword ptr [esp+0Ch] + \\ xor edx,edx + \\ div ecx + \\ mov eax,dword ptr [esp+8] + \\ div ecx + \\ mov eax,edx + \\ xor edx,edx + \\ jmp L2a + \\ L1a: + \\ mov ecx,eax + \\ mov ebx,dword ptr [esp+10h] + \\ mov edx,dword ptr [esp+0Ch] + \\ mov eax,dword ptr [esp+8] + \\ L3a: + \\ shr ecx,1 + \\ rcr ebx,1 + \\ shr edx,1 + \\ rcr eax,1 + \\ or ecx,ecx + \\ jne L3a + \\ div ebx + \\ mov ecx,eax + \\ mul dword ptr [esp+14h] + \\ xchg eax,ecx + \\ mul dword ptr [esp+10h] + \\ add edx,ecx + \\ jb L4a + \\ cmp edx,dword ptr [esp+0Ch] + \\ ja L4a + \\ jb L5a + \\ cmp eax,dword ptr [esp+8] + \\ jbe L5a + \\ L4a: + \\ sub eax,dword ptr [esp+10h] + \\ sbb edx,dword ptr [esp+14h] + \\ L5a: + \\ sub eax,dword ptr [esp+8] + \\ sbb edx,dword ptr [esp+0Ch] + \\ neg edx + \\ neg eax + \\ sbb edx,0 + \\ L2a: + \\ pop ebx + \\ ret 10h + ); } diff --git a/std/special/compiler_rt/comparetf2.zig b/std/special/compiler_rt/comparetf2.zig index f1552ca61f..0834072672 100644 --- a/std/special/compiler_rt/comparetf2.zig +++ b/std/special/compiler_rt/comparetf2.zig @@ -20,11 +20,9 @@ const infRep = exponentMask; const builtin = @import("builtin"); const is_test = builtin.is_test; -const linkage = @import("index.zig").linkage; -export fn __letf2(a: f128, b: f128) -> c_int { +pub extern fn __letf2(a: f128, b: f128) -> c_int { @setDebugSafety(this, is_test); - @setGlobalLinkage(__letf2, linkage); const aInt = @bitCast(rep_t, a); const bInt = @bitCast(rep_t, b); @@ -63,14 +61,6 @@ export fn __letf2(a: f128, b: f128) -> c_int { }; } -// Alias for libgcc compatibility -// TODO https://github.com/zig-lang/zig/issues/420 -export fn __cmptf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__cmptf2, linkage); - @setDebugSafety(this, is_test); - return __letf2(a, b); -} - // TODO https://github.com/zig-lang/zig/issues/305 // and then make the return types of some of these functions the enum instead of c_int const GE_LESS = c_int(-1); @@ -78,8 +68,7 @@ const GE_EQUAL = c_int(0); const GE_GREATER = c_int(1); const GE_UNORDERED = c_int(-1); // Note: different from LE_UNORDERED -export fn __getf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__getf2, linkage); +pub extern fn __getf2(a: f128, b: f128) -> c_int { @setDebugSafety(this, is_test); const aInt = @bitCast(srep_t, a); @@ -108,38 +97,10 @@ export fn __getf2(a: f128, b: f128) -> c_int { }; } -export fn __unordtf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__unordtf2, linkage); +pub extern fn __unordtf2(a: f128, b: f128) -> c_int { @setDebugSafety(this, is_test); const aAbs = @bitCast(rep_t, a) & absMask; const bAbs = @bitCast(rep_t, b) & absMask; return c_int(aAbs > infRep or bAbs > infRep); } - -// The following are alternative names for the preceding routines. -// TODO use aliases https://github.com/zig-lang/zig/issues/462 - -export fn __eqtf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__eqtf2, linkage); - @setDebugSafety(this, is_test); - return __letf2(a, b); -} - -export fn __lttf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__lttf2, linkage); - @setDebugSafety(this, is_test); - return __letf2(a, b); -} - -export fn __netf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__netf2, linkage); - @setDebugSafety(this, is_test); - return __letf2(a, b); -} - -export fn __gttf2(a: f128, b: f128) -> c_int { - @setGlobalLinkage(__gttf2, linkage); - @setDebugSafety(this, is_test); - return __getf2(a, b); -} diff --git a/std/special/compiler_rt/fixunsdfdi.zig b/std/special/compiler_rt/fixunsdfdi.zig index 5f730bbc85..7e33987997 100644 --- a/std/special/compiler_rt/fixunsdfdi.zig +++ b/std/special/compiler_rt/fixunsdfdi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunsdfdi(a: f64) -> u64 { +pub extern fn __fixunsdfdi(a: f64) -> u64 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunsdfdi, linkage); return fixuint(f64, u64, a); } diff --git a/std/special/compiler_rt/fixunsdfsi.zig b/std/special/compiler_rt/fixunsdfsi.zig index 784d5fde4f..e710e1852b 100644 --- a/std/special/compiler_rt/fixunsdfsi.zig +++ b/std/special/compiler_rt/fixunsdfsi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunsdfsi(a: f64) -> u32 { +pub extern fn __fixunsdfsi(a: f64) -> u32 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunsdfsi, linkage); return fixuint(f64, u32, a); } diff --git a/std/special/compiler_rt/fixunsdfti.zig b/std/special/compiler_rt/fixunsdfti.zig index 579455c2f9..79d924f0a8 100644 --- a/std/special/compiler_rt/fixunsdfti.zig +++ b/std/special/compiler_rt/fixunsdfti.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunsdfti(a: f64) -> u128 { +pub extern fn __fixunsdfti(a: f64) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunsdfti, linkage); return fixuint(f64, u128, a); } diff --git a/std/special/compiler_rt/fixunssfdi.zig b/std/special/compiler_rt/fixunssfdi.zig index eab553d8c9..f72f62d68c 100644 --- a/std/special/compiler_rt/fixunssfdi.zig +++ b/std/special/compiler_rt/fixunssfdi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunssfdi(a: f32) -> u64 { +pub extern fn __fixunssfdi(a: f32) -> u64 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunssfdi, linkage); return fixuint(f32, u64, a); } diff --git a/std/special/compiler_rt/fixunssfsi.zig b/std/special/compiler_rt/fixunssfsi.zig index 18c0e66677..4c9a5001ab 100644 --- a/std/special/compiler_rt/fixunssfsi.zig +++ b/std/special/compiler_rt/fixunssfsi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunssfsi(a: f32) -> u32 { +pub extern fn __fixunssfsi(a: f32) -> u32 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunssfsi, linkage); return fixuint(f32, u32, a); } diff --git a/std/special/compiler_rt/fixunssfti.zig b/std/special/compiler_rt/fixunssfti.zig index f513604247..59b94cfc51 100644 --- a/std/special/compiler_rt/fixunssfti.zig +++ b/std/special/compiler_rt/fixunssfti.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunssfti(a: f32) -> u128 { +pub extern fn __fixunssfti(a: f32) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunssfti, linkage); return fixuint(f32, u128, a); } diff --git a/std/special/compiler_rt/fixunstfdi.zig b/std/special/compiler_rt/fixunstfdi.zig index 85212e2176..06b117a414 100644 --- a/std/special/compiler_rt/fixunstfdi.zig +++ b/std/special/compiler_rt/fixunstfdi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunstfdi(a: f128) -> u64 { +pub extern fn __fixunstfdi(a: f128) -> u64 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunstfdi, linkage); return fixuint(f128, u64, a); } diff --git a/std/special/compiler_rt/fixunstfsi.zig b/std/special/compiler_rt/fixunstfsi.zig index 33c85c9224..8a5efe711d 100644 --- a/std/special/compiler_rt/fixunstfsi.zig +++ b/std/special/compiler_rt/fixunstfsi.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunstfsi(a: f128) -> u32 { +pub extern fn __fixunstfsi(a: f128) -> u32 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunstfsi, linkage); return fixuint(f128, u32, a); } diff --git a/std/special/compiler_rt/fixunstfti.zig b/std/special/compiler_rt/fixunstfti.zig index 1bf7fbab4b..d8b654d3a3 100644 --- a/std/special/compiler_rt/fixunstfti.zig +++ b/std/special/compiler_rt/fixunstfti.zig @@ -1,10 +1,8 @@ const fixuint = @import("fixuint.zig").fixuint; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __fixunstfti(a: f128) -> u128 { +pub extern fn __fixunstfti(a: f128) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__fixunstfti, linkage); return fixuint(f128, u128, a); } diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index bea06a0b41..717c6934f5 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -1,34 +1,75 @@ -comptime { - _ = @import("comparetf2.zig"); - _ = @import("fixunsdfdi.zig"); - _ = @import("fixunsdfsi.zig"); - _ = @import("fixunsdfti.zig"); - _ = @import("fixunssfdi.zig"); - _ = @import("fixunssfsi.zig"); - _ = @import("fixunssfti.zig"); - _ = @import("fixunstfdi.zig"); - _ = @import("fixunstfsi.zig"); - _ = @import("fixunstfti.zig"); - _ = @import("udivmoddi4.zig"); - _ = @import("udivmodti4.zig"); - _ = @import("udivti3.zig"); - _ = @import("umodti3.zig"); - _ = @import("aulldiv.zig"); - _ = @import("aullrem.zig"); -} - const builtin = @import("builtin"); const is_test = builtin.is_test; + +comptime { + const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; + const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; + + @exportWithLinkage("__letf2", @import("comparetf2.zig").__letf2, linkage); + @exportWithLinkage("__getf2", @import("comparetf2.zig").__getf2, linkage); + + if (!is_test) { + // only create these aliases when not testing + @exportWithLinkage("__cmptf2", @import("comparetf2.zig").__letf2, linkage); + @exportWithLinkage("__eqtf2", @import("comparetf2.zig").__letf2, linkage); + @exportWithLinkage("__lttf2", @import("comparetf2.zig").__letf2, linkage); + @exportWithLinkage("__netf2", @import("comparetf2.zig").__letf2, linkage); + @exportWithLinkage("__gttf2", @import("comparetf2.zig").__getf2, linkage); + } + + @exportWithLinkage("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage); + + @exportWithLinkage("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage); + @exportWithLinkage("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage); + @exportWithLinkage("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage); + + @exportWithLinkage("__fixunsdfsi", @import("fixunsdfsi.zig").__fixunsdfsi, linkage); + @exportWithLinkage("__fixunsdfdi", @import("fixunsdfdi.zig").__fixunsdfdi, linkage); + @exportWithLinkage("__fixunsdfti", @import("fixunsdfti.zig").__fixunsdfti, linkage); + + @exportWithLinkage("__fixunstfsi", @import("fixunstfsi.zig").__fixunstfsi, linkage); + @exportWithLinkage("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage); + @exportWithLinkage("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage); + + @exportWithLinkage("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage); + @exportWithLinkage("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage); + + @exportWithLinkage("__udivti3", @import("udivti3.zig").__udivti3, linkage); + @exportWithLinkage("__umodti3", @import("umodti3.zig").__umodti3, linkage); + + @exportWithLinkage("__udivsi3", __udivsi3, linkage); + @exportWithLinkage("__udivdi3", __udivdi3, linkage); + @exportWithLinkage("__umoddi3", __umoddi3, linkage); + @exportWithLinkage("__udivmodsi4", __udivmodsi4, linkage); + + if (isArmArch()) { + @exportWithLinkage("__aeabi_uldivmod", __aeabi_uldivmod, linkage); + @exportWithLinkage("__aeabi_uidivmod", __aeabi_uidivmod, linkage); + @exportWithLinkage("__aeabi_uidiv", __udivsi3, linkage); + } + if (builtin.os == builtin.Os.windows) { + switch (builtin.arch) { + builtin.Arch.i386 => { + if (!builtin.link_libc) { + @exportWithLinkage("_chkstk", _chkstk, strong_linkage); + @exportWithLinkage("__chkstk_ms", __chkstk_ms, linkage); + } + @exportWithLinkage("_aulldiv", @import("aulldiv.zig")._aulldiv, strong_linkage); + @exportWithLinkage("_aullrem", @import("aullrem.zig")._aullrem, strong_linkage); + }, + builtin.Arch.x86_64 => { + if (!builtin.link_libc) { + @exportWithLinkage("__chkstk", __chkstk, strong_linkage); + @exportWithLinkage("___chkstk_ms", ___chkstk_ms, linkage); + } + }, + else => {}, + } + } +} + const assert = @import("../../debug.zig").assert; - -const win32 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386; -const win64 = builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.x86_64; -const win32_nocrt = win32 and !builtin.link_libc; -const win64_nocrt = win64 and !builtin.link_libc; -pub const linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; -const strong_linkage = if (builtin.is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; - const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; // Avoid dragging in the debug safety mechanisms into this .o file, @@ -41,15 +82,13 @@ pub coldcc fn panic(msg: []const u8) -> noreturn { } } -export fn __udivdi3(a: u64, b: u64) -> u64 { +extern fn __udivdi3(a: u64, b: u64) -> u64 { @setDebugSafety(this, is_test); - @setGlobalLinkage(__udivdi3, linkage); return __udivmoddi4(a, b, null); } -export fn __umoddi3(a: u64, b: u64) -> u64 { +extern fn __umoddi3(a: u64, b: u64) -> u64 { @setDebugSafety(this, is_test); - @setGlobalLinkage(__umoddi3, linkage); var r: u64 = undefined; _ = __udivmoddi4(a, b, &r); @@ -60,17 +99,11 @@ const AeabiUlDivModResult = extern struct { quot: u64, rem: u64, }; -export fn __aeabi_uldivmod(numerator: u64, denominator: u64) -> AeabiUlDivModResult { +extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) -> AeabiUlDivModResult { @setDebugSafety(this, is_test); - if (comptime isArmArch()) { - @setGlobalLinkage(__aeabi_uldivmod, linkage); - var result: AeabiUlDivModResult = undefined; - result.quot = __udivmoddi4(numerator, denominator, &result.rem); - return result; - } - - @setGlobalLinkage(__aeabi_uldivmod, builtin.GlobalLinkage.Internal); - unreachable; + var result: AeabiUlDivModResult = undefined; + result.quot = __udivmoddi4(numerator, denominator, &result.rem); + return result; } fn isArmArch() -> bool { @@ -98,156 +131,124 @@ fn isArmArch() -> bool { }; } -export nakedcc fn __aeabi_uidivmod() { +nakedcc fn __aeabi_uidivmod() { @setDebugSafety(this, false); - - if (comptime isArmArch()) { - @setGlobalLinkage(__aeabi_uidivmod, linkage); - asm volatile ( - \\ push { lr } - \\ sub sp, sp, #4 - \\ mov r2, sp - \\ bl __udivmodsi4 - \\ ldr r1, [sp] - \\ add sp, sp, #4 - \\ pop { pc } - ::: "r2", "r1"); - unreachable; - } - - @setGlobalLinkage(__aeabi_uidivmod, builtin.GlobalLinkage.Internal); + asm volatile ( + \\ push { lr } + \\ sub sp, sp, #4 + \\ mov r2, sp + \\ bl __udivmodsi4 + \\ ldr r1, [sp] + \\ add sp, sp, #4 + \\ pop { pc } + ::: "r2", "r1"); } // _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments, // then decrement %esp by %eax. Preserves all registers except %esp and flags. // This routine is windows specific // http://msdn.microsoft.com/en-us/library/ms648426.aspx -export nakedcc fn _chkstk() align(4) { +nakedcc fn _chkstk() align(4) { @setDebugSafety(this, false); - if (win32_nocrt) { - @setGlobalLinkage(_chkstk, strong_linkage); - asm volatile ( - \\ push %%ecx - \\ push %%eax - \\ cmp $0x1000,%%eax - \\ lea 12(%%esp),%%ecx - \\ jb 1f - \\ 2: - \\ sub $0x1000,%%ecx - \\ test %%ecx,(%%ecx) - \\ sub $0x1000,%%eax - \\ cmp $0x1000,%%eax - \\ ja 2b - \\ 1: - \\ sub %%eax,%%ecx - \\ test %%ecx,(%%ecx) - \\ pop %%eax - \\ pop %%ecx - \\ ret - ); - unreachable; - } - - @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal); + asm volatile ( + \\ push %%ecx + \\ push %%eax + \\ cmp $0x1000,%%eax + \\ lea 12(%%esp),%%ecx + \\ jb 1f + \\ 2: + \\ sub $0x1000,%%ecx + \\ test %%ecx,(%%ecx) + \\ sub $0x1000,%%eax + \\ cmp $0x1000,%%eax + \\ ja 2b + \\ 1: + \\ sub %%eax,%%ecx + \\ test %%ecx,(%%ecx) + \\ pop %%eax + \\ pop %%ecx + \\ ret + ); } -export nakedcc fn __chkstk() align(4) { +nakedcc fn __chkstk() align(4) { @setDebugSafety(this, false); - if (win64_nocrt) { - @setGlobalLinkage(__chkstk, strong_linkage); - asm volatile ( - \\ push %%rcx - \\ push %%rax - \\ cmp $0x1000,%%rax - \\ lea 24(%%rsp),%%rcx - \\ jb 1f - \\2: - \\ sub $0x1000,%%rcx - \\ test %%rcx,(%%rcx) - \\ sub $0x1000,%%rax - \\ cmp $0x1000,%%rax - \\ ja 2b - \\1: - \\ sub %%rax,%%rcx - \\ test %%rcx,(%%rcx) - \\ pop %%rax - \\ pop %%rcx - \\ ret - ); - unreachable; - } - - @setGlobalLinkage(__chkstk, builtin.GlobalLinkage.Internal); + asm volatile ( + \\ push %%rcx + \\ push %%rax + \\ cmp $0x1000,%%rax + \\ lea 24(%%rsp),%%rcx + \\ jb 1f + \\2: + \\ sub $0x1000,%%rcx + \\ test %%rcx,(%%rcx) + \\ sub $0x1000,%%rax + \\ cmp $0x1000,%%rax + \\ ja 2b + \\1: + \\ sub %%rax,%%rcx + \\ test %%rcx,(%%rcx) + \\ pop %%rax + \\ pop %%rcx + \\ ret + ); } // _chkstk routine // This routine is windows specific // http://msdn.microsoft.com/en-us/library/ms648426.aspx -export nakedcc fn __chkstk_ms() align(4) { +nakedcc fn __chkstk_ms() align(4) { @setDebugSafety(this, false); - if (win32_nocrt) { - @setGlobalLinkage(__chkstk_ms, linkage); - asm volatile ( - \\ push %%ecx - \\ push %%eax - \\ cmp $0x1000,%%eax - \\ lea 12(%%esp),%%ecx - \\ jb 1f - \\ 2: - \\ sub $0x1000,%%ecx - \\ test %%ecx,(%%ecx) - \\ sub $0x1000,%%eax - \\ cmp $0x1000,%%eax - \\ ja 2b - \\ 1: - \\ sub %%eax,%%ecx - \\ test %%ecx,(%%ecx) - \\ pop %%eax - \\ pop %%ecx - \\ ret - ); - unreachable; - } - - @setGlobalLinkage(__chkstk_ms, builtin.GlobalLinkage.Internal); + asm volatile ( + \\ push %%ecx + \\ push %%eax + \\ cmp $0x1000,%%eax + \\ lea 12(%%esp),%%ecx + \\ jb 1f + \\ 2: + \\ sub $0x1000,%%ecx + \\ test %%ecx,(%%ecx) + \\ sub $0x1000,%%eax + \\ cmp $0x1000,%%eax + \\ ja 2b + \\ 1: + \\ sub %%eax,%%ecx + \\ test %%ecx,(%%ecx) + \\ pop %%eax + \\ pop %%ecx + \\ ret + ); } -export nakedcc fn ___chkstk_ms() align(4) { +nakedcc fn ___chkstk_ms() align(4) { @setDebugSafety(this, false); - if (win64_nocrt) { - @setGlobalLinkage(___chkstk_ms, linkage); - asm volatile ( - \\ push %%rcx - \\ push %%rax - \\ cmp $0x1000,%%rax - \\ lea 24(%%rsp),%%rcx - \\ jb 1f - \\2: - \\ sub $0x1000,%%rcx - \\ test %%rcx,(%%rcx) - \\ sub $0x1000,%%rax - \\ cmp $0x1000,%%rax - \\ ja 2b - \\1: - \\ sub %%rax,%%rcx - \\ test %%rcx,(%%rcx) - \\ pop %%rax - \\ pop %%rcx - \\ ret - ); - unreachable; - } - - @setGlobalLinkage(___chkstk_ms, builtin.GlobalLinkage.Internal); + asm volatile ( + \\ push %%rcx + \\ push %%rax + \\ cmp $0x1000,%%rax + \\ lea 24(%%rsp),%%rcx + \\ jb 1f + \\2: + \\ sub $0x1000,%%rcx + \\ test %%rcx,(%%rcx) + \\ sub $0x1000,%%rax + \\ cmp $0x1000,%%rax + \\ ja 2b + \\1: + \\ sub %%rax,%%rcx + \\ test %%rcx,(%%rcx) + \\ pop %%rax + \\ pop %%rcx + \\ ret + ); } -export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { +extern fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { @setDebugSafety(this, is_test); - @setGlobalLinkage(__udivmodsi4, linkage); const d = __udivsi3(a, b); *rem = u32(i32(a) -% (i32(d) * i32(b))); @@ -255,19 +256,8 @@ export fn __udivmodsi4(a: u32, b: u32, rem: &u32) -> u32 { } -// TODO make this an alias instead of an extra function call -// https://github.com/andrewrk/zig/issues/256 - -export fn __aeabi_uidiv(n: u32, d: u32) -> u32 { +extern fn __udivsi3(n: u32, d: u32) -> u32 { @setDebugSafety(this, is_test); - @setGlobalLinkage(__aeabi_uidiv, linkage); - - return __udivsi3(n, d); -} - -export fn __udivsi3(n: u32, d: u32) -> u32 { - @setDebugSafety(this, is_test); - @setGlobalLinkage(__udivsi3, linkage); const n_uword_bits: c_uint = u32.bit_count; // special cases @@ -463,4 +453,3 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) { const q: u32 = __udivsi3(a, b); assert(q == expected_q); } - diff --git a/std/special/compiler_rt/udivmoddi4.zig b/std/special/compiler_rt/udivmoddi4.zig index 8005538d9a..4e2117cfa5 100644 --- a/std/special/compiler_rt/udivmoddi4.zig +++ b/std/special/compiler_rt/udivmoddi4.zig @@ -1,10 +1,8 @@ const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?&u64) -> u64 { +pub extern fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?&u64) -> u64 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__udivmoddi4, linkage); return udivmod(u64, a, b, maybe_rem); } diff --git a/std/special/compiler_rt/udivmodti4.zig b/std/special/compiler_rt/udivmodti4.zig index 2ee2fdb57f..c56a958f27 100644 --- a/std/special/compiler_rt/udivmodti4.zig +++ b/std/special/compiler_rt/udivmodti4.zig @@ -1,10 +1,8 @@ const udivmod = @import("udivmod.zig").udivmod; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) -> u128 { +pub extern fn __udivmodti4(a: u128, b: u128, maybe_rem: ?&u128) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__udivmodti4, linkage); return udivmod(u128, a, b, maybe_rem); } diff --git a/std/special/compiler_rt/udivti3.zig b/std/special/compiler_rt/udivti3.zig index 3764449758..115c748cfb 100644 --- a/std/special/compiler_rt/udivti3.zig +++ b/std/special/compiler_rt/udivti3.zig @@ -1,9 +1,7 @@ const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __udivti3(a: u128, b: u128) -> u128 { +pub extern fn __udivti3(a: u128, b: u128) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__udivti3, linkage); return __udivmodti4(a, b, null); } diff --git a/std/special/compiler_rt/umodti3.zig b/std/special/compiler_rt/umodti3.zig index 0ad9e127b3..9f680369eb 100644 --- a/std/special/compiler_rt/umodti3.zig +++ b/std/special/compiler_rt/umodti3.zig @@ -1,10 +1,8 @@ const __udivmodti4 = @import("udivmodti4.zig").__udivmodti4; const builtin = @import("builtin"); -const linkage = @import("index.zig").linkage; -export fn __umodti3(a: u128, b: u128) -> u128 { +pub extern fn __umodti3(a: u128, b: u128) -> u128 { @setDebugSafety(this, builtin.is_test); - @setGlobalLinkage(__umodti3, linkage); var r: u128 = undefined; _ = __udivmodti4(a, b, &r); return r; diff --git a/test/cases/asm.zig b/test/cases/asm.zig index 8a3020fe23..d7b88bd69e 100644 --- a/test/cases/asm.zig +++ b/test/cases/asm.zig @@ -2,23 +2,24 @@ const config = @import("builtin"); const assert = @import("std").debug.assert; comptime { + @export("derp", derp); if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { asm volatile ( - \\.globl aoeu; - \\.type aoeu, @function; - \\.set aoeu, derp; + \\.globl my_aoeu_symbol_asdf; + \\.type my_aoeu_symbol_asdf, @function; + \\.set my_aoeu_symbol_asdf, derp; ); } } test "module level assembly" { if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { - assert(aoeu() == 1234); + assert(my_aoeu_symbol_asdf() == 1234); } } -extern fn aoeu() -> i32; +extern fn my_aoeu_symbol_asdf() -> i32; -export fn derp() -> i32 { +extern fn derp() -> i32 { return 1234; } diff --git a/test/cases/misc.zig b/test/cases/misc.zig index e5e6575fab..1511c84b0c 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -12,8 +12,10 @@ test "empty function with comments" { emptyFunctionWithComments(); } -export fn disabledExternFn() { - @setGlobalLinkage(disabledExternFn, builtin.GlobalLinkage.Internal); +comptime { + @exportWithLinkage("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal) +} +extern fn disabledExternFn() { } test "call disabled extern fn" { @@ -533,7 +535,10 @@ var global_ptr = &gdt[0]; // can't really run this test but we can make sure it has no compile error // and generates code const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000]; -export fn writeToVRam() { +comptime { + @export("writeToVRam", writeToVRam); +} +extern fn writeToVRam() { vram[0] = 'X'; } @@ -557,3 +562,15 @@ fn hereIsAnOpaqueType(ptr: &OpaqueA) -> &OpaqueA { var a = ptr; return a; } + +test "function and variable in weird section" { + if (builtin.os == builtin.Os.linux or builtin.os == builtin.Os.windows) { + // macos can't handle this + assert(fnInWeirdSection() == 1234); + } +} + +var varInWeirdSection: i32 section(".data2") = 1234; +fn fnInWeirdSection() section(".text2") -> i32 { + return varInWeirdSection; +} diff --git a/test/compare_output.zig b/test/compare_output.zig index ad9c91ff20..4829a39fb6 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -4,7 +4,8 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompareOutputContext) { cases.addC("hello world with libc", \\const c = @cImport(@cInclude("stdio.h")); - \\export fn main(argc: c_int, argv: &&u8) -> c_int { + \\comptime { @export("main", main); } + \\extern fn main(argc: c_int, argv: &&u8) -> c_int { \\ _ = c.puts(c"Hello, world!"); \\ return 0; \\} @@ -137,7 +138,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ @cInclude("stdio.h"); \\}); \\ - \\export fn main(argc: c_int, argv: &&u8) -> c_int { + \\comptime { @export("main", main); } + \\extern fn main(argc: c_int, argv: &&u8) -> c_int { \\ if (is_windows) { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); @@ -282,7 +284,10 @@ pub fn addCases(cases: &tests.CompareOutputContext) { cases.addC("expose function pointer to C land", \\const c = @cImport(@cInclude("stdlib.h")); \\ - \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { + \\comptime { + \\ @export("main", main); + \\} + \\extern fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { \\ const a_int = @ptrCast(&align(1) i32, a ?? unreachable); \\ const b_int = @ptrCast(&align(1) i32, b ?? unreachable); \\ if (*a_int < *b_int) { @@ -294,7 +299,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ } \\} \\ - \\export fn main() -> c_int { + \\extern fn main() -> c_int { \\ var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; \\ \\ c.qsort(@ptrCast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); @@ -322,7 +327,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ @cInclude("stdio.h"); \\}); \\ - \\export fn main(argc: c_int, argv: &&u8) -> c_int { + \\comptime { @export("main", main); } + \\extern fn main(argc: c_int, argv: &&u8) -> c_int { \\ if (is_windows) { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 8dbb8171c2..8aa57c4468 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,253 +1,328 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompileErrorContext) { + cases.add("wrong return type for main", + \\pub fn main() { } + , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); + + cases.add("double ?? on main return value", + \\pub fn main() -> ??void { + \\} + , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); + + cases.add("setting a section on an extern variable", + \\extern var foo: i32 section(".text2"); + \\extern fn entry() -> i32 { + \\ return foo; + \\} + \\comptime { @export("entry", entry); } + , + ".tmp_source.zig:1:29: error: cannot set section of external variable 'foo'"); + + cases.add("setting a section on a local variable", + \\extern fn entry() -> i32 { + \\ var foo: i32 section(".text2") = 1234; + \\ return foo; + \\} + \\comptime { @export("entry", entry); } + , + ".tmp_source.zig:2:26: error: cannot set section of local variable 'foo'"); + + cases.add("setting a section on an extern fn", + \\extern fn foo() section(".text2"); + \\extern fn entry() { + \\ foo(); + \\} + \\comptime { @export("entry", entry); } + , + ".tmp_source.zig:1:25: error: cannot set section of external function 'foo'"); + + cases.add("wrong types given to exportWithLinkage", + \\extern fn entry() { } + \\comptime { + \\ @exportWithLinkage("entry", entry, u32(1234)); + \\} + , + ".tmp_source.zig:3:43: error: expected type 'GlobalLinkage', found 'u32'"); + cases.add("implicit semicolon - block statement", - \\export fn entry() { + \\extern fn entry() { \\ {} \\ var good = {}; \\ ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - block expr", - \\export fn entry() { + \\extern fn entry() { \\ _ = {}; \\ var good = {}; \\ _ = {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - comptime statement", - \\export fn entry() { + \\extern fn entry() { \\ comptime {} \\ var good = {}; \\ comptime ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - comptime expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = comptime {}; \\ var good = {}; \\ _ = comptime {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - defer", - \\export fn entry() { + \\extern fn entry() { \\ defer {} \\ var good = {}; \\ defer ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); cases.add("implicit semicolon - if statement", - \\export fn entry() { + \\extern fn entry() { \\ if(true) {} \\ var good = {}; \\ if(true) ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = if(true) {}; \\ var good = {}; \\ _ = if(true) {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else statement", - \\export fn entry() { + \\extern fn entry() { \\ if(true) {} else {} \\ var good = {}; \\ if(true) ({}) else ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = if(true) {} else {}; \\ var good = {}; \\ _ = if(true) {} else {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if statement", - \\export fn entry() { + \\extern fn entry() { \\ if(true) {} else if(true) {} \\ var good = {}; \\ if(true) ({}) else if(true) ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = if(true) {} else if(true) {}; \\ var good = {}; \\ _ = if(true) {} else if(true) {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if-else statement", - \\export fn entry() { + \\extern fn entry() { \\ if(true) {} else if(true) {} else {} \\ var good = {}; \\ if(true) ({}) else if(true) ({}) else ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if-else expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = if(true) {} else if(true) {} else {}; \\ var good = {}; \\ _ = if(true) {} else if(true) {} else {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - test statement", - \\export fn entry() { + \\extern fn entry() { \\ if (foo()) |_| {} \\ var good = {}; \\ if (foo()) |_| ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - test expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = if (foo()) |_| {}; \\ var good = {}; \\ _ = if (foo()) |_| {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while statement", - \\export fn entry() { + \\extern fn entry() { \\ while(true) {} \\ var good = {}; \\ while(true) ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = while(true) {}; \\ var good = {}; \\ _ = while(true) {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while-continue statement", - \\export fn entry() { + \\extern fn entry() { \\ while(true):({}) {} \\ var good = {}; \\ while(true):({}) ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while-continue expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = while(true):({}) {}; \\ var good = {}; \\ _ = while(true):({}) {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - for statement", - \\export fn entry() { + \\extern fn entry() { \\ for(foo()) {} \\ var good = {}; \\ for(foo()) ({}) \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - for expression", - \\export fn entry() { + \\extern fn entry() { \\ _ = for(foo()) {}; \\ var good = {}; \\ _ = for(foo()) {} \\ var bad = {}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("multiple function definitions", \\fn a() {} \\fn a() {} - \\export fn entry() { a(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { a(); } , ".tmp_source.zig:2:1: error: redefinition of 'a'"); cases.add("unreachable with return", \\fn a() -> noreturn {return;} - \\export fn entry() { a(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { a(); } , ".tmp_source.zig:1:21: error: expected type 'noreturn', found 'void'"); cases.add("control reaches end of non-void function", \\fn a() -> i32 {} - \\export fn entry() { _ = a(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { _ = a(); } , ".tmp_source.zig:1:15: error: expected type 'i32', found 'void'"); cases.add("undefined function call", - \\export fn a() { + \\extern fn a() { \\ b(); \\} + \\comptime {@export("a", a);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'"); cases.add("wrong number of arguments", - \\export fn a() { + \\extern fn a() { \\ b(1); \\} \\fn b(a: i32, b: i32, c: i32) { } + \\comptime {@export("a", a);} , ".tmp_source.zig:2:6: error: expected 3 arguments, found 1"); cases.add("invalid type", \\fn a() -> bogus {} - \\export fn entry() { _ = a(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { _ = a(); } , ".tmp_source.zig:1:11: error: use of undeclared identifier 'bogus'"); cases.add("pointer to unreachable", \\fn a() -> &noreturn {} - \\export fn entry() { _ = a(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { _ = a(); } , ".tmp_source.zig:1:12: error: pointer to unreachable not allowed"); cases.add("unreachable code", - \\export fn a() { + \\extern fn a() { \\ return; \\ b(); \\} \\ \\fn b() {} + \\comptime {@export("a", a);} , ".tmp_source.zig:3:5: error: unreachable code"); cases.add("bad import", \\const bogus = @import("bogus-does-not-exist.zig"); - \\export fn entry() { bogus.bogo(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { bogus.bogo(); } , ".tmp_source.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'"); cases.add("undeclared identifier", - \\export fn a() { + \\extern fn a() { \\ b + \\ c \\} + \\comptime {@export("a", a);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'", ".tmp_source.zig:3:5: error: use of undeclared identifier 'c'"); @@ -255,99 +330,114 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("parameter redeclaration", \\fn f(a : i32, a : i32) { \\} - \\export fn entry() { f(1, 2); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { f(1, 2); } , ".tmp_source.zig:1:15: error: redeclaration of variable 'a'"); cases.add("local variable redeclaration", - \\export fn f() { + \\extern fn f() { \\ const a : i32 = 0; \\ const a = 0; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:5: error: redeclaration of variable 'a'"); cases.add("local variable redeclares parameter", \\fn f(a : i32) { \\ const a = 0; \\} - \\export fn entry() { f(1); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { f(1); } , ".tmp_source.zig:2:5: error: redeclaration of variable 'a'"); cases.add("variable has wrong type", - \\export fn f() -> i32 { + \\extern fn f() -> i32 { \\ const a = c"a"; \\ a \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:5: error: expected type 'i32', found '&const u8'"); cases.add("if condition is bool, not int", - \\export fn f() { + \\extern fn f() { \\ if (0) {} \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:9: error: integer value 0 cannot be implicitly casted to type 'bool'"); cases.add("assign unreachable", - \\export fn f() { + \\extern fn f() { \\ const a = return; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: unreachable code"); cases.add("unreachable variable", - \\export fn f() { + \\extern fn f() { \\ const a: noreturn = {}; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:14: error: variable of type 'noreturn' not allowed"); cases.add("unreachable parameter", \\fn f(a: noreturn) {} - \\export fn entry() { f(); } + \\comptime {@export("entry", entry);} + \\extern fn entry() { f(); } , ".tmp_source.zig:1:9: error: parameter of type 'noreturn' not allowed"); cases.add("bad assignment target", - \\export fn f() { + \\extern fn f() { \\ 3 = 3; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:7: error: cannot assign to constant"); cases.add("assign to constant variable", - \\export fn f() { + \\extern fn f() { \\ const a = 3; \\ a = 4; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:7: error: cannot assign to constant"); cases.add("use of undeclared identifier", - \\export fn f() { + \\extern fn f() { \\ b = 3; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'"); cases.add("const is a statement, not an expression", - \\export fn f() { + \\extern fn f() { \\ (const a = 0); \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:6: error: invalid token: 'const'"); cases.add("array access of undeclared identifier", - \\export fn f() { + \\extern fn f() { \\ i[i] = i[i]; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'", ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'"); cases.add("array access of non array", - \\export fn f() { + \\extern fn f() { \\ var bad : bool = undefined; \\ bad[bad] = bad[bad]; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:8: error: array access of non-array type 'bool'", ".tmp_source.zig:3:19: error: array access of non-array type 'bool'"); cases.add("array access with non integer index", - \\export fn f() { + \\extern fn f() { \\ var array = "aoeu"; \\ var bad = false; \\ array[bad] = array[bad]; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'", ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'"); @@ -356,7 +446,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f() { \\ x = 1; \\} - \\export fn entry() { f(); } + \\extern fn entry() { f(); } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:7: error: cannot assign to constant"); @@ -365,29 +456,33 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ const x : i32 = if (b) { 1 }; \\ const y = if (b) { i32(1) }; \\} - \\export fn entry() { f(true); } + \\extern fn entry() { f(true); } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:30: error: integer value 1 cannot be implicitly casted to type 'void'", ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'"); cases.add("direct struct loop", \\const A = struct { a : A, }; - \\export fn entry() -> usize { @sizeOf(A) } + \\extern fn entry() -> usize { @sizeOf(A) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); cases.add("indirect struct loop", \\const A = struct { b : B, }; \\const B = struct { c : C, }; \\const C = struct { a : A, }; - \\export fn entry() -> usize { @sizeOf(A) } + \\extern fn entry() -> usize { @sizeOf(A) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); cases.add("invalid struct field", \\const A = struct { x : i32, }; - \\export fn f() { + \\extern fn f() { \\ var a : A = undefined; \\ a.foo = 1; \\ const y = a.bar; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'", ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'"); @@ -415,7 +510,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\export fn f() { + \\extern fn f() { \\ const a = A { \\ .z = 1, \\ .y = 2, @@ -423,6 +518,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ .z = 4, \\ }; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:11:9: error: duplicate field"); cases.add("missing field in struct value expression", @@ -431,7 +527,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\export fn f() { + \\extern fn f() { \\ // we want the error on the '{' not the 'A' because \\ // the A could be a complicated expression \\ const a = A { @@ -439,6 +535,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ .y = 2, \\ }; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:9:17: error: missing field: 'x'"); cases.add("invalid field in struct value expression", @@ -447,69 +544,79 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\export fn f() { + \\extern fn f() { \\ const a = A { \\ .z = 4, \\ .y = 2, \\ .foo = 42, \\ }; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'"); cases.add("invalid break expression", - \\export fn f() { + \\extern fn f() { \\ break; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: break expression outside loop"); cases.add("invalid continue expression", - \\export fn f() { + \\extern fn f() { \\ continue; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: continue expression outside loop"); cases.add("invalid maybe type", - \\export fn f() { + \\extern fn f() { \\ if (true) |x| { } \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:9: error: expected nullable type, found 'bool'"); cases.add("cast unreachable", \\fn f() -> i32 { \\ i32(return 1) \\} - \\export fn entry() { _ = f(); } + \\extern fn entry() { _ = f(); } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:8: error: unreachable code"); cases.add("invalid builtin fn", \\fn f() -> @bogus(foo) { \\} - \\export fn entry() { _ = f(); } + \\extern fn entry() { _ = f(); } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:11: error: invalid builtin function: 'bogus'"); cases.add("top level decl dependency loop", \\const a : @typeOf(b) = 0; \\const b : @typeOf(a) = 0; - \\export fn entry() { + \\extern fn entry() { \\ const c = a + b; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: 'a' depends on itself"); cases.add("noalias on non pointer param", \\fn f(noalias x: i32) {} - \\export fn entry() { f(1234); } + \\extern fn entry() { f(1234); } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:6: error: noalias on non-pointer parameter"); cases.add("struct init syntax for array", \\const foo = []u16{.x = 1024,}; - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax"); cases.add("type variables must be constant", \\var foo = u8; - \\export fn entry() -> foo { + \\extern fn entry() -> foo { \\ return 1; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: variable of type 'type' must be constant"); @@ -521,9 +628,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ var Bar : i32 = undefined; \\} \\ - \\export fn entry() { + \\extern fn entry() { \\ f(1234); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:6: error: redefinition of 'Foo'", ".tmp_source.zig:1:1: note: previous definition is here", @@ -545,7 +653,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch"); cases.add("switch expression - duplicate enumeration prong", @@ -565,7 +674,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:13:15: error: duplicate switch value", ".tmp_source.zig:10:15: note: other value is here"); @@ -587,7 +697,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:13:15: error: duplicate switch value", ".tmp_source.zig:10:15: note: other value is here"); @@ -599,9 +710,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ else => true, \\ }; \\} - \\export fn entry() { + \\extern fn entry() { \\ f(1234); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:9: error: multiple else prongs in switch expression"); cases.add("switch expression - non exhaustive integer prongs", @@ -610,7 +722,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 0 => {}, \\ } \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: switch must handle all possibilities"); @@ -623,7 +736,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 206 ... 255 => 3, \\ } \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:9: error: duplicate switch value", ".tmp_source.zig:5:14: note: previous value is here"); @@ -635,14 +749,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\const y: u8 = 100; - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: else prong required when switching on type '&u8'"); cases.add("global variable initializer must be constant expression", \\extern fn foo() -> i32; \\const x = foo(); - \\export fn entry() -> i32 { x } + \\extern fn entry() -> i32 { x } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:11: error: unable to evaluate constant expression"); cases.add("array concatenation with wrong type", @@ -650,7 +766,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const derp = usize(1234); \\const a = derp ++ "foo"; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'"); cases.add("non compile time array concatenation", @@ -658,12 +775,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ s ++ "foo" \\} \\var s: [10]u8 = undefined; - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: unable to evaluate constant expression"); cases.add("@cImport with bogus include", \\const c = @cImport(@cInclude("bogus.h")); - \\export fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:11: error: C import failed", ".h:1:10: note: 'bogus.h' file not found"); @@ -671,17 +790,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const x = 3; \\const y = &x; \\fn foo() -> &const i32 { y } - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:26: error: expected type '&const i32', found '&const (integer literal)'"); cases.add("integer overflow error", \\const x : u8 = 300; - \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'"); cases.add("incompatible number literals", \\const x = 2 == 2.0; - \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'"); cases.add("missing function call param", @@ -707,13 +829,15 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ const result = members[index](); \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0"); cases.add("missing function name and param name", \\fn () {} \\fn f(i32) {} - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: missing function name", ".tmp_source.zig:2:6: error: missing parameter name"); @@ -723,16 +847,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn a() -> i32 {0} \\fn b() -> i32 {1} \\fn c() -> i32 {2} - \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(fns)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:21: error: expected type 'fn()', found 'fn() -> i32'"); cases.add("extern function pointer mismatch", \\const fns = [](fn(i32)->i32){ a, b, c }; \\pub fn a(x: i32) -> i32 {x + 0} \\pub fn b(x: i32) -> i32 {x + 1} - \\export fn c(x: i32) -> i32 {x + 2} + \\extern fn c(x: i32) -> i32 {x + 2} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(fns)) } + \\ + \\comptime {@export("entry", entry);} + \\comptime {@export("c", c);} , ".tmp_source.zig:1:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'"); @@ -740,14 +868,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const x : f64 = 1.0; \\const y : f32 = x; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'"); cases.add("colliding invalid top level functions", \\fn func() -> bogus {} \\fn func() -> bogus {} - \\export fn entry() -> usize { @sizeOf(@typeOf(func)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(func)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:1: error: redefinition of 'func'", ".tmp_source.zig:1:14: error: use of undeclared identifier 'bogus'"); @@ -755,7 +885,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("bogus compile var", \\const x = @import("builtin").bogus; - \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:29: error: no member named 'bogus' in '"); @@ -766,7 +897,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\var global_var: usize = 1; \\fn get() -> usize { global_var } \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(Foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(Foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:21: error: unable to evaluate constant expression", ".tmp_source.zig:2:12: note: called from here", @@ -779,7 +911,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\}; \\const x = Foo {.field = 1} + Foo {.field = 2}; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'"); @@ -789,10 +922,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const int_x = u32(1) / u32(0); \\const float_x = f32(1.0) / f32(0.0); \\ - \\export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } - \\export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } - \\export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } - \\export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } + \\extern fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } + \\extern fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } + \\extern fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } + \\extern fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } + \\comptime {@export("entry1", entry1);} + \\comptime {@export("entry2", entry2);} + \\comptime {@export("entry3", entry3);} + \\comptime {@export("entry4", entry4);} , ".tmp_source.zig:1:21: error: division by zero is undefined", ".tmp_source.zig:2:25: error: division by zero is undefined", @@ -804,14 +941,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const foo = "a \\b"; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: newline not allowed in string literal"); cases.add("invalid comparison for function pointers", \\fn foo() {} \\const invalid = foo > foo; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(invalid)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(invalid)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn()'"); cases.add("generic function instance with non-constant expression", @@ -820,16 +959,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return foo(a, b); \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(test1)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(test1)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:16: error: unable to evaluate constant expression"); cases.add("goto jumping into block", - \\export fn f() { + \\extern fn f() { \\ { \\a_label: \\ } \\ goto a_label; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:5:5: error: no label in scope named 'a_label'"); cases.add("goto jumping past a defer", @@ -840,20 +981,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\fn derp(){} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:12: error: no label in scope named 'label'"); cases.add("assign null to non-nullable pointer", \\const a: &u8 = null; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'"); cases.add("indexing an array of size zero", \\const array = []u8{}; - \\export fn foo() { + \\extern fn foo() { \\ const pointer = &array[0]; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:27: error: index 0 outside array of size 0"); cases.add("compile time division by zero", @@ -862,7 +1006,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 1 / x \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:7: error: division by zero is undefined", ".tmp_source.zig:1:14: note: called from here"); @@ -870,7 +1015,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("branch on undefined value", \\const x = if (undefined) true else false; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:15: error: use of undefined value"); @@ -880,7 +1026,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return fibbonaci(x - 1) + fibbonaci(x - 2); \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } , ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches", ".tmp_source.zig:3:21: note: called from here"); @@ -888,7 +1035,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("@embedFile with bogus file", \\const resource = @embedFile("bogus.txt"); \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(resource)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(resource)) } , ".tmp_source.zig:1:29: error: unable to find '", "bogus.txt'"); cases.add("non-const expression in struct literal outside function", @@ -898,7 +1046,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const a = Foo {.x = get_it()}; \\extern fn get_it() -> i32; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:4:21: error: unable to evaluate constant expression"); cases.add("non-const expression function call with struct return value outside function", @@ -912,18 +1061,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\var global_side_effect = false; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:6:24: error: unable to evaluate constant expression", ".tmp_source.zig:4:17: note: called from here"); cases.add("undeclared identifier error should mark fn as impure", - \\export fn foo() { + \\extern fn foo() { \\ test_a_thing(); \\} \\fn test_a_thing() { \\ bad_fn_call(); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:5: error: use of undeclared identifier 'bad_fn_call'"); cases.add("illegal comparison of types", @@ -938,14 +1089,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ *a == *b \\} \\ - \\export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } - \\export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } + \\extern fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } + \\extern fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } + \\comptime {@export("entry1", entry1);} + \\comptime {@export("entry2", entry2);} , ".tmp_source.zig:2:7: error: operator not allowed for type '[]u8'", ".tmp_source.zig:9:8: error: operator not allowed for type 'EnumWithData'"); cases.add("non-const switch number literal", - \\export fn foo() { + \\extern fn foo() { \\ const x = switch (bar()) { \\ 1, 2 => 1, \\ 3, 4 => 2, @@ -955,22 +1108,25 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar() -> i32 { \\ 2 \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: unable to infer expression type"); cases.add("atomic orderings of cmpxchg - failure stricter than success", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\export fn f() { + \\extern fn f() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {} \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success"); cases.add("atomic orderings of cmpxchg - success Monotonic or stricter", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\export fn f() { + \\extern fn f() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {} \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:4:49: error: success atomic ordering must be Monotonic or stricter"); cases.add("negation overflow in function evaluation", @@ -979,7 +1135,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ -x \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:5: error: negation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -990,7 +1147,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a + b \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1002,7 +1160,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a - b \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1013,7 +1172,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a * b \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1024,40 +1184,35 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ @truncate(i8, x) \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:19: error: expected signed integer type, found 'u32'"); cases.add("%return in function with non error return type", - \\export fn f() { + \\extern fn f() { \\ %return something(); \\} \\fn something() -> %void { } + \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: expected type 'void', found 'error'"); - cases.add("wrong return type for main", - \\pub fn main() { } - , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); - - cases.add("double ?? on main return value", - \\pub fn main() -> ??void { - \\} - , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); - cases.add("invalid pointer for var type", \\extern fn ext() -> usize; \\var bytes: [ext()]u8 = undefined; - \\export fn f() { + \\extern fn f() { \\ for (bytes) |*b, i| { \\ *b = u8(i); \\ } \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:2:13: error: unable to evaluate constant expression"); cases.add("export function with comptime parameter", - \\export fn foo(comptime x: i32, y: i32) -> i32{ + \\extern fn foo(comptime x: i32, y: i32) -> i32{ \\ x + y \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); cases.add("extern function with comptime parameter", @@ -1065,14 +1220,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f() -> i32 { \\ foo(1, 2) \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); cases.add("convert fixed size array to slice with invalid size", - \\export fn f() { + \\extern fn f() { \\ var array: [5]u8 = undefined; \\ var foo = ([]const u32)(array)[0]; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:28: error: unable to convert [5]u8 to []const u32: size mismatch"); cases.add("non-pure function returns type", @@ -1090,10 +1247,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\export fn function_with_return_type_type() { + \\extern fn function_with_return_type_type() { \\ var list: List(i32) = undefined; \\ list.length = 10; \\} + \\comptime {@export("function_with_return_type_type", function_with_return_type_type);} , ".tmp_source.zig:3:7: error: unable to evaluate constant expression", ".tmp_source.zig:16:19: note: called from here"); @@ -1102,7 +1260,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f(m: []const u8) { \\ m.copy(u8, self[0..], m); \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'"); cases.add("wrong number of arguments for method fn call", @@ -1113,21 +1272,24 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ \\ foo.method(1, 2); \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3"); cases.add("assign through constant pointer", - \\export fn f() { + \\extern fn f() { \\ var cstr = c"Hat"; \\ cstr[0] = 'W'; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:11: error: cannot assign to constant"); cases.add("assign through constant slice", - \\export fn f() { + \\extern fn f() { \\ var cstr: []const u8 = "Hat"; \\ cstr[0] = 'W'; \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:3:11: error: cannot assign to constant"); cases.add("main function with bogus args type", @@ -1138,7 +1300,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn foo(blah: []u8) { \\ for (blah) { } \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: for loop expression missing element parameter"); cases.add("misspelled type with pointer only reference", @@ -1171,7 +1334,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} }; \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'"); cases.add("method call with first arg type primitive", @@ -1185,11 +1349,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\}; \\ - \\export fn f() { + \\extern fn f() { \\ const derp = Foo.init(3); \\ \\ derp.init(); \\} + \\comptime {@export("f", f);} , ".tmp_source.zig:14:5: error: expected type 'i32', found '&const Foo'"); cases.add("method call with first arg type wrong container", @@ -1213,10 +1378,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ field: i32, \\}; \\ - \\export fn foo() { + \\extern fn foo() { \\ var x = List.init(&global_allocator); \\ x.init(); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:23:5: error: expected type '&Allocator', found '&List'"); cases.add("binary not on number literal", @@ -1224,16 +1390,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT; \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1); \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'"); cases.addCase({ const tc = cases.create("multiple files with private function error", \\const foo = @import("foo.zig"); \\ - \\export fn callPrivFunction() { + \\extern fn callPrivFunction() { \\ foo.privateFunction(); \\} + \\comptime {@export("callPrivFunction", callPrivFunction);} , ".tmp_source.zig:4:8: error: 'privateFunction' is private", "foo.zig:1:1: note: declared here"); @@ -1249,17 +1417,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const zero: i32 = 0; \\const a = zero{1}; \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:11: error: expected type, found 'i32'"); cases.add("assign to constant field", \\const Foo = struct { \\ field: i32, \\}; - \\export fn derp() { + \\extern fn derp() { \\ const f = Foo {.field = 1234,}; \\ f.field = 0; \\} + \\comptime {@export("derp", derp);} , ".tmp_source.zig:6:13: error: cannot assign to constant"); cases.add("return from defer expression", @@ -1277,7 +1447,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return 0; \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:11: error: cannot return from defer expression"); cases.add("attempt to access var args out of bounds", @@ -1289,7 +1460,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ add(i32(1234)) \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:19: error: index 1 outside argument list of size 1", ".tmp_source.zig:6:8: note: called from here"); @@ -1307,27 +1479,31 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ add(1, 2, 3, 4) \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(bar)) } + \\comptime {@export("entry", entry);} + \\extern fn entry() -> usize { @sizeOf(@typeOf(bar)) } , ".tmp_source.zig:10:9: error: parameter of type '(integer literal)' requires comptime"); cases.add("assign too big number to u16", - \\export fn foo() { + \\extern fn foo() { \\ var vga_mem: u16 = 0xB8000; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'"); cases.add("global variable alignment non power of 2", \\const some_data: [100]u8 align(3) = undefined; - \\export fn entry() -> usize { @sizeOf(@typeOf(some_data)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(some_data)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2"); cases.add("function alignment non power of 2", \\extern fn foo() align(3); - \\export fn entry() { foo() } + \\extern fn entry() { foo() } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2"); cases.add("compile log", - \\export fn foo() { + \\extern fn foo() { \\ comptime bar(12, "hi"); \\} \\fn bar(a: i32, b: []const u8) { @@ -1335,6 +1511,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ @compileLog("a", a, "b", b); \\ @compileLog("end"); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:5: error: found compile log statement", ".tmp_source.zig:2:17: note: called from here", @@ -1358,7 +1535,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return *x; \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:26: error: expected type '&const u3', found '&align(1:3:6) const u3'"); cases.add("referring to a struct that is invalid", @@ -1366,19 +1544,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Type: u8, \\}; \\ - \\export fn foo() { + \\extern fn foo() { \\ comptime assert(@sizeOf(UsbDeviceRequest) == 0x8); \\} \\ \\fn assert(ok: bool) { \\ if (!ok) unreachable; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:10:14: error: unable to evaluate constant expression", ".tmp_source.zig:6:20: note: called from here"); cases.add("control flow uses comptime var at runtime", - \\export fn foo() { + \\extern fn foo() { \\ comptime var i = 0; \\ while (i < 5) : (i += 1) { \\ bar(); @@ -1386,53 +1565,61 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\ \\fn bar() { } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: control flow attempts to use compile-time variable at runtime", ".tmp_source.zig:3:24: note: compile-time variable assigned here"); cases.add("ignored return value", - \\export fn foo() { + \\extern fn foo() { \\ bar(); \\} \\fn bar() -> i32 { 0 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:8: error: expression value is ignored"); cases.add("ignored assert-err-ok return value", - \\export fn foo() { + \\extern fn foo() { \\ %%bar(); \\} \\fn bar() -> %i32 { 0 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored statement value", - \\export fn foo() { + \\extern fn foo() { \\ 1; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored comptime statement value", - \\export fn foo() { + \\extern fn foo() { \\ comptime {1;} \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expression value is ignored"); cases.add("ignored comptime value", - \\export fn foo() { + \\extern fn foo() { \\ comptime 1; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored defered statement value", - \\export fn foo() { + \\extern fn foo() { \\ defer {1;} \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:12: error: expression value is ignored"); cases.add("ignored defered statement value", - \\export fn foo() { + \\extern fn foo() { \\ defer bar(); \\} \\fn bar() -> %i32 { 0 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:14: error: expression value is ignored"); cases.add("dereference an array", @@ -1443,7 +1630,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return (*out)[0..1]; \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(pass)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(pass)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'"); cases.add("pass const ptr to mutable ptr fn", @@ -1456,46 +1644,31 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return true; \\} \\ - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'"); - cases.addCase({ - const tc = cases.create("export collision", - \\const foo = @import("foo.zig"); - \\ - \\export fn bar() -> usize { - \\ return foo.baz; - \\} - , - "foo.zig:1:8: error: exported symbol collision: 'bar'", - ".tmp_source.zig:3:8: note: other symbol is here"); - - tc.addSourceFile("foo.zig", - \\export fn bar() {} - \\pub const baz = 1234; - ); - - tc - }); - cases.add("pass non-copyable type by value to function", \\const Point = struct { x: i32, y: i32, }; \\fn foo(p: Point) { } - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value"); cases.add("implicit cast from array to mutable slice", \\var global_array: [10]i32 = undefined; \\fn foo(param: []i32) {} - \\export fn entry() { + \\extern fn entry() { \\ foo(global_array); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'"); cases.add("ptrcast to non-pointer", - \\export fn entry(a: &i32) -> usize { + \\extern fn entry(a: &i32) -> usize { \\ return @ptrCast(usize, a); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'"); cases.add("too many error values to cast to small integer", @@ -1504,7 +1677,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn foo(e: error) -> u2 { \\ return u2(e); \\} - \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'"); cases.add("asm at compile time", @@ -1523,41 +1697,46 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("invalid member of builtin enum", \\const builtin = @import("builtin"); - \\export fn entry() { + \\extern fn entry() { \\ const foo = builtin.Arch.x86; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:29: error: container 'Arch' has no member called 'x86'"); cases.add("int to ptr of 0 bits", - \\export fn foo() { + \\extern fn foo() { \\ var x: usize = 0x1000; \\ var y: &void = @intToPtr(&void, x); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:31: error: type '&void' has 0 bits and cannot store information"); cases.add("@fieldParentPtr - non struct", \\const Foo = i32; - \\export fn foo(a: &i32) -> &Foo { + \\extern fn foo(a: &i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:28: error: expected struct type, found 'i32'"); cases.add("@fieldParentPtr - bad field name", \\const Foo = struct { \\ derp: i32, \\}; - \\export fn foo(a: &i32) -> &Foo { + \\extern fn foo(a: &i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:33: error: struct 'Foo' has no field 'a'"); cases.add("@fieldParentPtr - field pointer is not pointer", \\const Foo = struct { \\ a: i32, \\}; - \\export fn foo(a: i32) -> &Foo { + \\extern fn foo(a: i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:38: error: expected pointer, found 'i32'"); cases.add("@fieldParentPtr - comptime field ptr not based on struct", @@ -1587,18 +1766,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("@offsetOf - non struct", \\const Foo = i32; - \\export fn foo() -> usize { + \\extern fn foo() -> usize { \\ return @offsetOf(Foo, "a"); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:22: error: expected struct type, found 'i32'"); cases.add("@offsetOf - bad field name", \\const Foo = struct { \\ derp: i32, \\}; - \\export fn foo() -> usize { + \\extern fn foo() -> usize { \\ return @offsetOf(Foo, "a"); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'"); cases.addExe("missing main fn in executable", @@ -1611,38 +1792,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) { "error: 'main' is private", ".tmp_source.zig:1:1: note: declared here"); - cases.add("@setGlobalSection extern variable", - \\extern var foo: i32; - \\comptime { - \\ @setGlobalSection(foo, ".text2"); - \\} - , - ".tmp_source.zig:3:5: error: cannot set section of external variable 'foo'", - ".tmp_source.zig:1:8: note: declared here"); - - cases.add("@setGlobalSection extern fn", - \\extern fn foo(); - \\comptime { - \\ @setGlobalSection(foo, ".text2"); - \\} - , - ".tmp_source.zig:3:5: error: cannot set section of external function 'foo'", - ".tmp_source.zig:1:8: note: declared here"); - cases.add("returning address of local variable - simple", - \\export fn foo() -> &i32 { + \\extern fn foo() -> &i32 { \\ var a: i32 = undefined; \\ return &a; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:13: error: function returns address of local variable"); cases.add("returning address of local variable - phi", - \\export fn foo(c: bool) -> &i32 { + \\extern fn foo(c: bool) -> &i32 { \\ var a: i32 = undefined; \\ var b: i32 = undefined; \\ return if (c) &a else &b; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:12: error: function returns address of local variable"); @@ -1671,55 +1836,61 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:5:9: note: previous definition is here"); cases.add("while expected bool, got nullable", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) {} \\} \\fn bar() -> ?i32 { 1 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'"); cases.add("while expected bool, got error union", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) {} \\} \\fn bar() -> %i32 { 1 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'"); cases.add("while expected nullable, got bool", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) |x| {} \\} \\fn bar() -> bool { true } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'"); cases.add("while expected nullable, got error union", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) |x| {} \\} \\fn bar() -> %i32 { 1 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'"); cases.add("while expected error union, got bool", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) |x| {} else |err| {} \\} \\fn bar() -> bool { true } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected error union type, found 'bool'"); cases.add("while expected error union, got nullable", - \\export fn foo() { + \\extern fn foo() { \\ while (bar()) |x| {} else |err| {} \\} \\fn bar() -> ?i32 { 1 } + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected error union type, found '?i32'"); cases.add("inline fn calls itself indirectly", - \\export fn foo() { + \\extern fn foo() { \\ bar(); \\} \\inline fn bar() { @@ -1731,29 +1902,33 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ quux(); \\} \\extern fn quux(); + \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:8: error: unable to inline function"); cases.add("save reference to inline function", - \\export fn foo() { + \\extern fn foo() { \\ quux(@ptrToInt(bar)); \\} \\inline fn bar() { } \\extern fn quux(usize); + \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:8: error: unable to inline function"); cases.add("signed integer division", - \\export fn foo(a: i32, b: i32) -> i32 { + \\extern fn foo(a: i32, b: i32) -> i32 { \\ a / b \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:7: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact"); cases.add("signed integer remainder division", - \\export fn foo(a: i32, b: i32) -> i32 { + \\extern fn foo(a: i32, b: i32) -> i32 { \\ a % b \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:7: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod"); @@ -1792,59 +1967,65 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:3:20: error: cast from 'u16' to 'u8' truncates bits"); cases.add("@setDebugSafety twice for same scope", - \\export fn foo() { + \\extern fn foo() { \\ @setDebugSafety(this, false); \\ @setDebugSafety(this, false); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: debug safety set twice for same scope", ".tmp_source.zig:2:5: note: first set here"); cases.add("@setFloatMode twice for same scope", - \\export fn foo() { + \\extern fn foo() { \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: float mode set twice for same scope", ".tmp_source.zig:2:5: note: first set here"); cases.add("array access of type", - \\export fn foo() { + \\extern fn foo() { \\ var b: u8[40] = undefined; \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:14: error: array access of non-array type 'type'"); cases.add("cannot break out of defer expression", - \\export fn foo() { + \\extern fn foo() { \\ while (true) { \\ defer { \\ break; \\ } \\ } \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:13: error: cannot break out of defer expression"); cases.add("cannot continue out of defer expression", - \\export fn foo() { + \\extern fn foo() { \\ while (true) { \\ defer { \\ continue; \\ } \\ } \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:13: error: cannot continue out of defer expression"); cases.add("cannot goto out of defer expression", - \\export fn foo() { + \\extern fn foo() { \\ defer { \\ goto label; \\ }; \\label: \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:9: error: cannot goto out of defer expression"); @@ -1878,9 +2059,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const bar = baz + foo; \\const baz = 1; \\ - \\export fn entry() -> i32 { + \\extern fn entry() -> i32 { \\ return bar; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: aoeu", ".tmp_source.zig:3:19: note: referenced here", @@ -1893,9 +2075,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ \\var foo: Foo = undefined; \\ - \\export fn entry() -> usize { + \\extern fn entry() -> usize { \\ return @sizeOf(@typeOf(foo.x)); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: struct 'Foo' contains itself"); @@ -1914,16 +2097,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:15: error: float literal out of range of any type"); cases.add("explicit cast float literal to integer when there is a fraction component", - \\export fn entry() -> i32 { + \\extern fn entry() -> i32 { \\ i32(12.34) \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:9: error: fractional component prevents float value 12.340000 from being casted to type 'i32'"); cases.add("non pointer given to @ptrToInt", - \\export fn entry(x: i32) -> usize { + \\extern fn entry(x: i32) -> usize { \\ @ptrToInt(x) \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:15: error: expected pointer, found 'i32'"); @@ -1942,24 +2127,27 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:15: error: exact shift shifted out 1 bits"); cases.add("shifting without int type or comptime known", - \\export fn entry(x: u8) -> u8 { + \\extern fn entry(x: u8) -> u8 { \\ return 0x11 << x; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:17: error: LHS of shift must be an integer type, or RHS must be compile-time known"); cases.add("shifting RHS is log2 of LHS int bit width", - \\export fn entry(x: u8, y: u8) -> u8 { + \\extern fn entry(x: u8, y: u8) -> u8 { \\ return x << y; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'"); cases.add("globally shadowing a primitive type", \\const u16 = @intType(false, 8); - \\export fn entry() { + \\extern fn entry() { \\ const a: u16 = 300; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: declaration shadows type 'u16'"); @@ -1969,7 +2157,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ b: u32, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var foo = Foo { .a = 1, .b = 10 }; \\ bar(&foo.b); \\} @@ -1977,6 +2165,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: &u32) { \\ *x += 1; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:13: error: expected type '&u32', found '&align(1) u32'"); @@ -1986,7 +2175,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ b: u32, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var foo = Foo { .a = 1, .b = 10 }; \\ foo.b += 1; \\ bar((&foo.b)[0..1]); @@ -1995,55 +2184,61 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: []u32) { \\ x[0] += 1; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:17: error: expected type '[]u32', found '[]align(1) u32'"); cases.add("increase pointer alignment in @ptrCast", - \\export fn entry() -> u32 { + \\extern fn entry() -> u32 { \\ var bytes: [4]u8 = []u8{0x01, 0x02, 0x03, 0x04}; \\ const ptr = @ptrCast(&u32, &bytes[0]); \\ return *ptr; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:17: error: cast increases pointer alignment", ".tmp_source.zig:3:38: note: '&u8' has alignment 1", ".tmp_source.zig:3:27: note: '&u32' has alignment 4"); cases.add("increase pointer alignment in slice resize", - \\export fn entry() -> u32 { + \\extern fn entry() -> u32 { \\ var bytes = []u8{0x01, 0x02, 0x03, 0x04}; \\ return ([]u32)(bytes[0..])[0]; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:19: error: cast increases pointer alignment", ".tmp_source.zig:3:19: note: '[]u8' has alignment 1", ".tmp_source.zig:3:19: note: '[]u32' has alignment 4"); cases.add("@alignCast expects pointer or slice", - \\export fn entry() { + \\extern fn entry() { \\ @alignCast(4, u32(3)) \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'"); cases.add("passing an under-aligned function pointer", - \\export fn entry() { + \\extern fn entry() { \\ testImplicitlyDecreaseFnAlign(alignedSmall, 1234); \\} \\fn testImplicitlyDecreaseFnAlign(ptr: fn () align(8) -> i32, answer: i32) { \\ if (ptr() != answer) unreachable; \\} \\fn alignedSmall() align(4) -> i32 { 1234 } + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:35: error: expected type 'fn() align(8) -> i32', found 'fn() align(4) -> i32'"); cases.add("passing a not-aligned-enough pointer to cmpxchg", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\export fn entry() -> bool { + \\extern fn entry() -> bool { \\ var x: i32 align(1) = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {} \\ return x == 5678; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:23: error: expected pointer alignment of at least 4, found 1"); @@ -2069,17 +2264,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("wrong pointer implicitly casted to pointer to @OpaqueType()", \\const Derp = @OpaqueType(); \\extern fn bar(d: &Derp); - \\export fn foo() { + \\extern fn foo() { \\ const x = u8(1); \\ bar(@ptrCast(&c_void, &x)); \\} + \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:9: error: expected type '&Derp', found '&c_void'"); cases.add("non-const variables of things that require const variables", \\const Opaque = @OpaqueType(); \\ - \\export fn entry(opaque: &Opaque) { + \\extern fn entry(opaque: &Opaque) { \\ var m2 = &2; \\ const y: u32 = *m2; \\ @@ -2099,6 +2295,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = struct { \\ fn bar(self: &const Foo) {} \\}; + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:4: error: variable of type '&const (integer literal)' must be const or comptime", ".tmp_source.zig:7:4: error: variable of type '(undefined)' must be const or comptime", @@ -2113,20 +2310,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:17:4: error: unreachable code"); cases.add("wrong types given to atomic order args in cmpxchg", - \\export fn entry() { + \\extern fn entry() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, u32(1234), u32(1234))) {} \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:41: error: expected type 'AtomicOrder', found 'u32'"); - cases.add("wrong types given to setGlobalLinkage", - \\export fn entry() { - \\ @setGlobalLinkage(entry, u32(1234)); - \\} - , - ".tmp_source.zig:2:33: error: expected type 'GlobalLinkage', found 'u32'"); - cases.add("struct with invalid field", \\const std = @import("std"); \\const Allocator = std.mem.Allocator; @@ -2145,12 +2336,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ }, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ const a = MdNode.Header { \\ .text = MdText.init(&std.debug.global_allocator), \\ .weight = HeaderWeight.H1, \\ }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'"); @@ -2162,35 +2354,39 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:5: error: @setAlignStack outside function"); cases.add("@setAlignStack in naked function", - \\export nakedcc fn entry() { + \\nakedcc fn entry() { \\ @setAlignStack(16); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: @setAlignStack in naked function"); cases.add("@setAlignStack in inline function", - \\export fn entry() { + \\extern fn entry() { \\ foo(); \\} \\inline fn foo() { \\ @setAlignStack(16); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: @setAlignStack in inline function"); cases.add("@setAlignStack set twice", - \\export fn entry() { + \\extern fn entry() { \\ @setAlignStack(16); \\ @setAlignStack(16); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:5: error: alignstack set twice", ".tmp_source.zig:2:5: note: first set here"); cases.add("@setAlignStack too big", - \\export fn entry() { + \\extern fn entry() { \\ @setAlignStack(511 + 1); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256"); @@ -2221,7 +2417,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ LinkLibC, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ const tests = []TestCase { \\ Free("001"), \\ Free("002"), @@ -2236,13 +2432,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\ } \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:37:16: error: cannot store runtime value in compile time variable"); cases.add("field access of opaque type", \\const MyType = @OpaqueType(); \\ - \\export fn entry() -> bool { + \\extern fn entry() -> bool { \\ var x: i32 = 1; \\ return bar(@ptrCast(&MyType, &x)); \\} @@ -2250,6 +2447,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: &MyType) -> bool { \\ return x.blah; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:13: error: type '&MyType' does not support field access"); @@ -2353,10 +2551,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members"); cases.add("calling var args extern function, passing array instead of pointer", - \\export fn entry() { + \\extern fn entry() { \\ foo("hello"); \\} \\pub extern fn foo(format: &const u8, ...); + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:9: error: expected type '&const u8', found '[5]u8'"); @@ -2371,9 +2570,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\export fn entry() { + \\extern fn entry() { \\ var allocator: ContextAllocator = undefined; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:25: error: aoeu", ".tmp_source.zig:1:36: note: called from here", @@ -2388,9 +2588,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Five, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var x = Small.One; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:20: error: 'u2' too small to hold all bits; must be at least 'u3'"); @@ -2401,9 +2602,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Three, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var x = Small.One; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:20: error: expected integer, found 'f32'"); @@ -2415,9 +2617,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var x: u2 = Small.Two; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'"); @@ -2429,9 +2632,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var x = u3(Small.Two); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'"); @@ -2443,10 +2647,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var y = u3(3); \\ var x = Small(y); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'"); @@ -2458,9 +2663,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\export fn entry() { + \\extern fn entry() { \\ var y = Small.Two; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'"); @@ -2468,9 +2674,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const MultipleChoice = struct { \\ A: i32 = 20, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x: MultipleChoice = undefined; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:14: error: enums, not structs, support field assignment"); @@ -2478,26 +2685,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const MultipleChoice = union { \\ A: i32 = 20, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x: MultipleChoice = undefined; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:14: error: non-enum union field assignment", ".tmp_source.zig:1:24: note: consider 'union(enum)' here"); cases.add("enum with 0 fields", \\const Foo = enum {}; - \\export fn entry() -> usize { + \\extern fn entry() -> usize { \\ return @sizeOf(Foo); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: enums must have 1 or more fields"); cases.add("union with 0 fields", \\const Foo = union {}; - \\export fn entry() -> usize { + \\extern fn entry() -> usize { \\ return @sizeOf(Foo); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: unions must have 1 or more fields"); @@ -2509,9 +2719,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ D = 1000, \\ E = 60, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x = MultipleChoice.C; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:9: error: enum tag value 60 already taken", ".tmp_source.zig:4:9: note: other occurrence here"); @@ -2526,9 +2737,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ A: i32, \\ B: f64, \\}; - \\export fn entry() -> usize { + \\extern fn entry() -> usize { \\ return @sizeOf(Payload); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:17: error: enum field missing: 'C'", ".tmp_source.zig:4:5: note: declared here"); @@ -2537,9 +2749,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union { \\ A: i32, \\}; - \\export fn entry() { + \\extern fn entry() { \\ const x = @TagType(Foo); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:24: error: union 'Foo' has no tag", ".tmp_source.zig:1:13: note: consider 'union(enum)' here"); @@ -2548,9 +2761,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union(enum(f32)) { \\ A: i32, \\}; - \\export fn entry() { + \\extern fn entry() { \\ const x = @TagType(Foo); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'"); @@ -2558,9 +2772,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union(u32) { \\ A: i32, \\}; - \\export fn entry() { + \\extern fn entry() { \\ const x = @TagType(Foo); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'"); @@ -2572,9 +2787,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ D = 1000, \\ E = 60, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x = MultipleChoice { .C = {} }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:9: error: enum tag value 60 already taken", ".tmp_source.zig:4:9: note: other occurrence here"); @@ -2591,9 +2807,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ C: bool, \\ D: bool, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var a = Payload {.A = 1234}; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:10:5: error: enum field not found: 'D'", ".tmp_source.zig:1:16: note: enum declared here"); @@ -2604,9 +2821,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var b = Letter.B; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:8: error: structs and unions, not enums, support field types", ".tmp_source.zig:1:16: note: consider 'union(enum)' here"); @@ -2615,9 +2833,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Letter = struct { \\ A, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var a = Letter { .A = {} }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: struct field missing type"); @@ -2625,9 +2844,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Letter = extern union { \\ A, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var a = Letter { .A = {} }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: union field missing type"); @@ -2642,9 +2862,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var a = Payload { .A = { 1234 } }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:29: error: extern union does not support enum tag type"); @@ -2659,9 +2880,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var a = Payload { .A = { 1234 } }; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:29: error: packed union does not support enum tag type"); @@ -2671,7 +2893,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\export fn entry() { + \\extern fn entry() { \\ const a = Payload { .A = { 1234 } }; \\ foo(a); \\} @@ -2681,6 +2903,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ else => unreachable, \\ } \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:11:13: error: switch on union which has no attached enum", ".tmp_source.zig:1:17: note: consider 'union(enum)' here"); @@ -2690,9 +2913,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ A = 10, \\ B = 11, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x = Foo(0); \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0", ".tmp_source.zig:1:13: note: 'Foo' declared here"); @@ -2704,9 +2928,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\export fn entry() { + \\extern fn entry() { \\ var x: Value = Letter.A; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'", ".tmp_source.zig:3:5: note: field 'A' declared here"); @@ -2718,13 +2943,36 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\export fn entry() { + \\extern fn entry() { \\ foo(Letter.A); \\} \\fn foo(l: Letter) { \\ var x: Value = l; \\} + \\comptime {@export("entry", entry);} , ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields", ".tmp_source.zig:3:5: note: field 'A' has type 'i32'"); + + cases.addCase({ + const tc = cases.create("export collision", + \\const foo = @import("foo.zig"); + \\ + \\comptime {@export("bar", bar);} + \\extern fn bar() -> usize { + \\ return foo.baz; + \\} + , + "foo.zig:2:11: error: exported symbol collision: 'bar'", + ".tmp_source.zig:3:11: note: other symbol is here"); + + tc.addSourceFile("foo.zig", + \\extern fn bar() {} + \\comptime {@export("bar", bar);} + \\pub const baz = 1234; + ); + + tc + }); + } diff --git a/test/standalone/issue_339/test.zig b/test/standalone/issue_339/test.zig index c1faa015c6..a3058e58ed 100644 --- a/test/standalone/issue_339/test.zig +++ b/test/standalone/issue_339/test.zig @@ -2,6 +2,9 @@ pub fn panic(msg: []const u8) -> noreturn { @breakpoint(); while (true) {} } fn bar() -> %void {} -export fn foo() { +comptime { + @export("foo", foo); +} +extern fn foo() { %%bar(); } diff --git a/test/translate_c.zig b/test/translate_c.zig index d50c7b9691..01f6622a71 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -26,7 +26,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a < 0 ? -a : a; \\} , - \\export fn abs(a: c_int) -> c_int { + \\pub fn abs(a: c_int) -> c_int { \\ return if (a < 0) -a else a; \\} ); @@ -325,12 +325,12 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\export fn foo1(_arg_a: c_uint) -> c_uint { + \\pub fn foo1(_arg_a: c_uint) -> c_uint { \\ var a = _arg_a; \\ a +%= 1; \\ return a; \\} - \\export fn foo2(_arg_a: c_int) -> c_int { + \\pub fn foo2(_arg_a: c_int) -> c_int { \\ var a = _arg_a; \\ a += 1; \\ return a; @@ -346,7 +346,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return i; \\} , - \\export fn log2(_arg_a: c_uint) -> c_int { + \\pub fn log2(_arg_a: c_uint) -> c_int { \\ var a = _arg_a; \\ var i: c_int = 0; \\ while (a > c_uint(0)) { @@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\export fn max(a: c_int, b: c_int) -> c_int { + \\pub fn max(a: c_int, b: c_int) -> c_int { \\ if (a < b) return b; \\ if (a < b) return b else return a; \\} @@ -382,7 +382,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\export fn max(a: c_int, b: c_int) -> c_int { + \\pub fn max(a: c_int, b: c_int) -> c_int { \\ if (a == b) return a; \\ if (a != b) return b; \\ return a; @@ -407,7 +407,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = a % b; \\} , - \\export fn s(a: c_int, b: c_int) -> c_int { + \\pub fn s(a: c_int, b: c_int) -> c_int { \\ var c: c_int; \\ c = (a + b); \\ c = (a - b); @@ -415,7 +415,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = @divTrunc(a, b); \\ c = @rem(a, b); \\} - \\export fn u(a: c_uint, b: c_uint) -> c_uint { + \\pub fn u(a: c_uint, b: c_uint) -> c_uint { \\ var c: c_uint; \\ c = (a +% b); \\ c = (a -% b); @@ -430,7 +430,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (a & b) ^ (a | b); \\} , - \\export fn max(a: c_int, b: c_int) -> c_int { + \\pub fn max(a: c_int, b: c_int) -> c_int { \\ return (a & b) ^ (a | b); \\} ); @@ -444,7 +444,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\export fn max(a: c_int, b: c_int) -> c_int { + \\pub fn max(a: c_int, b: c_int) -> c_int { \\ if ((a < b) or (a == b)) return b; \\ if ((a >= b) and (a == b)) return a; \\ return a; @@ -458,7 +458,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a = tmp; \\} , - \\export fn max(_arg_a: c_int) -> c_int { + \\pub fn max(_arg_a: c_int) -> c_int { \\ var a = _arg_a; \\ var tmp: c_int; \\ tmp = a; @@ -472,7 +472,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = b = a; \\} , - \\export fn max(a: c_int) { + \\pub fn max(a: c_int) { \\ var b: c_int; \\ var c: c_int; \\ c = { @@ -493,7 +493,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return i; \\} , - \\export fn log2(_arg_a: u32) -> c_int { + \\pub fn log2(_arg_a: u32) -> c_int { \\ var a = _arg_a; \\ var i: c_int = 0; \\ while (a > c_uint(0)) { @@ -518,7 +518,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\void foo(void) { bar(); } , \\pub fn bar() {} - \\export fn foo() { + \\pub fn foo() { \\ bar(); \\} ); @@ -534,7 +534,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\pub const struct_Foo = extern struct { \\ field: c_int, \\}; - \\export fn read_field(foo: ?&struct_Foo) -> c_int { + \\pub fn read_field(foo: ?&struct_Foo) -> c_int { \\ return (??foo).field; \\} ); @@ -544,7 +544,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ ;;;;; \\} , - \\export fn foo() {} + \\pub fn foo() {} ); cases.add("undefined array global", @@ -560,7 +560,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\} , \\pub var array: [100]c_int = undefined; - \\export fn foo(index: c_int) -> c_int { + \\pub fn foo(index: c_int) -> c_int { \\ return array[index]; \\} ); @@ -571,7 +571,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (int)a; \\} , - \\export fn float_to_int(a: f32) -> c_int { + \\pub fn float_to_int(a: f32) -> c_int { \\ return c_int(a); \\} ); @@ -581,7 +581,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return x; \\} , - \\export fn foo(x: ?&c_ushort) -> ?&c_void { + \\pub fn foo(x: ?&c_ushort) -> ?&c_void { \\ return @ptrCast(?&c_void, x); \\} ); @@ -592,7 +592,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return sizeof(int); \\} , - \\export fn size_of() -> usize { + \\pub fn size_of() -> usize { \\ return @sizeOf(c_int); \\} ); @@ -602,7 +602,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return 0; \\} , - \\export fn foo() -> ?&c_int { + \\pub fn foo() -> ?&c_int { \\ return null; \\} ); @@ -612,7 +612,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return 1, 2; \\} , - \\export fn foo() -> c_int { + \\pub fn foo() -> c_int { \\ return { \\ _ = 1; \\ 2 @@ -625,7 +625,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (1 << 2) >> 1; \\} , - \\export fn foo() -> c_int { + \\pub fn foo() -> c_int { \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1); \\} ); @@ -643,7 +643,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a <<= (a <<= 1); \\} , - \\export fn foo() { + \\pub fn foo() { \\ var a: c_int = 0; \\ a += { \\ const _ref = &a; @@ -701,7 +701,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a <<= (a <<= 1); \\} , - \\export fn foo() { + \\pub fn foo() { \\ var a: c_uint = c_uint(0); \\ a +%= { \\ const _ref = &a; @@ -771,7 +771,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ u = u--; \\} , - \\export fn foo() { + \\pub fn foo() { \\ var i: c_int = 0; \\ var u: c_uint = c_uint(0); \\ i += 1; @@ -819,7 +819,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ u = --u; \\} , - \\export fn foo() { + \\pub fn foo() { \\ var i: c_int = 0; \\ var u: c_uint = c_uint(0); \\ i += 1; @@ -862,7 +862,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ while (b != 0); \\} , - \\export fn foo() { + \\pub fn foo() { \\ var a: c_int = 2; \\ while (true) { \\ a -= 1; @@ -886,9 +886,9 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ baz(); \\} , - \\export fn foo() {} - \\export fn baz() {} - \\export fn bar() { + \\pub fn foo() {} + \\pub fn baz() {} + \\pub fn bar() { \\ var f: ?extern fn() = foo; \\ (??f)(); \\ (??f)(); @@ -901,7 +901,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ *x = 1; \\} , - \\export fn foo(x: ?&c_int) { + \\pub fn foo(x: ?&c_int) { \\ (*??x) = 1; \\} ); From c627f9ea18b5f194860c6bf3730f3f0407c224f2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 19 Dec 2017 01:19:49 -0500 Subject: [PATCH 2/4] wip bring back export keyword --- doc/langref.html.in | 14 +++--- src/all_types.hpp | 10 ++-- src/analyze.cpp | 29 ++++++++++- src/ir.cpp | 2 +- src/parser.cpp | 114 +++++++++++++++++++++++++++----------------- src/tokenizer.cpp | 2 + src/tokenizer.hpp | 1 + 7 files changed, 112 insertions(+), 60 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index f302cbec5d..beb113682a 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5819,9 +5819,11 @@ TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) ErrorValueDecl = "error" Symbol ";" -GlobalVarDecl = VariableDeclaration ";" +GlobalVarDecl = option("export") VariableDeclaration ";" -VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression +LocalVarDecl = option("comptime") VariableDeclaration + +VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") option("section" "(" Expression ")") "=" Expression ContainerMember = (ContainerField | FnDef | GlobalVarDecl) @@ -5831,9 +5833,9 @@ UseDecl = "use" Expression ";" ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";" -FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("->" TypeExpr) +FnProto = option("coldcc" | "nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("->" TypeExpr) -FnDef = option("inline" | "extern") FnProto Block +FnDef = option("inline" | "export") FnProto Block ParamDeclList = "(" list(ParamDecl, ",") ")" @@ -5841,7 +5843,7 @@ ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...") Block = "{" many(Statement) option(Expression) "}" -Statement = Label | VariableDeclaration ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" +Statement = Label | LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";" Label = Symbol ":" @@ -5947,7 +5949,7 @@ StructLiteralField = "." Symbol "=" Expression PrefixOp = "!" | "-" | "~" | "*" | ("&" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%" -PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl +PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl ArrayType : "[" option(Expression) "]" option("align" "(" Expression option(":" Integer ":" Integer) ")")) option("const") option("volatile") TypeExpr diff --git a/src/all_types.hpp b/src/all_types.hpp index 9256777428..106ccf6471 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -315,12 +315,6 @@ struct TldVar { VariableTableEntry *var; Buf *extern_lib_name; Buf *section_name; - - size_t export_count; - union { - TldExport *tld; // if export_count == 1 - TldExport **tld_list; // if export_count > 1 - } export_data; }; struct TldFn { @@ -428,6 +422,7 @@ struct AstNodeFnProto { AstNode *return_type; bool is_var_args; bool is_extern; + bool is_export; bool is_inline; CallingConvention cc; AstNode *fn_def_node; @@ -485,7 +480,8 @@ struct AstNodeVariableDeclaration { VisibMod visib_mod; Buf *symbol; bool is_const; - bool is_inline; + bool is_comptime; + bool is_export; bool is_extern; // one or both of type and expr will be non null AstNode *type; diff --git a/src/analyze.cpp b/src/analyze.cpp index 84d9b9feaf..470d54ff84 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1062,7 +1062,7 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; if (fn_proto->cc == CallingConventionUnspecified) { - bool extern_abi = fn_proto->is_extern; + bool extern_abi = fn_proto->is_extern || fn_proto->is_export; fn_type_id->cc = extern_abi ? CallingConventionC : CallingConventionUnspecified; } else { fn_type_id->cc = fn_proto->cc; @@ -2675,6 +2675,26 @@ static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { } static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { + bool is_export = false; + if (tld->id == TldIdVar) { + assert(tld->source_node->type == NodeTypeVariableDeclaration); + is_export = tld->source_node->data.variable_declaration.is_export; + } else if (tld->id == TldIdFn) { + assert(tld->source_node->type == NodeTypeFnProto); + is_export = tld->source_node->data.fn_proto.is_export; + } + if (is_export) { + g->resolve_queue.append(tld); + + auto entry = g->exported_symbol_names.put_unique(tld->name, tld->source_node); + if (entry) { + AstNode *other_source_node = entry->value; + ErrorMsg *msg = add_node_error(g, tld->source_node, + buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name))); + add_error_note(g, msg, other_source_node, buf_sprintf("other symbol here")); + } + } + { auto entry = decls_scope->decl_table.put_unique(tld->name, tld); if (entry) { @@ -3006,6 +3026,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { bool is_const = var_decl->is_const; bool is_extern = var_decl->is_extern; + bool is_export = var_decl->is_export; TypeTableEntry *explicit_type = nullptr; if (var_decl->type) { @@ -3013,8 +3034,12 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { explicit_type = validate_var_type(g, var_decl->type, proposed_type); } + assert(!is_export || !is_extern); + VarLinkage linkage; - if (is_extern) { + if (is_export) { + linkage = VarLinkageExport; + } else if (is_extern) { linkage = VarLinkageExternal; } else { linkage = VarLinkageInternal; diff --git a/src/ir.cpp b/src/ir.cpp index 81b64a318d..78f7c25dca 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5066,7 +5066,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod bool is_const = variable_declaration->is_const; bool is_extern = variable_declaration->is_extern; IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, - ir_should_inline(irb->exec, scope) || variable_declaration->is_inline); + ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime); VariableTableEntry *var = ir_create_var(irb, node, scope, variable_declaration->symbol, is_const, is_const, is_shadowable, is_comptime); // we detect IrInstructionIdDeclVar in gen_block to make sure the next node diff --git a/src/parser.cpp b/src/parser.cpp index 07c221e287..a2b06410ea 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -676,7 +676,7 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b } /* -PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl +PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." Symbol) | ContainerDecl KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable" */ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { @@ -791,13 +791,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo if (container_decl) return container_decl; - if (token->id == TokenIdKeywordExtern) { - *token_index += 1; - AstNode *node = ast_parse_fn_proto(pc, token_index, true, VisibModPrivate); - node->data.fn_proto.is_extern = true; - return node; - } - if (!mandatory) return nullptr; @@ -1534,38 +1527,20 @@ static AstNode *ast_parse_defer_expr(ParseContext *pc, size_t *token_index) { } /* -VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression +VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) option("align" "(" Expression ")") "=" Expression */ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *token_index, bool mandatory, - VisibMod visib_mod) + VisibMod visib_mod, bool is_comptime, bool is_export) { Token *first_token = &pc->tokens->at(*token_index); Token *var_token; bool is_const; - bool is_comptime; - if (first_token->id == TokenIdKeywordCompTime) { - is_comptime = true; - var_token = &pc->tokens->at(*token_index + 1); - - if (var_token->id == TokenIdKeywordVar) { - is_const = false; - } else if (var_token->id == TokenIdKeywordConst) { - is_const = true; - } else if (mandatory) { - ast_invalid_token_error(pc, var_token); - } else { - return nullptr; - } - - *token_index += 2; - } else if (first_token->id == TokenIdKeywordVar) { - is_comptime = false; + if (first_token->id == TokenIdKeywordVar) { is_const = false; var_token = first_token; *token_index += 1; } else if (first_token->id == TokenIdKeywordConst) { - is_comptime = false; is_const = true; var_token = first_token; *token_index += 1; @@ -1577,7 +1552,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, var_token); - node->data.variable_declaration.is_inline = is_comptime; + node->data.variable_declaration.is_comptime = is_comptime; node->data.variable_declaration.is_const = is_const; node->data.variable_declaration.visib_mod = visib_mod; @@ -1620,6 +1595,50 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to return node; } +/* +GlobalVarDecl = option("export") VariableDeclaration ";" +*/ +static AstNode *ast_parse_global_var_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) { + Token *first_token = &pc->tokens->at(*token_index); + + bool is_export = false;; + if (first_token->id == TokenIdKeywordExport) { + *token_index += 1; + is_export = true; + } + + AstNode *node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod, false, is_export); + if (node == nullptr) { + if (is_export) { + *token_index -= 1; + } + return nullptr; + } + return node; +} + +/* +LocalVarDecl = option("comptime") VariableDeclaration +*/ +static AstNode *ast_parse_local_var_decl(ParseContext *pc, size_t *token_index) { + Token *first_token = &pc->tokens->at(*token_index); + + bool is_comptime = false;; + if (first_token->id == TokenIdKeywordCompTime) { + *token_index += 1; + is_comptime = true; + } + + AstNode *node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate, is_comptime, false); + if (node == nullptr) { + if (is_comptime) { + *token_index -= 1; + } + return nullptr; + } + return node; +} + /* BoolOrExpression = BoolAndExpression "or" BoolOrExpression | BoolAndExpression */ @@ -2171,7 +2190,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand for (;;) { AstNode *statement_node = ast_parse_label(pc, token_index, false); if (!statement_node) - statement_node = ast_parse_variable_declaration_expr(pc, token_index, false, VisibModPrivate); + statement_node = ast_parse_local_var_decl(pc, token_index); if (!statement_node) statement_node = ast_parse_defer_expr(pc, token_index); if (!statement_node) @@ -2213,13 +2232,14 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand } /* -FnProto = option("coldcc" | "nakedcc" | "stdcallcc") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("->" TypeExpr) +FnProto = option("coldcc" | "nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("->" TypeExpr) */ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { Token *first_token = &pc->tokens->at(*token_index); Token *fn_token; CallingConvention cc; + bool is_extern = false; if (first_token->id == TokenIdKeywordColdCC) { *token_index += 1; fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); @@ -2232,8 +2252,13 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m *token_index += 1; fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); cc = CallingConventionStdcall; + } else if (first_token->id == TokenIdKeywordExtern) { + *token_index += 1; + fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); + cc = CallingConventionC; } else if (first_token->id == TokenIdKeywordFn) { fn_token = first_token; + is_extern = true; *token_index += 1; cc = CallingConventionUnspecified; } else if (mandatory) { @@ -2246,6 +2271,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token); node->data.fn_proto.visib_mod = visib_mod; node->data.fn_proto.cc = cc; + node->data.fn_proto.is_extern = is_extern; Token *fn_name = &pc->tokens->at(*token_index); @@ -2286,35 +2312,35 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m } /* -FnDef = option("inline" | "extern") FnProto Block +FnDef = option("inline" | "export") FnProto Block */ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) { Token *first_token = &pc->tokens->at(*token_index); bool is_inline; - bool is_extern; + bool is_export; if (first_token->id == TokenIdKeywordInline) { *token_index += 1; is_inline = true; - is_extern = false; - } else if (first_token->id == TokenIdKeywordExtern) { + is_export = false; + } else if (first_token->id == TokenIdKeywordExport) { *token_index += 1; - is_extern = true; + is_export = true; is_inline = false; } else { is_inline = false; - is_extern = false; + is_export = false; } AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, visib_mod); if (!fn_proto) { - if (is_inline || is_extern) { + if (is_inline || is_export) { *token_index -= 1; } return nullptr; } fn_proto->data.fn_proto.is_inline = is_inline; - fn_proto->data.fn_proto.is_extern = is_extern; + fn_proto->data.fn_proto.is_export = is_export; Token *semi_token = &pc->tokens->at(*token_index); if (semi_token->id == TokenIdSemicolon) { @@ -2360,7 +2386,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, size_t *token_index, boo return fn_proto_node; } - AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); + AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod, false, false); if (var_decl_node) { ast_eat_token(pc, token_index, TokenIdSemicolon); @@ -2473,7 +2499,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, continue; } - AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); + AstNode *var_decl_node = ast_parse_global_var_decl(pc, token_index, visib_mod); if (var_decl_node) { ast_eat_token(pc, token_index, TokenIdSemicolon); node->data.container_decl.decls.append(var_decl_node); @@ -2566,7 +2592,7 @@ static AstNode *ast_parse_test_decl_node(ParseContext *pc, size_t *token_index) /* TopLevelItem = ErrorValueDecl | CompTimeExpression(Block) | TopLevelDecl | TestDecl -TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | UseDecl) +TopLevelDecl = option("pub") (FnDef | ExternDecl | GlobalVarDecl | UseDecl) */ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList *top_level_decls) { for (;;) { @@ -2615,7 +2641,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig continue; } - AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); + AstNode *var_decl_node = ast_parse_global_var_decl(pc, token_index, visib_mod); if (var_decl_node) { ast_eat_token(pc, token_index, TokenIdSemicolon); top_level_decls->append(var_decl_node); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index a14f709744..9bcc79ede7 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -119,6 +119,7 @@ static const struct ZigKeyword zig_keywords[] = { {"else", TokenIdKeywordElse}, {"enum", TokenIdKeywordEnum}, {"error", TokenIdKeywordError}, + {"export", TokenIdKeywordExport}, {"extern", TokenIdKeywordExtern}, {"false", TokenIdKeywordFalse}, {"fn", TokenIdKeywordFn}, @@ -1518,6 +1519,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordElse: return "else"; case TokenIdKeywordEnum: return "enum"; case TokenIdKeywordError: return "error"; + case TokenIdKeywordExport: return "export"; case TokenIdKeywordExtern: return "extern"; case TokenIdKeywordFalse: return "false"; case TokenIdKeywordFn: return "fn"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index b0444b9c3b..58a20adc1a 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -59,6 +59,7 @@ enum TokenId { TokenIdKeywordElse, TokenIdKeywordEnum, TokenIdKeywordError, + TokenIdKeywordExport, TokenIdKeywordExtern, TokenIdKeywordFalse, TokenIdKeywordFn, From 27ba4f0baf5168b2fb8f0dd72b04f528092f075a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 19 Dec 2017 01:49:42 -0500 Subject: [PATCH 3/4] export keyword works again --- src/all_types.hpp | 1 - src/analyze.cpp | 33 +++++++++++++++++++++++++++++++++ src/analyze.hpp | 1 + src/ir.cpp | 30 +++--------------------------- src/parser.cpp | 1 + 5 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 106ccf6471..1ec3c809a2 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1183,7 +1183,6 @@ enum FnInline { struct FnExport { Buf name; GlobalLinkageId linkage; - AstNode *source_node; }; struct FnTableEntry { diff --git a/src/analyze.cpp b/src/analyze.cpp index 470d54ff84..e2df4955da 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2577,6 +2577,34 @@ TypeTableEntry *get_test_fn_type(CodeGen *g) { return g->test_fn_type; } +void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc) { + if (ccc) { + if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) { + g->have_c_main = true; + g->windows_subsystem_windows = false; + g->windows_subsystem_console = true; + } else if (buf_eql_str(symbol_name, "WinMain") && + g->zig_target.os == ZigLLVM_Win32) + { + g->have_winmain = true; + g->windows_subsystem_windows = true; + g->windows_subsystem_console = false; + } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && + g->zig_target.os == ZigLLVM_Win32) + { + g->have_winmain_crt_startup = true; + } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") && + g->zig_target.os == ZigLLVM_Win32) + { + g->have_dllmain_crt_startup = true; + } + } + FnExport *fn_export = fn_table_entry->export_list.add_one(); + memset(fn_export, 0, sizeof(FnExport)); + buf_init_from_buf(&fn_export->name, symbol_name); + fn_export->linkage = linkage; +} + static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { ImportTableEntry *import = tld_fn->base.import; AstNode *source_node = tld_fn->base.source_node; @@ -2588,6 +2616,11 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { FnTableEntry *fn_table_entry = create_fn(source_node); get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); + if (fn_proto->is_export) { + bool ccc = (fn_proto->cc == CallingConventionUnspecified || fn_proto->cc == CallingConventionC); + add_fn_export(g, fn_table_entry, &fn_table_entry->symbol_name, GlobalLinkageIdStrong, ccc); + } + tld_fn->fn_entry = fn_table_entry; if (fn_table_entry->body_node) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 0e727568c6..6224e64dd5 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -183,5 +183,6 @@ TypeTableEntry *get_align_amt_type(CodeGen *g); PackageTableEntry *new_anonymous_package(void); Buf *const_value_to_buffer(ConstExprValue *const_val); +void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc); #endif diff --git a/src/ir.cpp b/src/ir.cpp index 78f7c25dca..4afc1a2c60 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10504,35 +10504,11 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here")); } break; case CallingConventionC: - if (buf_eql_str(symbol_name, "main") && ira->codegen->libc_link_lib != nullptr) { - ira->codegen->have_c_main = true; - ira->codegen->windows_subsystem_windows = false; - ira->codegen->windows_subsystem_console = true; - } else if (buf_eql_str(symbol_name, "WinMain") && - ira->codegen->zig_target.os == ZigLLVM_Win32) - { - ira->codegen->have_winmain = true; - ira->codegen->windows_subsystem_windows = true; - ira->codegen->windows_subsystem_console = false; - } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && - ira->codegen->zig_target.os == ZigLLVM_Win32) - { - ira->codegen->have_winmain_crt_startup = true; - } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") && - ira->codegen->zig_target.os == ZigLLVM_Win32) - { - ira->codegen->have_dllmain_crt_startup = true; - } - // fallthrough case CallingConventionNaked: case CallingConventionCold: - case CallingConventionStdcall: { - FnExport *fn_export = fn_entry->export_list.add_one(); - memset(fn_export, 0, sizeof(FnExport)); - buf_init_from_buf(&fn_export->name, symbol_name); - fn_export->linkage = global_linkage_id; - fn_export->source_node = instruction->base.source_node; - } break; + case CallingConventionStdcall: + add_fn_export(ira->codegen, fn_entry, symbol_name, global_linkage_id, cc == CallingConventionC); + break; } } break; case TypeTableEntryIdStruct: diff --git a/src/parser.cpp b/src/parser.cpp index a2b06410ea..cc337471ba 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1553,6 +1553,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, var_token); node->data.variable_declaration.is_comptime = is_comptime; + node->data.variable_declaration.is_export = is_export; node->data.variable_declaration.is_const = is_const; node->data.variable_declaration.visib_mod = visib_mod; From 9d9201c3b48873e432dc6824d42b5ca96b236daa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 19 Dec 2017 02:39:43 -0500 Subject: [PATCH 4/4] bring back code that uses export and fix tests partial revert of 1fdebc1dc4881a00766f7c2b4b2d8ee6ad6e79b6 --- doc/langref.html.in | 6 + example/hello_world/hello_libc.zig | 8 +- example/mix_o_files/base64.zig | 5 +- example/shared_library/mathtest.zig | 5 +- src/all_types.hpp | 1 - src/ast_render.cpp | 7 +- src/codegen.cpp | 3 +- src/ir.cpp | 14 +- src/parser.cpp | 30 +- src/translate_c.cpp | 5 +- std/special/bootstrap.zig | 7 +- std/special/builtin.zig | 35 +- std/special/compiler_rt/index.zig | 68 +-- test/cases/asm.zig | 13 +- test/cases/misc.zig | 20 +- test/compare_output.zig | 16 +- test/compile_errors.zig | 829 ++++++++++------------------ test/standalone/issue_339/test.zig | 5 +- test/translate_c.zig | 64 +-- 19 files changed, 443 insertions(+), 698 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index beb113682a..e17e1ecd8f 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -136,6 +136,7 @@
  • @divFloor
  • @divTrunc
  • @embedFile
  • +
  • @export
  • @tagName
  • @EnumTagType
  • @errorName
  • @@ -4368,6 +4369,11 @@ test.zig:6:2: error: found compile log statement +

    @export

    +
    @export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) -> []const u8
    +

    + Creates a symbol in the output object file. +

    @tagName

    @tagName(value: var) -> []const u8

    diff --git a/example/hello_world/hello_libc.zig b/example/hello_world/hello_libc.zig index 16d0f303cc..ea8aec1e4f 100644 --- a/example/hello_world/hello_libc.zig +++ b/example/hello_world/hello_libc.zig @@ -5,13 +5,9 @@ const c = @cImport({ @cInclude("string.h"); }); -comptime { - @export("main", main); -} - -extern fn main(argc: c_int, argv: &&u8) -> c_int { - const msg = c"Hello, world!\n"; +const msg = c"Hello, world!\n"; +export fn main(argc: c_int, argv: &&u8) -> c_int { if (c.printf(msg) != c_int(c.strlen(msg))) return -1; diff --git a/example/mix_o_files/base64.zig b/example/mix_o_files/base64.zig index a8358e9685..49c9bc6012 100644 --- a/example/mix_o_files/base64.zig +++ b/example/mix_o_files/base64.zig @@ -1,9 +1,6 @@ const base64 = @import("std").base64; -comptime { - @export("decode_base_64", decode_base_64); -} -extern fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { +export fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { const src = source_ptr[0..source_len]; const dest = dest_ptr[0..dest_len]; const base64_decoder = base64.standard_decoder_unsafe; diff --git a/example/shared_library/mathtest.zig b/example/shared_library/mathtest.zig index f6d0a61c90..a11642554f 100644 --- a/example/shared_library/mathtest.zig +++ b/example/shared_library/mathtest.zig @@ -1,6 +1,3 @@ -comptime { - @export("add", add); -} -extern fn add(a: i32, b: i32) -> i32 { +export fn add(a: i32, b: i32) -> i32 { a + b } diff --git a/src/all_types.hpp b/src/all_types.hpp index 1ec3c809a2..28477c8107 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1285,7 +1285,6 @@ enum BuiltinFnId { BuiltinFnIdSetAlignStack, BuiltinFnIdArgType, BuiltinFnIdExport, - BuiltinFnIdExportWithLinkage, }; struct BuiltinFnEntry { diff --git a/src/ast_render.cpp b/src/ast_render.cpp index fc01c79ca6..c22c16d90a 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -111,6 +111,10 @@ static const char *extern_string(bool is_extern) { return is_extern ? "extern " : ""; } +static const char *export_string(bool is_export) { + return is_export ? "export " : ""; +} + //static const char *calling_convention_string(CallingConvention cc) { // switch (cc) { // case CallingConventionUnspecified: return ""; @@ -410,8 +414,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { { const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod); const char *extern_str = extern_string(node->data.fn_proto.is_extern); + const char *export_str = export_string(node->data.fn_proto.is_export); const char *inline_str = inline_string(node->data.fn_proto.is_inline); - fprintf(ar->f, "%s%s%sfn", pub_str, inline_str, extern_str); + fprintf(ar->f, "%s%s%s%sfn", pub_str, inline_str, export_str, extern_str); if (node->data.fn_proto.name != nullptr) { fprintf(ar->f, " "); print_symbol(ar, node->data.fn_proto.name); diff --git a/src/codegen.cpp b/src/codegen.cpp index 5be26eb445..7fe4f95f85 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5016,8 +5016,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2); - create_builtin_fn(g, BuiltinFnIdExport, "export", 2); - create_builtin_fn(g, BuiltinFnIdExportWithLinkage, "exportWithLinkage", 3); + create_builtin_fn(g, BuiltinFnIdExport, "export", 3); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index 4afc1a2c60..7bd045bd92 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4739,7 +4739,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value); } case BuiltinFnIdExport: - case BuiltinFnIdExportWithLinkage: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); @@ -4751,15 +4750,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *arg2_value; - if (builtin_fn->id == BuiltinFnIdExportWithLinkage) { - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - arg2_value = ir_gen_node(irb, arg2_node, scope); - if (arg2_value == irb->codegen->invalid_instruction) - return arg2_value; - } else { - arg2_value = nullptr; - } + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_instruction) + return arg2_value; return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value); } diff --git a/src/parser.cpp b/src/parser.cpp index cc337471ba..579fe85f3b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -740,9 +740,21 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo return node; } else if (token->id == TokenIdAtSign) { *token_index += 1; - Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); + Token *name_tok = &pc->tokens->at(*token_index); + Buf *name_buf; + if (name_tok->id == TokenIdKeywordExport) { + name_buf = buf_create_from_str("export"); + *token_index += 1; + } else if (name_tok->id == TokenIdSymbol) { + name_buf = token_buf(name_tok); + *token_index += 1; + } else { + ast_expect_token(pc, name_tok, TokenIdSymbol); + zig_unreachable(); + } + AstNode *name_node = ast_create_node(pc, NodeTypeSymbol, name_tok); - name_node->data.symbol_expr.symbol = token_buf(name_tok); + name_node->data.symbol_expr.symbol = name_buf; AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token); node->data.fn_call_expr.fn_ref_expr = name_node; @@ -2254,12 +2266,22 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); cc = CallingConventionStdcall; } else if (first_token->id == TokenIdKeywordExtern) { + is_extern = true; *token_index += 1; - fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn); + Token *next_token = &pc->tokens->at(*token_index); + if (next_token->id == TokenIdKeywordFn) { + fn_token = next_token; + *token_index += 1; + } else if (mandatory) { + ast_expect_token(pc, next_token, TokenIdKeywordFn); + zig_unreachable(); + } else { + *token_index -= 1; + return nullptr; + } cc = CallingConventionC; } else if (first_token->id == TokenIdKeywordFn) { fn_token = first_token; - is_extern = true; *token_index += 1; cc = CallingConventionUnspecified; } else if (mandatory) { diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 77afc38a51..eba594e085 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -73,6 +73,7 @@ struct Context { ImportTableEntry *import; ZigList *errors; VisibMod visib_mod; + bool want_export; AstNode *root; HashMap decl_table; HashMap macro_table; @@ -3250,8 +3251,8 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { StorageClass sc = fn_decl->getStorageClass(); if (sc == SC_None) { - // TODO add export decl proto_node->data.fn_proto.visib_mod = c->visib_mod; + proto_node->data.fn_proto.is_export = fn_decl->hasBody() ? c->want_export : false; } else if (sc == SC_Extern || sc == SC_Static) { proto_node->data.fn_proto.visib_mod = c->visib_mod; } else if (sc == SC_PrivateExtern) { @@ -4274,8 +4275,10 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch c->errors = errors; if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { c->visib_mod = VisibModPub; + c->want_export = false; } else { c->visib_mod = VisibModPub; + c->want_export = true; } c->decl_table.init(8); c->macro_table.init(8); diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index ee63467305..177e245400 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -8,12 +8,13 @@ const builtin = @import("builtin"); var argc_ptr: &usize = undefined; comptime { + const strong_linkage = builtin.GlobalLinkage.Strong; if (builtin.link_libc) { - @export("main", main); + @export("main", main, strong_linkage); } else if (builtin.os == builtin.Os.windows) { - @export("WinMainCRTStartup", WinMainCRTStartup); + @export("WinMainCRTStartup", WinMainCRTStartup, strong_linkage); } else { - @export("_start", _start); + @export("_start", _start, strong_linkage); } } diff --git a/std/special/builtin.zig b/std/special/builtin.zig index 9ace9b46ca..a2455a9690 100644 --- a/std/special/builtin.zig +++ b/std/special/builtin.zig @@ -13,24 +13,10 @@ pub coldcc fn panic(msg: []const u8) -> noreturn { } } -comptime { - @export("memset", memset); - @export("memcpy", memcpy); - @export("fmodf", fmodf); - @export("fmod", fmod); - @export("floorf", floorf); - @export("ceilf", ceilf); - @export("floor", floor); - @export("ceil", ceil); - if (builtin.mode != builtin.Mode.ReleaseFast and builtin.os != builtin.Os.windows) { - @export("__stack_chk_fail", __stack_chk_fail); - } -} - // Note that memset does not return `dest`, like the libc API. // The semantics of memset is dictated by the corresponding // LLVM intrinsics, not by the libc API. -extern fn memset(dest: ?&u8, c: u8, n: usize) { +export fn memset(dest: ?&u8, c: u8, n: usize) { @setDebugSafety(this, false); var index: usize = 0; @@ -41,7 +27,7 @@ extern fn memset(dest: ?&u8, c: u8, n: usize) { // Note that memcpy does not return `dest`, like the libc API. // The semantics of memcpy is dictated by the corresponding // LLVM intrinsics, not by the libc API. -extern fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { +export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { @setDebugSafety(this, false); var index: usize = 0; @@ -49,21 +35,26 @@ extern fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) { (??dest)[index] = (??src)[index]; } +comptime { + if (builtin.mode != builtin.Mode.ReleaseFast and builtin.os != builtin.Os.windows) { + @export("__stack_chk_fail", __stack_chk_fail, builtin.GlobalLinkage.Strong); + } +} extern fn __stack_chk_fail() -> noreturn { @panic("stack smashing detected"); } const math = @import("../math/index.zig"); -extern fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) } -extern fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) } +export fn fmodf(x: f32, y: f32) -> f32 { generic_fmod(f32, x, y) } +export fn fmod(x: f64, y: f64) -> f64 { generic_fmod(f64, x, y) } // TODO add intrinsics for these (and probably the double version too) // and have the math stuff use the intrinsic. same as @mod and @rem -extern fn floorf(x: f32) -> f32 { math.floor(x) } -extern fn ceilf(x: f32) -> f32 { math.ceil(x) } -extern fn floor(x: f64) -> f64 { math.floor(x) } -extern fn ceil(x: f64) -> f64 { math.ceil(x) } +export fn floorf(x: f32) -> f32 { math.floor(x) } +export fn ceilf(x: f32) -> f32 { math.ceil(x) } +export fn floor(x: f64) -> f64 { math.floor(x) } +export fn ceil(x: f64) -> f64 { math.ceil(x) } fn generic_fmod(comptime T: type, x: T, y: T) -> T { @setDebugSafety(this, false); diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index 717c6934f5..fab7b7c878 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -5,62 +5,62 @@ comptime { const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; - @exportWithLinkage("__letf2", @import("comparetf2.zig").__letf2, linkage); - @exportWithLinkage("__getf2", @import("comparetf2.zig").__getf2, linkage); + @export("__letf2", @import("comparetf2.zig").__letf2, linkage); + @export("__getf2", @import("comparetf2.zig").__getf2, linkage); if (!is_test) { // only create these aliases when not testing - @exportWithLinkage("__cmptf2", @import("comparetf2.zig").__letf2, linkage); - @exportWithLinkage("__eqtf2", @import("comparetf2.zig").__letf2, linkage); - @exportWithLinkage("__lttf2", @import("comparetf2.zig").__letf2, linkage); - @exportWithLinkage("__netf2", @import("comparetf2.zig").__letf2, linkage); - @exportWithLinkage("__gttf2", @import("comparetf2.zig").__getf2, linkage); + @export("__cmptf2", @import("comparetf2.zig").__letf2, linkage); + @export("__eqtf2", @import("comparetf2.zig").__letf2, linkage); + @export("__lttf2", @import("comparetf2.zig").__letf2, linkage); + @export("__netf2", @import("comparetf2.zig").__letf2, linkage); + @export("__gttf2", @import("comparetf2.zig").__getf2, linkage); } - @exportWithLinkage("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage); + @export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage); - @exportWithLinkage("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage); - @exportWithLinkage("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage); - @exportWithLinkage("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage); + @export("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage); + @export("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage); + @export("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage); - @exportWithLinkage("__fixunsdfsi", @import("fixunsdfsi.zig").__fixunsdfsi, linkage); - @exportWithLinkage("__fixunsdfdi", @import("fixunsdfdi.zig").__fixunsdfdi, linkage); - @exportWithLinkage("__fixunsdfti", @import("fixunsdfti.zig").__fixunsdfti, linkage); + @export("__fixunsdfsi", @import("fixunsdfsi.zig").__fixunsdfsi, linkage); + @export("__fixunsdfdi", @import("fixunsdfdi.zig").__fixunsdfdi, linkage); + @export("__fixunsdfti", @import("fixunsdfti.zig").__fixunsdfti, linkage); - @exportWithLinkage("__fixunstfsi", @import("fixunstfsi.zig").__fixunstfsi, linkage); - @exportWithLinkage("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage); - @exportWithLinkage("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage); + @export("__fixunstfsi", @import("fixunstfsi.zig").__fixunstfsi, linkage); + @export("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage); + @export("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage); - @exportWithLinkage("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage); - @exportWithLinkage("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage); + @export("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage); + @export("__udivmodti4", @import("udivmodti4.zig").__udivmodti4, linkage); - @exportWithLinkage("__udivti3", @import("udivti3.zig").__udivti3, linkage); - @exportWithLinkage("__umodti3", @import("umodti3.zig").__umodti3, linkage); + @export("__udivti3", @import("udivti3.zig").__udivti3, linkage); + @export("__umodti3", @import("umodti3.zig").__umodti3, linkage); - @exportWithLinkage("__udivsi3", __udivsi3, linkage); - @exportWithLinkage("__udivdi3", __udivdi3, linkage); - @exportWithLinkage("__umoddi3", __umoddi3, linkage); - @exportWithLinkage("__udivmodsi4", __udivmodsi4, linkage); + @export("__udivsi3", __udivsi3, linkage); + @export("__udivdi3", __udivdi3, linkage); + @export("__umoddi3", __umoddi3, linkage); + @export("__udivmodsi4", __udivmodsi4, linkage); if (isArmArch()) { - @exportWithLinkage("__aeabi_uldivmod", __aeabi_uldivmod, linkage); - @exportWithLinkage("__aeabi_uidivmod", __aeabi_uidivmod, linkage); - @exportWithLinkage("__aeabi_uidiv", __udivsi3, linkage); + @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage); + @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage); + @export("__aeabi_uidiv", __udivsi3, linkage); } if (builtin.os == builtin.Os.windows) { switch (builtin.arch) { builtin.Arch.i386 => { if (!builtin.link_libc) { - @exportWithLinkage("_chkstk", _chkstk, strong_linkage); - @exportWithLinkage("__chkstk_ms", __chkstk_ms, linkage); + @export("_chkstk", _chkstk, strong_linkage); + @export("__chkstk_ms", __chkstk_ms, linkage); } - @exportWithLinkage("_aulldiv", @import("aulldiv.zig")._aulldiv, strong_linkage); - @exportWithLinkage("_aullrem", @import("aullrem.zig")._aullrem, strong_linkage); + @export("_aulldiv", @import("aulldiv.zig")._aulldiv, strong_linkage); + @export("_aullrem", @import("aullrem.zig")._aullrem, strong_linkage); }, builtin.Arch.x86_64 => { if (!builtin.link_libc) { - @exportWithLinkage("__chkstk", __chkstk, strong_linkage); - @exportWithLinkage("___chkstk_ms", ___chkstk_ms, linkage); + @export("__chkstk", __chkstk, strong_linkage); + @export("___chkstk_ms", ___chkstk_ms, linkage); } }, else => {}, diff --git a/test/cases/asm.zig b/test/cases/asm.zig index d7b88bd69e..8a3020fe23 100644 --- a/test/cases/asm.zig +++ b/test/cases/asm.zig @@ -2,24 +2,23 @@ const config = @import("builtin"); const assert = @import("std").debug.assert; comptime { - @export("derp", derp); if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { asm volatile ( - \\.globl my_aoeu_symbol_asdf; - \\.type my_aoeu_symbol_asdf, @function; - \\.set my_aoeu_symbol_asdf, derp; + \\.globl aoeu; + \\.type aoeu, @function; + \\.set aoeu, derp; ); } } test "module level assembly" { if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { - assert(my_aoeu_symbol_asdf() == 1234); + assert(aoeu() == 1234); } } -extern fn my_aoeu_symbol_asdf() -> i32; +extern fn aoeu() -> i32; -extern fn derp() -> i32 { +export fn derp() -> i32 { return 1234; } diff --git a/test/cases/misc.zig b/test/cases/misc.zig index 1511c84b0c..daa7c3eb98 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -13,8 +13,9 @@ test "empty function with comments" { } comptime { - @exportWithLinkage("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal) + @export("disabledExternFn", disabledExternFn, builtin.GlobalLinkage.Internal); } + extern fn disabledExternFn() { } @@ -535,10 +536,7 @@ var global_ptr = &gdt[0]; // can't really run this test but we can make sure it has no compile error // and generates code const vram = @intToPtr(&volatile u8, 0x20000000)[0..0x8000]; -comptime { - @export("writeToVRam", writeToVRam); -} -extern fn writeToVRam() { +export fn writeToVRam() { vram[0] = 'X'; } @@ -562,15 +560,3 @@ fn hereIsAnOpaqueType(ptr: &OpaqueA) -> &OpaqueA { var a = ptr; return a; } - -test "function and variable in weird section" { - if (builtin.os == builtin.Os.linux or builtin.os == builtin.Os.windows) { - // macos can't handle this - assert(fnInWeirdSection() == 1234); - } -} - -var varInWeirdSection: i32 section(".data2") = 1234; -fn fnInWeirdSection() section(".text2") -> i32 { - return varInWeirdSection; -} diff --git a/test/compare_output.zig b/test/compare_output.zig index 4829a39fb6..ad9c91ff20 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -4,8 +4,7 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompareOutputContext) { cases.addC("hello world with libc", \\const c = @cImport(@cInclude("stdio.h")); - \\comptime { @export("main", main); } - \\extern fn main(argc: c_int, argv: &&u8) -> c_int { + \\export fn main(argc: c_int, argv: &&u8) -> c_int { \\ _ = c.puts(c"Hello, world!"); \\ return 0; \\} @@ -138,8 +137,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ @cInclude("stdio.h"); \\}); \\ - \\comptime { @export("main", main); } - \\extern fn main(argc: c_int, argv: &&u8) -> c_int { + \\export fn main(argc: c_int, argv: &&u8) -> c_int { \\ if (is_windows) { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); @@ -284,10 +282,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { cases.addC("expose function pointer to C land", \\const c = @cImport(@cInclude("stdlib.h")); \\ - \\comptime { - \\ @export("main", main); - \\} - \\extern fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { + \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { \\ const a_int = @ptrCast(&align(1) i32, a ?? unreachable); \\ const b_int = @ptrCast(&align(1) i32, b ?? unreachable); \\ if (*a_int < *b_int) { @@ -299,7 +294,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ } \\} \\ - \\extern fn main() -> c_int { + \\export fn main() -> c_int { \\ var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; \\ \\ c.qsort(@ptrCast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); @@ -327,8 +322,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) { \\ @cInclude("stdio.h"); \\}); \\ - \\comptime { @export("main", main); } - \\extern fn main(argc: c_int, argv: &&u8) -> c_int { + \\export fn main(argc: c_int, argv: &&u8) -> c_int { \\ if (is_windows) { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 8aa57c4468..22520802fb 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,328 +1,253 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompileErrorContext) { - cases.add("wrong return type for main", - \\pub fn main() { } - , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); - - cases.add("double ?? on main return value", - \\pub fn main() -> ??void { - \\} - , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); - - cases.add("setting a section on an extern variable", - \\extern var foo: i32 section(".text2"); - \\extern fn entry() -> i32 { - \\ return foo; - \\} - \\comptime { @export("entry", entry); } - , - ".tmp_source.zig:1:29: error: cannot set section of external variable 'foo'"); - - cases.add("setting a section on a local variable", - \\extern fn entry() -> i32 { - \\ var foo: i32 section(".text2") = 1234; - \\ return foo; - \\} - \\comptime { @export("entry", entry); } - , - ".tmp_source.zig:2:26: error: cannot set section of local variable 'foo'"); - - cases.add("setting a section on an extern fn", - \\extern fn foo() section(".text2"); - \\extern fn entry() { - \\ foo(); - \\} - \\comptime { @export("entry", entry); } - , - ".tmp_source.zig:1:25: error: cannot set section of external function 'foo'"); - - cases.add("wrong types given to exportWithLinkage", - \\extern fn entry() { } - \\comptime { - \\ @exportWithLinkage("entry", entry, u32(1234)); - \\} - , - ".tmp_source.zig:3:43: error: expected type 'GlobalLinkage', found 'u32'"); - cases.add("implicit semicolon - block statement", - \\extern fn entry() { + \\export fn entry() { \\ {} \\ var good = {}; \\ ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - block expr", - \\extern fn entry() { + \\export fn entry() { \\ _ = {}; \\ var good = {}; \\ _ = {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - comptime statement", - \\extern fn entry() { + \\export fn entry() { \\ comptime {} \\ var good = {}; \\ comptime ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - comptime expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = comptime {}; \\ var good = {}; \\ _ = comptime {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - defer", - \\extern fn entry() { + \\export fn entry() { \\ defer {} \\ var good = {}; \\ defer ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); cases.add("implicit semicolon - if statement", - \\extern fn entry() { + \\export fn entry() { \\ if(true) {} \\ var good = {}; \\ if(true) ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = if(true) {}; \\ var good = {}; \\ _ = if(true) {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else statement", - \\extern fn entry() { + \\export fn entry() { \\ if(true) {} else {} \\ var good = {}; \\ if(true) ({}) else ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = if(true) {} else {}; \\ var good = {}; \\ _ = if(true) {} else {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if statement", - \\extern fn entry() { + \\export fn entry() { \\ if(true) {} else if(true) {} \\ var good = {}; \\ if(true) ({}) else if(true) ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = if(true) {} else if(true) {}; \\ var good = {}; \\ _ = if(true) {} else if(true) {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if-else statement", - \\extern fn entry() { + \\export fn entry() { \\ if(true) {} else if(true) {} else {} \\ var good = {}; \\ if(true) ({}) else if(true) ({}) else ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - if-else-if-else expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = if(true) {} else if(true) {} else {}; \\ var good = {}; \\ _ = if(true) {} else if(true) {} else {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - test statement", - \\extern fn entry() { + \\export fn entry() { \\ if (foo()) |_| {} \\ var good = {}; \\ if (foo()) |_| ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - test expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = if (foo()) |_| {}; \\ var good = {}; \\ _ = if (foo()) |_| {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while statement", - \\extern fn entry() { + \\export fn entry() { \\ while(true) {} \\ var good = {}; \\ while(true) ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = while(true) {}; \\ var good = {}; \\ _ = while(true) {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while-continue statement", - \\extern fn entry() { + \\export fn entry() { \\ while(true):({}) {} \\ var good = {}; \\ while(true):({}) ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - while-continue expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = while(true):({}) {}; \\ var good = {}; \\ _ = while(true):({}) {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - for statement", - \\extern fn entry() { + \\export fn entry() { \\ for(foo()) {} \\ var good = {}; \\ for(foo()) ({}) \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("implicit semicolon - for expression", - \\extern fn entry() { + \\export fn entry() { \\ _ = for(foo()) {}; \\ var good = {}; \\ _ = for(foo()) {} \\ var bad = {}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: invalid token: 'var'"); cases.add("multiple function definitions", \\fn a() {} \\fn a() {} - \\comptime {@export("entry", entry);} - \\extern fn entry() { a(); } + \\export fn entry() { a(); } , ".tmp_source.zig:2:1: error: redefinition of 'a'"); cases.add("unreachable with return", \\fn a() -> noreturn {return;} - \\comptime {@export("entry", entry);} - \\extern fn entry() { a(); } + \\export fn entry() { a(); } , ".tmp_source.zig:1:21: error: expected type 'noreturn', found 'void'"); cases.add("control reaches end of non-void function", \\fn a() -> i32 {} - \\comptime {@export("entry", entry);} - \\extern fn entry() { _ = a(); } + \\export fn entry() { _ = a(); } , ".tmp_source.zig:1:15: error: expected type 'i32', found 'void'"); cases.add("undefined function call", - \\extern fn a() { + \\export fn a() { \\ b(); \\} - \\comptime {@export("a", a);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'"); cases.add("wrong number of arguments", - \\extern fn a() { + \\export fn a() { \\ b(1); \\} \\fn b(a: i32, b: i32, c: i32) { } - \\comptime {@export("a", a);} , ".tmp_source.zig:2:6: error: expected 3 arguments, found 1"); cases.add("invalid type", \\fn a() -> bogus {} - \\comptime {@export("entry", entry);} - \\extern fn entry() { _ = a(); } + \\export fn entry() { _ = a(); } , ".tmp_source.zig:1:11: error: use of undeclared identifier 'bogus'"); cases.add("pointer to unreachable", \\fn a() -> &noreturn {} - \\comptime {@export("entry", entry);} - \\extern fn entry() { _ = a(); } + \\export fn entry() { _ = a(); } , ".tmp_source.zig:1:12: error: pointer to unreachable not allowed"); cases.add("unreachable code", - \\extern fn a() { + \\export fn a() { \\ return; \\ b(); \\} \\ \\fn b() {} - \\comptime {@export("a", a);} , ".tmp_source.zig:3:5: error: unreachable code"); cases.add("bad import", \\const bogus = @import("bogus-does-not-exist.zig"); - \\comptime {@export("entry", entry);} - \\extern fn entry() { bogus.bogo(); } + \\export fn entry() { bogus.bogo(); } , ".tmp_source.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'"); cases.add("undeclared identifier", - \\extern fn a() { + \\export fn a() { \\ b + \\ c \\} - \\comptime {@export("a", a);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'", ".tmp_source.zig:3:5: error: use of undeclared identifier 'c'"); @@ -330,114 +255,99 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("parameter redeclaration", \\fn f(a : i32, a : i32) { \\} - \\comptime {@export("entry", entry);} - \\extern fn entry() { f(1, 2); } + \\export fn entry() { f(1, 2); } , ".tmp_source.zig:1:15: error: redeclaration of variable 'a'"); cases.add("local variable redeclaration", - \\extern fn f() { + \\export fn f() { \\ const a : i32 = 0; \\ const a = 0; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:5: error: redeclaration of variable 'a'"); cases.add("local variable redeclares parameter", \\fn f(a : i32) { \\ const a = 0; \\} - \\comptime {@export("entry", entry);} - \\extern fn entry() { f(1); } + \\export fn entry() { f(1); } , ".tmp_source.zig:2:5: error: redeclaration of variable 'a'"); cases.add("variable has wrong type", - \\extern fn f() -> i32 { + \\export fn f() -> i32 { \\ const a = c"a"; \\ a \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:5: error: expected type 'i32', found '&const u8'"); cases.add("if condition is bool, not int", - \\extern fn f() { + \\export fn f() { \\ if (0) {} \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:9: error: integer value 0 cannot be implicitly casted to type 'bool'"); cases.add("assign unreachable", - \\extern fn f() { + \\export fn f() { \\ const a = return; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: unreachable code"); cases.add("unreachable variable", - \\extern fn f() { + \\export fn f() { \\ const a: noreturn = {}; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:14: error: variable of type 'noreturn' not allowed"); cases.add("unreachable parameter", \\fn f(a: noreturn) {} - \\comptime {@export("entry", entry);} - \\extern fn entry() { f(); } + \\export fn entry() { f(); } , ".tmp_source.zig:1:9: error: parameter of type 'noreturn' not allowed"); cases.add("bad assignment target", - \\extern fn f() { + \\export fn f() { \\ 3 = 3; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:7: error: cannot assign to constant"); cases.add("assign to constant variable", - \\extern fn f() { + \\export fn f() { \\ const a = 3; \\ a = 4; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:7: error: cannot assign to constant"); cases.add("use of undeclared identifier", - \\extern fn f() { + \\export fn f() { \\ b = 3; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'"); cases.add("const is a statement, not an expression", - \\extern fn f() { + \\export fn f() { \\ (const a = 0); \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:6: error: invalid token: 'const'"); cases.add("array access of undeclared identifier", - \\extern fn f() { + \\export fn f() { \\ i[i] = i[i]; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'", ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'"); cases.add("array access of non array", - \\extern fn f() { + \\export fn f() { \\ var bad : bool = undefined; \\ bad[bad] = bad[bad]; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:8: error: array access of non-array type 'bool'", ".tmp_source.zig:3:19: error: array access of non-array type 'bool'"); cases.add("array access with non integer index", - \\extern fn f() { + \\export fn f() { \\ var array = "aoeu"; \\ var bad = false; \\ array[bad] = array[bad]; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'", ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'"); @@ -446,8 +356,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f() { \\ x = 1; \\} - \\extern fn entry() { f(); } - \\comptime {@export("entry", entry);} + \\export fn entry() { f(); } , ".tmp_source.zig:3:7: error: cannot assign to constant"); @@ -456,33 +365,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ const x : i32 = if (b) { 1 }; \\ const y = if (b) { i32(1) }; \\} - \\extern fn entry() { f(true); } - \\comptime {@export("entry", entry);} + \\export fn entry() { f(true); } , ".tmp_source.zig:2:30: error: integer value 1 cannot be implicitly casted to type 'void'", ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'"); cases.add("direct struct loop", \\const A = struct { a : A, }; - \\extern fn entry() -> usize { @sizeOf(A) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(A) } , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); cases.add("indirect struct loop", \\const A = struct { b : B, }; \\const B = struct { c : C, }; \\const C = struct { a : A, }; - \\extern fn entry() -> usize { @sizeOf(A) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(A) } , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); cases.add("invalid struct field", \\const A = struct { x : i32, }; - \\extern fn f() { + \\export fn f() { \\ var a : A = undefined; \\ a.foo = 1; \\ const y = a.bar; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'", ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'"); @@ -510,7 +415,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\extern fn f() { + \\export fn f() { \\ const a = A { \\ .z = 1, \\ .y = 2, @@ -518,7 +423,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ .z = 4, \\ }; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:11:9: error: duplicate field"); cases.add("missing field in struct value expression", @@ -527,7 +431,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\extern fn f() { + \\export fn f() { \\ // we want the error on the '{' not the 'A' because \\ // the A could be a complicated expression \\ const a = A { @@ -535,7 +439,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ .y = 2, \\ }; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:9:17: error: missing field: 'x'"); cases.add("invalid field in struct value expression", @@ -544,79 +447,69 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ y : i32, \\ z : i32, \\}; - \\extern fn f() { + \\export fn f() { \\ const a = A { \\ .z = 4, \\ .y = 2, \\ .foo = 42, \\ }; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'"); cases.add("invalid break expression", - \\extern fn f() { + \\export fn f() { \\ break; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: break expression outside loop"); cases.add("invalid continue expression", - \\extern fn f() { + \\export fn f() { \\ continue; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: continue expression outside loop"); cases.add("invalid maybe type", - \\extern fn f() { + \\export fn f() { \\ if (true) |x| { } \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:9: error: expected nullable type, found 'bool'"); cases.add("cast unreachable", \\fn f() -> i32 { \\ i32(return 1) \\} - \\extern fn entry() { _ = f(); } - \\comptime {@export("entry", entry);} + \\export fn entry() { _ = f(); } , ".tmp_source.zig:2:8: error: unreachable code"); cases.add("invalid builtin fn", \\fn f() -> @bogus(foo) { \\} - \\extern fn entry() { _ = f(); } - \\comptime {@export("entry", entry);} + \\export fn entry() { _ = f(); } , ".tmp_source.zig:1:11: error: invalid builtin function: 'bogus'"); cases.add("top level decl dependency loop", \\const a : @typeOf(b) = 0; \\const b : @typeOf(a) = 0; - \\extern fn entry() { + \\export fn entry() { \\ const c = a + b; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: 'a' depends on itself"); cases.add("noalias on non pointer param", \\fn f(noalias x: i32) {} - \\extern fn entry() { f(1234); } - \\comptime {@export("entry", entry);} + \\export fn entry() { f(1234); } , ".tmp_source.zig:1:6: error: noalias on non-pointer parameter"); cases.add("struct init syntax for array", \\const foo = []u16{.x = 1024,}; - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax"); cases.add("type variables must be constant", \\var foo = u8; - \\extern fn entry() -> foo { + \\export fn entry() -> foo { \\ return 1; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: variable of type 'type' must be constant"); @@ -628,10 +521,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ var Bar : i32 = undefined; \\} \\ - \\extern fn entry() { + \\export fn entry() { \\ f(1234); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:6: error: redefinition of 'Foo'", ".tmp_source.zig:1:1: note: previous definition is here", @@ -653,8 +545,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch"); cases.add("switch expression - duplicate enumeration prong", @@ -674,8 +565,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:13:15: error: duplicate switch value", ".tmp_source.zig:10:15: note: other value is here"); @@ -697,8 +587,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:13:15: error: duplicate switch value", ".tmp_source.zig:10:15: note: other value is here"); @@ -710,10 +599,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ else => true, \\ }; \\} - \\extern fn entry() { + \\export fn entry() { \\ f(1234); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:9: error: multiple else prongs in switch expression"); cases.add("switch expression - non exhaustive integer prongs", @@ -722,8 +610,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 0 => {}, \\ } \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:5: error: switch must handle all possibilities"); @@ -736,8 +623,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 206 ... 255 => 3, \\ } \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:6:9: error: duplicate switch value", ".tmp_source.zig:5:14: note: previous value is here"); @@ -749,16 +635,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\const y: u8 = 100; - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:5: error: else prong required when switching on type '&u8'"); cases.add("global variable initializer must be constant expression", \\extern fn foo() -> i32; \\const x = foo(); - \\extern fn entry() -> i32 { x } - \\comptime {@export("entry", entry);} + \\export fn entry() -> i32 { x } , ".tmp_source.zig:2:11: error: unable to evaluate constant expression"); cases.add("array concatenation with wrong type", @@ -766,8 +650,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const derp = usize(1234); \\const a = derp ++ "foo"; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'"); cases.add("non compile time array concatenation", @@ -775,14 +658,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ s ++ "foo" \\} \\var s: [10]u8 = undefined; - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:2:5: error: unable to evaluate constant expression"); cases.add("@cImport with bogus include", \\const c = @cImport(@cInclude("bogus.h")); - \\extern fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } , ".tmp_source.zig:1:11: error: C import failed", ".h:1:10: note: 'bogus.h' file not found"); @@ -790,20 +671,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const x = 3; \\const y = &x; \\fn foo() -> &const i32 { y } - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:3:26: error: expected type '&const i32', found '&const (integer literal)'"); cases.add("integer overflow error", \\const x : u8 = 300; - \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'"); cases.add("incompatible number literals", \\const x = 2 == 2.0; - \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'"); cases.add("missing function call param", @@ -829,15 +707,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ const result = members[index](); \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0"); cases.add("missing function name and param name", \\fn () {} \\fn f(i32) {} - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:1:1: error: missing function name", ".tmp_source.zig:2:6: error: missing parameter name"); @@ -847,20 +723,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn a() -> i32 {0} \\fn b() -> i32 {1} \\fn c() -> i32 {2} - \\extern fn entry() -> usize { @sizeOf(@typeOf(fns)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } , ".tmp_source.zig:1:21: error: expected type 'fn()', found 'fn() -> i32'"); cases.add("extern function pointer mismatch", \\const fns = [](fn(i32)->i32){ a, b, c }; \\pub fn a(x: i32) -> i32 {x + 0} \\pub fn b(x: i32) -> i32 {x + 1} - \\extern fn c(x: i32) -> i32 {x + 2} + \\export fn c(x: i32) -> i32 {x + 2} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(fns)) } - \\ - \\comptime {@export("entry", entry);} - \\comptime {@export("c", c);} + \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } , ".tmp_source.zig:1:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'"); @@ -868,16 +740,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const x : f64 = 1.0; \\const y : f32 = x; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'"); cases.add("colliding invalid top level functions", \\fn func() -> bogus {} \\fn func() -> bogus {} - \\extern fn entry() -> usize { @sizeOf(@typeOf(func)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(func)) } , ".tmp_source.zig:2:1: error: redefinition of 'func'", ".tmp_source.zig:1:14: error: use of undeclared identifier 'bogus'"); @@ -885,8 +755,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("bogus compile var", \\const x = @import("builtin").bogus; - \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } , ".tmp_source.zig:1:29: error: no member named 'bogus' in '"); @@ -897,8 +766,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\var global_var: usize = 1; \\fn get() -> usize { global_var } \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(Foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(Foo)) } , ".tmp_source.zig:5:21: error: unable to evaluate constant expression", ".tmp_source.zig:2:12: note: called from here", @@ -911,8 +779,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\}; \\const x = Foo {.field = 1} + Foo {.field = 2}; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } , ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'"); @@ -922,14 +789,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const int_x = u32(1) / u32(0); \\const float_x = f32(1.0) / f32(0.0); \\ - \\extern fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } - \\extern fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } - \\extern fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } - \\extern fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } - \\comptime {@export("entry1", entry1);} - \\comptime {@export("entry2", entry2);} - \\comptime {@export("entry3", entry3);} - \\comptime {@export("entry4", entry4);} + \\export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } + \\export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } + \\export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } + \\export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } , ".tmp_source.zig:1:21: error: division by zero is undefined", ".tmp_source.zig:2:25: error: division by zero is undefined", @@ -941,16 +804,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const foo = "a \\b"; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:1:13: error: newline not allowed in string literal"); cases.add("invalid comparison for function pointers", \\fn foo() {} \\const invalid = foo > foo; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(invalid)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(invalid)) } , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn()'"); cases.add("generic function instance with non-constant expression", @@ -959,18 +820,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return foo(a, b); \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(test1)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(test1)) } , ".tmp_source.zig:3:16: error: unable to evaluate constant expression"); cases.add("goto jumping into block", - \\extern fn f() { + \\export fn f() { \\ { \\a_label: \\ } \\ goto a_label; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:5:5: error: no label in scope named 'a_label'"); cases.add("goto jumping past a defer", @@ -981,23 +840,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\fn derp(){} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:2:12: error: no label in scope named 'label'"); cases.add("assign null to non-nullable pointer", \\const a: &u8 = null; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'"); cases.add("indexing an array of size zero", \\const array = []u8{}; - \\extern fn foo() { + \\export fn foo() { \\ const pointer = &array[0]; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:27: error: index 0 outside array of size 0"); cases.add("compile time division by zero", @@ -1006,8 +862,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ 1 / x \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:3:7: error: division by zero is undefined", ".tmp_source.zig:1:14: note: called from here"); @@ -1015,8 +870,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("branch on undefined value", \\const x = if (undefined) true else false; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(x)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } , ".tmp_source.zig:1:15: error: use of undefined value"); @@ -1026,8 +880,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return fibbonaci(x - 1) + fibbonaci(x - 2); \\} \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } , ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches", ".tmp_source.zig:3:21: note: called from here"); @@ -1035,8 +888,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("@embedFile with bogus file", \\const resource = @embedFile("bogus.txt"); \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(resource)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(resource)) } , ".tmp_source.zig:1:29: error: unable to find '", "bogus.txt'"); cases.add("non-const expression in struct literal outside function", @@ -1046,8 +898,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const a = Foo {.x = get_it()}; \\extern fn get_it() -> i32; \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:4:21: error: unable to evaluate constant expression"); cases.add("non-const expression function call with struct return value outside function", @@ -1061,20 +912,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\var global_side_effect = false; \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:6:24: error: unable to evaluate constant expression", ".tmp_source.zig:4:17: note: called from here"); cases.add("undeclared identifier error should mark fn as impure", - \\extern fn foo() { + \\export fn foo() { \\ test_a_thing(); \\} \\fn test_a_thing() { \\ bad_fn_call(); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:5: error: use of undeclared identifier 'bad_fn_call'"); cases.add("illegal comparison of types", @@ -1089,16 +938,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ *a == *b \\} \\ - \\extern fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } - \\extern fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } - \\comptime {@export("entry1", entry1);} - \\comptime {@export("entry2", entry2);} + \\export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } + \\export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } , ".tmp_source.zig:2:7: error: operator not allowed for type '[]u8'", ".tmp_source.zig:9:8: error: operator not allowed for type 'EnumWithData'"); cases.add("non-const switch number literal", - \\extern fn foo() { + \\export fn foo() { \\ const x = switch (bar()) { \\ 1, 2 => 1, \\ 3, 4 => 2, @@ -1108,25 +955,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar() -> i32 { \\ 2 \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: unable to infer expression type"); cases.add("atomic orderings of cmpxchg - failure stricter than success", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\extern fn f() { + \\export fn f() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {} \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success"); cases.add("atomic orderings of cmpxchg - success Monotonic or stricter", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\extern fn f() { + \\export fn f() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {} \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:4:49: error: success atomic ordering must be Monotonic or stricter"); cases.add("negation overflow in function evaluation", @@ -1135,8 +979,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ -x \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:3:5: error: negation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1147,8 +990,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a + b \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1160,8 +1002,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a - b \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1172,8 +1013,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ a * b \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(y)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } , ".tmp_source.zig:3:7: error: operation caused overflow", ".tmp_source.zig:1:14: note: called from here"); @@ -1184,35 +1024,40 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ @truncate(i8, x) \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:3:19: error: expected signed integer type, found 'u32'"); cases.add("%return in function with non error return type", - \\extern fn f() { + \\export fn f() { \\ %return something(); \\} \\fn something() -> %void { } - \\comptime {@export("f", f);} , ".tmp_source.zig:2:5: error: expected type 'void', found 'error'"); + cases.add("wrong return type for main", + \\pub fn main() { } + , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); + + cases.add("double ?? on main return value", + \\pub fn main() -> ??void { + \\} + , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); + cases.add("invalid pointer for var type", \\extern fn ext() -> usize; \\var bytes: [ext()]u8 = undefined; - \\extern fn f() { + \\export fn f() { \\ for (bytes) |*b, i| { \\ *b = u8(i); \\ } \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:2:13: error: unable to evaluate constant expression"); cases.add("export function with comptime parameter", - \\extern fn foo(comptime x: i32, y: i32) -> i32{ + \\export fn foo(comptime x: i32, y: i32) -> i32{ \\ x + y \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); cases.add("extern function with comptime parameter", @@ -1220,16 +1065,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f() -> i32 { \\ foo(1, 2) \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:1:15: error: comptime parameter not allowed in function with calling convention 'ccc'"); cases.add("convert fixed size array to slice with invalid size", - \\extern fn f() { + \\export fn f() { \\ var array: [5]u8 = undefined; \\ var foo = ([]const u32)(array)[0]; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:28: error: unable to convert [5]u8 to []const u32: size mismatch"); cases.add("non-pure function returns type", @@ -1247,11 +1090,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\extern fn function_with_return_type_type() { + \\export fn function_with_return_type_type() { \\ var list: List(i32) = undefined; \\ list.length = 10; \\} - \\comptime {@export("function_with_return_type_type", function_with_return_type_type);} , ".tmp_source.zig:3:7: error: unable to evaluate constant expression", ".tmp_source.zig:16:19: note: called from here"); @@ -1260,8 +1102,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn f(m: []const u8) { \\ m.copy(u8, self[0..], m); \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'"); cases.add("wrong number of arguments for method fn call", @@ -1272,24 +1113,21 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ \\ foo.method(1, 2); \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(f)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3"); cases.add("assign through constant pointer", - \\extern fn f() { + \\export fn f() { \\ var cstr = c"Hat"; \\ cstr[0] = 'W'; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:11: error: cannot assign to constant"); cases.add("assign through constant slice", - \\extern fn f() { + \\export fn f() { \\ var cstr: []const u8 = "Hat"; \\ cstr[0] = 'W'; \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:3:11: error: cannot assign to constant"); cases.add("main function with bogus args type", @@ -1300,8 +1138,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn foo(blah: []u8) { \\ for (blah) { } \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:5: error: for loop expression missing element parameter"); cases.add("misspelled type with pointer only reference", @@ -1334,8 +1171,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} }; \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'"); cases.add("method call with first arg type primitive", @@ -1349,12 +1185,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\}; \\ - \\extern fn f() { + \\export fn f() { \\ const derp = Foo.init(3); \\ \\ derp.init(); \\} - \\comptime {@export("f", f);} , ".tmp_source.zig:14:5: error: expected type 'i32', found '&const Foo'"); cases.add("method call with first arg type wrong container", @@ -1378,11 +1213,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ field: i32, \\}; \\ - \\extern fn foo() { + \\export fn foo() { \\ var x = List.init(&global_allocator); \\ x.init(); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:23:5: error: expected type '&Allocator', found '&List'"); cases.add("binary not on number literal", @@ -1390,18 +1224,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT; \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1); \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'"); cases.addCase({ const tc = cases.create("multiple files with private function error", \\const foo = @import("foo.zig"); \\ - \\extern fn callPrivFunction() { + \\export fn callPrivFunction() { \\ foo.privateFunction(); \\} - \\comptime {@export("callPrivFunction", callPrivFunction);} , ".tmp_source.zig:4:8: error: 'privateFunction' is private", "foo.zig:1:1: note: declared here"); @@ -1417,19 +1249,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const zero: i32 = 0; \\const a = zero{1}; \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(a)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } , ".tmp_source.zig:2:11: error: expected type, found 'i32'"); cases.add("assign to constant field", \\const Foo = struct { \\ field: i32, \\}; - \\extern fn derp() { + \\export fn derp() { \\ const f = Foo {.field = 1234,}; \\ f.field = 0; \\} - \\comptime {@export("derp", derp);} , ".tmp_source.zig:6:13: error: cannot assign to constant"); cases.add("return from defer expression", @@ -1447,8 +1277,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return 0; \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } , ".tmp_source.zig:4:11: error: cannot return from defer expression"); cases.add("attempt to access var args out of bounds", @@ -1460,8 +1289,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ add(i32(1234)) \\} \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:19: error: index 1 outside argument list of size 1", ".tmp_source.zig:6:8: note: called from here"); @@ -1479,31 +1307,27 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ add(1, 2, 3, 4) \\} \\ - \\comptime {@export("entry", entry);} - \\extern fn entry() -> usize { @sizeOf(@typeOf(bar)) } + \\export fn entry() -> usize { @sizeOf(@typeOf(bar)) } , ".tmp_source.zig:10:9: error: parameter of type '(integer literal)' requires comptime"); cases.add("assign too big number to u16", - \\extern fn foo() { + \\export fn foo() { \\ var vga_mem: u16 = 0xB8000; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'"); cases.add("global variable alignment non power of 2", \\const some_data: [100]u8 align(3) = undefined; - \\extern fn entry() -> usize { @sizeOf(@typeOf(some_data)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(some_data)) } , ".tmp_source.zig:1:32: error: alignment value 3 is not a power of 2"); cases.add("function alignment non power of 2", \\extern fn foo() align(3); - \\extern fn entry() { foo() } - \\comptime {@export("entry", entry);} + \\export fn entry() { foo() } , ".tmp_source.zig:1:23: error: alignment value 3 is not a power of 2"); cases.add("compile log", - \\extern fn foo() { + \\export fn foo() { \\ comptime bar(12, "hi"); \\} \\fn bar(a: i32, b: []const u8) { @@ -1511,7 +1335,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ @compileLog("a", a, "b", b); \\ @compileLog("end"); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:5: error: found compile log statement", ".tmp_source.zig:2:17: note: called from here", @@ -1535,8 +1358,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return *x; \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:8:26: error: expected type '&const u3', found '&align(1:3:6) const u3'"); cases.add("referring to a struct that is invalid", @@ -1544,20 +1366,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Type: u8, \\}; \\ - \\extern fn foo() { + \\export fn foo() { \\ comptime assert(@sizeOf(UsbDeviceRequest) == 0x8); \\} \\ \\fn assert(ok: bool) { \\ if (!ok) unreachable; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:10:14: error: unable to evaluate constant expression", ".tmp_source.zig:6:20: note: called from here"); cases.add("control flow uses comptime var at runtime", - \\extern fn foo() { + \\export fn foo() { \\ comptime var i = 0; \\ while (i < 5) : (i += 1) { \\ bar(); @@ -1565,61 +1386,53 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} \\ \\fn bar() { } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: control flow attempts to use compile-time variable at runtime", ".tmp_source.zig:3:24: note: compile-time variable assigned here"); cases.add("ignored return value", - \\extern fn foo() { + \\export fn foo() { \\ bar(); \\} \\fn bar() -> i32 { 0 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:8: error: expression value is ignored"); cases.add("ignored assert-err-ok return value", - \\extern fn foo() { + \\export fn foo() { \\ %%bar(); \\} \\fn bar() -> %i32 { 0 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored statement value", - \\extern fn foo() { + \\export fn foo() { \\ 1; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored comptime statement value", - \\extern fn foo() { + \\export fn foo() { \\ comptime {1;} \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expression value is ignored"); cases.add("ignored comptime value", - \\extern fn foo() { + \\export fn foo() { \\ comptime 1; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:5: error: expression value is ignored"); cases.add("ignored defered statement value", - \\extern fn foo() { + \\export fn foo() { \\ defer {1;} \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:12: error: expression value is ignored"); cases.add("ignored defered statement value", - \\extern fn foo() { + \\export fn foo() { \\ defer bar(); \\} \\fn bar() -> %i32 { 0 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:14: error: expression value is ignored"); cases.add("dereference an array", @@ -1630,8 +1443,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return (*out)[0..1]; \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(pass)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(pass)) } , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'"); cases.add("pass const ptr to mutable ptr fn", @@ -1644,31 +1456,46 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ return true; \\} \\ - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'"); + cases.addCase({ + const tc = cases.create("export collision", + \\const foo = @import("foo.zig"); + \\ + \\export fn bar() -> usize { + \\ return foo.baz; + \\} + , + "foo.zig:1:8: error: exported symbol collision: 'bar'", + ".tmp_source.zig:3:8: note: other symbol here"); + + tc.addSourceFile("foo.zig", + \\export fn bar() {} + \\pub const baz = 1234; + ); + + tc + }); + cases.add("pass non-copyable type by value to function", \\const Point = struct { x: i32, y: i32, }; \\fn foo(p: Point) { } - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value"); cases.add("implicit cast from array to mutable slice", \\var global_array: [10]i32 = undefined; \\fn foo(param: []i32) {} - \\extern fn entry() { + \\export fn entry() { \\ foo(global_array); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'"); cases.add("ptrcast to non-pointer", - \\extern fn entry(a: &i32) -> usize { + \\export fn entry(a: &i32) -> usize { \\ return @ptrCast(usize, a); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'"); cases.add("too many error values to cast to small integer", @@ -1677,8 +1504,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn foo(e: error) -> u2 { \\ return u2(e); \\} - \\extern fn entry() -> usize { @sizeOf(@typeOf(foo)) } - \\comptime {@export("entry", entry);} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'"); cases.add("asm at compile time", @@ -1697,46 +1523,41 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("invalid member of builtin enum", \\const builtin = @import("builtin"); - \\extern fn entry() { + \\export fn entry() { \\ const foo = builtin.Arch.x86; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:29: error: container 'Arch' has no member called 'x86'"); cases.add("int to ptr of 0 bits", - \\extern fn foo() { + \\export fn foo() { \\ var x: usize = 0x1000; \\ var y: &void = @intToPtr(&void, x); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:31: error: type '&void' has 0 bits and cannot store information"); cases.add("@fieldParentPtr - non struct", \\const Foo = i32; - \\extern fn foo(a: &i32) -> &Foo { + \\export fn foo(a: &i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:28: error: expected struct type, found 'i32'"); cases.add("@fieldParentPtr - bad field name", \\const Foo = struct { \\ derp: i32, \\}; - \\extern fn foo(a: &i32) -> &Foo { + \\export fn foo(a: &i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:33: error: struct 'Foo' has no field 'a'"); cases.add("@fieldParentPtr - field pointer is not pointer", \\const Foo = struct { \\ a: i32, \\}; - \\extern fn foo(a: i32) -> &Foo { + \\export fn foo(a: i32) -> &Foo { \\ return @fieldParentPtr(Foo, "a", a); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:38: error: expected pointer, found 'i32'"); cases.add("@fieldParentPtr - comptime field ptr not based on struct", @@ -1766,20 +1587,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("@offsetOf - non struct", \\const Foo = i32; - \\extern fn foo() -> usize { + \\export fn foo() -> usize { \\ return @offsetOf(Foo, "a"); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:22: error: expected struct type, found 'i32'"); cases.add("@offsetOf - bad field name", \\const Foo = struct { \\ derp: i32, \\}; - \\extern fn foo() -> usize { + \\export fn foo() -> usize { \\ return @offsetOf(Foo, "a"); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'"); cases.addExe("missing main fn in executable", @@ -1792,22 +1611,44 @@ pub fn addCases(cases: &tests.CompileErrorContext) { "error: 'main' is private", ".tmp_source.zig:1:1: note: declared here"); + cases.add("setting a section on an extern variable", + \\extern var foo: i32 section(".text2"); + \\export fn entry() -> i32 { + \\ return foo; + \\} + , + ".tmp_source.zig:1:29: error: cannot set section of external variable 'foo'"); + + cases.add("setting a section on a local variable", + \\export fn entry() -> i32 { + \\ var foo: i32 section(".text2") = 1234; + \\ return foo; + \\} + , + ".tmp_source.zig:2:26: error: cannot set section of local variable 'foo'"); + + cases.add("setting a section on an extern fn", + \\extern fn foo() section(".text2"); + \\export fn entry() { + \\ foo(); + \\} + , + ".tmp_source.zig:1:25: error: cannot set section of external function 'foo'"); + cases.add("returning address of local variable - simple", - \\extern fn foo() -> &i32 { + \\export fn foo() -> &i32 { \\ var a: i32 = undefined; \\ return &a; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:13: error: function returns address of local variable"); cases.add("returning address of local variable - phi", - \\extern fn foo(c: bool) -> &i32 { + \\export fn foo(c: bool) -> &i32 { \\ var a: i32 = undefined; \\ var b: i32 = undefined; \\ return if (c) &a else &b; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:12: error: function returns address of local variable"); @@ -1836,61 +1677,55 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:5:9: note: previous definition is here"); cases.add("while expected bool, got nullable", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) {} \\} \\fn bar() -> ?i32 { 1 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected type 'bool', found '?i32'"); cases.add("while expected bool, got error union", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) {} \\} \\fn bar() -> %i32 { 1 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected type 'bool', found '%i32'"); cases.add("while expected nullable, got bool", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) |x| {} \\} \\fn bar() -> bool { true } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'"); cases.add("while expected nullable, got error union", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) |x| {} \\} \\fn bar() -> %i32 { 1 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected nullable type, found '%i32'"); cases.add("while expected error union, got bool", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) |x| {} else |err| {} \\} \\fn bar() -> bool { true } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected error union type, found 'bool'"); cases.add("while expected error union, got nullable", - \\extern fn foo() { + \\export fn foo() { \\ while (bar()) |x| {} else |err| {} \\} \\fn bar() -> ?i32 { 1 } - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:15: error: expected error union type, found '?i32'"); cases.add("inline fn calls itself indirectly", - \\extern fn foo() { + \\export fn foo() { \\ bar(); \\} \\inline fn bar() { @@ -1902,33 +1737,29 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ quux(); \\} \\extern fn quux(); - \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:8: error: unable to inline function"); cases.add("save reference to inline function", - \\extern fn foo() { + \\export fn foo() { \\ quux(@ptrToInt(bar)); \\} \\inline fn bar() { } \\extern fn quux(usize); - \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:8: error: unable to inline function"); cases.add("signed integer division", - \\extern fn foo(a: i32, b: i32) -> i32 { + \\export fn foo(a: i32, b: i32) -> i32 { \\ a / b \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:7: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact"); cases.add("signed integer remainder division", - \\extern fn foo(a: i32, b: i32) -> i32 { + \\export fn foo(a: i32, b: i32) -> i32 { \\ a % b \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:7: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod"); @@ -1967,65 +1798,59 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:3:20: error: cast from 'u16' to 'u8' truncates bits"); cases.add("@setDebugSafety twice for same scope", - \\extern fn foo() { + \\export fn foo() { \\ @setDebugSafety(this, false); \\ @setDebugSafety(this, false); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: debug safety set twice for same scope", ".tmp_source.zig:2:5: note: first set here"); cases.add("@setFloatMode twice for same scope", - \\extern fn foo() { + \\export fn foo() { \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:5: error: float mode set twice for same scope", ".tmp_source.zig:2:5: note: first set here"); cases.add("array access of type", - \\extern fn foo() { + \\export fn foo() { \\ var b: u8[40] = undefined; \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:2:14: error: array access of non-array type 'type'"); cases.add("cannot break out of defer expression", - \\extern fn foo() { + \\export fn foo() { \\ while (true) { \\ defer { \\ break; \\ } \\ } \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:13: error: cannot break out of defer expression"); cases.add("cannot continue out of defer expression", - \\extern fn foo() { + \\export fn foo() { \\ while (true) { \\ defer { \\ continue; \\ } \\ } \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:4:13: error: cannot continue out of defer expression"); cases.add("cannot goto out of defer expression", - \\extern fn foo() { + \\export fn foo() { \\ defer { \\ goto label; \\ }; \\label: \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:3:9: error: cannot goto out of defer expression"); @@ -2059,10 +1884,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const bar = baz + foo; \\const baz = 1; \\ - \\extern fn entry() -> i32 { + \\export fn entry() -> i32 { \\ return bar; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: aoeu", ".tmp_source.zig:3:19: note: referenced here", @@ -2075,10 +1899,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ \\var foo: Foo = undefined; \\ - \\extern fn entry() -> usize { + \\export fn entry() -> usize { \\ return @sizeOf(@typeOf(foo.x)); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: struct 'Foo' contains itself"); @@ -2097,18 +1920,16 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:15: error: float literal out of range of any type"); cases.add("explicit cast float literal to integer when there is a fraction component", - \\extern fn entry() -> i32 { + \\export fn entry() -> i32 { \\ i32(12.34) \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:9: error: fractional component prevents float value 12.340000 from being casted to type 'i32'"); cases.add("non pointer given to @ptrToInt", - \\extern fn entry(x: i32) -> usize { + \\export fn entry(x: i32) -> usize { \\ @ptrToInt(x) \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:15: error: expected pointer, found 'i32'"); @@ -2127,27 +1948,24 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:15: error: exact shift shifted out 1 bits"); cases.add("shifting without int type or comptime known", - \\extern fn entry(x: u8) -> u8 { + \\export fn entry(x: u8) -> u8 { \\ return 0x11 << x; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:17: error: LHS of shift must be an integer type, or RHS must be compile-time known"); cases.add("shifting RHS is log2 of LHS int bit width", - \\extern fn entry(x: u8, y: u8) -> u8 { + \\export fn entry(x: u8, y: u8) -> u8 { \\ return x << y; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:17: error: expected type 'u3', found 'u8'"); cases.add("globally shadowing a primitive type", \\const u16 = @intType(false, 8); - \\extern fn entry() { + \\export fn entry() { \\ const a: u16 = 300; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:1: error: declaration shadows type 'u16'"); @@ -2157,7 +1975,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ b: u32, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var foo = Foo { .a = 1, .b = 10 }; \\ bar(&foo.b); \\} @@ -2165,7 +1983,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: &u32) { \\ *x += 1; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:13: error: expected type '&u32', found '&align(1) u32'"); @@ -2175,7 +1992,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ b: u32, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var foo = Foo { .a = 1, .b = 10 }; \\ foo.b += 1; \\ bar((&foo.b)[0..1]); @@ -2184,61 +2001,55 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: []u32) { \\ x[0] += 1; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:17: error: expected type '[]u32', found '[]align(1) u32'"); cases.add("increase pointer alignment in @ptrCast", - \\extern fn entry() -> u32 { + \\export fn entry() -> u32 { \\ var bytes: [4]u8 = []u8{0x01, 0x02, 0x03, 0x04}; \\ const ptr = @ptrCast(&u32, &bytes[0]); \\ return *ptr; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:17: error: cast increases pointer alignment", ".tmp_source.zig:3:38: note: '&u8' has alignment 1", ".tmp_source.zig:3:27: note: '&u32' has alignment 4"); cases.add("increase pointer alignment in slice resize", - \\extern fn entry() -> u32 { + \\export fn entry() -> u32 { \\ var bytes = []u8{0x01, 0x02, 0x03, 0x04}; \\ return ([]u32)(bytes[0..])[0]; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:19: error: cast increases pointer alignment", ".tmp_source.zig:3:19: note: '[]u8' has alignment 1", ".tmp_source.zig:3:19: note: '[]u32' has alignment 4"); cases.add("@alignCast expects pointer or slice", - \\extern fn entry() { + \\export fn entry() { \\ @alignCast(4, u32(3)) \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:22: error: expected pointer or slice, found 'u32'"); cases.add("passing an under-aligned function pointer", - \\extern fn entry() { + \\export fn entry() { \\ testImplicitlyDecreaseFnAlign(alignedSmall, 1234); \\} \\fn testImplicitlyDecreaseFnAlign(ptr: fn () align(8) -> i32, answer: i32) { \\ if (ptr() != answer) unreachable; \\} \\fn alignedSmall() align(4) -> i32 { 1234 } - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:35: error: expected type 'fn() align(8) -> i32', found 'fn() align(4) -> i32'"); cases.add("passing a not-aligned-enough pointer to cmpxchg", \\const AtomicOrder = @import("builtin").AtomicOrder; - \\extern fn entry() -> bool { + \\export fn entry() -> bool { \\ var x: i32 align(1) = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) {} \\ return x == 5678; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:23: error: expected pointer alignment of at least 4, found 1"); @@ -2264,18 +2075,17 @@ pub fn addCases(cases: &tests.CompileErrorContext) { cases.add("wrong pointer implicitly casted to pointer to @OpaqueType()", \\const Derp = @OpaqueType(); \\extern fn bar(d: &Derp); - \\extern fn foo() { + \\export fn foo() { \\ const x = u8(1); \\ bar(@ptrCast(&c_void, &x)); \\} - \\comptime {@export("foo", foo);} , ".tmp_source.zig:5:9: error: expected type '&Derp', found '&c_void'"); cases.add("non-const variables of things that require const variables", \\const Opaque = @OpaqueType(); \\ - \\extern fn entry(opaque: &Opaque) { + \\export fn entry(opaque: &Opaque) { \\ var m2 = &2; \\ const y: u32 = *m2; \\ @@ -2295,7 +2105,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = struct { \\ fn bar(self: &const Foo) {} \\}; - \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:4: error: variable of type '&const (integer literal)' must be const or comptime", ".tmp_source.zig:7:4: error: variable of type '(undefined)' must be const or comptime", @@ -2310,14 +2119,21 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:17:4: error: unreachable code"); cases.add("wrong types given to atomic order args in cmpxchg", - \\extern fn entry() { + \\export fn entry() { \\ var x: i32 = 1234; \\ while (!@cmpxchg(&x, 1234, 5678, u32(1234), u32(1234))) {} \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:41: error: expected type 'AtomicOrder', found 'u32'"); + cases.add("wrong types given to @export", + \\extern fn entry() { } + \\comptime { + \\ @export("entry", entry, u32(1234)); + \\} + , + ".tmp_source.zig:3:32: error: expected type 'GlobalLinkage', found 'u32'"); + cases.add("struct with invalid field", \\const std = @import("std"); \\const Allocator = std.mem.Allocator; @@ -2336,13 +2152,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ }, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ const a = MdNode.Header { \\ .text = MdText.init(&std.debug.global_allocator), \\ .weight = HeaderWeight.H1, \\ }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'"); @@ -2354,39 +2169,35 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:5: error: @setAlignStack outside function"); cases.add("@setAlignStack in naked function", - \\nakedcc fn entry() { + \\export nakedcc fn entry() { \\ @setAlignStack(16); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: @setAlignStack in naked function"); cases.add("@setAlignStack in inline function", - \\extern fn entry() { + \\export fn entry() { \\ foo(); \\} \\inline fn foo() { \\ @setAlignStack(16); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:5: error: @setAlignStack in inline function"); cases.add("@setAlignStack set twice", - \\extern fn entry() { + \\export fn entry() { \\ @setAlignStack(16); \\ @setAlignStack(16); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:3:5: error: alignstack set twice", ".tmp_source.zig:2:5: note: first set here"); cases.add("@setAlignStack too big", - \\extern fn entry() { + \\export fn entry() { \\ @setAlignStack(511 + 1); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: attempt to @setAlignStack(512); maximum is 256"); @@ -2417,7 +2228,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ LinkLibC, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ const tests = []TestCase { \\ Free("001"), \\ Free("002"), @@ -2432,14 +2243,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\ } \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:37:16: error: cannot store runtime value in compile time variable"); cases.add("field access of opaque type", \\const MyType = @OpaqueType(); \\ - \\extern fn entry() -> bool { + \\export fn entry() -> bool { \\ var x: i32 = 1; \\ return bar(@ptrCast(&MyType, &x)); \\} @@ -2447,7 +2257,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\fn bar(x: &MyType) -> bool { \\ return x.blah; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:13: error: type '&MyType' does not support field access"); @@ -2551,11 +2360,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members"); cases.add("calling var args extern function, passing array instead of pointer", - \\extern fn entry() { + \\export fn entry() { \\ foo("hello"); \\} \\pub extern fn foo(format: &const u8, ...); - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:9: error: expected type '&const u8', found '[5]u8'"); @@ -2570,10 +2378,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ } \\} \\ - \\extern fn entry() { + \\export fn entry() { \\ var allocator: ContextAllocator = undefined; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:4:25: error: aoeu", ".tmp_source.zig:1:36: note: called from here", @@ -2588,10 +2395,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Five, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var x = Small.One; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:20: error: 'u2' too small to hold all bits; must be at least 'u3'"); @@ -2602,10 +2408,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Three, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var x = Small.One; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:20: error: expected integer, found 'f32'"); @@ -2617,10 +2422,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var x: u2 = Small.Two; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'"); @@ -2632,10 +2436,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var x = u3(Small.Two); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'"); @@ -2647,11 +2450,10 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var y = u3(3); \\ var x = Small(y); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'"); @@ -2663,10 +2465,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ Four, \\}; \\ - \\extern fn entry() { + \\export fn entry() { \\ var y = Small.Two; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'"); @@ -2674,10 +2475,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const MultipleChoice = struct { \\ A: i32 = 20, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x: MultipleChoice = undefined; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:14: error: enums, not structs, support field assignment"); @@ -2685,29 +2485,26 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const MultipleChoice = union { \\ A: i32 = 20, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x: MultipleChoice = undefined; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:14: error: non-enum union field assignment", ".tmp_source.zig:1:24: note: consider 'union(enum)' here"); cases.add("enum with 0 fields", \\const Foo = enum {}; - \\extern fn entry() -> usize { + \\export fn entry() -> usize { \\ return @sizeOf(Foo); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: enums must have 1 or more fields"); cases.add("union with 0 fields", \\const Foo = union {}; - \\extern fn entry() -> usize { + \\export fn entry() -> usize { \\ return @sizeOf(Foo); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:13: error: unions must have 1 or more fields"); @@ -2719,10 +2516,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ D = 1000, \\ E = 60, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x = MultipleChoice.C; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:9: error: enum tag value 60 already taken", ".tmp_source.zig:4:9: note: other occurrence here"); @@ -2737,10 +2533,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ A: i32, \\ B: f64, \\}; - \\extern fn entry() -> usize { + \\export fn entry() -> usize { \\ return @sizeOf(Payload); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:17: error: enum field missing: 'C'", ".tmp_source.zig:4:5: note: declared here"); @@ -2749,10 +2544,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union { \\ A: i32, \\}; - \\extern fn entry() { + \\export fn entry() { \\ const x = @TagType(Foo); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:5:24: error: union 'Foo' has no tag", ".tmp_source.zig:1:13: note: consider 'union(enum)' here"); @@ -2761,10 +2555,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union(enum(f32)) { \\ A: i32, \\}; - \\extern fn entry() { + \\export fn entry() { \\ const x = @TagType(Foo); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'"); @@ -2772,10 +2565,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Foo = union(u32) { \\ A: i32, \\}; - \\extern fn entry() { + \\export fn entry() { \\ const x = @TagType(Foo); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'"); @@ -2787,10 +2579,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ D = 1000, \\ E = 60, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x = MultipleChoice { .C = {} }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:9: error: enum tag value 60 already taken", ".tmp_source.zig:4:9: note: other occurrence here"); @@ -2807,10 +2598,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ C: bool, \\ D: bool, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var a = Payload {.A = 1234}; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:10:5: error: enum field not found: 'D'", ".tmp_source.zig:1:16: note: enum declared here"); @@ -2821,10 +2611,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var b = Letter.B; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:8: error: structs and unions, not enums, support field types", ".tmp_source.zig:1:16: note: consider 'union(enum)' here"); @@ -2833,10 +2622,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Letter = struct { \\ A, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var a = Letter { .A = {} }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: struct field missing type"); @@ -2844,10 +2632,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\const Letter = extern union { \\ A, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var a = Letter { .A = {} }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:2:5: error: union field missing type"); @@ -2862,10 +2649,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var a = Payload { .A = { 1234 } }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:29: error: extern union does not support enum tag type"); @@ -2880,10 +2666,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var a = Payload { .A = { 1234 } }; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:29: error: packed union does not support enum tag type"); @@ -2893,7 +2678,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B: f64, \\ C: bool, \\}; - \\extern fn entry() { + \\export fn entry() { \\ const a = Payload { .A = { 1234 } }; \\ foo(a); \\} @@ -2903,7 +2688,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ else => unreachable, \\ } \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:11:13: error: switch on union which has no attached enum", ".tmp_source.zig:1:17: note: consider 'union(enum)' here"); @@ -2913,10 +2697,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ A = 10, \\ B = 11, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x = Foo(0); \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0", ".tmp_source.zig:1:13: note: 'Foo' declared here"); @@ -2928,10 +2711,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\extern fn entry() { + \\export fn entry() { \\ var x: Value = Letter.A; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'", ".tmp_source.zig:3:5: note: field 'A' declared here"); @@ -2943,36 +2725,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\ B, \\ C, \\}; - \\extern fn entry() { + \\export fn entry() { \\ foo(Letter.A); \\} \\fn foo(l: Letter) { \\ var x: Value = l; \\} - \\comptime {@export("entry", entry);} , ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields", ".tmp_source.zig:3:5: note: field 'A' has type 'i32'"); - - cases.addCase({ - const tc = cases.create("export collision", - \\const foo = @import("foo.zig"); - \\ - \\comptime {@export("bar", bar);} - \\extern fn bar() -> usize { - \\ return foo.baz; - \\} - , - "foo.zig:2:11: error: exported symbol collision: 'bar'", - ".tmp_source.zig:3:11: note: other symbol is here"); - - tc.addSourceFile("foo.zig", - \\extern fn bar() {} - \\comptime {@export("bar", bar);} - \\pub const baz = 1234; - ); - - tc - }); - } diff --git a/test/standalone/issue_339/test.zig b/test/standalone/issue_339/test.zig index a3058e58ed..c1faa015c6 100644 --- a/test/standalone/issue_339/test.zig +++ b/test/standalone/issue_339/test.zig @@ -2,9 +2,6 @@ pub fn panic(msg: []const u8) -> noreturn { @breakpoint(); while (true) {} } fn bar() -> %void {} -comptime { - @export("foo", foo); -} -extern fn foo() { +export fn foo() { %%bar(); } diff --git a/test/translate_c.zig b/test/translate_c.zig index 01f6622a71..aff2140f8d 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -26,7 +26,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a < 0 ? -a : a; \\} , - \\pub fn abs(a: c_int) -> c_int { + \\export fn abs(a: c_int) -> c_int { \\ return if (a < 0) -a else a; \\} ); @@ -325,12 +325,12 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\pub fn foo1(_arg_a: c_uint) -> c_uint { + \\pub export fn foo1(_arg_a: c_uint) -> c_uint { \\ var a = _arg_a; \\ a +%= 1; \\ return a; \\} - \\pub fn foo2(_arg_a: c_int) -> c_int { + \\pub export fn foo2(_arg_a: c_int) -> c_int { \\ var a = _arg_a; \\ a += 1; \\ return a; @@ -346,7 +346,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return i; \\} , - \\pub fn log2(_arg_a: c_uint) -> c_int { + \\pub export fn log2(_arg_a: c_uint) -> c_int { \\ var a = _arg_a; \\ var i: c_int = 0; \\ while (a > c_uint(0)) { @@ -367,7 +367,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\pub fn max(a: c_int, b: c_int) -> c_int { + \\pub export fn max(a: c_int, b: c_int) -> c_int { \\ if (a < b) return b; \\ if (a < b) return b else return a; \\} @@ -382,7 +382,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\pub fn max(a: c_int, b: c_int) -> c_int { + \\pub export fn max(a: c_int, b: c_int) -> c_int { \\ if (a == b) return a; \\ if (a != b) return b; \\ return a; @@ -407,7 +407,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = a % b; \\} , - \\pub fn s(a: c_int, b: c_int) -> c_int { + \\pub export fn s(a: c_int, b: c_int) -> c_int { \\ var c: c_int; \\ c = (a + b); \\ c = (a - b); @@ -415,7 +415,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = @divTrunc(a, b); \\ c = @rem(a, b); \\} - \\pub fn u(a: c_uint, b: c_uint) -> c_uint { + \\pub export fn u(a: c_uint, b: c_uint) -> c_uint { \\ var c: c_uint; \\ c = (a +% b); \\ c = (a -% b); @@ -430,7 +430,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (a & b) ^ (a | b); \\} , - \\pub fn max(a: c_int, b: c_int) -> c_int { + \\pub export fn max(a: c_int, b: c_int) -> c_int { \\ return (a & b) ^ (a | b); \\} ); @@ -444,7 +444,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return a; \\} , - \\pub fn max(a: c_int, b: c_int) -> c_int { + \\pub export fn max(a: c_int, b: c_int) -> c_int { \\ if ((a < b) or (a == b)) return b; \\ if ((a >= b) and (a == b)) return a; \\ return a; @@ -458,7 +458,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a = tmp; \\} , - \\pub fn max(_arg_a: c_int) -> c_int { + \\pub export fn max(_arg_a: c_int) -> c_int { \\ var a = _arg_a; \\ var tmp: c_int; \\ tmp = a; @@ -472,7 +472,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ c = b = a; \\} , - \\pub fn max(a: c_int) { + \\pub export fn max(a: c_int) { \\ var b: c_int; \\ var c: c_int; \\ c = { @@ -493,7 +493,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return i; \\} , - \\pub fn log2(_arg_a: u32) -> c_int { + \\pub export fn log2(_arg_a: u32) -> c_int { \\ var a = _arg_a; \\ var i: c_int = 0; \\ while (a > c_uint(0)) { @@ -518,7 +518,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\void foo(void) { bar(); } , \\pub fn bar() {} - \\pub fn foo() { + \\pub export fn foo() { \\ bar(); \\} ); @@ -534,7 +534,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\pub const struct_Foo = extern struct { \\ field: c_int, \\}; - \\pub fn read_field(foo: ?&struct_Foo) -> c_int { + \\pub export fn read_field(foo: ?&struct_Foo) -> c_int { \\ return (??foo).field; \\} ); @@ -544,7 +544,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ ;;;;; \\} , - \\pub fn foo() {} + \\pub export fn foo() {} ); cases.add("undefined array global", @@ -560,7 +560,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\} , \\pub var array: [100]c_int = undefined; - \\pub fn foo(index: c_int) -> c_int { + \\pub export fn foo(index: c_int) -> c_int { \\ return array[index]; \\} ); @@ -571,7 +571,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (int)a; \\} , - \\pub fn float_to_int(a: f32) -> c_int { + \\pub export fn float_to_int(a: f32) -> c_int { \\ return c_int(a); \\} ); @@ -581,7 +581,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return x; \\} , - \\pub fn foo(x: ?&c_ushort) -> ?&c_void { + \\pub export fn foo(x: ?&c_ushort) -> ?&c_void { \\ return @ptrCast(?&c_void, x); \\} ); @@ -592,7 +592,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return sizeof(int); \\} , - \\pub fn size_of() -> usize { + \\pub export fn size_of() -> usize { \\ return @sizeOf(c_int); \\} ); @@ -602,7 +602,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return 0; \\} , - \\pub fn foo() -> ?&c_int { + \\pub export fn foo() -> ?&c_int { \\ return null; \\} ); @@ -612,7 +612,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return 1, 2; \\} , - \\pub fn foo() -> c_int { + \\pub export fn foo() -> c_int { \\ return { \\ _ = 1; \\ 2 @@ -625,7 +625,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ return (1 << 2) >> 1; \\} , - \\pub fn foo() -> c_int { + \\pub export fn foo() -> c_int { \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1); \\} ); @@ -643,7 +643,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a <<= (a <<= 1); \\} , - \\pub fn foo() { + \\pub export fn foo() { \\ var a: c_int = 0; \\ a += { \\ const _ref = &a; @@ -701,7 +701,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ a <<= (a <<= 1); \\} , - \\pub fn foo() { + \\pub export fn foo() { \\ var a: c_uint = c_uint(0); \\ a +%= { \\ const _ref = &a; @@ -771,7 +771,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ u = u--; \\} , - \\pub fn foo() { + \\pub export fn foo() { \\ var i: c_int = 0; \\ var u: c_uint = c_uint(0); \\ i += 1; @@ -819,7 +819,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ u = --u; \\} , - \\pub fn foo() { + \\pub export fn foo() { \\ var i: c_int = 0; \\ var u: c_uint = c_uint(0); \\ i += 1; @@ -862,7 +862,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ while (b != 0); \\} , - \\pub fn foo() { + \\pub export fn foo() { \\ var a: c_int = 2; \\ while (true) { \\ a -= 1; @@ -886,9 +886,9 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ baz(); \\} , - \\pub fn foo() {} - \\pub fn baz() {} - \\pub fn bar() { + \\pub export fn foo() {} + \\pub export fn baz() {} + \\pub export fn bar() { \\ var f: ?extern fn() = foo; \\ (??f)(); \\ (??f)(); @@ -901,7 +901,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ *x = 1; \\} , - \\pub fn foo(x: ?&c_int) { + \\pub export fn foo(x: ?&c_int) { \\ (*??x) = 1; \\} );