From 3b1f7d28c11a0f88ab52504c4b8e1dc9e7789883 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 28 Jan 2019 12:22:11 -0800 Subject: [PATCH] Expose span locations on stable --- .travis.yml | 2 ++ Cargo.toml | 4 +++ build.rs | 21 ++++++++++---- src/fallback.rs | 73 +++++++++++++++++++++++++++++++++---------------- src/lib.rs | 16 +++++------ src/strnom.rs | 6 ++-- src/wrapper.rs | 13 ++++++--- tests/test.rs | 2 +- 8 files changed, 91 insertions(+), 46 deletions(-) diff --git a/.travis.yml b/.travis.yml index c3bfa6c9..89da7248 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ matrix: script: - cargo test - cargo test --no-default-features + - cargo test --features span-locations - RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test - RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features - cargo update -Z minimal-versions && cargo build @@ -25,6 +26,7 @@ before_script: script: - cargo test - cargo test --no-default-features + - cargo test --features span-locations - RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test - RUSTFLAGS='--cfg procmacro2_semver_exempt' cargo test --no-default-features diff --git a/Cargo.toml b/Cargo.toml index 929314e2..4d48b661 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,10 @@ quote = "0.6" proc-macro = [] default = ["proc-macro"] +# Expose methods Span::start and Span::end which give the line/column location +# of a token. +span-locations = [] + # This feature no longer means anything. nightly = [] diff --git a/build.rs b/build.rs index 6973ca77..6c011215 100644 --- a/build.rs +++ b/build.rs @@ -31,6 +31,12 @@ // "super_unstable" // Implement the semver exempt API in terms of the nightly-only proc_macro // API. Enabled when using procmacro2_semver_exempt on a nightly compiler. +// +// "span_locations" +// Provide methods Span::start and Span::end which give the line/column +// location of a token. Enabled by procmacro2_semver_exempt or the +// "span-locations" Cargo cfg. This is behind a cfg because tracking +// location inside spans is a performance hit. use std::env; use std::process::Command; @@ -50,17 +56,22 @@ fn main() { println!("cargo:rustc-cfg=u128"); } - if !enable_use_proc_macro(&target) { - return; - } - println!("cargo:rustc-cfg=use_proc_macro"); - let semver_exempt = cfg!(procmacro2_semver_exempt); if semver_exempt { // https://github.com/alexcrichton/proc-macro2/issues/147 println!("cargo:rustc-cfg=procmacro2_semver_exempt"); } + if semver_exempt || cfg!(feature = "span-locations") { + println!("cargo:rustc-cfg=span_locations"); + } + + if !enable_use_proc_macro(&target) { + return; + } + + println!("cargo:rustc-cfg=use_proc_macro"); + // Rust 1.29 stabilized the necessary APIs in the `proc_macro` crate if version.nightly || version.minor >= 29 && !semver_exempt { println!("cargo:rustc-cfg=wrap_proc_macro"); diff --git a/src/fallback.rs b/src/fallback.rs index 7f3cc4e4..928c7472 100644 --- a/src/fallback.rs +++ b/src/fallback.rs @@ -1,6 +1,4 @@ -#![cfg_attr(not(procmacro2_semver_exempt), allow(dead_code))] - -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_locations)] use std::cell::RefCell; #[cfg(procmacro2_semver_exempt)] use std::cmp; @@ -35,7 +33,7 @@ impl TokenStream { } } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_locations)] fn get_cursor(src: &str) -> Cursor { // Create a dummy file & add it to the codemap CODEMAP.with(|cm| { @@ -49,7 +47,7 @@ fn get_cursor(src: &str) -> Cursor { }) } -#[cfg(not(procmacro2_semver_exempt))] +#[cfg(not(span_locations))] fn get_cursor(src: &str) -> Cursor { Cursor { rest: src } } @@ -225,27 +223,41 @@ pub struct LineColumn { pub column: usize, } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_locations)] thread_local! { static CODEMAP: RefCell = RefCell::new(Codemap { // NOTE: We start with a single dummy file which all call_site() and // def_site() spans reference. - files: vec![FileInfo { - name: "".to_owned(), - span: Span { lo: 0, hi: 0 }, - lines: vec![0], + files: vec![{ + #[cfg(procmacro2_semver_exempt)] + { + FileInfo { + name: "".to_owned(), + span: Span { lo: 0, hi: 0 }, + lines: vec![0], + } + } + + #[cfg(not(procmacro2_semver_exempt))] + { + FileInfo { + span: Span { lo: 0, hi: 0 }, + lines: vec![0], + } + } }], }); } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_locations)] struct FileInfo { + #[cfg(procmacro2_semver_exempt)] name: String, span: Span, lines: Vec, } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_locations)] impl FileInfo { fn offset_line_column(&self, offset: usize) -> LineColumn { assert!(self.span_within(Span { @@ -271,7 +283,7 @@ impl FileInfo { } /// Computesthe offsets of each line in the given source string. -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_locations)] fn lines_offsets(s: &str) -> Vec { let mut lines = vec![0]; let mut prev = 0; @@ -282,12 +294,12 @@ fn lines_offsets(s: &str) -> Vec { lines } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_locations)] struct Codemap { files: Vec, } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_locations)] impl Codemap { fn next_start_pos(&self) -> u32 { // Add 1 so there's always space between files. @@ -306,12 +318,20 @@ impl Codemap { hi: lo + (src.len() as u32), }; + #[cfg(procmacro2_semver_exempt)] self.files.push(FileInfo { name: name.to_owned(), span: span, lines: lines, }); + #[cfg(not(procmacro2_semver_exempt))] + self.files.push(FileInfo { + span: span, + lines: lines, + }); + let _ = name; + span } @@ -327,27 +347,29 @@ impl Codemap { #[derive(Clone, Copy, PartialEq, Eq)] pub struct Span { - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_locations)] lo: u32, - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_locations)] hi: u32, } impl Span { - #[cfg(not(procmacro2_semver_exempt))] + #[cfg(not(span_locations))] pub fn call_site() -> Span { Span {} } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_locations)] pub fn call_site() -> Span { Span { lo: 0, hi: 0 } } + #[cfg(procmacro2_semver_exempt)] pub fn def_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 @@ -355,6 +377,7 @@ impl Span { *self } + #[cfg(procmacro2_semver_exempt)] pub fn located_at(&self, other: Span) -> Span { other } @@ -370,7 +393,7 @@ impl Span { }) } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_locations)] pub fn start(&self) -> LineColumn { CODEMAP.with(|cm| { let cm = cm.borrow(); @@ -379,7 +402,7 @@ impl Span { }) } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_locations)] pub fn end(&self) -> LineColumn { CODEMAP.with(|cm| { let cm = cm.borrow(); @@ -448,10 +471,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 } @@ -788,16 +813,16 @@ fn token_stream(mut input: Cursor) -> PResult { Ok((input, TokenStream { inner: trees })) } -#[cfg(not(procmacro2_semver_exempt))] +#[cfg(not(span_locations))] fn spanned<'a, T>( input: Cursor<'a>, f: fn(Cursor<'a>) -> PResult<'a, T>, ) -> PResult<'a, (T, ::Span)> { let (a, b) = f(skip_whitespace(input))?; - Ok((a, ((b, ::Span::_new_stable(Span {}))))) + Ok((a, ((b, ::Span::_new_stable(Span::call_site()))))) } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_locations)] 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..5b96ad3f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,10 +80,8 @@ // Proc-macro2 types in rustdoc of other crates get linked to here. #![doc(html_root_url = "https://docs.rs/proc-macro2/0.4.26")] -#![cfg_attr( - super_unstable, - feature(proc_macro_raw_ident, proc_macro_span, proc_macro_def_site) -)] +#![cfg_attr(nightly, feature(proc_macro_span))] +#![cfg_attr(super_unstable, feature(proc_macro_raw_ident, proc_macro_def_site))] #[cfg(use_proc_macro)] extern crate proc_macro; @@ -302,7 +300,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_locations)] pub struct LineColumn { /// The 1-indexed line in the source file on which the span starts or ends /// (inclusive). @@ -401,8 +399,8 @@ impl Span { /// 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 requires the `"span-locations"` feature to be enabled. + #[cfg(span_locations)] pub fn start(&self) -> LineColumn { let imp::LineColumn { line, column } = self.inner.start(); LineColumn { @@ -413,8 +411,8 @@ 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 requires the `"span-locations"` feature to be enabled. + #[cfg(span_locations)] 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..96789d56 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_locations)] pub off: u32, } impl<'a> Cursor<'a> { - #[cfg(not(procmacro2_semver_exempt))] + #[cfg(not(span_locations))] pub fn advance(&self, amt: usize) -> Cursor<'a> { Cursor { rest: &self.rest[amt..], } } - #[cfg(procmacro2_semver_exempt)] + #[cfg(span_locations)] pub fn advance(&self, amt: usize) -> Cursor<'a> { Cursor { rest: &self.rest[amt..], diff --git a/src/wrapper.rs b/src/wrapper.rs index 11d1a3b8..c45dff89 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -1,5 +1,3 @@ -#![cfg_attr(not(super_unstable), allow(dead_code))] - use std::fmt; use std::iter; use std::panic::{self, PanicInfo}; @@ -413,6 +411,7 @@ impl fmt::Debug for SourceFile { } } +#[cfg(any(super_unstable, feature = "span-locations"))] pub struct LineColumn { pub line: usize, pub column: usize, @@ -475,13 +474,16 @@ impl Span { } } - #[cfg(super_unstable)] + #[cfg(any(super_unstable, feature = "span-locations"))] pub fn start(&self) -> LineColumn { match self { + #[cfg(nightly)] Span::Compiler(s) => { let proc_macro::LineColumn { line, column } = s.start(); LineColumn { line, column } } + #[cfg(not(nightly))] + Span::Compiler(_) => LineColumn { line: 0, column: 0 }, Span::Fallback(s) => { let fallback::LineColumn { line, column } = s.start(); LineColumn { line, column } @@ -489,13 +491,16 @@ impl Span { } } - #[cfg(super_unstable)] + #[cfg(any(super_unstable, feature = "span-locations"))] pub fn end(&self) -> LineColumn { match self { + #[cfg(nightly)] Span::Compiler(s) => { let proc_macro::LineColumn { line, column } = s.end(); LineColumn { line, column } } + #[cfg(not(nightly))] + Span::Compiler(_) => LineColumn { line: 0, column: 0 }, Span::Fallback(s) => { let fallback::LineColumn { line, column } = s.end(); LineColumn { line, column } diff --git a/tests/test.rs b/tests/test.rs index 6da12832..055ebfdc 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -137,7 +137,7 @@ fn fail() { fail("r#_"); } -#[cfg(procmacro2_semver_exempt)] +#[cfg(span_locations)] #[test] fn span_test() { use proc_macro2::TokenTree;