diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 8c1e38ea09..bf9a2d5682 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -68,6 +68,14 @@ pub const GlobalLinkage = enum { LinkOnce, }; +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const SymbolVisibility = enum { + default, + hidden, + protected, +}; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const AtomicOrder = enum { @@ -655,6 +663,7 @@ pub const ExportOptions = struct { name: []const u8, linkage: GlobalLinkage = .Strong, section: ?[]const u8 = null, + visibility: SymbolVisibility = .default, }; /// This data structure is used by the Zig language code generation and diff --git a/src/Sema.zig b/src/Sema.zig index 2e7e5c9293..fbf25be288 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4348,6 +4348,7 @@ pub fn analyzeExport( .name = symbol_name, .linkage = borrowed_options.linkage, .section = section, + .visibility = borrowed_options.visibility, }, .src = src, .link = switch (mod.comp.bin_file.tag) { @@ -14998,23 +14999,37 @@ fn resolveExportOptions( const air_ref = sema.resolveInst(zir_ref); const options = try sema.coerce(block, export_options_ty, air_ref, src); - const name = try sema.fieldVal(block, src, options, "name", src); - const name_val = try sema.resolveConstValue(block, src, name); + const name_operand = try sema.fieldVal(block, src, options, "name", src); + const name_val = try sema.resolveConstValue(block, src, name_operand); + const name_ty = Type.initTag(.const_slice_u8); + const name = try name_val.toAllocatedBytes(name_ty, sema.arena, sema.mod); - const linkage = try sema.fieldVal(block, src, options, "linkage", src); - const linkage_val = try sema.resolveConstValue(block, src, linkage); + const linkage_operand = try sema.fieldVal(block, src, options, "linkage", src); + const linkage_val = try sema.resolveConstValue(block, src, linkage_operand); + const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage); const section = try sema.fieldVal(block, src, options, "section", src); const section_val = try sema.resolveConstValue(block, src, section); + const visibility_operand = try sema.fieldVal(block, src, options, "visibility", src); + const visibility_val = try sema.resolveConstValue(block, src, visibility_operand); + const visibility = visibility_val.toEnum(std.builtin.SymbolVisibility); + + if (visibility != .default and linkage == .Internal) { + return sema.fail(block, src, "symbol '{s}' exported with internal linkage has non-default visibility {s}", .{ + name, @tagName(visibility), + }); + } + if (!section_val.isNull()) { return sema.fail(block, src, "TODO: implement exporting with linksection", .{}); } - const name_ty = Type.initTag(.const_slice_u8); + return std.builtin.ExportOptions{ - .name = try name_val.toAllocatedBytes(name_ty, sema.arena, sema.mod), - .linkage = linkage_val.toEnum(std.builtin.GlobalLinkage), + .name = name, + .linkage = linkage, .section = null, // TODO + .visibility = visibility, }; } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 57bcbe9338..5e70710046 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -808,6 +808,11 @@ pub const Object = struct { .Weak => llvm_global.setLinkage(.WeakODR), .LinkOnce => llvm_global.setLinkage(.LinkOnceODR), } + switch (exports[0].options.visibility) { + .default => llvm_global.setVisibility(.Default), + .hidden => llvm_global.setVisibility(.Hidden), + .protected => llvm_global.setVisibility(.Protected), + } if (decl.val.castTag(.variable)) |variable| { if (variable.data.is_threadlocal) { llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index c70a7d1553..f3987a8665 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -117,6 +117,9 @@ pub const Value = opaque { pub const setLinkage = LLVMSetLinkage; extern fn LLVMSetLinkage(Global: *const Value, Linkage: Linkage) void; + pub const setVisibility = LLVMSetVisibility; + extern fn LLVMSetVisibility(Global: *const Value, Linkage: Visibility) void; + pub const setUnnamedAddr = LLVMSetUnnamedAddr; extern fn LLVMSetUnnamedAddr(Global: *const Value, HasUnnamedAddr: Bool) void; @@ -1324,6 +1327,12 @@ pub const Linkage = enum(c_uint) { LinkerPrivateWeak, }; +pub const Visibility = enum(c_uint) { + Default, + Hidden, + Protected, +}; + pub const ThreadLocalMode = enum(c_uint) { NotThreadLocal, GeneralDynamicTLSModel,