diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a09bea25a249c..01bee83c85dcc 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -719,6 +719,7 @@ pub struct ExtCtxt<'a> { pub parse_sess: &'a parse::ParseSess, pub ecfg: expand::ExpansionConfig<'a>, pub root_path: PathBuf, + pub context_path: Option>, pub resolver: &'a mut Resolver, pub resolve_err_count: usize, pub current_expansion: ExpansionData, @@ -736,6 +737,7 @@ impl<'a> ExtCtxt<'a> { root_path: PathBuf::new(), resolver, resolve_err_count: 0, + context_path: None, current_expansion: ExpansionData { mark: Mark::root(), depth: 0, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 678c20402d6f4..d97516f27611c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -137,6 +137,13 @@ expansions! { "foreign item", .make_foreign_items, lift .fold_foreign_item, lift .visit_foreign_item; } +fn dummy_path() -> Path { + Path { + span: DUMMY_SP, + segments: Vec::new(), + } +} + impl ExpansionKind { fn dummy(self, span: Span) -> Option { self.make_from(DummyResult::any(span)) @@ -189,6 +196,7 @@ pub enum InvocationKind { mac: ast::Mac, ident: Option, span: Span, + context_path: Rc, }, Attr { attr: Option, @@ -271,7 +279,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let orig_expansion_data = self.cx.current_expansion.clone(); self.cx.current_expansion.depth = 0; - let (expansion, mut invocations) = self.collect_invocations(expansion, &[]); + let (expansion, mut invocations) = self.collect_invocations(expansion, &[], None); self.resolve_imports(); invocations.reverse(); @@ -309,10 +317,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // FIXME(jseyfried): Refactor out the following logic let (expansion, new_invocations) = if let Some(ext) = ext { if let Some(ext) = ext { - let dummy = invoc.expansion_kind.dummy(invoc.span()).unwrap(); - let expansion = self.expand_invoc(invoc, &*ext).unwrap_or(dummy); - self.collect_invocations(expansion, &[]) - } else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind { + let dummy = (invoc.expansion_kind.dummy( + invoc.span()).unwrap(), None); + let (expansion, context_path) = + self.expand_invoc(invoc, &*ext).unwrap_or(dummy); + self.collect_invocations(expansion, &[], context_path) + } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { if !item.derive_allowed() { let attr = attr::find_by_name(item.attrs(), "derive") .expect("`derive` attribute should exist"); @@ -357,12 +367,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } let expansion = invoc.expansion_kind .expect_from_annotatables(::std::iter::once(item_with_markers)); - self.collect_invocations(expansion, derives) + self.collect_invocations(expansion, derives, None) } else { unreachable!() } } else { - self.collect_invocations(invoc.expansion_kind.dummy(invoc.span()).unwrap(), &[]) + self.collect_invocations( + invoc.expansion_kind.dummy(invoc.span()).unwrap(), &[], None) }; if expansions.len() < depth { @@ -395,7 +406,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn collect_invocations(&mut self, expansion: Expansion, derives: &[Mark]) + fn collect_invocations(&mut self, + expansion: Expansion, derives: &[Mark], context_path : Option>) -> (Expansion, Vec) { let result = { let mut collector = InvocationCollector { @@ -405,6 +417,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { features: self.cx.ecfg.features, }, cx: self.cx, + context_path : match context_path { + None => dummy_path(), + Some(path) => (*path).clone(), + }, invocations: Vec::new(), monotonic: self.monotonic, }; @@ -453,11 +469,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option { + fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) + -> Option<(Expansion, Option>)> { let result = match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext)?, - InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext)?, - InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext)?, + InvocationKind::Attr { .. } => + self.expand_attr_invoc(invoc, ext).map(|x|(x, None))?, + InvocationKind::Derive { .. } => + self.expand_derive_invoc(invoc, ext).map(|x|(x, None))?, }; if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { @@ -543,13 +562,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn expand_bang_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) - -> Option { + -> Option<(Expansion, Option>)> { let (mark, kind) = (invoc.expansion_data.mark, invoc.expansion_kind); - let (mac, ident, span) = match invoc.kind { - InvocationKind::Bang { mac, ident, span } => (mac, ident, span), + let (mac, ident, span, context_path) = match invoc.kind { + InvocationKind::Bang { mac, ident, span, context_path } + => (mac, ident, span, context_path), _ => unreachable!(), }; let path = &mac.node.path; + self.cx.context_path = None; let ident = ident.unwrap_or_else(|| keywords::Invalid.ident()); let validate_and_set_expn_info = |this: &mut Self, // arg instead of capture @@ -601,6 +622,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { false, false, None) { dummy_span } else { + self.cx.context_path = Some(context_path.clone()); kind.make_from(expand.expand(self.cx, span, mac.node.stream())) } } @@ -618,6 +640,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { unstable_feature) { dummy_span } else { + self.cx.context_path = Some(context_path.clone()); kind.make_from(expander.expand(self.cx, span, mac.node.stream())) } } @@ -684,7 +707,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } }; - if opt_expanded.is_some() { + let r = if opt_expanded.is_some() { opt_expanded } else { let msg = format!("non-{kind} macro in {kind} position: {name}", @@ -692,7 +715,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.span_err(path.span, &msg); self.cx.trace_macros_diag(); kind.dummy(span) - } + }; + r.map(|x|(x, Some(context_path))) } /// Expand a derive invocation. Returns the result of expansion. @@ -854,6 +878,7 @@ impl<'a> Parser<'a> { struct InvocationCollector<'a, 'b: 'a> { cx: &'a mut ExtCtxt<'b>, cfg: StripUnconfigured<'a>, + context_path: Path, invocations: Vec, monotonic: bool, } @@ -873,8 +898,26 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { placeholder(expansion_kind, NodeId::placeholder_from_mark(mark)) } + fn push_ident(&mut self, ident: &Ident) -> bool { + if *ident != keywords::Invalid.ident() { + self.context_path.segments.push(ast::PathSegment { + ident : ident.clone(), + parameters : None, // FIXME + }); + true + } else { + false + } + } + + fn make_bang(&self, ident: Option, mac: ast::Mac, span: Span) -> InvocationKind { + InvocationKind::Bang { + mac: mac, ident, span: span, context_path: Rc::new(self.context_path.clone()) } + } + fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion { - self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span }) + let bang = self.make_bang(None, mac, span); + self.collect(kind, bang) } fn collect_attr(&mut self, @@ -1054,16 +1097,41 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { return self.collect_attr(attr, traits, item, ExpansionKind::Items).make_items(); } - match item.node { + let mut pushed_ident = false; + match &item.node { + &ast::ItemKind::Impl(_, _, _, _, _, ref ty, _) => { + pushed_ident = self.push_ident(&item.ident); + if !pushed_ident { + if let ast::TyKind::Path(_, ref path) = &ty.node { + match path.segments.last() { + Some(last) => { + self.context_path.segments.push(last.clone()); + pushed_ident = true; + } + None => {} + } + } + } + } + ast::ItemKind::Mod(_) => { + // module_path!() macro already covers crate/module hierarchy + } + ast::ItemKind::Static(_, _, _) => { + // if function!() used to initialize a static, the name of the static + // should not wind up in the ident list. + } + _ => { + pushed_ident = self.push_ident(&item.ident); + } + } + + let folded = match item.node { ast::ItemKind::Mac(..) => { self.check_attributes(&item.attrs); item.and_then(|item| match item.node { ItemKind::Mac(mac) => { - self.collect(ExpansionKind::Items, InvocationKind::Bang { - mac, - ident: Some(item.ident), - span: item.span, - }).make_items() + let bang = self.make_bang(Some(item.ident), mac, item.span); + self.collect(ExpansionKind::Items, bang).make_items() } _ => unreachable!(), }) @@ -1126,7 +1194,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { noop_fold_item(item, self) } _ => noop_fold_item(item, self), + }; + + if pushed_ident { + self.context_path.segments.pop(); } + + folded } fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { @@ -1139,14 +1213,22 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { .make_trait_items() } - match item.node { + let pushed_ident = self.push_ident(&item.ident); + + let r = match item.node { ast::TraitItemKind::Macro(mac) => { let ast::TraitItem { attrs, span, .. } = item; self.check_attributes(&attrs); self.collect_bang(mac, span, ExpansionKind::TraitItems).make_trait_items() } _ => fold::noop_fold_trait_item(item, self), + }; + + if pushed_ident { + self.context_path.segments.pop(); } + + r } fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { @@ -1159,14 +1241,22 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { .make_impl_items(); } - match item.node { + let pushed_ident = self.push_ident(&item.ident); + + let r = match item.node { ast::ImplItemKind::Macro(mac) => { let ast::ImplItem { attrs, span, .. } = item; self.check_attributes(&attrs); self.collect_bang(mac, span, ExpansionKind::ImplItems).make_impl_items() } _ => fold::noop_fold_impl_item(item, self), + }; + + if pushed_ident { + self.context_path.segments.pop(); } + + r } fn fold_ty(&mut self, ty: P) -> P { diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index d6dce63ea5e4b..65295e57ac2b1 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -74,6 +74,19 @@ pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) base::MacEager::expr(cx.expr_str(topmost, Symbol::intern(&loc.file.name.to_string()))) } +pub fn expand_function<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, tts: &[tokenstream::TokenTree]) + -> Box { + base::check_zero_tts(cx, sp, tts, "function!"); + + let topmost = cx.expansion_cause().unwrap_or(sp); + let symbol = match cx.context_path.as_ref() { + None => Symbol::intern(""), + Some(path) => Symbol::intern((*path).to_string().as_str()) + }; + base::MacEager::expr(cx.expr_str(topmost, symbol)) +} + pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { let s = pprust::tts_to_string(tts); diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 249a64b353f59..5a1e3467a5bcf 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -97,6 +97,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, line: expand_line, __rust_unstable_column: expand_column_gated, column: expand_column, + function: expand_function, file: expand_file, stringify: expand_stringify, include: expand_include,