-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracking issue for proc_macro::Span
inspection APIs
#54725
Comments
I wanted to shed some pain this is causing with tarpaulin. Tarpaulin has worked amazingly well for me and my company as a replacement for kcov which historically been a pain to get accurate, reliable and correct results. At the moment tarpaulin stands as the most promising goto option for codecoverage in rust and just feels more like the only first class tooling option. Having one of those when choosing to invest in a technology is important for many company's adoption story for checking off code quantity checkmarks. When they see that rust doesn't have a reasonable code quality story that works on stable rust, that's can result in a "pass" rather than "I'll take it". There are currently some work arounds for making this work-ish on stable but it feels very much like the story serde was in a year or so ago when you wanted to show all your friends how amazing serde was but then was embarrassed to show what it took to make work on stable because of a macro stabilization blocker. |
With procedural macros having reached a point where they're very useful on stable, I expect many users will find themselves needing access to this information. Would it be reasonable to only stabilize parts of the |
This unstable feature (rust-lang/rust#54725) is the last thing that we require in Nightly. Removing it will cause a significant regression in error messages, but that can be improved after switching to parsing the grammar as tokens rather than as a string literal.
I have a concern about exposing My understanding is that, if one adds a blank line to the start of the file, the line_column information of the input spans to proc macro changes. That means that IDE would have to re-expand procedural macros even after insignificant white space changes. I would feel more confident if proc-macros were strictly a pure function from the input token stream to output token stream. This can be achieved, for example, by making line-column infocation relative to the start of macro invocation (as opposed to relative to the start of the file). I don't feel that exposing absolute position is necessary the end of the world: IDE can track if a macro actually makes use of the info, or it can supply macro with some fake line/columns. But it's hard to tell if such hacks would work well in practice, and it's hard to experiment with them for the lack of IDE which handled proc-macros incrementally.... |
If the parser allocated IDs to every AST node, then, and this is the hard part, when an edit was made to the source, the parser tried to keep those IDs the same in all the non-edited code and only allocate new IDs for new nodes, that would allow spans to be kept completely separate from the AST. Those IDs could be passed through macro expansion without causing unnecessary invalidations. If something needed a span later on, it could then go back and ask the parser for the span for that particular AST node ID. I feel like having an incremental parser is important, not because parsing is the bottleneck, but because it underpins everything else. |
@davidlattimore this is fascinating, but slightly off-topic for the issue. I've created a thread on internals: https://internals.rust-lang.org/t/macros-vs-incremental-parsing/9323 |
The column!() macro as well as std::panic::Location::column are returning 1-based columns while the span available from the proc-macro crate is 0-based according to its docs. Is this inconsistency intended? |
This thread has more discussion about 1-based columns: #46762 (comment) |
Another open question is how this API relates to #47389 which is about minimizing span information throughout the compiler. Should stabilization be blocked until a design for #47389 is found? Is it too late already as we have |
#47389 is mostly concerned about data types that are used later in the compilation pipeline, such as type information and MIR. Exposing things at the proc-macro level should not be too bad. |
But rust-analyzer might one day expand the scope of incremental compilation to the parsing stage, right? |
Hello! I'm interested in writing a proc macro that utilizes the feature of obtaining the caller's file location. Is there any new update on this issue? |
the capabilities remain the same in stable. There are some very cursed patterns you can do if there is a unique string you know will only appear in one file in the crate, like my very cursed In practice this works great, but it is intended more as an IDE-extension-living-in-a-proc-macro than a real proc macro you would keep in your source code. In fact it is designed so that when you hit CTRL+S in your editor, the invocation disappears and is replaced with the expansion from gpt. |
Implement proposed API for `proc_macro_span` As proposed in [#54725 (comment)](rust-lang/rust#54725 (comment)). I have omitted the byte-level API as it's already available as [`Span::byte_range`](https://doc.rust-lang.org/nightly/proc_macro/struct.Span.html#method.byte_range). `@rustbot` label +A-proc-macros r? `@m-ou-se`
I come here when I need to write a procedural macro which could get the file path the macro is called, chatGpt give me the code like this: #[proc_macro]
pub fn example_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
// Get the `Span` where the macro was called
let span = proc_macro::Span::call_site();
// Use the `Span` to get the `SourceFile`
let source_file = span.source_file();
// Get the path of the `SourceFile`
let path: PathBuf = source_file.path();
// Now you can use the file path for further processing
// ...
// Return the original input for this example
input
} Then fn |
You could also look at |
Although in a multi-crate workspace this tends to break as well when you deploy to crates.io if any of the files are up one or more directories from the invocation, as I frequently encounter in my docify crate |
@wyatt-herkamp, @sam0x17 , thanks! This workaround is feasible in my case, which wrapping a trait in a functional macro, and I modified it a little into this: struct TraitVisitor {
trait_name: String,
found: Option<Macro>,
}
impl<'ast> Visit<'ast> for TraitVisitor {
fn visit_macro(&mut self, mac: &'ast Macro) {
if self.found.is_some() {
return;
}
let last_seg = mac.path.segments.last().unwrap();
if last_seg.ident != "trait_variable" {
return;
}
// Convert the macro body tokens into a vector of Ident
let idents: Vec<Ident> = mac.tokens.clone().into_iter().filter_map(|tt| match tt {
proc_macro2::TokenTree::Ident(ident) => Some(ident),
_ => None,
}).collect();
// Check for the presence of 'trait' keyword followed by the desired trait name
for i in 0..idents.len() - 1 {
if idents[i] == "trait" && idents[i + 1] == self.trait_name {
println!("found trait: {:?}", self.trait_name);
self.found = Some(mac.clone());
break;
}
}
}
} |
Implement proposed API for `proc_macro_span` As proposed in [#54725 (comment)](rust-lang/rust#54725 (comment)). I have omitted the byte-level API as it's already available as [`Span::byte_range`](https://doc.rust-lang.org/nightly/proc_macro/struct.Span.html#method.byte_range). `@rustbot` label +A-proc-macros r? `@m-ou-se`
Would be great to get the source file... |
Emm. if without this feature, we cannot write something like include_str!() right? |
No, this issue is unrelated. See two proposals mentioned here for doing that: #54725 (comment) |
This comment was marked as off-topic.
This comment was marked as off-topic.
I believe that rustc now uses a span model that is compatible with this ask, but currently doesn't use it during macro expansion, ironically. |
I don't believe it's possible to get the absolute path of a source file with |
Templates can now be placed directly next to the source file that they are defined in as a default. This relies on an unstable rust compiler feature, which exposes the source file to proc macros. See <rust-lang/rust#54725> for more info. This requires the nightly compiler to run, and enabling the proc_macro_span and procmacro2_semver_exempt cfg flags. To build / test: ```shell RUSTFLAGS='--cfg proc_macro_span --cfg procmacro2_semver_exempt' \ cargo +nightly build ``` Fixes: <https://github.com/djc/askama/issues/877>
Templates can now be placed directly next to the source file that they are defined in as a default. This relies on an unstable rust compiler feature, which exposes the source file to proc macros. See <rust-lang/rust#54725> for more info. This requires the nightly compiler to run, and enabling the proc_macro_span and procmacro2_semver_exempt cfg flags. To build / test: ```shell RUSTFLAGS='--cfg proc_macro_span --cfg procmacro2_semver_exempt' \ cargo +nightly build ``` Fixes: <https://github.com/djc/askama/issues/877>
This issue is intended to track a number of unstable APIs which are used to inspect the contents of a
Span
for information like the file name, byte position, manufacturing new spans, combining them, etc.This issue tracks the
proc_macro_span
unstable feature.Public API
Already stabilized:
To be stabilized, probably in their current form:
To be stabilized after some (re)design or discussion:
Things that require more discussion:
The text was updated successfully, but these errors were encountered: