-
-
Notifications
You must be signed in to change notification settings - Fork 15.4k
break rustc_expand-rustc_middle dependency #161263
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,8 @@ | ||
| use rustc_ast as ast; | ||
| use rustc_ast::tokenstream::TokenStream; | ||
| use rustc_data_structures::AtomicRef; | ||
| use rustc_data_structures::profiling::TimingGuard; | ||
| use rustc_errors::ErrorGuaranteed; | ||
| use rustc_middle::ty::{self, TyCtxt}; | ||
| use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser}; | ||
| use rustc_proc_macro as pm; | ||
| use rustc_session::Session; | ||
|
|
@@ -113,14 +113,7 @@ impl MultiItemModifier for DeriveProcMacro { | |
| let res = if ecx.sess.opts.incremental.is_some() | ||
| && ecx.sess.opts.unstable_opts.cache_proc_macros | ||
| { | ||
| ty::tls::with(|tcx| { | ||
| let input = &*tcx.arena.alloc(input); | ||
| let key: (LocalExpnId, &TokenStream) = (invoc_id, input); | ||
|
|
||
| QueryDeriveExpandCtx::enter(ecx, self.client, move || { | ||
| tcx.derive_macro_expansion(key).cloned() | ||
| }) | ||
| }) | ||
| (*EXPAND_DERIVE_CACHED)(invoc_id, input, ecx, self.client) | ||
| } else { | ||
| expand_derive_macro(invoc_id, input, ecx, self.client) | ||
| }; | ||
|
|
@@ -163,24 +156,9 @@ impl MultiItemModifier for DeriveProcMacro { | |
| } | ||
| } | ||
|
|
||
| /// Provide a query for computing the output of a derive macro. | ||
| pub(super) fn provide_derive_macro_expansion<'tcx>( | ||
| tcx: TyCtxt<'tcx>, | ||
| key: (LocalExpnId, &'tcx TokenStream), | ||
| ) -> Result<&'tcx TokenStream, ()> { | ||
| let (invoc_id, input) = key; | ||
|
|
||
| // Make sure that we invalidate the query when the crate defining the proc macro changes | ||
| let _ = tcx.crate_hash(invoc_id.expn_data().macro_def_id.unwrap().krate); | ||
|
|
||
| QueryDeriveExpandCtx::with(|ecx, client| { | ||
| expand_derive_macro(invoc_id, input.clone(), ecx, client).map(|ts| &*tcx.arena.alloc(ts)) | ||
| }) | ||
| } | ||
|
|
||
| type DeriveClient = pm::bridge::client::Client; | ||
|
|
||
| fn expand_derive_macro( | ||
| pub fn expand_derive_macro( | ||
| invoc_id: LocalExpnId, | ||
| input: TokenStream, | ||
| ecx: &mut ExtCtxt<'_>, | ||
|
|
@@ -216,47 +194,6 @@ fn expand_derive_macro( | |
| } | ||
| } | ||
|
|
||
| /// Stores the context necessary to expand a derive proc macro via a query. | ||
| struct QueryDeriveExpandCtx { | ||
| /// Type-erased version of `&mut ExtCtxt` | ||
| expansion_ctx: *mut (), | ||
| client: DeriveClient, | ||
| } | ||
|
|
||
| impl QueryDeriveExpandCtx { | ||
| /// Store the extension context and the client into the thread local value. | ||
| /// It will be accessible via the `with` method while `f` is active. | ||
| fn enter<F, R>(ecx: &mut ExtCtxt<'_>, client: DeriveClient, f: F) -> R | ||
| where | ||
| F: FnOnce() -> R, | ||
| { | ||
| // We need erasure to get rid of the lifetime | ||
| let ctx = Self { expansion_ctx: ecx as *mut _ as *mut (), client }; | ||
| DERIVE_EXPAND_CTX.set(&ctx, f) | ||
| } | ||
|
|
||
| /// Accesses the thread local value of the derive expansion context. | ||
| /// Must be called while the `enter` function is active. | ||
| fn with<F, R>(f: F) -> R | ||
| where | ||
| F: for<'a, 'b> FnOnce(&'b mut ExtCtxt<'a>, DeriveClient) -> R, | ||
| { | ||
| DERIVE_EXPAND_CTX.with(|ctx| { | ||
| let ectx = { | ||
| let casted = ctx.expansion_ctx.cast::<ExtCtxt<'_>>(); | ||
| // SAFETY: We can only get the value from `with` while the `enter` function | ||
| // is active (on the callstack), and that function's signature ensures that the | ||
| // lifetime is valid. | ||
| // If `with` is called at some other time, it will panic due to usage of | ||
| // `scoped_tls::with`. | ||
| unsafe { casted.as_mut().unwrap() } | ||
| }; | ||
|
|
||
| f(ectx, ctx.client) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| // When we invoke a query to expand a derive proc macro, we need to provide it with the expansion | ||
| // context and derive Client. We do that using a thread-local. | ||
| scoped_tls::scoped_thread_local!(static DERIVE_EXPAND_CTX: QueryDeriveExpandCtx); | ||
| pub static EXPAND_DERIVE_CACHED: AtomicRef< | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we use EII here instead of an
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. EIIs aren't used anywhere inside rustc yet. It is probably fine given that no default impl is necessary, but maybe do it in a separate PR that moves all callbacks to EII? Edit: Actually please wait with EII usage until #159843 gets merged. |
||
| fn(LocalExpnId, TokenStream, &mut ExtCtxt<'_>, DeriveClient) -> Result<TokenStream, ()>, | ||
| > = AtomicRef::new(&(expand_derive_macro as _)); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| [package] | ||
| name = "rustc_expand_queries" | ||
| version = "0.0.0" | ||
| edition = "2024" | ||
| build = false | ||
|
|
||
| [lib] | ||
| doctest = false | ||
|
|
||
| [dependencies] | ||
| # tidy-alphabetical-start | ||
| rustc_ast = { path = "../rustc_ast" } | ||
| rustc_expand = { path = "../rustc_expand" } | ||
| rustc_middle = { path = "../rustc_middle" } | ||
| # We must use the proc_macro version that we will compile proc-macros against, | ||
| # not the one from our own sysroot. | ||
| rustc_proc_macro = { path = "../rustc_proc_macro" } | ||
| rustc_span = { path = "../rustc_span" } | ||
| scoped-tls = "1.0" | ||
| # tidy-alphabetical-end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| use rustc_ast::tokenstream::TokenStream; | ||
| use rustc_expand::base::ExtCtxt; | ||
| use rustc_middle::ty::{TyCtxt, tls}; | ||
| use rustc_proc_macro as pm; | ||
| use rustc_span::LocalExpnId; | ||
|
|
||
| type DeriveClient = pm::bridge::client::Client; | ||
|
|
||
| /// Stores the context necessary to expand a derive proc macro via a query. | ||
| struct QueryDeriveExpandCtx { | ||
| /// Type-erased version of `&mut ExtCtxt` | ||
| expansion_ctx: *mut (), | ||
| client: DeriveClient, | ||
| } | ||
|
|
||
| impl QueryDeriveExpandCtx { | ||
| /// Store the extension context and the client into the thread local value. | ||
| /// It will be accessible via the `with` method while `f` is active. | ||
| fn enter<F, R>(ecx: &mut ExtCtxt<'_>, client: DeriveClient, f: F) -> R | ||
| where | ||
| F: FnOnce() -> R, | ||
| { | ||
| // We need erasure to get rid of the lifetime | ||
| let ctx = Self { expansion_ctx: ecx as *mut _ as *mut (), client }; | ||
| DERIVE_EXPAND_CTX.set(&ctx, f) | ||
| } | ||
|
|
||
| /// Accesses the thread local value of the derive expansion context. | ||
| /// Must be called while the `enter` function is active. | ||
| fn with<F, R>(f: F) -> R | ||
| where | ||
| F: for<'a, 'b> FnOnce(&'b mut ExtCtxt<'a>, DeriveClient) -> R, | ||
| { | ||
| DERIVE_EXPAND_CTX.with(|ctx| { | ||
| let ectx = { | ||
| let casted = ctx.expansion_ctx.cast::<ExtCtxt<'_>>(); | ||
| // SAFETY: We can only get the value from `with` while the `enter` function | ||
| // is active (on the callstack), and that function's signature ensures that the | ||
| // lifetime is valid. | ||
| // If `with` is called at some other time, it will panic due to usage of | ||
| // `scoped_tls::with`. | ||
| unsafe { casted.as_mut().unwrap() } | ||
| }; | ||
|
|
||
| f(ectx, ctx.client) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| // When we invoke a query to expand a derive proc macro, we need to provide it with the expansion | ||
| // context and derive Client. We do that using a thread-local. | ||
| scoped_tls::scoped_thread_local!(static DERIVE_EXPAND_CTX: QueryDeriveExpandCtx); | ||
|
|
||
| pub(crate) fn expand_derive_macro( | ||
| invoc_id: LocalExpnId, | ||
| input: TokenStream, | ||
| ecx: &mut ExtCtxt<'_>, | ||
| client: DeriveClient, | ||
| ) -> Result<TokenStream, ()> { | ||
| tls::with(|tcx| { | ||
| let input = &*tcx.arena.alloc(input); | ||
| let key: (LocalExpnId, &TokenStream) = (invoc_id, input); | ||
|
|
||
| QueryDeriveExpandCtx::enter(ecx, client, move || tcx.derive_macro_expansion(key).cloned()) | ||
| }) | ||
| } | ||
|
|
||
| /// Provide a query for computing the output of a derive macro. | ||
| pub(crate) fn derive_macro_expansion<'tcx>( | ||
| tcx: TyCtxt<'tcx>, | ||
| key: (LocalExpnId, &'tcx TokenStream), | ||
| ) -> Result<&'tcx TokenStream, ()> { | ||
| let (invoc_id, input) = key; | ||
|
|
||
| // Make sure that we invalidate the query when the crate defining the proc macro changes | ||
| let _ = tcx.crate_hash(invoc_id.expn_data().macro_def_id.unwrap().krate); | ||
|
|
||
| QueryDeriveExpandCtx::with(|ecx, client| { | ||
| rustc_expand::proc_macro::expand_derive_macro(invoc_id, input.clone(), ecx, client) | ||
| .map(|ts| &*tcx.arena.alloc(ts)) | ||
| }) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| #![allow(internal_features, reason = "proc macro internals")] | ||
| #![feature(proc_macro_internals)] | ||
|
|
||
| mod derive; | ||
|
|
||
| pub fn enable() { | ||
| rustc_expand::proc_macro::EXPAND_DERIVE_CACHED.swap(&(derive::expand_derive_macro as _)); | ||
| } | ||
|
|
||
| pub fn provide(providers: &mut rustc_middle::query::Providers) { | ||
| providers.derive_macro_expansion = derive::derive_macro_expansion; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that we expect this to be replaced by the proper function way before this is ever called, does it make sense to default this to
expand_derive_macro? Can we panic instead?View changes since the review