Re: [PATCH] rust: proc-macro2: enable `proc_macro_span` feature
From: Gary Guo
Date: Mon Sep 28 2026 - 07:31:26 EST
On Mon Sep 28, 2026 at 10:31 AM BST, Miguel Ojeda wrote:
> On Mon, Sep 21, 2026 at 1:57 PM Gary Guo <gary@xxxxxxxxxx> wrote:
>>
>> Miguel, please let me know if you're okay with the proc-macro2
>> modification.
>>
>> I'd like to take this via pin-init-next if possible.
>
> If you think the diagnostics improvements are worth it, then I guess
> it is fine. The ones in the commit message do not seem like a big
> deal, but I assume the upcoming ones you mention in pin-init are
> bigger improvements?
Some examples from pin-init's diagnostics test suite (latest development tree,
w/ selfref feature):
Suggestion not matching the quoted span:
error: expected nothing or `..Zeroable::init_zeroed()`.
--> tests/ui/compile-fail/zeroable/invalid_spread.rs:15:11
|
15 | ..MyZeroable::init_zeroed()
| ^^^^^^^^^^
vs:
error: expected nothing or `..Zeroable::init_zeroed()`.
--> tests/ui/compile-fail/zeroable/invalid_spread.rs:15:9
|
15 | ..MyZeroable::init_zeroed()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Attribute diagnostics confusingly point to the `#`:
error: `#[pin]` attribute specified more than once
--> tests/ui/compile-fail/pin_data/twice_pin.rs:6:5
|
6 | #[pin]
| ^
vs:
error: `#[pin]` attribute specified more than once
--> tests/ui/compile-fail/pin_data/twice_pin.rs:6:5
|
6 | #[pin]
| ^^^^^^
Self-ref pin-init variance check points to the ADT that is not the problem. In
this case, the `dyn` is causing invariance. There's no way to actually point to
that specific part, so pin-init wants to point to the whole type and let user
decide. Without `join`, we can only point to the first token, which may confuse
user to think that is the issue:
error: lifetime may not live long enough
--> tests/ui/compile-fail/pin_data/selfref_covariant_check.rs:5:14
|
3 | #[pin_data]
| ----------- in this procedural macro expansion
4 | struct SelfRef {
5 | not_cov: Box<dyn Fn(&'str str) -> bool + 'str>,
| ^^^
| |
| lifetime `'__short` defined here
| lifetime `'__long` defined here
| function was supposed to return data with lifetime `'__long` but it is returning data with lifetime `'__short`
|
= help: consider adding the following bound: `'__short: '__long`
= note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info)
vs:
error: lifetime may not live long enough
--> tests/ui/compile-fail/pin_data/selfref_covariant_check.rs:5:14
|
3 | #[pin_data]
| ----------- in this procedural macro expansion
4 | struct SelfRef {
5 | not_cov: Box<dyn Fn(&'str str) -> bool + 'str>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| lifetime `'__short` defined here
| lifetime `'__long` defined here
| function was supposed to return data with lifetime `'__long` but it is returning data with lifetime `'__short`
|
= help: consider adding the following bound: `'__short: '__long`
= note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info)
For some spans we try to point to the full operation, where first span can be
confusing to user:
error[E0277]: `?` couldn't convert the error to `std::alloc::AllocError`
--> tests/ui/compile-fail/init/no_error_coercion.rs:18:15
|
18 | bar <- init!(Bar { b: 42 }),
| --^
| | |
| | the trait `From<Infallible>` is not implemented for `std::alloc::AllocError`
| this can't be annotated with `?` because it has type `Result<_, Infallible>`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= note: this error originates in the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info)
vs:
error[E0277]: `?` couldn't convert the error to `std::alloc::AllocError`
--> tests/ui/compile-fail/init/no_error_coercion.rs:18:15
|
18 | bar <- init!(Bar { b: 42 }),
| --^------------------------
| | |
| | the trait `From<Infallible>` is not implemented for `std::alloc::AllocError`
| this can't be annotated with `?` because it has type `Result<_, Infallible>`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= note: this error originates in the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info)
Another thing is that pin-init's diagnostics test suite is built with Cargo,
and the build script of proc-macro2 will probe if the nightly feature is
available and enable proc_macro_span automatically. So if this is not enabled on
RfL side, the diagnostics can diverge from what we expect.
I think the self-ref one is the main motivating factor, because the diagnostics
with that can be confusing in general. That said, I have improved it much over
the last week, it seems that it is not *that* needed anymore.
So, none of these are really big deals and that can be said to diagnostics in
general. But I think the change needed here is small enough that any improvement
can be used to justify that. I also submitted the proc-macro2 change upstream
too: https://github.com/dtolnay/proc-macro2/pull/542; if that is merged and we
later update proc-macro2, we should get down to just a single Makefile line
change.
Best,
Gary
>
> (I would also probably had shown the improved example outputs in the
> commit message for comparison; and especially one of the upcoming ones
> if those are more important to get right)
>
> If so, then please feel free to pick it up, thanks! The change itself
> looks good.
>
> Link: https://github.com/rust-lang/rust/issues/54725
>
> I would also wrap the `README.md` like
>
> identifiers, to remove the `unicode-ident` dependency, and to build
> with 1.85 with nightly features enabled.
>
> to keep it like the previous lines.
>
> Nit: "a overall" -> "an overall"
>
> Cheers,
> Miguel