Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d75c64d

Browse files
authoredSep 6, 2016
Auto merge of #36214 - jseyfried:stackless_expansion, r=nrc
macros: stackless expansion After this PR, macro expansion cannot overflow the stack unless the expanded crate is too deep to fold. Everything but the stackless placeholder expansion commit is also groundwork for macro modularization. r? @nrc or @eddyb
2 parents e1d0de8 + 400a4f2 commit d75c64d

File tree

12 files changed

+895
-755
lines changed

12 files changed

+895
-755
lines changed
 

‎src/librustc_driver/driver.rs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ pub struct ExpansionResult<'a> {
551551
/// Returns `None` if we're aborting after handling -W help.
552552
pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
553553
cstore: &CStore,
554-
mut krate: ast::Crate,
554+
krate: ast::Crate,
555555
registry: Option<Registry>,
556556
crate_name: &'a str,
557557
addl_plugins: Option<Vec<String>>,
@@ -562,21 +562,9 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
562562
{
563563
let time_passes = sess.time_passes();
564564

565-
// strip before anything else because crate metadata may use #[cfg_attr]
566-
// and so macros can depend on configuration variables, such as
567-
//
568-
// #[macro_use] #[cfg(foo)]
569-
// mod bar { macro_rules! baz!(() => {{}}) }
570-
//
571-
// baz! should not use this definition unless foo is enabled.
572-
573-
krate = time(time_passes, "configuration", || {
574-
let (krate, features) =
575-
syntax::config::strip_unconfigured_items(krate, &sess.parse_sess, sess.opts.test);
576-
// these need to be set "early" so that expansion sees `quote` if enabled.
577-
*sess.features.borrow_mut() = features;
578-
krate
579-
});
565+
let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test);
566+
// these need to be set "early" so that expansion sees `quote` if enabled.
567+
*sess.features.borrow_mut() = features;
580568

581569
*sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
582570
*sess.crate_disambiguator.borrow_mut() =

‎src/libsyntax/config.rs

Lines changed: 63 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,13 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use attr::HasAttrs;
11+
use attr::{self, HasAttrs};
1212
use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
13-
use fold::Folder;
14-
use {fold, attr};
1513
use ast;
1614
use codemap::{Spanned, respan};
17-
use parse::{ParseSess, token};
15+
use parse::ParseSess;
1816
use ptr::P;
1917

20-
use util::small_vector::SmallVector;
21-
2218
/// A folder that strips out items that do not belong in the current configuration.
2319
pub struct StripUnconfigured<'a> {
2420
pub config: &'a ast::CrateConfig,
@@ -27,8 +23,42 @@ pub struct StripUnconfigured<'a> {
2723
pub features: Option<&'a Features>,
2824
}
2925

26+
// `cfg_attr`-process the crate's attributes and compute the crate's features.
27+
pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool)
28+
-> (ast::Crate, Features) {
29+
let features;
30+
{
31+
let mut strip_unconfigured = StripUnconfigured {
32+
config: &krate.config.clone(),
33+
should_test: should_test,
34+
sess: sess,
35+
features: None,
36+
};
37+
38+
let unconfigured_attrs = krate.attrs.clone();
39+
let err_count = sess.span_diagnostic.err_count();
40+
if let Some(attrs) = strip_unconfigured.configure(krate.attrs) {
41+
krate.attrs = attrs;
42+
} else { // the entire crate is unconfigured
43+
krate.attrs = Vec::new();
44+
krate.module.items = Vec::new();
45+
return (krate, Features::new());
46+
}
47+
48+
features = get_features(&sess.span_diagnostic, &krate.attrs);
49+
50+
// Avoid reconfiguring malformed `cfg_attr`s
51+
if err_count == sess.span_diagnostic.err_count() {
52+
strip_unconfigured.features = Some(&features);
53+
strip_unconfigured.configure(unconfigured_attrs);
54+
}
55+
}
56+
57+
(krate, features)
58+
}
59+
3060
impl<'a> StripUnconfigured<'a> {
31-
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
61+
pub fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
3262
let node = self.process_cfg_attrs(node);
3363
if self.in_cfg(node.attrs()) { Some(node) } else { None }
3464
}
@@ -123,65 +153,35 @@ impl<'a> StripUnconfigured<'a> {
123153
}
124154
}
125155
}
126-
}
127-
128-
// Support conditional compilation by transforming the AST, stripping out
129-
// any items that do not belong in the current configuration
130-
pub fn strip_unconfigured_items(mut krate: ast::Crate, sess: &ParseSess, should_test: bool)
131-
-> (ast::Crate, Features) {
132-
let features;
133-
{
134-
let mut strip_unconfigured = StripUnconfigured {
135-
config: &krate.config.clone(),
136-
should_test: should_test,
137-
sess: sess,
138-
features: None,
139-
};
140156

141-
let err_count = sess.span_diagnostic.err_count();
142-
let krate_attrs = strip_unconfigured.configure(krate.attrs.clone()).unwrap_or_default();
143-
features = get_features(&sess.span_diagnostic, &krate_attrs);
144-
if err_count < sess.span_diagnostic.err_count() {
145-
krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s
146-
}
147-
148-
strip_unconfigured.features = Some(&features);
149-
krate = strip_unconfigured.fold_crate(krate);
150-
krate.attrs = krate_attrs;
151-
}
152-
153-
(krate, features)
154-
}
155-
156-
impl<'a> fold::Folder for StripUnconfigured<'a> {
157-
fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
157+
pub fn configure_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
158158
ast::ForeignMod {
159159
abi: foreign_mod.abi,
160-
items: foreign_mod.items.into_iter().filter_map(|item| {
161-
self.configure(item).map(|item| fold::noop_fold_foreign_item(item, self))
162-
}).collect(),
160+
items: foreign_mod.items.into_iter().filter_map(|item| self.configure(item)).collect(),
163161
}
164162
}
165163

166-
fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
167-
let fold_struct = |this: &mut Self, vdata| match vdata {
164+
fn configure_variant_data(&mut self, vdata: ast::VariantData) -> ast::VariantData {
165+
match vdata {
168166
ast::VariantData::Struct(fields, id) => {
169-
let fields = fields.into_iter().filter_map(|field| this.configure(field));
167+
let fields = fields.into_iter().filter_map(|field| self.configure(field));
170168
ast::VariantData::Struct(fields.collect(), id)
171169
}
172170
ast::VariantData::Tuple(fields, id) => {
173-
let fields = fields.into_iter().filter_map(|field| this.configure(field));
171+
let fields = fields.into_iter().filter_map(|field| self.configure(field));
174172
ast::VariantData::Tuple(fields.collect(), id)
175173
}
176174
ast::VariantData::Unit(id) => ast::VariantData::Unit(id)
177-
};
175+
}
176+
}
178177

179-
let item = match item {
178+
pub fn configure_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
179+
match item {
180180
ast::ItemKind::Struct(def, generics) => {
181-
ast::ItemKind::Struct(fold_struct(self, def), generics)
181+
ast::ItemKind::Struct(self.configure_variant_data(def), generics)
182182
}
183183
ast::ItemKind::Union(def, generics) => {
184-
ast::ItemKind::Union(fold_struct(self, def), generics)
184+
ast::ItemKind::Union(self.configure_variant_data(def), generics)
185185
}
186186
ast::ItemKind::Enum(def, generics) => {
187187
let variants = def.variants.into_iter().filter_map(|v| {
@@ -190,7 +190,7 @@ impl<'a> fold::Folder for StripUnconfigured<'a> {
190190
node: ast::Variant_ {
191191
name: v.node.name,
192192
attrs: v.node.attrs,
193-
data: fold_struct(self, v.node.data),
193+
data: self.configure_variant_data(v.node.data),
194194
disr_expr: v.node.disr_expr,
195195
},
196196
span: v.span
@@ -202,12 +202,19 @@ impl<'a> fold::Folder for StripUnconfigured<'a> {
202202
}, generics)
203203
}
204204
item => item,
205-
};
205+
}
206+
}
206207

207-
fold::noop_fold_item_kind(item, self)
208+
pub fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind {
209+
if let ast::ExprKind::Match(m, arms) = expr_kind {
210+
let arms = arms.into_iter().filter_map(|a| self.configure(a)).collect();
211+
ast::ExprKind::Match(m, arms)
212+
} else {
213+
expr_kind
214+
}
208215
}
209216

210-
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
217+
pub fn configure_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
211218
self.visit_stmt_or_expr_attrs(expr.attrs());
212219

213220
// If an expr is valid to cfg away it will have been removed by the
@@ -222,62 +229,13 @@ impl<'a> fold::Folder for StripUnconfigured<'a> {
222229
self.sess.span_diagnostic.span_err(attr.span, msg);
223230
}
224231

225-
let expr = self.process_cfg_attrs(expr);
226-
fold_expr(self, expr)
232+
self.process_cfg_attrs(expr)
227233
}
228234

229-
fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
230-
self.configure(expr).map(|expr| fold_expr(self, expr))
231-
}
232-
233-
fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
235+
pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option<ast::Stmt> {
234236
self.visit_stmt_or_expr_attrs(stmt.attrs());
235-
self.configure(stmt).map(|stmt| fold::noop_fold_stmt(stmt, self))
236-
.unwrap_or(SmallVector::zero())
237-
}
238-
239-
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
240-
fold::noop_fold_mac(mac, self)
241-
}
242-
243-
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
244-
self.configure(item).map(|item| fold::noop_fold_item(item, self))
245-
.unwrap_or(SmallVector::zero())
246-
}
247-
248-
fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector<ast::ImplItem> {
249-
self.configure(item).map(|item| fold::noop_fold_impl_item(item, self))
250-
.unwrap_or(SmallVector::zero())
251-
}
252-
253-
fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> {
254-
self.configure(item).map(|item| fold::noop_fold_trait_item(item, self))
255-
.unwrap_or(SmallVector::zero())
237+
self.configure(stmt)
256238
}
257-
258-
fn fold_interpolated(&mut self, nt: token::Nonterminal) -> token::Nonterminal {
259-
// Don't configure interpolated AST (c.f. #34171).
260-
// Interpolated AST will get configured once the surrounding tokens are parsed.
261-
nt
262-
}
263-
}
264-
265-
fn fold_expr(folder: &mut StripUnconfigured, expr: P<ast::Expr>) -> P<ast::Expr> {
266-
expr.map(|ast::Expr {id, span, node, attrs}| {
267-
fold::noop_fold_expr(ast::Expr {
268-
id: id,
269-
node: match node {
270-
ast::ExprKind::Match(m, arms) => {
271-
ast::ExprKind::Match(m, arms.into_iter()
272-
.filter_map(|a| folder.configure(a))
273-
.collect())
274-
}
275-
_ => node
276-
},
277-
span: span,
278-
attrs: attrs,
279-
}, folder)
280-
})
281239
}
282240

283241
fn is_cfg(attr: &ast::Attribute) -> bool {

‎src/libsyntax/ext/base.rs

Lines changed: 90 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ use parse::parser;
2424
use parse::token;
2525
use parse::token::{InternedString, intern, str_to_ident};
2626
use ptr::P;
27+
use std_inject;
2728
use util::small_vector::SmallVector;
2829
use util::lev_distance::find_best_match_for_name;
2930
use fold::Folder;
3031
use feature_gate;
3132

3233
use std::collections::{HashMap, HashSet};
34+
use std::path::PathBuf;
3335
use std::rc::Rc;
3436
use tokenstream;
3537

@@ -90,16 +92,6 @@ impl Annotatable {
9092
_ => panic!("expected Item")
9193
}
9294
}
93-
94-
pub fn fold_with<F: Folder>(self, folder: &mut F) -> SmallVector<Self> {
95-
match self {
96-
Annotatable::Item(item) => folder.fold_item(item).map(Annotatable::Item),
97-
Annotatable::ImplItem(item) =>
98-
folder.fold_impl_item(item.unwrap()).map(|item| Annotatable::ImplItem(P(item))),
99-
Annotatable::TraitItem(item) =>
100-
folder.fold_trait_item(item.unwrap()).map(|item| Annotatable::TraitItem(P(item))),
101-
}
102-
}
10395
}
10496

10597
// A more flexible ItemDecorator.
@@ -472,19 +464,6 @@ pub enum SyntaxExtension {
472464

473465
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
474466

475-
pub struct BlockInfo {
476-
/// Should macros escape from this scope?
477-
pub macros_escape: bool,
478-
}
479-
480-
impl BlockInfo {
481-
pub fn new() -> BlockInfo {
482-
BlockInfo {
483-
macros_escape: false,
484-
}
485-
}
486-
}
487-
488467
/// The base map of methods for expanding syntax extension
489468
/// AST nodes into full ASTs
490469
fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
@@ -595,40 +574,29 @@ pub struct ExtCtxt<'a> {
595574
pub crate_root: Option<&'static str>,
596575
pub loader: &'a mut MacroLoader,
597576

598-
pub mod_path: Vec<ast::Ident> ,
599577
pub exported_macros: Vec<ast::MacroDef>,
600578

601579
pub syntax_env: SyntaxEnv,
602580
pub derive_modes: HashMap<InternedString, Box<MultiItemModifier>>,
603581
pub recursion_count: usize,
604-
605-
pub filename: Option<String>,
606-
pub mod_path_stack: Vec<InternedString>,
607-
pub in_block: bool,
608582
}
609583

610584
impl<'a> ExtCtxt<'a> {
611585
pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
612586
ecfg: expand::ExpansionConfig<'a>,
613587
loader: &'a mut MacroLoader)
614588
-> ExtCtxt<'a> {
615-
let env = initial_syntax_expander_table(&ecfg);
616589
ExtCtxt {
590+
syntax_env: initial_syntax_expander_table(&ecfg),
617591
parse_sess: parse_sess,
618592
cfg: cfg,
619593
backtrace: NO_EXPANSION,
620-
mod_path: Vec::new(),
621594
ecfg: ecfg,
622595
crate_root: None,
623596
exported_macros: Vec::new(),
624597
loader: loader,
625-
syntax_env: env,
626598
derive_modes: HashMap::new(),
627599
recursion_count: 0,
628-
629-
filename: None,
630-
mod_path_stack: Vec::new(),
631-
in_block: false,
632600
}
633601
}
634602

@@ -677,16 +645,7 @@ impl<'a> ExtCtxt<'a> {
677645
last_macro.expect("missing expansion backtrace")
678646
}
679647

680-
pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }
681-
pub fn mod_pop(&mut self) { self.mod_path.pop().unwrap(); }
682-
pub fn mod_path(&self) -> Vec<ast::Ident> {
683-
let mut v = Vec::new();
684-
v.push(token::str_to_ident(&self.ecfg.crate_name));
685-
v.extend(self.mod_path.iter().cloned());
686-
return v;
687-
}
688648
pub fn bt_push(&mut self, ei: ExpnInfo) {
689-
self.recursion_count += 1;
690649
if self.recursion_count > self.ecfg.recursion_limit {
691650
self.span_fatal(ei.call_site,
692651
&format!("recursion limit reached while expanding the macro `{}`",
@@ -700,17 +659,7 @@ impl<'a> ExtCtxt<'a> {
700659
callee: ei.callee
701660
});
702661
}
703-
pub fn bt_pop(&mut self) {
704-
match self.backtrace {
705-
NO_EXPANSION => self.bug("tried to pop without a push"),
706-
expn_id => {
707-
self.recursion_count -= 1;
708-
self.backtrace = self.codemap().with_expn_info(expn_id, |expn_info| {
709-
expn_info.map_or(NO_EXPANSION, |ei| ei.call_site.expn_id)
710-
});
711-
}
712-
}
713-
}
662+
pub fn bt_pop(&mut self) {}
714663

715664
pub fn insert_macro(&mut self, def: ast::MacroDef) {
716665
if def.export {
@@ -829,6 +778,28 @@ impl<'a> ExtCtxt<'a> {
829778
}
830779
}
831780
}
781+
782+
pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::Crate) {
783+
if std_inject::no_core(&krate) {
784+
self.crate_root = None;
785+
} else if std_inject::no_std(&krate) {
786+
self.crate_root = Some("core");
787+
} else {
788+
self.crate_root = Some("std");
789+
}
790+
791+
for (name, extension) in user_exts {
792+
self.syntax_env.insert(name, extension);
793+
}
794+
795+
self.syntax_env.current_module = Module(0);
796+
let mut paths = ModulePaths {
797+
mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
798+
directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
799+
};
800+
paths.directory.pop();
801+
self.syntax_env.module_data[0].paths = Rc::new(paths);
802+
}
832803
}
833804

834805
/// Extract a string literal from the macro expanded version of `expr`,
@@ -915,79 +886,97 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
915886
///
916887
/// This environment maps Names to SyntaxExtensions.
917888
pub struct SyntaxEnv {
918-
chain: Vec<MapChainFrame>,
889+
module_data: Vec<ModuleData>,
890+
pub current_module: Module,
891+
919892
/// All bang-style macro/extension names
920893
/// encountered so far; to be used for diagnostics in resolve
921894
pub names: HashSet<Name>,
922895
}
923896

924-
// impl question: how to implement it? Initially, the
925-
// env will contain only macros, so it might be painful
926-
// to add an empty frame for every context. Let's just
927-
// get it working, first....
897+
#[derive(Copy, Clone, PartialEq, Eq)]
898+
pub struct Module(u32);
928899

929-
// NB! the mutability of the underlying maps means that
930-
// if expansion is out-of-order, a deeper scope may be
931-
// able to refer to a macro that was added to an enclosing
932-
// scope lexically later than the deeper scope.
900+
struct ModuleData {
901+
parent: Module,
902+
paths: Rc<ModulePaths>,
903+
macros: HashMap<Name, Rc<SyntaxExtension>>,
904+
macros_escape: bool,
905+
in_block: bool,
906+
}
933907

934-
struct MapChainFrame {
935-
info: BlockInfo,
936-
map: HashMap<Name, Rc<SyntaxExtension>>,
908+
#[derive(Clone)]
909+
pub struct ModulePaths {
910+
pub mod_path: Vec<ast::Ident>,
911+
pub directory: PathBuf,
937912
}
938913

939914
impl SyntaxEnv {
940915
fn new() -> SyntaxEnv {
941-
let mut map = SyntaxEnv { chain: Vec::new() , names: HashSet::new()};
942-
map.push_frame();
943-
map
916+
let mut env = SyntaxEnv {
917+
current_module: Module(0),
918+
module_data: Vec::new(),
919+
names: HashSet::new(),
920+
};
921+
let paths = Rc::new(ModulePaths { mod_path: Vec::new(), directory: PathBuf::new() });
922+
env.add_module(false, false, paths);
923+
env
944924
}
945925

946-
pub fn push_frame(&mut self) {
947-
self.chain.push(MapChainFrame {
948-
info: BlockInfo::new(),
949-
map: HashMap::new(),
950-
});
926+
fn data(&self, module: Module) -> &ModuleData {
927+
&self.module_data[module.0 as usize]
951928
}
952929

953-
pub fn pop_frame(&mut self) {
954-
assert!(self.chain.len() > 1, "too many pops on MapChain!");
955-
self.chain.pop();
930+
pub fn paths(&self) -> Rc<ModulePaths> {
931+
self.data(self.current_module).paths.clone()
956932
}
957933

958-
fn find_escape_frame(&mut self) -> &mut MapChainFrame {
959-
for (i, frame) in self.chain.iter_mut().enumerate().rev() {
960-
if !frame.info.macros_escape || i == 0 {
961-
return frame
962-
}
963-
}
964-
unreachable!()
934+
pub fn in_block(&self) -> bool {
935+
self.data(self.current_module).in_block
965936
}
966937

967-
pub fn find(&self, k: Name) -> Option<Rc<SyntaxExtension>> {
968-
for frame in self.chain.iter().rev() {
969-
if let Some(v) = frame.map.get(&k) {
970-
return Some(v.clone());
938+
pub fn add_module(&mut self, macros_escape: bool, in_block: bool, paths: Rc<ModulePaths>)
939+
-> Module {
940+
let data = ModuleData {
941+
parent: self.current_module,
942+
paths: paths,
943+
macros: HashMap::new(),
944+
macros_escape: macros_escape,
945+
in_block: in_block,
946+
};
947+
948+
self.module_data.push(data);
949+
Module(self.module_data.len() as u32 - 1)
950+
}
951+
952+
pub fn find(&self, name: Name) -> Option<Rc<SyntaxExtension>> {
953+
let mut module = self.current_module;
954+
let mut module_data;
955+
loop {
956+
module_data = self.data(module);
957+
if let Some(ext) = module_data.macros.get(&name) {
958+
return Some(ext.clone());
971959
}
960+
if module == module_data.parent {
961+
return None;
962+
}
963+
module = module_data.parent;
972964
}
973-
None
974965
}
975966

976-
pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
977-
if let NormalTT(..) = v {
978-
self.names.insert(k);
967+
pub fn insert(&mut self, name: Name, ext: SyntaxExtension) {
968+
if let NormalTT(..) = ext {
969+
self.names.insert(name);
979970
}
980-
self.find_escape_frame().map.insert(k, Rc::new(v));
981-
}
982971

983-
pub fn info(&mut self) -> &mut BlockInfo {
984-
let last_chain_index = self.chain.len() - 1;
985-
&mut self.chain[last_chain_index].info
972+
let mut module = self.current_module;
973+
while self.data(module).macros_escape {
974+
module = self.data(module).parent;
975+
}
976+
self.module_data[module.0 as usize].macros.insert(name, Rc::new(ext));
986977
}
987978

988979
pub fn is_crate_root(&mut self) -> bool {
989-
// The first frame is pushed in `SyntaxEnv::new()` and the second frame is
990-
// pushed when folding the crate root pseudo-module (c.f. noop_fold_crate).
991-
self.chain.len() <= 2
980+
self.current_module == Module(0)
992981
}
993982
}

‎src/libsyntax/ext/expand.rs

Lines changed: 529 additions & 494 deletions
Large diffs are not rendered by default.

‎src/libsyntax/ext/hygiene.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ impl Mark {
4040
::std::mem::replace(&mut data.next_mark, next_mark)
4141
})
4242
}
43+
44+
pub fn as_u32(&self) -> u32 {
45+
self.0
46+
}
4347
}
4448

4549
struct HygieneData {

‎src/libsyntax/ext/placeholders.rs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use ast;
12+
use codemap::{DUMMY_SP, dummy_spanned};
13+
use ext::expand::{Expansion, ExpansionKind};
14+
use fold::*;
15+
use parse::token::keywords;
16+
use ptr::P;
17+
use util::small_vector::SmallVector;
18+
19+
use std::collections::HashMap;
20+
21+
pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
22+
fn mac_placeholder() -> ast::Mac {
23+
dummy_spanned(ast::Mac_ {
24+
path: ast::Path { span: DUMMY_SP, global: false, segments: Vec::new() },
25+
tts: Vec::new(),
26+
})
27+
}
28+
29+
let ident = keywords::Invalid.ident();
30+
let attrs = Vec::new();
31+
let vis = ast::Visibility::Inherited;
32+
let span = DUMMY_SP;
33+
let expr_placeholder = || P(ast::Expr {
34+
id: id, span: span,
35+
attrs: ast::ThinVec::new(),
36+
node: ast::ExprKind::Mac(mac_placeholder()),
37+
});
38+
39+
match kind {
40+
ExpansionKind::Expr => Expansion::Expr(expr_placeholder()),
41+
ExpansionKind::OptExpr => Expansion::OptExpr(Some(expr_placeholder())),
42+
ExpansionKind::Items => Expansion::Items(SmallVector::one(P(ast::Item {
43+
id: id, span: span, ident: ident, vis: vis, attrs: attrs,
44+
node: ast::ItemKind::Mac(mac_placeholder()),
45+
}))),
46+
ExpansionKind::TraitItems => Expansion::TraitItems(SmallVector::one(ast::TraitItem {
47+
id: id, span: span, ident: ident, attrs: attrs,
48+
node: ast::TraitItemKind::Macro(mac_placeholder()),
49+
})),
50+
ExpansionKind::ImplItems => Expansion::ImplItems(SmallVector::one(ast::ImplItem {
51+
id: id, span: span, ident: ident, vis: vis, attrs: attrs,
52+
node: ast::ImplItemKind::Macro(mac_placeholder()),
53+
defaultness: ast::Defaultness::Final,
54+
})),
55+
ExpansionKind::Pat => Expansion::Pat(P(ast::Pat {
56+
id: id, span: span, node: ast::PatKind::Mac(mac_placeholder()),
57+
})),
58+
ExpansionKind::Ty => Expansion::Ty(P(ast::Ty {
59+
id: id, span: span, node: ast::TyKind::Mac(mac_placeholder()),
60+
})),
61+
ExpansionKind::Stmts => Expansion::Stmts(SmallVector::one({
62+
let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::ThinVec::new()));
63+
ast::Stmt { id: id, span: span, node: ast::StmtKind::Mac(mac) }
64+
})),
65+
}
66+
}
67+
68+
pub fn macro_scope_placeholder() -> Expansion {
69+
placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
70+
}
71+
72+
pub struct PlaceholderExpander {
73+
expansions: HashMap<ast::NodeId, Expansion>,
74+
}
75+
76+
impl PlaceholderExpander {
77+
pub fn new() -> Self {
78+
PlaceholderExpander {
79+
expansions: HashMap::new(),
80+
}
81+
}
82+
83+
pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) {
84+
self.expansions.insert(id, expansion);
85+
}
86+
87+
pub fn remove(&mut self, id: ast::NodeId) -> Expansion {
88+
self.expansions.remove(&id).unwrap()
89+
}
90+
}
91+
92+
impl Folder for PlaceholderExpander {
93+
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
94+
match item.node {
95+
// Scope placeholder
96+
ast::ItemKind::Mac(_) if item.id == ast::DUMMY_NODE_ID => SmallVector::one(item),
97+
ast::ItemKind::Mac(_) => self.remove(item.id).make_items(),
98+
_ => noop_fold_item(item, self),
99+
}
100+
}
101+
102+
fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> {
103+
match item.node {
104+
ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(),
105+
_ => noop_fold_trait_item(item, self),
106+
}
107+
}
108+
109+
fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector<ast::ImplItem> {
110+
match item.node {
111+
ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(),
112+
_ => noop_fold_impl_item(item, self),
113+
}
114+
}
115+
116+
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
117+
match expr.node {
118+
ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(),
119+
_ => expr.map(|expr| noop_fold_expr(expr, self)),
120+
}
121+
}
122+
123+
fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
124+
match expr.node {
125+
ast::ExprKind::Mac(_) => self.remove(expr.id).make_opt_expr(),
126+
_ => noop_fold_opt_expr(expr, self),
127+
}
128+
}
129+
130+
fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
131+
let (style, mut expansion) = match stmt.node {
132+
ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()),
133+
_ => return noop_fold_stmt(stmt, self),
134+
};
135+
136+
if style == ast::MacStmtStyle::Semicolon {
137+
if let Some(stmt) = expansion.pop() {
138+
expansion.push(stmt.add_trailing_semicolon());
139+
}
140+
}
141+
142+
expansion
143+
}
144+
145+
fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
146+
match pat.node {
147+
ast::PatKind::Mac(_) => self.remove(pat.id).make_pat(),
148+
_ => noop_fold_pat(pat, self),
149+
}
150+
}
151+
152+
fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> {
153+
match ty.node {
154+
ast::TyKind::Mac(_) => self.remove(ty.id).make_ty(),
155+
_ => noop_fold_ty(ty, self),
156+
}
157+
}
158+
}
159+
160+
pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion {
161+
Expansion::Items(SmallVector::one(P(ast::Item {
162+
ident: def.ident,
163+
attrs: def.attrs.clone(),
164+
id: ast::DUMMY_NODE_ID,
165+
node: ast::ItemKind::Mac(ast::Mac {
166+
span: def.span,
167+
node: ast::Mac_ {
168+
path: path.clone(),
169+
tts: def.body.clone(),
170+
}
171+
}),
172+
vis: ast::Visibility::Inherited,
173+
span: def.span,
174+
})))
175+
}

‎src/libsyntax/ext/source_util.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,9 @@ pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTre
7474
pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
7575
-> Box<base::MacResult+'static> {
7676
base::check_zero_tts(cx, sp, tts, "module_path!");
77-
let string = cx.mod_path()
78-
.iter()
79-
.map(|x| x.to_string())
80-
.collect::<Vec<String>>()
81-
.join("::");
77+
let paths = cx.syntax_env.paths();
78+
let string = paths.mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
79+
8280
base::MacEager::expr(cx.expr_str(
8381
sp,
8482
token::intern_and_get_ident(&string[..])))

‎src/libsyntax/ext/tt/macro_rules.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,8 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
211211
imported_from,
212212
rhs);
213213
let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
214-
p.filename = cx.filename.clone();
215-
p.mod_path_stack = cx.mod_path_stack.clone();
216-
p.restrictions = match cx.in_block {
214+
p.directory = cx.syntax_env.paths().directory.clone();
215+
p.restrictions = match cx.syntax_env.in_block() {
217216
true => Restrictions::NO_NONINLINE_MOD,
218217
false => Restrictions::empty(),
219218
};

‎src/libsyntax/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ pub mod ext {
126126
pub mod base;
127127
pub mod build;
128128
pub mod expand;
129+
pub mod placeholders;
129130
pub mod hygiene;
130131
pub mod proc_macro_shim;
131132
pub mod quote;

‎src/libsyntax/parse/parser.rs

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,7 @@ pub struct Parser<'a> {
264264
/// extra detail when the same error is seen twice
265265
pub obsolete_set: HashSet<ObsoleteSyntax>,
266266
/// Used to determine the path to externally loaded source files
267-
pub filename: Option<String>,
268-
pub mod_path_stack: Vec<InternedString>,
267+
pub directory: PathBuf,
269268
/// Stack of open delimiters and their spans. Used for error message.
270269
pub open_braces: Vec<(token::DelimToken, Span)>,
271270
/// Flag if this parser "owns" the directory that it is currently parsing
@@ -346,9 +345,11 @@ impl<'a> Parser<'a> {
346345
{
347346
let tok0 = rdr.real_token();
348347
let span = tok0.sp;
349-
let filename = if span != syntax_pos::DUMMY_SP {
350-
Some(sess.codemap().span_to_filename(span))
351-
} else { None };
348+
let mut directory = match span {
349+
syntax_pos::DUMMY_SP => PathBuf::new(),
350+
_ => PathBuf::from(sess.codemap().span_to_filename(span)),
351+
};
352+
directory.pop();
352353
let placeholder = TokenAndSpan {
353354
tok: token::Underscore,
354355
sp: span,
@@ -377,8 +378,7 @@ impl<'a> Parser<'a> {
377378
quote_depth: 0,
378379
parsing_token_tree: false,
379380
obsolete_set: HashSet::new(),
380-
mod_path_stack: Vec::new(),
381-
filename: filename,
381+
directory: directory,
382382
open_braces: Vec::new(),
383383
owns_directory: true,
384384
root_module_name: None,
@@ -5306,27 +5306,24 @@ impl<'a> Parser<'a> {
53065306
let (m, attrs) = self.eval_src_mod(id, &outer_attrs, id_span)?;
53075307
Ok((id, m, Some(attrs)))
53085308
} else {
5309-
self.push_mod_path(id, &outer_attrs);
5309+
let directory = self.directory.clone();
5310+
self.push_directory(id, &outer_attrs);
53105311
self.expect(&token::OpenDelim(token::Brace))?;
53115312
let mod_inner_lo = self.span.lo;
53125313
let attrs = self.parse_inner_attributes()?;
53135314
let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
5314-
self.pop_mod_path();
5315+
self.directory = directory;
53155316
Ok((id, ItemKind::Mod(m), Some(attrs)))
53165317
}
53175318
}
53185319

5319-
fn push_mod_path(&mut self, id: Ident, attrs: &[Attribute]) {
5320+
fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
53205321
let default_path = self.id_to_interned_str(id);
53215322
let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") {
53225323
Some(d) => d,
53235324
None => default_path,
53245325
};
5325-
self.mod_path_stack.push(file_path)
5326-
}
5327-
5328-
fn pop_mod_path(&mut self) {
5329-
self.mod_path_stack.pop().unwrap();
5326+
self.directory.push(&*file_path)
53305327
}
53315328

53325329
pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option<PathBuf> {
@@ -5374,18 +5371,11 @@ impl<'a> Parser<'a> {
53745371
id: ast::Ident,
53755372
outer_attrs: &[ast::Attribute],
53765373
id_sp: Span) -> PResult<'a, ModulePathSuccess> {
5377-
let mut prefix = PathBuf::from(self.filename.as_ref().unwrap());
5378-
prefix.pop();
5379-
let mut dir_path = prefix;
5380-
for part in &self.mod_path_stack {
5381-
dir_path.push(&**part);
5382-
}
5383-
5384-
if let Some(p) = Parser::submod_path_from_attr(outer_attrs, &dir_path) {
5374+
if let Some(p) = Parser::submod_path_from_attr(outer_attrs, &self.directory) {
53855375
return Ok(ModulePathSuccess { path: p, owns_directory: true });
53865376
}
53875377

5388-
let paths = Parser::default_submod_path(id, &dir_path, self.sess.codemap());
5378+
let paths = Parser::default_submod_path(id, &self.directory, self.sess.codemap());
53895379

53905380
if self.restrictions.contains(Restrictions::NO_NONINLINE_MOD) {
53915381
let msg =
@@ -5400,8 +5390,8 @@ impl<'a> Parser<'a> {
54005390
} else if !self.owns_directory {
54015391
let mut err = self.diagnostic().struct_span_err(id_sp,
54025392
"cannot declare a new module at this location");
5403-
let this_module = match self.mod_path_stack.last() {
5404-
Some(name) => name.to_string(),
5393+
let this_module = match self.directory.file_name() {
5394+
Some(file_name) => file_name.to_str().unwrap().to_owned(),
54055395
None => self.root_module_name.as_ref().unwrap().clone(),
54065396
};
54075397
err.span_note(id_sp,

‎src/libsyntax/test.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,14 +300,11 @@ fn generate_test_harness(sess: &ParseSess,
300300
}
301301
});
302302

303-
let mut fold = TestHarnessGenerator {
303+
TestHarnessGenerator {
304304
cx: cx,
305305
tests: Vec::new(),
306306
tested_submods: Vec::new(),
307-
};
308-
let res = fold.fold_crate(krate);
309-
fold.cx.ext_cx.bt_pop();
310-
return res;
307+
}.fold_crate(krate)
311308
}
312309

313310
/// Craft a span that will be ignored by the stability lint's

‎src/libsyntax/util/small_vector.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ enum SmallVectorRepr<T> {
2929
Many(Vec<T>),
3030
}
3131

32+
impl<T> Default for SmallVector<T> {
33+
fn default() -> Self {
34+
SmallVector { repr: Zero }
35+
}
36+
}
37+
3238
impl<T> Into<Vec<T>> for SmallVector<T> {
3339
fn into(self) -> Vec<T> {
3440
match self.repr {

0 commit comments

Comments
 (0)
Please sign in to comment.