about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-07-29 17:01:14 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-08-03 17:23:01 -0700
commit5cccf3cd256420d9f32c265e83036dea1d5f94d8 (patch)
tree22904c7bb3df0872afa227638aa5e1e4ccb99fbc /src/libsyntax
parentceded6adb3a4e172eabef09e1c78717a99c16b14 (diff)
downloadrust-5cccf3cd256420d9f32c265e83036dea1d5f94d8.tar.gz
rust-5cccf3cd256420d9f32c265e83036dea1d5f94d8.zip
syntax: Implement #![no_core]
This commit is an implementation of [RFC 1184][rfc] which tweaks the behavior of
the `#![no_std]` attribute and adds a new `#![no_core]` attribute. The
`#![no_std]` attribute now injects `extern crate core` at the top of the crate
as well as the libcore prelude into all modules (in the same manner as the
standard library's prelude). The `#![no_core]` attribute disables both std and
core injection.

[rfc]: https://github.com/rust-lang/rfcs/pull/1184
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/base.rs13
-rw-r--r--src/libsyntax/ext/build.rs80
-rw-r--r--src/libsyntax/ext/deriving/bounds.rs9
-rw-r--r--src/libsyntax/ext/deriving/clone.rs7
-rw-r--r--src/libsyntax/ext/deriving/cmp/ord.rs12
-rw-r--r--src/libsyntax/ext/deriving/cmp/partial_ord.rs12
-rw-r--r--src/libsyntax/ext/deriving/decodable.rs7
-rw-r--r--src/libsyntax/ext/deriving/default.rs7
-rw-r--r--src/libsyntax/ext/deriving/encodable.rs5
-rw-r--r--src/libsyntax/ext/deriving/generic/mod.rs8
-rw-r--r--src/libsyntax/ext/deriving/hash.rs7
-rw-r--r--src/libsyntax/ext/deriving/mod.rs12
-rw-r--r--src/libsyntax/ext/env.rs10
-rw-r--r--src/libsyntax/ext/expand.rs26
-rw-r--r--src/libsyntax/ext/format.rs31
-rw-r--r--src/libsyntax/feature_gate.rs5
-rw-r--r--src/libsyntax/print/pprust.rs2
-rw-r--r--src/libsyntax/std_inject.rs59
-rw-r--r--src/libsyntax/test.rs1
19 files changed, 107 insertions, 206 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 409ae86db35..b2cff3ed53c 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -611,7 +611,7 @@ pub struct ExtCtxt<'a> {
     pub cfg: ast::CrateConfig,
     pub backtrace: ExpnId,
     pub ecfg: expand::ExpansionConfig<'a>,
-    pub use_std: bool,
+    pub crate_root: Option<&'static str>,
 
     pub mod_path: Vec<ast::Ident> ,
     pub exported_macros: Vec<ast::MacroDef>,
@@ -630,7 +630,7 @@ impl<'a> ExtCtxt<'a> {
             backtrace: NO_EXPANSION,
             mod_path: Vec::new(),
             ecfg: ecfg,
-            use_std: true,
+            crate_root: None,
             exported_macros: Vec::new(),
             syntax_env: env,
             recursion_count: 0,
@@ -805,8 +805,13 @@ impl<'a> ExtCtxt<'a> {
     pub fn ident_of(&self, st: &str) -> ast::Ident {
         str_to_ident(st)
     }
-    pub fn ident_of_std(&self, st: &str) -> ast::Ident {
-        self.ident_of(if self.use_std { "std" } else { st })
+    pub fn std_path(&self, components: &[&str]) -> Vec<ast::Ident> {
+        let mut v = Vec::new();
+        if let Some(s) = self.crate_root {
+            v.push(self.ident_of(s));
+        }
+        v.extend(components.iter().map(|s| self.ident_of(s)));
+        return v
     }
     pub fn name_of(&self, st: &str) -> ast::Name {
         token::intern(st)
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index b91c54ae972..2061165abd2 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -437,11 +437,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.ty_path(
             self.path_all(DUMMY_SP,
                           true,
-                          vec!(
-                              self.ident_of_std("core"),
-                              self.ident_of("option"),
-                              self.ident_of("Option")
-                          ),
+                          self.std_path(&["option", "Option"]),
                           Vec::new(),
                           vec!( ty ),
                           Vec::new()))
@@ -713,11 +709,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.expr(sp, ast::ExprVec(exprs))
     }
     fn expr_vec_ng(&self, sp: Span) -> P<ast::Expr> {
-        self.expr_call_global(sp,
-                              vec!(self.ident_of_std("collections"),
-                                   self.ident_of("vec"),
-                                   self.ident_of("Vec"),
-                                   self.ident_of("new")),
+        self.expr_call_global(sp, self.std_path(&["vec", "Vec", "new"]),
                               Vec::new())
     }
     fn expr_vec_slice(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
@@ -733,20 +725,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
 
 
     fn expr_some(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
-        let some = vec!(
-            self.ident_of_std("core"),
-            self.ident_of("option"),
-            self.ident_of("Option"),
-            self.ident_of("Some"));
+        let some = self.std_path(&["option", "Option", "Some"]);
         self.expr_call_global(sp, some, vec!(expr))
     }
 
     fn expr_none(&self, sp: Span) -> P<ast::Expr> {
-        let none = self.path_global(sp, vec!(
-            self.ident_of_std("core"),
-            self.ident_of("option"),
-            self.ident_of("Option"),
-            self.ident_of("None")));
+        let none = self.std_path(&["option", "Option", "None"]);
+        let none = self.path_global(sp, none);
         self.expr_path(none)
     }
 
@@ -769,10 +754,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         let expr_file_line_ptr = self.expr_addr_of(span, expr_file_line_tuple);
         self.expr_call_global(
             span,
-            vec!(
-                self.ident_of_std("core"),
-                self.ident_of("rt"),
-                self.ident_of("begin_unwind")),
+            self.std_path(&["rt", "begin_unwind"]),
             vec!(
                 self.expr_str(span, msg),
                 expr_file_line_ptr))
@@ -785,37 +767,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
 
     fn expr_ok(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
-        let ok = vec!(
-            self.ident_of_std("core"),
-            self.ident_of("result"),
-            self.ident_of("Result"),
-            self.ident_of("Ok"));
+        let ok = self.std_path(&["result", "Result", "Ok"]);
         self.expr_call_global(sp, ok, vec!(expr))
     }
 
     fn expr_err(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {
-        let err = vec!(
-            self.ident_of_std("core"),
-            self.ident_of("result"),
-            self.ident_of("Result"),
-            self.ident_of("Err"));
+        let err = self.std_path(&["result", "Result", "Err"]);
         self.expr_call_global(sp, err, vec!(expr))
     }
 
     fn expr_try(&self, sp: Span, head: P<ast::Expr>) -> P<ast::Expr> {
-        let ok = vec![
-            self.ident_of_std("core"),
-            self.ident_of("result"),
-            self.ident_of("Result"),
-            self.ident_of("Ok")
-        ];
+        let ok = self.std_path(&["result", "Result", "Ok"]);
         let ok_path = self.path_global(sp, ok);
-        let err = vec![
-            self.ident_of_std("core"),
-            self.ident_of("result"),
-            self.ident_of("Result"),
-            self.ident_of("Err")
-        ];
+        let err = self.std_path(&["result", "Result", "Err"]);
         let err_path = self.path_global(sp, err);
 
         let binding_variable = self.ident_of("__try_var");
@@ -876,41 +840,25 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
 
     fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
-        let some = vec!(
-            self.ident_of_std("core"),
-            self.ident_of("option"),
-            self.ident_of("Option"),
-            self.ident_of("Some"));
+        let some = self.std_path(&["option", "Option", "Some"]);
         let path = self.path_global(span, some);
         self.pat_enum(span, path, vec!(pat))
     }
 
     fn pat_none(&self, span: Span) -> P<ast::Pat> {
-        let some = vec!(
-            self.ident_of_std("core"),
-            self.ident_of("option"),
-            self.ident_of("Option"),
-            self.ident_of("None"));
+        let some = self.std_path(&["option", "Option", "None"]);
         let path = self.path_global(span, some);
         self.pat_enum(span, path, vec!())
     }
 
     fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
-        let some = vec!(
-            self.ident_of_std("core"),
-            self.ident_of("result"),
-            self.ident_of("Result"),
-            self.ident_of("Ok"));
+        let some = self.std_path(&["result", "Result", "Ok"]);
         let path = self.path_global(span, some);
         self.pat_enum(span, path, vec!(pat))
     }
 
     fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
-        let some = vec!(
-            self.ident_of_std("core"),
-            self.ident_of("result"),
-            self.ident_of("Result"),
-            self.ident_of("Err"));
+        let some = self.std_path(&["result", "Result", "Err"]);
         let path = self.path_global(span, some);
         self.pat_enum(span, path, vec!(pat))
     }
diff --git a/src/libsyntax/ext/deriving/bounds.rs b/src/libsyntax/ext/deriving/bounds.rs
index 689a4e96aec..71b6184390a 100644
--- a/src/libsyntax/ext/deriving/bounds.rs
+++ b/src/libsyntax/ext/deriving/bounds.rs
@@ -29,11 +29,10 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt,
                             item: &Annotatable,
                             push: &mut FnMut(Annotatable))
 {
-    let path = Path::new(vec![
-        if cx.use_std { "std" } else { "core" },
-        "marker",
-        "Copy",
-    ]);
+    let mut v = cx.crate_root.map(|s| vec![s]).unwrap_or(Vec::new());
+    v.push("marker");
+    v.push("Copy");
+    let path = Path::new(v);
 
     let trait_def = TraitDef {
         span: span,
diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs
index a9c05339894..9261c0162c7 100644
--- a/src/libsyntax/ext/deriving/clone.rs
+++ b/src/libsyntax/ext/deriving/clone.rs
@@ -57,12 +57,7 @@ fn cs_clone(
     substr: &Substructure) -> P<Expr> {
     let ctor_path;
     let all_fields;
-    let fn_path = vec![
-        cx.ident_of_std("core"),
-        cx.ident_of("clone"),
-        cx.ident_of("Clone"),
-        cx.ident_of("clone"),
-    ];
+    let fn_path = cx.std_path(&["clone", "Clone", "clone"]);
     let subcall = |field: &FieldInfo| {
         let args = vec![cx.expr_addr_of(field.span, field.self_.clone())];
 
diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs
index d605e0286f5..815448ac610 100644
--- a/src/libsyntax/ext/deriving/cmp/ord.rs
+++ b/src/libsyntax/ext/deriving/cmp/ord.rs
@@ -65,17 +65,9 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span,
               substr: &Substructure) -> P<Expr> {
     let test_id = cx.ident_of("__test");
     let equals_path = cx.path_global(span,
-                                     vec!(cx.ident_of_std("core"),
-                                          cx.ident_of("cmp"),
-                                          cx.ident_of("Ordering"),
-                                          cx.ident_of("Equal")));
+                                     cx.std_path(&["cmp", "Ordering", "Equal"]));
 
-    let cmp_path = vec![
-        cx.ident_of_std("core"),
-        cx.ident_of("cmp"),
-        cx.ident_of("Ord"),
-        cx.ident_of("cmp"),
-    ];
+    let cmp_path = cx.std_path(&["cmp", "Ord", "cmp"]);
 
     /*
     Builds:
diff --git a/src/libsyntax/ext/deriving/cmp/partial_ord.rs b/src/libsyntax/ext/deriving/cmp/partial_ord.rs
index 4eb95343a49..a11e9f473a4 100644
--- a/src/libsyntax/ext/deriving/cmp/partial_ord.rs
+++ b/src/libsyntax/ext/deriving/cmp/partial_ord.rs
@@ -108,19 +108,11 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span,
               substr: &Substructure) -> P<Expr> {
     let test_id = cx.ident_of("__test");
     let ordering = cx.path_global(span,
-                                  vec!(cx.ident_of_std("core"),
-                                       cx.ident_of("cmp"),
-                                       cx.ident_of("Ordering"),
-                                       cx.ident_of("Equal")));
+                                  cx.std_path(&["cmp", "Ordering", "Equal"]));
     let ordering = cx.expr_path(ordering);
     let equals_expr = cx.expr_some(span, ordering);
 
-    let partial_cmp_path = vec![
-        cx.ident_of_std("core"),
-        cx.ident_of("cmp"),
-        cx.ident_of("PartialOrd"),
-        cx.ident_of("partial_cmp"),
-    ];
+    let partial_cmp_path = cx.std_path(&["cmp", "PartialOrd", "partial_cmp"]);
 
     /*
     Builds:
diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs
index 085d9d60937..99fac991e7f 100644
--- a/src/libsyntax/ext/deriving/decodable.rs
+++ b/src/libsyntax/ext/deriving/decodable.rs
@@ -46,10 +46,11 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
                                  push: &mut FnMut(Annotatable),
                                  krate: &'static str)
 {
-    if !cx.use_std {
+    if cx.crate_root != Some("std") {
         // FIXME(#21880): lift this requirement.
-        cx.span_err(span, "this trait cannot be derived with #![no_std]");
-        return;
+        cx.span_err(span, "this trait cannot be derived with #![no_std] \
+                           or #![no_core]");
+        return
     }
 
     let trait_def = TraitDef {
diff --git a/src/libsyntax/ext/deriving/default.rs b/src/libsyntax/ext/deriving/default.rs
index ab22b710700..3f4e9da0ed5 100644
--- a/src/libsyntax/ext/deriving/default.rs
+++ b/src/libsyntax/ext/deriving/default.rs
@@ -51,12 +51,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt,
 }
 
 fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
-    let default_ident = vec!(
-        cx.ident_of_std("core"),
-        cx.ident_of("default"),
-        cx.ident_of("Default"),
-        cx.ident_of("default")
-    );
+    let default_ident = cx.std_path(&["default", "Default", "default"]);
     let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new());
 
     return match *substr.fields {
diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs
index ae4d337b9f6..3c77effe5f5 100644
--- a/src/libsyntax/ext/deriving/encodable.rs
+++ b/src/libsyntax/ext/deriving/encodable.rs
@@ -122,9 +122,10 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt,
                                  push: &mut FnMut(Annotatable),
                                  krate: &'static str)
 {
-    if !cx.use_std {
+    if cx.crate_root != Some("std") {
         // FIXME(#21880): lift this requirement.
-        cx.span_err(span, "this trait cannot be derived with #![no_std]");
+        cx.span_err(span, "this trait cannot be derived with #![no_std] \
+                           or #![no_core]");
         return;
     }
 
diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs
index 8f9e0279b29..1f4860b7ec1 100644
--- a/src/libsyntax/ext/deriving/generic/mod.rs
+++ b/src/libsyntax/ext/deriving/generic/mod.rs
@@ -1252,9 +1252,7 @@ impl<'a> MethodDef<'a> {
 
             let mut first_ident = None;
             for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
-                let path = vec![cx.ident_of_std("core"),
-                                cx.ident_of("intrinsics"),
-                                cx.ident_of("discriminant_value")];
+                let path = cx.std_path(&["intrinsics", "discriminant_value"]);
                 let call = cx.expr_call_global(
                     sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]);
                 let variant_value = cx.expr_block(P(ast::Block {
@@ -1289,9 +1287,7 @@ impl<'a> MethodDef<'a> {
             //Since we know that all the arguments will match if we reach the match expression we
             //add the unreachable intrinsics as the result of the catch all which should help llvm
             //in optimizing it
-            let path = vec![cx.ident_of_std("core"),
-                            cx.ident_of("intrinsics"),
-                            cx.ident_of("unreachable")];
+            let path = cx.std_path(&["intrinsics", "unreachable"]);
             let call = cx.expr_call_global(
                 sp, path, vec![]);
             let unreachable = cx.expr_block(P(ast::Block {
diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs
index cdb378a34d4..97c50ed1eea 100644
--- a/src/libsyntax/ext/deriving/hash.rs
+++ b/src/libsyntax/ext/deriving/hash.rs
@@ -63,12 +63,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
     };
     let call_hash = |span, thing_expr| {
         let hash_path = {
-            let strs = vec![
-                cx.ident_of_std("core"),
-                cx.ident_of("hash"),
-                cx.ident_of("Hash"),
-                cx.ident_of("hash"),
-            ];
+            let strs = cx.std_path(&["hash", "Hash", "hash"]);
 
             cx.expr_path(cx.path_global(span, strs))
         };
diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs
index 344515b875f..36deaf488e1 100644
--- a/src/libsyntax/ext/deriving/mod.rs
+++ b/src/libsyntax/ext/deriving/mod.rs
@@ -40,13 +40,13 @@ macro_rules! path_local {
 }
 
 macro_rules! pathvec_std {
-    ($cx:expr, $first:ident :: $($rest:ident)::+) => (
-        if $cx.use_std {
-            pathvec!(std :: $($rest)::+)
-        } else {
-            pathvec!($first :: $($rest)::+)
+    ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
+        let mut v = pathvec!($($rest)::+);
+        if let Some(s) = $cx.crate_root {
+            v.insert(0, s);
         }
-    )
+        v
+    })
 }
 
 macro_rules! path_std {
diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs
index 2ca74644b3b..d85071e78af 100644
--- a/src/libsyntax/ext/env.rs
+++ b/src/libsyntax/ext/env.rs
@@ -34,10 +34,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT
       Err(..) => {
           cx.expr_path(cx.path_all(sp,
                                    true,
-                                   vec!(cx.ident_of_std("core"),
-                                        cx.ident_of("option"),
-                                        cx.ident_of("Option"),
-                                        cx.ident_of("None")),
+                                   cx.std_path(&["option", "Option", "None"]),
                                    Vec::new(),
                                    vec!(cx.ty_rptr(sp,
                                                    cx.ty_ident(sp,
@@ -50,10 +47,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT
       }
       Ok(s) => {
           cx.expr_call_global(sp,
-                              vec!(cx.ident_of_std("core"),
-                                   cx.ident_of("option"),
-                                   cx.ident_of("Option"),
-                                   cx.ident_of("Some")),
+                              cx.std_path(&["option", "Option", "Some"]),
                               vec!(cx.expr_str(sp,
                                                token::intern_and_get_ident(
                                           &s[..]))))
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6e49b190f7c..66b3768a476 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -38,8 +38,7 @@ use std_inject;
 fn mk_core_path(fld: &mut MacroExpander,
                 span: Span,
                 suffix: &[&'static str]) -> ast::Path {
-    let mut idents = vec![fld.cx.ident_of_std("core")];
-    for s in suffix.iter() { idents.push(fld.cx.ident_of(*s)); }
+    let idents = fld.cx.std_path(suffix);
     fld.cx.path_global(span, idents)
 }
 
@@ -417,12 +416,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             // `match ::std::iter::Iterator::next(&mut iter) { ... }`
             let match_expr = {
                 let next_path = {
-                    let strs = vec![
-                        fld.cx.ident_of_std("core"),
-                        fld.cx.ident_of("iter"),
-                        fld.cx.ident_of("Iterator"),
-                        fld.cx.ident_of("next"),
-                    ];
+                    let strs = fld.cx.std_path(&["iter", "Iterator", "next"]);
 
                     fld.cx.path_global(span, strs)
                 };
@@ -450,12 +444,8 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
             let into_iter_expr = {
                 let into_iter_path = {
-                    let strs = vec![
-                        fld.cx.ident_of_std("core"),
-                        fld.cx.ident_of("iter"),
-                        fld.cx.ident_of("IntoIterator"),
-                        fld.cx.ident_of("into_iter"),
-                    ];
+                    let strs = fld.cx.std_path(&["iter", "IntoIterator",
+                                                 "into_iter"]);
 
                     fld.cx.path_global(span, strs)
                 };
@@ -1665,7 +1655,13 @@ pub fn expand_crate<'feat>(parse_sess: &parse::ParseSess,
                            user_exts: Vec<NamedSyntaxExtension>,
                            c: Crate) -> Crate {
     let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
-    cx.use_std = std_inject::use_std(&c);
+    if std_inject::no_core(&c) {
+        cx.crate_root = None;
+    } else if std_inject::no_std(&c) {
+        cx.crate_root = Some("core");
+    } else {
+        cx.crate_root = Some("std");
+    }
 
     let mut expander = MacroExpander::new(&mut cx);
 
diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs
index 5a2b9c0eea4..cc2f94f05d4 100644
--- a/src/libsyntax/ext/format.rs
+++ b/src/libsyntax/ext/format.rs
@@ -305,8 +305,7 @@ impl<'a, 'b> Context<'a, 'b> {
     }
 
     fn rtpath(ecx: &ExtCtxt, s: &str) -> Vec<ast::Ident> {
-        vec![ecx.ident_of_std("core"), ecx.ident_of("fmt"), ecx.ident_of("rt"),
-             ecx.ident_of("v1"), ecx.ident_of(s)]
+        ecx.std_path(&["fmt", "rt", "v1", s])
     }
 
     fn trans_count(&self, c: parse::Count) -> P<ast::Expr> {
@@ -579,11 +578,8 @@ impl<'a, 'b> Context<'a, 'b> {
             ("new_v1_formatted", vec![pieces, args_slice, fmt])
         };
 
-        self.ecx.expr_call_global(self.macsp, vec!(
-                self.ecx.ident_of_std("core"),
-                self.ecx.ident_of("fmt"),
-                self.ecx.ident_of("Arguments"),
-                self.ecx.ident_of(fn_name)), fn_args)
+        let path = self.ecx.std_path(&["fmt", "Arguments", fn_name]);
+        self.ecx.expr_call_global(self.macsp, path, fn_args)
     }
 
     fn format_arg(ecx: &ExtCtxt, macsp: Span, sp: Span,
@@ -610,24 +606,15 @@ impl<'a, 'b> Context<'a, 'b> {
                 }
             }
             Unsigned => {
-                return ecx.expr_call_global(macsp, vec![
-                        ecx.ident_of_std("core"),
-                        ecx.ident_of("fmt"),
-                        ecx.ident_of("ArgumentV1"),
-                        ecx.ident_of("from_usize")], vec![arg])
+                let path = ecx.std_path(&["fmt", "ArgumentV1", "from_usize"]);
+                return ecx.expr_call_global(macsp, path, vec![arg])
             }
         };
 
-        let format_fn = ecx.path_global(sp, vec![
-                ecx.ident_of_std("core"),
-                ecx.ident_of("fmt"),
-                ecx.ident_of(trait_),
-                ecx.ident_of("fmt")]);
-        ecx.expr_call_global(macsp, vec![
-                ecx.ident_of_std("core"),
-                ecx.ident_of("fmt"),
-                ecx.ident_of("ArgumentV1"),
-                ecx.ident_of("new")], vec![arg, ecx.expr_path(format_fn)])
+        let path = ecx.std_path(&["fmt", trait_, "fmt"]);
+        let format_fn = ecx.path_global(sp, path);
+        let path = ecx.std_path(&["fmt", "ArgumentV1", "new"]);
+        ecx.expr_call_global(macsp, path, vec![arg, ecx.expr_path(format_fn)])
     }
 }
 
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 945e457a77b..4a1b74d89d0 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -122,6 +122,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
     // Allows using #![no_std]
     ("no_std", "1.0.0", Active),
 
+    // Allows using #![no_core]
+    ("no_core", "1.3.0", Active),
+
     // Allows using `box` in patterns; RFC 469
     ("box_patterns", "1.0.0", Active),
 
@@ -226,6 +229,8 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
                       and possibly buggy")),
     ("no_std", Gated("no_std",
                      "no_std is experimental")),
+    ("no_core", Gated("no_core",
+                     "no_core is experimental")),
     ("lang", Gated("lang_items",
                      "language items are subject to change")),
     ("linkage", Gated("linkage",
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 6cfe85bc37e..f0973e0ba6e 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -113,7 +113,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
                                       out,
                                       ann,
                                       is_expanded);
-    if is_expanded && std_inject::use_std(krate) {
+    if is_expanded && !std_inject::no_std(krate) {
         // We need to print `#![no_std]` (and its feature gate) so that
         // compiling pretty-printed source won't inject libstd again.
         // However we don't want these attributes in the AST because
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index 9787f2537c6..d41a8ff140c 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -41,52 +41,57 @@ fn ignored_span(sess: &ParseSess, sp: Span) -> Span {
 
 pub fn maybe_inject_crates_ref(krate: ast::Crate, alt_std_name: Option<String>)
                                -> ast::Crate {
-    if use_std(&krate) {
-        inject_crates_ref(krate, alt_std_name)
-    } else {
+    if no_core(&krate) {
         krate
+    } else {
+        let name = if no_std(&krate) {"core"} else {"std"};
+        let mut fold = CrateInjector {
+            item_name: token::str_to_ident(name),
+            crate_name: token::intern(&alt_std_name.unwrap_or(name.to_string())),
+        };
+        fold.fold_crate(krate)
     }
 }
 
 pub fn maybe_inject_prelude(sess: &ParseSess, krate: ast::Crate) -> ast::Crate {
-    if use_std(&krate) {
+    if no_core(&krate) {
+        krate
+    } else {
+        let name = if no_std(&krate) {"core"} else {"std"};
         let mut fold = PreludeInjector {
-            span: ignored_span(sess, DUMMY_SP)
+            span: ignored_span(sess, DUMMY_SP),
+            crate_identifier: token::str_to_ident(name),
         };
         fold.fold_crate(krate)
-    } else {
-        krate
     }
 }
 
-pub fn use_std(krate: &ast::Crate) -> bool {
-    !attr::contains_name(&krate.attrs, "no_std")
+pub fn no_core(krate: &ast::Crate) -> bool {
+    attr::contains_name(&krate.attrs, "no_core")
+}
+
+pub fn no_std(krate: &ast::Crate) -> bool {
+    attr::contains_name(&krate.attrs, "no_std") || no_core(krate)
 }
 
 fn no_prelude(attrs: &[ast::Attribute]) -> bool {
     attr::contains_name(attrs, "no_implicit_prelude")
 }
 
-struct StandardLibraryInjector {
-    alt_std_name: Option<String>,
+struct CrateInjector {
+    item_name: ast::Ident,
+    crate_name: ast::Name,
 }
 
-impl fold::Folder for StandardLibraryInjector {
+impl fold::Folder for CrateInjector {
     fn fold_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
-
-        // The name to use in `extern crate name as std;`
-        let actual_crate_name = match self.alt_std_name {
-            Some(ref s) => token::intern(&s),
-            None => token::intern("std"),
-        };
-
         krate.module.items.insert(0, P(ast::Item {
             id: ast::DUMMY_NODE_ID,
-            ident: token::str_to_ident("std"),
+            ident: self.item_name,
             attrs: vec!(
                 attr::mk_attr_outer(attr::mk_attr_id(), attr::mk_word_item(
                         InternedString::new("macro_use")))),
-            node: ast::ItemExternCrate(Some(actual_crate_name)),
+            node: ast::ItemExternCrate(Some(self.crate_name)),
             vis: ast::Inherited,
             span: DUMMY_SP
         }));
@@ -95,15 +100,9 @@ impl fold::Folder for StandardLibraryInjector {
     }
 }
 
-fn inject_crates_ref(krate: ast::Crate, alt_std_name: Option<String>) -> ast::Crate {
-    let mut fold = StandardLibraryInjector {
-        alt_std_name: alt_std_name
-    };
-    fold.fold_crate(krate)
-}
-
 struct PreludeInjector {
-    span: Span
+    span: Span,
+    crate_identifier: ast::Ident,
 }
 
 impl fold::Folder for PreludeInjector {
@@ -134,7 +133,7 @@ impl fold::Folder for PreludeInjector {
             global: false,
             segments: vec![
                 ast::PathSegment {
-                    identifier: token::str_to_ident("std"),
+                    identifier: self.crate_identifier,
                     parameters: ast::PathParameters::none(),
                 },
                 ast::PathSegment {
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index cbc7b38b1ed..2408e6b65a3 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -258,6 +258,7 @@ fn generate_test_harness(sess: &ParseSess,
         config: krate.config.clone(),
         toplevel_reexport: None,
     };
+    cx.ext_cx.crate_root = Some("std");
 
     cx.ext_cx.bt_push(ExpnInfo {
         call_site: DUMMY_SP,