Commit ee25757245

kcbanner <kcbanner@gmail.com>
2024-10-20 00:15:39
Add support for specifying `dll_storage_class` in @extern
1 parent 2d888a8
Changed files (6)
lib/std/builtin.zig
@@ -68,6 +68,14 @@ pub const GlobalLinkage = enum {
     link_once,
 };
 
+/// This data structure is used by the Zig language code generation and
+/// therefore must be kept in sync with the compiler implementation.
+pub const DllStorageClass = enum {
+    default,
+    import,
+    @"export",
+};
+
 /// 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 {
@@ -683,6 +691,7 @@ pub const ExternOptions = struct {
     library_name: ?[]const u8 = null,
     linkage: GlobalLinkage = .strong,
     is_thread_local: bool = false,
+    dll_storage_class: DllStorageClass = .default,
 };
 
 /// This data structure is used by the Zig language code generation and
src/codegen/llvm.zig
@@ -4782,10 +4782,10 @@ pub const NavGen = struct {
         const nav = ip.getNav(nav_index);
         const resolved = nav.status.resolved;
 
-        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)) {
-            .variable => |variable| .{ false, variable.lib_name, variable.is_threadlocal, variable.is_weak_linkage, false, variable.init, variable.owner_nav },
-            .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_const, .none, @"extern".owner_nav },
-            else => .{ false, .none, false, false, true, resolved.val, nav_index },
+        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)) {
+            .variable => |variable| .{ false, variable.lib_name, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },
+            .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
+            else => .{ false, .none, false, false, false, true, resolved.val, nav_index },
         };
         const ty = Type.fromInterned(nav.typeOf(ip));
 
@@ -4860,8 +4860,11 @@ pub const NavGen = struct {
             try global_index.rename(decl_name, &o.builder);
             global_index.setLinkage(.external, &o.builder);
             global_index.setUnnamedAddr(.default, &o.builder);
-            if (zcu.comp.config.dll_export_fns)
+            if (is_dll_import) {
+                global_index.setDllStorageClass(.dllimport, &o.builder);
+            } else if (zcu.comp.config.dll_export_fns) {
                 global_index.setDllStorageClass(.default, &o.builder);
+            }
 
             if (is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);
         }
src/Zcu/PerThread.zig
@@ -2763,6 +2763,7 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V
                 .is_const = e.is_const,
                 .is_threadlocal = e.is_threadlocal,
                 .is_weak_linkage = e.is_weak_linkage,
+                .is_dll_import = e.is_dll_import,
                 .alignment = e.alignment,
                 .@"addrspace" = e.@"addrspace",
                 .zir_index = e.zir_index,
src/InternPool.zig
@@ -2054,6 +2054,7 @@ pub const Key = union(enum) {
         is_const: bool,
         is_threadlocal: bool,
         is_weak_linkage: bool,
+        is_dll_import: bool,
         alignment: Alignment,
         @"addrspace": std.builtin.AddressSpace,
         /// The ZIR instruction which created this extern; used only for source locations.
@@ -2675,6 +2676,7 @@ pub const Key = union(enum) {
                 asBytes(&e.ty) ++ asBytes(&e.lib_name) ++
                 asBytes(&e.is_const) ++ asBytes(&e.is_threadlocal) ++
                 asBytes(&e.is_weak_linkage) ++ asBytes(&e.alignment) ++
+                asBytes(&e.is_dll_import) ++ asBytes(&e.alignment) ++
                 asBytes(&e.@"addrspace") ++ asBytes(&e.zir_index)),
         };
     }
@@ -2771,6 +2773,7 @@ pub const Key = union(enum) {
                     a_info.is_const == b_info.is_const and
                     a_info.is_threadlocal == b_info.is_threadlocal and
                     a_info.is_weak_linkage == b_info.is_weak_linkage and
+                    a_info.is_dll_import == b_info.is_dll_import and
                     a_info.alignment == b_info.alignment and
                     a_info.@"addrspace" == b_info.@"addrspace" and
                     a_info.zir_index == b_info.zir_index;
@@ -5370,7 +5373,8 @@ pub const Tag = enum(u8) {
             is_const: bool,
             is_threadlocal: bool,
             is_weak_linkage: bool,
-            _: u29 = 0,
+            is_dll_import: bool,
+            _: u28 = 0,
         };
     };
 
@@ -6715,6 +6719,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
                 .is_const = extra.flags.is_const,
                 .is_threadlocal = extra.flags.is_threadlocal,
                 .is_weak_linkage = extra.flags.is_weak_linkage,
+                .is_dll_import = extra.flags.is_dll_import,
                 .alignment = nav.status.resolved.alignment,
                 .@"addrspace" = nav.status.resolved.@"addrspace",
                 .zir_index = extra.zir_index,
@@ -7381,6 +7386,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
                         .is_const = false,
                         .is_threadlocal = variable.is_threadlocal,
                         .is_weak_linkage = variable.is_weak_linkage,
+                        .is_dll_import = false,
                     },
                 }),
             });
@@ -8644,6 +8650,7 @@ pub fn getExtern(
             .is_const = key.is_const,
             .is_threadlocal = key.is_threadlocal,
             .is_weak_linkage = key.is_weak_linkage,
+            .is_dll_import = key.is_dll_import,
         },
         .zir_index = key.zir_index,
         .owner_nav = owner_nav,
src/Sema.zig
@@ -9960,6 +9960,7 @@ fn funcCommon(
             .is_const = true,
             .is_threadlocal = false,
             .is_weak_linkage = false,
+            .is_dll_import = false,
             .alignment = alignment orelse .none,
             .@"addrspace" = address_space orelse .generic,
             .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction
@@ -26505,6 +26506,7 @@ fn zirVarExtended(
             .is_const = small.is_const,
             .is_threadlocal = small.is_threadlocal,
             .is_weak_linkage = false,
+            .is_dll_import = false,
             .alignment = alignment,
             .@"addrspace" = @"addrspace",
             .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction
@@ -26958,6 +26960,7 @@ fn resolveExternOptions(
     library_name: InternPool.OptionalNullTerminatedString = .none,
     linkage: std.builtin.GlobalLinkage = .strong,
     is_thread_local: bool = false,
+    dll_storage_class: std.builtin.DllStorageClass = .default,
 } {
     const pt = sema.pt;
     const zcu = pt.zcu;
@@ -26971,6 +26974,7 @@ fn resolveExternOptions(
     const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });
     const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node });
     const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });
+    const dll_storage_class_src = block.src(.{ .init_field_dll_storage_class = src.offset.node_offset_builtin_call_arg.builtin_call_node });
 
     const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);
     const name = try sema.toConstString(block, name_src, name_ref, .{
@@ -27004,6 +27008,12 @@ fn resolveExternOptions(
         break :library_name library_name;
     } else null;
 
+    const dll_storage_class_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "dll_storage_class", .no_embedded_nulls), dll_storage_class_src);
+    const dll_storage_class_val = try sema.resolveConstDefinedValue(block, dll_storage_class_src, dll_storage_class_ref, .{
+        .needed_comptime_reason = "dll_storage_class of the extern symbol must be comptime-known",
+    });
+    const dll_storage_class = zcu.toEnum(std.builtin.DllStorageClass, dll_storage_class_val);
+
     if (name.len == 0) {
         return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});
     }
@@ -27012,11 +27022,16 @@ fn resolveExternOptions(
         return sema.fail(block, linkage_src, "extern symbol must use strong or weak linkage", .{});
     }
 
+    if (dll_storage_class == .@"export") {
+        return sema.fail(block, dll_storage_class_src, "extern symbol cannot have export dll storage class", .{});
+    }
+
     return .{
         .name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),
         .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),
         .linkage = linkage,
         .is_thread_local = is_thread_local_val.toBool(),
+        .dll_storage_class = dll_storage_class,
     };
 }
 
@@ -27062,6 +27077,7 @@ fn zirBuiltinExtern(
         .is_const = ptr_info.flags.is_const,
         .is_threadlocal = options.is_thread_local,
         .is_weak_linkage = options.linkage == .weak,
+        .is_dll_import = options.dll_storage_class == .import,
         .alignment = ptr_info.flags.alignment,
         .@"addrspace" = ptr_info.flags.address_space,
         // This instruction is just for source locations.
src/Zcu.zig
@@ -1522,6 +1522,7 @@ pub const SrcLoc = struct {
             .init_field_cache,
             .init_field_library,
             .init_field_thread_local,
+            .init_field_dll_storage_class,
             => |builtin_call_node| {
                 const wanted = switch (src_loc.lazy) {
                     .init_field_name => "name",
@@ -1533,6 +1534,7 @@ pub const SrcLoc = struct {
                     .init_field_cache => "cache",
                     .init_field_library => "library",
                     .init_field_thread_local => "thread_local",
+                    .init_field_dll_storage_class => "dll_storage_class",
                     else => unreachable,
                 };
                 const tree = try src_loc.file_scope.getTree(gpa);
@@ -1959,6 +1961,7 @@ pub const LazySrcLoc = struct {
         init_field_cache: i32,
         init_field_library: i32,
         init_field_thread_local: i32,
+        init_field_dll_storage_class: i32,
         /// The source location points to the value of an item in a specific
         /// case of a `switch`.
         switch_case_item: SwitchItem,