| author | |
| committer | |
| log | 9cfcd0c29677e11f76846b006757ff49e05e3d6f |
| tree | 285973ffaab76ee3ca831a9663f15be62c44d32b |
| parent | 1ca49b92c650e9b8988a35983e202cdb9c7ba6e7 |
| parent | 717e2a365d9b5103f855668e4765cc154203a2bf |
| signature |
Disallow extern variables with initializers.13 files changed, 122 insertions(+), 33 deletions(-)
lib/std/c/darwin.zig+3-2| ... | ... | @@ -46,10 +46,11 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header; |
| 46 | 46 | /// on this operating system. However when building object files or libraries, |
| 47 | 47 | /// the system libc won't be linked until the final executable. So we |
| 48 | 48 | /// export a weak symbol here, to be overridden by the real one. |
| 49 | pub extern "c" var _mh_execute_header: mach_hdr = undefined; | |
| 49 | var dummy_execute_header: mach_hdr = undefined; | |
| 50 | pub extern var _mh_execute_header: mach_hdr; | |
| 50 | 51 | comptime { |
| 51 | 52 | if (std.Target.current.isDarwin()) { |
| 52 | @export(_mh_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak }); | |
| 53 | @export(dummy_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak }); | |
| 53 | 54 | } |
| 54 | 55 | } |
| 55 | 56 |
lib/std/mem.zig+19-1| ... | ... | @@ -226,9 +226,19 @@ pub fn zeroes(comptime T: type) T { |
| 226 | 226 | .Vector => |info| { |
| 227 | 227 | return @splat(info.len, zeroes(info.child)); |
| 228 | 228 | }, |
| 229 | .Union => |info| { | |
| 230 | if (comptime meta.containerLayout(T) == .Extern) { | |
| 231 | // The C language specification states that (global) unions | |
| 232 | // should be zero initialized to the first named member. | |
| 233 | var item: T = undefined; | |
| 234 | @field(item, info.fields[0].name) = zeroes(@TypeOf(@field(item, info.fields[0].name))); | |
| 235 | return item; | |
| 236 | } | |
| 237 | ||
| 238 | @compileError("Can't set a " ++ @typeName(T) ++ " to zero."); | |
| 239 | }, | |
| 229 | 240 | .ErrorUnion, |
| 230 | 241 | .ErrorSet, |
| 231 | .Union, | |
| 232 | 242 | .Fn, |
| 233 | 243 | .BoundFn, |
| 234 | 244 | .Type, |
| ... | ... | @@ -317,6 +327,14 @@ test "mem.zeroes" { |
| 317 | 327 | for (b.sentinel) |e| { |
| 318 | 328 | testing.expectEqual(@as(u8, 0), e); |
| 319 | 329 | } |
| 330 | ||
| 331 | const C_union = extern union { | |
| 332 | a: u8, | |
| 333 | b: u32, | |
| 334 | }; | |
| 335 | ||
| 336 | var c = zeroes(C_union); | |
| 337 | testing.expectEqual(@as(u8, 0), c.a); | |
| 320 | 338 | } |
| 321 | 339 | |
| 322 | 340 | /// Sets a slice to zeroes. |
lib/std/special/c.zig+1-1| ... | ... | @@ -40,7 +40,7 @@ comptime { |
| 40 | 40 | } |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | extern var _fltused: c_int = 1; | |
| 43 | var _fltused: c_int = 1; | |
| 44 | 44 | |
| 45 | 45 | extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; |
| 46 | 46 | fn wasm_start() callconv(.C) void { |
lib/std/special/compiler_rt.zig+1-1| ... | ... | @@ -340,7 +340,7 @@ fn __stack_chk_fail() callconv(.C) noreturn { |
| 340 | 340 | @panic("stack smashing detected"); |
| 341 | 341 | } |
| 342 | 342 | |
| 343 | extern var __stack_chk_guard: usize = blk: { | |
| 343 | var __stack_chk_guard: usize = blk: { | |
| 344 | 344 | var buf = [1]u8{0} ** @sizeOf(usize); |
| 345 | 345 | buf[@sizeOf(usize) - 1] = 255; |
| 346 | 346 | buf[@sizeOf(usize) - 2] = '\n'; |
src-self-hosted/Module.zig+7-4| ... | ... | @@ -324,10 +324,10 @@ pub const Fn = struct { |
| 324 | 324 | }; |
| 325 | 325 | |
| 326 | 326 | pub const Var = struct { |
| 327 | /// if is_extern == true this is undefined | |
| 327 | 328 | init: Value, |
| 328 | 329 | owner_decl: *Decl, |
| 329 | 330 | |
| 330 | has_init: bool, | |
| 331 | 331 | is_extern: bool, |
| 332 | 332 | is_mutable: bool, |
| 333 | 333 | is_threadlocal: bool, |
| ... | ... | @@ -1456,7 +1456,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1456 | 1456 | const is_extern = blk: { |
| 1457 | 1457 | const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse |
| 1458 | 1458 | break :blk false; |
| 1459 | break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern; | |
| 1459 | if (tree.token_ids[maybe_extern_token] != .Keyword_extern) break :blk false; | |
| 1460 | if (var_decl.getTrailer("init_node")) |some| { | |
| 1461 | return self.failNode(&block_scope.base, some, "extern variables have no initializers", .{}); | |
| 1462 | } | |
| 1463 | break :blk true; | |
| 1460 | 1464 | }; |
| 1461 | 1465 | if (var_decl.getTrailer("lib_name")) |lib_name| { |
| 1462 | 1466 | assert(is_extern); |
| ... | ... | @@ -1569,7 +1573,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1569 | 1573 | new_variable.* = .{ |
| 1570 | 1574 | .owner_decl = decl, |
| 1571 | 1575 | .init = value orelse undefined, |
| 1572 | .has_init = value != null, | |
| 1573 | 1576 | .is_extern = is_extern, |
| 1574 | 1577 | .is_mutable = is_mutable, |
| 1575 | 1578 | .is_threadlocal = is_threadlocal, |
| ... | ... | @@ -2440,7 +2443,7 @@ fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) Inner |
| 2440 | 2443 | const variable = tv.val.cast(Value.Payload.Variable).?.variable; |
| 2441 | 2444 | |
| 2442 | 2445 | const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); |
| 2443 | if (!variable.is_mutable and !variable.is_extern and variable.has_init) { | |
| 2446 | if (!variable.is_mutable and !variable.is_extern) { | |
| 2444 | 2447 | const val_payload = try scope.arena().create(Value.Payload.RefVal); |
| 2445 | 2448 | val_payload.* = .{ .val = variable.init }; |
| 2446 | 2449 | return self.constInst(scope, src, .{ |
src-self-hosted/translate_c.zig+41-13| ... | ... | @@ -498,7 +498,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 498 | 498 | _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); |
| 499 | 499 | }, |
| 500 | 500 | .Var => { |
| 501 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); | |
| 501 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl), null); | |
| 502 | 502 | }, |
| 503 | 503 | .Empty => { |
| 504 | 504 | // Do nothing |
| ... | ... | @@ -679,12 +679,13 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 679 | 679 | return addTopLevelDecl(c, fn_name, &proto_node.base); |
| 680 | 680 | } |
| 681 | 681 | |
| 682 | fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | |
| 683 | const var_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl))); | |
| 682 | /// if mangled_name is not null, this var decl was declared in a block scope. | |
| 683 | fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl, mangled_name: ?[]const u8) Error!void { | |
| 684 | const var_name = mangled_name orelse try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, var_decl))); | |
| 684 | 685 | if (c.global_scope.sym_table.contains(var_name)) |
| 685 | 686 | return; // Avoid processing this decl twice |
| 686 | 687 | const rp = makeRestorePoint(c); |
| 687 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 688 | const visib_tok = if (mangled_name) |_| null else try appendToken(c, .Keyword_pub, "pub"); | |
| 688 | 689 | |
| 689 | 690 | const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) |
| 690 | 691 | null |
| ... | ... | @@ -701,8 +702,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 701 | 702 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| 702 | 703 | const storage_class = ZigClangVarDecl_getStorageClass(var_decl); |
| 703 | 704 | const is_const = ZigClangQualType_isConstQualified(qual_type); |
| 704 | ||
| 705 | const extern_tok = if (storage_class == .Extern) | |
| 705 | const has_init = ZigClangVarDecl_hasInit(var_decl); | |
| 706 | ||
| 707 | // In C extern variables with initializers behave like Zig exports. | |
| 708 | // extern int foo = 2; | |
| 709 | // does the same as: | |
| 710 | // extern int foo; | |
| 711 | // int foo = 2; | |
| 712 | const extern_tok = if (storage_class == .Extern and !has_init) | |
| 706 | 713 | try appendToken(c, .Keyword_extern, "extern") |
| 707 | 714 | else if (storage_class != .Static) |
| 708 | 715 | try appendToken(c, .Keyword_export, "export") |
| ... | ... | @@ -730,7 +737,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 730 | 737 | // If the initialization expression is not present, initialize with undefined. |
| 731 | 738 | // If it is an integer literal, we can skip the @as since it will be redundant |
| 732 | 739 | // with the variable type. |
| 733 | if (ZigClangVarDecl_hasInit(var_decl)) { | |
| 740 | if (has_init) { | |
| 734 | 741 | eq_tok = try appendToken(c, .Equal, "="); |
| 735 | 742 | init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| |
| 736 | 743 | transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) { |
| ... | ... | @@ -745,7 +752,22 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 745 | 752 | try transCreateNodeUndefinedLiteral(c); |
| 746 | 753 | } else if (storage_class != .Extern) { |
| 747 | 754 | eq_tok = try appendToken(c, .Equal, "="); |
| 748 | init_node = try transCreateNodeIdentifierUnchecked(c, "undefined"); | |
| 755 | // The C language specification states that variables with static or threadlocal | |
| 756 | // storage without an initializer are initialized to a zero value. | |
| 757 | ||
| 758 | // @import("std").mem.zeroes(T) | |
| 759 | const import_fn_call = try c.createBuiltinCall("@import", 1); | |
| 760 | const std_node = try transCreateNodeStringLiteral(c, "\"std\""); | |
| 761 | import_fn_call.params()[0] = std_node; | |
| 762 | import_fn_call.rparen_token = try appendToken(c, .RParen, ")"); | |
| 763 | const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem"); | |
| 764 | const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroes"); | |
| 765 | ||
| 766 | const zero_init_call = try c.createCall(outer_field_access, 1); | |
| 767 | zero_init_call.params()[0] = type_node; | |
| 768 | zero_init_call.rtoken = try appendToken(c, .RParen, ")"); | |
| 769 | ||
| 770 | init_node = &zero_init_call.base; | |
| 749 | 771 | } |
| 750 | 772 | |
| 751 | 773 | const linksection_expr = blk: { |
| ... | ... | @@ -1561,15 +1583,22 @@ fn transDeclStmtOne( |
| 1561 | 1583 | .Var => { |
| 1562 | 1584 | const var_decl = @ptrCast(*const ZigClangVarDecl, decl); |
| 1563 | 1585 | |
| 1564 | const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) | |
| 1565 | null | |
| 1566 | else | |
| 1567 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); | |
| 1568 | 1586 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| 1569 | 1587 | const name = try c.str(ZigClangNamedDecl_getName_bytes_begin( |
| 1570 | 1588 | @ptrCast(*const ZigClangNamedDecl, var_decl), |
| 1571 | 1589 | )); |
| 1572 | 1590 | const mangled_name = try block_scope.makeMangledName(c, name); |
| 1591 | ||
| 1592 | switch (ZigClangVarDecl_getStorageClass(var_decl)) { | |
| 1593 | .Extern, .Static => { | |
| 1594 | // This is actually a global variable, put it in the global scope and reference it. | |
| 1595 | // `_ = mangled_name;` | |
| 1596 | try visitVarDecl(rp.c, var_decl, mangled_name); | |
| 1597 | return try maybeSuppressResult(rp, scope, .unused, try transCreateNodeIdentifier(rp.c, mangled_name)); | |
| 1598 | }, | |
| 1599 | else => {}, | |
| 1600 | } | |
| 1601 | ||
| 1573 | 1602 | const mut_tok = if (ZigClangQualType_isConstQualified(qual_type)) |
| 1574 | 1603 | try appendToken(c, .Keyword_const, "const") |
| 1575 | 1604 | else |
| ... | ... | @@ -1597,7 +1626,6 @@ fn transDeclStmtOne( |
| 1597 | 1626 | .mut_token = mut_tok, |
| 1598 | 1627 | .semicolon_token = semicolon_token, |
| 1599 | 1628 | }, .{ |
| 1600 | .thread_local_token = thread_local_token, | |
| 1601 | 1629 | .eq_token = eq_token, |
| 1602 | 1630 | .type_node = type_node, |
| 1603 | 1631 | .init_node = init_node, |
src/codegen.cpp+5-4| ... | ... | @@ -292,13 +292,14 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { |
| 292 | 292 | } |
| 293 | 293 | } |
| 294 | 294 | |
| 295 | static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) { | |
| 295 | static LLVMLinkage to_llvm_linkage(GlobalLinkageId id, bool is_extern) { | |
| 296 | 296 | switch (id) { |
| 297 | 297 | case GlobalLinkageIdInternal: |
| 298 | 298 | return LLVMInternalLinkage; |
| 299 | 299 | case GlobalLinkageIdStrong: |
| 300 | 300 | return LLVMExternalLinkage; |
| 301 | 301 | case GlobalLinkageIdWeak: |
| 302 | if (is_extern) return LLVMExternalWeakLinkage; | |
| 302 | 303 | return LLVMWeakODRLinkage; |
| 303 | 304 | case GlobalLinkageIdLinkOnce: |
| 304 | 305 | return LLVMLinkOnceODRLinkage; |
| ... | ... | @@ -521,7 +522,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 521 | 522 | } |
| 522 | 523 | |
| 523 | 524 | |
| 524 | LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage)); | |
| 525 | LLVMSetLinkage(llvm_fn, to_llvm_linkage(linkage, fn->body_node == nullptr)); | |
| 525 | 526 | |
| 526 | 527 | if (linkage == GlobalLinkageIdInternal) { |
| 527 | 528 | LLVMSetUnnamedAddr(llvm_fn, true); |
| ... | ... | @@ -7962,7 +7963,7 @@ static void do_code_gen(CodeGen *g) { |
| 7962 | 7963 | global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name); |
| 7963 | 7964 | // TODO debug info for the extern variable |
| 7964 | 7965 | |
| 7965 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); | |
| 7966 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage, true)); | |
| 7966 | 7967 | maybe_import_dll(g, global_value, GlobalLinkageIdStrong); |
| 7967 | 7968 | LLVMSetAlignment(global_value, var->align_bytes); |
| 7968 | 7969 | LLVMSetGlobalConstant(global_value, var->gen_is_const); |
| ... | ... | @@ -7975,7 +7976,7 @@ static void do_code_gen(CodeGen *g) { |
| 7975 | 7976 | global_value = var->const_value->llvm_global; |
| 7976 | 7977 | |
| 7977 | 7978 | if (exported) { |
| 7978 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage)); | |
| 7979 | LLVMSetLinkage(global_value, to_llvm_linkage(linkage, false)); | |
| 7979 | 7980 | maybe_export_dll(g, global_value, GlobalLinkageIdStrong); |
| 7980 | 7981 | } |
| 7981 | 7982 | if (var->section_name) { |
src/parser.cpp+3| ... | ... | @@ -680,6 +680,9 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B |
| 680 | 680 | AstNode *var_decl = ast_parse_var_decl(pc); |
| 681 | 681 | if (var_decl != nullptr) { |
| 682 | 682 | assert(var_decl->type == NodeTypeVariableDeclaration); |
| 683 | if (first->id == TokenIdKeywordExtern && var_decl->data.variable_declaration.expr != nullptr) { | |
| 684 | ast_error(pc, first, "extern variables have no initializers"); | |
| 685 | } | |
| 683 | 686 | var_decl->line = first->start_line; |
| 684 | 687 | var_decl->column = first->start_column; |
| 685 | 688 | var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; |
test/compile_errors.zig+6| ... | ... | @@ -2,6 +2,12 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const std = @import("std"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.addTest("reject extern variables with initializers", | |
| 6 | \\extern var foo: int = 2; | |
| 7 | , &[_][]const u8{ | |
| 8 | "tmp.zig:1:1: error: extern variables have no initializers", | |
| 9 | }); | |
| 10 | ||
| 5 | 11 | cases.addTest("duplicate/unused labels", |
| 6 | 12 | \\comptime { |
| 7 | 13 | \\ blk: { blk: while (false) {} } |
test/run_translated_c.zig+14| ... | ... | @@ -3,6 +3,20 @@ const tests = @import("tests.zig"); |
| 3 | 3 | const nl = std.cstr.line_sep; |
| 4 | 4 | |
| 5 | 5 | pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 6 | cases.add("static variable in block scope", | |
| 7 | \\#include <stdlib.h> | |
| 8 | \\int foo() { | |
| 9 | \\ static int bar; | |
| 10 | \\ bar += 1; | |
| 11 | \\ return bar; | |
| 12 | \\} | |
| 13 | \\int main() { | |
| 14 | \\ foo(); | |
| 15 | \\ foo(); | |
| 16 | \\ if (foo() != 3) abort(); | |
| 17 | \\} | |
| 18 | , ""); | |
| 19 | ||
| 6 | 20 | cases.add("array initializer", |
| 7 | 21 | \\#include <stdlib.h> |
| 8 | 22 | \\int main(int argc, char **argv) { |
test/standalone/global_linkage/obj1.zig+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | extern var internal_integer: usize = 1; | |
| 2 | extern var obj1_integer: usize = 421; | |
| 1 | var internal_integer: usize = 1; | |
| 2 | var obj1_integer: usize = 421; | |
| 3 | 3 | |
| 4 | 4 | comptime { |
| 5 | 5 | @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal }); |
test/standalone/global_linkage/obj2.zig+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | extern var internal_integer: usize = 2; | |
| 2 | extern var obj2_integer: usize = 422; | |
| 1 | var internal_integer: usize = 2; | |
| 2 | var obj2_integer: usize = 422; | |
| 3 | 3 | |
| 4 | 4 | comptime { |
| 5 | 5 | @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal }); |
test/translate_c.zig+18-3| ... | ... | @@ -3,6 +3,20 @@ const std = @import("std"); |
| 3 | 3 | const CrossTarget = std.zig.CrossTarget; |
| 4 | 4 | |
| 5 | 5 | pub fn addCases(cases: *tests.TranslateCContext) void { |
| 6 | cases.add("extern variable in block scope", | |
| 7 | \\float bar; | |
| 8 | \\int foo() { | |
| 9 | \\ _Thread_local static int bar = 2; | |
| 10 | \\} | |
| 11 | , &[_][]const u8{ | |
| 12 | \\pub export var bar: f32 = @import("std").mem.zeroes(f32); | |
| 13 | \\threadlocal var bar_1: c_int = 2; | |
| 14 | \\pub export fn foo() c_int { | |
| 15 | \\ _ = bar_1; | |
| 16 | \\ return 0; | |
| 17 | \\} | |
| 18 | }); | |
| 19 | ||
| 6 | 20 | cases.add("missing return stmt", |
| 7 | 21 | \\int foo() {} |
| 8 | 22 | \\int bar() { |
| ... | ... | @@ -466,7 +480,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 466 | 480 | , &[_][]const u8{ |
| 467 | 481 | \\pub extern var extern_var: c_int; |
| 468 | 482 | \\pub const int_var: c_int = 13; |
| 469 | \\pub export var foo: c_int = undefined; | |
| 483 | \\pub export var foo: c_int = @import("std").mem.zeroes(c_int); | |
| 470 | 484 | }); |
| 471 | 485 | |
| 472 | 486 | cases.add("const ptr initializer", |
| ... | ... | @@ -480,8 +494,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 480 | 494 | \\ static const char v2[] = "2.2.2"; |
| 481 | 495 | \\} |
| 482 | 496 | , &[_][]const u8{ |
| 497 | \\const v2: [*c]const u8 = "2.2.2"; | |
| 483 | 498 | \\pub export fn foo() void { |
| 484 | \\ const v2: [*c]const u8 = "2.2.2"; | |
| 499 | \\ _ = v2; | |
| 485 | 500 | \\} |
| 486 | 501 | }); |
| 487 | 502 | |
| ... | ... | @@ -1327,7 +1342,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1327 | 1342 | \\static char arr1[] = "hello"; |
| 1328 | 1343 | \\char arr2[] = "hello"; |
| 1329 | 1344 | , &[_][]const u8{ |
| 1330 | \\pub extern var arr0: [*c]u8 = "hello"; | |
| 1345 | \\pub export var arr0: [*c]u8 = "hello"; | |
| 1331 | 1346 | \\pub var arr1: [*c]u8 = "hello"; |
| 1332 | 1347 | \\pub export var arr2: [*c]u8 = "hello"; |
| 1333 | 1348 | }); |