From b8cab941478e4908a150b632c1f5e41d283bf4a8 Mon Sep 17 00:00:00 2001 From: Keith-Cancel Date: Tue, 25 Nov 2025 10:49:37 -0800 Subject: [PATCH 1/2] refresh labels From d255ff62505df9074adae023fd0e6a3efe025899 Mon Sep 17 00:00:00 2001 From: Keith-Cancel Date: Tue, 25 Nov 2025 12:58:33 -0800 Subject: [PATCH 2/2] Make `Group::span_open()` and Group::span_close()` more accurate after set_span call. This tries to recover the open in and close delimiter spans for the new span, otherwise it reverts to old behavior of using the the whole span for the open and close delimiter. --- library/proc_macro/src/lib.rs | 44 +++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 4efdfcad924b5..3bf29d56dfcd8 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -46,7 +46,7 @@ mod to_tokens; use core::ops::BitOr; use std::ffi::CStr; -use std::ops::{Range, RangeBounds}; +use std::ops::{Bound, Range, RangeBounds}; use std::path::PathBuf; use std::str::FromStr; use std::{error, fmt}; @@ -880,7 +880,47 @@ impl Group { /// tokens at the level of the `Group`. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn set_span(&mut self, span: Span) { - self.0.span = bridge::DelimSpan::from_single(span.0); + let (open_chr, close_chr) = match self.0.delimiter { + Delimiter::Brace => (b'{', b'}'), + Delimiter::Bracket => (b'[', b']'), + Delimiter::Parenthesis => (b'(', b')'), + Delimiter::None => { + // None delimiters are the whole span for open and close + // same behavior as in the compiler. + self.0.span = bridge::DelimSpan::from_single(span.0); + return; + } + }; + + // No source text to check or source text is too small. + // just go back to default behavior. + let source = match span.0.source_text() { + Some(s) if s.len() >= 2 => s, + _ => { + self.0.span = bridge::DelimSpan::from_single(span.0); + return; + } + }; + let src = source.as_bytes(); + + // Make sure that the last and first characters match up + if src[0] != open_chr || src[src.len() - 1] != close_chr { + self.0.span = bridge::DelimSpan::from_single(span.0); + return; + } + + // Compute the spans. + let Some(open) = span.0.subspan(Bound::Included(0), Bound::Excluded(1)) else { + self.0.span = bridge::DelimSpan::from_single(span.0); + return; + }; + + let Some(close) = span.0.subspan(Bound::Included(src.len() - 1), Bound::Unbounded) else { + self.0.span = bridge::DelimSpan::from_single(span.0); + return; + }; + + self.0.span = bridge::DelimSpan { open, close, entire: span.0 }; } }