Skip to content
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

Experimental: Add Derive Proc-Macro Caching #129102

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3db813e
deps(rustc_expand): Add `rustc_middle` as a dep
futile Aug 11, 2024
2507253
refactor(rustc_expand): Take &SyntaxExtension instead of only &*Kind
futile Aug 11, 2024
0733fbd
wip: So yeah, tests pass, but still `eval_always` (not far from disk …
futile Aug 12, 2024
a4b675c
fix: Prevent double-enter with same `&mut ExtCtxt` (which would be UB)
futile Aug 12, 2024
209fd8a
chore: Remove old `allow`
futile Aug 12, 2024
fe36059
chore: Remove unneeded code, adapt TODOs for pr-time
futile Aug 12, 2024
eb99b01
wip(test): Run with `-- --nocapture --verbose` and `invoked` should n…
futile Aug 12, 2024
fc3bc29
wip: Activate, test (and fix) on_disk caching for proc-macro expansions!
futile Aug 12, 2024
075853d
chore: Adjust timing outputs
futile Aug 12, 2024
7a1b2f5
feat: Add `-Zcache-all-derive-macros` to use/bypass cache
futile Aug 12, 2024
d781c4b
wip: try also hashing query output
futile Aug 12, 2024
a81aaed
prepare for PR (tidy should pass, caching=yes by default for rustc-perf)
futile Aug 14, 2024
91c0d1b
wip: Undo unnecessary refactoring
futile Aug 19, 2024
8521154
rebase + fix unreachable pub-items, inline some CONTEXT-things
futile Sep 9, 2024
17dcadf
chore: Run `x fmt` after rebase, should probably squash.
futile Nov 9, 2024
35beb09
fix: comment + unused warning
futile Nov 16, 2024
382c5d0
style: move import to correct place
futile Nov 16, 2024
b71c42d
chore: remove old comment
futile Nov 16, 2024
a359e3c
don't flatten proc macro output, let's see how it goes
futile Nov 16, 2024
f768697
only retrieve expn_data once
futile Nov 16, 2024
bb3bddf
fix: Ensure incremental compilation is also enabled
futile Dec 8, 2024
77944c9
refactor!: Rename `cache-all-derive-macros` option to `cache-proc-mac…
futile Dec 28, 2024
de0fad9
nit: remove comment
futile Dec 28, 2024
d6c2527
refactor: Require `ecx` less
futile Dec 28, 2024
00cff94
refactor: Only call invoc_id.expn_data() once, inline some `res`
futile Dec 28, 2024
abcc4a2
refactor: Don't enter context if not caching (don't need it then)
futile Dec 28, 2024
e93beac
refactor: Move derive_macro_expansion.rs to end of proc_macro.rs
futile Dec 28, 2024
cd82e38
fix: Make non-context expansion actually work
futile Dec 28, 2024
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
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3752,6 +3752,7 @@ dependencies = [
"rustc_lexer",
"rustc_lint_defs",
"rustc_macros",
"rustc_middle",
"rustc_parse",
"rustc_serialize",
"rustc_session",
Expand Down
94 changes: 93 additions & 1 deletion compiler/rustc_ast/src/tokenstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
//! ownership of the original.

use std::borrow::Cow;
use std::hash::Hash;
use std::{cmp, fmt, iter};

use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{self, Lrc};
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_serialize::{Decodable, Encodable};
use rustc_serialize::{Decodable, Encodable, Encoder};
use rustc_span::def_id::{CrateNum, DefIndex};
use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};

use crate::ast::{AttrStyle, StmtKind};
Expand Down Expand Up @@ -295,6 +297,96 @@ pub struct AttrsTarget {
#[derive(Clone, Debug, Default, Encodable, Decodable)]
pub struct TokenStream(pub(crate) Lrc<Vec<TokenTree>>);

struct HashEncoder<H: std::hash::Hasher> {
hasher: H,
}

impl<H: std::hash::Hasher> Encoder for HashEncoder<H> {
fn emit_usize(&mut self, v: usize) {
self.hasher.write_usize(v)
}

fn emit_u128(&mut self, v: u128) {
self.hasher.write_u128(v)
}

fn emit_u64(&mut self, v: u64) {
self.hasher.write_u64(v)
}

fn emit_u32(&mut self, v: u32) {
self.hasher.write_u32(v)
}

fn emit_u16(&mut self, v: u16) {
self.hasher.write_u16(v)
}

fn emit_u8(&mut self, v: u8) {
self.hasher.write_u8(v)
}

fn emit_isize(&mut self, v: isize) {
self.hasher.write_isize(v)
}

fn emit_i128(&mut self, v: i128) {
self.hasher.write_i128(v)
}

fn emit_i64(&mut self, v: i64) {
self.hasher.write_i64(v)
}

fn emit_i32(&mut self, v: i32) {
self.hasher.write_i32(v)
}

fn emit_i16(&mut self, v: i16) {
self.hasher.write_i16(v)
}

fn emit_raw_bytes(&mut self, s: &[u8]) {
self.hasher.write(s)
}
}

impl<H: std::hash::Hasher> SpanEncoder for HashEncoder<H> {
fn encode_span(&mut self, span: Span) {
span.hash(&mut self.hasher)
}

fn encode_symbol(&mut self, symbol: Symbol) {
symbol.hash(&mut self.hasher)
}

fn encode_expn_id(&mut self, expn_id: rustc_span::ExpnId) {
expn_id.hash(&mut self.hasher)
}

fn encode_syntax_context(&mut self, syntax_context: rustc_span::SyntaxContext) {
syntax_context.hash(&mut self.hasher)
}

fn encode_crate_num(&mut self, crate_num: CrateNum) {
crate_num.hash(&mut self.hasher)
}

fn encode_def_index(&mut self, def_index: DefIndex) {
def_index.hash(&mut self.hasher)
}

fn encode_def_id(&mut self, def_id: rustc_span::def_id::DefId) {
def_id.hash(&mut self.hasher)
}
}

impl Hash for TokenStream {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is implementation of unstable hash required for TokenStream?
Unstable hashing shouldn't be used in incremental compilation, and TokenStrem already has a stable hashing implementation because token streams are used in attributes.

(Also the use of (Span)Encoder here is strange, I don't think it's supposed to be used like this.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried removing the Hash-impl again, but it seems the query system requires it somehow:

   Compiling rustc_middle v0.0.0 (/home/felix/gits/rust/compiler/rustc_middle)
error[E0277]: the trait bound `rustc_ast::tokenstream::TokenStream: Hash` is not satisfied
    --> compiler/rustc_middle/src/query/plumbing.rs:434:28
     |
275  |  / macro_rules! define_callbacks {
276  |  |     (
277  |  |      $($(#[$attr:meta])*
278  |  |         [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
...     |
434  |  |                 pub $name: DynamicQuery<'tcx, queries::$name::Storage<'tcx>>,
     |  |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Hash` is not implemented for `rustc_ast::tokenstream::TokenStream`, which is required by `DefaultCache<(rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream), Erased<query::erase::Erase<Result<&'tcx rustc_ast::tokenstream::TokenStream, ()>>::{opaque#0}>>: rustc_query_system::query::QueryCache`
...     |
490  |  |     };
491  |  | }
     |  |_- in this expansion of `define_callbacks!` (#2)
     |
    ::: compiler/rustc_middle/src/query/mod.rs:108:1
     |
108  | /  rustc_queries! {
109  | |      query derive_macro_expansion(key: (LocalExpnId, Svh, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
110  | |          // eval_always
111  | |          // no_hash
...    |
2335 | |      }
2336 | |  }
     | |  -
     | |  |
     | |__in this expansion of `rustc_query_append!` (#1)
     |    in this macro invocation (#2)
2337 |
2338 |    rustc_query_append! { define_callbacks! }
     |    ----------------------------------------- in this macro invocation (#1)
     |
     = help: the trait `rustc_query_system::query::QueryCache` is implemented for `DefaultCache<K, V>`
     = note: required for `&'tcx rustc_ast::tokenstream::TokenStream` to implement `Hash`
     = note: 1 redundant requirement hidden
     = note: required for `(rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream)` to implement `Hash`
     = note: required for `DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>>` to implement `rustc_query_system::query::QueryCache`
note: required by a bound in `DynamicQuery`
    --> compiler/rustc_middle/src/query/plumbing.rs:22:34
     |
22   | pub struct DynamicQuery<'tcx, C: QueryCache> {
     |                                  ^^^^^^^^^^ required by this bound in `DynamicQuery`
     = note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-16771981020465904745.txt'
     = note: consider using `--verbose` to print the full type name to the console

Adding no_hash also didn't help (i.e., error stayed the same). I know there is something like arena_cache, but I'm not really familiar with the query/caching system, so no idea if that would be better here/not require the Hash-impl.

Full error message (long!)

Compiling rustc_middle v0.0.0 (/home/felix/gits/rust/compiler/rustc_middle)
error[E0277]: the trait bound rustc_ast::tokenstream::TokenStream: Hash is not satisfied
--> compiler/rustc_middle/src/query/plumbing.rs:434:28
|
275 | / macro_rules! define_callbacks {
276 | | (
277 | | $($(#[$attr:meta])*
278 | | [$($modifiers:tt)] fn $name:ident($($K:tt)) -> $V:ty,)*) => {
... |
434 | | pub $name: DynamicQuery<'tcx, queries::$name::Storage<'tcx>>,
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait Hash is not implemented for rustc_ast::tokenstream::TokenStream, which is required by DefaultCache<(rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream), Erased<query::erase::Erase<Result<&'tcx rustc_ast::tokenstream::TokenStream, ()>>::{opaque#0}>>: rustc_query_system::query::QueryCache
... |
490 | | };
491 | | }
| |_- in this expansion of define_callbacks! (#2)
|
::: compiler/rustc_middle/src/query/mod.rs:108:1
|
108 | / rustc_queries! {
109 | | query derive_macro_expansion(key: (LocalExpnId, Svh, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
110 | | // eval_always
111 | | // no_hash
... |
2335 | | }
2336 | | }
| | -
| | |
| |__in this expansion of rustc_query_append! (#1)
| in this macro invocation (#2)
2337 |
2338 | rustc_query_append! { define_callbacks! }
| ----------------------------------------- in this macro invocation (#1)
|
= help: the trait rustc_query_system::query::QueryCache is implemented for DefaultCache<K, V>
= note: required for &'tcx rustc_ast::tokenstream::TokenStream to implement Hash
= note: 1 redundant requirement hidden
= note: required for (rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream) to implement Hash
= note: required for DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>> to implement rustc_query_system::query::QueryCache
note: required by a bound in DynamicQuery
--> compiler/rustc_middle/src/query/plumbing.rs:22:34
|
22 | pub struct DynamicQuery<'tcx, C: QueryCache> {
| ^^^^^^^^^^ required by this bound in DynamicQuery
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-16771981020465904745.txt'
= note: consider using --verbose to print the full type name to the console

error[E0277]: the trait bound rustc_ast::tokenstream::TokenStream: Hash is not satisfied
--> compiler/rustc_middle/src/ty/context.rs:1267:29
|
1267 | sync::assert_dyn_sync::<&'_ GlobalCtxt<'>>();
| ^^^^^^^^^^^^^^^^^^ the trait Hash is not implemented for rustc_ast::tokenstream::TokenStream, which is required by &GlobalCtxt<'_>: DynSync
|
= note: required for &rustc_ast::tokenstream::TokenStream to implement Hash
= note: 1 redundant requirement hidden
= note: required for (rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &rustc_ast::tokenstream::TokenStream) to implement Hash
= note: required for DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>> to implement rustc_query_system::query::QueryCache
note: required because it appears within the type DynamicQuery<'_, DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>>>
--> compiler/rustc_middle/src/query/plumbing.rs:22:12
|
22 | pub struct DynamicQuery<'tcx, C: QueryCache> {
| ^^^^^^^^^^^^
note: required because it appears within the type DynamicQueries<'_>
--> compiler/rustc_middle/src/query/plumbing.rs:432:20
|
275 | / macro_rules! define_callbacks {
276 | | (
277 | | $($(#[$attr:meta])*
278 | | [$($modifiers:tt)] fn $name:ident($($K:tt)) -> $V:ty,)*) => {
... |
432 | | pub struct DynamicQueries<'tcx> {
| | ^^^^^^^^^^^^^^
... |
490 | | };
491 | | }
| |
- in this expansion of define_callbacks! (#2)
|
::: compiler/rustc_middle/src/query/mod.rs:108:1
|
108 | / rustc_queries! {
109 | | query derive_macro_expansion(key: (LocalExpnId, Svh, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
110 | | // eval_always
111 | | // no_hash
... |
2335 | | }
2336 | | }
| | -
| | |
| |__in this expansion of rustc_query_append! (#1)
| in this macro invocation (#2)
2337 |
2338 | rustc_query_append! { define_callbacks! }
| ----------------------------------------- in this macro invocation (#1)
note: required because it appears within the type QuerySystem<'_>
--> compiler/rustc_middle/src/query/plumbing.rs:59:12
|
59 | pub struct QuerySystem<'tcx> {
| ^^^^^^^^^^^
note: required because it appears within the type GlobalCtxt<'_>
--> compiler/rustc_middle/src/ty/context.rs:1280:12
|
1280 | pub struct GlobalCtxt<'tcx> {
| ^^^^^^^^^^
= note: required because it appears within the type &GlobalCtxt<'_>
note: required by a bound in assert_dyn_sync
--> /home/felix/gits/rust/compiler/rustc_data_structures/src/marker.rs:192:36
|
192 | pub fn assert_dyn_sync<T: ?Sized + DynSync>() {}
| ^^^^^^^ required by this bound in assert_dyn_sync
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-9950355256232114649.txt'
= note: consider using --verbose to print the full type name to the console
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-14307373095868409618.txt'
= note: consider using --verbose to print the full type name to the console

error[E0277]: the trait bound rustc_ast::tokenstream::TokenStream: Hash is not satisfied
--> compiler/rustc_middle/src/ty/context.rs:1268:29
|
1268 | sync::assert_dyn_send::<&'_ GlobalCtxt<'>>();
| ^^^^^^^^^^^^^^^^^^ the trait Hash is not implemented for rustc_ast::tokenstream::TokenStream, which is required by &GlobalCtxt<'_>: DynSend
|
= note: required for &rustc_ast::tokenstream::TokenStream to implement Hash
= note: 1 redundant requirement hidden
= note: required for (rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &rustc_ast::tokenstream::TokenStream) to implement Hash
= note: required for DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>> to implement rustc_query_system::query::QueryCache
note: required because it appears within the type DynamicQuery<'_, DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>>>
--> compiler/rustc_middle/src/query/plumbing.rs:22:12
|
22 | pub struct DynamicQuery<'tcx, C: QueryCache> {
| ^^^^^^^^^^^^
note: required because it appears within the type DynamicQueries<'_>
--> compiler/rustc_middle/src/query/plumbing.rs:432:20
|
275 | / macro_rules! define_callbacks {
276 | | (
277 | | $($(#[$attr:meta])*
278 | | [$($modifiers:tt)] fn $name:ident($($K:tt)) -> $V:ty,)*) => {
... |
432 | | pub struct DynamicQueries<'tcx> {
| | ^^^^^^^^^^^^^^
... |
490 | | };
491 | | }
| |
- in this expansion of define_callbacks! (#2)
|
::: compiler/rustc_middle/src/query/mod.rs:108:1
|
108 | / rustc_queries! {
109 | | query derive_macro_expansion(key: (LocalExpnId, Svh, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
110 | | // eval_always
111 | | // no_hash
... |
2335 | | }
2336 | | }
| | -
| | |
| |__in this expansion of rustc_query_append! (#1)
| in this macro invocation (#2)
2337 |
2338 | rustc_query_append! { define_callbacks! }
| ----------------------------------------- in this macro invocation (#1)
note: required because it appears within the type QuerySystem<'_>
--> compiler/rustc_middle/src/query/plumbing.rs:59:12
|
59 | pub struct QuerySystem<'tcx> {
| ^^^^^^^^^^^
note: required because it appears within the type GlobalCtxt<'_>
--> compiler/rustc_middle/src/ty/context.rs:1280:12
|
1280 | pub struct GlobalCtxt<'tcx> {
| ^^^^^^^^^^
= note: required for &GlobalCtxt<'_> to implement DynSend
note: required by a bound in assert_dyn_send
--> /home/felix/gits/rust/compiler/rustc_data_structures/src/marker.rs:193:36
|
193 | pub fn assert_dyn_send<T: ?Sized + DynSend>() {}
| ^^^^^^^ required by this bound in assert_dyn_send
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-15445565275656164200.txt'
= note: consider using --verbose to print the full type name to the console
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-2573109838703607371.txt'
= note: consider using --verbose to print the full type name to the console

error[E0277]: the trait bound rustc_ast::tokenstream::TokenStream: Hash is not satisfied
--> compiler/rustc_middle/src/query/plumbing.rs:386:21
|
194 | query_ensure($($args))
| ------------ required by a bound introduced by this call
...
275 | / macro_rules! define_callbacks {
276 | | (
277 | | $($(#[$attr:meta])

278 | | [$($modifiers:tt)] fn $name:ident($($K:tt)) -> $V:ty,)*) => {
... |
386 | | &self.tcx.query_system.caches.$name,
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait Hash is not implemented for rustc_ast::tokenstream::TokenStream, which is required by DefaultCache<(rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream), Erased<query::erase::Erase<Result<&'tcx rustc_ast::tokenstream::TokenStream, ()>>::{opaque#0}>>: rustc_query_system::query::QueryCache
... |
490 | | };
491 | | }
| |_- in this expansion of define_callbacks! (#2)
|
::: compiler/rustc_middle/src/query/mod.rs:108:1
|
108 | / rustc_queries! {
109 | | query derive_macro_expansion(key: (LocalExpnId, Svh, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
110 | | // eval_always
111 | | // no_hash
... |
2335 | | }
2336 | | }
| | -
| | |
| |__in this expansion of rustc_query_append! (#1)
| in this macro invocation (#2)
2337 |
2338 | rustc_query_append! { define_callbacks! }
| ----------------------------------------- in this macro invocation (#1)
|
= help: the trait rustc_query_system::query::QueryCache is implemented for DefaultCache<K, V>
= note: required for &'tcx rustc_ast::tokenstream::TokenStream to implement Hash
= note: 1 redundant requirement hidden
= note: required for (rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream) to implement Hash
= note: required for DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>> to implement rustc_query_system::query::QueryCache
note: required by a bound in query_ensure
--> compiler/rustc_middle/src/query/plumbing.rs:155:12
|
148 | pub fn query_ensure<'tcx, Cache>(
| ------------ required by a bound in this function
...
155 | Cache: QueryCache,
| ^^^^^^^^^^ required by this bound in query_ensure
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-16771981020465904745.txt'
= note: consider using --verbose to print the full type name to the console

error[E0277]: the trait bound rustc_ast::tokenstream::TokenStream: Hash is not satisfied
--> compiler/rustc_middle/src/query/plumbing.rs:194:9
|
192 | / macro_rules! query_ensure {
193 | | ([]$($args:tt)) => {
194 | | query_ensure($($args)
)
| | ^^^^^^^^^^^^^^^^^^^^^^^ the trait Hash is not implemented for rustc_ast::tokenstream::TokenStream, which is required by DefaultCache<(rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream), Erased<query::erase::Erase<Result<&'tcx rustc_ast::tokenstream::TokenStream, ()>>::{opaque#0}>>: rustc_query_system::query::QueryCache
195 | | };
... |
200 | | query_ensure!([$($modifiers)]$($args))
| | ----------------------------------------
| | |
| | in this macro invocation (#4)
| | in this macro invocation (#5)
201 | | };
202 | | }
| | -
| | |
| | in this expansion of query_ensure! (#3)
| |in this expansion of query_ensure! (#4)
| in this expansion of query_ensure! (#5)
...
275 | / macro_rules! define_callbacks {
276 | | (
277 | | $($(#[$attr:meta])*
278 | | [$($modifiers:tt)] fn $name:ident($($K:tt)) -> $V:ty,)) => {
... |
382 | / query_ensure!(
383 | [$($modifiers)
]
384 | self.tcx,
385 | self.tcx.query_system.fns.engine.$name,
...
388 | false,
389 | | )
| |_________________- in this macro invocation (#3)
...
490 | | };
491 | | }
| |
- in this expansion of define_callbacks! (#2)
|
::: compiler/rustc_middle/src/query/mod.rs:108:1
|
108 | / rustc_queries! {
109 | | query derive_macro_expansion(key: (LocalExpnId, Svh, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
110 | | // eval_always
111 | | // no_hash
... |
2335 | | }
2336 | | }
| | -
| | |
| |______in this expansion of rustc_query_append! (#1)
| in this macro invocation (#2)
2337 |
2338 | rustc_query_append! { define_callbacks! }
| ----------------------------------------- in this macro invocation (#1)
|
= help: the trait rustc_query_system::query::QueryCache is implemented for DefaultCache<K, V>
= note: required for &'tcx rustc_ast::tokenstream::TokenStream to implement Hash
= note: 1 redundant requirement hidden
= note: required for (rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream) to implement Hash
= note: required for DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>> to implement rustc_query_system::query::QueryCache
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-16771981020465904745.txt'
= note: consider using --verbose to print the full type name to the console

error[E0277]: the trait bound rustc_ast::tokenstream::TokenStream: Hash is not satisfied
--> compiler/rustc_middle/src/query/plumbing.rs:400:21
|
275 | / macro_rules! define_callbacks {
276 | | (
277 | | $($(#[$attr:meta])*
278 | | [$($modifiers:tt)] fn $name:ident($($K:tt)) -> $V:ty,)*) => {
... |
397 | | query_ensure(
| | ------------ required by a bound introduced by this call
... |
400 | | &self.tcx.query_system.caches.$name,
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait Hash is not implemented for rustc_ast::tokenstream::TokenStream, which is required by DefaultCache<(rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream), Erased<query::erase::Erase<Result<&'tcx rustc_ast::tokenstream::TokenStream, ()>>::{opaque#0}>>: rustc_query_system::query::QueryCache
... |
490 | | };
491 | | }
| |_- in this expansion of define_callbacks! (#2)
|
::: compiler/rustc_middle/src/query/mod.rs:108:1
|
108 | / rustc_queries! {
109 | | query derive_macro_expansion(key: (LocalExpnId, Svh, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
110 | | // eval_always
111 | | // no_hash
... |
2335 | | }
2336 | | }
| | -
| | |
| |__in this expansion of rustc_query_append! (#1)
| in this macro invocation (#2)
2337 |
2338 | rustc_query_append! { define_callbacks! }
| ----------------------------------------- in this macro invocation (#1)
|
= help: the trait rustc_query_system::query::QueryCache is implemented for DefaultCache<K, V>
= note: required for &'tcx rustc_ast::tokenstream::TokenStream to implement Hash
= note: 1 redundant requirement hidden
= note: required for (rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream) to implement Hash
= note: required for DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>> to implement rustc_query_system::query::QueryCache
note: required by a bound in query_ensure
--> compiler/rustc_middle/src/query/plumbing.rs:155:12
|
148 | pub fn query_ensure<'tcx, Cache>(
| ------------ required by a bound in this function
...
155 | Cache: QueryCache,
| ^^^^^^^^^^ required by this bound in query_ensure
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-16771981020465904745.txt'
= note: consider using --verbose to print the full type name to the console

error[E0277]: the trait bound rustc_ast::tokenstream::TokenStream: Hash is not satisfied
--> compiler/rustc_middle/src/query/plumbing.rs:397:17
|
275 | / macro_rules! define_callbacks {
276 | | (
277 | | $($(#[$attr:meta])*
278 | | [$($modifiers:tt)] fn $name:ident($($K:tt)) -> $V:ty,)*) => {
... |
397 | |/ query_ensure(
398 | || self.tcx,
399 | || self.tcx.query_system.fns.engine.$name,
400 | || &self.tcx.query_system.caches.$name,
401 | || key.into_query_param(),
402 | || true,
403 | || );
| ||_______________^ the trait Hash is not implemented for rustc_ast::tokenstream::TokenStream, which is required by DefaultCache<(rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream), Erased<query::erase::Erase<Result<&'tcx rustc_ast::tokenstream::TokenStream, ()>>::{opaque#0}>>: rustc_query_system::query::QueryCache
... |
490 | | };
491 | | }
| |
- in this expansion of define_callbacks! (#2)
|
::: compiler/rustc_middle/src/query/mod.rs:108:1
|
108 | / rustc_queries! {
109 | | query derive_macro_expansion(key: (LocalExpnId, Svh, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
110 | | // eval_always
111 | | // no_hash
... |
2335 | | }
2336 | | }
| | -
| | |
| |___in this expansion of rustc_query_append! (#1)
| in this macro invocation (#2)
2337 |
2338 | rustc_query_append! { define_callbacks! }
| ----------------------------------------- in this macro invocation (#1)
|
= help: the trait rustc_query_system::query::QueryCache is implemented for DefaultCache<K, V>
= note: required for &'tcx rustc_ast::tokenstream::TokenStream to implement Hash
= note: 1 redundant requirement hidden
= note: required for (rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream) to implement Hash
= note: required for DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>> to implement rustc_query_system::query::QueryCache
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-16771981020465904745.txt'
= note: consider using --verbose to print the full type name to the console

error[E0277]: the trait bound rustc_ast::tokenstream::TokenStream: Hash is not satisfied
--> compiler/rustc_middle/src/query/plumbing.rs:425:21
|
275 | / macro_rules! define_callbacks {
276 | | (
277 | | $($(#[$attr:meta])*
278 | | [$($modifiers:tt)] fn $name:ident($($K:tt)) -> $V:ty,)*) => {
... |
422 | | restore::<$V>(query_get_at(
| | ------------ required by a bound introduced by this call
... |
425 | | &self.tcx.query_system.caches.$name,
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait Hash is not implemented for rustc_ast::tokenstream::TokenStream, which is required by DefaultCache<(rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream), Erased<query::erase::Erase<Result<&'tcx rustc_ast::tokenstream::TokenStream, ()>>::{opaque#0}>>: rustc_query_system::query::QueryCache
... |
490 | | };
491 | | }
| |_- in this expansion of define_callbacks! (#2)
|
::: compiler/rustc_middle/src/query/mod.rs:108:1
|
108 | / rustc_queries! {
109 | | query derive_macro_expansion(key: (LocalExpnId, Svh, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
110 | | // eval_always
111 | | // no_hash
... |
2335 | | }
2336 | | }
| | -
| | |
| |__in this expansion of rustc_query_append! (#1)
| in this macro invocation (#2)
2337 |
2338 | rustc_query_append! { define_callbacks! }
| ----------------------------------------- in this macro invocation (#1)
|
= help: the trait rustc_query_system::query::QueryCache is implemented for DefaultCache<K, V>
= note: required for &'tcx rustc_ast::tokenstream::TokenStream to implement Hash
= note: 1 redundant requirement hidden
= note: required for (rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream) to implement Hash
= note: required for DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>> to implement rustc_query_system::query::QueryCache
note: required by a bound in query_get_at
--> compiler/rustc_middle/src/query/plumbing.rs:138:12
|
130 | pub fn query_get_at<'tcx, Cache>(
| ------------ required by a bound in this function
...
138 | Cache: QueryCache,
| ^^^^^^^^^^ required by this bound in query_get_at
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-16771981020465904745.txt'
= note: consider using --verbose to print the full type name to the console

error[E0277]: the trait bound rustc_ast::tokenstream::TokenStream: Hash is not satisfied
--> compiler/rustc_middle/src/query/plumbing.rs:422:31
|
275 | / macro_rules! define_callbacks {
276 | | (
277 | | $($(#[$attr:meta])*
278 | | [$($modifiers:tt)] fn $name:ident($($K:tt)) -> $V:ty,)*) => {
... |
422 | | restore::<$V>(query_get_at(
| | _______________________________^
423 | || self.tcx,
424 | || self.tcx.query_system.fns.engine.$name,
425 | || &self.tcx.query_system.caches.$name,
426 | || self.span,
427 | || key.into_query_param(),
428 | || ))
| ||_______________^ the trait Hash is not implemented for rustc_ast::tokenstream::TokenStream, which is required by DefaultCache<(rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream), Erased<query::erase::Erase<Result<&'tcx rustc_ast::tokenstream::TokenStream, ()>>::{opaque#0}>>: rustc_query_system::query::QueryCache
... |
490 | | };
491 | | }
| |
- in this expansion of define_callbacks! (#2)
|
::: compiler/rustc_middle/src/query/mod.rs:108:1
|
108 | / rustc_queries! {
109 | | query derive_macro_expansion(key: (LocalExpnId, Svh, &'tcx TokenStream)) -> Result<&'tcx TokenStream, ()> {
110 | | // eval_always
111 | | // no_hash
... |
2335 | | }
2336 | | }
| | -
| | |
| |___in this expansion of rustc_query_append! (#1)
| in this macro invocation (#2)
2337 |
2338 | rustc_query_append! { define_callbacks! }
| ----------------------------------------- in this macro invocation (#1)
|
= help: the trait rustc_query_system::query::QueryCache is implemented for DefaultCache<K, V>
= note: required for &'tcx rustc_ast::tokenstream::TokenStream to implement Hash
= note: 1 redundant requirement hidden
= note: required for (rustc_span::LocalExpnId, rustc_data_structures::svh::Svh, &'tcx rustc_ast::tokenstream::TokenStream) to implement Hash
= note: required for DefaultCache<(LocalExpnId, Svh, &TokenStream), Erased<Erase<Result<&TokenStream, ()>>::{opaque#0}>> to implement rustc_query_system::query::QueryCache
= note: the full name for the type has been written to '/home/felix/gits/rust/build/x86_64-unknown-linux-gnu/stage0-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-3afd8e69956fb57f.long-type-16771981020465904745.txt'
= note: consider using --verbose to print the full type name to the console

For more information about this error, try rustc --explain E0277.
error: could not compile rustc_middle (lib) due to 9 previous errors

fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
Encodable::encode(self, &mut HashEncoder { hasher: state });
}
}

/// Indicates whether a token can join with the following token to form a
/// compound token. Used for conversions to `proc_macro::Spacing`. Also used to
/// guide pretty-printing, which is where the `JointHidden` value (which isn't
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_expand/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_parse = { path = "../rustc_parse" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_expand/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ pub mod module;
#[allow(rustc::untranslatable_diagnostic)]
pub mod proc_macro;

pub fn provide(providers: &mut rustc_middle::util::Providers) {
providers.derive_macro_expansion = proc_macro::provide_derive_macro_expansion;
}

rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
178 changes: 147 additions & 31 deletions compiler/rustc_expand/src/proc_macro.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
use std::cell::Cell;
use std::ptr::{self, NonNull};

use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_data_structures::svh::Svh;
use rustc_errors::ErrorGuaranteed;
use rustc_middle::ty::{self, TyCtxt};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_session::Session;
use rustc_session::config::ProcMacroExecutionStrategy;
use rustc_span::Span;
use rustc_span::profiling::SpannedEventArgRecorder;
use rustc_span::{LocalExpnId, Span};

use crate::base::{self, *};
use crate::{errors, proc_macro_server};
Expand All @@ -31,9 +37,9 @@ impl<T> pm::bridge::server::MessagePipe<T> for MessagePipe<T> {
}
}

fn exec_strategy(ecx: &ExtCtxt<'_>) -> impl pm::bridge::server::ExecutionStrategy {
pub fn exec_strategy(sess: &Session) -> impl pm::bridge::server::ExecutionStrategy {
pm::bridge::server::MaybeCrossThread::<MessagePipe<_>>::new(
ecx.sess.opts.unstable_opts.proc_macro_execution_strategy
sess.opts.unstable_opts.proc_macro_execution_strategy
== ProcMacroExecutionStrategy::CrossThread,
)
}
Expand All @@ -55,7 +61,7 @@ impl base::BangProcMacro for BangProcMacro {
});

let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let strategy = exec_strategy(ecx);
let strategy = exec_strategy(ecx.sess);
let server = proc_macro_server::Rustc::new(ecx);
self.client.run(&strategy, server, input, proc_macro_backtrace).map_err(|e| {
ecx.dcx().emit_err(errors::ProcMacroPanicked {
Expand Down Expand Up @@ -86,7 +92,7 @@ impl base::AttrProcMacro for AttrProcMacro {
});

let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let strategy = exec_strategy(ecx);
let strategy = exec_strategy(ecx.sess);
let server = proc_macro_server::Rustc::new(ecx);
self.client.run(&strategy, server, annotation, annotated, proc_macro_backtrace).map_err(
|e| {
Expand Down Expand Up @@ -114,6 +120,13 @@ impl MultiItemModifier for DeriveProcMacro {
item: Annotatable,
_is_derive_const: bool,
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
let _timer = ecx.sess.prof.generic_activity_with_arg_recorder(
"expand_derive_proc_macro_outer",
|recorder| {
recorder.record_arg_with_span(ecx.sess.source_map(), ecx.expansion_descr(), span);
},
);

// We need special handling for statement items
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
let is_stmt = matches!(item, Annotatable::Stmt(..));
Expand All @@ -124,36 +137,40 @@ impl MultiItemModifier for DeriveProcMacro {
// altogether. See #73345.
crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess);
let input = item.to_tokens();
let stream = {
let _timer =
ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
recorder.record_arg_with_span(
ecx.sess.source_map(),
ecx.expansion_descr(),
span,
);
});
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let strategy = exec_strategy(ecx);
let server = proc_macro_server::Rustc::new(ecx);
match self.client.run(&strategy, server, input, proc_macro_backtrace) {
Ok(stream) => stream,
Err(e) => {
ecx.dcx().emit_err({
errors::ProcMacroDerivePanicked {
span,
message: e.as_str().map(|message| {
errors::ProcMacroDerivePanickedHelp { message: message.into() }
}),
}
});
return ExpandResult::Ready(vec![]);
}
let res = ty::tls::with(|tcx| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be necessary, ecx.resolver has tcx, it just needs to be exposed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave it a try, but this seems to require adding a lifetime <'tcx> to ResolverExpand (the trait), which required more/deeper changes than I was able to make.

// FIXME(pr-time): without flattened some (weird) tests fail, but no idea if it's correct/enough
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory flattening should always be correct (proc macro APIs will perform flattening lazily when necessary), but in practice there may be issues with badly written proc macros that pretty-print token streams and then parse the result as a text.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mhhm, makes sense. What would you suggest for now? I think caching needs the flattening, so should I try to not flatten when caching is disabled, that is, use the same behavior as before this PR?

let input = tcx.arena.alloc(input.flattened()) as &TokenStream;
let invoc_id = ecx.current_expansion.id;
let invoc_expn_data = invoc_id.expn_data();

assert_eq!(invoc_expn_data.call_site, span);

// FIXME(pr-time): Is this the correct way to check for incremental compilation (as
// well as for `cache_proc_macros`)?
if tcx.sess.opts.incremental.is_some() && tcx.sess.opts.unstable_opts.cache_proc_macros
{
// FIXME(pr-time): Just using the crate hash to notice when the proc-macro code has
// changed. How to *correctly* depend on exactly the macro definition?
// I.e., depending on the crate hash is just a HACK, and ideally the dependency would be
// more narrow.
let macro_def_id = invoc_expn_data.macro_def_id.unwrap();
let proc_macro_crate_hash = tcx.crate_hash(macro_def_id.krate);

let key = (invoc_id, proc_macro_crate_hash, input);

enter_context((ecx, self.client), move || tcx.derive_macro_expansion(key).cloned())
} else {
expand_derive_macro(tcx, invoc_id, input, ecx, self.client).cloned()
}
});

let Ok(output) = res else {
// error will already have been emitted
return ExpandResult::Ready(vec![]);
};

let error_count_before = ecx.dcx().err_count();
let mut parser = Parser::new(&ecx.sess.psess, stream, Some("proc-macro derive"));
let mut parser = Parser::new(&ecx.sess.psess, output, Some("proc-macro derive"));
let mut items = vec![];

loop {
Expand Down Expand Up @@ -181,3 +198,102 @@ impl MultiItemModifier for DeriveProcMacro {
ExpandResult::Ready(items)
}
}

pub(super) fn provide_derive_macro_expansion<'tcx>(
tcx: TyCtxt<'tcx>,
key: (LocalExpnId, Svh, &'tcx TokenStream),
) -> Result<&'tcx TokenStream, ()> {
let (invoc_id, _macro_crate_hash, input) = key;

with_context(|(ecx, client)| expand_derive_macro(tcx, invoc_id, input, ecx, *client))
}

type CLIENT = pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>;

fn expand_derive_macro<'tcx>(
tcx: TyCtxt<'tcx>,
invoc_id: LocalExpnId,
input: &'tcx TokenStream,
ecx: &mut ExtCtxt<'_>,
client: CLIENT,
) -> Result<&'tcx TokenStream, ()> {
let invoc_expn_data = invoc_id.expn_data();
let span = invoc_expn_data.call_site;
let event_arg = invoc_expn_data.kind.descr();
let _timer = tcx.sess.prof.generic_activity_with_arg_recorder(
"expand_derive_proc_macro_inner",
|recorder| {
recorder.record_arg_with_span(tcx.sess.source_map(), event_arg.clone(), span);
},
);

let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let strategy = crate::proc_macro::exec_strategy(tcx.sess);
let server = crate::proc_macro_server::Rustc::new(ecx);

match client.run(&strategy, server, input.clone(), proc_macro_backtrace) {
Ok(stream) => Ok(tcx.arena.alloc(stream) as &TokenStream),
Err(e) => {
tcx.dcx().emit_err({
errors::ProcMacroDerivePanicked {
span,
message: e.as_str().map(|message| errors::ProcMacroDerivePanickedHelp {
message: message.into(),
}),
}
});
Err(())
}
}
}

// based on rust/compiler/rustc_middle/src/ty/context/tls.rs
thread_local! {
/// A thread local variable that stores a pointer to the current `CONTEXT`.
static TLV: Cell<(*mut (), Option<CLIENT>)> = const { Cell::new((ptr::null_mut(), None)) };
}

/// Sets `context` as the new current `CONTEXT` for the duration of the function `f`.
#[inline]
pub(crate) fn enter_context<'a, F, R>(context: (&mut ExtCtxt<'a>, CLIENT), f: F) -> R
where
F: FnOnce() -> R,
{
let (ectx, client) = context;
let erased = (ectx as *mut _ as *mut (), Some(client));
TLV.with(|tlv| {
let old = tlv.replace(erased);
let _reset = rustc_data_structures::defer(move || tlv.set(old));
f()
})
}

/// Allows access to the current `CONTEXT`.
/// Panics if there is no `CONTEXT` available.
#[inline]
#[track_caller]
fn with_context<F, R>(f: F) -> R
where
F: for<'a, 'b> FnOnce(&'b mut (&mut ExtCtxt<'a>, CLIENT)) -> R,
{
let (ectx, client_opt) = TLV.get();
let ectx = NonNull::new(ectx).expect("no CONTEXT stored in tls");

// We could get an `CONTEXT` pointer from another thread.
// Ensure that `CONTEXT` is `DynSync`.
// FIXME(pr-time): we should not be able to?
// sync::assert_dyn_sync::<CONTEXT<'_>>();

// prevent double entering, as that would allow creating two `&mut ExtCtxt`s
// FIXME(pr-time): probably use a RefCell instead (which checks this properly)?
TLV.with(|tlv| {
let old = tlv.replace((ptr::null_mut(), None));
let _reset = rustc_data_structures::defer(move || tlv.set(old));
let ectx = {
let mut casted = ectx.cast::<ExtCtxt<'_>>();
unsafe { casted.as_mut() }
};

f(&mut (ectx, client_opt.unwrap()))
})
}
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
providers.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1;
providers.early_lint_checks = early_lint_checks;
proc_macro_decls::provide(providers);
rustc_expand::provide(providers);
rustc_const_eval::provide(providers);
rustc_middle::hir::provide(providers);
rustc_borrowck::provide(providers);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ macro_rules! arena_types {
[decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph,
[] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls,
[] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>,
[decode] token_stream: rustc_ast::tokenstream::TokenStream,
]);
)
}
Expand Down
Loading
Loading