| author | |
| committer | |
| log | d3ebd428650748e60db70dd2171cc044855814b1 |
| tree | 877fd512be87b46adf73c8143d0c721e9d9849c0 |
| parent | 3b26e508638e96997aff3d5ef2c42a917bf86cc8 |
This commit makes it possible to obtain pointers to `extern` variables
at comptime.
- `ir_get_var_ptr` employs several checks to determine if the given
variable is eligible for obtaining its pointer at comptime. This
commit alters these checks to consider `extern` variables, which have
runtime values, as eligible.
- After this change, it's now possible for `render_const_val` to be
called for `extern` variables. This commit modifies
`render_const_val` to suppress the value generation for `extern`
variables.
- `do_code_gen` now creates `ZigValue::llvm_global` of `extern`
variables before iterating through module-level variables so that
other module-level variables can refer to them.
This solution is incomplete since there are several cases still
failing:
- `global_var.array[n..m]`
- `&global_var.array[i]`
- `&global_var.inner_struct.value`
- `&global_array[i]`
Closes #53498 files changed, 284 insertions(+), 47 deletions(-)
src/codegen.cpp+50-20| ... | @@ -7754,6 +7754,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n | ... | @@ -7754,6 +7754,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n |
| 7754 | } | 7754 | } |
| 7755 | 7755 | ||
| 7756 | static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name) { | 7756 | static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name) { |
| 7757 | if (const_val->special == ConstValSpecialRuntime) { | ||
| 7758 | // `const_val` refers to an extern variable. Don't generate an `LLVMValueRef` for | ||
| 7759 | // the variable. We shouldn't call `LLVMSetInitializer` on it either. | ||
| 7760 | assert(const_val->llvm_global); | ||
| 7761 | return; | ||
| 7762 | } | ||
| 7763 | |||
| 7757 | if (!const_val->llvm_value) | 7764 | if (!const_val->llvm_value) |
| 7758 | const_val->llvm_value = gen_const_val(g, const_val, name); | 7765 | const_val->llvm_value = gen_const_val(g, const_val, name); |
| 7759 | 7766 | ||
| ... | @@ -7762,6 +7769,13 @@ static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name) | ... | @@ -7762,6 +7769,13 @@ static void render_const_val(CodeGen *g, ZigValue *const_val, const char *name) |
| 7762 | } | 7769 | } |
| 7763 | 7770 | ||
| 7764 | static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name) { | 7771 | static void render_const_val_global(CodeGen *g, ZigValue *const_val, const char *name) { |
| 7772 | if (const_val->special == ConstValSpecialRuntime) { | ||
| 7773 | // `const_val` refers to an extern variable. `llvm_global` should already | ||
| 7774 | // have been created by an earlier codegen pass. | ||
| 7775 | assert(const_val->llvm_global); | ||
| 7776 | return; | ||
| 7777 | } | ||
| 7778 | |||
| 7765 | if (!const_val->llvm_global) { | 7779 | if (!const_val->llvm_global) { |
| 7766 | LLVMTypeRef type_ref = const_val->llvm_value ? | 7780 | LLVMTypeRef type_ref = const_val->llvm_value ? |
| 7767 | LLVMTypeOf(const_val->llvm_value) : get_llvm_type(g, const_val->type); | 7781 | LLVMTypeOf(const_val->llvm_value) : get_llvm_type(g, const_val->type); |
| ... | @@ -7891,6 +7905,39 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -7891,6 +7905,39 @@ static void do_code_gen(CodeGen *g) { |
| 7891 | 7905 | ||
| 7892 | generate_error_name_table(g); | 7906 | generate_error_name_table(g); |
| 7893 | 7907 | ||
| 7908 | // Create extern variables | ||
| 7909 | for (size_t i = 0; i < g->global_vars.length; i += 1) { | ||
| 7910 | TldVar *tld_var = g->global_vars.at(i); | ||
| 7911 | ZigVar *var = tld_var->var; | ||
| 7912 | |||
| 7913 | bool externally_initialized = var->decl_node->data.variable_declaration.expr == nullptr; | ||
| 7914 | if (!externally_initialized) { | ||
| 7915 | continue; | ||
| 7916 | } | ||
| 7917 | |||
| 7918 | assert(var->decl_node->data.variable_declaration.is_extern); | ||
| 7919 | const char *symbol_name = var->name; | ||
| 7920 | |||
| 7921 | LLVMValueRef global_value; | ||
| 7922 | LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, symbol_name); | ||
| 7923 | if (existing_llvm_var) { | ||
| 7924 | global_value = LLVMConstBitCast(existing_llvm_var, | ||
| 7925 | LLVMPointerType(get_llvm_type(g, var->var_type), 0)); | ||
| 7926 | } else { | ||
| 7927 | global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name); | ||
| 7928 | // TODO debug info for the extern variable | ||
| 7929 | |||
| 7930 | LLVMSetLinkage(global_value, LLVMExternalLinkage); | ||
| 7931 | maybe_import_dll(g, global_value, GlobalLinkageIdStrong); | ||
| 7932 | LLVMSetAlignment(global_value, var->align_bytes); | ||
| 7933 | LLVMSetGlobalConstant(global_value, var->gen_is_const); | ||
| 7934 | set_global_tls(g, var, global_value); | ||
| 7935 | } | ||
| 7936 | |||
| 7937 | var->value_ref = global_value; | ||
| 7938 | var->const_value->llvm_global = global_value; | ||
| 7939 | } | ||
| 7940 | |||
| 7894 | // Generate module level variables | 7941 | // Generate module level variables |
| 7895 | for (size_t i = 0; i < g->global_vars.length; i += 1) { | 7942 | for (size_t i = 0; i < g->global_vars.length; i += 1) { |
| 7896 | TldVar *tld_var = g->global_vars.at(i); | 7943 | TldVar *tld_var = g->global_vars.at(i); |
| ... | @@ -7956,28 +8003,12 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -7956,28 +8003,12 @@ static void do_code_gen(CodeGen *g) { |
| 7956 | linkage = global_export->linkage; | 8003 | linkage = global_export->linkage; |
| 7957 | } | 8004 | } |
| 7958 | 8005 | ||
| 7959 | LLVMValueRef global_value; | ||
| 7960 | bool externally_initialized = var->decl_node->data.variable_declaration.expr == nullptr; | 8006 | bool externally_initialized = var->decl_node->data.variable_declaration.expr == nullptr; |
| 7961 | if (externally_initialized) { | 8007 | if (!externally_initialized) { |
| 7962 | LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, symbol_name); | ||
| 7963 | if (existing_llvm_var) { | ||
| 7964 | global_value = LLVMConstBitCast(existing_llvm_var, | ||
| 7965 | LLVMPointerType(get_llvm_type(g, var->var_type), 0)); | ||
| 7966 | } else { | ||
| 7967 | global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name); | ||
| 7968 | // TODO debug info for the extern variable | ||
| 7969 | |||
| 7970 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); | ||
| 7971 | maybe_import_dll(g, global_value, GlobalLinkageIdStrong); | ||
| 7972 | LLVMSetAlignment(global_value, var->align_bytes); | ||
| 7973 | LLVMSetGlobalConstant(global_value, var->gen_is_const); | ||
| 7974 | set_global_tls(g, var, global_value); | ||
| 7975 | } | ||
| 7976 | } else { | ||
| 7977 | bool exported = (linkage != GlobalLinkageIdInternal); | 8008 | bool exported = (linkage != GlobalLinkageIdInternal); |
| 7978 | render_const_val(g, var->const_value, symbol_name); | 8009 | render_const_val(g, var->const_value, symbol_name); |
| 7979 | render_const_val_global(g, var->const_value, symbol_name); | 8010 | render_const_val_global(g, var->const_value, symbol_name); |
| 7980 | global_value = var->const_value->llvm_global; | 8011 | LLVMValueRef global_value = var->const_value->llvm_global; |
| 7981 | 8012 | ||
| 7982 | if (exported) { | 8013 | if (exported) { |
| 7983 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); | 8014 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); |
| ... | @@ -7997,10 +8028,9 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -7997,10 +8028,9 @@ static void do_code_gen(CodeGen *g) { |
| 7997 | 8028 | ||
| 7998 | LLVMSetGlobalConstant(global_value, var->gen_is_const); | 8029 | LLVMSetGlobalConstant(global_value, var->gen_is_const); |
| 7999 | set_global_tls(g, var, global_value); | 8030 | set_global_tls(g, var, global_value); |
| 8031 | var->value_ref = global_value; | ||
| 8000 | } | 8032 | } |
| 8001 | 8033 | ||
| 8002 | var->value_ref = global_value; | ||
| 8003 | |||
| 8004 | for (size_t export_i = 1; export_i < var->export_list.length; export_i += 1) { | 8034 | for (size_t export_i = 1; export_i < var->export_list.length; export_i += 1) { |
| 8005 | GlobalExport *global_export = &var->export_list.items[export_i]; | 8035 | GlobalExport *global_export = &var->export_list.items[export_i]; |
| 8006 | LLVMAddAlias(g->module, LLVMTypeOf(var->value_ref), var->value_ref, buf_ptr(&global_export->name)); | 8036 | LLVMAddAlias(g->module, LLVMTypeOf(var->value_ref), var->value_ref, buf_ptr(&global_export->name)); |
src/ir.cpp+34-27| ... | @@ -19894,30 +19894,34 @@ static IrInstGen *ir_get_var_ptr(IrAnalyze *ira, IrInst *source_instr, ZigVar *v | ... | @@ -19894,30 +19894,34 @@ static IrInstGen *ir_get_var_ptr(IrAnalyze *ira, IrInst *source_instr, ZigVar *v |
| 19894 | IrInstGen *result = ir_build_var_ptr_gen(ira, source_instr, var); | 19894 | IrInstGen *result = ir_build_var_ptr_gen(ira, source_instr, var); |
| 19895 | result->value->type = var_ptr_type; | 19895 | result->value->type = var_ptr_type; |
| 19896 | 19896 | ||
| 19897 | if (!linkage_makes_it_runtime && !var->is_thread_local && value_is_comptime(var->const_value)) { | 19897 | bool is_local_var = !var->decl_node->data.variable_declaration.is_extern && |
| 19898 | var->const_value->special == ConstValSpecialRuntime; | ||
| 19899 | |||
| 19900 | // The address of a thread-local variable can't be resolved even by a linker because | ||
| 19901 | // it's dependent on the current thread. The concept of current thread doesn't exist | ||
| 19902 | // at compile time, so even if we had a symbolic (i.e., relocatable) representation | ||
| 19903 | // of a pointer to a thread-local variable, there would be no ways to make use of it | ||
| 19904 | // in a meaningful way. | ||
| 19905 | // | ||
| 19906 | // The same goes for local variables - They are stored in a stack frame, whose | ||
| 19907 | // instance doesn't even exist at compile/link time. | ||
| 19908 | if (!var->is_thread_local && !is_local_var) { | ||
| 19898 | ZigValue *val = var->const_value; | 19909 | ZigValue *val = var->const_value; |
| 19899 | switch (val->special) { | 19910 | |
| 19900 | case ConstValSpecialRuntime: | 19911 | ConstPtrMut ptr_mut; |
| 19901 | break; | 19912 | if (comptime_var_mem) { |
| 19902 | case ConstValSpecialStatic: // fallthrough | 19913 | ptr_mut = ConstPtrMutComptimeVar; |
| 19903 | case ConstValSpecialLazy: // fallthrough | 19914 | } else if (var->gen_is_const && !linkage_makes_it_runtime) { |
| 19904 | case ConstValSpecialUndef: { | 19915 | ptr_mut = ConstPtrMutComptimeConst; |
| 19905 | ConstPtrMut ptr_mut; | 19916 | } else { |
| 19906 | if (comptime_var_mem) { | 19917 | assert(!comptime_var_mem); |
| 19907 | ptr_mut = ConstPtrMutComptimeVar; | 19918 | ptr_mut = ConstPtrMutRuntimeVar; |
| 19908 | } else if (var->gen_is_const) { | ||
| 19909 | ptr_mut = ConstPtrMutComptimeConst; | ||
| 19910 | } else { | ||
| 19911 | assert(!comptime_var_mem); | ||
| 19912 | ptr_mut = ConstPtrMutRuntimeVar; | ||
| 19913 | } | ||
| 19914 | result->value->special = ConstValSpecialStatic; | ||
| 19915 | result->value->data.x_ptr.mut = ptr_mut; | ||
| 19916 | result->value->data.x_ptr.special = ConstPtrSpecialRef; | ||
| 19917 | result->value->data.x_ptr.data.ref.pointee = val; | ||
| 19918 | return result; | ||
| 19919 | } | ||
| 19920 | } | 19919 | } |
| 19920 | result->value->special = ConstValSpecialStatic; | ||
| 19921 | result->value->data.x_ptr.mut = ptr_mut; | ||
| 19922 | result->value->data.x_ptr.special = ConstPtrSpecialRef; | ||
| 19923 | result->value->data.x_ptr.data.ref.pointee = val; | ||
| 19924 | return result; | ||
| 19921 | } | 19925 | } |
| 19922 | 19926 | ||
| 19923 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); | 19927 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); |
| ... | @@ -22288,12 +22292,15 @@ static IrInstGen *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInst* source_ins | ... | @@ -22288,12 +22292,15 @@ static IrInstGen *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInst* source_ins |
| 22288 | if (type_is_invalid(struct_val->type)) | 22292 | if (type_is_invalid(struct_val->type)) |
| 22289 | return ira->codegen->invalid_inst_gen; | 22293 | return ira->codegen->invalid_inst_gen; |
| 22290 | 22294 | ||
| 22291 | // This to allow lazy values to be resolved. | 22295 | if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { |
| 22292 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, | 22296 | // This to allow lazy values to be resolved. |
| 22293 | source_instr->source_node, struct_val, UndefOk))) | 22297 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, |
| 22294 | { | 22298 | source_instr->source_node, struct_val, UndefOk))) |
| 22295 | return ira->codegen->invalid_inst_gen; | 22299 | { |
| 22300 | return ira->codegen->invalid_inst_gen; | ||
| 22301 | } | ||
| 22296 | } | 22302 | } |
| 22303 | |||
| 22297 | if (initializing && struct_val->special == ConstValSpecialUndef) { | 22304 | if (initializing && struct_val->special == ConstValSpecialUndef) { |
| 22298 | struct_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, struct_type->data.structure.src_field_count); | 22305 | struct_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, struct_type->data.structure.src_field_count); |
| 22299 | struct_val->special = ConstValSpecialStatic; | 22306 | struct_val->special = ConstValSpecialStatic; |
test/compile_errors.zig+22| ... | @@ -7637,4 +7637,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -7637,4 +7637,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 7637 | , &[_][]const u8{ | 7637 | , &[_][]const u8{ |
| 7638 | "tmp.zig:4:9: error: expected type '*c_void', found '?*c_void'", | 7638 | "tmp.zig:4:9: error: expected type '*c_void', found '?*c_void'", |
| 7639 | }); | 7639 | }); |
| 7640 | |||
| 7641 | cases.add("pointer to a local runtime `var` is not constant", | ||
| 7642 | \\export fn get_ptr() *const u32 { | ||
| 7643 | \\ var local_var: u32 = 42; | ||
| 7644 | \\ return struct { | ||
| 7645 | \\ const ptr = &local_var; | ||
| 7646 | \\ }.ptr; | ||
| 7647 | \\} | ||
| 7648 | , &[_][]const u8{ | ||
| 7649 | ":4:21: error: cannot store runtime value in compile time variable", | ||
| 7650 | }); | ||
| 7651 | |||
| 7652 | cases.add("pointer to a local runtime `const` is not constant", | ||
| 7653 | \\export fn get_ptr(x: u32) *const u32 { | ||
| 7654 | \\ const local_var: u32 = x; | ||
| 7655 | \\ return struct { | ||
| 7656 | \\ const ptr = &local_var; | ||
| 7657 | \\ }.ptr; | ||
| 7658 | \\} | ||
| 7659 | , &[_][]const u8{ | ||
| 7660 | ":4:21: error: cannot store runtime value in compile time variable", | ||
| 7661 | }); | ||
| 7640 | } | 7662 | } |
test/standalone.zig+1| ... | @@ -19,6 +19,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -19,6 +19,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 19 | cases.addBuildFile("test/standalone/use_alias/build.zig"); | 19 | cases.addBuildFile("test/standalone/use_alias/build.zig"); |
| 20 | cases.addBuildFile("test/standalone/brace_expansion/build.zig"); | 20 | cases.addBuildFile("test/standalone/brace_expansion/build.zig"); |
| 21 | cases.addBuildFile("test/standalone/empty_env/build.zig"); | 21 | cases.addBuildFile("test/standalone/empty_env/build.zig"); |
| 22 | cases.addBuildFile("test/standalone/extern_ref/build.zig"); | ||
| 22 | if (std.Target.current.os.tag != .wasi) { | 23 | if (std.Target.current.os.tag != .wasi) { |
| 23 | cases.addBuildFile("test/standalone/load_dynamic_library/build.zig"); | 24 | cases.addBuildFile("test/standalone/load_dynamic_library/build.zig"); |
| 24 | } | 25 | } |
test/standalone/extern_ref/build.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | const Builder = @import("std").build.Builder; | ||
| 2 | |||
| 3 | pub fn build(b: *Builder) void { | ||
| 4 | const mode = b.standardReleaseOptions(); | ||
| 5 | |||
| 6 | const obj = b.addStaticLibrary("obj", "obj.zig"); | ||
| 7 | obj.setBuildMode(mode); | ||
| 8 | |||
| 9 | const main = b.addTest("main.zig"); | ||
| 10 | main.setBuildMode(mode); | ||
| 11 | main.linkLibrary(obj); | ||
| 12 | |||
| 13 | const test_step = b.step("test", "Test it"); | ||
| 14 | test_step.dependOn(&main.step); | ||
| 15 | } | ||
test/standalone/extern_ref/main.zig created+120| ... | @@ -0,0 +1,120 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const eql = std.mem.eql; | ||
| 3 | |||
| 4 | // These are defined in `obj.zig` | ||
| 5 | extern var global_var: usize; | ||
| 6 | extern const global_const: usize; | ||
| 7 | |||
| 8 | const TheStruct = @import("./types.zig").TheStruct; | ||
| 9 | extern var global_var_struct: TheStruct; | ||
| 10 | extern const global_const_struct: TheStruct; | ||
| 11 | |||
| 12 | const TheUnion = @import("./types.zig").TheUnion; | ||
| 13 | extern var global_var_union: TheUnion; | ||
| 14 | extern const global_const_union: TheUnion; | ||
| 15 | |||
| 16 | extern var global_var_array: [4]u32; | ||
| 17 | extern const global_const_array: [4]u32; | ||
| 18 | |||
| 19 | // Take the pointers to external entities as constant values | ||
| 20 | const p_global_var = &global_var; | ||
| 21 | const p_global_const = &global_const; | ||
| 22 | |||
| 23 | test "access the external integers" { | ||
| 24 | std.testing.expect(p_global_var.* == 2); | ||
| 25 | std.testing.expect(p_global_const.* == 422); | ||
| 26 | } | ||
| 27 | |||
| 28 | const p_global_var_struct = &global_var_struct; | ||
| 29 | const p_global_const_struct = &global_const_struct; | ||
| 30 | |||
| 31 | const p_global_var_struct_val = &global_var_struct.value; | ||
| 32 | const p_global_const_struct_val = &global_const_struct.value; | ||
| 33 | |||
| 34 | const p_global_var_struct_array = &global_var_struct.array; | ||
| 35 | const p_global_const_struct_array = &global_const_struct.array; | ||
| 36 | |||
| 37 | const p_global_var_struct_array2 = global_var_struct.array[1..3]; | ||
| 38 | const p_global_const_struct_array2 = global_const_struct.array[1..3]; | ||
| 39 | |||
| 40 | const p_global_var_struct_array3 = &global_var_struct.array[1]; | ||
| 41 | const p_global_const_struct_array3 = &global_const_struct.array[1]; | ||
| 42 | |||
| 43 | test "access the external integers in a struct through comptime ptrs" { | ||
| 44 | std.testing.expect(p_global_var_struct.value == 2); | ||
| 45 | std.testing.expect(p_global_const_struct.value == 422); | ||
| 46 | |||
| 47 | std.testing.expect(p_global_var_struct_val.* == 2); | ||
| 48 | std.testing.expect(p_global_const_struct_val.* == 422); | ||
| 49 | } | ||
| 50 | |||
| 51 | test "access the external arrays in a struct through comptime ptrs" { | ||
| 52 | // TODO | ||
| 53 | // std.testing.expect(eql(u32, &p_global_var_struct.array, &[_]u32{1, 2, 3, 4})); | ||
| 54 | // std.testing.expect(eql(u32, &p_global_const_struct.array, &[_]u32{5, 6, 7, 8})); | ||
| 55 | |||
| 56 | // TODO | ||
| 57 | // std.testing.expect(eql(u32, p_global_var_struct_array, &[_]u32{1, 2, 3, 4})); | ||
| 58 | // std.testing.expect(eql(u32, p_global_const_struct_array, &[_]u32{5, 6, 7, 8})); | ||
| 59 | |||
| 60 | // TODO | ||
| 61 | // std.testing.expect(eql(u32, p_global_var_struct_array2, &[_]u32{2, 3})); | ||
| 62 | // std.testing.expect(eql(u32, p_global_const_struct_array2, &[_]u32{6, 7})); | ||
| 63 | |||
| 64 | // TODO | ||
| 65 | // std.testing.expect(p_global_var_struct_array3.* == 2); | ||
| 66 | // std.testing.expect(p_global_const_struct_array3.* == 6); | ||
| 67 | } | ||
| 68 | |||
| 69 | test "access the external integers with indirection through comptime ptrs" { | ||
| 70 | std.testing.expect(p_global_var_struct.p_value.* == 3); | ||
| 71 | std.testing.expect(p_global_const_struct.p_value.* == 423); | ||
| 72 | } | ||
| 73 | |||
| 74 | const p_global_var_struct_inner_val = &global_var_struct.inner.value; | ||
| 75 | const p_global_const_struct_inner_val = &global_const_struct.inner.value; | ||
| 76 | |||
| 77 | test "access the external integers in a nested struct through comptime ptrs" { | ||
| 78 | // TODO | ||
| 79 | // std.testing.expect(p_global_var_struct_inner_val.* == 4); | ||
| 80 | // std.testing.expect(p_global_const_struct_inner_val.* == 424); | ||
| 81 | } | ||
| 82 | |||
| 83 | const p_global_var_union = &global_var_union; | ||
| 84 | const p_global_const_union = &global_const_union; | ||
| 85 | |||
| 86 | const p_global_var_union_val = &global_var_union.U32; | ||
| 87 | const p_global_const_union_val = &global_const_union.U32; | ||
| 88 | |||
| 89 | test "access the external integers in a union through comptime ptrs" { | ||
| 90 | std.testing.expect(p_global_var_union.U32 == 10); | ||
| 91 | std.testing.expect(p_global_const_union.U32 == 20); | ||
| 92 | |||
| 93 | // TODO | ||
| 94 | // std.testing.expect(p_global_var_union_val.* == 10); | ||
| 95 | // std.testing.expect(p_global_const_union_val.* == 20); | ||
| 96 | } | ||
| 97 | |||
| 98 | const p_global_var_array = &global_var_array; | ||
| 99 | const p_global_const_array = &global_const_array; | ||
| 100 | |||
| 101 | const p_global_var_array2 = global_var_array[1..3]; | ||
| 102 | const p_global_const_array2 = global_const_array[1..3]; | ||
| 103 | |||
| 104 | const p_global_var_array3 = &global_var_array[1]; | ||
| 105 | const p_global_const_array3 = &global_const_array[1]; | ||
| 106 | |||
| 107 | test "access the external arrays through comptime ptrs" { | ||
| 108 | std.testing.expect(eql(u32, &global_var_array, &[_]u32{1, 2, 3, 4})); | ||
| 109 | std.testing.expect(eql(u32, &global_const_array, &[_]u32{5, 6, 7, 8})); | ||
| 110 | |||
| 111 | std.testing.expect(eql(u32, p_global_var_array, &[_]u32{1, 2, 3, 4})); | ||
| 112 | std.testing.expect(eql(u32, p_global_const_array, &[_]u32{5, 6, 7, 8})); | ||
| 113 | |||
| 114 | std.testing.expect(eql(u32, p_global_var_array2, &[_]u32{2, 3})); | ||
| 115 | std.testing.expect(eql(u32, p_global_const_array2, &[_]u32{6, 7})); | ||
| 116 | |||
| 117 | // TODO | ||
| 118 | // std.testing.expect(p_global_var_array3.* == 2); | ||
| 119 | // std.testing.expect(p_global_const_array3.* == 6); | ||
| 120 | } | ||
test/standalone/extern_ref/obj.zig created+27| ... | @@ -0,0 +1,27 @@ | ||
| 1 | export var global_var: usize = 2; | ||
| 2 | export const global_const: usize = 422; | ||
| 3 | |||
| 4 | const TheStruct = @import("./types.zig").TheStruct; | ||
| 5 | export var global_var_struct = TheStruct{ | ||
| 6 | .value = 2, | ||
| 7 | .array = [_]u32{ 1, 2, 3, 4 }, | ||
| 8 | .p_value = &@as(u32, 3), | ||
| 9 | .inner = .{ .value = 4 }, | ||
| 10 | }; | ||
| 11 | export const global_const_struct = TheStruct{ | ||
| 12 | .value = 422, | ||
| 13 | .array = [_]u32{ 5, 6, 7, 8 }, | ||
| 14 | .p_value = &@as(u32, 423), | ||
| 15 | .inner = .{ .value = 424 }, | ||
| 16 | }; | ||
| 17 | |||
| 18 | const TheUnion = @import("./types.zig").TheUnion; | ||
| 19 | export var global_var_union = TheUnion{ | ||
| 20 | .U32 = 10, | ||
| 21 | }; | ||
| 22 | export const global_const_union = TheUnion{ | ||
| 23 | .U32 = 20, | ||
| 24 | }; | ||
| 25 | |||
| 26 | export var global_var_array = [4]u32{ 1, 2, 3, 4 }; | ||
| 27 | export const global_const_array = [4]u32{ 5, 6, 7, 8 }; | ||
test/standalone/extern_ref/types.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | pub const TheStruct = extern struct { | ||
| 2 | value: u32, | ||
| 3 | array: [4]u32, | ||
| 4 | p_value: *const u32, | ||
| 5 | inner: InnerStruct, | ||
| 6 | }; | ||
| 7 | |||
| 8 | pub const InnerStruct = extern struct { | ||
| 9 | value: u32, | ||
| 10 | }; | ||
| 11 | |||
| 12 | pub const TheUnion = extern union { | ||
| 13 | U32: u32, | ||
| 14 | Bool: bool, | ||
| 15 | }; | ||