From 1e4af5e39a31219e9d53d18821057abf6d4fe1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 4 Dec 2023 02:10:11 +0100 Subject: [PATCH] Introduce proc_macro::DeriveExpansionOptions --- compiler/rustc_expand/src/proc_macro.rs | 11 ++++--- .../rustc_expand/src/proc_macro_server.rs | 13 +++++++- compiler/rustc_passes/src/check_attr.rs | 7 ++++ library/proc_macro/src/bridge/client.rs | 33 +++++++++++++++++-- library/proc_macro/src/bridge/mod.rs | 1 + library/proc_macro/src/lib.rs | 27 +++++++++++++++ .../auxiliary/is-derive-const.rs | 13 ++++++++ .../const_derives/derive-const-custom.rs | 20 +++++++++++ 8 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/auxiliary/is-derive-const.rs create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-custom.rs diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 39a16259fa6e5..20aa036036235 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -59,7 +59,7 @@ impl base::BangProcMacro for BangProcMacro { let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; let strategy = exec_strategy(ecx); - let server = proc_macro_server::Rustc::new(ecx); + let server = proc_macro_server::Rustc::new(ecx, Default::default()); self.client.run(&strategy, server, input, proc_macro_backtrace).map_err(|e| { ecx.sess.emit_err(errors::ProcMacroPanicked { span, @@ -90,7 +90,7 @@ impl base::AttrProcMacro for AttrProcMacro { let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; let strategy = exec_strategy(ecx); - let server = proc_macro_server::Rustc::new(ecx); + let server = proc_macro_server::Rustc::new(ecx, Default::default()); self.client.run(&strategy, server, annotation, annotated, proc_macro_backtrace).map_err( |e| { let mut err = ecx.struct_span_err(span, "custom attribute panicked"); @@ -114,7 +114,7 @@ impl MultiItemModifier for DeriveProcMacro { span: Span, _meta_item: &ast::MetaItem, item: Annotatable, - _is_derive_const: bool, + is_derive_const: bool, ) -> ExpandResult, Annotatable> { // We need special handling for statement items // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`) @@ -142,7 +142,10 @@ impl MultiItemModifier for DeriveProcMacro { }); let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace; let strategy = exec_strategy(ecx); - let server = proc_macro_server::Rustc::new(ecx); + let server = proc_macro_server::Rustc::new( + ecx, + proc_macro_server::ExpansionOptions { is_derive_const }, + ); match self.client.run(&strategy, server, input, proc_macro_backtrace) { Ok(stream) => stream, Err(e) => { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index b057a645f8195..f78c461290488 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -370,10 +370,11 @@ pub(crate) struct Rustc<'a, 'b> { mixed_site: Span, krate: CrateNum, rebased_spans: FxHashMap, + options: ExpansionOptions, } impl<'a, 'b> Rustc<'a, 'b> { - pub fn new(ecx: &'a mut ExtCtxt<'b>) -> Self { + pub fn new(ecx: &'a mut ExtCtxt<'b>, options: ExpansionOptions) -> Self { let expn_data = ecx.current_expansion.id.expn_data(); Rustc { def_site: ecx.with_def_site_ctxt(expn_data.def_site), @@ -381,6 +382,7 @@ impl<'a, 'b> Rustc<'a, 'b> { mixed_site: ecx.with_mixed_site_ctxt(expn_data.call_site), krate: expn_data.macro_def_id.unwrap().krate, rebased_spans: FxHashMap::default(), + options, ecx, } } @@ -390,6 +392,11 @@ impl<'a, 'b> Rustc<'a, 'b> { } } +#[derive(Default)] +pub(crate) struct ExpansionOptions { + pub(crate) is_derive_const: bool, +} + impl server::Types for Rustc<'_, '_> { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; @@ -477,6 +484,10 @@ impl server::FreeFunctions for Rustc<'_, '_> { } self.sess().span_diagnostic.emit_diagnostic(&mut diag); } + + fn is_derive_const(&mut self) -> bool { + self.options.is_derive_const + } } impl server::TokenStream for Rustc<'_, '_> { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4910d63010c6e..c402fc57423fb 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2280,6 +2280,13 @@ impl CheckAttrVisitor<'_> { /// /// If this best effort goes wrong, it will just emit a worse error later (see #102923) fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) { + // FIXME(fmease): This is temporary. Update this function to permit the signature of derive + // macros to be EITHER `fn(TS) -> TS` OR `fn(TS, DEO) -> TS`. Should be straightforward to + // implement. + if true { + return; + } + if target != Target::Fn { return; } diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 52a08cad9110f..e1d0de159db1a 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -484,12 +484,16 @@ impl ProcMacro { } } - pub const fn custom_derive( + pub const fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], - expand: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy, + expand: impl ~const ExpandCustomDerive, ) -> Self { - ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } + ProcMacro::CustomDerive { + trait_name, + attributes, + client: Client::expand1(expand.into_fn()), + } } pub const fn attr( @@ -506,3 +510,26 @@ impl ProcMacro { ProcMacro::Bang { name, client: Client::expand1(expand) } } } + +#[const_trait] +pub trait ExpandCustomDerive { + fn into_fn(self) -> impl Fn(crate::TokenStream) -> crate::TokenStream + Copy; +} + +impl const ExpandCustomDerive<()> for F +where + F: Fn(crate::TokenStream) -> crate::TokenStream + Copy, +{ + fn into_fn(self) -> impl Fn(crate::TokenStream) -> crate::TokenStream + Copy { + self + } +} + +impl const ExpandCustomDerive for F +where + F: Fn(crate::TokenStream, crate::DeriveExpansionOptions) -> crate::TokenStream + Copy, +{ + fn into_fn(self) -> impl Fn(crate::TokenStream) -> crate::TokenStream + Copy { + move |input| self(input, Default::default()) + } +} diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 86ce5d9c6d5fe..b3e73d877f22b 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -59,6 +59,7 @@ macro_rules! with_api { fn track_path(path: &str); fn literal_from_str(s: &str) -> Result, ()>; fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>); + fn is_derive_const() -> bool; }, TokenStream { fn drop($self: $S::TokenStream); diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index d3f1fba9369ca..72021975f32e9 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -25,7 +25,9 @@ #![feature(rustc_allow_const_fn_unstable)] #![feature(staged_api)] #![feature(allow_internal_unstable)] +#![feature(const_trait_impl)] #![feature(decl_macro)] +#![feature(effects)] #![feature(maybe_uninit_write_slice)] #![feature(negative_impls)] #![feature(new_uninit)] @@ -85,6 +87,31 @@ impl !Send for TokenStream {} #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl !Sync for TokenStream {} +/// Derive expansion options. +#[unstable(feature = "derive_const", issue = "none")] +#[derive(Default, Clone)] +#[non_exhaustive] +pub struct DeriveExpansionOptions; + +impl DeriveExpansionOptions { + /// Returns the default options. + #[unstable(feature = "derive_const", issue = "none")] + pub fn new() -> Self { + Self::default() + } + + /// Whether this is a `#[derive_const]` or a `#[derive]`. + #[unstable(feature = "derive_const", issue = "none")] + pub fn is_const(&self) -> bool { + bridge::client::FreeFunctions::is_derive_const() + } +} + +#[unstable(feature = "derive_const", issue = "none")] +impl !Send for DeriveExpansionOptions {} +#[unstable(feature = "derive_const", issue = "none")] +impl !Sync for DeriveExpansionOptions {} + /// Error returned from `TokenStream::from_str`. #[stable(feature = "proc_macro_lib", since = "1.15.0")] #[non_exhaustive] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/auxiliary/is-derive-const.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/auxiliary/is-derive-const.rs new file mode 100644 index 0000000000000..edd5cf0b13b36 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/auxiliary/is-derive-const.rs @@ -0,0 +1,13 @@ +// force-host +// no-prefer-dynamic +#![crate_type = "proc-macro"] +#![feature(derive_const)] + +extern crate proc_macro; + +use proc_macro::{TokenStream, DeriveExpansionOptions}; + +#[proc_macro_derive(IsDeriveConst)] +pub fn is_derive_const(_: TokenStream, options: DeriveExpansionOptions) -> TokenStream { + format!("const IS_DERIVE_CONST: bool = {};", options.is_const()).parse().unwrap() +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-custom.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-custom.rs new file mode 100644 index 0000000000000..8c755b73aa134 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const_derives/derive-const-custom.rs @@ -0,0 +1,20 @@ +// check-pass +// edition: 2021 +// aux-crate:is_derive_const=is-derive-const.rs +#![feature(derive_const)] + +const _: () = { + #[derive(is_derive_const::IsDeriveConst)] + struct _Type; + + assert!(!IS_DERIVE_CONST); +}; + +const _: () = { + #[derive_const(is_derive_const::IsDeriveConst)] + struct _Type; + + assert!(IS_DERIVE_CONST); +}; + +fn main() {}