| author | |
| committer | |
| log | dea72d15da4fba909dc3ccb2e9dc5286372ac023 |
| tree | daea2909e476467396347897bc12b13ae2a37ff7 |
| parent | ab381933c87bcc744058d25a876cfdc0d23fc674 |
| parent | 43a949ee95ce72003bb2d2ee22e1f4b5aea96739 |
| signature |
Implement `@deprecated`17 files changed, 251 insertions(+), 15 deletions(-)
doc/langref.html.in+49-13| ... | ... | @@ -2288,7 +2288,7 @@ or |
| 2288 | 2288 | {#code|test_aligned_struct_fields.zig#} |
| 2289 | 2289 | |
| 2290 | 2290 | <p> |
| 2291 | Equating packed structs results in a comparison of the backing integer, | |
| 2291 | Equating packed structs results in a comparison of the backing integer, | |
| 2292 | 2292 | and only works for the `==` and `!=` operators. |
| 2293 | 2293 | </p> |
| 2294 | 2294 | {#code|test_packed_struct_equality.zig#} |
| ... | ... | @@ -4086,7 +4086,7 @@ fn performFn(start_value: i32) i32 { |
| 4086 | 4086 | special-case syntax. |
| 4087 | 4087 | </p> |
| 4088 | 4088 | <p> |
| 4089 | 			Here is an example of a generic {#syntax#}List{#endsyntax#} data structure. | |
| 4089 | Here is an example of a generic {#syntax#}List{#endsyntax#} data structure. | |
| 4090 | 4090 | </p> |
| 4091 | 4091 | {#code|generic_data_structure.zig#} |
| 4092 | 4092 | |
| ... | ... | @@ -4291,10 +4291,10 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void { |
| 4291 | 4291 | <pre>{#syntax#}@addrSpaceCast(ptr: anytype) anytype{#endsyntax#}</pre> |
| 4292 | 4292 | <p> |
| 4293 | 4293 | Converts a pointer from one address space to another. The new address space is inferred |
| 4294 | 			based on the result type. Depending on the current target and address spaces, this cast | |
| 4295 | 			may be a no-op, a complex operation, or illegal. If the cast is legal, then the resulting | |
| 4296 | 			pointer points to the same memory location as the pointer operand. It is always valid to | |
| 4297 | 			cast a pointer between the same address spaces. | |
| 4294 | based on the result type. Depending on the current target and address spaces, this cast | |
| 4295 | may be a no-op, a complex operation, or illegal. If the cast is legal, then the resulting | |
| 4296 | pointer points to the same memory location as the pointer operand. It is always valid to | |
| 4297 | cast a pointer between the same address spaces. | |
| 4298 | 4298 | </p> |
| 4299 | 4299 | {#header_close#} |
| 4300 | 4300 | {#header_open|@addWithOverflow#} |
| ... | ... | @@ -4307,7 +4307,7 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void { |
| 4307 | 4307 | <pre>{#syntax#}@alignCast(ptr: anytype) anytype{#endsyntax#}</pre> |
| 4308 | 4308 | <p> |
| 4309 | 4309 | {#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}?*T{#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. |
| 4310 | 			Changes the alignment of a pointer. The alignment to use is inferred based on the result type. | |
| 4310 | Changes the alignment of a pointer. The alignment to use is inferred based on the result type. | |
| 4311 | 4311 | </p> |
| 4312 | 4312 | <p>A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added |
| 4313 | 4313 | to the generated code to make sure the pointer is aligned as promised.</p> |
| ... | ... | @@ -4384,7 +4384,7 @@ comptime { |
| 4384 | 4384 | <pre>{#syntax#}@bitCast(value: anytype) anytype{#endsyntax#}</pre> |
| 4385 | 4385 | <p> |
| 4386 | 4386 | Converts a value of one type to another type. The return type is the |
| 4387 | 			inferred result type. | |
| 4387 | inferred result type. | |
| 4388 | 4388 | </p> |
| 4389 | 4389 | <p> |
| 4390 | 4390 | Asserts that {#syntax#}@sizeOf(@TypeOf(value)) == @sizeOf(DestType){#endsyntax#}. |
| ... | ... | @@ -4741,6 +4741,42 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 4741 | 4741 | {#see_also|@cVaArg|@cVaCopy|@cVaEnd#} |
| 4742 | 4742 | {#header_close#} |
| 4743 | 4743 | |
| 4744 | {#header_open|@deprecated#} | |
| 4745 | <pre>{#syntax#}@deprecated(value: anytype) @TypeOf(value){#endsyntax#}</pre> | |
| 4746 | <pre>{#syntax#}@deprecated() void{#endsyntax#}</pre> | |
| 4747 | <p> | |
| 4748 | Marks a given code path as scheduled for removal. Evaluates to the same | |
| 4749 | value passed in as argument, or the {#syntax#}void{#endsyntax#} value | |
| 4750 | when given none. | |
| 4751 | </p> | |
| 4752 | <p> | |
| 4753 | When a public declaration has been moved to a new location, the old | |
| 4754 | location can be marked {#syntax#}@deprecated{#endsyntax#}: | |
| 4755 | </p> | |
| 4756 | {#syntax_block|zig|root.zig#} | |
| 4757 | pub const fooToBar = @deprecated(bar.fromFoo); // moved | |
| 4758 | {#end_syntax_block#} | |
| 4759 | <p> | |
| 4760 | By default deprecated code paths are disallowed in a module defined by | |
| 4761 | the root package but allowed in modules defined by the rest of the | |
| 4762 | dependency tree. This behavior can be overridden by passing | |
| 4763 | <code>-fallow-deprecated</code> or <code>-fno-allow-deprecated</code> to | |
| 4764 | <code>zig build</code>. | |
| 4765 | </p> | |
| 4766 | <p> | |
| 4767 | The purpose of {#syntax#}@deprecated{#endsyntax#} is to provide at least | |
| 4768 | one version (a "grace period") of a package that supports both old and new APIs | |
| 4769 | simultaneously, while providing tooling for programmers to discover what needs | |
| 4770 | to be upgraded to migrate to the new API. Such a grace period has the key property | |
| 4771 | that it allows a project's dependency tree to be upgraded <em>one package at a time</em>. | |
| 4772 | </p> | |
| 4773 | <p> | |
| 4774 | Using {#syntax#}@deprecated{#endsyntax#} without an argument can be | |
| 4775 | useful inside of conditionally compiled blocks: | |
| 4776 | </p> | |
| 4777 | {#code|test_deprecated_builtin.zig#} | |
| 4778 | {#header_close#} | |
| 4779 | ||
| 4744 | 4780 | {#header_open|@divExact#} |
| 4745 | 4781 | <pre>{#syntax#}@divExact(numerator: T, denominator: T) T{#endsyntax#}</pre> |
| 4746 | 4782 | <p> |
| ... | ... | @@ -4855,8 +4891,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 4855 | 4891 | <pre>{#syntax#}@errorCast(value: anytype) anytype{#endsyntax#}</pre> |
| 4856 | 4892 | <p> |
| 4857 | 4893 | Converts an error set or error union value from one error set to another error set. The return type is the |
| 4858 | 			inferred result type. Attempting to convert an error which is not in the destination error | |
| 4859 | 			set results in safety-checked {#link|Illegal Behavior#}. | |
| 4894 | inferred result type. Attempting to convert an error which is not in the destination error | |
| 4895 | set results in safety-checked {#link|Illegal Behavior#}. | |
| 4860 | 4896 | </p> |
| 4861 | 4897 | {#header_close#} |
| 4862 | 4898 | |
| ... | ... | @@ -4935,7 +4971,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 4935 | 4971 | <pre>{#syntax#}@floatFromInt(int: anytype) anytype{#endsyntax#}</pre> |
| 4936 | 4972 | <p> |
| 4937 | 4973 | Converts an integer to the closest floating point representation. The return type is the inferred result type. |
| 4938 | 			To convert the other way, use {#link|@intFromFloat#}. This operation is legal | |
| 4974 | To convert the other way, use {#link|@intFromFloat#}. This operation is legal | |
| 4939 | 4975 | for all values of all integer types. |
| 4940 | 4976 | </p> |
| 4941 | 4977 | {#header_close#} |
| ... | ... | @@ -5027,7 +5063,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 5027 | 5063 | <pre>{#syntax#}@intCast(int: anytype) anytype{#endsyntax#}</pre> |
| 5028 | 5064 | <p> |
| 5029 | 5065 | Converts an integer to another integer while keeping the same numerical value. |
| 5030 | 			The return type is the inferred result type. | |
| 5066 | The return type is the inferred result type. | |
| 5031 | 5067 | Attempting to convert a number which is out of range of the destination type results in |
| 5032 | 5068 | safety-checked {#link|Illegal Behavior#}. |
| 5033 | 5069 | </p> |
| ... | ... | @@ -5280,7 +5316,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 5280 | 5316 | <pre>{#syntax#}@ptrFromInt(address: usize) anytype{#endsyntax#}</pre> |
| 5281 | 5317 | <p> |
| 5282 | 5318 | Converts an integer to a {#link|pointer|Pointers#}. The return type is the inferred result type. |
| 5283 | 			To convert the other way, use {#link|@intFromPtr#}. Casting an address of 0 to a destination type | |
| 5319 | To convert the other way, use {#link|@intFromPtr#}. Casting an address of 0 to a destination type | |
| 5284 | 5320 | which in not {#link|optional|Optional Pointers#} and does not have the {#syntax#}allowzero{#endsyntax#} attribute will result in a |
| 5285 | 5321 | {#link|Pointer Cast Invalid Null#} panic when runtime safety checks are enabled. |
| 5286 | 5322 | </p> |
doc/langref/test_deprecated_builtin.zig created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | test "deprecated code path" { | |
| 2 | compute(.greedy, false, 42); | |
| 3 | } | |
| 4 | ||
| 5 | const Strategy = enum { greedy, expensive, fast }; | |
| 6 | fn compute(comptime strat: Strategy, comptime foo: bool, bar: usize) void { | |
| 7 | switch (strat) { | |
| 8 | .greedy => { | |
| 9 | // This combination turned out to be ineffective. | |
| 10 | if (!foo) @deprecated(); // use fast strategy when foo is false | |
| 11 | runGreedy(foo, bar); | |
| 12 | }, | |
| 13 | .expensive => runExpensive(foo, bar), | |
| 14 | .fast => runFast(foo, bar), | |
| 15 | } | |
| 16 | } | |
| 17 | ||
| 18 | extern fn runGreedy(foo: bool, bar: usize) void; | |
| 19 | extern fn runExpensive(foo: bool, bar: usize) void; | |
| 20 | extern fn runFast(foo: bool, bar: usize) void; | |
| 21 | ||
| 22 | // test_error=deprecated |
lib/compiler/build_runner.zig+8| ... | ... | @@ -80,6 +80,7 @@ pub fn main() !void { |
| 80 | 80 | .query = .{}, |
| 81 | 81 | .result = try std.zig.system.resolveTargetQuery(.{}), |
| 82 | 82 | }, |
| 83 | .root_builder = undefined, // populated below | |
| 83 | 84 | }; |
| 84 | 85 | |
| 85 | 86 | graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() }); |
| ... | ... | @@ -94,6 +95,7 @@ pub fn main() !void { |
| 94 | 95 | local_cache_directory, |
| 95 | 96 | dependencies.root_deps, |
| 96 | 97 | ); |
| 98 | graph.root_builder = builder; | |
| 97 | 99 | |
| 98 | 100 | var targets = ArrayList([]const u8).init(arena); |
| 99 | 101 | var debug_log_scopes = ArrayList([]const u8).init(arena); |
| ... | ... | @@ -260,6 +262,10 @@ pub fn main() !void { |
| 260 | 262 | graph.incremental = true; |
| 261 | 263 | } else if (mem.eql(u8, arg, "-fno-incremental")) { |
| 262 | 264 | graph.incremental = false; |
| 265 | } else if (mem.eql(u8, arg, "-fallow-deprecated")) { | |
| 266 | graph.allow_deprecated = true; | |
| 267 | } else if (mem.eql(u8, arg, "-fno-allow-deprecated")) { | |
| 268 | graph.allow_deprecated = false; | |
| 263 | 269 | } else if (mem.eql(u8, arg, "-fwine")) { |
| 264 | 270 | builder.enable_wine = true; |
| 265 | 271 | } else if (mem.eql(u8, arg, "-fno-wine")) { |
| ... | ... | @@ -1290,6 +1296,8 @@ fn usage(b: *std.Build, out_stream: anytype) !void { |
| 1290 | 1296 | \\ new Omit cached steps |
| 1291 | 1297 | \\ failures (Default) Only print failed steps |
| 1292 | 1298 | \\ none Do not print the build summary |
| 1299 | \\ -fallow-deprecated Allow usage of deprecated code for the entire build graph | |
| 1300 | \\ -fno-allow-deprecated Disallow usage of deprecated code for the entire build graph | |
| 1293 | 1301 | \\ -j<N> Limit concurrent jobs (default is to use all CPU cores) |
| 1294 | 1302 | \\ --maxrss <bytes> Limit memory usage (default is to use available memory) |
| 1295 | 1303 | \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss |
lib/std/Build.zig+2| ... | ... | @@ -121,6 +121,8 @@ pub const Graph = struct { |
| 121 | 121 | random_seed: u32 = 0, |
| 122 | 122 | dependency_cache: InitializedDepMap = .empty, |
| 123 | 123 | allow_so_scripts: ?bool = null, |
| 124 | allow_deprecated: ?bool = null, | |
| 125 | root_builder: *std.Build, | |
| 124 | 126 | }; |
| 125 | 127 | |
| 126 | 128 | const AvailableDeps = []const struct { []const u8, []const u8 }; |
lib/std/Build/Module.zig+4| ... | ... | @@ -557,6 +557,10 @@ pub fn appendZigProcessFlags( |
| 557 | 557 | try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC"); |
| 558 | 558 | try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone"); |
| 559 | 559 | |
| 560 | // -fno-allow-deprecated is the CLI default, and not inherited, so only pass the flag if true. | |
| 561 | const allow_deprecated = m.owner.graph.allow_deprecated orelse (m.owner.graph.root_builder != m.owner); | |
| 562 | if (allow_deprecated == true) try zig_args.append("-fallow-deprecated"); | |
| 563 | ||
| 560 | 564 | if (m.dwarf_format) |dwarf_format| { |
| 561 | 565 | try zig_args.append(switch (dwarf_format) { |
| 562 | 566 | .@"32" => "-gdwarf32", |
lib/std/Build/Step/Options.zig+3| ... | ... | @@ -514,6 +514,7 @@ test Options { |
| 514 | 514 | .result = try std.zig.system.resolveTargetQuery(.{}), |
| 515 | 515 | }, |
| 516 | 516 | .zig_lib_directory = std.Build.Cache.Directory.cwd(), |
| 517 | .root_builder = undefined, | |
| 517 | 518 | }; |
| 518 | 519 | |
| 519 | 520 | var builder = try std.Build.create( |
| ... | ... | @@ -523,6 +524,8 @@ test Options { |
| 523 | 524 | &.{}, |
| 524 | 525 | ); |
| 525 | 526 | |
| 527 | graph.root_builder = builder; | |
| 528 | ||
| 526 | 529 | const options = builder.addOptions(); |
| 527 | 530 | |
| 528 | 531 | const KeywordEnum = enum { |
lib/std/zig/AstGen.zig+13| ... | ... | @@ -9695,6 +9695,19 @@ fn builtinCall( |
| 9695 | 9695 | .volatile_cast, |
| 9696 | 9696 | => return ptrCast(gz, scope, ri, node), |
| 9697 | 9697 | |
| 9698 | .deprecated => { | |
| 9699 | _ = try gz.addExtendedNodeSmall(.deprecated, node, 0); | |
| 9700 | switch (params.len) { | |
| 9701 | 0 => return .void_value, | |
| 9702 | 1 => return expr(gz, scope, ri, params[0]), | |
| 9703 | else => return astgen.failNode( | |
| 9704 | node, | |
| 9705 | "expected 0 or 1 argument, found {}", | |
| 9706 | .{params.len}, | |
| 9707 | ), | |
| 9708 | } | |
| 9709 | }, | |
| 9710 | ||
| 9698 | 9711 | // zig fmt: off |
| 9699 | 9712 | .has_decl => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_decl), |
| 9700 | 9713 | .has_field => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_field), |
lib/std/zig/AstRlAnnotate.zig+5-2| ... | ... | @@ -817,8 +817,6 @@ fn blockExpr(astrl: *AstRlAnnotate, parent_block: ?*Block, ri: ResultInfo, node: |
| 817 | 817 | } |
| 818 | 818 | |
| 819 | 819 | fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.Node.Index, args: []const Ast.Node.Index) !bool { |
| 820 | _ = ri; // Currently, no builtin consumes its result location. | |
| 821 | ||
| 822 | 820 | const tree = astrl.tree; |
| 823 | 821 | const main_tokens = tree.nodes.items(.main_token); |
| 824 | 822 | const builtin_token = main_tokens[node]; |
| ... | ... | @@ -828,6 +826,11 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast. |
| 828 | 826 | if (expected != args.len) return false; |
| 829 | 827 | } |
| 830 | 828 | switch (info.tag) { |
| 829 | .deprecated => if (args.len >= 1) { | |
| 830 | return astrl.expr(args[0], block, ri); | |
| 831 | } else { | |
| 832 | return false; | |
| 833 | }, | |
| 831 | 834 | .import => return false, |
| 832 | 835 | .branch_hint => { |
| 833 | 836 | _ = try astrl.expr(args[0], block, ResultInfo.type_only); |
lib/std/zig/BuiltinFn.zig+9| ... | ... | @@ -121,6 +121,7 @@ pub const Tag = enum { |
| 121 | 121 | work_item_id, |
| 122 | 122 | work_group_size, |
| 123 | 123 | work_group_id, |
| 124 | deprecated, | |
| 124 | 125 | }; |
| 125 | 126 | |
| 126 | 127 | pub const EvalToError = enum { |
| ... | ... | @@ -1016,6 +1017,14 @@ pub const list = list: { |
| 1016 | 1017 | .illegal_outside_function = true, |
| 1017 | 1018 | }, |
| 1018 | 1019 | }, |
| 1020 | .{ | |
| 1021 | "@deprecated", | |
| 1022 | .{ | |
| 1023 | .tag = .deprecated, | |
| 1024 | .param_count = null, | |
| 1025 | .eval_to_error = .maybe, | |
| 1026 | }, | |
| 1027 | }, | |
| 1019 | 1028 | }); |
| 1020 | 1029 | }; |
| 1021 | 1030 |
lib/std/zig/Zir.zig+4| ... | ... | @@ -2112,6 +2112,9 @@ pub const Inst = struct { |
| 2112 | 2112 | /// any code may have gone here, avoiding false-positive "unreachable code" errors. |
| 2113 | 2113 | astgen_error, |
| 2114 | 2114 | |
| 2115 | /// `operand` is `src_node: i32`. | |
| 2116 | deprecated, | |
| 2117 | ||
| 2115 | 2118 | pub const InstData = struct { |
| 2116 | 2119 | opcode: Extended, |
| 2117 | 2120 | small: u16, |
| ... | ... | @@ -4363,6 +4366,7 @@ fn findTrackableInner( |
| 4363 | 4366 | .tuple_decl, |
| 4364 | 4367 | .dbg_empty_stmt, |
| 4365 | 4368 | .astgen_error, |
| 4369 | .deprecated, | |
| 4366 | 4370 | => return, |
| 4367 | 4371 | |
| 4368 | 4372 | // `@TypeOf` has a body. |
src/Compilation.zig+1| ... | ... | @@ -869,6 +869,7 @@ pub const cache_helpers = struct { |
| 869 | 869 | hh.add(mod.sanitize_c); |
| 870 | 870 | hh.add(mod.sanitize_thread); |
| 871 | 871 | hh.add(mod.fuzz); |
| 872 | hh.add(mod.allow_deprecated); | |
| 872 | 873 | hh.add(mod.unwind_tables); |
| 873 | 874 | hh.add(mod.structured_cfg); |
| 874 | 875 | hh.add(mod.no_builtin); |
src/Package/Module.zig+10| ... | ... | @@ -27,6 +27,7 @@ red_zone: bool, |
| 27 | 27 | sanitize_c: bool, |
| 28 | 28 | sanitize_thread: bool, |
| 29 | 29 | fuzz: bool, |
| 30 | allow_deprecated: bool, | |
| 30 | 31 | unwind_tables: std.builtin.UnwindTables, |
| 31 | 32 | cc_argv: []const []const u8, |
| 32 | 33 | /// (SPIR-V) whether to generate a structured control flow graph or not |
| ... | ... | @@ -95,6 +96,7 @@ pub const CreateOptions = struct { |
| 95 | 96 | sanitize_c: ?bool = null, |
| 96 | 97 | sanitize_thread: ?bool = null, |
| 97 | 98 | fuzz: ?bool = null, |
| 99 | allow_deprecated: ?bool = null, | |
| 98 | 100 | structured_cfg: ?bool = null, |
| 99 | 101 | no_builtin: ?bool = null, |
| 100 | 102 | }; |
| ... | ... | @@ -234,6 +236,11 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { |
| 234 | 236 | break :b false; |
| 235 | 237 | }; |
| 236 | 238 | |
| 239 | const allow_deprecated = b: { | |
| 240 | if (options.inherited.allow_deprecated) |x| break :b x; | |
| 241 | break :b false; | |
| 242 | }; | |
| 243 | ||
| 237 | 244 | const code_model = b: { |
| 238 | 245 | if (options.inherited.code_model) |x| break :b x; |
| 239 | 246 | if (options.parent) |p| break :b p.code_model; |
| ... | ... | @@ -380,6 +387,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { |
| 380 | 387 | .sanitize_c = sanitize_c, |
| 381 | 388 | .sanitize_thread = sanitize_thread, |
| 382 | 389 | .fuzz = fuzz, |
| 390 | .allow_deprecated = allow_deprecated, | |
| 383 | 391 | .unwind_tables = unwind_tables, |
| 384 | 392 | .cc_argv = options.cc_argv, |
| 385 | 393 | .structured_cfg = structured_cfg, |
| ... | ... | @@ -474,6 +482,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { |
| 474 | 482 | .sanitize_c = sanitize_c, |
| 475 | 483 | .sanitize_thread = sanitize_thread, |
| 476 | 484 | .fuzz = fuzz, |
| 485 | .allow_deprecated = allow_deprecated, | |
| 477 | 486 | .unwind_tables = unwind_tables, |
| 478 | 487 | .cc_argv = &.{}, |
| 479 | 488 | .structured_cfg = structured_cfg, |
| ... | ... | @@ -532,6 +541,7 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P |
| 532 | 541 | .sanitize_c = undefined, |
| 533 | 542 | .sanitize_thread = undefined, |
| 534 | 543 | .fuzz = undefined, |
| 544 | .allow_deprecated = undefined, | |
| 535 | 545 | .unwind_tables = undefined, |
| 536 | 546 | .cc_argv = undefined, |
| 537 | 547 | .structured_cfg = undefined, |
src/Sema.zig+11| ... | ... | @@ -1091,6 +1091,7 @@ fn analyzeBodyInner( |
| 1091 | 1091 | const map = &sema.inst_map; |
| 1092 | 1092 | const tags = sema.code.instructions.items(.tag); |
| 1093 | 1093 | const datas = sema.code.instructions.items(.data); |
| 1094 | const mod = block.ownerModule(); | |
| 1094 | 1095 | |
| 1095 | 1096 | var crash_info = crash_report.prepAnalyzeBody(sema, block, body); |
| 1096 | 1097 | crash_info.push(); |
| ... | ... | @@ -1404,6 +1405,16 @@ fn analyzeBodyInner( |
| 1404 | 1405 | i += 1; |
| 1405 | 1406 | continue; |
| 1406 | 1407 | }, |
| 1408 | .deprecated => { | |
| 1409 | if (!mod.allow_deprecated) { | |
| 1410 | const src_node: i32 = @bitCast(extended.operand); | |
| 1411 | const src = block.nodeOffset(src_node); | |
| 1412 | return sema.fail(block, src, "reached deprecated code", .{}); | |
| 1413 | } | |
| 1414 | ||
| 1415 | i += 1; | |
| 1416 | continue; | |
| 1417 | }, | |
| 1407 | 1418 | .disable_instrumentation => { |
| 1408 | 1419 | try sema.zirDisableInstrumentation(); |
| 1409 | 1420 | i += 1; |
src/main.zig+6| ... | ... | @@ -520,6 +520,8 @@ const usage_build_generic = |
| 520 | 520 | \\ -fno-sanitize-thread Disable Thread Sanitizer |
| 521 | 521 | \\ -ffuzz Enable fuzz testing instrumentation |
| 522 | 522 | \\ -fno-fuzz Disable fuzz testing instrumentation |
| 523 | \\ -fallow-deprecated Allow usage of deprecated code | |
| 524 | \\ -fno-allow-deprecated Disallow usage of deprecated code | |
| 523 | 525 | \\ -funwind-tables Always produce unwind table entries for all functions |
| 524 | 526 | \\ -fasync-unwind-tables Always produce asynchronous unwind table entries for all functions |
| 525 | 527 | \\ -fno-unwind-tables Never produce unwind table entries |
| ... | ... | @@ -1454,6 +1456,10 @@ fn buildOutputType( |
| 1454 | 1456 | mod_opts.fuzz = true; |
| 1455 | 1457 | } else if (mem.eql(u8, arg, "-fno-fuzz")) { |
| 1456 | 1458 | mod_opts.fuzz = false; |
| 1459 | } else if (mem.eql(u8, arg, "-fallow-deprecated")) { | |
| 1460 | mod_opts.allow_deprecated = true; | |
| 1461 | } else if (mem.eql(u8, arg, "-fno-allow-deprecated")) { | |
| 1462 | mod_opts.allow_deprecated = false; | |
| 1457 | 1463 | } else if (mem.eql(u8, arg, "-fllvm")) { |
| 1458 | 1464 | create_module.opts.use_llvm = true; |
| 1459 | 1465 | } else if (mem.eql(u8, arg, "-fno-llvm")) { |
src/print_zir.zig+1| ... | ... | @@ -535,6 +535,7 @@ const Writer = struct { |
| 535 | 535 | .c_va_start, |
| 536 | 536 | .in_comptime, |
| 537 | 537 | .value_placeholder, |
| 538 | .deprecated, | |
| 538 | 539 | => try self.writeExtNode(stream, extended), |
| 539 | 540 | |
| 540 | 541 | .builtin_src => { |
test/cases/compile_errors/deprecated.zig created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | const bad = @deprecated(42); | |
| 2 | ||
| 3 | pub export fn foo() usize { | |
| 4 | return bad; | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // | |
| 9 | // :1:13: error: reached deprecated code |
test/tests.zig+94| ... | ... | @@ -1176,6 +1176,100 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 1176 | 1176 | step.dependOn(&cleanup.step); |
| 1177 | 1177 | } |
| 1178 | 1178 | |
| 1179 | { | |
| 1180 | // Test `zig build -fallow-deprecated`. | |
| 1181 | ||
| 1182 | const deprecated_check: std.Build.Step.Run.StdIo.Check = .{ | |
| 1183 | .expect_stderr_match = "reached deprecated code", | |
| 1184 | }; | |
| 1185 | ||
| 1186 | const tmp_path = b.makeTempPath(); | |
| 1187 | ||
| 1188 | // create custom main.zig file containing a deprecated decl | |
| 1189 | { | |
| 1190 | const new_main_src = | |
| 1191 | \\const bad = @deprecated(42); | |
| 1192 | \\ | |
| 1193 | \\pub fn main() u8 { | |
| 1194 | \\ return bad; | |
| 1195 | \\} | |
| 1196 | \\ | |
| 1197 | \\test { | |
| 1198 | \\ if (bad != 42) return error.Bad; | |
| 1199 | \\} | |
| 1200 | ; | |
| 1201 | ||
| 1202 | var src_dir = std.fs.cwd().makeOpenPath(b.pathJoin(&.{ tmp_path, "src" }), .{}) catch @panic("unable to create tmp path"); | |
| 1203 | defer src_dir.close(); | |
| 1204 | ||
| 1205 | var main = src_dir.createFile("main.zig", .{}) catch @panic("unable to create main.zig"); | |
| 1206 | defer main.close(); | |
| 1207 | ||
| 1208 | main.writeAll(new_main_src) catch @panic("unable to write to main.zig"); | |
| 1209 | } | |
| 1210 | ||
| 1211 | const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init" }); | |
| 1212 | init_exe.setCwd(.{ .cwd_relative = tmp_path }); | |
| 1213 | init_exe.setName("zig init"); | |
| 1214 | init_exe.expectStdOutEqual(""); | |
| 1215 | init_exe.expectStdErrEqual("info: created build.zig\n" ++ | |
| 1216 | "info: created build.zig.zon\n" ++ | |
| 1217 | "info: preserving already existing file: src" ++ s ++ "main.zig\n" ++ | |
| 1218 | "info: created src" ++ s ++ "root.zig\n"); | |
| 1219 | ||
| 1220 | const run_test_bad = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "test", "--color", "off" }); | |
| 1221 | run_test_bad.setCwd(.{ .cwd_relative = tmp_path }); | |
| 1222 | run_test_bad.setName("zig build test"); | |
| 1223 | run_test_bad.expectExitCode(1); | |
| 1224 | run_test_bad.expectStdOutEqual(""); | |
| 1225 | run_test_bad.addCheck(deprecated_check); | |
| 1226 | run_test_bad.step.dependOn(&init_exe.step); | |
| 1227 | ||
| 1228 | const run_test = b.addSystemCommand(&.{ | |
| 1229 | b.graph.zig_exe, | |
| 1230 | "build", | |
| 1231 | "test", | |
| 1232 | "--color", | |
| 1233 | "off", | |
| 1234 | "-fallow-deprecated", | |
| 1235 | }); | |
| 1236 | run_test.setCwd(.{ .cwd_relative = tmp_path }); | |
| 1237 | run_test.setName("zig build test"); | |
| 1238 | run_test.expectExitCode(0); | |
| 1239 | run_test.expectStdOutEqual(""); | |
| 1240 | run_test.expectStdErrEqual(""); | |
| 1241 | run_test.step.dependOn(&init_exe.step); | |
| 1242 | ||
| 1243 | const run_build_bad = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "--color", "off" }); | |
| 1244 | run_build_bad.setCwd(.{ .cwd_relative = tmp_path }); | |
| 1245 | run_build_bad.setName("zig build test"); | |
| 1246 | run_build_bad.expectExitCode(1); | |
| 1247 | run_build_bad.expectStdOutEqual(""); | |
| 1248 | run_build_bad.addCheck(deprecated_check); | |
| 1249 | run_build_bad.step.dependOn(&init_exe.step); | |
| 1250 | ||
| 1251 | const run_build = b.addSystemCommand(&.{ | |
| 1252 | b.graph.zig_exe, | |
| 1253 | "build", | |
| 1254 | "--color", | |
| 1255 | "off", | |
| 1256 | "-fallow-deprecated", | |
| 1257 | }); | |
| 1258 | run_build.setCwd(.{ .cwd_relative = tmp_path }); | |
| 1259 | run_build.setName("zig build test"); | |
| 1260 | run_build.expectExitCode(0); | |
| 1261 | run_build.expectStdOutEqual(""); | |
| 1262 | run_build.expectStdErrEqual(""); | |
| 1263 | run_build.step.dependOn(&init_exe.step); | |
| 1264 | ||
| 1265 | const cleanup = b.addRemoveDirTree(.{ .cwd_relative = tmp_path }); | |
| 1266 | cleanup.step.dependOn(&run_test.step); | |
| 1267 | cleanup.step.dependOn(&run_test_bad.step); | |
| 1268 | cleanup.step.dependOn(&run_build.step); | |
| 1269 | cleanup.step.dependOn(&run_build_bad.step); | |
| 1270 | ||
| 1271 | step.dependOn(&cleanup.step); | |
| 1272 | } | |
| 1179 | 1273 | // Test Godbolt API |
| 1180 | 1274 | if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) { |
| 1181 | 1275 | const tmp_path = b.makeTempPath(); |