Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement @deprecated #22898

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

kristoff-it
Copy link
Member

Implements #22822

The part I'm most unsure about this implementation relates to how the build system represents -fallow-deprecated and -fno-allow-deprecated internally and how then this is reflected in the CLI invocation of build-exe and related subcommands.

@@ -284,6 +285,7 @@ pub fn init(
.owner = owner,
.root_source_file = if (options.root_source_file) |lp| lp.dupe(owner) else null,
.import_table = .{},
.allow_deprecated = owner.graph.allow_deprecated orelse !owner.is_root,
Copy link
Member Author

@kristoff-it kristoff-it Feb 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this version of the code modules track individually whether they're allowed to use deprecated code or not, giving to users the option of overriding the default behavior. See later comments for an alternative way of approaching this, although AFAIK it's not possible to make this system fully abuse-proof.

@@ -94,6 +94,9 @@ available_deps: AvailableDeps,

release_mode: ReleaseMode,

// True only for the top-level builder.
is_root: bool = false,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I'm aware whichever way this functionality is implemented requires tracking this information, which could be abused by users, for example by making the root builder forget that it's the root one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that while this could be abused, there's no way around it.

@@ -557,6 +559,10 @@ pub fn appendZigProcessFlags(
try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC");
try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone");

if (m.root_source_file != null) {
try addFlag(zig_args, m.allow_deprecated, "-fallow-deprecated", "-fno-allow-deprecated");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's desirable to prevent individual modules in the Zig build system from overriding their allow-deprecated behavior, here we could instead check the is_root property of the builder that owns m.

As mentioned earlier this would not be a full solution though, since the root builder could be modified by the user.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a better idea. It's not so much that we want to stop people from sneakily changing the field; it's more that this is just a simpler way to do it (don't duplicate data needlessly!).

I definitely don't think the build system should support changing this flag on a per-module basis for now; assume YAGNI.

@@ -523,6 +523,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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only added these flags for zig build (in the build runner) and here for modules, which means that the flags can't be used directly with zig build-exe or zig run.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what you mean here. What you've changed here is the usage string and arg handling loop for build-exe, run, etc. Clearly you can pass this to build-exe; otherwise, the build system wouldn't be able to pass it. What did you mean by this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm saying that zig build-exe foo.zig -fallow-deprecated doesn't work, because that's a module flag, not a global flag.

Maybe a global flag is desirable but then I'm not sure if it's ok for all of those to have the same name.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not how this works. If you never use -M, there's effectively an implicit -Mroot=the_source_file_you_passed at the end. If per-module flags didn't work with an implicit root module, then huge chunks of the compiler usage would be broken.

mlugg suggested a better way of implementing analysis of an istruction
that cannot be referenced by other instructions.
@andrewrk
Copy link
Member

Can't wait to use this immediately, like this:

    if (std.meta.hasMethod(T, "format")) {
        if (fmt.len > 0 and fmt[0] == 'f') {
            return value.format(fmt[1..], options, bw);
        } else {
            @deprecated();
            // After 0.14.0 is tagged, uncomment this next line:
            //@compileError("ambiguous format string; specify {f} to call format method, or {any} to skip it");
            //and then delete the `hasMethod` condition
            return value.format(fmt, options, bw);
        }
    }

@kristoff-it
Copy link
Member Author

@andrewrk rewiew it and it's all yours :^)

<pre>{#syntax#}@deprecated() void{#endsyntax#}</pre>
<p>
Used to mark a given code path as deprecated. It evaluates to the same value
passed in as argument, or the {#syntax#}void{#endsyntax#} value when given none.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
passed in as argument, or the {#syntax#}void{#endsyntax#} value when given none.
passed in as argument, or to {#syntax#}{}{#endsyntax#} value when no argument is given.

Mainly the first bit; "the void value" reads like it might literally mean void

Comment on lines +4752 to +4758
As an example, in Zig 0.14.0 {#syntax#}std.time.sleep{#endsyntax#} was
deprecated and the sleep function was moved to {#syntax#}std.Thread.sleep{#endsyntax#}.
This is how this deprecation could have been expressed:

{#syntax_block|zig|lib/std/time.zig#}
pub const sleep = @deprecated(std.Thread.sleep); // moved
{#end_syntax_block#}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The langref ought not to refer to specific old deprecations IMO. Perhaps:

Suggested change
As an example, in Zig 0.14.0 {#syntax#}std.time.sleep{#endsyntax#} was
deprecated and the sleep function was moved to {#syntax#}std.Thread.sleep{#endsyntax#}.
This is how this deprecation could have been expressed:
{#syntax_block|zig|lib/std/time.zig#}
pub const sleep = @deprecated(std.Thread.sleep); // moved
{#end_syntax_block#}
For instance, consider a function which is moved to a different namespace, with a deprecated alias in the old namespace for compatibility. This is written as follows:
{#syntax_block|zig|old_namespace.zig#}
pub const my_function = @deprecated(new_namespace.my_function); // moved
{#end_syntax_block#}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, is it correct for syntax blocks to be inside a <p>? IIRC they should be outside of it, but I haven't checked.

{#end_syntax_block#}
</p>
<p>
By default it is a <b>compile error</b> to depend on deprecated code in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
By default it is a <b>compile error</b> to depend on deprecated code in
By default it is a <b>compile error</b> to reference deprecated code in

"depend on" is vague

</p>

<p>
{#syntax#}@deprecated{#endsyntax#} can also be used without argument:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{#syntax#}@deprecated{#endsyntax#} can also be used without argument:
Using {#syntax#}@deprecated{#endsyntax#} without an argument can be useful inside of blocks:

We already know this usage exists; more helpfully, say why it exists!

@@ -557,6 +559,10 @@ pub fn appendZigProcessFlags(
try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC");
try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone");

if (m.root_source_file != null) {
try addFlag(zig_args, m.allow_deprecated, "-fallow-deprecated", "-fno-allow-deprecated");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a better idea. It's not so much that we want to stop people from sneakily changing the field; it's more that this is just a simpler way to do it (don't duplicate data needlessly!).

I definitely don't think the build system should support changing this flag on a per-module basis for now; assume YAGNI.

@@ -523,6 +523,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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what you mean here. What you've changed here is the usage string and arg handling loop for build-exe, run, etc. Clearly you can pass this to build-exe; otherwise, the build system wouldn't be able to pass it. What did you mean by this?

Comment on lines +248 to +260
{
const case = ctx.obj("usage of deprecated code", b.graph.host);

case.addError(
\\const bad = @deprecated(42);
\\
\\pub export fn foo() usize {
\\ return bad;
\\}
, &[_][]const u8{
":1:13: error: found deprecated code",
});
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file should have a big comment at the top saying "DON'T PUT THINGS HERE" :P

Please put this test in test/cases/compile_errors/deprecated.zig (or something like that) instead.

Comment on lines +1171 to +1200
// Test `zig build -fallow-deprecated`.

const deprecated_check: std.Build.Step.Run.StdIo.Check = .{
.expect_stderr_match = "found 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 unreachable;
defer src_dir.close();

var main = src_dir.createFile("main.zig", .{}) catch unreachable;
defer main.close();

main.writeAll(new_main_src) catch unreachable;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't your fault, since you've just taken it from some of the surrounding cases, but... ooh, using std.fs in a build script is very naughty. I'm not gonna ask you to change this for now, though, since you're just following the surrounding cases.

However, these should be @panics, not unreachable; please do fix that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants