mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Merge pull request #22898 from kristoff-it/deprecated-proposal
Implement `@deprecated`
This commit is contained in:
commit
dea72d15da
@ -2288,7 +2288,7 @@ or
|
|||||||
{#code|test_aligned_struct_fields.zig#}
|
{#code|test_aligned_struct_fields.zig#}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Equating packed structs results in a comparison of the backing integer,
|
Equating packed structs results in a comparison of the backing integer,
|
||||||
and only works for the `==` and `!=` operators.
|
and only works for the `==` and `!=` operators.
|
||||||
</p>
|
</p>
|
||||||
{#code|test_packed_struct_equality.zig#}
|
{#code|test_packed_struct_equality.zig#}
|
||||||
@ -4086,7 +4086,7 @@ fn performFn(start_value: i32) i32 {
|
|||||||
special-case syntax.
|
special-case syntax.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Here is an example of a generic {#syntax#}List{#endsyntax#} data structure.
|
Here is an example of a generic {#syntax#}List{#endsyntax#} data structure.
|
||||||
</p>
|
</p>
|
||||||
{#code|generic_data_structure.zig#}
|
{#code|generic_data_structure.zig#}
|
||||||
|
|
||||||
@ -4291,10 +4291,10 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {
|
|||||||
<pre>{#syntax#}@addrSpaceCast(ptr: anytype) anytype{#endsyntax#}</pre>
|
<pre>{#syntax#}@addrSpaceCast(ptr: anytype) anytype{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
Converts a pointer from one address space to another. The new address space is inferred
|
Converts a pointer from one address space to another. The new address space is inferred
|
||||||
based on the result type. Depending on the current target and address spaces, this cast
|
based on the result type. Depending on the current target and address spaces, this cast
|
||||||
may be a no-op, a complex operation, or illegal. If the cast is legal, then the resulting
|
may be a no-op, a complex operation, or illegal. If the cast is legal, then the resulting
|
||||||
pointer points to the same memory location as the pointer operand. It is always valid to
|
pointer points to the same memory location as the pointer operand. It is always valid to
|
||||||
cast a pointer between the same address spaces.
|
cast a pointer between the same address spaces.
|
||||||
</p>
|
</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
{#header_open|@addWithOverflow#}
|
{#header_open|@addWithOverflow#}
|
||||||
@ -4307,7 +4307,7 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {
|
|||||||
<pre>{#syntax#}@alignCast(ptr: anytype) anytype{#endsyntax#}</pre>
|
<pre>{#syntax#}@alignCast(ptr: anytype) anytype{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
{#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}?*T{#endsyntax#}, or {#syntax#}[]T{#endsyntax#}.
|
{#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}?*T{#endsyntax#}, or {#syntax#}[]T{#endsyntax#}.
|
||||||
Changes the alignment of a pointer. The alignment to use is inferred based on the result type.
|
Changes the alignment of a pointer. The alignment to use is inferred based on the result type.
|
||||||
</p>
|
</p>
|
||||||
<p>A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added
|
<p>A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added
|
||||||
to the generated code to make sure the pointer is aligned as promised.</p>
|
to the generated code to make sure the pointer is aligned as promised.</p>
|
||||||
@ -4384,7 +4384,7 @@ comptime {
|
|||||||
<pre>{#syntax#}@bitCast(value: anytype) anytype{#endsyntax#}</pre>
|
<pre>{#syntax#}@bitCast(value: anytype) anytype{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
Converts a value of one type to another type. The return type is the
|
Converts a value of one type to another type. The return type is the
|
||||||
inferred result type.
|
inferred result type.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Asserts that {#syntax#}@sizeOf(@TypeOf(value)) == @sizeOf(DestType){#endsyntax#}.
|
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
|
|||||||
{#see_also|@cVaArg|@cVaCopy|@cVaEnd#}
|
{#see_also|@cVaArg|@cVaCopy|@cVaEnd#}
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
|
{#header_open|@deprecated#}
|
||||||
|
<pre>{#syntax#}@deprecated(value: anytype) @TypeOf(value){#endsyntax#}</pre>
|
||||||
|
<pre>{#syntax#}@deprecated() void{#endsyntax#}</pre>
|
||||||
|
<p>
|
||||||
|
Marks a given code path as scheduled for removal. Evaluates to the same
|
||||||
|
value passed in as argument, or the {#syntax#}void{#endsyntax#} value
|
||||||
|
when given none.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
When a public declaration has been moved to a new location, the old
|
||||||
|
location can be marked {#syntax#}@deprecated{#endsyntax#}:
|
||||||
|
</p>
|
||||||
|
{#syntax_block|zig|root.zig#}
|
||||||
|
pub const fooToBar = @deprecated(bar.fromFoo); // moved
|
||||||
|
{#end_syntax_block#}
|
||||||
|
<p>
|
||||||
|
By default deprecated code paths are disallowed in a module defined by
|
||||||
|
the root package but allowed in modules defined by the rest of the
|
||||||
|
dependency tree. This behavior can be overridden by passing
|
||||||
|
<code>-fallow-deprecated</code> or <code>-fno-allow-deprecated</code> to
|
||||||
|
<code>zig build</code>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The purpose of {#syntax#}@deprecated{#endsyntax#} is to provide at least
|
||||||
|
one version (a "grace period") of a package that supports both old and new APIs
|
||||||
|
simultaneously, while providing tooling for programmers to discover what needs
|
||||||
|
to be upgraded to migrate to the new API. Such a grace period has the key property
|
||||||
|
that it allows a project's dependency tree to be upgraded <em>one package at a time</em>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Using {#syntax#}@deprecated{#endsyntax#} without an argument can be
|
||||||
|
useful inside of conditionally compiled blocks:
|
||||||
|
</p>
|
||||||
|
{#code|test_deprecated_builtin.zig#}
|
||||||
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@divExact#}
|
{#header_open|@divExact#}
|
||||||
<pre>{#syntax#}@divExact(numerator: T, denominator: T) T{#endsyntax#}</pre>
|
<pre>{#syntax#}@divExact(numerator: T, denominator: T) T{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
@ -4855,8 +4891,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||||||
<pre>{#syntax#}@errorCast(value: anytype) anytype{#endsyntax#}</pre>
|
<pre>{#syntax#}@errorCast(value: anytype) anytype{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
Converts an error set or error union value from one error set to another error set. The return type is the
|
Converts an error set or error union value from one error set to another error set. The return type is the
|
||||||
inferred result type. Attempting to convert an error which is not in the destination error
|
inferred result type. Attempting to convert an error which is not in the destination error
|
||||||
set results in safety-checked {#link|Illegal Behavior#}.
|
set results in safety-checked {#link|Illegal Behavior#}.
|
||||||
</p>
|
</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
@ -4935,7 +4971,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||||||
<pre>{#syntax#}@floatFromInt(int: anytype) anytype{#endsyntax#}</pre>
|
<pre>{#syntax#}@floatFromInt(int: anytype) anytype{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
Converts an integer to the closest floating point representation. The return type is the inferred result type.
|
Converts an integer to the closest floating point representation. The return type is the inferred result type.
|
||||||
To convert the other way, use {#link|@intFromFloat#}. This operation is legal
|
To convert the other way, use {#link|@intFromFloat#}. This operation is legal
|
||||||
for all values of all integer types.
|
for all values of all integer types.
|
||||||
</p>
|
</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
@ -5027,7 +5063,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||||||
<pre>{#syntax#}@intCast(int: anytype) anytype{#endsyntax#}</pre>
|
<pre>{#syntax#}@intCast(int: anytype) anytype{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
Converts an integer to another integer while keeping the same numerical value.
|
Converts an integer to another integer while keeping the same numerical value.
|
||||||
The return type is the inferred result type.
|
The return type is the inferred result type.
|
||||||
Attempting to convert a number which is out of range of the destination type results in
|
Attempting to convert a number which is out of range of the destination type results in
|
||||||
safety-checked {#link|Illegal Behavior#}.
|
safety-checked {#link|Illegal Behavior#}.
|
||||||
</p>
|
</p>
|
||||||
@ -5280,7 +5316,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
|
|||||||
<pre>{#syntax#}@ptrFromInt(address: usize) anytype{#endsyntax#}</pre>
|
<pre>{#syntax#}@ptrFromInt(address: usize) anytype{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
Converts an integer to a {#link|pointer|Pointers#}. The return type is the inferred result type.
|
Converts an integer to a {#link|pointer|Pointers#}. The return type is the inferred result type.
|
||||||
To convert the other way, use {#link|@intFromPtr#}. Casting an address of 0 to a destination type
|
To convert the other way, use {#link|@intFromPtr#}. Casting an address of 0 to a destination type
|
||||||
which in not {#link|optional|Optional Pointers#} and does not have the {#syntax#}allowzero{#endsyntax#} attribute will result in a
|
which in not {#link|optional|Optional Pointers#} and does not have the {#syntax#}allowzero{#endsyntax#} attribute will result in a
|
||||||
{#link|Pointer Cast Invalid Null#} panic when runtime safety checks are enabled.
|
{#link|Pointer Cast Invalid Null#} panic when runtime safety checks are enabled.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
22
doc/langref/test_deprecated_builtin.zig
Normal file
22
doc/langref/test_deprecated_builtin.zig
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
test "deprecated code path" {
|
||||||
|
compute(.greedy, false, 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Strategy = enum { greedy, expensive, fast };
|
||||||
|
fn compute(comptime strat: Strategy, comptime foo: bool, bar: usize) void {
|
||||||
|
switch (strat) {
|
||||||
|
.greedy => {
|
||||||
|
// This combination turned out to be ineffective.
|
||||||
|
if (!foo) @deprecated(); // use fast strategy when foo is false
|
||||||
|
runGreedy(foo, bar);
|
||||||
|
},
|
||||||
|
.expensive => runExpensive(foo, bar),
|
||||||
|
.fast => runFast(foo, bar),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn runGreedy(foo: bool, bar: usize) void;
|
||||||
|
extern fn runExpensive(foo: bool, bar: usize) void;
|
||||||
|
extern fn runFast(foo: bool, bar: usize) void;
|
||||||
|
|
||||||
|
// test_error=deprecated
|
||||||
@ -80,6 +80,7 @@ pub fn main() !void {
|
|||||||
.query = .{},
|
.query = .{},
|
||||||
.result = try std.zig.system.resolveTargetQuery(.{}),
|
.result = try std.zig.system.resolveTargetQuery(.{}),
|
||||||
},
|
},
|
||||||
|
.root_builder = undefined, // populated below
|
||||||
};
|
};
|
||||||
|
|
||||||
graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
|
graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
|
||||||
@ -94,6 +95,7 @@ pub fn main() !void {
|
|||||||
local_cache_directory,
|
local_cache_directory,
|
||||||
dependencies.root_deps,
|
dependencies.root_deps,
|
||||||
);
|
);
|
||||||
|
graph.root_builder = builder;
|
||||||
|
|
||||||
var targets = ArrayList([]const u8).init(arena);
|
var targets = ArrayList([]const u8).init(arena);
|
||||||
var debug_log_scopes = ArrayList([]const u8).init(arena);
|
var debug_log_scopes = ArrayList([]const u8).init(arena);
|
||||||
@ -260,6 +262,10 @@ pub fn main() !void {
|
|||||||
graph.incremental = true;
|
graph.incremental = true;
|
||||||
} else if (mem.eql(u8, arg, "-fno-incremental")) {
|
} else if (mem.eql(u8, arg, "-fno-incremental")) {
|
||||||
graph.incremental = false;
|
graph.incremental = false;
|
||||||
|
} else if (mem.eql(u8, arg, "-fallow-deprecated")) {
|
||||||
|
graph.allow_deprecated = true;
|
||||||
|
} else if (mem.eql(u8, arg, "-fno-allow-deprecated")) {
|
||||||
|
graph.allow_deprecated = false;
|
||||||
} else if (mem.eql(u8, arg, "-fwine")) {
|
} else if (mem.eql(u8, arg, "-fwine")) {
|
||||||
builder.enable_wine = true;
|
builder.enable_wine = true;
|
||||||
} else if (mem.eql(u8, arg, "-fno-wine")) {
|
} else if (mem.eql(u8, arg, "-fno-wine")) {
|
||||||
@ -1290,6 +1296,8 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
|
|||||||
\\ new Omit cached steps
|
\\ new Omit cached steps
|
||||||
\\ failures (Default) Only print failed steps
|
\\ failures (Default) Only print failed steps
|
||||||
\\ none Do not print the build summary
|
\\ none Do not print the build summary
|
||||||
|
\\ -fallow-deprecated Allow usage of deprecated code for the entire build graph
|
||||||
|
\\ -fno-allow-deprecated Disallow usage of deprecated code for the entire build graph
|
||||||
\\ -j<N> Limit concurrent jobs (default is to use all CPU cores)
|
\\ -j<N> Limit concurrent jobs (default is to use all CPU cores)
|
||||||
\\ --maxrss <bytes> Limit memory usage (default is to use available memory)
|
\\ --maxrss <bytes> Limit memory usage (default is to use available memory)
|
||||||
\\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
|
\\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
|
||||||
|
|||||||
@ -121,6 +121,8 @@ pub const Graph = struct {
|
|||||||
random_seed: u32 = 0,
|
random_seed: u32 = 0,
|
||||||
dependency_cache: InitializedDepMap = .empty,
|
dependency_cache: InitializedDepMap = .empty,
|
||||||
allow_so_scripts: ?bool = null,
|
allow_so_scripts: ?bool = null,
|
||||||
|
allow_deprecated: ?bool = null,
|
||||||
|
root_builder: *std.Build,
|
||||||
};
|
};
|
||||||
|
|
||||||
const AvailableDeps = []const struct { []const u8, []const u8 };
|
const AvailableDeps = []const struct { []const u8, []const u8 };
|
||||||
|
|||||||
@ -557,6 +557,10 @@ pub fn appendZigProcessFlags(
|
|||||||
try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC");
|
try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC");
|
||||||
try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone");
|
try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone");
|
||||||
|
|
||||||
|
// -fno-allow-deprecated is the CLI default, and not inherited, so only pass the flag if true.
|
||||||
|
const allow_deprecated = m.owner.graph.allow_deprecated orelse (m.owner.graph.root_builder != m.owner);
|
||||||
|
if (allow_deprecated == true) try zig_args.append("-fallow-deprecated");
|
||||||
|
|
||||||
if (m.dwarf_format) |dwarf_format| {
|
if (m.dwarf_format) |dwarf_format| {
|
||||||
try zig_args.append(switch (dwarf_format) {
|
try zig_args.append(switch (dwarf_format) {
|
||||||
.@"32" => "-gdwarf32",
|
.@"32" => "-gdwarf32",
|
||||||
|
|||||||
@ -514,6 +514,7 @@ test Options {
|
|||||||
.result = try std.zig.system.resolveTargetQuery(.{}),
|
.result = try std.zig.system.resolveTargetQuery(.{}),
|
||||||
},
|
},
|
||||||
.zig_lib_directory = std.Build.Cache.Directory.cwd(),
|
.zig_lib_directory = std.Build.Cache.Directory.cwd(),
|
||||||
|
.root_builder = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
var builder = try std.Build.create(
|
var builder = try std.Build.create(
|
||||||
@ -523,6 +524,8 @@ test Options {
|
|||||||
&.{},
|
&.{},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
graph.root_builder = builder;
|
||||||
|
|
||||||
const options = builder.addOptions();
|
const options = builder.addOptions();
|
||||||
|
|
||||||
const KeywordEnum = enum {
|
const KeywordEnum = enum {
|
||||||
|
|||||||
@ -9695,6 +9695,19 @@ fn builtinCall(
|
|||||||
.volatile_cast,
|
.volatile_cast,
|
||||||
=> return ptrCast(gz, scope, ri, node),
|
=> 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
|
// zig fmt: off
|
||||||
.has_decl => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_decl),
|
.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),
|
.has_field => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_field),
|
||||||
|
|||||||
@ -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 {
|
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 tree = astrl.tree;
|
||||||
const main_tokens = tree.nodes.items(.main_token);
|
const main_tokens = tree.nodes.items(.main_token);
|
||||||
const builtin_token = main_tokens[node];
|
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;
|
if (expected != args.len) return false;
|
||||||
}
|
}
|
||||||
switch (info.tag) {
|
switch (info.tag) {
|
||||||
|
.deprecated => if (args.len >= 1) {
|
||||||
|
return astrl.expr(args[0], block, ri);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
.import => return false,
|
.import => return false,
|
||||||
.branch_hint => {
|
.branch_hint => {
|
||||||
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
||||||
|
|||||||
@ -121,6 +121,7 @@ pub const Tag = enum {
|
|||||||
work_item_id,
|
work_item_id,
|
||||||
work_group_size,
|
work_group_size,
|
||||||
work_group_id,
|
work_group_id,
|
||||||
|
deprecated,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const EvalToError = enum {
|
pub const EvalToError = enum {
|
||||||
@ -1016,6 +1017,14 @@ pub const list = list: {
|
|||||||
.illegal_outside_function = true,
|
.illegal_outside_function = true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.{
|
||||||
|
"@deprecated",
|
||||||
|
.{
|
||||||
|
.tag = .deprecated,
|
||||||
|
.param_count = null,
|
||||||
|
.eval_to_error = .maybe,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2112,6 +2112,9 @@ pub const Inst = struct {
|
|||||||
/// any code may have gone here, avoiding false-positive "unreachable code" errors.
|
/// any code may have gone here, avoiding false-positive "unreachable code" errors.
|
||||||
astgen_error,
|
astgen_error,
|
||||||
|
|
||||||
|
/// `operand` is `src_node: i32`.
|
||||||
|
deprecated,
|
||||||
|
|
||||||
pub const InstData = struct {
|
pub const InstData = struct {
|
||||||
opcode: Extended,
|
opcode: Extended,
|
||||||
small: u16,
|
small: u16,
|
||||||
@ -4363,6 +4366,7 @@ fn findTrackableInner(
|
|||||||
.tuple_decl,
|
.tuple_decl,
|
||||||
.dbg_empty_stmt,
|
.dbg_empty_stmt,
|
||||||
.astgen_error,
|
.astgen_error,
|
||||||
|
.deprecated,
|
||||||
=> return,
|
=> return,
|
||||||
|
|
||||||
// `@TypeOf` has a body.
|
// `@TypeOf` has a body.
|
||||||
|
|||||||
@ -869,6 +869,7 @@ pub const cache_helpers = struct {
|
|||||||
hh.add(mod.sanitize_c);
|
hh.add(mod.sanitize_c);
|
||||||
hh.add(mod.sanitize_thread);
|
hh.add(mod.sanitize_thread);
|
||||||
hh.add(mod.fuzz);
|
hh.add(mod.fuzz);
|
||||||
|
hh.add(mod.allow_deprecated);
|
||||||
hh.add(mod.unwind_tables);
|
hh.add(mod.unwind_tables);
|
||||||
hh.add(mod.structured_cfg);
|
hh.add(mod.structured_cfg);
|
||||||
hh.add(mod.no_builtin);
|
hh.add(mod.no_builtin);
|
||||||
|
|||||||
@ -27,6 +27,7 @@ red_zone: bool,
|
|||||||
sanitize_c: bool,
|
sanitize_c: bool,
|
||||||
sanitize_thread: bool,
|
sanitize_thread: bool,
|
||||||
fuzz: bool,
|
fuzz: bool,
|
||||||
|
allow_deprecated: bool,
|
||||||
unwind_tables: std.builtin.UnwindTables,
|
unwind_tables: std.builtin.UnwindTables,
|
||||||
cc_argv: []const []const u8,
|
cc_argv: []const []const u8,
|
||||||
/// (SPIR-V) whether to generate a structured control flow graph or not
|
/// (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_c: ?bool = null,
|
||||||
sanitize_thread: ?bool = null,
|
sanitize_thread: ?bool = null,
|
||||||
fuzz: ?bool = null,
|
fuzz: ?bool = null,
|
||||||
|
allow_deprecated: ?bool = null,
|
||||||
structured_cfg: ?bool = null,
|
structured_cfg: ?bool = null,
|
||||||
no_builtin: ?bool = null,
|
no_builtin: ?bool = null,
|
||||||
};
|
};
|
||||||
@ -234,6 +236,11 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
|
|||||||
break :b false;
|
break :b false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const allow_deprecated = b: {
|
||||||
|
if (options.inherited.allow_deprecated) |x| break :b x;
|
||||||
|
break :b false;
|
||||||
|
};
|
||||||
|
|
||||||
const code_model = b: {
|
const code_model = b: {
|
||||||
if (options.inherited.code_model) |x| break :b x;
|
if (options.inherited.code_model) |x| break :b x;
|
||||||
if (options.parent) |p| break :b p.code_model;
|
if (options.parent) |p| break :b p.code_model;
|
||||||
@ -380,6 +387,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
|
|||||||
.sanitize_c = sanitize_c,
|
.sanitize_c = sanitize_c,
|
||||||
.sanitize_thread = sanitize_thread,
|
.sanitize_thread = sanitize_thread,
|
||||||
.fuzz = fuzz,
|
.fuzz = fuzz,
|
||||||
|
.allow_deprecated = allow_deprecated,
|
||||||
.unwind_tables = unwind_tables,
|
.unwind_tables = unwind_tables,
|
||||||
.cc_argv = options.cc_argv,
|
.cc_argv = options.cc_argv,
|
||||||
.structured_cfg = structured_cfg,
|
.structured_cfg = structured_cfg,
|
||||||
@ -474,6 +482,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
|
|||||||
.sanitize_c = sanitize_c,
|
.sanitize_c = sanitize_c,
|
||||||
.sanitize_thread = sanitize_thread,
|
.sanitize_thread = sanitize_thread,
|
||||||
.fuzz = fuzz,
|
.fuzz = fuzz,
|
||||||
|
.allow_deprecated = allow_deprecated,
|
||||||
.unwind_tables = unwind_tables,
|
.unwind_tables = unwind_tables,
|
||||||
.cc_argv = &.{},
|
.cc_argv = &.{},
|
||||||
.structured_cfg = structured_cfg,
|
.structured_cfg = structured_cfg,
|
||||||
@ -532,6 +541,7 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P
|
|||||||
.sanitize_c = undefined,
|
.sanitize_c = undefined,
|
||||||
.sanitize_thread = undefined,
|
.sanitize_thread = undefined,
|
||||||
.fuzz = undefined,
|
.fuzz = undefined,
|
||||||
|
.allow_deprecated = undefined,
|
||||||
.unwind_tables = undefined,
|
.unwind_tables = undefined,
|
||||||
.cc_argv = undefined,
|
.cc_argv = undefined,
|
||||||
.structured_cfg = undefined,
|
.structured_cfg = undefined,
|
||||||
|
|||||||
11
src/Sema.zig
11
src/Sema.zig
@ -1091,6 +1091,7 @@ fn analyzeBodyInner(
|
|||||||
const map = &sema.inst_map;
|
const map = &sema.inst_map;
|
||||||
const tags = sema.code.instructions.items(.tag);
|
const tags = sema.code.instructions.items(.tag);
|
||||||
const datas = sema.code.instructions.items(.data);
|
const datas = sema.code.instructions.items(.data);
|
||||||
|
const mod = block.ownerModule();
|
||||||
|
|
||||||
var crash_info = crash_report.prepAnalyzeBody(sema, block, body);
|
var crash_info = crash_report.prepAnalyzeBody(sema, block, body);
|
||||||
crash_info.push();
|
crash_info.push();
|
||||||
@ -1404,6 +1405,16 @@ fn analyzeBodyInner(
|
|||||||
i += 1;
|
i += 1;
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
|
.deprecated => {
|
||||||
|
if (!mod.allow_deprecated) {
|
||||||
|
const src_node: i32 = @bitCast(extended.operand);
|
||||||
|
const src = block.nodeOffset(src_node);
|
||||||
|
return sema.fail(block, src, "reached deprecated code", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
},
|
||||||
.disable_instrumentation => {
|
.disable_instrumentation => {
|
||||||
try sema.zirDisableInstrumentation();
|
try sema.zirDisableInstrumentation();
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|||||||
@ -520,6 +520,8 @@ const usage_build_generic =
|
|||||||
\\ -fno-sanitize-thread Disable Thread Sanitizer
|
\\ -fno-sanitize-thread Disable Thread Sanitizer
|
||||||
\\ -ffuzz Enable fuzz testing instrumentation
|
\\ -ffuzz Enable fuzz testing instrumentation
|
||||||
\\ -fno-fuzz Disable 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
|
\\ -funwind-tables Always produce unwind table entries for all functions
|
||||||
\\ -fasync-unwind-tables Always produce asynchronous 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
|
\\ -fno-unwind-tables Never produce unwind table entries
|
||||||
@ -1454,6 +1456,10 @@ fn buildOutputType(
|
|||||||
mod_opts.fuzz = true;
|
mod_opts.fuzz = true;
|
||||||
} else if (mem.eql(u8, arg, "-fno-fuzz")) {
|
} else if (mem.eql(u8, arg, "-fno-fuzz")) {
|
||||||
mod_opts.fuzz = false;
|
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")) {
|
} else if (mem.eql(u8, arg, "-fllvm")) {
|
||||||
create_module.opts.use_llvm = true;
|
create_module.opts.use_llvm = true;
|
||||||
} else if (mem.eql(u8, arg, "-fno-llvm")) {
|
} else if (mem.eql(u8, arg, "-fno-llvm")) {
|
||||||
|
|||||||
@ -535,6 +535,7 @@ const Writer = struct {
|
|||||||
.c_va_start,
|
.c_va_start,
|
||||||
.in_comptime,
|
.in_comptime,
|
||||||
.value_placeholder,
|
.value_placeholder,
|
||||||
|
.deprecated,
|
||||||
=> try self.writeExtNode(stream, extended),
|
=> try self.writeExtNode(stream, extended),
|
||||||
|
|
||||||
.builtin_src => {
|
.builtin_src => {
|
||||||
|
|||||||
9
test/cases/compile_errors/deprecated.zig
Normal file
9
test/cases/compile_errors/deprecated.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const bad = @deprecated(42);
|
||||||
|
|
||||||
|
pub export fn foo() usize {
|
||||||
|
return bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
//
|
||||||
|
// :1:13: error: reached deprecated code
|
||||||
@ -1176,6 +1176,100 @@ pub fn addCliTests(b: *std.Build) *Step {
|
|||||||
step.dependOn(&cleanup.step);
|
step.dependOn(&cleanup.step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Test `zig build -fallow-deprecated`.
|
||||||
|
|
||||||
|
const deprecated_check: std.Build.Step.Run.StdIo.Check = .{
|
||||||
|
.expect_stderr_match = "reached deprecated code",
|
||||||
|
};
|
||||||
|
|
||||||
|
const tmp_path = b.makeTempPath();
|
||||||
|
|
||||||
|
// create custom main.zig file containing a deprecated decl
|
||||||
|
{
|
||||||
|
const new_main_src =
|
||||||
|
\\const bad = @deprecated(42);
|
||||||
|
\\
|
||||||
|
\\pub fn main() u8 {
|
||||||
|
\\ return bad;
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
\\test {
|
||||||
|
\\ if (bad != 42) return error.Bad;
|
||||||
|
\\}
|
||||||
|
;
|
||||||
|
|
||||||
|
var src_dir = std.fs.cwd().makeOpenPath(b.pathJoin(&.{ tmp_path, "src" }), .{}) catch @panic("unable to create tmp path");
|
||||||
|
defer src_dir.close();
|
||||||
|
|
||||||
|
var main = src_dir.createFile("main.zig", .{}) catch @panic("unable to create main.zig");
|
||||||
|
defer main.close();
|
||||||
|
|
||||||
|
main.writeAll(new_main_src) catch @panic("unable to write to main.zig");
|
||||||
|
}
|
||||||
|
|
||||||
|
const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init" });
|
||||||
|
init_exe.setCwd(.{ .cwd_relative = tmp_path });
|
||||||
|
init_exe.setName("zig init");
|
||||||
|
init_exe.expectStdOutEqual("");
|
||||||
|
init_exe.expectStdErrEqual("info: created build.zig\n" ++
|
||||||
|
"info: created build.zig.zon\n" ++
|
||||||
|
"info: preserving already existing file: src" ++ s ++ "main.zig\n" ++
|
||||||
|
"info: created src" ++ s ++ "root.zig\n");
|
||||||
|
|
||||||
|
const run_test_bad = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "test", "--color", "off" });
|
||||||
|
run_test_bad.setCwd(.{ .cwd_relative = tmp_path });
|
||||||
|
run_test_bad.setName("zig build test");
|
||||||
|
run_test_bad.expectExitCode(1);
|
||||||
|
run_test_bad.expectStdOutEqual("");
|
||||||
|
run_test_bad.addCheck(deprecated_check);
|
||||||
|
run_test_bad.step.dependOn(&init_exe.step);
|
||||||
|
|
||||||
|
const run_test = b.addSystemCommand(&.{
|
||||||
|
b.graph.zig_exe,
|
||||||
|
"build",
|
||||||
|
"test",
|
||||||
|
"--color",
|
||||||
|
"off",
|
||||||
|
"-fallow-deprecated",
|
||||||
|
});
|
||||||
|
run_test.setCwd(.{ .cwd_relative = tmp_path });
|
||||||
|
run_test.setName("zig build test");
|
||||||
|
run_test.expectExitCode(0);
|
||||||
|
run_test.expectStdOutEqual("");
|
||||||
|
run_test.expectStdErrEqual("");
|
||||||
|
run_test.step.dependOn(&init_exe.step);
|
||||||
|
|
||||||
|
const run_build_bad = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "--color", "off" });
|
||||||
|
run_build_bad.setCwd(.{ .cwd_relative = tmp_path });
|
||||||
|
run_build_bad.setName("zig build test");
|
||||||
|
run_build_bad.expectExitCode(1);
|
||||||
|
run_build_bad.expectStdOutEqual("");
|
||||||
|
run_build_bad.addCheck(deprecated_check);
|
||||||
|
run_build_bad.step.dependOn(&init_exe.step);
|
||||||
|
|
||||||
|
const run_build = b.addSystemCommand(&.{
|
||||||
|
b.graph.zig_exe,
|
||||||
|
"build",
|
||||||
|
"--color",
|
||||||
|
"off",
|
||||||
|
"-fallow-deprecated",
|
||||||
|
});
|
||||||
|
run_build.setCwd(.{ .cwd_relative = tmp_path });
|
||||||
|
run_build.setName("zig build test");
|
||||||
|
run_build.expectExitCode(0);
|
||||||
|
run_build.expectStdOutEqual("");
|
||||||
|
run_build.expectStdErrEqual("");
|
||||||
|
run_build.step.dependOn(&init_exe.step);
|
||||||
|
|
||||||
|
const cleanup = b.addRemoveDirTree(.{ .cwd_relative = tmp_path });
|
||||||
|
cleanup.step.dependOn(&run_test.step);
|
||||||
|
cleanup.step.dependOn(&run_test_bad.step);
|
||||||
|
cleanup.step.dependOn(&run_build.step);
|
||||||
|
cleanup.step.dependOn(&run_build_bad.step);
|
||||||
|
|
||||||
|
step.dependOn(&cleanup.step);
|
||||||
|
}
|
||||||
// Test Godbolt API
|
// Test Godbolt API
|
||||||
if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {
|
if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {
|
||||||
const tmp_path = b.makeTempPath();
|
const tmp_path = b.makeTempPath();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user