authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-23 15:35:54-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-10-23 15:35:54-07:00
log78f643c46d36d296d17b332b577c966fd0dd21bb
treedaa72a84c587ed47377d6db27bf9725f95d94cb2
parent6bf52b0505ad7317b5f0d6fa77b7c41318b9c73b
parent7edd69d8aade6da2339cb0d9a027c52b3015bc31
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21758 from kcbanner/dll_storage_class

Add `is_dll_import` to @extern, to support `__declspec(dllimport)` with the MSVC ABI

12 files changed, 99 insertions(+), 19 deletions(-)

lib/std/builtin.zig+1
...@@ -969,6 +969,7 @@ pub const ExternOptions = struct {...@@ -969,6 +969,7 @@ pub const ExternOptions = struct {
969 library_name: ?[]const u8 = null,969 library_name: ?[]const u8 = null,
970 linkage: GlobalLinkage = .strong,970 linkage: GlobalLinkage = .strong,
971 is_thread_local: bool = false,971 is_thread_local: bool = false,
972 is_dll_import: bool = false,
972};973};
973974
974/// This data structure is used by the Zig language code generation and975/// This data structure is used by the Zig language code generation and
src/InternPool.zig+9-2
...@@ -2054,6 +2054,7 @@ pub const Key = union(enum) {...@@ -2054,6 +2054,7 @@ pub const Key = union(enum) {
2054 is_const: bool,2054 is_const: bool,
2055 is_threadlocal: bool,2055 is_threadlocal: bool,
2056 is_weak_linkage: bool,2056 is_weak_linkage: bool,
2057 is_dll_import: bool,
2057 alignment: Alignment,2058 alignment: Alignment,
2058 @"addrspace": std.builtin.AddressSpace,2059 @"addrspace": std.builtin.AddressSpace,
2059 /// The ZIR instruction which created this extern; used only for source locations.2060 /// The ZIR instruction which created this extern; used only for source locations.
...@@ -2675,7 +2676,8 @@ pub const Key = union(enum) {...@@ -2675,7 +2676,8 @@ pub const Key = union(enum) {
2675 asBytes(&e.ty) ++ asBytes(&e.lib_name) ++2676 asBytes(&e.ty) ++ asBytes(&e.lib_name) ++
2676 asBytes(&e.is_const) ++ asBytes(&e.is_threadlocal) ++2677 asBytes(&e.is_const) ++ asBytes(&e.is_threadlocal) ++
2677 asBytes(&e.is_weak_linkage) ++ asBytes(&e.alignment) ++2678 asBytes(&e.is_weak_linkage) ++ asBytes(&e.alignment) ++
2678 asBytes(&e.@"addrspace") ++ asBytes(&e.zir_index)),2679 asBytes(&e.is_dll_import) ++ asBytes(&e.@"addrspace") ++
2680 asBytes(&e.zir_index)),
2679 };2681 };
2680 }2682 }
26812683
...@@ -2771,6 +2773,7 @@ pub const Key = union(enum) {...@@ -2771,6 +2773,7 @@ pub const Key = union(enum) {
2771 a_info.is_const == b_info.is_const and2773 a_info.is_const == b_info.is_const and
2772 a_info.is_threadlocal == b_info.is_threadlocal and2774 a_info.is_threadlocal == b_info.is_threadlocal and
2773 a_info.is_weak_linkage == b_info.is_weak_linkage and2775 a_info.is_weak_linkage == b_info.is_weak_linkage and
2776 a_info.is_dll_import == b_info.is_dll_import and
2774 a_info.alignment == b_info.alignment and2777 a_info.alignment == b_info.alignment and
2775 a_info.@"addrspace" == b_info.@"addrspace" and2778 a_info.@"addrspace" == b_info.@"addrspace" and
2776 a_info.zir_index == b_info.zir_index;2779 a_info.zir_index == b_info.zir_index;
...@@ -5370,7 +5373,8 @@ pub const Tag = enum(u8) {...@@ -5370,7 +5373,8 @@ pub const Tag = enum(u8) {
5370 is_const: bool,5373 is_const: bool,
5371 is_threadlocal: bool,5374 is_threadlocal: bool,
5372 is_weak_linkage: bool,5375 is_weak_linkage: bool,
5373 _: u29 = 0,5376 is_dll_import: bool,
5377 _: u28 = 0,
5374 };5378 };
5375 };5379 };
53765380
...@@ -6714,6 +6718,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6714,6 +6718,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6714 .is_const = extra.flags.is_const,6718 .is_const = extra.flags.is_const,
6715 .is_threadlocal = extra.flags.is_threadlocal,6719 .is_threadlocal = extra.flags.is_threadlocal,
6716 .is_weak_linkage = extra.flags.is_weak_linkage,6720 .is_weak_linkage = extra.flags.is_weak_linkage,
6721 .is_dll_import = extra.flags.is_dll_import,
6717 .alignment = nav.status.resolved.alignment,6722 .alignment = nav.status.resolved.alignment,
6718 .@"addrspace" = nav.status.resolved.@"addrspace",6723 .@"addrspace" = nav.status.resolved.@"addrspace",
6719 .zir_index = extra.zir_index,6724 .zir_index = extra.zir_index,
...@@ -7380,6 +7385,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -7380,6 +7385,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
7380 .is_const = false,7385 .is_const = false,
7381 .is_threadlocal = variable.is_threadlocal,7386 .is_threadlocal = variable.is_threadlocal,
7382 .is_weak_linkage = variable.is_weak_linkage,7387 .is_weak_linkage = variable.is_weak_linkage,
7388 .is_dll_import = false,
7383 },7389 },
7384 }),7390 }),
7385 });7391 });
...@@ -8643,6 +8649,7 @@ pub fn getExtern(...@@ -8643,6 +8649,7 @@ pub fn getExtern(
8643 .is_const = key.is_const,8649 .is_const = key.is_const,
8644 .is_threadlocal = key.is_threadlocal,8650 .is_threadlocal = key.is_threadlocal,
8645 .is_weak_linkage = key.is_weak_linkage,8651 .is_weak_linkage = key.is_weak_linkage,
8652 .is_dll_import = key.is_dll_import,
8646 },8653 },
8647 .zir_index = key.zir_index,8654 .zir_index = key.zir_index,
8648 .owner_nav = owner_nav,8655 .owner_nav = owner_nav,
src/Sema.zig+22-1
...@@ -876,6 +876,7 @@ const InferredAlloc = struct {...@@ -876,6 +876,7 @@ const InferredAlloc = struct {
876876
877const NeededComptimeReason = struct {877const NeededComptimeReason = struct {
878 needed_comptime_reason: []const u8,878 needed_comptime_reason: []const u8,
879 value_comptime_reason: ?[]const u8 = null,
879 block_comptime_reason: ?*const Block.ComptimeReason = null,880 block_comptime_reason: ?*const Block.ComptimeReason = null,
880};881};
881882
...@@ -2246,7 +2247,7 @@ fn resolveValueAllowVariables(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Val...@@ -2246,7 +2247,7 @@ fn resolveValueAllowVariables(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Val
2246 }2247 }
2247 };2248 };
2248 const val = Value.fromInterned(ip_index);2249 const val = Value.fromInterned(ip_index);
2249 if (val.isPtrToThreadLocal(pt.zcu)) return null;2250 if (val.isPtrRuntimeValue(pt.zcu)) return null;
2250 return val;2251 return val;
2251}2252}
22522253
...@@ -2272,8 +2273,14 @@ pub fn resolveFinalDeclValue(...@@ -2272,8 +2273,14 @@ pub fn resolveFinalDeclValue(
2272 const zcu = sema.pt.zcu;2273 const zcu = sema.pt.zcu;
22732274
2274 const val = try sema.resolveValueAllowVariables(air_ref) orelse {2275 const val = try sema.resolveValueAllowVariables(air_ref) orelse {
2276 const value_comptime_reason: ?[]const u8 = if (air_ref.toInterned()) |_|
2277 "thread local and dll imported variables have runtime-known addresses"
2278 else
2279 null;
2280
2275 return sema.failWithNeededComptime(block, src, .{2281 return sema.failWithNeededComptime(block, src, .{
2276 .needed_comptime_reason = "global variable initializer must be comptime-known",2282 .needed_comptime_reason = "global variable initializer must be comptime-known",
2283 .value_comptime_reason = value_comptime_reason,
2277 });2284 });
2278 };2285 };
2279 if (val.isGenericPoison()) return error.GenericPoison;2286 if (val.isGenericPoison()) return error.GenericPoison;
...@@ -2291,6 +2298,9 @@ fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: N...@@ -2291,6 +2298,9 @@ fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: N
2291 const msg = try sema.errMsg(src, "unable to resolve comptime value", .{});2298 const msg = try sema.errMsg(src, "unable to resolve comptime value", .{});
2292 errdefer msg.destroy(sema.gpa);2299 errdefer msg.destroy(sema.gpa);
2293 try sema.errNote(src, msg, "{s}", .{reason.needed_comptime_reason});2300 try sema.errNote(src, msg, "{s}", .{reason.needed_comptime_reason});
2301 if (reason.value_comptime_reason) |value_comptime_reason| {
2302 try sema.errNote(src, msg, "{s}", .{value_comptime_reason});
2303 }
22942304
2295 if (reason.block_comptime_reason) |block_comptime_reason| {2305 if (reason.block_comptime_reason) |block_comptime_reason| {
2296 try block_comptime_reason.explain(sema, msg);2306 try block_comptime_reason.explain(sema, msg);
...@@ -10023,6 +10033,7 @@ fn funcCommon(...@@ -10023,6 +10033,7 @@ fn funcCommon(
10023 .is_const = true,10033 .is_const = true,
10024 .is_threadlocal = false,10034 .is_threadlocal = false,
10025 .is_weak_linkage = false,10035 .is_weak_linkage = false,
10036 .is_dll_import = false,
10026 .alignment = alignment orelse .none,10037 .alignment = alignment orelse .none,
10027 .@"addrspace" = address_space orelse .generic,10038 .@"addrspace" = address_space orelse .generic,
10028 .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction10039 .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction
...@@ -26577,6 +26588,7 @@ fn zirVarExtended(...@@ -26577,6 +26588,7 @@ fn zirVarExtended(
26577 .is_const = small.is_const,26588 .is_const = small.is_const,
26578 .is_threadlocal = small.is_threadlocal,26589 .is_threadlocal = small.is_threadlocal,
26579 .is_weak_linkage = false,26590 .is_weak_linkage = false,
26591 .is_dll_import = false,
26580 .alignment = alignment,26592 .alignment = alignment,
26581 .@"addrspace" = @"addrspace",26593 .@"addrspace" = @"addrspace",
26582 .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction26594 .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction
...@@ -27030,6 +27042,7 @@ fn resolveExternOptions(...@@ -27030,6 +27042,7 @@ fn resolveExternOptions(
27030 library_name: InternPool.OptionalNullTerminatedString = .none,27042 library_name: InternPool.OptionalNullTerminatedString = .none,
27031 linkage: std.builtin.GlobalLinkage = .strong,27043 linkage: std.builtin.GlobalLinkage = .strong,
27032 is_thread_local: bool = false,27044 is_thread_local: bool = false,
27045 is_dll_import: bool = false,
27033} {27046} {
27034 const pt = sema.pt;27047 const pt = sema.pt;
27035 const zcu = pt.zcu;27048 const zcu = pt.zcu;
...@@ -27043,6 +27056,7 @@ fn resolveExternOptions(...@@ -27043,6 +27056,7 @@ fn resolveExternOptions(
27043 const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });27056 const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });
27044 const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node });27057 const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node });
27045 const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });27058 const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });
27059 const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2704627060
27047 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);27061 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);
27048 const name = try sema.toConstString(block, name_src, name_ref, .{27062 const name = try sema.toConstString(block, name_src, name_ref, .{
...@@ -27076,6 +27090,11 @@ fn resolveExternOptions(...@@ -27076,6 +27090,11 @@ fn resolveExternOptions(
27076 break :library_name library_name;27090 break :library_name library_name;
27077 } else null;27091 } else null;
2707827092
27093 const is_dll_import_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_dll_import", .no_embedded_nulls), dll_import_src);
27094 const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{
27095 .needed_comptime_reason = "it must be comptime-known if the symbol is imported from a dll",
27096 });
27097
27079 if (name.len == 0) {27098 if (name.len == 0) {
27080 return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});27099 return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});
27081 }27100 }
...@@ -27089,6 +27108,7 @@ fn resolveExternOptions(...@@ -27089,6 +27108,7 @@ fn resolveExternOptions(
27089 .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),27108 .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),
27090 .linkage = linkage,27109 .linkage = linkage,
27091 .is_thread_local = is_thread_local_val.toBool(),27110 .is_thread_local = is_thread_local_val.toBool(),
27111 .is_dll_import = is_dll_import_val.toBool(),
27092 };27112 };
27093}27113}
2709427114
...@@ -27134,6 +27154,7 @@ fn zirBuiltinExtern(...@@ -27134,6 +27154,7 @@ fn zirBuiltinExtern(
27134 .is_const = ptr_info.flags.is_const,27154 .is_const = ptr_info.flags.is_const,
27135 .is_threadlocal = options.is_thread_local,27155 .is_threadlocal = options.is_thread_local,
27136 .is_weak_linkage = options.linkage == .weak,27156 .is_weak_linkage = options.linkage == .weak,
27157 .is_dll_import = options.is_dll_import,
27137 .alignment = ptr_info.flags.alignment,27158 .alignment = ptr_info.flags.alignment,
27138 .@"addrspace" = ptr_info.flags.address_space,27159 .@"addrspace" = ptr_info.flags.address_space,
27139 // This instruction is just for source locations.27160 // This instruction is just for source locations.
src/Value.zig+2-2
...@@ -1340,11 +1340,11 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool {...@@ -1340,11 +1340,11 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool {
1340 };1340 };
1341}1341}
13421342
1343pub fn isPtrToThreadLocal(val: Value, zcu: *Zcu) bool {1343pub fn isPtrRuntimeValue(val: Value, zcu: *Zcu) bool {
1344 const ip = &zcu.intern_pool;1344 const ip = &zcu.intern_pool;
1345 const nav = ip.getBackingNav(val.toIntern()).unwrap() orelse return false;1345 const nav = ip.getBackingNav(val.toIntern()).unwrap() orelse return false;
1346 return switch (ip.indexToKey(ip.getNav(nav).status.resolved.val)) {1346 return switch (ip.indexToKey(ip.getNav(nav).status.resolved.val)) {
1347 .@"extern" => |e| e.is_threadlocal,1347 .@"extern" => |e| e.is_threadlocal or e.is_dll_import,
1348 .variable => |v| v.is_threadlocal,1348 .variable => |v| v.is_threadlocal,
1349 else => false,1349 else => false,
1350 };1350 };
src/Zcu.zig+3
...@@ -1522,6 +1522,7 @@ pub const SrcLoc = struct {...@@ -1522,6 +1522,7 @@ pub const SrcLoc = struct {
1522 .init_field_cache,1522 .init_field_cache,
1523 .init_field_library,1523 .init_field_library,
1524 .init_field_thread_local,1524 .init_field_thread_local,
1525 .init_field_dll_import,
1525 => |builtin_call_node| {1526 => |builtin_call_node| {
1526 const wanted = switch (src_loc.lazy) {1527 const wanted = switch (src_loc.lazy) {
1527 .init_field_name => "name",1528 .init_field_name => "name",
...@@ -1533,6 +1534,7 @@ pub const SrcLoc = struct {...@@ -1533,6 +1534,7 @@ pub const SrcLoc = struct {
1533 .init_field_cache => "cache",1534 .init_field_cache => "cache",
1534 .init_field_library => "library",1535 .init_field_library => "library",
1535 .init_field_thread_local => "thread_local",1536 .init_field_thread_local => "thread_local",
1537 .init_field_dll_import => "dll_import",
1536 else => unreachable,1538 else => unreachable,
1537 };1539 };
1538 const tree = try src_loc.file_scope.getTree(gpa);1540 const tree = try src_loc.file_scope.getTree(gpa);
...@@ -1959,6 +1961,7 @@ pub const LazySrcLoc = struct {...@@ -1959,6 +1961,7 @@ pub const LazySrcLoc = struct {
1959 init_field_cache: i32,1961 init_field_cache: i32,
1960 init_field_library: i32,1962 init_field_library: i32,
1961 init_field_thread_local: i32,1963 init_field_thread_local: i32,
1964 init_field_dll_import: i32,
1962 /// The source location points to the value of an item in a specific1965 /// The source location points to the value of an item in a specific
1963 /// case of a `switch`.1966 /// case of a `switch`.
1964 switch_case_item: SwitchItem,1967 switch_case_item: SwitchItem,
src/Zcu/PerThread.zig+1
...@@ -2763,6 +2763,7 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V...@@ -2763,6 +2763,7 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V
2763 .is_const = e.is_const,2763 .is_const = e.is_const,
2764 .is_threadlocal = e.is_threadlocal,2764 .is_threadlocal = e.is_threadlocal,
2765 .is_weak_linkage = e.is_weak_linkage,2765 .is_weak_linkage = e.is_weak_linkage,
2766 .is_dll_import = e.is_dll_import,
2766 .alignment = e.alignment,2767 .alignment = e.alignment,
2767 .@"addrspace" = e.@"addrspace",2768 .@"addrspace" = e.@"addrspace",
2768 .zir_index = e.zir_index,2769 .zir_index = e.zir_index,
src/codegen/llvm.zig+13-9
...@@ -3260,10 +3260,10 @@ pub const Object = struct {...@@ -3260,10 +3260,10 @@ pub const Object = struct {
3260 const ip = &zcu.intern_pool;3260 const ip = &zcu.intern_pool;
3261 const nav = ip.getNav(nav_index);3261 const nav = ip.getNav(nav_index);
3262 const resolved = nav.status.resolved;3262 const resolved = nav.status.resolved;
3263 const is_extern, const is_threadlocal, const is_weak_linkage = switch (ip.indexToKey(resolved.val)) {3263 const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (ip.indexToKey(resolved.val)) {
3264 .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage },3264 .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },
3265 .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage },3265 .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },
3266 else => .{ false, false, false },3266 else => .{ false, false, false, false },
3267 };3267 };
32683268
3269 const variable_index = try o.builder.addVariable(3269 const variable_index = try o.builder.addVariable(
...@@ -3280,6 +3280,7 @@ pub const Object = struct {...@@ -3280,6 +3280,7 @@ pub const Object = struct {
3280 if (is_threadlocal and !zcu.navFileScope(nav_index).mod.single_threaded)3280 if (is_threadlocal and !zcu.navFileScope(nav_index).mod.single_threaded)
3281 variable_index.setThreadLocal(.generaldynamic, &o.builder);3281 variable_index.setThreadLocal(.generaldynamic, &o.builder);
3282 if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder);3282 if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder);
3283 if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
3283 } else {3284 } else {
3284 variable_index.setLinkage(.internal, &o.builder);3285 variable_index.setLinkage(.internal, &o.builder);
3285 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);3286 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
...@@ -4810,10 +4811,10 @@ pub const NavGen = struct {...@@ -4810,10 +4811,10 @@ pub const NavGen = struct {
4810 const nav = ip.getNav(nav_index);4811 const nav = ip.getNav(nav_index);
4811 const resolved = nav.status.resolved;4812 const resolved = nav.status.resolved;
48124813
4813 const is_extern, const lib_name, const is_threadlocal, const is_weak_linkage, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {4814 const is_extern, const lib_name, const is_threadlocal, const is_weak_linkage, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {
4814 .variable => |variable| .{ false, variable.lib_name, variable.is_threadlocal, variable.is_weak_linkage, false, variable.init, variable.owner_nav },4815 .variable => |variable| .{ false, variable.lib_name, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },
4815 .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_const, .none, @"extern".owner_nav },4816 .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
4816 else => .{ false, .none, false, false, true, resolved.val, nav_index },4817 else => .{ false, .none, false, false, false, true, resolved.val, nav_index },
4817 };4818 };
4818 const ty = Type.fromInterned(nav.typeOf(ip));4819 const ty = Type.fromInterned(nav.typeOf(ip));
48194820
...@@ -4888,8 +4889,11 @@ pub const NavGen = struct {...@@ -4888,8 +4889,11 @@ pub const NavGen = struct {
4888 try global_index.rename(decl_name, &o.builder);4889 try global_index.rename(decl_name, &o.builder);
4889 global_index.setLinkage(.external, &o.builder);4890 global_index.setLinkage(.external, &o.builder);
4890 global_index.setUnnamedAddr(.default, &o.builder);4891 global_index.setUnnamedAddr(.default, &o.builder);
4891 if (zcu.comp.config.dll_export_fns)4892 if (is_dll_import) {
4893 global_index.setDllStorageClass(.dllimport, &o.builder);
4894 } else if (zcu.comp.config.dll_export_fns) {
4892 global_index.setDllStorageClass(.default, &o.builder);4895 global_index.setDllStorageClass(.default, &o.builder);
4896 }
48934897
4894 if (is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);4898 if (is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);
4895 }4899 }
src/codegen/llvm/Builder.zig+4
...@@ -2541,6 +2541,10 @@ pub const Variable = struct {...@@ -2541,6 +2541,10 @@ pub const Variable = struct {
2541 return self.ptrConst(builder).global.setLinkage(linkage, builder);2541 return self.ptrConst(builder).global.setLinkage(linkage, builder);
2542 }2542 }
25432543
2544 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
2545 return self.ptrConst(builder).global.setDllStorageClass(class, builder);
2546 }
2547
2544 pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {2548 pub fn setUnnamedAddr(self: Index, unnamed_addr: UnnamedAddr, builder: *Builder) void {
2545 return self.ptrConst(builder).global.setUnnamedAddr(unnamed_addr, builder);2549 return self.ptrConst(builder).global.setUnnamedAddr(unnamed_addr, builder);
2546 }2550 }
test/cases/compile_errors/builtin_extern_in_comptime_scope.zig created+18
...@@ -0,0 +1,18 @@
1const foo_tl = @extern(*i32, .{ .name = "foo", .is_thread_local = true });
2const foo_dll = @extern(*i32, .{ .name = "foo", .is_dll_import = true });
3pub export fn entry() void {
4 _ = foo_tl;
5}
6pub export fn entry2() void {
7 _ = foo_dll;
8}
9// error
10// backend=stage2
11// target=native
12//
13// :1:16: error: unable to resolve comptime value
14// :1:16: note: global variable initializer must be comptime-known
15// :1:16: note: thread local and dll imported variables have runtime-known addresses
16// :2:17: error: unable to resolve comptime value
17// :2:17: note: global variable initializer must be comptime-known
18// :2:17: note: thread local and dll imported variables have runtime-known addresses
test/standalone/extern/build.zig+15-4
...@@ -1,6 +1,9 @@...@@ -1,6 +1,9 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
4 const test_step = b.step("test", "Test it");
5 b.default_step = test_step;
6
4 const optimize: std.builtin.OptimizeMode = .Debug;7 const optimize: std.builtin.OptimizeMode = .Debug;
58
6 const obj = b.addObject(.{9 const obj = b.addObject(.{
...@@ -9,12 +12,20 @@ pub fn build(b: *std.Build) void {...@@ -9,12 +12,20 @@ pub fn build(b: *std.Build) void {
9 .target = b.graph.host,12 .target = b.graph.host,
10 .optimize = optimize,13 .optimize = optimize,
11 });14 });
12 const main = b.addTest(.{15 const shared = b.addSharedLibrary(.{
16 .name = "shared",
17 .target = b.graph.host,
18 .optimize = optimize,
19 .link_libc = true,
20 });
21 if (b.graph.host.result.abi == .msvc) shared.defineCMacro("API", "__declspec(dllexport)");
22 shared.addCSourceFile(.{ .file = b.path("shared.c"), .flags = &.{} });
23 const test_exe = b.addTest(.{
13 .root_source_file = b.path("main.zig"),24 .root_source_file = b.path("main.zig"),
14 .optimize = optimize,25 .optimize = optimize,
15 });26 });
16 main.addObject(obj);27 test_exe.addObject(obj);
28 test_exe.linkLibrary(shared);
1729
18 const test_step = b.step("test", "Test it");30 test_step.dependOn(&b.addRunArtifact(test_exe).step);
19 test_step.dependOn(&main.step);
20}31}
test/standalone/extern/main.zig+6-1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
2const testing = @import("std").testing;
23
3const updateHidden = @extern(*const fn (u32) callconv(.C) void, .{ .name = "updateHidden" });4const updateHidden = @extern(*const fn (u32) callconv(.C) void, .{ .name = "updateHidden" });
4const getHidden = @extern(*const fn () callconv(.C) u32, .{ .name = "getHidden" });5const getHidden = @extern(*const fn () callconv(.C) u32, .{ .name = "getHidden" });
...@@ -8,14 +9,18 @@ const T = extern struct { x: u32 };...@@ -8,14 +9,18 @@ const T = extern struct { x: u32 };
8test {9test {
9 const mut_val_ptr = @extern(*f64, .{ .name = "mut_val" });10 const mut_val_ptr = @extern(*f64, .{ .name = "mut_val" });
10 const const_val_ptr = @extern(*const T, .{ .name = "const_val" });11 const const_val_ptr = @extern(*const T, .{ .name = "const_val" });
12 const shared_val_ptr = @extern(*c_int, .{ .name = "shared_val", .is_dll_import = true });
1113
12 assert(getHidden() == 0);14 assert(getHidden() == 0);
13 updateHidden(123);15 updateHidden(123);
14 assert(getHidden() == 123);16 assert(getHidden() == 123);
15
16 assert(mut_val_ptr.* == 1.23);17 assert(mut_val_ptr.* == 1.23);
17 mut_val_ptr.* = 10.0;18 mut_val_ptr.* = 10.0;
18 assert(mut_val_ptr.* == 10.0);19 assert(mut_val_ptr.* == 10.0);
1920
20 assert(const_val_ptr.x == 42);21 assert(const_val_ptr.x == 42);
22
23 assert(shared_val_ptr.* == 1234);
24 shared_val_ptr.* = 1235;
25 assert(shared_val_ptr.* == 1235);
21}26}
test/standalone/extern/shared.c created+5
...@@ -0,0 +1,5 @@
1#ifndef API
2#define API
3#endif
4
5API int shared_val = 1234;