Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -791,10 +791,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
)
) =>
{
rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
rustc_parse::fake_token_stream_for_item(
&self.cx.sess.psess,
item_inner,
Some(&attr),
)
}
Annotatable::Item(item_inner) if item_inner.tokens.is_none() => {
rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
rustc_parse::fake_token_stream_for_item(
&self.cx.sess.psess,
item_inner,
None,
)
}
// When a function has EII implementations attached (via `eii_impls`),
// use fake tokens so the pretty-printer re-emits the EII attribute
Expand All @@ -806,7 +814,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
if matches!(&item_inner.kind,
ItemKind::Fn(f) if !f.eii_impls.is_empty()) =>
{
rustc_parse::fake_token_stream_for_item(&self.cx.sess.psess, item_inner)
rustc_parse::fake_token_stream_for_item(
&self.cx.sess.psess,
item_inner,
None,
)
}
Annotatable::ForeignItem(item_inner) if item_inner.tokens.is_none() => {
rustc_parse::fake_token_stream_for_foreign_item(
Expand Down
89 changes: 87 additions & 2 deletions compiler/rustc_parse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::sync::Arc;

use rustc_ast as ast;
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast_pretty::pprust;
use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize};
pub use rustc_lexer::UNICODE_VERSION;
Expand Down Expand Up @@ -251,12 +251,97 @@ pub fn parse_in<'a, T>(
Ok(result)
}

pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenStream {
pub fn fake_token_stream_for_item(
psess: &ParseSess,
item: &ast::Item,
attr_to_exclude: Option<&ast::Attribute>,
) -> TokenStream {
if let Some(tokens) = fake_token_stream_for_file_mod(psess, item, attr_to_exclude) {
return tokens;
}

let source = pprust::item_to_string(item);
let filename = FileName::macro_expansion_source_code(&source);
unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)))
}

fn fake_token_stream_for_file_mod(
psess: &ParseSess,
item: &ast::Item,
attr_to_exclude: Option<&ast::Attribute>,
) -> Option<TokenStream> {
let ast::ItemKind::Mod(safety, ident, ast::ModKind::Loaded(_, ast::Inline::No { .. }, spans)) =
&item.kind
else {
return None;
};

let attrs_hi = item
.attrs
.iter()
.filter(|attr| attr.style == ast::AttrStyle::Inner)
.map(|attr| attr.span.hi())
.chain(
attr_to_exclude
.filter(|attr| attr.style == ast::AttrStyle::Inner)
.map(|attr| attr.span.hi()),
)
.max()
.unwrap_or(spans.inject_use_span.lo());
let body_span = spans.inner_span.with_lo(attrs_hi);
let body_src = psess.source_map().span_to_snippet(body_span).ok()?;
Comment thread
Dnreikronos marked this conversation as resolved.
let body_stream = unwrap_or_emit_fatal(lexer::lex_token_trees(
psess,
&body_src,
body_span.lo(),
None,
StripTokens::Nothing,
));

let mut body_tts = Vec::new();
for attr in item.attrs.iter().filter(|attr| attr.style == ast::AttrStyle::Inner) {
body_tts.extend(attr.token_trees());
}
body_tts.extend(body_stream.iter().cloned());

// Synthesize only the `mod name { ... }` wrapper. The body tokens come from
// the loaded file so diagnostics inside the module keep their real spans.
let wrapper = ast::Item {
attrs: item
.attrs
.iter()
.filter(|attr| attr.style == ast::AttrStyle::Outer)
.cloned()
.collect(),
id: item.id,
span: item.span,
vis: item.vis.clone(),
kind: ast::ItemKind::Mod(
*safety,
*ident,
ast::ModKind::Loaded(Default::default(), ast::Inline::Yes, ast::ModSpans::default()),
),
tokens: None,
};

let source = pprust::item_to_string(&wrapper);
let filename = FileName::macro_expansion_source_code(&source);
let wrapper_stream =
unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)));
let mut wrapper_tts: Vec<_> = wrapper_stream.iter().cloned().collect();

let Some(TokenTree::Delimited(_, _, token::Delimiter::Brace, stream)) = wrapper_tts
.iter_mut()
.rev()
.find(|tt| matches!(tt, TokenTree::Delimited(_, _, token::Delimiter::Brace, _)))
else {
return None;
};
*stream = TokenStream::new(body_tts);

Some(TokenStream::new(wrapper_tts))
}

pub fn fake_token_stream_for_foreign_item(
psess: &ParseSess,
item: &ast::ForeignItem,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#![test_macros::identity_attr]

pub fn f() {
g()
}
14 changes: 14 additions & 0 deletions tests/ui/proc-macro/inner-attr-file-mod-diagnostics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//@ proc-macro: test-macros.rs
//@ edition:2024

#![feature(custom_inner_attributes)]
#![feature(proc_macro_hygiene)]

extern crate test_macros;

#[path = "auxiliary/inner_attr_file_mod_diagnostics_child.rs"]
pub mod child;

fn main() {}

//~? ERROR cannot find function `g` in this scope
9 changes: 9 additions & 0 deletions tests/ui/proc-macro/inner-attr-file-mod-diagnostics.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0425]: cannot find function `g` in this scope
--> $DIR/auxiliary/inner_attr_file_mod_diagnostics_child.rs:4:5
|
LL | g()
| ^ not found in this scope

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0425`.
2 changes: 1 addition & 1 deletion tests/ui/proc-macro/inner-attr-file-mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ extern crate test_macros;

#[deny(unused_attributes)]
mod module_with_attrs;
//~^ ERROR custom inner attributes are unstable

fn main() {}

//~? ERROR custom inner attributes are unstable
//~? ERROR custom inner attributes are unstable
//~? ERROR inner macro attributes are unstable
7 changes: 4 additions & 3 deletions tests/ui/proc-macro/inner-attr-file-mod.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ LL | #![print_attr]
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: custom inner attributes are unstable
--> $DIR/inner-attr-file-mod.rs:11:1
--> $DIR/module_with_attrs.rs:3:4
|
LL | mod module_with_attrs;
| ^^^^^^^^^^^^^^^^^^^^^^
LL | #![rustfmt::skip]
| ^^^^^^^^^^^^^
|
= note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information
= help: add `#![feature(custom_inner_attributes)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 3 previous errors

Expand Down
14 changes: 7 additions & 7 deletions tests/ui/proc-macro/inner-attr-file-mod.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -40,36 +40,36 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
spacing: Joint,
span: $DIR/inner-attr-file-mod.rs:11:1: 11:23 (#0),
span: $DIR/module_with_attrs.rs:3:1: 3:2 (#0),
},
Punct {
ch: '!',
spacing: Alone,
span: $DIR/inner-attr-file-mod.rs:11:1: 11:23 (#0),
span: $DIR/module_with_attrs.rs:3:2: 3:3 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "rustfmt",
span: $DIR/inner-attr-file-mod.rs:11:1: 11:23 (#0),
span: $DIR/module_with_attrs.rs:3:4: 3:11 (#0),
},
Punct {
ch: ':',
spacing: Joint,
span: $DIR/inner-attr-file-mod.rs:11:1: 11:23 (#0),
span: $DIR/module_with_attrs.rs:3:11: 3:12 (#0),
},
Punct {
ch: ':',
spacing: Alone,
span: $DIR/inner-attr-file-mod.rs:11:1: 11:23 (#0),
span: $DIR/module_with_attrs.rs:3:12: 3:13 (#0),
},
Ident {
ident: "skip",
span: $DIR/inner-attr-file-mod.rs:11:1: 11:23 (#0),
span: $DIR/module_with_attrs.rs:3:13: 3:17 (#0),
},
],
span: $DIR/inner-attr-file-mod.rs:11:1: 11:23 (#0),
span: $DIR/module_with_attrs.rs:3:3: 3:18 (#0),
},
],
span: $DIR/inner-attr-file-mod.rs:11:1: 11:23 (#0),
Expand Down
Loading