From e09dfd48f2ac12a38898aa7812bd06935298d23f Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 24 Jan 2019 01:14:30 +0100 Subject: [PATCH 1/3] Make span location information available through a feature --- Cargo.toml | 3 +++ build.rs | 9 +++++++- src/fallback.rs | 56 +++++++++++++++++++++++++------------------------ src/lib.rs | 46 +++++++++++++++++++++++++--------------- src/strnom.rs | 6 +++--- 5 files changed, 72 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 929314e2..8e0b57a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,9 @@ quote = "0.6" proc-macro = [] default = ["proc-macro"] +# turns on location info on spans +span-location-info = [] + # This feature no longer means anything. nightly = [] diff --git a/build.rs b/build.rs index 6973ca77..d6f92550 100644 --- a/build.rs +++ b/build.rs @@ -55,14 +55,21 @@ fn main() { } println!("cargo:rustc-cfg=use_proc_macro"); + let mut span_location_info = cfg!(feature = "span-location-info"); + let semver_exempt = cfg!(procmacro2_semver_exempt); if semver_exempt { + span_location_info = true; // https://github.com/alexcrichton/proc-macro2/issues/147 println!("cargo:rustc-cfg=procmacro2_semver_exempt"); } + if span_location_info { + println!("cargo:rustc-cfg=span_location_info"); + } + // Rust 1.29 stabilized the necessary APIs in the `proc_macro` crate - if version.nightly || version.minor >= 29 && !semver_exempt { + if version.nightly || version.minor >= 29 && !(semver_exempt || span_location_info) { println!("cargo:rustc-cfg=wrap_proc_macro"); } diff --git a/src/fallback.rs b/src/fallback.rs index 7f3cc4e4..69d3e39b 100644 --- a/src/fallback.rs +++ b/src/fallback.rs @@ -1,12 +1,12 @@ -#![cfg_attr(not(procmacro2_semver_exempt), allow(dead_code))] +#![cfg_attr(not(any(procmacro2_semver_exempt, span_location_info)), allow(dead_code))] -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] use std::cell::RefCell; #[cfg(procmacro2_semver_exempt)] use std::cmp; use std::fmt; use std::iter; -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] use std::path::Path; use std::path::PathBuf; use std::str::FromStr; @@ -35,7 +35,7 @@ impl TokenStream { } } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] fn get_cursor(src: &str) -> Cursor { // Create a dummy file & add it to the codemap CODEMAP.with(|cm| { @@ -49,7 +49,7 @@ fn get_cursor(src: &str) -> Cursor { }) } -#[cfg(not(procmacro2_semver_exempt))] +#[cfg(not(span_location_info))] fn get_cursor(src: &str) -> Cursor { Cursor { rest: src } } @@ -225,7 +225,7 @@ pub struct LineColumn { pub column: usize, } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] thread_local! { static CODEMAP: RefCell = RefCell::new(Codemap { // NOTE: We start with a single dummy file which all call_site() and @@ -238,14 +238,14 @@ thread_local! { }); } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] struct FileInfo { name: String, span: Span, lines: Vec, } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] impl FileInfo { fn offset_line_column(&self, offset: usize) -> LineColumn { assert!(self.span_within(Span { @@ -271,7 +271,7 @@ impl FileInfo { } /// Computesthe offsets of each line in the given source string. -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] fn lines_offsets(s: &str) -> Vec { let mut lines = vec![0]; let mut prev = 0; @@ -282,12 +282,12 @@ fn lines_offsets(s: &str) -> Vec { lines } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] struct Codemap { files: Vec, } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] impl Codemap { fn next_start_pos(&self) -> u32 { // Add 1 so there's always space between files. @@ -327,19 +327,19 @@ impl Codemap { #[derive(Clone, Copy, PartialEq, Eq)] pub struct Span { - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] lo: u32, - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] hi: u32, } impl Span { - #[cfg(not(procmacro2_semver_exempt))] + #[cfg(not(span_location_info))] pub fn call_site() -> Span { Span {} } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn call_site() -> Span { Span { lo: 0, hi: 0 } } @@ -359,7 +359,7 @@ impl Span { other } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn source_file(&self) -> SourceFile { CODEMAP.with(|cm| { let cm = cm.borrow(); @@ -370,7 +370,7 @@ impl Span { }) } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn start(&self) -> LineColumn { CODEMAP.with(|cm| { let cm = cm.borrow(); @@ -379,7 +379,7 @@ impl Span { }) } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn end(&self) -> LineColumn { CODEMAP.with(|cm| { let cm = cm.borrow(); @@ -406,16 +406,16 @@ impl Span { impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] return write!(f, "bytes({}..{})", self.lo, self.hi); - #[cfg(not(procmacro2_semver_exempt))] + #[cfg(not(span_location_info))] write!(f, "Span") } } pub fn debug_span_field_if_nontrivial(debug: &mut fmt::DebugStruct, span: Span) { - if cfg!(procmacro2_semver_exempt) { + if cfg!(span_location_info) { debug.field("span", &span); } } @@ -448,10 +448,12 @@ impl Group { self.span } + #[cfg(procmacro2_semver_exempt)] pub fn span_open(&self) -> Span { self.span } + #[cfg(procmacro2_semver_exempt)] pub fn span_close(&self) -> Span { self.span } @@ -483,7 +485,7 @@ impl fmt::Debug for Group { let mut debug = fmt.debug_struct("Group"); debug.field("delimiter", &self.delimiter); debug.field("stream", &self.stream); - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] debug.field("span", &self.span); debug.finish() } @@ -601,7 +603,7 @@ impl fmt::Display for Ident { impl fmt::Debug for Ident { // Ident(proc_macro), Ident(r#union) - #[cfg(not(procmacro2_semver_exempt))] + #[cfg(not(span_location_info))] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut debug = f.debug_tuple("Ident"); debug.field(&format_args!("{}", self)); @@ -612,7 +614,7 @@ impl fmt::Debug for Ident { // sym: proc_macro, // span: bytes(128..138) // } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut debug = f.debug_struct("Ident"); debug.field("sym", &format_args!("{}", self)); @@ -759,7 +761,7 @@ impl fmt::Debug for Literal { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut debug = fmt.debug_struct("Literal"); debug.field("lit", &format_args!("{}", self.text)); - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] debug.field("span", &self.span); debug.finish() } @@ -788,7 +790,7 @@ fn token_stream(mut input: Cursor) -> PResult { Ok((input, TokenStream { inner: trees })) } -#[cfg(not(procmacro2_semver_exempt))] +#[cfg(not(span_location_info))] fn spanned<'a, T>( input: Cursor<'a>, f: fn(Cursor<'a>) -> PResult<'a, T>, @@ -797,7 +799,7 @@ fn spanned<'a, T>( Ok((a, ((b, ::Span::_new_stable(Span {}))))) } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] fn spanned<'a, T>( input: Cursor<'a>, f: fn(Cursor<'a>) -> PResult<'a, T>, diff --git a/src/lib.rs b/src/lib.rs index 70b25e98..863d116b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,6 +55,12 @@ //! propagate parse errors correctly back to the compiler when parsing fails. //! //! [`parse_macro_input!`]: https://docs.rs/syn/0.15/syn/macro.parse_macro_input.html +//! +//! # Opt-in features +//! +//! Location information on spans is currently disabled by default and can be +//! enabled with the `span-location-info` flag. This feature is automatically +//! enabled with `procmacro2_semver_exempt`. //! //! # Unstable features //! @@ -94,7 +100,7 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::iter::FromIterator; use std::marker; -#[cfg(procmacro2_semver_exempt)] +#[cfg(any(span_location_info))] use std::path::PathBuf; use std::rc::Rc; use std::str::FromStr; @@ -252,14 +258,14 @@ impl fmt::Debug for LexError { /// The source file of a given `Span`. /// /// This type is semver exempt and not exposed by default. -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] #[derive(Clone, PartialEq, Eq)] pub struct SourceFile { inner: imp::SourceFile, _marker: marker::PhantomData>, } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] impl SourceFile { fn _new(inner: imp::SourceFile) -> Self { SourceFile { @@ -292,7 +298,7 @@ impl SourceFile { } } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] impl fmt::Debug for SourceFile { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.inner.fmt(f) @@ -302,7 +308,7 @@ impl fmt::Debug for SourceFile { /// A line-column pair representing the start or end of a `Span`. /// /// This type is semver exempt and not exposed by default. -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] pub struct LineColumn { /// The 1-indexed line in the source file on which the span starts or ends /// (inclusive). @@ -345,8 +351,9 @@ impl Span { /// A span that resolves at the macro definition site. /// - /// This method is semver exempt and not exposed by default. - #[cfg(procmacro2_semver_exempt)] + /// This method is available by enabling the `span-location-info` feature + /// and disabled by default. + #[cfg(span_location_info)] pub fn def_site() -> Span { Span::_new(imp::Span::def_site()) } @@ -354,8 +361,9 @@ 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)] + /// This method is available by enabling the `span-location-info` feature + /// and disabled by default. + #[cfg(span_location_info)] pub fn resolved_at(&self, other: Span) -> Span { Span::_new(self.inner.resolved_at(other.inner)) } @@ -363,8 +371,9 @@ 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)] + /// This method is available by enabling the `span-location-info` feature + /// and disabled by default. + #[cfg(span_location_info)] pub fn located_at(&self, other: Span) -> Span { Span::_new(self.inner.located_at(other.inner)) } @@ -393,16 +402,18 @@ impl Span { /// The original source file into which this span points. /// - /// This method is semver exempt and not exposed by default. - #[cfg(procmacro2_semver_exempt)] + /// This method is available by enabling the `span-location-info` feature + /// and disabled by default. + #[cfg(span_location_info)] pub fn source_file(&self) -> SourceFile { SourceFile::_new(self.inner.source_file()) } /// Get the starting line/column in the source file for this span. /// - /// This method is semver exempt and not exposed by default. - #[cfg(procmacro2_semver_exempt)] + /// This method is available by enabling the `span-location-info` feature + /// and disabled by default. + #[cfg(span_location_info)] pub fn start(&self) -> LineColumn { let imp::LineColumn { line, column } = self.inner.start(); LineColumn { @@ -413,8 +424,9 @@ impl Span { /// Get the ending line/column in the source file for this span. /// - /// This method is semver exempt and not exposed by default. - #[cfg(procmacro2_semver_exempt)] + /// This method is available by enabling the `span-location-info` feature + /// and disabled by default. + #[cfg(span_location_info)] pub fn end(&self) -> LineColumn { let imp::LineColumn { line, column } = self.inner.end(); LineColumn { diff --git a/src/strnom.rs b/src/strnom.rs index 6f320626..37c6f456 100644 --- a/src/strnom.rs +++ b/src/strnom.rs @@ -9,18 +9,18 @@ use fallback::LexError; #[derive(Copy, Clone, Eq, PartialEq)] pub struct Cursor<'a> { pub rest: &'a str, - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub off: u32, } impl<'a> Cursor<'a> { - #[cfg(not(procmacro2_semver_exempt))] + #[cfg(not(span_location_info))] pub fn advance(&self, amt: usize) -> Cursor<'a> { Cursor { rest: &self.rest[amt..], } } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn advance(&self, amt: usize) -> Cursor<'a> { Cursor { rest: &self.rest[amt..], From 008269bc864676a1e7a3bdabaf0180facfba5b5d Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Mon, 28 Jan 2019 20:55:10 +0100 Subject: [PATCH 2/3] Expose more span functionality and restore support on older rusts --- src/fallback.rs | 10 +++++----- src/lib.rs | 16 ++++------------ tests/marker.rs | 2 +- tests/test.rs | 14 +++++++------- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/fallback.rs b/src/fallback.rs index 69d3e39b..60ee23e7 100644 --- a/src/fallback.rs +++ b/src/fallback.rs @@ -1,8 +1,8 @@ -#![cfg_attr(not(any(procmacro2_semver_exempt, span_location_info)), allow(dead_code))] +#![cfg_attr(not(all(procmacro2_semver_exempt, span_location_info)), allow(dead_code))] #[cfg(span_location_info)] use std::cell::RefCell; -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] use std::cmp; use std::fmt; use std::iter; @@ -388,7 +388,7 @@ impl Span { }) } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn join(&self, other: Span) -> Option { CODEMAP.with(|cm| { let cm = cm.borrow(); @@ -448,12 +448,12 @@ impl Group { self.span } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn span_open(&self) -> Span { self.span } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn span_close(&self) -> Span { self.span } diff --git a/src/lib.rs b/src/lib.rs index 863d116b..068c4ef6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -256,8 +256,6 @@ impl fmt::Debug for LexError { } /// The source file of a given `Span`. -/// -/// This type is semver exempt and not exposed by default. #[cfg(span_location_info)] #[derive(Clone, PartialEq, Eq)] pub struct SourceFile { @@ -306,8 +304,6 @@ impl fmt::Debug for SourceFile { } /// A line-column pair representing the start or end of a `Span`. -/// -/// This type is semver exempt and not exposed by default. #[cfg(span_location_info)] pub struct LineColumn { /// The 1-indexed line in the source file on which the span starts or ends @@ -438,17 +434,13 @@ impl Span { /// Create a new span encompassing `self` and `other`. /// /// Returns `None` if `self` and `other` are from different files. - /// - /// This method is semver exempt and not exposed by default. - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn join(&self, other: Span) -> Option { self.inner.join(other.inner).map(Span::_new) } /// Compares to spans to see if they're equal. - /// - /// This method is semver exempt and not exposed by default. - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn eq(&self, other: &Span) -> bool { self.inner.eq(&other.inner) } @@ -639,7 +631,7 @@ impl Group { /// pub fn span_open(&self) -> Span { /// ^ /// ``` - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn span_open(&self) -> Span { Span::_new(self.inner.span_open()) } @@ -650,7 +642,7 @@ impl Group { /// pub fn span_close(&self) -> Span { /// ^ /// ``` - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] pub fn span_close(&self) -> Span { Span::_new(self.inner.span_close()) } diff --git a/tests/marker.rs b/tests/marker.rs index 7bb50276..a09cd7e8 100644 --- a/tests/marker.rs +++ b/tests/marker.rs @@ -51,7 +51,7 @@ assert_impl!(Span is not Send or Sync); assert_impl!(TokenStream is not Send or Sync); assert_impl!(TokenTree is not Send or Sync); -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] mod semver_exempt { use super::*; diff --git a/tests/test.rs b/tests/test.rs index 6da12832..42f5fbbd 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -137,7 +137,7 @@ fn fail() { fail("r#_"); } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] #[test] fn span_test() { use proc_macro2::TokenTree; @@ -192,7 +192,7 @@ testing 123 ); } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] #[cfg(not(nightly))] #[test] fn default_span() { @@ -207,7 +207,7 @@ fn default_span() { assert!(!source_file.is_real()); } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_location_info)] #[test] fn span_join() { let source1 = "aaa\nbbb" @@ -319,10 +319,10 @@ fn raw_identifier() { fn test_debug_ident() { let ident = Ident::new("proc_macro", Span::call_site()); - #[cfg(not(procmacro2_semver_exempt))] + #[cfg(not(span_location_info))] let expected = "Ident(proc_macro)"; - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] let expected = "Ident { sym: proc_macro, span: bytes(0..0) }"; assert_eq!(expected, format!("{:?}", ident)); @@ -332,7 +332,7 @@ fn test_debug_ident() { fn test_debug_tokenstream() { let tts = TokenStream::from_str("[a + 1]").unwrap(); - #[cfg(not(procmacro2_semver_exempt))] + #[cfg(not(span_location_info))] let expected = "\ TokenStream [ Group { @@ -353,7 +353,7 @@ TokenStream [ ]\ "; - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_location_info)] let expected = "\ TokenStream [ Group { From 965cb79820512adeec44af1d343460bfb467b795 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Mon, 28 Jan 2019 21:38:44 +0100 Subject: [PATCH 3/3] Also test span location info --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index c3bfa6c9..83b1e46c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ matrix: - cargo test --no-default-features - RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test - RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features + - cargo test --features span-location-info + - cargo test --features span-location-info --no-default-features - cargo update -Z minimal-versions && cargo build - rust: nightly name: WebAssembly