Skip to content

derive helpers not in attrs field in rustdoc json #157107

Closed

Description

@SwishSwushPow

Problem

This regression has been noticed when running the integration test of BuFFI after updating the toolchain from Rust 1.95.0 to 1.96.0.

For the functionality of BuFFI we rely on attribute information being provided in the output of rustdoc json which we parse using rustdoc-types. We are aware that this json output is unstable and we usually can adjust our side to keep track, but this time the version of rustdoc-types has not changed, yet it seems that some attribute information that was provided as part of Item objects seems to have vanished completely. After checking it I can confirm that it is not showing up in the rustdoc json output anymore.

Code

We have this enum in the example for BuFFI and we rely on the attributes to generate the correct FFI code.

#[derive(serde::Serialize, serde::Deserialize)]
pub enum RandomEnum {
    /// An empty case that is here to make the test simpler
    NoValue,
    /// A timestamp from chrono that we would like to use in the API
    TimeStamp(#[serde(with = "crate::DateTimeHelper")] DateTime<Utc>),
}

I have chosen this example because it is the point where the test currently fails. There are more types in the example that show the various ways how we make use of attributes. If necessary I can provide a smaller example where it is also visible that the attributes are not part of the rustdoc json anymore.

If we have a look at the case TimeStamp, we want to have information about the serde attribute.

After parsing the generated json with rustdoc-types and resolving it partially, before we had

...
attrs: [
    Other(
        "#[serde(with = \"crate::DateTimeHelper\")]",
    ),
],
...
dbg! output on 1.95.0
[buffi/src/lib.rs:1486:29] &t = Item {
    id: Id(
        126,
    ),
    crate_id: 0,
    name: Some(
        "0",
    ),
    span: Some(
        Span {
            filename: "example/buffi_example/src/lib.rs",
            begin: (
                69,
                56,
            ),
            end: (
                69,
                69,
            ),
        },
    ),
    visibility: Default,
    docs: None,
    links: {},
    attrs: [
        Other(
            "#[serde(with = \"crate::DateTimeHelper\")]",
        ),
    ],
    deprecation: None,
    inner: StructField(
        ResolvedPath(
            Path {
                path: "chrono::DateTime",
                id: Id(
                    94,
                ),
                args: Some(
                    AngleBracketed {
                        args: [
                            Type(
                                ResolvedPath(
                                    Path {
                                        path: "chrono::Utc",
                                        id: Id(
                                            95,
                                        ),
                                        args: None,
                                    },
                                ),
                            ),
                        ],
                        constraints: [],
                    },
                ),
            },
        ),
    ),
}

while now we get

...
attrs: [],
...
dbg! output on 1.96.0 (note the empty `attrs` field)
[buffi/src/lib.rs:1486:29] &t = Item {
    id: Id(
        126,
    ),
    crate_id: 0,
    name: Some(
        "0",
    ),
    span: Some(
        Span {
            filename: "example/buffi_example/src/lib.rs",
            begin: (
                69,
                56,
            ),
            end: (
                69,
                69,
            ),
        },
    ),
    visibility: Default,
    docs: None,
    links: {},
    attrs: [],
    deprecation: None,
    inner: StructField(
        ResolvedPath(
            Path {
                path: "chrono::DateTime",
                id: Id(
                    94,
                ),
                args: Some(
                    AngleBracketed {
                        args: [
                            Type(
                                ResolvedPath(
                                    Path {
                                        path: "chrono::Utc",
                                        id: Id(
                                            95,
                                        ),
                                        args: None,
                                    },
                                ),
                            ),
                        ],
                        constraints: [],
                    },
                ),
            },
        ),
    ),
}

Using cargo-bisect-rustc I was able to narrow down the problem to this commit eb9d3ca.

I think the relevat PR could be #153540.

Version it worked on

It most recently worked on: Rust 1.95.0

Version with regression

rustc --version --verbose:

rustc 1.96.0 (ac68faa20 2026-05-25)
binary: rustc
commit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96
commit-date: 2026-05-25
host: aarch64-apple-darwin
release: 1.96.0
LLVM version: 22.1.2

Pinging @aDotInTheVoid (we briefly chatted about BuFFI and its use of rustdoc json before) and @scrabsha (author of the PR listed above) because I think they could be interested in the regression and might be best suited to answer if that is intended or not. I hope that is ok. 😅

@rustbot modify labels: +regression-from-stable-to-stable -regression-untriaged

Activity

  1. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.
    and removed
    regression-untriagedUntriaged performance or correctness regression.
    on May 29, 2026
  2. scrabsha commented on May 29, 2026

    @scrabsha
    Contributor

    oh, i did not know derive helpers were exposed in rustdoc-json in the first place. my PR is indeed the culprit.

  3. added
    T-rustdocRelevant to the rustdoc team, which will review and decide on the PR/issue.
    A-attributesArea: Attributes (`#[…]`, `#![…]`)
    and removed
    T-rustdocRelevant to the rustdoc team, which will review and decide on the PR/issue.
    A-attributesArea: Attributes (`#[…]`, `#![…]`)
    regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.
    C-bugCategory: This is a bug.
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on May 29, 2026
  4. 14 remaining items

  5. JonathanBrouwer commented on May 30, 2026

    @JonathanBrouwer
    Member

    Made a PR but we can wait a little bit with merging this in case we can find a better solution
    #157150

  6. JonathanBrouwer commented on May 30, 2026

    @JonathanBrouwer
    Member

    No, you almost can and it would fix 99% of cases, but in the following specific case this wouldn't work:

    • An item has a derive helper attribute on the item itself
    • The item is re-exported publicly by another crate, and we're looking at the rustdoc-json output of this re-export

    The problem is that only the crate for which documentation is being generated has self.sess.actually_rustdoc set to true, the dependency crate doesn't

    Actually I'm not sure attributes from re-exports were ever forwarded for rustdoc-json, so maybe this approach works. I'll have more time to play around with this idea tomorrow, feel free to do it if you have time earlier @scrabsha

  7. scrabsha commented on May 30, 2026

    @scrabsha
    Contributor

    i'd prefer to dedicate my tomorrow to understanding how type inference work, happy to rubber duck around the actually_rustdoc approach though :)

  8. added a commit that references this issue on May 30, 2026
  9. obi1kenobi commented on May 30, 2026

    @obi1kenobi
    Member

    Derive helpers are often part of the public API contract and SemVer-relevant. The following is a SemVer-major breaking change:

      #[derive(Default)]
      pub enum Witness {
    -     #[default]
          A,
    +     #[default]
          B,
      }

    Nothing we can retroactively about this case unfortunately. But could I be in in the loop for future changes around removing or materially changing how rustdoc JSON data is represented?

    In particular I'm curious to understand more about the re-exports case, since cargo-semver-checks does track re-exports.

  10. JonathanBrouwer commented on May 30, 2026

    @JonathanBrouwer
    Member

    Derive helpers are often part of the public API contract and SemVer-relevant. The following is a SemVer-major breaking change:

      #[derive(Default)]
      pub enum Witness {
    -     #[default]
          A,
    +     #[default]
          B,
      }

    Nothing we can retroactively about this case unfortunately. But could I be in in the loop for future changes around removing or materially changing how rustdoc JSON data is represented?

    In particular I'm curious to understand more about the re-exports case, since cargo-semver-checks does track re-exports.

    This was an unintentional change to rustdoc-json which we will be reverting in #157150. I know you as someone who's interested in the format and I appreciate your work so would definitely have pinged you if this was intentional :)

  11. aDotInTheVoid commented on May 30, 2026

    @aDotInTheVoid
    Member

    Thanks for the report!

    Rustdoc-Json is a unstable feature that's only usable on nightly, not stable. While this is a bug with rustdoc-json, it's not a stable-to-stable regression.

    The item is re-exported publicly by another crate, and we're looking at the rustdoc-json output of this re-export

    This is fine, rustdoc-json doesn't inline items (unlike rustdoc-html), so we can rely on the fact that we're only generated documentation for local items, not cross-crate items.

  12. changed the title [-]`attrs` field empty in rustdoc json on Rust 1.96.0 (stable)[/-] [+]derive helpers not in `attrs` field in rustdoc json[/+] on May 30, 2026
  13. obi1kenobi commented on May 30, 2026

    @obi1kenobi
    Member
  14. SwishSwushPow commented on May 30, 2026

    @SwishSwushPow
    Author

    Thanks everyone for handling this so quickly. :)

    “Beta backport” means that this change would go into the 1.97.0 release already and not the 1.98.0 release, do I understand this correctly? In that case I would also be happy about a backport so that BuFFI can pick up the support sooner rather than later.

    Although I’m not 100% sure if that is still on the table since that comment seems to have vanished. 😁

    But in any case thanks again to everyone that chimed in!

  15. added a commit that references this issue on May 30, 2026
  16. added a commit that references this issue on May 30, 2026
  17. JonathanBrouwer commented on May 30, 2026

    @JonathanBrouwer
    Member

    Beta backport decision thread opened here: #t-compiler/backports > #157150: beta-nominated @ 💬

    “Beta backport” means that this change would go into the 1.97.0 release already and not the 1.98.0 release, do I understand this correctly?

    Yes

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

Metadata

Metadata

Labels

A-attributesArea: Attributes (`#[…]`, `#![…]`)A-rustdoc-jsonArea: Rustdoc JSON backendT-rustdocRelevant to the rustdoc team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions