Skip to content

Commit

Permalink
Generate proc macro harness in AST order.
Browse files Browse the repository at this point in the history
This ensures that we match the order used by proc macro metadata
serialization.

Fixes #64251
  • Loading branch information
Aaron1011 committed Sep 17, 2019
1 parent 7efe1c6 commit 3daa8bd
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 49 deletions.
6 changes: 5 additions & 1 deletion src/librustc_metadata/decoder.rs
Expand Up @@ -489,7 +489,11 @@ impl<'a, 'tcx> CrateMetadata {

fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
// DefIndex's in root.proc_macro_data have a one-to-one correspondence
// with items in 'raw_proc_macros'
// with items in 'raw_proc_macros'.
// NOTE: If you update the order of macros in 'proc_macro_data' for any reason,
// you must also update src/libsyntax_ext/proc_macro_harness.rs
// Failing to do so will result in incorrect data being associated
// with proc macros when deserialized.
let pos = self.root.proc_macro_data.unwrap().decode(self).position(|i| i == id).unwrap();
&self.raw_proc_macros.unwrap()[pos]
}
Expand Down
109 changes: 62 additions & 47 deletions src/libsyntax_ext/proc_macro_harness.rs
Expand Up @@ -20,15 +20,24 @@ struct ProcMacroDerive {
attrs: Vec<ast::Name>,
}

enum ProcMacroDefType {
Attr,
Bang
}

struct ProcMacroDef {
function_name: Ident,
span: Span,
def_type: ProcMacroDefType
}

enum ProcMacro {
Derive(ProcMacroDerive),
Def(ProcMacroDef)
}

struct CollectProcMacros<'a> {
derives: Vec<ProcMacroDerive>,
attr_macros: Vec<ProcMacroDef>,
bang_macros: Vec<ProcMacroDef>,
macros: Vec<ProcMacro>,
in_root: bool,
handler: &'a errors::Handler,
is_proc_macro_crate: bool,
Expand All @@ -46,22 +55,22 @@ pub fn inject(sess: &ParseSess,
let ecfg = ExpansionConfig::default("proc_macro".to_string());
let mut cx = ExtCtxt::new(sess, ecfg, resolver);

let (derives, attr_macros, bang_macros) = {
let mut collect = CollectProcMacros {
derives: Vec::new(),
attr_macros: Vec::new(),
bang_macros: Vec::new(),
in_root: true,
handler,
is_proc_macro_crate,
is_test_crate,
};
if has_proc_macro_decls || is_proc_macro_crate {
visit::walk_crate(&mut collect, &krate);
}
(collect.derives, collect.attr_macros, collect.bang_macros)
let mut collect = CollectProcMacros {
macros: Vec::new(),
in_root: true,
handler,
is_proc_macro_crate,
is_test_crate,
};

if has_proc_macro_decls || is_proc_macro_crate {
visit::walk_crate(&mut collect, &krate);
}
// NOTE: If you change the order of macros in this vec
// for any reason, you must also update 'raw_proc_macro'
// in src/librustc_metadata/decoder.rs
let macros = collect.macros;

if !is_proc_macro_crate {
return krate
}
Expand All @@ -74,7 +83,7 @@ pub fn inject(sess: &ParseSess,
return krate;
}

krate.module.items.push(mk_decls(&mut cx, &derives, &attr_macros, &bang_macros));
krate.module.items.push(mk_decls(&mut cx, &macros));

krate
}
Expand Down Expand Up @@ -161,12 +170,12 @@ impl<'a> CollectProcMacros<'a> {
};

if self.in_root && item.vis.node.is_pub() {
self.derives.push(ProcMacroDerive {
self.macros.push(ProcMacro::Derive(ProcMacroDerive {
span: item.span,
trait_name: trait_ident.name,
function_name: item.ident,
attrs: proc_attrs,
});
}));
} else {
let msg = if !self.in_root {
"functions tagged with `#[proc_macro_derive]` must \
Expand All @@ -180,10 +189,11 @@ impl<'a> CollectProcMacros<'a> {

fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) {
if self.in_root && item.vis.node.is_pub() {
self.attr_macros.push(ProcMacroDef {
self.macros.push(ProcMacro::Def(ProcMacroDef {
span: item.span,
function_name: item.ident,
});
def_type: ProcMacroDefType::Attr
}));
} else {
let msg = if !self.in_root {
"functions tagged with `#[proc_macro_attribute]` must \
Expand All @@ -197,10 +207,11 @@ impl<'a> CollectProcMacros<'a> {

fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) {
if self.in_root && item.vis.node.is_pub() {
self.bang_macros.push(ProcMacroDef {
self.macros.push(ProcMacro::Def(ProcMacroDef {
span: item.span,
function_name: item.ident,
});
def_type: ProcMacroDefType::Bang
}));
} else {
let msg = if !self.in_root {
"functions tagged with `#[proc_macro]` must \
Expand Down Expand Up @@ -322,9 +333,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
// }
fn mk_decls(
cx: &mut ExtCtxt<'_>,
custom_derives: &[ProcMacroDerive],
custom_attrs: &[ProcMacroDef],
custom_macros: &[ProcMacroDef],
macros: &[ProcMacro],
) -> P<ast::Item> {
let expn_id = cx.resolver.expansion_for_ast_pass(
DUMMY_SP,
Expand Down Expand Up @@ -354,26 +363,32 @@ fn mk_decls(
let proc_macro_ty_method_path = |method| cx.expr_path(cx.path(span, vec![
proc_macro, bridge, client, proc_macro_ty, method,
]));
custom_derives.iter().map(|cd| {
cx.expr_call(span, proc_macro_ty_method_path(custom_derive), vec![
cx.expr_str(cd.span, cd.trait_name),
cx.expr_vec_slice(
span,
cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::<Vec<_>>()
),
local_path(cd.span, cd.function_name),
])
}).chain(custom_attrs.iter().map(|ca| {
cx.expr_call(span, proc_macro_ty_method_path(attr), vec![
cx.expr_str(ca.span, ca.function_name.name),
local_path(ca.span, ca.function_name),
])
})).chain(custom_macros.iter().map(|cm| {
cx.expr_call(span, proc_macro_ty_method_path(bang), vec![
cx.expr_str(cm.span, cm.function_name.name),
local_path(cm.span, cm.function_name),
])
})).collect()
macros.iter().map(|m| {
match m {
ProcMacro::Derive(cd) => {
cx.expr_call(span, proc_macro_ty_method_path(custom_derive), vec![
cx.expr_str(cd.span, cd.trait_name),
cx.expr_vec_slice(
span,
cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::<Vec<_>>()
),
local_path(cd.span, cd.function_name),
])
},
ProcMacro::Def(ca) => {
let ident = match ca.def_type {
ProcMacroDefType::Attr => attr,
ProcMacroDefType::Bang => bang
};

cx.expr_call(span, proc_macro_ty_method_path(ident), vec![
cx.expr_str(ca.span, ca.function_name.name),
local_path(ca.span, ca.function_name),
])

}
}
}).collect()
};

let decls_static = cx.item_static(
Expand Down
13 changes: 12 additions & 1 deletion src/test/rustdoc/inline_cross/proc_macro.rs
Expand Up @@ -10,8 +10,19 @@ extern crate some_macros;
// @has proc_macro/macro.some_proc_macro.html
// @has proc_macro/attr.some_proc_attr.html
// @has proc_macro/derive.SomeDerive.html
pub use some_macros::{some_proc_macro, some_proc_attr, SomeDerive};

// @has proc_macro/macro.some_proc_macro.html
// @has - 'a proc-macro that swallows its input and does nothing.'
pub use some_macros::some_proc_macro;

// @has proc_macro/macro.reexported_macro.html
// @has - 'Doc comment from the original crate'
pub use some_macros::reexported_macro;

// @has proc_macro/attr.some_proc_attr.html
// @has - 'a proc-macro attribute that passes its item through verbatim.'
pub use some_macros::some_proc_attr;

// @has proc_macro/derive.SomeDerive.html
// @has - 'a derive attribute that adds nothing to its input.'
pub use some_macros::SomeDerive;

0 comments on commit 3daa8bd

Please sign in to comment.