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

Record proc macro harness order for use during metadata deserialization #68814

Merged
merged 2 commits into from
Feb 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 src/librustc/hir/map/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
trait_impls: _,
body_ids: _,
modules: _,
proc_macros: _,
} = *krate;

alloc_hir_dep_nodes(
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_ast_lowering/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let module = self.lower_mod(&c.module);
let attrs = self.lower_attrs(&c.attrs);
let body_ids = body_ids(&self.bodies);
let proc_macros = c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id]).collect();

self.resolver.definitions().init_node_id_to_hir_id_mapping(self.node_id_to_hir_id);

Expand All @@ -546,6 +547,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
body_ids,
trait_impls: self.trait_impls,
modules: self.modules,
proc_macros,
}
}

Expand Down
61 changes: 43 additions & 18 deletions src/librustc_builtin_macros/proc_macro_harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ use rustc_span::hygiene::AstPass;
use rustc_span::symbol::{kw, sym};
use rustc_span::{Span, DUMMY_SP};
use smallvec::smallvec;
use syntax::ast::{self, Ident};
use std::cell::RefCell;
use syntax::ast::{self, Ident, NodeId};
use syntax::attr;
use syntax::expand::is_proc_macro_attr;
use syntax::ptr::P;
use syntax::visit::{self, Visitor};

struct ProcMacroDerive {
id: NodeId,
trait_name: ast::Name,
function_name: Ident,
span: Span,
Expand All @@ -27,6 +29,7 @@ enum ProcMacroDefType {
}

struct ProcMacroDef {
id: NodeId,
function_name: Ident,
span: Span,
def_type: ProcMacroDefType,
Expand Down Expand Up @@ -69,9 +72,6 @@ pub fn inject(
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 {
Expand All @@ -86,7 +86,8 @@ pub fn inject(
return krate;
}

krate.module.items.push(mk_decls(&mut cx, &macros));
let decls = mk_decls(&mut krate, &mut cx, &macros);
krate.module.items.push(decls);

krate
}
Expand Down Expand Up @@ -181,6 +182,7 @@ impl<'a> CollectProcMacros<'a> {

if self.in_root && item.vis.node.is_pub() {
self.macros.push(ProcMacro::Derive(ProcMacroDerive {
id: item.id,
span: item.span,
trait_name: trait_ident.name,
function_name: item.ident,
Expand All @@ -200,6 +202,7 @@ 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.macros.push(ProcMacro::Def(ProcMacroDef {
id: item.id,
span: item.span,
function_name: item.ident,
def_type: ProcMacroDefType::Attr,
Expand All @@ -218,6 +221,7 @@ 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.macros.push(ProcMacro::Def(ProcMacroDef {
id: item.id,
span: item.span,
function_name: item.ident,
def_type: ProcMacroDefType::Bang,
Expand Down Expand Up @@ -357,7 +361,15 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
// // ...
// ];
// }
fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
fn mk_decls(
ast_krate: &mut ast::Crate,
cx: &mut ExtCtxt<'_>,
macros: &[ProcMacro],
) -> P<ast::Item> {
// We're the ones filling in this Vec,
// so it should be empty to start with
assert!(ast_krate.proc_macros.is_empty());

let expn_id = cx.resolver.expansion_for_ast_pass(
DUMMY_SP,
AstPass::ProcMacroHarness,
Expand All @@ -376,6 +388,12 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
let attr = cx.ident_of("attr", span);
let bang = cx.ident_of("bang", span);

let krate_ref = RefCell::new(ast_krate);

// We add NodeIds to 'krate.proc_macros' in the order
// that we generate expressions. The position of each NodeId
// in the 'proc_macros' Vec corresponds to its position
// in the static array that will be generated
let decls = {
let local_path =
|sp: Span, name| cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![name]));
Expand All @@ -385,19 +403,26 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
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::Derive(cd) => {
krate_ref.borrow_mut().proc_macros.push(cd.id);
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) => {
krate_ref.borrow_mut().proc_macros.push(ca.id);
let ident = match ca.def_type {
ProcMacroDefType::Attr => attr,
ProcMacroDefType::Bang => bang,
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_hir/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,9 @@ pub struct Crate<'hir> {
/// A list of modules written out in the order in which they
/// appear in the crate. This includes the main crate module.
pub modules: BTreeMap<HirId, ModuleItems>,
/// A list of proc macro HirIds, written out in the order in which
/// they are declared in the static array generated by proc_macro_harness.
pub proc_macros: Vec<HirId>,
}

impl Crate<'hir> {
Expand Down
4 changes: 0 additions & 4 deletions src/librustc_metadata/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -637,10 +637,6 @@ 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'.
// NOTE: If you update the order of macros in 'proc_macro_data' for any reason,
// you must also update src/librustc_builtin_macros/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
9 changes: 1 addition & 8 deletions src/librustc_metadata/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ use std::path::Path;
use std::u32;
use syntax::ast;
use syntax::attr;
use syntax::expand::is_proc_macro_attr;

use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
Expand Down Expand Up @@ -1328,13 +1327,7 @@ impl EncodeContext<'tcx> {
let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro);
if is_proc_macro {
let tcx = self.tcx;
Some(self.lazy(tcx.hir().krate().items.values().filter_map(|item| {
if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
Some(item.hir_id.owner)
} else {
None
}
})))
Some(self.lazy(tcx.hir().krate().proc_macros.iter().map(|p| p.owner)))
} else {
None
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_parse/parser/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ impl<'a> Parser<'a> {
attrs: self.parse_inner_attributes()?,
module: self.parse_mod_items(&token::Eof, lo)?,
span: lo.to(self.token.span),
// Filled in by proc_macro_harness::inject()
proc_macros: Vec::new(),
});
krate
}
Expand Down
7 changes: 7 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,13 @@ pub struct Crate {
pub module: Mod,
pub attrs: Vec<Attribute>,
pub span: Span,
/// The order of items in the HIR is unrelated to the order of
/// items in the AST. However, we generate proc macro harnesses
/// based on the AST order, and later refer to these harnesses
/// from the HIR. This field keeps track of the order in which
/// we generated proc macros harnesses, so that we can map
/// HIR proc macros items back to their harness items.
pub proc_macros: Vec<NodeId>,
}

/// Possible values inside of compile-time attribute lists.
Expand Down
6 changes: 3 additions & 3 deletions src/libsyntax/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,7 @@ pub fn noop_visit_mod<T: MutVisitor>(Mod { inner, items, inline: _ }: &mut Mod,
}

pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
visit_clobber(krate, |Crate { module, attrs, span }| {
visit_clobber(krate, |Crate { module, attrs, span, proc_macros }| {
let item = P(Item {
ident: Ident::invalid(),
attrs,
Expand All @@ -1004,11 +1004,11 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
let len = items.len();
if len == 0 {
let module = Mod { inner: span, items: vec![], inline: true };
Crate { module, attrs: vec![], span }
Crate { module, attrs: vec![], span, proc_macros }
} else if len == 1 {
let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
match kind {
ItemKind::Mod(module) => Crate { module, attrs, span },
ItemKind::Mod(module) => Crate { module, attrs, span, proc_macros },
_ => panic!("visitor converted a module to not a module"),
}
} else {
Expand Down
13 changes: 13 additions & 0 deletions src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ extern crate proc_macro;

use proc_macro::TokenStream;

macro_rules! make_attr_macro {
($name:ident) => {
/// Generated doc comment
#[proc_macro_attribute]
pub fn $name(args: TokenStream, input: TokenStream) -> TokenStream {
panic!()
}
}
}

make_attr_macro!(first_attr);
make_attr_macro!(second_attr);

/// a proc-macro that swallows its input and does nothing.
#[proc_macro]
pub fn some_proc_macro(_input: TokenStream) -> TokenStream {
Expand Down
8 changes: 8 additions & 0 deletions src/test/rustdoc/inline_cross/proc_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,11 @@ 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;

// @has proc_macro/attr.first_attr.html
// @has - 'Generated doc comment'
pub use some_macros::first_attr;

// @has proc_macro/attr.second_attr.html
// @has - 'Generated doc comment'
pub use some_macros::second_attr;
2 changes: 1 addition & 1 deletion src/test/ui/ast-json/ast-json-output.stdout
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}}
{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0},"proc_macros":[]}