]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #34837 - GuillaumeGomez:better_example, r=nagisa
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Sat, 16 Jul 2016 14:55:59 +0000 (16:55 +0200)
committerGitHub <noreply@github.com>
Sat, 16 Jul 2016 14:55:59 +0000 (16:55 +0200)
Improve float number example

r? @nagisa

21 files changed:
configure
mk/cfg/mips-unknown-linux-gnu.mk
mk/main.mk
mk/stage0.mk
src/bootstrap/lib.rs
src/doc/reference.md
src/etc/local_stage0.sh
src/libcore/hash/sip.rs
src/librustc_driver/driver.rs
src/librustc_resolve/assign_ids.rs [new file with mode: 0644]
src/librustc_resolve/lib.rs
src/libsyntax/ast.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/mtwt.rs
src/libsyntax/parse/attr.rs
src/libsyntax/parse/token.rs
src/libsyntax/test.rs
src/test/parse-fail/inner-attr-after-doc-comment.rs [new file with mode: 0644]
src/test/parse-fail/inner-attr.rs [new file with mode: 0644]
src/test/run-pass/hygiene.rs

index 16496eb89d4ca8ef1ec581fb60fbebc0d43af1f3..fd009a757a4b70dee62e84b4d8d391ec503d6344 100755 (executable)
--- a/configure
+++ b/configure
@@ -600,7 +600,7 @@ opt debug-assertions 0 "build with debugging assertions"
 opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
 opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds"
 opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
-opt local-rebuild 0 "use an installed rustc matching the current version, for rebuilds"
+opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version"
 opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
 opt rpath 1 "build rpaths into rustc itself"
 opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0"
index 9e7042befa975b0e013623162e8b48297fed2f49..0783a4c17a4f2153393e5f17171e78793c2e6f94 100644 (file)
@@ -7,10 +7,10 @@ CFG_LIB_NAME_mips-unknown-linux-gnu=lib$(1).so
 CFG_STATIC_LIB_NAME_mips-unknown-linux-gnu=lib$(1).a
 CFG_LIB_GLOB_mips-unknown-linux-gnu=lib$(1)-*.so
 CFG_LIB_DSYM_GLOB_mips-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
-CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -msoft-float -mabi=32 $(CFLAGS)
-CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 $(CFLAGS)
+CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -mabi=32 $(CFLAGS)
+CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -mabi=32 $(CFLAGS)
 CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
-CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32
+CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -mabi=32
 CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
 CFG_LLC_FLAGS_mips-unknown-linux-gnu :=
 CFG_INSTALL_NAME_mips-unknown-linux-gnu =
index 4c72597f0c5c1d2a2192a24f9d2337a36ae46be9..fd12bf26dfc72fdca793e5efa4ae459c24320819 100644 (file)
@@ -20,29 +20,6 @@ CFG_RELEASE_NUM=1.12.0
 # versions (section 9)
 CFG_PRERELEASE_VERSION=.1
 
-# Append a version-dependent hash to each library, so we can install different
-# versions in the same place
-CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND))
-
-# A magic value that allows the compiler to use unstable features during the
-# bootstrap even when doing so would normally be an error because of feature
-# staging or because the build turns on warnings-as-errors and unstable features
-# default to warnings. The build has to match this key in an env var.
-#
-# This value is keyed off the release to ensure that all compilers for one
-# particular release have the same bootstrap key. Note that this is
-# intentionally not "secure" by any definition, this is largely just a deterrent
-# from users enabling unstable features on the stable compiler.
-CFG_BOOTSTRAP_KEY=$(CFG_FILENAME_EXTRA)
-
-# The stage0 compiler needs to use the previous key recorded in src/stage0.txt,
-# except for local-rebuild when it just uses the same current key.
-ifdef CFG_ENABLE_LOCAL_REBUILD
-CFG_BOOTSTRAP_KEY_STAGE0=$(CFG_BOOTSTRAP_KEY)
-else
-CFG_BOOTSTRAP_KEY_STAGE0=$(shell grep 'rustc_key' $(S)src/stage0.txt | sed 's/rustc_key: '//)
-endif
-
 ifeq ($(CFG_RELEASE_CHANNEL),stable)
 # This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly"
 CFG_RELEASE=$(CFG_RELEASE_NUM)
@@ -72,6 +49,38 @@ CFG_RELEASE=$(CFG_RELEASE_NUM)-dev
 CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-dev
 endif
 
+# Append a version-dependent hash to each library, so we can install different
+# versions in the same place
+CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND))
+
+# A magic value that allows the compiler to use unstable features during the
+# bootstrap even when doing so would normally be an error because of feature
+# staging or because the build turns on warnings-as-errors and unstable features
+# default to warnings. The build has to match this key in an env var.
+#
+# This value is keyed off the release to ensure that all compilers for one
+# particular release have the same bootstrap key. Note that this is
+# intentionally not "secure" by any definition, this is largely just a deterrent
+# from users enabling unstable features on the stable compiler.
+CFG_BOOTSTRAP_KEY=$(CFG_FILENAME_EXTRA)
+
+# If local-rust is the same as the current version, then force a local-rebuild
+ifdef CFG_ENABLE_LOCAL_RUST
+ifeq ($(CFG_RELEASE),\
+      $(shell $(S)src/etc/local_stage0.sh --print-rustc-release $(CFG_LOCAL_RUST_ROOT)))
+    CFG_INFO := $(info cfg: auto-detected local-rebuild $(CFG_RELEASE))
+    CFG_ENABLE_LOCAL_REBUILD = 1
+endif
+endif
+
+# The stage0 compiler needs to use the previous key recorded in src/stage0.txt,
+# except for local-rebuild when it just uses the same current key.
+ifdef CFG_ENABLE_LOCAL_REBUILD
+CFG_BOOTSTRAP_KEY_STAGE0=$(CFG_BOOTSTRAP_KEY)
+else
+CFG_BOOTSTRAP_KEY_STAGE0=$(shell sed -ne 's/^rustc_key: //p' $(S)src/stage0.txt)
+endif
+
 # The name of the package to use for creating tarballs, installers etc.
 CFG_PACKAGE_NAME=rustc-$(CFG_PACKAGE_VERS)
 
index d0191874cb3d96968c8fcd086c7ffd413ef35bf1..8a2bf2ebbde649817af12b2eb753fa2559939a3a 100644 (file)
@@ -11,6 +11,7 @@ endif
 
 $(SNAPSHOT_RUSTC_POST_CLEANUP): \
                $(S)src/stage0.txt \
+               $(S)src/etc/local_stage0.sh \
                $(S)src/etc/get-stage0.py $(MKFILE_DEPS) \
                | $(HBIN0_H_$(CFG_BUILD))/
        @$(call E, fetch: $@)
index 943271fc8a641665734531b3393b32d4f37d1e5e..caa6ea17ea0544d6f6a5c263239e4548ad469db4 100644 (file)
@@ -118,6 +118,7 @@ pub struct Build {
     ver_date: Option<String>,
     version: String,
     package_vers: String,
+    local_rebuild: bool,
     bootstrap_key: String,
     bootstrap_key_stage0: String,
 
@@ -174,6 +175,7 @@ pub fn new(flags: Flags, config: Config) -> Build {
             Some(ref s) => PathBuf::from(s),
             None => stage0_root.join(exe("cargo", &config.build)),
         };
+        let local_rebuild = config.local_rebuild;
 
         Build {
             flags: flags,
@@ -189,6 +191,7 @@ pub fn new(flags: Flags, config: Config) -> Build {
             short_ver_hash: None,
             ver_date: None,
             version: String::new(),
+            local_rebuild: local_rebuild,
             bootstrap_key: String::new(),
             bootstrap_key_stage0: String::new(),
             package_vers: String::new(),
@@ -219,6 +222,16 @@ pub fn build(&mut self) {
         sanity::check(self);
         self.verbose("collecting channel variables");
         channel::collect(self);
+        // If local-rust is the same as the current version, then force a local-rebuild
+        let local_version_verbose = output(
+            Command::new(&self.rustc).arg("--version").arg("--verbose"));
+        let local_release = local_version_verbose
+            .lines().filter(|x| x.starts_with("release:"))
+            .next().unwrap().trim_left_matches("release:").trim();
+        if local_release == self.release {
+            self.verbose(&format!("auto-detected local-rebuild {}", self.release));
+            self.local_rebuild = true;
+        }
         self.verbose("updating submodules");
         self.update_submodules();
 
@@ -525,7 +538,7 @@ fn cargo(&self,
              .arg("--target").arg(target);
 
         let stage;
-        if compiler.stage == 0 && self.config.local_rebuild {
+        if compiler.stage == 0 && self.local_rebuild {
             // Assume the local-rebuild rustc already has stage1 features.
             stage = 1;
         } else {
@@ -766,7 +779,7 @@ fn add_bootstrap_key(&self, compiler: &Compiler, cmd: &mut Command) {
         // In stage0 we're using a previously released stable compiler, so we
         // use the stage0 bootstrap key. Otherwise we use our own build's
         // bootstrap key.
-        let bootstrap_key = if compiler.is_snapshot(self) && !self.config.local_rebuild {
+        let bootstrap_key = if compiler.is_snapshot(self) && !self.local_rebuild {
             &self.bootstrap_key_stage0
         } else {
             &self.bootstrap_key
index b3073f5e526033271c855588b8fb343d40d63bb5..b8509321e3d19b0679ba7a29aea280336229dab2 100644 (file)
@@ -853,6 +853,20 @@ extern crate std; // equivalent to: extern crate std as std;
 extern crate std as ruststd; // linking to 'std' under another name
 ```
 
+When naming Rust crates, hyphens are disallowed. However, Cargo packages may
+make use of them. In such case, when `Cargo.toml` doesn't specify a crate name,
+Cargo will transparently replace `-` with `_` (Refer to [RFC 940] for more
+details).
+
+Here is an example:
+
+```{.ignore}
+// Importing the Cargo package hello-world
+extern crate hello_world; // hyphen replaced with an underscore
+```
+
+[RFC 940]: https://github.com/rust-lang/rfcs/blob/master/text/0940-hyphens-considered-harmful.md
+
 #### Use declarations
 
 A _use declaration_ creates one or more local name bindings synonymous with
@@ -3744,9 +3758,9 @@ Since `'static` "lives longer" than `'a`, `&'static str` is a subtype of
 
 ## Type coercions
 
-Coercions are defined in [RFC401]. A coercion is implicit and has no syntax.
+Coercions are defined in [RFC 401]. A coercion is implicit and has no syntax.
 
-[RFC401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
+[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
 
 ### Coercion sites
 
@@ -3886,7 +3900,7 @@ Coercion is allowed between the following types:
 
     In the future, coerce_inner will be recursively extended to tuples and
     structs. In addition, coercions from sub-traits to super-traits will be
-    added. See [RFC401] for more details.
+    added. See [RFC 401] for more details.
 
 # Special traits
 
index fb455441910b8ca4f9fca9c98164e1e0320f73c3..354be34b6a2950efe920bd2e44e57efe77e2bf74 100755 (executable)
@@ -49,6 +49,13 @@ if [ -z $TARG_DIR ]; then
     exit 1
 fi
 
+case "$TARG_DIR" in
+--print-rustc-release)
+  # not actually copying to TARG_DIR, just print the local rustc version and exit
+  ${PREFIX}/bin/rustc${BIN_SUF} --version --verbose | sed -ne 's/^release: //p'
+;;
+*)
+
 cp ${PREFIX}/bin/rustc${BIN_SUF} ${TARG_DIR}/stage0/bin/
 cp ${PREFIX}/${LIB_DIR}/${RUSTLIBDIR}/${TARG_DIR}/${LIB_DIR}/* ${TARG_DIR}/stage0/${LIB_DIR}/
 cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}extra*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
@@ -66,3 +73,5 @@ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}term*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DI
 
 # do not fail if one of the above fails, as all we need is a working rustc!
 exit 0
+
+esac
index c52c0b0730be785d8d8aad84bdd68577df4023e3..4a806a3c98602aa224b963e8a862526d3b1b48ef 100644 (file)
@@ -18,7 +18,7 @@
 /// An implementation of SipHash 1-3.
 ///
 /// See: https://131002.net/siphash/
-#[unstable(feature = "sip_hash_13", issue = "29754")]
+#[unstable(feature = "sip_hash_13", issue = "34767")]
 #[derive(Debug, Clone, Default)]
 pub struct SipHasher13 {
     hasher: Hasher<Sip13Rounds>,
@@ -27,7 +27,7 @@ pub struct SipHasher13 {
 /// An implementation of SipHash 2-4.
 ///
 /// See: https://131002.net/siphash/
-#[unstable(feature = "sip_hash_13", issue = "29754")]
+#[unstable(feature = "sip_hash_13", issue = "34767")]
 #[derive(Debug, Clone, Default)]
 pub struct SipHasher24 {
     hasher: Hasher<Sip24Rounds>,
@@ -154,14 +154,14 @@ pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
 impl SipHasher13 {
     /// Creates a new `SipHasher13` with the two initial keys set to 0.
     #[inline]
-    #[unstable(feature = "sip_hash_13", issue = "29754")]
+    #[unstable(feature = "sip_hash_13", issue = "34767")]
     pub fn new() -> SipHasher13 {
         SipHasher13::new_with_keys(0, 0)
     }
 
     /// Creates a `SipHasher13` that is keyed off the provided keys.
     #[inline]
-    #[unstable(feature = "sip_hash_13", issue = "29754")]
+    #[unstable(feature = "sip_hash_13", issue = "34767")]
     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
         SipHasher13 {
             hasher: Hasher::new_with_keys(key0, key1)
@@ -172,14 +172,14 @@ pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
 impl SipHasher24 {
     /// Creates a new `SipHasher24` with the two initial keys set to 0.
     #[inline]
-    #[unstable(feature = "sip_hash_13", issue = "29754")]
+    #[unstable(feature = "sip_hash_13", issue = "34767")]
     pub fn new() -> SipHasher24 {
         SipHasher24::new_with_keys(0, 0)
     }
 
     /// Creates a `SipHasher24` that is keyed off the provided keys.
     #[inline]
-    #[unstable(feature = "sip_hash_13", issue = "29754")]
+    #[unstable(feature = "sip_hash_13", issue = "34767")]
     pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 {
         SipHasher24 {
             hasher: Hasher::new_with_keys(key0, key1)
@@ -232,7 +232,7 @@ fn finish(&self) -> u64 {
     }
 }
 
-#[unstable(feature = "sip_hash_13", issue = "29754")]
+#[unstable(feature = "sip_hash_13", issue = "34767")]
 impl super::Hasher for SipHasher13 {
     #[inline]
     fn write(&mut self, msg: &[u8]) {
@@ -245,7 +245,7 @@ fn finish(&self) -> u64 {
     }
 }
 
-#[unstable(feature = "sip_hash_13", issue = "29754")]
+#[unstable(feature = "sip_hash_13", issue = "34767")]
 impl super::Hasher for SipHasher24 {
     #[inline]
     fn write(&mut self, msg: &[u8]) {
index ba59c2afc769d3e5112fa436f2c725047ea76173..3b1124a911e5d2ad9bb9b8a3acf91f9d531bc34e 100644 (file)
@@ -50,7 +50,6 @@
 use std::path::{Path, PathBuf};
 use syntax::{ast, diagnostics, visit};
 use syntax::attr::{self, AttrMetaMethods};
-use syntax::fold::Folder;
 use syntax::parse::{self, PResult, token};
 use syntax::util::node_count::NodeCounter;
 use syntax;
@@ -695,6 +694,19 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
                                          sess.diagnostic())
     });
 
+    let resolver_arenas = Resolver::arenas();
+    let mut resolver = Resolver::new(sess, make_glob_map, &resolver_arenas);
+
+    let krate = time(sess.time_passes(), "assigning node ids", || resolver.assign_node_ids(krate));
+
+    if sess.opts.debugging_opts.input_stats {
+        println!("Post-expansion node count: {}", count_nodes(&krate));
+    }
+
+    if sess.opts.debugging_opts.ast_json {
+        println!("{}", json::as_json(&krate));
+    }
+
     time(time_passes,
          "checking for inline asm in case the target doesn't support it",
          || no_asm::check_crate(sess, &krate));
@@ -710,15 +722,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
         })
     })?;
 
-    if sess.opts.debugging_opts.input_stats {
-        println!("Post-expansion node count: {}", count_nodes(&krate));
-    }
-
-    krate = assign_node_ids(sess, krate);
-
-    let resolver_arenas = Resolver::arenas();
-    let mut resolver = Resolver::new(sess, make_glob_map, &resolver_arenas);
-
     // Collect defintions for def ids.
     time(sess.time_passes(), "collecting defs", || resolver.definitions.collect(&krate));
 
@@ -783,53 +786,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
     })
 }
 
-pub fn assign_node_ids(sess: &Session, krate: ast::Crate) -> ast::Crate {
-    use syntax::ptr::P;
-    use syntax::util::move_map::MoveMap;
-
-    struct NodeIdAssigner<'a> {
-        sess: &'a Session,
-    }
-
-    impl<'a> Folder for NodeIdAssigner<'a> {
-        fn new_id(&mut self, old_id: ast::NodeId) -> ast::NodeId {
-            assert_eq!(old_id, ast::DUMMY_NODE_ID);
-            self.sess.next_node_id()
-        }
-
-        fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
-            block.map(|mut block| {
-                block.id = self.new_id(block.id);
-
-                let stmt = block.stmts.pop();
-                block.stmts = block.stmts.move_flat_map(|s| self.fold_stmt(s).into_iter());
-                if let Some(ast::Stmt { node: ast::StmtKind::Expr(expr), span, .. }) = stmt {
-                    let expr = self.fold_expr(expr);
-                    block.stmts.push(ast::Stmt {
-                        id: expr.id,
-                        node: ast::StmtKind::Expr(expr),
-                        span: span,
-                    });
-                } else if let Some(stmt) = stmt {
-                    block.stmts.extend(self.fold_stmt(stmt));
-                }
-
-                block
-            })
-        }
-    }
-
-    let krate = time(sess.time_passes(),
-                     "assigning node ids",
-                     || NodeIdAssigner { sess: sess }.fold_crate(krate));
-
-    if sess.opts.debugging_opts.ast_json {
-        println!("{}", json::as_json(&krate));
-    }
-
-    krate
-}
-
 /// Run the resolution, typechecking, region checking and other
 /// miscellaneous analysis passes on the crate. Return various
 /// structures carrying the results of the analysis.
diff --git a/src/librustc_resolve/assign_ids.rs b/src/librustc_resolve/assign_ids.rs
new file mode 100644 (file)
index 0000000..d446582
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use Resolver;
+use rustc::session::Session;
+use syntax::ast;
+use syntax::ext::mtwt;
+use syntax::fold::{self, Folder};
+use syntax::ptr::P;
+use syntax::util::move_map::MoveMap;
+use syntax::util::small_vector::SmallVector;
+
+use std::collections::HashMap;
+use std::mem;
+
+impl<'a> Resolver<'a> {
+    pub fn assign_node_ids(&mut self, krate: ast::Crate) -> ast::Crate {
+        NodeIdAssigner {
+            sess: self.session,
+            macros_at_scope: &mut self.macros_at_scope,
+        }.fold_crate(krate)
+    }
+}
+
+struct NodeIdAssigner<'a> {
+    sess: &'a Session,
+    macros_at_scope: &'a mut HashMap<ast::NodeId, Vec<ast::Mrk>>,
+}
+
+impl<'a> Folder for NodeIdAssigner<'a> {
+    fn new_id(&mut self, old_id: ast::NodeId) -> ast::NodeId {
+        assert_eq!(old_id, ast::DUMMY_NODE_ID);
+        self.sess.next_node_id()
+    }
+
+    fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> {
+        block.map(|mut block| {
+            block.id = self.new_id(block.id);
+
+            let stmt = block.stmts.pop();
+            let mut macros = Vec::new();
+            block.stmts = block.stmts.move_flat_map(|stmt| {
+                if let ast::StmtKind::Item(ref item) = stmt.node {
+                    if let ast::ItemKind::Mac(..) = item.node {
+                        macros.push(mtwt::outer_mark(item.ident.ctxt));
+                        return None;
+                    }
+                }
+
+                let stmt = self.fold_stmt(stmt).pop().unwrap();
+                if !macros.is_empty() {
+                    self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new()));
+                }
+                Some(stmt)
+            });
+
+            stmt.and_then(|mut stmt| {
+                // Avoid wasting a node id on a trailing expression statement,
+                // which shares a HIR node with the expression itself.
+                if let ast::StmtKind::Expr(expr) = stmt.node {
+                    let expr = self.fold_expr(expr);
+                    stmt.id = expr.id;
+                    stmt.node = ast::StmtKind::Expr(expr);
+                    Some(stmt)
+                } else {
+                    self.fold_stmt(stmt).pop()
+                }
+            }).map(|stmt| {
+                if !macros.is_empty() {
+                    self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new()));
+                }
+                block.stmts.push(stmt);
+            });
+
+            block
+        })
+    }
+
+    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
+        match item.node {
+            ast::ItemKind::Mac(..) => SmallVector::zero(),
+            _ => fold::noop_fold_item(item, self),
+        }
+    }
+}
index 9079cc8ccb122b86ecf41654a760b6c0e595ef08..2535c264ef8f647fc516231ae8a55a2ed93375f5 100644 (file)
@@ -83,6 +83,7 @@
 mod check_unused;
 mod build_reduced_graph;
 mod resolve_imports;
+mod assign_ids;
 
 enum SuggestionType {
     Macro(String),
@@ -461,7 +462,7 @@ struct BindingInfo {
 }
 
 // Map from the name in a pattern to its binding mode.
-type BindingMap = HashMap<Name, BindingInfo>;
+type BindingMap = HashMap<ast::Ident, BindingInfo>;
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum PatternSource {
@@ -651,6 +652,9 @@ enum RibKind<'a> {
 
     // We passed through a module.
     ModuleRibKind(Module<'a>),
+
+    // We passed through a `macro_rules!` statement with the given expansion
+    MacroDefinition(ast::Mrk),
 }
 
 #[derive(Copy, Clone)]
@@ -667,7 +671,7 @@ enum ModulePrefixResult<'a> {
 /// One local scope.
 #[derive(Debug)]
 struct Rib<'a> {
-    bindings: HashMap<Name, Def>,
+    bindings: HashMap<ast::Ident, Def>,
     kind: RibKind<'a>,
 }
 
@@ -927,6 +931,10 @@ pub struct Resolver<'a> {
 
     pub definitions: Definitions,
 
+    // Maps the node id of a statement to the expansions of the `macro_rules!`s
+    // immediately above the statement (if appropriate).
+    macros_at_scope: HashMap<NodeId, Vec<ast::Mrk>>,
+
     graph_root: Module<'a>,
 
     prelude: Option<Module<'a>>,
@@ -1113,6 +1121,7 @@ pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a Resolve
             session: session,
 
             definitions: Definitions::new(),
+            macros_at_scope: HashMap::new(),
 
             // The outermost module has def ID 0; this is not reflected in the
             // AST.
@@ -1384,15 +1393,17 @@ fn resolve_module_path(&mut self,
     /// Invariant: This must only be called during main resolution, not during
     /// import resolution.
     fn resolve_ident_in_lexical_scope(&mut self,
-                                      ident: ast::Ident,
+                                      mut ident: ast::Ident,
                                       ns: Namespace,
                                       record_used: bool)
                                       -> Option<LexicalScopeBinding<'a>> {
-        let name = match ns { ValueNS => mtwt::resolve(ident), TypeNS => ident.name };
+        if ns == TypeNS {
+            ident = ast::Ident::with_empty_ctxt(ident.name);
+        }
 
         // Walk backwards up the ribs in scope.
         for i in (0 .. self.get_ribs(ns).len()).rev() {
-            if let Some(def) = self.get_ribs(ns)[i].bindings.get(&name).cloned() {
+            if let Some(def) = self.get_ribs(ns)[i].bindings.get(&ident).cloned() {
                 // The ident resolves to a type parameter or local variable.
                 return Some(LexicalScopeBinding::LocalDef(LocalDef {
                     ribs: Some((ns, i)),
@@ -1419,6 +1430,16 @@ fn resolve_ident_in_lexical_scope(&mut self,
                     };
                 }
             }
+
+            if let MacroDefinition(mac) = self.get_ribs(ns)[i].kind {
+                // If an invocation of this macro created `ident`, give up on `ident`
+                // and switch to `ident`'s source from the macro definition.
+                if let Some((source_ident, source_macro)) = mtwt::source(ident) {
+                    if mac == source_macro {
+                        ident = source_ident;
+                    }
+                }
+            }
         }
 
         None
@@ -1555,18 +1576,27 @@ fn with_scope<F>(&mut self, id: NodeId, f: F)
 
     /// Searches the current set of local scopes for labels.
     /// Stops after meeting a closure.
-    fn search_label(&self, name: Name) -> Option<Def> {
+    fn search_label(&self, mut ident: ast::Ident) -> Option<Def> {
         for rib in self.label_ribs.iter().rev() {
             match rib.kind {
                 NormalRibKind => {
                     // Continue
                 }
+                MacroDefinition(mac) => {
+                    // If an invocation of this macro created `ident`, give up on `ident`
+                    // and switch to `ident`'s source from the macro definition.
+                    if let Some((source_ident, source_macro)) = mtwt::source(ident) {
+                        if mac == source_macro {
+                            ident = source_ident;
+                        }
+                    }
+                }
                 _ => {
                     // Do not resolve labels across function boundary
                     return None;
                 }
             }
-            let result = rib.bindings.get(&name).cloned();
+            let result = rib.bindings.get(&ident).cloned();
             if result.is_some() {
                 return result;
             }
@@ -1715,7 +1745,7 @@ fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<
                     // plain insert (no renaming)
                     let def_id = self.definitions.local_def_id(type_parameter.id);
                     let def = Def::TyParam(space, index as u32, def_id, name);
-                    function_type_rib.bindings.insert(name, def);
+                    function_type_rib.bindings.insert(ast::Ident::with_empty_ctxt(name), def);
                 }
                 self.type_ribs.push(function_type_rib);
             }
@@ -1886,7 +1916,7 @@ fn with_self_rib<F>(&mut self, self_def: Def, f: F)
         let mut self_type_rib = Rib::new(NormalRibKind);
 
         // plain insert (no renaming, types are not currently hygienic....)
-        self_type_rib.bindings.insert(keywords::SelfType.name(), self_def);
+        self_type_rib.bindings.insert(keywords::SelfType.ident(), self_def);
         self.type_ribs.push(self_type_rib);
         f(self);
         self.type_ribs.pop();
@@ -1997,7 +2027,7 @@ fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
                     _ => false,
                 } {
                     let binding_info = BindingInfo { span: ident.span, binding_mode: binding_mode };
-                    binding_map.insert(mtwt::resolve(ident.node), binding_info);
+                    binding_map.insert(ident.node, binding_info);
                 }
             }
             true
@@ -2019,15 +2049,14 @@ fn check_consistent_bindings(&mut self, arm: &Arm) {
             for (&key, &binding_0) in &map_0 {
                 match map_i.get(&key) {
                     None => {
-                        resolve_error(self,
-                                      p.span,
-                                      ResolutionError::VariableNotBoundInPattern(key, 1, i + 1));
+                        let error = ResolutionError::VariableNotBoundInPattern(key.name, 1, i + 1);
+                        resolve_error(self, p.span, error);
                     }
                     Some(binding_i) => {
                         if binding_0.binding_mode != binding_i.binding_mode {
                             resolve_error(self,
                                           binding_i.span,
-                                          ResolutionError::VariableBoundWithDifferentMode(key,
+                                          ResolutionError::VariableBoundWithDifferentMode(key.name,
                                                                                           i + 1));
                         }
                     }
@@ -2038,7 +2067,7 @@ fn check_consistent_bindings(&mut self, arm: &Arm) {
                 if !map_0.contains_key(&key) {
                     resolve_error(self,
                                   binding.span,
-                                  ResolutionError::VariableNotBoundInPattern(key, i + 1, 1));
+                                  ResolutionError::VariableNotBoundInPattern(key.name, i + 1, 1));
                 }
             }
         }
@@ -2068,6 +2097,7 @@ fn resolve_block(&mut self, block: &Block) {
         let orig_module = self.current_module;
         let anonymous_module = self.module_map.get(&block.id).cloned(); // clones a reference
 
+        let mut num_macro_definition_ribs = 0;
         if let Some(anonymous_module) = anonymous_module {
             debug!("(resolving block) found anonymous module, moving down");
             self.value_ribs.push(Rib::new(ModuleRibKind(anonymous_module)));
@@ -2078,10 +2108,24 @@ fn resolve_block(&mut self, block: &Block) {
         }
 
         // Descend into the block.
-        visit::walk_block(self, block);
+        for stmt in &block.stmts {
+            if let Some(marks) = self.macros_at_scope.remove(&stmt.id) {
+                num_macro_definition_ribs += marks.len() as u32;
+                for mark in marks {
+                    self.value_ribs.push(Rib::new(MacroDefinition(mark)));
+                    self.label_ribs.push(Rib::new(MacroDefinition(mark)));
+                }
+            }
+
+            self.visit_stmt(stmt);
+        }
 
         // Move back up.
         self.current_module = orig_module;
+        for _ in 0 .. num_macro_definition_ribs {
+            self.value_ribs.pop();
+            self.label_ribs.pop();
+        }
         self.value_ribs.pop();
         if let Some(_) = anonymous_module {
             self.type_ribs.pop();
@@ -2172,16 +2216,15 @@ fn fresh_binding(&mut self,
                      pat_id: NodeId,
                      outer_pat_id: NodeId,
                      pat_src: PatternSource,
-                     bindings: &mut HashMap<Name, NodeId>)
+                     bindings: &mut HashMap<ast::Ident, NodeId>)
                      -> PathResolution {
         // Add the binding to the local ribs, if it
         // doesn't already exist in the bindings map. (We
         // must not add it if it's in the bindings map
         // because that breaks the assumptions later
         // passes make about or-patterns.)
-        let renamed = mtwt::resolve(ident.node);
         let mut def = Def::Local(self.definitions.local_def_id(pat_id), pat_id);
-        match bindings.get(&renamed).cloned() {
+        match bindings.get(&ident.node).cloned() {
             Some(id) if id == outer_pat_id => {
                 // `Variant(a, a)`, error
                 resolve_error(
@@ -2203,7 +2246,7 @@ fn fresh_binding(&mut self,
             Some(..) if pat_src == PatternSource::Match => {
                 // `Variant1(a) | Variant2(a)`, ok
                 // Reuse definition from the first `a`.
-                def = self.value_ribs.last_mut().unwrap().bindings[&renamed];
+                def = self.value_ribs.last_mut().unwrap().bindings[&ident.node];
             }
             Some(..) => {
                 span_bug!(ident.span, "two bindings with the same name from \
@@ -2212,8 +2255,8 @@ fn fresh_binding(&mut self,
             None => {
                 // A completely fresh binding, add to the lists if it's valid.
                 if ident.node.name != keywords::Invalid.name() {
-                    bindings.insert(renamed, outer_pat_id);
-                    self.value_ribs.last_mut().unwrap().bindings.insert(renamed, def);
+                    bindings.insert(ident.node, outer_pat_id);
+                    self.value_ribs.last_mut().unwrap().bindings.insert(ident.node, def);
                 }
             }
         }
@@ -2274,7 +2317,7 @@ fn resolve_pattern(&mut self,
                        pat_src: PatternSource,
                        // Maps idents to the node ID for the
                        // outermost pattern that binds them.
-                       bindings: &mut HashMap<Name, NodeId>) {
+                       bindings: &mut HashMap<ast::Ident, NodeId>) {
         // Visit all direct subpatterns of this pattern.
         let outer_pat_id = pat.id;
         pat.walk(&mut |pat| {
@@ -2497,7 +2540,7 @@ fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Option<Def> {
             Def::Local(_, node_id) => {
                 for rib in ribs {
                     match rib.kind {
-                        NormalRibKind | ModuleRibKind(..) => {
+                        NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) => {
                             // Nothing to do. Continue.
                         }
                         ClosureRibKind(function_id) => {
@@ -2546,7 +2589,7 @@ fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Option<Def> {
                 for rib in ribs {
                     match rib.kind {
                         NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) |
-                        ModuleRibKind(..) => {
+                        ModuleRibKind(..) | MacroDefinition(..) => {
                             // Nothing to do. Continue.
                         }
                         ItemRibKind => {
@@ -2747,7 +2790,7 @@ fn find_best_match(&mut self, name: &str) -> SuggestionType {
         let names = self.value_ribs
                     .iter()
                     .rev()
-                    .flat_map(|rib| rib.bindings.keys());
+                    .flat_map(|rib| rib.bindings.keys().map(|ident| &ident.name));
 
         if let Some(found) = find_best_match_for_name(names, name, None) {
             if name != found {
@@ -2758,7 +2801,7 @@ fn find_best_match(&mut self, name: &str) -> SuggestionType {
 
     fn resolve_labeled_block(&mut self, label: Option<ast::Ident>, id: NodeId, block: &Block) {
         if let Some(label) = label {
-            let (label, def) = (mtwt::resolve(label), Def::Label(id));
+            let def = Def::Label(id);
             self.with_label_rib(|this| {
                 this.label_ribs.last_mut().unwrap().bindings.insert(label, def);
                 this.visit_block(block);
@@ -2965,7 +3008,7 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
 
                     {
                         let rib = this.label_ribs.last_mut().unwrap();
-                        rib.bindings.insert(mtwt::resolve(label.node), def);
+                        rib.bindings.insert(label.node, def);
                     }
 
                     visit::walk_expr(this, expr);
@@ -2973,7 +3016,7 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
             }
 
             ExprKind::Break(Some(label)) | ExprKind::Continue(Some(label)) => {
-                match self.search_label(mtwt::resolve(label.node)) {
+                match self.search_label(label.node) {
                     None => {
                         self.record_def(expr.id, err_path_resolution());
                         resolve_error(self,
index 99e37ec80c0817802e2abeb08b4bfbef9583308b..6b662c6779a4bd118e2dcffbe9c81b47a91c92b6 100644 (file)
@@ -26,7 +26,6 @@
 
 use std::fmt;
 use std::rc::Rc;
-use std::hash::{Hash, Hasher};
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 
 /// A name is a part of an identifier, representing a string or gensym. It's
@@ -46,7 +45,7 @@
 /// An identifier contains a Name (index into the interner
 /// table) and a SyntaxContext to track renaming and
 /// macro expansion per Flatt et al., "Macros That Work Together"
-#[derive(Clone, Copy, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Ident {
     pub name: Name,
     pub ctxt: SyntaxContext
@@ -93,40 +92,6 @@ pub const fn with_empty_ctxt(name: Name) -> Ident {
     }
 }
 
-impl PartialEq for Ident {
-    fn eq(&self, other: &Ident) -> bool {
-        if self.ctxt != other.ctxt {
-            // There's no one true way to compare Idents. They can be compared
-            // non-hygienically `id1.name == id2.name`, hygienically
-            // `mtwt::resolve(id1) == mtwt::resolve(id2)`, or even member-wise
-            // `(id1.name, id1.ctxt) == (id2.name, id2.ctxt)` depending on the situation.
-            // Ideally, PartialEq should not be implemented for Ident at all, but that
-            // would be too impractical, because many larger structures (Token, in particular)
-            // including Idents as their parts derive PartialEq and use it for non-hygienic
-            // comparisons. That's why PartialEq is implemented and defaults to non-hygienic
-            // comparison. Hash is implemented too and is consistent with PartialEq, i.e. only
-            // the name of Ident is hashed. Still try to avoid comparing idents in your code
-            // (especially as keys in hash maps), use one of the three methods listed above
-            // explicitly.
-            //
-            // If you see this panic, then some idents from different contexts were compared
-            // non-hygienically. It's likely a bug. Use one of the three comparison methods
-            // listed above explicitly.
-
-            panic!("idents with different contexts are compared with operator `==`: \
-                {:?}, {:?}.", self, other);
-        }
-
-        self.name == other.name
-    }
-}
-
-impl Hash for Ident {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.name.hash(state)
-    }
-}
-
 impl fmt::Debug for Ident {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}#{}", self.name, self.ctxt.0)
index 92670cd9def9015cc14d76809f3ba0f93e560046..7ebcd12cdb9512853b9122c49079f8690a381e65 100644 (file)
@@ -26,7 +26,6 @@
 use ptr::P;
 use util::small_vector::SmallVector;
 use util::lev_distance::find_best_match_for_name;
-use ext::mtwt;
 use fold::Folder;
 
 use std::collections::{HashMap, HashSet};
@@ -483,15 +482,12 @@ pub enum SyntaxExtension {
 pub struct BlockInfo {
     /// Should macros escape from this scope?
     pub macros_escape: bool,
-    /// What are the pending renames?
-    pub pending_renames: mtwt::RenameList,
 }
 
 impl BlockInfo {
     pub fn new() -> BlockInfo {
         BlockInfo {
             macros_escape: false,
-            pending_renames: Vec::new(),
         }
     }
 }
index 220e0a753c30b5b1e7f2c53e1adbc775590274df..3e9837a6995c3f06ba9791404a010603a49ec61d 100644 (file)
@@ -8,23 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{Block, Crate, PatKind};
-use ast::{Local, Ident, Mac_, Name, SpannedIdent};
+use ast::{Block, Crate, Ident, Mac_, Name, PatKind};
 use ast::{MacStmtStyle, Mrk, Stmt, StmtKind, ItemKind};
 use ast;
 use attr::HasAttrs;
 use ext::mtwt;
 use attr;
 use attr::AttrMetaMethods;
-use codemap::{Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
+use codemap::{dummy_spanned, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
 use config::StripUnconfigured;
 use ext::base::*;
 use feature_gate::{self, Features};
 use fold;
 use fold::*;
-use util::move_map::MoveMap;
-use parse::token::{fresh_mark, fresh_name, intern, keywords};
+use parse::token::{fresh_mark, intern, keywords};
 use ptr::P;
 use tokenstream::TokenTree;
 use util::small_vector::SmallVector;
@@ -96,89 +94,32 @@ fn visit_with<V: Visitor>(&self, visitor: &mut V) {
     }
 }
 
-pub fn expand_expr(mut expr: ast::Expr, fld: &mut MacroExpander) -> P<ast::Expr> {
+pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P<ast::Expr> {
     match expr.node {
         // expr_mac should really be expr_ext or something; it's the
         // entry-point for all syntax extensions.
         ast::ExprKind::Mac(mac) => {
             return expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, fld);
         }
+        _ => P(noop_fold_expr(expr, fld)),
+    }
+}
 
-        ast::ExprKind::While(cond, body, opt_ident) => {
-            let cond = fld.fold_expr(cond);
-            let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
-            expr.node = ast::ExprKind::While(cond, body, opt_ident);
-        }
-
-        ast::ExprKind::WhileLet(pat, cond, body, opt_ident) => {
-            let pat = fld.fold_pat(pat);
-            let cond = fld.fold_expr(cond);
-
-            // Hygienic renaming of the body.
-            let ((body, opt_ident), mut rewritten_pats) =
-                rename_in_scope(vec![pat],
-                                fld,
-                                (body, opt_ident),
-                                |rename_fld, fld, (body, opt_ident)| {
-                expand_loop_block(rename_fld.fold_block(body), opt_ident, fld)
-            });
-            assert!(rewritten_pats.len() == 1);
-
-            expr.node = ast::ExprKind::WhileLet(rewritten_pats.remove(0), cond, body, opt_ident);
-        }
-
-        ast::ExprKind::Loop(loop_block, opt_ident) => {
-            let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
-            expr.node = ast::ExprKind::Loop(loop_block, opt_ident);
-        }
-
-        ast::ExprKind::ForLoop(pat, head, body, opt_ident) => {
-            let pat = fld.fold_pat(pat);
-
-            // Hygienic renaming of the for loop body (for loop binds its pattern).
-            let ((body, opt_ident), mut rewritten_pats) =
-                rename_in_scope(vec![pat],
-                                fld,
-                                (body, opt_ident),
-                                |rename_fld, fld, (body, opt_ident)| {
-                expand_loop_block(rename_fld.fold_block(body), opt_ident, fld)
-            });
-            assert!(rewritten_pats.len() == 1);
-
-            let head = fld.fold_expr(head);
-            expr.node = ast::ExprKind::ForLoop(rewritten_pats.remove(0), head, body, opt_ident);
-        }
-
-        ast::ExprKind::IfLet(pat, sub_expr, body, else_opt) => {
-            let pat = fld.fold_pat(pat);
-
-            // Hygienic renaming of the body.
-            let (body, mut rewritten_pats) =
-                rename_in_scope(vec![pat],
-                                fld,
-                                body,
-                                |rename_fld, fld, body| {
-                fld.fold_block(rename_fld.fold_block(body))
-            });
-            assert!(rewritten_pats.len() == 1);
-
-            let else_opt = else_opt.map(|else_opt| fld.fold_expr(else_opt));
-            let sub_expr = fld.fold_expr(sub_expr);
-            expr.node = ast::ExprKind::IfLet(rewritten_pats.remove(0), sub_expr, body, else_opt);
-        }
-
-        ast::ExprKind::Closure(capture_clause, fn_decl, block, fn_decl_span) => {
-            let (rewritten_fn_decl, rewritten_block)
-                = expand_and_rename_fn_decl_and_block(fn_decl, block, fld);
-            expr.node = ast::ExprKind::Closure(capture_clause,
-                                               rewritten_fn_decl,
-                                               rewritten_block,
-                                               fn_decl_span);
-        }
-
-        _ => expr = noop_fold_expr(expr, fld),
-    };
-    P(expr)
+struct MacroScopePlaceholder;
+impl MacResult for MacroScopePlaceholder {
+    fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
+        Some(SmallVector::one(P(ast::Item {
+            ident: keywords::Invalid.ident(),
+            attrs: Vec::new(),
+            id: ast::DUMMY_NODE_ID,
+            node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
+                path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
+                tts: Vec::new(),
+            })),
+            vis: ast::Visibility::Inherited,
+            span: syntax_pos::DUMMY_SP,
+        })))
+    }
 }
 
 /// Expand a macro invocation. Returns the result of expansion.
@@ -219,6 +160,7 @@ fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, m
         };
 
         let ident = ident.unwrap_or(keywords::Invalid.ident());
+        let marked_tts = mark_tts(&tts, mark);
         match *extension {
             NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
                 if ident.name != keywords::Invalid.name() {
@@ -237,7 +179,6 @@ fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, m
                     },
                 });
 
-                let marked_tts = mark_tts(&tts, mark);
                 Some(expandfun.expand(fld.cx, call_site, &marked_tts))
             }
 
@@ -257,7 +198,6 @@ fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, m
                     }
                 });
 
-                let marked_tts = mark_tts(&tts, mark);
                 Some(expander.expand(fld.cx, call_site, ident, marked_tts))
             }
 
@@ -286,15 +226,14 @@ fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, m
                     span: call_site,
                     imported_from: None,
                     use_locally: true,
-                    body: tts,
+                    body: marked_tts,
                     export: attr::contains_name(&attrs, "macro_export"),
                     allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
                     attrs: attrs,
                 });
 
                 // macro_rules! has a side effect but expands to nothing.
-                fld.cx.bt_pop();
-                None
+                Some(Box::new(MacroScopePlaceholder))
             }
 
             MultiDecorator(..) | MultiModifier(..) => {
@@ -327,41 +266,6 @@ fn mac_result<'a>(path: &ast::Path, ident: Option<Ident>, tts: Vec<TokenTree>, m
     fully_expanded
 }
 
-/// Rename loop label and expand its loop body
-///
-/// The renaming procedure for loop is different in the sense that the loop
-/// body is in a block enclosed by loop head so the renaming of loop label
-/// must be propagated to the enclosed context.
-fn expand_loop_block(loop_block: P<Block>,
-                     opt_ident: Option<SpannedIdent>,
-                     fld: &mut MacroExpander) -> (P<Block>, Option<SpannedIdent>) {
-    match opt_ident {
-        Some(label) => {
-            let new_label = fresh_name(label.node);
-            let rename = (label.node, new_label);
-
-            // The rename *must not* be added to the pending list of current
-            // syntax context otherwise an unrelated `break` or `continue` in
-            // the same context will pick that up in the deferred renaming pass
-            // and be renamed incorrectly.
-            let mut rename_list = vec!(rename);
-            let mut rename_fld = IdentRenamer{renames: &mut rename_list};
-            let renamed_ident = rename_fld.fold_ident(label.node);
-
-            // The rename *must* be added to the enclosed syntax context for
-            // `break` or `continue` to pick up because by definition they are
-            // in a block enclosed by loop head.
-            fld.cx.syntax_env.push_frame();
-            fld.cx.syntax_env.info().pending_renames.push(rename);
-            let expanded_block = expand_block_elts(loop_block, fld);
-            fld.cx.syntax_env.pop_frame();
-
-            (expanded_block, Some(Spanned { node: renamed_ident, span: label.span }))
-        }
-        None => (fld.fold_block(loop_block), opt_ident)
-    }
-}
-
 // eval $e with a new exts frame.
 // must be a macro so that $e isn't evaluated too early.
 macro_rules! with_exts_frame {
@@ -381,20 +285,6 @@ pub fn expand_item(it: P<ast::Item>, fld: &mut MacroExpander)
         .into_iter().map(|i| i.expect_item()).collect()
 }
 
-/// Expand item_kind
-fn expand_item_kind(item: ast::ItemKind, fld: &mut MacroExpander) -> ast::ItemKind {
-    match item {
-        ast::ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => {
-            let (rewritten_fn_decl, rewritten_body)
-                = expand_and_rename_fn_decl_and_block(decl, body, fld);
-            let expanded_generics = fold::noop_fold_generics(generics,fld);
-            ast::ItemKind::Fn(rewritten_fn_decl, unsafety, constness, abi,
-                        expanded_generics, rewritten_body)
-        }
-        _ => noop_fold_item_kind(item, fld)
-    }
-}
-
 // does this attribute list contain "macro_use" ?
 fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
     for attr in attrs {
@@ -425,16 +315,9 @@ fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool
 
 /// Expand a stmt
 fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
-    // perform all pending renames
-    let stmt = {
-        let pending_renames = &mut fld.cx.syntax_env.info().pending_renames;
-        let mut rename_fld = IdentRenamer{renames:pending_renames};
-        rename_fld.fold_stmt(stmt).expect_one("rename_fold didn't return one value")
-    };
-
     let (mac, style, attrs) = match stmt.node {
         StmtKind::Mac(mac) => mac.unwrap(),
-        _ => return expand_non_macro_stmt(stmt, fld)
+        _ => return noop_fold_stmt(stmt, fld)
     };
 
     let mut fully_expanded: SmallVector<ast::Stmt> =
@@ -451,167 +334,6 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
     fully_expanded
 }
 
-// expand a non-macro stmt. this is essentially the fallthrough for
-// expand_stmt, above.
-fn expand_non_macro_stmt(stmt: Stmt, fld: &mut MacroExpander)
-                         -> SmallVector<Stmt> {
-    // is it a let?
-    match stmt.node {
-        StmtKind::Local(local) => {
-            // take it apart:
-            let rewritten_local = local.map(|Local {id, pat, ty, init, span, attrs}| {
-                // expand the ty since TyKind::FixedLengthVec contains an Expr
-                // and thus may have a macro use
-                let expanded_ty = ty.map(|t| fld.fold_ty(t));
-                // expand the pat (it might contain macro uses):
-                let expanded_pat = fld.fold_pat(pat);
-                // find the PatIdents in the pattern:
-                // oh dear heaven... this is going to include the enum
-                // names, as well... but that should be okay, as long as
-                // the new names are gensyms for the old ones.
-                // generate fresh names, push them to a new pending list
-                let idents = pattern_bindings(&expanded_pat);
-                let mut new_pending_renames =
-                    idents.iter().map(|ident| (*ident, fresh_name(*ident))).collect();
-                // rewrite the pattern using the new names (the old
-                // ones have already been applied):
-                let rewritten_pat = {
-                    // nested binding to allow borrow to expire:
-                    let mut rename_fld = IdentRenamer{renames: &mut new_pending_renames};
-                    rename_fld.fold_pat(expanded_pat)
-                };
-                // add them to the existing pending renames:
-                fld.cx.syntax_env.info().pending_renames
-                      .extend(new_pending_renames);
-                Local {
-                    id: id,
-                    ty: expanded_ty,
-                    pat: rewritten_pat,
-                    // also, don't forget to expand the init:
-                    init: init.map(|e| fld.fold_expr(e)),
-                    span: span,
-                    attrs: fold::fold_thin_attrs(attrs, fld),
-                }
-            });
-            SmallVector::one(Stmt {
-                id: stmt.id,
-                node: StmtKind::Local(rewritten_local),
-                span: stmt.span,
-            })
-        }
-        _ => noop_fold_stmt(stmt, fld),
-    }
-}
-
-// expand the arm of a 'match', renaming for macro hygiene
-fn expand_arm(arm: ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
-    // expand pats... they might contain macro uses:
-    let expanded_pats = arm.pats.move_map(|pat| fld.fold_pat(pat));
-    if expanded_pats.is_empty() {
-        panic!("encountered match arm with 0 patterns");
-    }
-
-    // apply renaming and then expansion to the guard and the body:
-    let ((rewritten_guard, rewritten_body), rewritten_pats) =
-        rename_in_scope(expanded_pats,
-                        fld,
-                        (arm.guard, arm.body),
-                        |rename_fld, fld, (ag, ab)|{
-        let rewritten_guard = ag.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
-        let rewritten_body = fld.fold_expr(rename_fld.fold_expr(ab));
-        (rewritten_guard, rewritten_body)
-    });
-
-    ast::Arm {
-        attrs: fold::fold_attrs(arm.attrs, fld),
-        pats: rewritten_pats,
-        guard: rewritten_guard,
-        body: rewritten_body,
-    }
-}
-
-fn rename_in_scope<X, F>(pats: Vec<P<ast::Pat>>,
-                         fld: &mut MacroExpander,
-                         x: X,
-                         f: F)
-                         -> (X, Vec<P<ast::Pat>>)
-    where F: Fn(&mut IdentRenamer, &mut MacroExpander, X) -> X
-{
-    // all of the pats must have the same set of bindings, so use the
-    // first one to extract them and generate new names:
-    let idents = pattern_bindings(&pats[0]);
-    let new_renames = idents.into_iter().map(|id| (id, fresh_name(id))).collect();
-    // apply the renaming, but only to the PatIdents:
-    let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames};
-    let rewritten_pats = pats.move_map(|pat| rename_pats_fld.fold_pat(pat));
-
-    let mut rename_fld = IdentRenamer{ renames:&new_renames };
-    (f(&mut rename_fld, fld, x), rewritten_pats)
-}
-
-/// A visitor that extracts the PatKind::Ident (binding) paths
-/// from a given thingy and puts them in a mutable
-/// array
-#[derive(Clone)]
-struct PatIdentFinder {
-    ident_accumulator: Vec<ast::Ident>
-}
-
-impl Visitor for PatIdentFinder {
-    fn visit_pat(&mut self, pattern: &ast::Pat) {
-        match *pattern {
-            ast::Pat { id: _, node: PatKind::Ident(_, ref path1, ref inner), span: _ } => {
-                self.ident_accumulator.push(path1.node);
-                // visit optional subpattern of PatKind::Ident:
-                if let Some(ref subpat) = *inner {
-                    self.visit_pat(subpat)
-                }
-            }
-            // use the default traversal for non-PatIdents
-            _ => visit::walk_pat(self, pattern)
-        }
-    }
-}
-
-/// find the PatKind::Ident paths in a pattern
-fn pattern_bindings(pat: &ast::Pat) -> Vec<ast::Ident> {
-    let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
-    name_finder.visit_pat(pat);
-    name_finder.ident_accumulator
-}
-
-/// find the PatKind::Ident paths in a
-fn fn_decl_arg_bindings(fn_decl: &ast::FnDecl) -> Vec<ast::Ident> {
-    let mut pat_idents = PatIdentFinder{ident_accumulator:Vec::new()};
-    for arg in &fn_decl.inputs {
-        pat_idents.visit_pat(&arg.pat);
-    }
-    pat_idents.ident_accumulator
-}
-
-// expand a block. pushes a new exts_frame, then calls expand_block_elts
-pub fn expand_block(blk: P<Block>, fld: &mut MacroExpander) -> P<Block> {
-    // see note below about treatment of exts table
-    with_exts_frame!(fld.cx.syntax_env,false,
-                     expand_block_elts(blk, fld))
-}
-
-// expand the elements of a block.
-pub fn expand_block_elts(b: P<Block>, fld: &mut MacroExpander) -> P<Block> {
-    b.map(|Block {id, stmts, rules, span}| {
-        let new_stmts = stmts.into_iter().flat_map(|x| {
-            // perform pending renames and expand macros in the statement
-            fld.fold_stmt(x).into_iter()
-        }).collect();
-        Block {
-            id: fld.new_id(id),
-            stmts: new_stmts,
-            rules: rules,
-            span: span
-        }
-    })
-}
-
 fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
     match p.node {
         PatKind::Mac(_) => {}
@@ -625,62 +347,16 @@ fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
     })
 }
 
-/// A tree-folder that applies every rename in its (mutable) list
-/// to every identifier, including both bindings and varrefs
-/// (and lots of things that will turn out to be neither)
-pub struct IdentRenamer<'a> {
-    renames: &'a mtwt::RenameList,
-}
-
-impl<'a> Folder for IdentRenamer<'a> {
-    fn fold_ident(&mut self, id: Ident) -> Ident {
-        mtwt::apply_renames(self.renames, id)
-    }
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-        fold::noop_fold_mac(mac, self)
-    }
-}
-
-/// A tree-folder that applies every rename in its list to
-/// the idents that are in PatKind::Ident patterns. This is more narrowly
-/// focused than IdentRenamer, and is needed for FnDecl,
-/// where we want to rename the args but not the fn name or the generics etc.
-pub struct PatIdentRenamer<'a> {
-    renames: &'a mtwt::RenameList,
-}
-
-impl<'a> Folder for PatIdentRenamer<'a> {
-    fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
-        match pat.node {
-            PatKind::Ident(..) => {},
-            _ => return noop_fold_pat(pat, self)
-        }
-
-        pat.map(|ast::Pat {id, node, span}| match node {
-            PatKind::Ident(binding_mode, Spanned{span: sp, node: ident}, sub) => {
-                let new_ident = mtwt::apply_renames(self.renames, ident);
-                let new_node =
-                    PatKind::Ident(binding_mode,
-                                  Spanned{span: sp, node: new_ident},
-                                  sub.map(|p| self.fold_pat(p)));
-                ast::Pat {
-                    id: id,
-                    node: new_node,
-                    span: span,
-                }
-            },
-            _ => unreachable!()
-        })
-    }
-    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
-        fold::noop_fold_mac(mac, self)
-    }
-}
-
 fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector<Annotatable> {
     match a {
         Annotatable::Item(it) => match it.node {
             ast::ItemKind::Mac(..) => {
+                if match it.node {
+                    ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
+                    _ => unreachable!(),
+                } {
+                    return SmallVector::one(Annotatable::Item(it));
+                }
                 it.and_then(|it| match it.node {
                     ItemKind::Mac(mac) =>
                         expand_mac_invoc(mac, Some(it.ident), it.attrs, it.span, fld),
@@ -774,21 +450,6 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVe
 fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
                  -> SmallVector<ast::ImplItem> {
     match ii.node {
-        ast::ImplItemKind::Method(..) => SmallVector::one(ast::ImplItem {
-            id: ii.id,
-            ident: ii.ident,
-            attrs: ii.attrs,
-            vis: ii.vis,
-            defaultness: ii.defaultness,
-            node: match ii.node {
-                ast::ImplItemKind::Method(sig, body) => {
-                    let (sig, body) = expand_and_rename_method(sig, body, fld);
-                    ast::ImplItemKind::Method(sig, body)
-                }
-                _ => unreachable!()
-            },
-            span: ii.span,
-        }),
         ast::ImplItemKind::Macro(mac) => {
             expand_mac_invoc(mac, None, ii.attrs, ii.span, fld)
         }
@@ -799,21 +460,6 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
 fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
                      -> SmallVector<ast::TraitItem> {
     match ti.node {
-        ast::TraitItemKind::Method(_, Some(_)) => {
-            SmallVector::one(ast::TraitItem {
-                id: ti.id,
-                ident: ti.ident,
-                attrs: ti.attrs,
-                node: match ti.node  {
-                    ast::TraitItemKind::Method(sig, Some(body)) => {
-                        let (sig, body) = expand_and_rename_method(sig, body, fld);
-                        ast::TraitItemKind::Method(sig, Some(body))
-                    }
-                    _ => unreachable!()
-                },
-                span: ti.span,
-            })
-        }
         ast::TraitItemKind::Macro(mac) => {
             expand_mac_invoc(mac, None, ti.attrs, ti.span, fld)
         }
@@ -821,39 +467,6 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
     }
 }
 
-/// Given a fn_decl and a block and a MacroExpander, expand the fn_decl, then use the
-/// PatIdents in its arguments to perform renaming in the FnDecl and
-/// the block, returning both the new FnDecl and the new Block.
-fn expand_and_rename_fn_decl_and_block(fn_decl: P<ast::FnDecl>, block: P<ast::Block>,
-                                       fld: &mut MacroExpander)
-                                       -> (P<ast::FnDecl>, P<ast::Block>) {
-    let expanded_decl = fld.fold_fn_decl(fn_decl);
-    let idents = fn_decl_arg_bindings(&expanded_decl);
-    let renames =
-        idents.iter().map(|id| (*id,fresh_name(*id))).collect();
-    // first, a renamer for the PatIdents, for the fn_decl:
-    let mut rename_pat_fld = PatIdentRenamer{renames: &renames};
-    let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(expanded_decl);
-    // now, a renamer for *all* idents, for the body:
-    let mut rename_fld = IdentRenamer{renames: &renames};
-    let rewritten_body = fld.fold_block(rename_fld.fold_block(block));
-    (rewritten_fn_decl,rewritten_body)
-}
-
-fn expand_and_rename_method(sig: ast::MethodSig, body: P<ast::Block>,
-                            fld: &mut MacroExpander)
-                            -> (ast::MethodSig, P<ast::Block>) {
-    let (rewritten_fn_decl, rewritten_body)
-        = expand_and_rename_fn_decl_and_block(sig.decl, body, fld);
-    (ast::MethodSig {
-        generics: fld.fold_generics(sig.generics),
-        abi: sig.abi,
-        unsafety: sig.unsafety,
-        constness: sig.constness,
-        decl: rewritten_fn_decl
-    }, rewritten_body)
-}
-
 pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
     let t = match t.node.clone() {
         ast::TyKind::Mac(mac) => {
@@ -976,25 +589,17 @@ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
         result
     }
 
-    fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
-        expand_item_kind(item, self)
-    }
-
     fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
         expand_stmt(stmt, self)
     }
 
     fn fold_block(&mut self, block: P<Block>) -> P<Block> {
         let was_in_block = ::std::mem::replace(&mut self.cx.in_block, true);
-        let result = expand_block(block, self);
+        let result = with_exts_frame!(self.cx.syntax_env, false, noop_fold_block(block, self));
         self.cx.in_block = was_in_block;
         result
     }
 
-    fn fold_arm(&mut self, arm: ast::Arm) -> ast::Arm {
-        expand_arm(arm, self)
-    }
-
     fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> {
         expand_annotatable(Annotatable::TraitItem(P(i)), self)
             .into_iter().map(|i| i.expect_trait_item()).collect()
@@ -1145,18 +750,11 @@ fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
 
 #[cfg(test)]
 mod tests {
-    use super::{pattern_bindings, expand_crate};
-    use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
+    use super::{expand_crate, ExpansionConfig};
     use ast;
-    use ast::Name;
-    use syntax_pos;
     use ext::base::{ExtCtxt, DummyMacroLoader};
-    use ext::mtwt;
-    use fold::Folder;
     use parse;
-    use parse::token;
     use util::parser_testing::{string_to_parser};
-    use util::parser_testing::{string_to_pat, string_to_crate, strs_to_idents};
     use visit;
     use visit::Visitor;
 
@@ -1177,32 +775,6 @@ fn visit_expr(&mut self, expr: &ast::Expr) {
         }
     }
 
-    // find the variable references in a crate
-    fn crate_varrefs(the_crate : &ast::Crate) -> Vec<ast::Path> {
-        let mut path_finder = PathExprFinderContext{path_accumulator:Vec::new()};
-        visit::walk_crate(&mut path_finder, the_crate);
-        path_finder.path_accumulator
-    }
-
-    /// A Visitor that extracts the identifiers from a thingy.
-    // as a side note, I'm starting to want to abstract over these....
-    struct IdentFinder {
-        ident_accumulator: Vec<ast::Ident>
-    }
-
-    impl Visitor for IdentFinder {
-        fn visit_ident(&mut self, _: syntax_pos::Span, id: ast::Ident){
-            self.ident_accumulator.push(id);
-        }
-    }
-
-    /// Find the idents in a crate
-    fn crate_idents(the_crate: &ast::Crate) -> Vec<ast::Ident> {
-        let mut ident_finder = IdentFinder{ident_accumulator: Vec::new()};
-        visit::walk_crate(&mut ident_finder, the_crate);
-        ident_finder.ident_accumulator
-    }
-
     // these following tests are quite fragile, in that they don't test what
     // *kind* of failure occurs.
 
@@ -1264,13 +836,6 @@ fn expand_crate_str(crate_str: String) -> ast::Crate {
         expand_crate(ecx, vec![], crate_ast).0
     }
 
-    // find the pat_ident paths in a crate
-    fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
-        let mut name_finder = PatIdentFinder{ident_accumulator:Vec::new()};
-        visit::walk_crate(&mut name_finder, the_crate);
-        name_finder.ident_accumulator
-    }
-
     #[test] fn macro_tokens_should_match(){
         expand_crate_str(
             "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string());
@@ -1287,93 +852,4 @@ fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
     // create a really evil test case where a $x appears inside a binding of $x
     // but *shouldn't* bind because it was inserted by a different macro....
     // can't write this test case until we have macro-generating macros.
-
-    #[test]
-    fn fmt_in_macro_used_inside_module_macro() {
-        let crate_str = "macro_rules! fmt_wrap(($b:expr)=>($b.to_string()));
-macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}}));
-foo_module!();
-".to_string();
-        let cr = expand_crate_str(crate_str);
-        // find the xx binding
-        let bindings = crate_bindings(&cr);
-        let cxbinds: Vec<&ast::Ident> =
-            bindings.iter().filter(|b| b.name.as_str() == "xx").collect();
-        let cxbinds: &[&ast::Ident] = &cxbinds[..];
-        let cxbind = match (cxbinds.len(), cxbinds.get(0)) {
-            (1, Some(b)) => *b,
-            _ => panic!("expected just one binding for ext_cx")
-        };
-        let resolved_binding = mtwt::resolve(*cxbind);
-        let varrefs = crate_varrefs(&cr);
-
-        // the xx binding should bind all of the xx varrefs:
-        for (idx,v) in varrefs.iter().filter(|p| {
-            p.segments.len() == 1
-            && p.segments[0].identifier.name.as_str() == "xx"
-        }).enumerate() {
-            if mtwt::resolve(v.segments[0].identifier) != resolved_binding {
-                println!("uh oh, xx binding didn't match xx varref:");
-                println!("this is xx varref \\# {}", idx);
-                println!("binding: {}", cxbind);
-                println!("resolves to: {}", resolved_binding);
-                println!("varref: {}", v.segments[0].identifier);
-                println!("resolves to: {}",
-                         mtwt::resolve(v.segments[0].identifier));
-                mtwt::with_sctable(|x| mtwt::display_sctable(x));
-            }
-            assert_eq!(mtwt::resolve(v.segments[0].identifier),
-                       resolved_binding);
-        };
-    }
-
-    #[test]
-    fn pat_idents(){
-        let pat = string_to_pat(
-            "(a,Foo{x:c @ (b,9),y:Bar(4,d)})".to_string());
-        let idents = pattern_bindings(&pat);
-        assert_eq!(idents, strs_to_idents(vec!("a","c","b","d")));
-    }
-
-    // test the list of identifier patterns gathered by the visitor. Note that
-    // 'None' is listed as an identifier pattern because we don't yet know that
-    // it's the name of a 0-ary variant, and that 'i' appears twice in succession.
-    #[test]
-    fn crate_bindings_test(){
-        let the_crate = string_to_crate("fn main (a: i32) -> i32 {|b| {
-        match 34 {None => 3, Some(i) | i => j, Foo{k:z,l:y} => \"banana\"}} }".to_string());
-        let idents = crate_bindings(&the_crate);
-        assert_eq!(idents, strs_to_idents(vec!("a","b","None","i","i","z","y")));
-    }
-
-    // test the IdentRenamer directly
-    #[test]
-    fn ident_renamer_test () {
-        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
-        let f_ident = token::str_to_ident("f");
-        let x_ident = token::str_to_ident("x");
-        let int_ident = token::str_to_ident("i32");
-        let renames = vec!((x_ident,Name(16)));
-        let mut renamer = IdentRenamer{renames: &renames};
-        let renamed_crate = renamer.fold_crate(the_crate);
-        let idents = crate_idents(&renamed_crate);
-        let resolved : Vec<ast::Name> = idents.iter().map(|id| mtwt::resolve(*id)).collect();
-        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),Name(16),Name(16)]);
-    }
-
-    // test the PatIdentRenamer; only PatIdents get renamed
-    #[test]
-    fn pat_ident_renamer_test () {
-        let the_crate = string_to_crate("fn f(x: i32){let x = x; x}".to_string());
-        let f_ident = token::str_to_ident("f");
-        let x_ident = token::str_to_ident("x");
-        let int_ident = token::str_to_ident("i32");
-        let renames = vec!((x_ident,Name(16)));
-        let mut renamer = PatIdentRenamer{renames: &renames};
-        let renamed_crate = renamer.fold_crate(the_crate);
-        let idents = crate_idents(&renamed_crate);
-        let resolved : Vec<ast::Name> = idents.iter().map(|id| mtwt::resolve(*id)).collect();
-        let x_name = x_ident.name;
-        assert_eq!(resolved, [f_ident.name,Name(16),int_ident.name,Name(16),x_name,x_name]);
-    }
 }
index c9e8715dda6a8a288ae2cebb61284268dca6f507..d2f6df9d5dbd3f1936609ee2b613a257c70fe5eb 100644 (file)
@@ -17,7 +17,7 @@
 
 pub use self::SyntaxContext_::*;
 
-use ast::{Ident, Mrk, Name, SyntaxContext};
+use ast::{Ident, Mrk, SyntaxContext};
 
 use std::cell::RefCell;
 use std::collections::HashMap;
 /// The SCTable contains a table of SyntaxContext_'s. It
 /// represents a flattened tree structure, to avoid having
 /// managed pointers everywhere (that caused an ICE).
-/// the `marks` and `renames` fields are side-tables
-/// that ensure that adding the same mark to the same context
-/// gives you back the same context as before. This should cut
-/// down on memory use *a lot*; applying a mark to a tree containing
-/// 50 identifiers would otherwise generate 50 new contexts.
+/// The `marks` ensures that adding the same mark to the
+/// same context gives you back the same context as before.
 pub struct SCTable {
     table: RefCell<Vec<SyntaxContext_>>,
     marks: RefCell<HashMap<(SyntaxContext,Mrk),SyntaxContext>>,
-    renames: RefCell<HashMap<Name,SyntaxContext>>,
 }
 
 #[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy, Clone)]
 pub enum SyntaxContext_ {
     EmptyCtxt,
     Mark (Mrk,SyntaxContext),
-    Rename (Name),
-    /// actually, IllegalCtxt may not be necessary.
-    IllegalCtxt
 }
 
-/// A list of ident->name renamings
-pub type RenameList = Vec<(Ident, Name)>;
-
 /// Extend a syntax context with a given mark
 pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext {
     with_sctable(|table| apply_mark_internal(m, ctxt, table))
@@ -65,32 +55,6 @@ fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxCo
     }
 }
 
-/// Extend a syntax context with a given rename
-pub fn apply_rename(from: Ident, to: Name, ident: Ident) -> Ident {
-    with_sctable(|table| apply_rename_internal(from, to, ident, table))
-}
-
-/// Extend a syntax context with a given rename and sctable (explicit memoization)
-fn apply_rename_internal(from: Ident, to: Name, ident: Ident, table: &SCTable) -> Ident {
-    if (ident.name, ident.ctxt) != (from.name, from.ctxt) {
-        return ident;
-    }
-    let ctxt = *table.renames.borrow_mut().entry(to).or_insert_with(|| {
-        SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Rename(to)))
-    });
-    Ident { ctxt: ctxt, ..ident }
-}
-
-/// Apply a list of renamings to a context
-// if these rename lists get long, it would make sense
-// to consider memoizing this fold. This may come up
-// when we add hygiene to item names.
-pub fn apply_renames(renames: &RenameList, ident: Ident) -> Ident {
-    renames.iter().fold(ident, |ident, &(from, to)| {
-        apply_rename(from, to, ident)
-    })
-}
-
 /// Fetch the SCTable from TLS, create one if it doesn't yet exist.
 pub fn with_sctable<T, F>(op: F) -> T where
     F: FnOnce(&SCTable) -> T,
@@ -99,21 +63,11 @@ pub fn with_sctable<T, F>(op: F) -> T where
     SCTABLE_KEY.with(move |slot| op(slot))
 }
 
-// Make a fresh syntax context table with EmptyCtxt in slot zero
-// and IllegalCtxt in slot one.
+// Make a fresh syntax context table with EmptyCtxt in slot zero.
 fn new_sctable_internal() -> SCTable {
     SCTable {
-        table: RefCell::new(vec!(EmptyCtxt, IllegalCtxt)),
+        table: RefCell::new(vec![EmptyCtxt]),
         marks: RefCell::new(HashMap::new()),
-        renames: RefCell::new(HashMap::new()),
-    }
-}
-
-/// Print out an SCTable for debugging
-pub fn display_sctable(table: &SCTable) {
-    error!("SC table:");
-    for (idx,val) in table.table.borrow().iter().enumerate() {
-        error!("{:4} : {:?}",idx,val);
     }
 }
 
@@ -122,16 +76,14 @@ pub fn clear_tables() {
     with_sctable(|table| {
         *table.table.borrow_mut() = Vec::new();
         *table.marks.borrow_mut() = HashMap::new();
-        *table.renames.borrow_mut() = HashMap::new();
     });
 }
 
 /// Reset the tables to their initial state
 pub fn reset_tables() {
     with_sctable(|table| {
-        *table.table.borrow_mut() = vec!(EmptyCtxt, IllegalCtxt);
+        *table.table.borrow_mut() = vec![EmptyCtxt];
         *table.marks.borrow_mut() = HashMap::new();
-        *table.renames.borrow_mut() = HashMap::new();
     });
 }
 
@@ -141,25 +93,6 @@ fn idx_push<T>(vec: &mut Vec<T>, val: T) -> u32 {
     (vec.len() - 1) as u32
 }
 
-/// Resolve a syntax object to a name, per MTWT.
-pub fn resolve(id: Ident) -> Name {
-    with_sctable(|sctable| {
-        resolve_internal(id, sctable)
-    })
-}
-
-/// Resolve a syntax object to a name, per MTWT.
-/// adding memoization to resolve 500+ seconds in resolve for librustc (!)
-fn resolve_internal(id: Ident, table: &SCTable) -> Name {
-    match table.table.borrow()[id.ctxt.0 as usize] {
-        EmptyCtxt => id.name,
-        // ignore marks here:
-        Mark(_, subctxt) => resolve_internal(Ident::new(id.name, subctxt), table),
-        Rename(name) => name,
-        IllegalCtxt => panic!("expected resolvable context, got IllegalCtxt")
-    }
-}
-
 /// Return the outer mark for a context with a mark at the outside.
 /// FAILS when outside is not a mark.
 pub fn outer_mark(ctxt: SyntaxContext) -> Mrk {
@@ -171,15 +104,24 @@ pub fn outer_mark(ctxt: SyntaxContext) -> Mrk {
     })
 }
 
+/// If `ident` is macro expanded, return the source ident from the macro definition
+/// and the mark of the expansion that created the macro definition.
+pub fn source(ident: Ident) -> Option<(Ident /* source ident */, Mrk /* source macro */)> {
+    with_sctable(|sctable| {
+        let ctxts = sctable.table.borrow();
+        if let Mark(_expansion_mark, macro_ctxt) = ctxts[ident.ctxt.0 as usize] {
+            if let Mark(definition_mark, orig_ctxt) = ctxts[macro_ctxt.0 as usize] {
+                return Some((Ident::new(ident.name, orig_ctxt), definition_mark));
+            }
+        }
+        None
+    })
+}
+
 #[cfg(test)]
 mod tests {
-    use ast::{EMPTY_CTXT, Ident, Mrk, Name, SyntaxContext};
-    use super::{resolve, apply_mark_internal, new_sctable_internal};
-    use super::{SCTable, Mark};
-
-    fn id(n: u32, s: SyntaxContext) -> Ident {
-        Ident::new(Name(n), s)
-    }
+    use ast::{EMPTY_CTXT, Mrk, SyntaxContext};
+    use super::{apply_mark_internal, new_sctable_internal, Mark, SCTable};
 
     // extend a syntax context with a sequence of marks given
     // in a vector. v[0] will be the outermost mark.
@@ -192,27 +134,21 @@ fn unfold_marks(mrks: Vec<Mrk> , tail: SyntaxContext, table: &SCTable)
     #[test] fn unfold_marks_test() {
         let mut t = new_sctable_internal();
 
-        assert_eq!(unfold_marks(vec!(3,7),EMPTY_CTXT,&mut t),SyntaxContext(3));
+        assert_eq!(unfold_marks(vec!(3,7),EMPTY_CTXT,&mut t),SyntaxContext(2));
         {
             let table = t.table.borrow();
-            assert!((*table)[2] == Mark(7,EMPTY_CTXT));
-            assert!((*table)[3] == Mark(3,SyntaxContext(2)));
+            assert!((*table)[1] == Mark(7,EMPTY_CTXT));
+            assert!((*table)[2] == Mark(3,SyntaxContext(1)));
         }
     }
 
-    #[test]
-    fn mtwt_resolve_test(){
-        let a = 40;
-        assert_eq!(resolve(id(a,EMPTY_CTXT)),Name(a));
-    }
-
     #[test]
     fn hashing_tests () {
         let mut t = new_sctable_internal();
-        assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(2));
-        assert_eq!(apply_mark_internal(13,EMPTY_CTXT,&mut t),SyntaxContext(3));
+        assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(1));
+        assert_eq!(apply_mark_internal(13,EMPTY_CTXT,&mut t),SyntaxContext(2));
         // using the same one again should result in the same index:
-        assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(2));
+        assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(1));
         // I'm assuming that the rename table will behave the same....
     }
 }
index 15344cef1dbcf438d157614df5bfd39064462152..2ae3236cd5aa72f818d353cf3e6aa75c722cc255 100644 (file)
 use parse::parser::{Parser, TokenType};
 use ptr::P;
 
+#[derive(PartialEq, Eq, Debug)]
+enum InnerAttributeParsePolicy<'a> {
+    Permitted,
+    NotPermitted { reason: &'a str },
+}
+
+const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &'static str = "an inner attribute is not \
+                                                             permitted in this context";
+
 impl<'a> Parser<'a> {
     /// Parse attributes that appear before an item
     pub fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
         let mut attrs: Vec<ast::Attribute> = Vec::new();
+        let mut just_parsed_doc_comment = false;
         loop {
             debug!("parse_outer_attributes: self.token={:?}", self.token);
             match self.token {
                 token::Pound => {
-                    attrs.push(self.parse_attribute(false)?);
+                    let inner_error_reason = if just_parsed_doc_comment {
+                        "an inner attribute is not permitted following an outer doc comment"
+                    } else if !attrs.is_empty() {
+                        "an inner attribute is not permitted following an outer attribute"
+                    } else {
+                        DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
+                    };
+                    let inner_parse_policy =
+                        InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason };
+                    attrs.push(self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?);
+                    just_parsed_doc_comment = false;
                 }
                 token::DocComment(s) => {
                     let attr = ::attr::mk_sugared_doc_attr(
-                    attr::mk_attr_id(),
-                    self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)),
-                    self.span.lo,
-                    self.span.hi
-                );
+                        attr::mk_attr_id(),
+                        self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)),
+                        self.span.lo,
+                        self.span.hi
+                    );
                     if attr.node.style != ast::AttrStyle::Outer {
                         let mut err = self.fatal("expected outer doc comment");
                         err.note("inner doc comments like this (starting with \
@@ -43,6 +63,7 @@ pub fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
                     }
                     attrs.push(attr);
                     self.bump();
+                    just_parsed_doc_comment = true;
                 }
                 _ => break,
             }
@@ -55,26 +76,46 @@ pub fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
     /// If permit_inner is true, then a leading `!` indicates an inner
     /// attribute
     pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
-        debug!("parse_attributes: permit_inner={:?} self.token={:?}",
+        debug!("parse_attribute: permit_inner={:?} self.token={:?}",
                permit_inner,
                self.token);
+        let inner_parse_policy = if permit_inner {
+            InnerAttributeParsePolicy::Permitted
+        } else {
+            InnerAttributeParsePolicy::NotPermitted
+                { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }
+        };
+        self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
+    }
+
+    /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
+    /// that prescribes how to handle inner attributes.
+    fn parse_attribute_with_inner_parse_policy(&mut self,
+                                               inner_parse_policy: InnerAttributeParsePolicy)
+                                               -> PResult<'a, ast::Attribute> {
+        debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
+               inner_parse_policy,
+               self.token);
         let (span, value, mut style) = match self.token {
             token::Pound => {
                 let lo = self.span.lo;
                 self.bump();
 
-                if permit_inner {
+                if inner_parse_policy == InnerAttributeParsePolicy::Permitted {
                     self.expected_tokens.push(TokenType::Token(token::Not));
                 }
                 let style = if self.token == token::Not {
                     self.bump();
-                    if !permit_inner {
+                    if let InnerAttributeParsePolicy::NotPermitted { reason } = inner_parse_policy
+                    {
                         let span = self.span;
                         self.diagnostic()
-                            .struct_span_err(span,
-                                             "an inner attribute is not permitted in this context")
-                            .help("place inner attribute at the top of the module or \
-                                   block")
+                            .struct_span_err(span, reason)
+                            .note("inner attributes and doc comments, like `#![no_std]` or \
+                                   `//! My crate`, annotate the item enclosing them, and are \
+                                   usually found at the beginning of source files. Outer \
+                                   attributes and doc comments, like `#[test]` and
+                                   `/// My function`, annotate the item following them.")
                             .emit()
                     }
                     ast::AttrStyle::Inner
@@ -95,7 +136,8 @@ pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attrib
             }
         };
 
-        if permit_inner && self.token == token::Semi {
+        if inner_parse_policy == InnerAttributeParsePolicy::Permitted &&
+           self.token == token::Semi {
             self.bump();
             self.span_warn(span,
                            "this inner attribute syntax is deprecated. The new syntax is \
index ab7ed223bb31820e23c59b7f2f68f84ce07e1e5b..fe9d3ef7c234dff8c364e9f4c9bdffb94183c150 100644 (file)
@@ -15,7 +15,6 @@
 pub use self::Token::*;
 
 use ast::{self, BinOpKind};
-use ext::mtwt;
 use ptr::P;
 use util::interner::Interner;
 use tokenstream;
@@ -313,17 +312,6 @@ pub fn is_reserved_keyword(&self) -> bool {
             _ => false,
         }
     }
-
-    /// Hygienic identifier equality comparison.
-    ///
-    /// See `styntax::ext::mtwt`.
-    pub fn mtwt_eq(&self, other : &Token) -> bool {
-        match (self, other) {
-            (&Ident(id1), &Ident(id2)) | (&Lifetime(id1), &Lifetime(id2)) =>
-                mtwt::resolve(id1) == mtwt::resolve(id2),
-            _ => *self == *other
-        }
-    }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
@@ -650,21 +638,3 @@ pub fn fresh_name(src: ast::Ident) -> ast::Name {
 pub fn fresh_mark() -> ast::Mrk {
     gensym("mark").0
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use ast;
-    use ext::mtwt;
-
-    fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident {
-        ast::Ident::new(id.name, mtwt::apply_mark(m, id.ctxt))
-    }
-
-    #[test] fn mtwt_token_eq_test() {
-        assert!(Gt.mtwt_eq(&Gt));
-        let a = str_to_ident("bac");
-        let a1 = mark_ident(a,92);
-        assert!(Ident(a).mtwt_eq(&Ident(a1)));
-    }
-}
index 0a60b7fd430c427277fcbe33cf3d7668388c9ae5..327696e87b08e26fc98ddbc9725f42a1c0a45580 100644 (file)
@@ -185,6 +185,8 @@ fn fold_mod(&mut self, m: ast::Mod) -> ast::Mod {
 
         mod_folded
     }
+
+    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
 }
 
 struct EntryPointCleaner {
@@ -234,6 +236,8 @@ fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
 
         SmallVector::one(folded)
     }
+
+    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
 }
 
 fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
diff --git a/src/test/parse-fail/inner-attr-after-doc-comment.rs b/src/test/parse-fail/inner-attr-after-doc-comment.rs
new file mode 100644 (file)
index 0000000..ed8342d
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+
+#![feature(lang_items)]
+/**
+ * My module
+ */
+
+#![recursion_limit="100"]
+//~^ ERROR an inner attribute is not permitted following an outer doc comment
+fn main() {}
diff --git a/src/test/parse-fail/inner-attr.rs b/src/test/parse-fail/inner-attr.rs
new file mode 100644 (file)
index 0000000..8cebda6
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+
+#[feature(lang_items)]
+
+#![recursion_limit="100"] //~ ERROR an inner attribute is not permitted following an outer attribute
+fn main() {}
index 4507ba50192dd67ccae1245cebb7c3245a1a0d4d..d72386190ecd2768326ca42afec211098279a76d 100644 (file)
@@ -106,6 +106,13 @@ macro_rules! m {
     m!(Ok(x), x);
 }
 
+fn label_hygiene() {
+    'a: loop {
+        macro_rules! m { () => { break 'a; } }
+        m!();
+    }
+}
+
 fn main() {
     f();
     g();