Skip to content

Continue resolving cargo-semver-checks blockers for merging into cargo #104

Open

Description

@nikomatsakis
Metadata
Contact @obi1kenobi
Team(s) cargo (@epage), rustdoc (@aDotInTheVoid)
Goal document 2026/cargo-semver-checks

Summary

Design and implement cargo-semver-checks functionality that lies on the critical path for merging the tool into cargo itself. Continues the work of the 2025h2 goal.


This issue is intended for status updates only.

For general questions or comments, please contact a goal owner or post in the Zulip topic.

Activity

  1. added this to the 2024h2 milestone on Jul 22, 2024
  2. locked and limited conversation to collaborators on Jul 25, 2024
  3. nikomatsakis commented on Jul 25, 2024

    @nikomatsakis
    ContributorAuthor

    This issue is intended for status updates only.

    For general questions or comments, please contact the owner(s) directly.

  4. obi1kenobi commented on Sep 1, 2024

    @obi1kenobi
    Member

    Status update as of September 1.

    Key developments: We've laid a lot of the groundwork to make manifest linting possible.

    • In preparation for the significant expansion of our CLI, we now have the ability to test how CLI invocations get interpreted internally. We can also now snapshot the output of any CLI invocation over a given workspace, allowing us to proceed with refactoring the implementation without breaking existing use cases.
    • We have a concrete design for the expansion of the CLI, and for the Trustfall schema changes that will be necessary to enable manifest linting.

    Not blocked on anything. No opportunities to contribute yet, but stay tuned — there will be some in future updates!

  5. obi1kenobi commented on Sep 17, 2024

    @obi1kenobi
    Member

    Status update as of September 17.

    Key developments: Working prototype of manifest querying.

    WIP branch here: https://github.com/obi1kenobi/trustfall-rustdoc-adapter/compare/manifest_querying

    An example SemVer lint this enables would be: "a non-nightly, non-underscore-prefixed feature has been removed from the package between releases."

    {
        CrateDiff {
            baseline {
                feature {
                    feature: name
                        @filter(op: "!=", value: ["$nightly"])
                        @tag
                        @output
                }
            }
    
            current {
                feature @fold @transform(op: "count") @filter(op: "=", value: ["$zero"]) {
                    name @filter(op: "=", value: ["%feature"])
                }
            }
        }
    }
    
    # args:
    {
        "nightly": "nightly",
        "zero": 0
    }

    This is SemVer-major because it'll break uses like: my_dep = { version = "1.0", features = ["removed_feature"] }. We're ignoring any features named nightly because community consensus is that such features are unstable — I'll do some more research on other expected-unstable feature patterns in the community before we ship any lints around this.

    Not blocked on anything. No opportunities to contribute yet, but stay tuned — there will be some in future updates!

  6. obi1kenobi commented on Sep 30, 2024

    @obi1kenobi
    Member

    No major updates to report. Preparing my talk for next week's EuroRust has taken away most of my free time.

  7. obi1kenobi commented on Nov 20, 2024

    @obi1kenobi
    Member

    Key developments:

    • Partial schema design and implementation of type information in lints
    • Resolved multi-team questions that were blocking cross-crate checking
    • Refactor of cargo-semver-checks data handling to enable supporting manifest information

    Partial schema design and implementation of type information in lints

    The schema we use for writing lints now contains information on:

    This newly allows the implementation of breaking-change lints such as "generic const parameter no longer has default value" or "trait bound removed from generic parameter in trait method."

    Additionally, @suaviloquence has implemented the ability to print rustdoc JSON type information into human-readable source code form, which will allow us to produce higher-quality diagnostics for type-related breaking changes. This required a lot of care, perseverance, and testing — thank you 🙏

    Resolved multi-team questions that were blocking cross-crate checking

    For a long time, cross-crate checking was blocked on a multi-team coordination problem: cargo-semver-checks needs more data from rustdoc, which in turn needs more data from rustc. This was a classic "everyone's third-most important thing" problem: important, but not critical and therefore never top of the agenda for resolving the open questions there.

    In-person meetings with Rust Project members during my trips to RustConf and EuroRust helped nudge this forward:

    • The compiler team MCP intended to provide additional data to rustdoc was merged and can now be implemented.
    • I synced up with T-rustdoc members on how rustdoc would then present that data to cargo-semver-checks in rustdoc JSON. Along the way, we were able to discuss and agree on several additional improvements to rustdoc JSON that improved performance in cargo-semver-checks.

    Refactor of cargo-semver-checks data handling

    Plumbing in manifest information was proving challenging due to a significant amount of tech debt accrued in the cargo-semver-checks code that loads the data of scanned crates. This PR is a significant clean-up and refactor of that portion of the tool, allowing us to move forward with retrieving manifest information while also supporting other quality-of-life improvements.

    With the mountain of tech debt largely resolved, I expect that adding manifest information should be relatively straightforward from here.

    This portion of the goal also greatly benefited from the Google Summer of Code work that @suaviloquence did — it wouldn't have been possible without the significant effort he put into improving our test suites and harnesses.

  8. obi1kenobi commented on Dec 1, 2024

    @obi1kenobi
    Member

    Key developments:

    Cargo manifest linting

    As a recap, the idea here is catching breakage caused by manifest (Cargo.toml) changes, not just source code changes.

    An example of such breakage is the removal of a package feature: any crates that enabled the removed feature will no longer build.

    The PR above builds upon the data-handling refactor from the previous update post, and makes it possible to lint manifests for breaking changes. The PR includes the feature_missing lint that checks for the exact case mentioned above. That is but one of many new lints that are now possible with this feature. Hooray! 🎉

  9. modified the milestones: 2024h2, 2025h1 on Feb 18, 2025
  10. nikomatsakis commented on Feb 18, 2025

    @nikomatsakis
    ContributorAuthor

    This is a continuing project goal, and the updates below this comment will be for the new period 2025h1

  11. obi1kenobi commented on Feb 19, 2025

    @obi1kenobi
    Member

    Thanks, Niko! Copying in the new tasks from the 2025h1 period:

    • Prototype cross-crate linting using workarounds (@obi1kenobi)
    • Allow linting generic types, lifetimes, bounds (@obi1kenobi)
    • Handle "special cases" like 'static and ?Sized (@obi1kenobi)
    • Handle #[doc(hidden)] in sealed trait analysis (@obi1kenobi)
    • Discussion and moral support (cargo, [rustdoc]
  12. 15 remaining items

  13. deleted a comment from nikomatsakis on Sep 19, 2025
  14. obi1kenobi commented on Sep 19, 2025

    @obi1kenobi
    Member

    Just removed the duplicate posts, guessing from a script that had a bad day.

  15. obi1kenobi commented on Nov 2, 2025

    @obi1kenobi
    Member

    Status update as of November 1

    Key developments:

    Linting ?Sized and 'static bounds turned out to be quite a bit more complex than I anticipated. The key issue is that seeing T: Foo + ?Sized does not guarantee that T can be unsized, since we might have Foo: Sized which renders the ?Sized relaxation ineffective. Similarly, seeing T: Foo might also non-obviously imply T: 'static via a similar implied bound.

    Failure to correctly account for implied bounds would lead to catastrophic false-positives and false-negatives. For example, changing T: Foo to T: Foo + 'static could be a major breaking change or a no-op, depending on whether we have Foo: 'static (either directly or implicitly via other trait bounds).

    We cannot determine implied bounds using information present in rustdoc JSON today, so the rustdoc team and I have been iterating on the best way to compute and include that information in rustdoc JSON. Assuming something similar to the aforementioned PR becomes part of rustdoc JSON, cargo-semver-checks stands to gain several dozen new lints covering these tricky cases over trait associated types, generic type parameters, and APIT/RPIT/RPITIT.

  16. obi1kenobi commented on Nov 23, 2025

    @obi1kenobi
    Member

    Google Summer of Code 2025 is complete + finally some movement on cross-crate linting! 🚀

    Key developments

  17. obi1kenobi commented on Jan 17, 2026

    @obi1kenobi
    Member

    I posted a "year in review" for cargo-semver-checks here: https://predr.ag/blog/cargo-semver-checks-2025-year-in-review/

    It has a section on how I think we should move forward in 2026 and beyond: https://predr.ag/blog/cargo-semver-checks-2025-year-in-review/#the-path-forward-for-2026-and-beyond

  18. modified the milestones: 2025h2-goals, 2026 on May 5, 2026
  19. tomassedovic commented on May 5, 2026

    @tomassedovic
    Contributor

    This is a continuing project goal, and the updates below this comment will be for the new period 2026

  20. added
    ex-2025h2Goals that were previously in 2025h2 (for reporting)
    and removed on May 11, 2026
  21. obi1kenobi commented on Jun 17, 2026

    @obi1kenobi
    Member

    There's been significant internal progress. As I described in my year-end overview post, we're aiming to solve cargo-semver-checks' key limitations, which requires solving several hard problems at once.

    We're about 9000 lines of code deep into implementing a normalized type representation, a prerequisite for efficient type-checking lints. The gist of the idea is:

    • We want to detect when types may have changed, so we can trigger a type-checking run.
    • That type-checking run is fairly expensive: we need to generate a witness program, and run cargo check on it up to twice.
    • Rust has many ways to make syntactic changes to types that are semantically irrelevant. For example, consider renaming all 'a lifetimes to 'b — this shouldn't run type-checking, because nothing semantic changed so there cannot be a Semantic Versioning violation.

    We expect we're a handful of PRs away from having a suitable implementation of this normalization process. Our focus will then pivot toward cross-crate rustdoc JSON use, which will both address a number of false-positives and false-negatives per se, and is another prerequisite for type-checking lints.

    Engaging with these hard problems is also producing benefits for Rustaceans today. First, digging deeply into the codebase helps discover bugs and edge cases, and then it produces a perfect opportunity to address them. For example, here are a couple of fixes that will be part of the next cargo-semver-checks release:

  22. obi1kenobi commented on Aug 1, 2026

    @obi1kenobi
    Member

    At the request of Rust project members, we took a brief detour to implement breakage-checking for the Rust standard library. This work is very close to the finish line and involved about 15kLoC across 30+ PRs, largely in order to handle stability attributes correctly. I plan to publish a blog post on it when it's complete.

    Like in the previous post, this process also caused us to discover and fix pre-existing issues in cargo-semver-checks affecting users today. For example, two lints had existing false-positives fixed as a result of us reasoning through the (much more complex) edge cases of partial stability in the Rust standard library.

    Additionally, we also improved the type normalization code to be more robust to generic parameter additions or removals. Previously, all generic parameters of the same kind (types, lifetimes, consts) shared the same normalization namespace. This caused issues. By way of analogy:

    impl<A> Foo<A> {
        fn bar<B>(_: B) {}
    }

    If Foo gains another generic type parameter, that new parameter would get normalized to B instead. This would change the normalization of bar<B> into bar<C>, making it normalize differently ("appear to change"). This would have triggered many unnecessary witness checks and would have been tediously slow. With the latest fixes, generics on a parent scope no longer change the normalization of inner scopes' generics, avoiding this problem.

  23. obi1kenobi commented on Sep 27, 2026

    @obi1kenobi
    Member

    Given recent improvements in AI models' cybersecurity capabilities, I've pivoted toward hardening the cargo-semver-checks GitHub Actions security posture. This work is largely done for the main repo and its primary dependencies that I also maintain.

    As a smaller work item, I've also taken the opportunity to add SemVer lints for breakage related to variadic functions. That functionality will be stable in the upcoming Rust 1.99, which makes this the upcoming cargo-semver-checks release the first time we'll have effectively "day 1" SemVer linting support for a new language feature!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions