Commit fff8eff2bd

Loris Cro <kappaloris@gmail.com>
2025-02-13 20:05:00
initial implementation of `@deprecated`
1 parent 8957b27
lib/std/zig/AstGen.zig
@@ -9695,6 +9695,19 @@ fn builtinCall(
         .volatile_cast,
         => return ptrCast(gz, scope, ri, node),
 
+        .deprecated => {
+            _ = try gz.addExtendedNodeSmall(.deprecated, node, 0);
+            switch (params.len) {
+                0 => return .void_value,
+                1 => return expr(gz, scope, ri, params[0]),
+                else => return astgen.failNode(
+                    node,
+                    "expected 0 or 1 argument, found {}",
+                    .{params.len},
+                ),
+            }
+        },
+
         // zig fmt: off
         .has_decl  => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_decl),
         .has_field => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_field),
lib/std/zig/AstRlAnnotate.zig
@@ -817,8 +817,6 @@ fn blockExpr(astrl: *AstRlAnnotate, parent_block: ?*Block, ri: ResultInfo, node:
 }
 
 fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.Node.Index, args: []const Ast.Node.Index) !bool {
-    _ = ri; // Currently, no builtin consumes its result location.
-
     const tree = astrl.tree;
     const main_tokens = tree.nodes.items(.main_token);
     const builtin_token = main_tokens[node];
@@ -828,6 +826,11 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
         if (expected != args.len) return false;
     }
     switch (info.tag) {
+        .deprecated => if (args.len >= 1) {
+            return astrl.expr(args[0], block, ri);
+        } else {
+            return false;
+        },
         .import => return false,
         .branch_hint => {
             _ = try astrl.expr(args[0], block, ResultInfo.type_only);
lib/std/zig/BuiltinFn.zig
@@ -121,6 +121,7 @@ pub const Tag = enum {
     work_item_id,
     work_group_size,
     work_group_id,
+    deprecated,
 };
 
 pub const EvalToError = enum {
@@ -1016,6 +1017,14 @@ pub const list = list: {
                 .illegal_outside_function = true,
             },
         },
+        .{
+            "@deprecated",
+            .{
+                .tag = .deprecated,
+                .param_count = null,
+                .eval_to_error = .maybe,
+            },
+        },
     });
 };
 
lib/std/zig/Zir.zig
@@ -2112,6 +2112,9 @@ pub const Inst = struct {
         /// any code may have gone here, avoiding false-positive "unreachable code" errors.
         astgen_error,
 
+        /// `operand` is `src_node: i32`.
+        deprecated,
+
         pub const InstData = struct {
             opcode: Extended,
             small: u16,
@@ -4310,6 +4313,7 @@ fn findTrackableInner(
                 .value_placeholder => unreachable,
 
                 // Once again, we start with the boring tags.
+                .deprecated,
                 .this,
                 .ret_addr,
                 .builtin_src,
src/Package/Module.zig
@@ -27,6 +27,7 @@ red_zone: bool,
 sanitize_c: bool,
 sanitize_thread: bool,
 fuzz: bool,
+allow_deprecated: bool,
 unwind_tables: std.builtin.UnwindTables,
 cc_argv: []const []const u8,
 /// (SPIR-V) whether to generate a structured control flow graph or not
@@ -95,6 +96,7 @@ pub const CreateOptions = struct {
         sanitize_c: ?bool = null,
         sanitize_thread: ?bool = null,
         fuzz: ?bool = null,
+        allow_deprecated: ?bool = null,
         structured_cfg: ?bool = null,
         no_builtin: ?bool = null,
     };
@@ -234,6 +236,12 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
         break :b false;
     };
 
+    const allow_deprecated = b: {
+        if (options.inherited.allow_deprecated) |x| break :b x;
+        if (options.parent) |p| break :b p.allow_deprecated;
+        break :b false;
+    };
+
     const code_model = b: {
         if (options.inherited.code_model) |x| break :b x;
         if (options.parent) |p| break :b p.code_model;
@@ -380,6 +388,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
         .sanitize_c = sanitize_c,
         .sanitize_thread = sanitize_thread,
         .fuzz = fuzz,
+        .allow_deprecated = allow_deprecated,
         .unwind_tables = unwind_tables,
         .cc_argv = options.cc_argv,
         .structured_cfg = structured_cfg,
@@ -474,6 +483,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
             .sanitize_c = sanitize_c,
             .sanitize_thread = sanitize_thread,
             .fuzz = fuzz,
+            .allow_deprecated = allow_deprecated,
             .unwind_tables = unwind_tables,
             .cc_argv = &.{},
             .structured_cfg = structured_cfg,
@@ -532,6 +542,7 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P
         .sanitize_c = undefined,
         .sanitize_thread = undefined,
         .fuzz = undefined,
+        .allow_deprecated = undefined,
         .unwind_tables = undefined,
         .cc_argv = undefined,
         .structured_cfg = undefined,
src/Compilation.zig
@@ -869,6 +869,7 @@ pub const cache_helpers = struct {
         hh.add(mod.sanitize_c);
         hh.add(mod.sanitize_thread);
         hh.add(mod.fuzz);
+        hh.add(mod.allow_deprecated);
         hh.add(mod.unwind_tables);
         hh.add(mod.structured_cfg);
         hh.add(mod.no_builtin);
src/main.zig
@@ -520,6 +520,8 @@ const usage_build_generic =
     \\  -fno-sanitize-thread      Disable Thread Sanitizer
     \\  -ffuzz                    Enable fuzz testing instrumentation
     \\  -fno-fuzz                 Disable fuzz testing instrumentation
+    \\  -fallow-deprecated        Allow usage of deprecated code
+    \\  -fno-allow-deprecated     Disallow usage of deprecated code
     \\  -funwind-tables           Always produce unwind table entries for all functions
     \\  -fasync-unwind-tables     Always produce asynchronous unwind table entries for all functions
     \\  -fno-unwind-tables        Never produce unwind table entries
@@ -1454,6 +1456,10 @@ fn buildOutputType(
                         mod_opts.fuzz = true;
                     } else if (mem.eql(u8, arg, "-fno-fuzz")) {
                         mod_opts.fuzz = false;
+                    } else if (mem.eql(u8, arg, "-fallow-deprecated")) {
+                        mod_opts.allow_deprecated = true;
+                    } else if (mem.eql(u8, arg, "-fno-allow-deprecated")) {
+                        mod_opts.allow_deprecated = false;
                     } else if (mem.eql(u8, arg, "-fllvm")) {
                         create_module.opts.use_llvm = true;
                     } else if (mem.eql(u8, arg, "-fno-llvm")) {
src/print_zir.zig
@@ -535,6 +535,7 @@ const Writer = struct {
             .c_va_start,
             .in_comptime,
             .value_placeholder,
+            .deprecated,
             => try self.writeExtNode(stream, extended),
 
             .builtin_src => {
src/Sema.zig
@@ -1091,6 +1091,7 @@ fn analyzeBodyInner(
     const map = &sema.inst_map;
     const tags = sema.code.instructions.items(.tag);
     const datas = sema.code.instructions.items(.data);
+    const mod = block.ownerModule();
 
     var crash_info = crash_report.prepAnalyzeBody(sema, block, body);
     crash_info.push();
@@ -1341,6 +1342,15 @@ fn analyzeBodyInner(
             .extended => ext: {
                 const extended = datas[@intFromEnum(inst)].extended;
                 break :ext switch (extended.opcode) {
+                    .deprecated => {
+                        if (!mod.allow_deprecated) {
+                            const src_node: i32 = @bitCast(extended.operand);
+                            const src = block.nodeOffset(src_node);
+                            return sema.fail(block, src, "found deprecated code", .{});
+                        }
+
+                        break :ext .void_value;
+                    },
                     // zig fmt: off
                     .struct_decl        => try sema.zirStructDecl(        block, extended, inst),
                     .enum_decl          => try sema.zirEnumDecl(          block, extended, inst),