diff --git a/build.rs b/build.rs index deb9b927..89e2ab39 100644 --- a/build.rs +++ b/build.rs @@ -14,6 +14,10 @@ // procmacro2_semver_exempt surface area is implemented by using the // nightly-only proc_macro API. // +// "hygiene" +// Enable Span::mixed_site() and non-dummy behavior of Span::resolved_at +// and Span::located_at. Enabled on Rust 1.45+. +// // "proc_macro_span" // Enable non-dummy behavior of Span::start and Span::end methods which // requires an unstable compiler feature. Enabled when building with @@ -57,6 +61,10 @@ fn main() { println!("cargo:rustc-cfg=span_locations"); } + if version.minor >= 45 { + println!("cargo:rustc-cfg=hygiene"); + } + let target = env::var("TARGET").unwrap(); if !enable_use_proc_macro(&target) { return; diff --git a/src/fallback.rs b/src/fallback.rs index fffea68f..eac975f2 100644 --- a/src/fallback.rs +++ b/src/fallback.rs @@ -374,24 +374,24 @@ impl Span { Span { lo: 0, hi: 0 } } - #[cfg(procmacro2_semver_exempt)] - pub fn def_site() -> Span { + #[cfg(hygiene)] + pub fn mixed_site() -> Span { Span::call_site() } #[cfg(procmacro2_semver_exempt)] - pub fn resolved_at(&self, _other: Span) -> Span { - // Stable spans consist only of line/column information, so - // `resolved_at` and `located_at` only select which span the - // caller wants line/column information from. - *self + pub fn def_site() -> Span { + Span::call_site() } - #[cfg(procmacro2_semver_exempt)] - pub fn located_at(&self, other: Span) -> Span { + pub fn resolved_at(&self, other: Span) -> Span { other } + pub fn located_at(&self, _other: Span) -> Span { + *self + } + #[cfg(procmacro2_semver_exempt)] pub fn source_file(&self) -> SourceFile { SOURCE_MAP.with(|cm| { diff --git a/src/lib.rs b/src/lib.rs index 23b2c266..98ba5950 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -348,6 +348,16 @@ impl Span { Span::_new(imp::Span::call_site()) } + /// The span located at the invocation of the procedural macro, but with + /// local variables, labels, and `$crate` resolved at the definition site + /// of the macro. This is the same hygiene behavior as `macro_rules`. + /// + /// This function requires Rust 1.45 or later. + #[cfg(hygiene)] + pub fn mixed_site() -> Span { + Span::_new(imp::Span::mixed_site()) + } + /// A span that resolves at the macro definition site. /// /// This method is semver exempt and not exposed by default. @@ -359,8 +369,8 @@ impl Span { /// Creates a new span with the same line/column information as `self` but /// that resolves symbols as though it were at `other`. /// - /// This method is semver exempt and not exposed by default. - #[cfg(procmacro2_semver_exempt)] + /// On versions of Rust prior to 1.45, this returns `other` to preserve the + /// name resolution behavior while discarding location information. pub fn resolved_at(&self, other: Span) -> Span { Span::_new(self.inner.resolved_at(other.inner)) } @@ -368,8 +378,8 @@ impl Span { /// Creates a new span with the same name resolution behavior as `self` but /// with the line/column information of `other`. /// - /// This method is semver exempt and not exposed by default. - #[cfg(procmacro2_semver_exempt)] + /// On versions of Rust prior to 1.45, this returns `self` to preserve the + /// name resolution behavior while discarding location information. pub fn located_at(&self, other: Span) -> Span { Span::_new(self.inner.located_at(other.inner)) } diff --git a/src/wrapper.rs b/src/wrapper.rs index 1887d8e2..32c71fad 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -376,6 +376,15 @@ impl Span { } } + #[cfg(hygiene)] + pub fn mixed_site() -> Span { + if inside_proc_macro() { + Span::Compiler(proc_macro::Span::mixed_site()) + } else { + Span::Fallback(fallback::Span::mixed_site()) + } + } + #[cfg(super_unstable)] pub fn def_site() -> Span { if inside_proc_macro() { @@ -385,19 +394,29 @@ impl Span { } } - #[cfg(super_unstable)] pub fn resolved_at(&self, other: Span) -> Span { match (self, other) { + #[cfg(hygiene)] (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.resolved_at(b)), + + // Name resolution affects semantics, but location is only cosmetic + #[cfg(not(hygiene))] + (Span::Compiler(_), Span::Compiler(_)) => other, + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.resolved_at(b)), _ => mismatch(), } } - #[cfg(super_unstable)] pub fn located_at(&self, other: Span) -> Span { match (self, other) { + #[cfg(hygiene)] (Span::Compiler(a), Span::Compiler(b)) => Span::Compiler(a.located_at(b)), + + // Name resolution affects semantics, but location is only cosmetic + #[cfg(not(hygiene))] + (Span::Compiler(_), Span::Compiler(_)) => *self, + (Span::Fallback(a), Span::Fallback(b)) => Span::Fallback(a.located_at(b)), _ => mismatch(), }