Skip to content

Commit 3768c8f

Browse files
committed
Introduce proc_macro::DeriveExpansionOptions
1 parent 8d39ec1 commit 3768c8f

File tree

13 files changed

+210
-23
lines changed

13 files changed

+210
-23
lines changed

compiler/rustc_expand/src/proc_macro.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl base::BangProcMacro for BangProcMacro {
5959

6060
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
6161
let strategy = exec_strategy(ecx);
62-
let server = proc_macro_server::Rustc::new(ecx);
62+
let server = proc_macro_server::Rustc::new(ecx, Default::default());
6363
self.client.run(&strategy, server, input, proc_macro_backtrace).map_err(|e| {
6464
ecx.dcx().emit_err(errors::ProcMacroPanicked {
6565
span,
@@ -90,7 +90,7 @@ impl base::AttrProcMacro for AttrProcMacro {
9090

9191
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
9292
let strategy = exec_strategy(ecx);
93-
let server = proc_macro_server::Rustc::new(ecx);
93+
let server = proc_macro_server::Rustc::new(ecx, Default::default());
9494
self.client.run(&strategy, server, annotation, annotated, proc_macro_backtrace).map_err(
9595
|e| {
9696
let mut err = ecx.dcx().struct_span_err(span, "custom attribute panicked");
@@ -114,7 +114,7 @@ impl MultiItemModifier for DeriveProcMacro {
114114
span: Span,
115115
_meta_item: &ast::MetaItem,
116116
item: Annotatable,
117-
_is_derive_const: bool,
117+
is_derive_const: bool,
118118
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
119119
// We need special handling for statement items
120120
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
@@ -142,7 +142,10 @@ impl MultiItemModifier for DeriveProcMacro {
142142
});
143143
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
144144
let strategy = exec_strategy(ecx);
145-
let server = proc_macro_server::Rustc::new(ecx);
145+
let server = proc_macro_server::Rustc::new(
146+
ecx,
147+
proc_macro_server::ExpansionOptions { is_derive_const },
148+
);
146149
match self.client.run(&strategy, server, input, proc_macro_backtrace) {
147150
Ok(stream) => stream,
148151
Err(e) => {

compiler/rustc_expand/src/proc_macro_server.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -397,17 +397,19 @@ pub(crate) struct Rustc<'a, 'b> {
397397
mixed_site: Span,
398398
krate: CrateNum,
399399
rebased_spans: FxHashMap<usize, Span>,
400+
options: ExpansionOptions,
400401
}
401402

402403
impl<'a, 'b> Rustc<'a, 'b> {
403-
pub fn new(ecx: &'a mut ExtCtxt<'b>) -> Self {
404+
pub fn new(ecx: &'a mut ExtCtxt<'b>, options: ExpansionOptions) -> Self {
404405
let expn_data = ecx.current_expansion.id.expn_data();
405406
Rustc {
406407
def_site: ecx.with_def_site_ctxt(expn_data.def_site),
407408
call_site: ecx.with_call_site_ctxt(expn_data.call_site),
408409
mixed_site: ecx.with_mixed_site_ctxt(expn_data.call_site),
409410
krate: expn_data.macro_def_id.unwrap().krate,
410411
rebased_spans: FxHashMap::default(),
412+
options,
411413
ecx,
412414
}
413415
}
@@ -417,6 +419,11 @@ impl<'a, 'b> Rustc<'a, 'b> {
417419
}
418420
}
419421

422+
#[derive(Default)]
423+
pub(crate) struct ExpansionOptions {
424+
pub(crate) is_derive_const: bool,
425+
}
426+
420427
impl server::Types for Rustc<'_, '_> {
421428
type FreeFunctions = FreeFunctions;
422429
type TokenStream = TokenStream;
@@ -503,6 +510,10 @@ impl server::FreeFunctions for Rustc<'_, '_> {
503510
}
504511
self.sess().dcx.emit_diagnostic(diag);
505512
}
513+
514+
fn is_derive_const(&mut self) -> bool {
515+
self.options.is_derive_const
516+
}
506517
}
507518

508519
impl server::TokenStream for Rustc<'_, '_> {

compiler/rustc_passes/src/check_attr.rs

+53-15
Original file line numberDiff line numberDiff line change
@@ -2293,10 +2293,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
22932293
}
22942294

22952295
let tcx = self.tcx;
2296-
let Some(token_stream_def_id) = tcx.get_diagnostic_item(sym::TokenStream) else {
2296+
2297+
let Some(token_stream) = tcx
2298+
.get_diagnostic_item(sym::TokenStream)
2299+
.and_then(|did| tcx.type_of(did).no_bound_vars())
2300+
else {
22972301
return;
22982302
};
2299-
let Some(token_stream) = tcx.type_of(token_stream_def_id).no_bound_vars() else {
2303+
let Some(derive_expansion_options) = tcx
2304+
.get_diagnostic_item(sym::DeriveExpansionOptions)
2305+
.and_then(|did| tcx.type_of(did).no_bound_vars())
2306+
else {
23002307
return;
23012308
};
23022309

@@ -2332,8 +2339,24 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
23322339
Unsafety::Normal,
23332340
Abi::Rust,
23342341
);
2342+
let expected_options_sig = tcx.mk_fn_sig(
2343+
[token_stream, derive_expansion_options],
2344+
token_stream,
2345+
false,
2346+
Unsafety::Normal,
2347+
Abi::Rust,
2348+
);
23352349

2336-
if let Err(terr) = ocx.eq(&cause, param_env, expected_sig, sig) {
2350+
let mut result = infcx.probe(|_| ocx.eq(&cause, param_env, expected_sig, sig));
2351+
if result.is_err()
2352+
&& let ProcMacroKind::Derive = kind
2353+
{
2354+
if infcx.probe(|_| ocx.eq(&cause, param_env, expected_options_sig, sig)).is_ok() {
2355+
result = Ok(());
2356+
}
2357+
}
2358+
2359+
if let Err(terr) = result {
23372360
let mut diag = tcx.dcx().create_err(errors::ProcMacroBadSig { span, kind });
23382361

23392362
let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id);
@@ -2368,18 +2391,33 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
23682391
}
23692392
}
23702393

2371-
infcx.err_ctxt().note_type_err(
2372-
&mut diag,
2373-
&cause,
2374-
None,
2375-
Some(ValuePairs::PolySigs(ExpectedFound {
2376-
expected: ty::Binder::dummy(expected_sig),
2377-
found: ty::Binder::dummy(sig),
2378-
})),
2379-
terr,
2380-
false,
2381-
false,
2382-
);
2394+
let mut note_expected_found = |expected_sig| {
2395+
infcx.err_ctxt().note_type_err(
2396+
&mut diag,
2397+
&cause,
2398+
None,
2399+
Some(ValuePairs::PolySigs(ExpectedFound {
2400+
expected: ty::Binder::dummy(expected_sig),
2401+
found: ty::Binder::dummy(sig),
2402+
})),
2403+
terr,
2404+
false,
2405+
false,
2406+
)
2407+
};
2408+
2409+
note_expected_found(expected_sig);
2410+
2411+
if let ProcMacroKind::Derive = kind
2412+
&& tcx
2413+
.features()
2414+
.declared_lib_features
2415+
.iter()
2416+
.any(|&(feature, _)| feature == sym::derive_const)
2417+
{
2418+
note_expected_found(expected_options_sig);
2419+
}
2420+
23832421
diag.emit();
23842422
self.abort.set(true);
23852423
}

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ symbols! {
182182
DecorateLint,
183183
Default,
184184
Deref,
185+
DeriveExpansionOptions,
185186
DiagnosticMessage,
186187
DirBuilder,
187188
Display,

library/proc_macro/src/bridge/client.rs

+30-3
Original file line numberDiff line numberDiff line change
@@ -484,12 +484,16 @@ impl ProcMacro {
484484
}
485485
}
486486

487-
pub const fn custom_derive(
487+
pub const fn custom_derive<Discriminant>(
488488
trait_name: &'static str,
489489
attributes: &'static [&'static str],
490-
expand: impl Fn(crate::TokenStream) -> crate::TokenStream + Copy,
490+
expand: impl ~const ExpandCustomDerive<Discriminant>,
491491
) -> Self {
492-
ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) }
492+
ProcMacro::CustomDerive {
493+
trait_name,
494+
attributes,
495+
client: Client::expand1(expand.into_fn()),
496+
}
493497
}
494498

495499
pub const fn attr(
@@ -506,3 +510,26 @@ impl ProcMacro {
506510
ProcMacro::Bang { name, client: Client::expand1(expand) }
507511
}
508512
}
513+
514+
#[const_trait]
515+
pub trait ExpandCustomDerive<Discriminant> {
516+
fn into_fn(self) -> impl Fn(crate::TokenStream) -> crate::TokenStream + Copy;
517+
}
518+
519+
impl<F> const ExpandCustomDerive<()> for F
520+
where
521+
F: Fn(crate::TokenStream) -> crate::TokenStream + Copy,
522+
{
523+
fn into_fn(self) -> impl Fn(crate::TokenStream) -> crate::TokenStream + Copy {
524+
self
525+
}
526+
}
527+
528+
impl<F> const ExpandCustomDerive<crate::DeriveExpansionOptions> for F
529+
where
530+
F: Fn(crate::TokenStream, crate::DeriveExpansionOptions) -> crate::TokenStream + Copy,
531+
{
532+
fn into_fn(self) -> impl Fn(crate::TokenStream) -> crate::TokenStream + Copy {
533+
move |input| self(input, Default::default())
534+
}
535+
}

library/proc_macro/src/bridge/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ macro_rules! with_api {
6060
fn track_path(path: &str);
6161
fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>;
6262
fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>);
63+
fn is_derive_const() -> bool;
6364
},
6465
TokenStream {
6566
fn drop($self: $S::TokenStream);

library/proc_macro/src/lib.rs

+28
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
#![feature(rustc_allow_const_fn_unstable)]
2626
#![feature(staged_api)]
2727
#![feature(allow_internal_unstable)]
28+
#![feature(const_trait_impl)]
2829
#![feature(decl_macro)]
30+
#![feature(effects)]
2931
#![feature(maybe_uninit_write_slice)]
3032
#![feature(negative_impls)]
3133
#![feature(new_uninit)]
@@ -85,6 +87,32 @@ impl !Send for TokenStream {}
8587
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
8688
impl !Sync for TokenStream {}
8789

90+
/// Derive expansion options.
91+
#[rustc_diagnostic_item = "DeriveExpansionOptions"]
92+
#[unstable(feature = "derive_const", issue = "none")]
93+
#[derive(Default, Clone)]
94+
#[non_exhaustive]
95+
pub struct DeriveExpansionOptions;
96+
97+
impl DeriveExpansionOptions {
98+
/// Returns the default options.
99+
#[unstable(feature = "derive_const", issue = "none")]
100+
pub fn new() -> Self {
101+
Self::default()
102+
}
103+
104+
/// Whether this is a `#[derive_const]` or a `#[derive]`.
105+
#[unstable(feature = "derive_const", issue = "none")]
106+
pub fn is_const(&self) -> bool {
107+
bridge::client::FreeFunctions::is_derive_const()
108+
}
109+
}
110+
111+
#[unstable(feature = "derive_const", issue = "none")]
112+
impl !Send for DeriveExpansionOptions {}
113+
#[unstable(feature = "derive_const", issue = "none")]
114+
impl !Sync for DeriveExpansionOptions {}
115+
88116
/// Error returned from `TokenStream::from_str`.
89117
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
90118
#[non_exhaustive]

src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs

+5
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ impl server::FreeFunctions for RaSpanServer {
8282
fn emit_diagnostic(&mut self, _: bridge::Diagnostic<Self::Span>) {
8383
// FIXME handle diagnostic
8484
}
85+
86+
fn is_derive_const(&mut self) -> bool {
87+
// FIXME: pass the correct information
88+
false
89+
}
8590
}
8691

8792
impl server::TokenStream for RaSpanServer {

src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs

+5
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ impl server::FreeFunctions for TokenIdServer {
7272
}
7373

7474
fn emit_diagnostic(&mut self, _: bridge::Diagnostic<Self::Span>) {}
75+
76+
fn is_derive_const(&mut self) -> bool {
77+
// FIXME: pass the correct information
78+
false
79+
}
7580
}
7681

7782
impl server::TokenStream for TokenIdServer {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// force-host
2+
// no-prefer-dynamic
3+
#![crate_type = "proc-macro"]
4+
#![feature(derive_const)]
5+
6+
extern crate proc_macro;
7+
8+
use proc_macro::{TokenStream, DeriveExpansionOptions};
9+
10+
#[proc_macro_derive(IsDeriveConst)]
11+
pub fn is_derive_const(_: TokenStream, options: DeriveExpansionOptions) -> TokenStream {
12+
format!("const IS_DERIVE_CONST: bool = {};", options.is_const()).parse().unwrap()
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// check-pass
2+
// edition: 2021
3+
// aux-crate:is_derive_const=is-derive-const.rs
4+
#![feature(derive_const)]
5+
6+
const _: () = {
7+
#[derive(is_derive_const::IsDeriveConst)]
8+
struct _Type;
9+
10+
assert!(!IS_DERIVE_CONST);
11+
};
12+
13+
const _: () = {
14+
#[derive_const(is_derive_const::IsDeriveConst)]
15+
struct _Type;
16+
17+
assert!(IS_DERIVE_CONST);
18+
};
19+
20+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Check that we suggest *both* possible signatures of derive proc macros, namely
2+
// fn(TokenStream) -> TokenStream
3+
// and
4+
// fn(TokenStream, DeriveExpansionOptions) -> TokenStream
5+
// provided libs feature `derive_const` is enabled.
6+
7+
// force-host
8+
// no-prefer-dynamic
9+
10+
#![crate_type = "proc-macro"]
11+
#![feature(derive_const)]
12+
13+
extern crate proc_macro;
14+
15+
#[proc_macro_derive(Blah)]
16+
pub fn bad_input() -> proc_macro::TokenStream {
17+
//~^ ERROR derive proc macro has incorrect signature
18+
Default::default()
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: derive proc macro has incorrect signature
2+
--> $DIR/signature-proc-macro-derive.rs:16:1
3+
|
4+
LL | pub fn bad_input() -> proc_macro::TokenStream {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| incorrect number of function parameters
8+
| incorrect number of function parameters
9+
|
10+
= note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
11+
found signature `fn() -> proc_macro::TokenStream`
12+
= note: expected signature `fn(proc_macro::TokenStream, DeriveExpansionOptions) -> proc_macro::TokenStream`
13+
found signature `fn() -> proc_macro::TokenStream`
14+
15+
error: aborting due to 1 previous error
16+

0 commit comments

Comments
 (0)