diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index a2a0660d575..bfa69583a06 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -176,6 +176,9 @@ pub fn phase_2_configure_and_expand(sess: Session,
     time(time_passes, "gated feature checking", (), |_|
          front::feature_gate::check_crate(sess, &crate));
 
+    crate = time(time_passes, "crate injection", crate, |crate|
+                 front::std_inject::maybe_inject_crates_ref(sess, crate));
+
     // strip before expansion to allow macros to depend on
     // configuration variables e.g/ in
     //
@@ -183,10 +186,6 @@ pub fn phase_2_configure_and_expand(sess: Session,
     //   mod bar { macro_rules! baz!(() => {{}}) }
     //
     // baz! should not use this definition unless foo is enabled.
-    crate = time(time_passes, "std macros injection", crate, |crate|
-                 syntax::ext::expand::inject_std_macros(sess.parse_sess,
-                                                        cfg.clone(),
-                                                        crate));
 
     crate = time(time_passes, "configuration 1", crate, |crate|
                  front::config::strip_unconfigured_items(crate));
@@ -207,8 +206,8 @@ pub fn phase_2_configure_and_expand(sess: Session,
     crate = time(time_passes, "maybe building test harness", crate, |crate|
                  front::test::modify_for_testing(sess, crate));
 
-    crate = time(time_passes, "std injection", crate, |crate|
-                 front::std_inject::maybe_inject_libstd_ref(sess, crate));
+    crate = time(time_passes, "prelude injection", crate, |crate|
+                 front::std_inject::maybe_inject_prelude(sess, crate));
 
     time(time_passes, "assinging node ids and indexing ast", crate, |crate|
          front::assign_node_ids_and_map::assign_node_ids_and_map(sess, crate))
diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs
index 6fa54061e34..71a82536aee 100644
--- a/src/librustc/front/std_inject.rs
+++ b/src/librustc/front/std_inject.rs
@@ -23,10 +23,18 @@ use syntax::util::small_vector::SmallVector;
 
 pub static VERSION: &'static str = "0.10-pre";
 
-pub fn maybe_inject_libstd_ref(sess: Session, crate: ast::Crate)
+pub fn maybe_inject_crates_ref(sess: Session, crate: ast::Crate)
                                -> ast::Crate {
     if use_std(&crate) {
-        inject_libstd_ref(sess, crate)
+        inject_crates_ref(sess, crate)
+    } else {
+        crate
+    }
+}
+
+pub fn maybe_inject_prelude(sess: Session, crate: ast::Crate) -> ast::Crate {
+    if use_std(&crate) {
+        inject_prelude(sess, crate)
     } else {
         crate
     }
@@ -44,13 +52,6 @@ fn no_prelude(attrs: &[ast::Attribute]) -> bool {
     attr::contains_name(attrs, "no_implicit_prelude")
 }
 
-fn spanned<T>(x: T) -> codemap::Spanned<T> {
-    codemap::Spanned {
-        node: x,
-        span: DUMMY_SP,
-    }
-}
-
 struct StandardLibraryInjector {
     sess: Session,
 }
@@ -71,7 +72,11 @@ impl fold::Folder for StandardLibraryInjector {
             node: ast::ViewItemExternMod(self.sess.ident_of("std"),
                                          with_version("std"),
                                          ast::DUMMY_NODE_ID),
-            attrs: ~[],
+            attrs: ~[
+                attr::mk_attr(attr::mk_list_item(@"phase",
+                                                 ~[attr::mk_word_item(@"syntax"),
+                                                   attr::mk_word_item(@"link")]))
+            ],
             vis: ast::Inherited,
             span: DUMMY_SP
         }];
@@ -96,22 +101,43 @@ impl fold::Folder for StandardLibraryInjector {
         }
 
         vis.push_all(crate.module.view_items);
-        let mut new_module = ast::Mod {
+        let new_module = ast::Mod {
             view_items: vis,
             ..crate.module.clone()
         };
 
-        if !no_prelude(crate.attrs) {
-            // only add `use std::prelude::*;` if there wasn't a
-            // `#[no_implicit_prelude];` at the crate level.
-            new_module = self.fold_mod(&new_module);
-        }
-
         ast::Crate {
             module: new_module,
             ..crate
         }
     }
+}
+
+fn inject_crates_ref(sess: Session, crate: ast::Crate) -> ast::Crate {
+    let mut fold = StandardLibraryInjector {
+        sess: sess,
+    };
+    fold.fold_crate(crate)
+}
+
+struct PreludeInjector {
+    sess: Session,
+}
+
+
+impl fold::Folder for PreludeInjector {
+    fn fold_crate(&mut self, crate: ast::Crate) -> ast::Crate {
+        if !no_prelude(crate.attrs) {
+            // only add `use std::prelude::*;` if there wasn't a
+            // `#[no_implicit_prelude];` at the crate level.
+            ast::Crate {
+                module: self.fold_mod(&crate.module),
+                ..crate
+            }
+        } else {
+            crate
+        }
+    }
 
     fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> {
         if !no_prelude(item.attrs) {
@@ -142,7 +168,7 @@ impl fold::Folder for StandardLibraryInjector {
             ],
         };
 
-        let vp = @spanned(ast::ViewPathGlob(prelude_path, ast::DUMMY_NODE_ID));
+        let vp = @codemap::dummy_spanned(ast::ViewPathGlob(prelude_path, ast::DUMMY_NODE_ID));
         let vi2 = ast::ViewItem {
             node: ast::ViewItemUse(~[vp]),
             attrs: ~[],
@@ -161,8 +187,8 @@ impl fold::Folder for StandardLibraryInjector {
     }
 }
 
-fn inject_libstd_ref(sess: Session, crate: ast::Crate) -> ast::Crate {
-    let mut fold = StandardLibraryInjector {
+fn inject_prelude(sess: Session, crate: ast::Crate) -> ast::Crate {
+    let mut fold = PreludeInjector {
         sess: sess,
     };
     fold.fold_crate(crate)
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 7e53a0071bd..4f13a517878 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -76,6 +76,8 @@
 #[cfg(test)] pub use ops = realstd::ops;
 #[cfg(test)] pub use cmp = realstd::cmp;
 
+mod macros;
+
 mod rtdeps;
 
 /* The Prelude. */
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
new file mode 100644
index 00000000000..e7844101c5f
--- /dev/null
+++ b/src/libstd/macros.rs
@@ -0,0 +1,189 @@
+// Copyright 2014 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.
+#[macro_escape];
+
+#[macro_export]
+macro_rules! log(
+    ($lvl:expr, $($arg:tt)+) => ({
+        let lvl = $lvl;
+        if lvl <= __log_level() {
+            format_args!(|args| {
+                ::std::logging::log(lvl, args)
+            }, $($arg)+)
+        }
+    })
+)
+#[macro_export]
+macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) )
+#[macro_export]
+macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) )
+#[macro_export]
+macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) )
+#[macro_export]
+macro_rules! debug( ($($arg:tt)*) => (
+    if cfg!(not(ndebug)) { log!(4u32, $($arg)*) }
+))
+
+#[macro_export]
+macro_rules! log_enabled(
+    ($lvl:expr) => ( {
+        let lvl = $lvl;
+        lvl <= __log_level() && (lvl != 4 || cfg!(not(ndebug)))
+    } )
+)
+
+#[macro_export]
+macro_rules! fail(
+    () => (
+        fail!("explicit failure")
+    );
+    ($msg:expr) => (
+        ::std::rt::begin_unwind($msg, file!(), line!())
+    );
+    ($fmt:expr, $($arg:tt)*) => (
+        ::std::rt::begin_unwind(format!($fmt, $($arg)*), file!(), line!())
+    )
+)
+
+#[macro_export]
+macro_rules! assert(
+    ($cond:expr) => {
+        if !$cond {
+            fail!("assertion failed: {:s}", stringify!($cond))
+        }
+    };
+    ($cond:expr, $msg:expr) => {
+        if !$cond {
+            fail!($msg)
+        }
+    };
+    ($cond:expr, $( $arg:expr ),+) => {
+        if !$cond {
+            fail!( $($arg),+ )
+        }
+    }
+)
+
+#[macro_export]
+macro_rules! assert_eq (
+    ($given:expr , $expected:expr) => (
+        {
+            let given_val = &($given);
+            let expected_val = &($expected);
+            // check both directions of equality....
+            if !((*given_val == *expected_val) &&
+                 (*expected_val == *given_val)) {
+                fail!("assertion failed: `(left == right) && (right == left)` \
+                       (left: `{:?}`, right: `{:?}`)", *given_val, *expected_val)
+            }
+        }
+    )
+)
+
+/// A utility macro for indicating unreachable code. It will fail if
+/// executed. This is occasionally useful to put after loops that never
+/// terminate normally, but instead directly return from a function.
+///
+/// # Example
+///
+/// ```rust
+/// fn choose_weighted_item(v: &[Item]) -> Item {
+///     assert!(!v.is_empty());
+///     let mut so_far = 0u;
+///     for item in v.iter() {
+///         so_far += item.weight;
+///         if so_far > 100 {
+///             return item;
+///         }
+///     }
+///     // The above loop always returns, so we must hint to the
+///     // type checker that it isn't possible to get down here
+///     unreachable!();
+/// }
+/// ```
+#[macro_export]
+macro_rules! unreachable (() => (
+    fail!("internal error: entered unreachable code");
+))
+
+#[macro_export]
+macro_rules! condition (
+
+    { pub $c:ident: $input:ty -> $out:ty; } => {
+
+        pub mod $c {
+            #[allow(unused_imports)];
+            #[allow(non_uppercase_statics)];
+            #[allow(missing_doc)];
+
+            use super::*;
+
+            local_data_key!(key: @::std::condition::Handler<$input, $out>)
+
+            pub static cond :
+                ::std::condition::Condition<$input,$out> =
+                ::std::condition::Condition {
+                    name: stringify!($c),
+                    key: key
+                };
+        }
+    };
+
+    { $c:ident: $input:ty -> $out:ty; } => {
+
+        mod $c {
+            #[allow(unused_imports)];
+            #[allow(non_uppercase_statics)];
+            #[allow(dead_code)];
+
+            use super::*;
+
+            local_data_key!(key: @::std::condition::Handler<$input, $out>)
+
+            pub static cond :
+                ::std::condition::Condition<$input,$out> =
+                ::std::condition::Condition {
+                    name: stringify!($c),
+                    key: key
+                };
+        }
+    }
+)
+
+#[macro_export]
+macro_rules! format(($($arg:tt)*) => (
+    format_args!(::std::fmt::format, $($arg)*)
+))
+#[macro_export]
+macro_rules! write(($dst:expr, $($arg:tt)*) => (
+    format_args!(|args| { ::std::fmt::write($dst, args) }, $($arg)*)
+))
+#[macro_export]
+macro_rules! writeln(($dst:expr, $($arg:tt)*) => (
+    format_args!(|args| { ::std::fmt::writeln($dst, args) }, $($arg)*)
+))
+#[macro_export]
+macro_rules! print (
+    ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*))
+)
+#[macro_export]
+macro_rules! println (
+    ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
+)
+
+#[macro_export]
+macro_rules! local_data_key (
+    ($name:ident: $ty:ty) => (
+        static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
+    );
+    (pub $name:ident: $ty:ty) => (
+        pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
+    )
+)
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 0534aa39848..43a5b01698b 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -22,7 +22,6 @@ use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use ext::base::*;
 use fold::*;
 use parse;
-use parse::{parse_item_from_source_str};
 use parse::token;
 use parse::token::{fresh_mark, fresh_name, ident_to_str, intern};
 use visit;
@@ -754,218 +753,6 @@ pub fn new_span(cx: &ExtCtxt, sp: Span) -> Span {
     }
 }
 
-// FIXME (#2247): this is a moderately bad kludge to inject some macros into
-// the default compilation environment in that it injects strings, rather than
-// syntax elements.
-
-pub fn std_macros() -> @str {
-@r#"mod __std_macros {
-    #[macro_escape];
-    #[doc(hidden)];
-    #[allow(dead_code)];
-
-    macro_rules! ignore (($($x:tt)*) => (()))
-
-    macro_rules! log(
-        ($lvl:expr, $($arg:tt)+) => ({
-            let lvl = $lvl;
-            if lvl <= __log_level() {
-                format_args!(|args| {
-                    ::std::logging::log(lvl, args)
-                }, $($arg)+)
-            }
-        })
-    )
-    macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) )
-    macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) )
-    macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) )
-    macro_rules! debug( ($($arg:tt)*) => (
-        if cfg!(not(ndebug)) { log!(4u32, $($arg)*) }
-    ))
-
-    macro_rules! log_enabled(
-        ($lvl:expr) => ( {
-            let lvl = $lvl;
-            lvl <= __log_level() && (lvl != 4 || cfg!(not(ndebug)))
-        } )
-    )
-
-    macro_rules! fail(
-        () => (
-            fail!("explicit failure")
-        );
-        ($msg:expr) => (
-            ::std::rt::begin_unwind($msg, file!(), line!())
-        );
-        ($fmt:expr, $($arg:tt)*) => (
-            ::std::rt::begin_unwind(format!($fmt, $($arg)*), file!(), line!())
-        )
-    )
-
-    macro_rules! assert(
-        ($cond:expr) => {
-            if !$cond {
-                fail!("assertion failed: {:s}", stringify!($cond))
-            }
-        };
-        ($cond:expr, $msg:expr) => {
-            if !$cond {
-                fail!($msg)
-            }
-        };
-        ($cond:expr, $( $arg:expr ),+) => {
-            if !$cond {
-                fail!( $($arg),+ )
-            }
-        }
-    )
-
-    macro_rules! assert_eq (
-        ($given:expr , $expected:expr) => (
-            {
-                let given_val = &($given);
-                let expected_val = &($expected);
-                // check both directions of equality....
-                if !((*given_val == *expected_val) &&
-                     (*expected_val == *given_val)) {
-                    fail!("assertion failed: `(left == right) && (right == left)` \
-                           (left: `{:?}`, right: `{:?}`)", *given_val, *expected_val)
-                }
-            }
-        )
-    )
-
-    /// A utility macro for indicating unreachable code. It will fail if
-    /// executed. This is occasionally useful to put after loops that never
-    /// terminate normally, but instead directly return from a function.
-    ///
-    /// # Example
-    ///
-    /// ```rust
-    /// fn choose_weighted_item(v: &[Item]) -> Item {
-    ///     assert!(!v.is_empty());
-    ///     let mut so_far = 0u;
-    ///     for item in v.iter() {
-    ///         so_far += item.weight;
-    ///         if so_far > 100 {
-    ///             return item;
-    ///         }
-    ///     }
-    ///     // The above loop always returns, so we must hint to the
-    ///     // type checker that it isn't possible to get down here
-    ///     unreachable!();
-    /// }
-    /// ```
-    macro_rules! unreachable (() => (
-        fail!("internal error: entered unreachable code");
-    ))
-
-    macro_rules! condition (
-
-        { pub $c:ident: $input:ty -> $out:ty; } => {
-
-            pub mod $c {
-                #[allow(unused_imports)];
-                #[allow(non_uppercase_statics)];
-                #[allow(missing_doc)];
-
-                use super::*;
-
-                local_data_key!(key: @::std::condition::Handler<$input, $out>)
-
-                pub static cond :
-                    ::std::condition::Condition<$input,$out> =
-                    ::std::condition::Condition {
-                        name: stringify!($c),
-                        key: key
-                    };
-            }
-        };
-
-        { $c:ident: $input:ty -> $out:ty; } => {
-
-            mod $c {
-                #[allow(unused_imports)];
-                #[allow(non_uppercase_statics)];
-                #[allow(dead_code)];
-
-                use super::*;
-
-                local_data_key!(key: @::std::condition::Handler<$input, $out>)
-
-                pub static cond :
-                    ::std::condition::Condition<$input,$out> =
-                    ::std::condition::Condition {
-                        name: stringify!($c),
-                        key: key
-                    };
-            }
-        }
-    )
-
-    macro_rules! format(($($arg:tt)*) => (
-        format_args!(::std::fmt::format, $($arg)*)
-    ))
-    macro_rules! write(($dst:expr, $($arg:tt)*) => (
-        format_args!(|args| { ::std::fmt::write($dst, args) }, $($arg)*)
-    ))
-    macro_rules! writeln(($dst:expr, $($arg:tt)*) => (
-        format_args!(|args| { ::std::fmt::writeln($dst, args) }, $($arg)*)
-    ))
-    macro_rules! print (
-        ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*))
-    )
-    macro_rules! println (
-        ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
-    )
-
-    macro_rules! local_data_key (
-        ($name:ident: $ty:ty) => (
-            static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
-        );
-        (pub $name:ident: $ty:ty) => (
-            pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
-        )
-    )
-}"#
-}
-
-struct Injector {
-    sm: @ast::Item,
-}
-
-impl Folder for Injector {
-    fn fold_mod(&mut self, module: &ast::Mod) -> ast::Mod {
-        // Just inject the standard macros at the start of the first module
-        // in the crate: that is, at the start of the crate file itself.
-        let items = vec::append(~[ self.sm ], module.items);
-        ast::Mod {
-            items: items,
-            ..(*module).clone() // FIXME #2543: Bad copy.
-        }
-    }
-}
-
-// add a bunch of macros as though they were placed at the head of the
-// program (ick). This should run before cfg stripping.
-pub fn inject_std_macros(parse_sess: @parse::ParseSess,
-                         cfg: ast::CrateConfig,
-                         c: Crate)
-                         -> Crate {
-    let sm = match parse_item_from_source_str(@"<std-macros>",
-                                              std_macros(),
-                                              cfg.clone(),
-                                              parse_sess) {
-        Some(item) => item,
-        None => fail!("expected core macros to parse correctly")
-    };
-
-    let mut injector = Injector {
-        sm: sm,
-    };
-    injector.fold_crate(c)
-}
-
 pub struct MacroExpander<'a> {
     extsbox: SyntaxEnv,
     cx: &'a mut ExtCtxt<'a>,
@@ -1231,20 +1018,6 @@ mod test {
         }
     }
 
-    // make sure that fail! is present
-    #[test] fn fail_exists_test () {
-        let src = @"fn main() { fail!(\"something appropriately gloomy\");}";
-        let sess = parse::new_parse_sess(None);
-        let crate_ast = parse::parse_crate_from_source_str(
-            @"<test>",
-            src,
-            ~[],sess);
-        let crate_ast = inject_std_macros(sess, ~[], crate_ast);
-        // don't bother with striping, doesn't affect fail!.
-        let mut loader = ErrLoader;
-        expand_crate(sess,&mut loader,~[],crate_ast);
-    }
-
     // these following tests are quite fragile, in that they don't test what
     // *kind* of failure occurs.
 
@@ -1292,20 +1065,6 @@ mod test {
         expand_crate(sess,&mut loader,~[],crate_ast);
     }
 
-    #[test] fn std_macros_must_parse () {
-        let src = super::std_macros();
-        let sess = parse::new_parse_sess(None);
-        let cfg = ~[];
-        let item_ast = parse::parse_item_from_source_str(
-            @"<test>",
-            src,
-            cfg,sess);
-        match item_ast {
-            Some(_) => (), // success
-            None => fail!("expected this to parse")
-        }
-    }
-
     #[test] fn test_contains_flatten (){
         let attr1 = make_dummy_attr (@"foo");
         let attr2 = make_dummy_attr (@"bar");
diff --git a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs
index ebd3320d901..0fc3b3912b1 100644
--- a/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs
+++ b/src/test/compile-fail/tag-that-dare-not-speak-its-name.rs
@@ -11,9 +11,7 @@
 // error-pattern:mismatched types: expected `char` but found
 // Issue #876
 
-#[no_std];
-
-extern mod std;
+#[no_implicit_prelude];
 
 fn last<T>(v: ~[&T]) -> std::option::Option<T> {
     fail!();