about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorJoshua Barretto <barry.of.smith@gmail.com>2018-04-05 20:59:32 +0100
committerGitHub <noreply@github.com>2018-04-05 20:59:32 +0100
commit5e94d5498d3a24418185a1783f2819cbb2280ddd (patch)
treead100bc79003d246837e5fc080b23f675d8c17c6 /src/libsyntax
parent446285e45c02f71392c7084328dc167d2e1ff58c (diff)
parent7222241e7c2d7caf9ad6ee6e34748e4addfb8dd3 (diff)
downloadrust-5e94d5498d3a24418185a1783f2819cbb2280ddd.tar.gz
rust-5e94d5498d3a24418185a1783f2819cbb2280ddd.zip
Merge pull request #1 from rust-lang/master
Merge upstream changes
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs12
-rw-r--r--src/libsyntax/attr.rs13
-rw-r--r--src/libsyntax/config.rs33
-rw-r--r--src/libsyntax/diagnostic_list.rs12
-rw-r--r--src/libsyntax/diagnostics/plugin.rs10
-rw-r--r--src/libsyntax/edition.rs (renamed from src/libsyntax/epoch.rs)51
-rw-r--r--src/libsyntax/ext/base.rs13
-rw-r--r--src/libsyntax/ext/build.rs10
-rw-r--r--src/libsyntax/ext/expand.rs89
-rw-r--r--src/libsyntax/ext/quote.rs12
-rw-r--r--src/libsyntax/ext/tt/macro_parser.rs21
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs6
-rw-r--r--src/libsyntax/ext/tt/quoted.rs6
-rw-r--r--src/libsyntax/ext/tt/transcribe.rs2
-rw-r--r--src/libsyntax/feature_gate.rs183
-rw-r--r--src/libsyntax/fold.rs8
-rw-r--r--src/libsyntax/lib.rs6
-rw-r--r--src/libsyntax/parse/lexer/mod.rs74
-rw-r--r--src/libsyntax/parse/mod.rs27
-rw-r--r--src/libsyntax/parse/obsolete.rs67
-rw-r--r--src/libsyntax/parse/parser.rs61
-rw-r--r--src/libsyntax/parse/token.rs94
-rw-r--r--src/libsyntax/print/pprust.rs59
-rw-r--r--src/libsyntax/test.rs31
-rw-r--r--src/libsyntax/tokenstream.rs2
-rw-r--r--src/libsyntax/util/parser.rs14
-rw-r--r--src/libsyntax/visit.rs4
27 files changed, 487 insertions, 433 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 1f16b728cd2..31bb1c88b87 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -112,7 +112,7 @@ impl Path {
     // or starts with something like `self`/`super`/`$crate`/etc.
     pub fn make_root(&self) -> Option<PathSegment> {
         if let Some(ident) = self.segments.get(0).map(|seg| seg.identifier) {
-            if ::parse::token::Ident(ident).is_path_segment_keyword() &&
+            if ::parse::token::is_path_segment_keyword(ident) &&
                ident.name != keywords::Crate.name() {
                 return None;
             }
@@ -837,6 +837,13 @@ impl Stmt {
             _ => false,
         }
     }
+
+    pub fn is_expr(&self) -> bool {
+        match self.node {
+            StmtKind::Expr(_) => true,
+            _ => false,
+        }
+    }
 }
 
 impl fmt::Debug for Stmt {
@@ -1004,7 +1011,6 @@ impl Expr {
     pub fn precedence(&self) -> ExprPrecedence {
         match self.node {
             ExprKind::Box(_) => ExprPrecedence::Box,
-            ExprKind::InPlace(..) => ExprPrecedence::InPlace,
             ExprKind::Array(_) => ExprPrecedence::Array,
             ExprKind::Call(..) => ExprPrecedence::Call,
             ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
@@ -1064,8 +1070,6 @@ pub enum RangeLimits {
 pub enum ExprKind {
     /// A `box x` expression.
     Box(P<Expr>),
-    /// First expr is the place; second expr is the value.
-    InPlace(P<Expr>, P<Expr>),
     /// An array (`[a, b, c, d]`)
     Array(Vec<P<Expr>>),
     /// A function call
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index f2cdcda98da..5954b9eb274 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -1106,7 +1106,8 @@ impl IntType {
 
 impl MetaItem {
     fn tokens(&self) -> TokenStream {
-        let ident = TokenTree::Token(self.span, Token::Ident(Ident::with_empty_ctxt(self.name)));
+        let ident = TokenTree::Token(self.span,
+                                     Token::from_ast_ident(Ident::with_empty_ctxt(self.name)));
         TokenStream::concat(vec![ident.into(), self.node.tokens(self.span)])
     }
 
@@ -1114,9 +1115,9 @@ impl MetaItem {
         where I: Iterator<Item = TokenTree>,
     {
         let (span, name) = match tokens.next() {
-            Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name),
+            Some(TokenTree::Token(span, Token::Ident(ident, _))) => (span, ident.name),
             Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match nt.0 {
-                token::Nonterminal::NtIdent(ident) => (ident.span, ident.node.name),
+                token::Nonterminal::NtIdent(ident, _) => (ident.span, ident.node.name),
                 token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()),
                 _ => return None,
             },
@@ -1269,14 +1270,14 @@ impl LitKind {
                 "true"
             } else {
                 "false"
-            }))),
+            })), false),
         }
     }
 
     fn from_token(token: Token) -> Option<LitKind> {
         match token {
-            Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)),
-            Token::Ident(ident) if ident.name == "false" => Some(LitKind::Bool(false)),
+            Token::Ident(ident, false) if ident.name == "true" => Some(LitKind::Bool(true)),
+            Token::Ident(ident, false) if ident.name == "false" => Some(LitKind::Bool(false)),
             Token::Interpolated(ref nt) => match nt.0 {
                 token::NtExpr(ref v) => match v.node {
                     ExprKind::Lit(ref lit) => Some(lit.node.clone()),
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 6013c20daf2..c0855d470c8 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -13,7 +13,7 @@ use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features
 use {fold, attr};
 use ast;
 use codemap::Spanned;
-use epoch::Epoch;
+use edition::Edition;
 use parse::{token, ParseSess};
 
 use ptr::P;
@@ -27,7 +27,7 @@ pub struct StripUnconfigured<'a> {
 }
 
 // `cfg_attr`-process the crate's attributes and compute the crate's features.
-pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool, epoch: Epoch)
+pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool, edition: Edition)
                 -> (ast::Crate, Features) {
     let features;
     {
@@ -47,7 +47,7 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool, epoc
             return (krate, Features::new());
         }
 
-        features = get_features(&sess.span_diagnostic, &krate.attrs, epoch);
+        features = get_features(&sess.span_diagnostic, &krate.attrs, edition);
 
         // Avoid reconfiguring malformed `cfg_attr`s
         if err_count == sess.span_diagnostic.err_count() {
@@ -149,17 +149,24 @@ impl<'a> StripUnconfigured<'a> {
     fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
         // flag the offending attributes
         for attr in attrs.iter() {
-            if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
-                let mut err = feature_err(self.sess,
-                                          "stmt_expr_attributes",
-                                          attr.span,
-                                          GateIssue::Language,
-                                          EXPLAIN_STMT_ATTR_SYNTAX);
-                if attr.is_sugared_doc {
-                    err.help("`///` is for documentation comments. For a plain comment, use `//`.");
-                }
-                err.emit();
+            self.maybe_emit_expr_attr_err(attr);
+        }
+    }
+
+    /// If attributes are not allowed on expressions, emit an error for `attr`
+    pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) {
+        if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
+            let mut err = feature_err(self.sess,
+                                      "stmt_expr_attributes",
+                                      attr.span,
+                                      GateIssue::Language,
+                                      EXPLAIN_STMT_ATTR_SYNTAX);
+
+            if attr.is_sugared_doc {
+                err.help("`///` is for documentation comments. For a plain comment, use `//`.");
             }
+
+            err.emit();
         }
     }
 
diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs
index 1f87c1b94c5..bb7988e64bc 100644
--- a/src/libsyntax/diagnostic_list.rs
+++ b/src/libsyntax/diagnostic_list.rs
@@ -250,7 +250,10 @@ An unstable feature was used.
 Erroneous code example:
 
 ```compile_fail,E658
-let x = ::std::u128::MAX; // error: use of unstable library feature 'i128'
+#[repr(u128)] // error: use of unstable library feature 'repr128'
+enum Foo {
+    Bar(u64),
+}
 ```
 
 If you're using a stable or a beta version of rustc, you won't be able to use
@@ -261,10 +264,11 @@ If you're using a nightly version of rustc, just add the corresponding feature
 to be able to use it:
 
 ```
-#![feature(i128)]
+#![feature(repr128)]
 
-fn main() {
-    let x = ::std::u128::MAX; // ok!
+#[repr(u128)] // ok!
+enum Foo {
+    Bar(u64),
 }
 ```
 "##,
diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs
index 2c91844da96..aecf32ab6af 100644
--- a/src/libsyntax/diagnostics/plugin.rs
+++ b/src/libsyntax/diagnostics/plugin.rs
@@ -44,7 +44,7 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt,
                                    token_tree: &[TokenTree])
                                    -> Box<MacResult+'cx> {
     let code = match (token_tree.len(), token_tree.get(0)) {
-        (1, Some(&TokenTree::Token(_, token::Ident(code)))) => code,
+        (1, Some(&TokenTree::Token(_, token::Ident(code, _)))) => code,
         _ => unreachable!()
     };
 
@@ -82,10 +82,10 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt,
         token_tree.get(1),
         token_tree.get(2)
     ) {
-        (1, Some(&TokenTree::Token(_, token::Ident(ref code))), None, None) => {
+        (1, Some(&TokenTree::Token(_, token::Ident(ref code, _))), None, None) => {
             (code, None)
         },
-        (3, Some(&TokenTree::Token(_, token::Ident(ref code))),
+        (3, Some(&TokenTree::Token(_, token::Ident(ref code, _))),
             Some(&TokenTree::Token(_, token::Comma)),
             Some(&TokenTree::Token(_, token::Literal(token::StrRaw(description, _), None)))) => {
             (code, Some(description))
@@ -150,9 +150,9 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
     let (crate_name, name) = match (&token_tree[0], &token_tree[2]) {
         (
             // Crate name.
-            &TokenTree::Token(_, token::Ident(ref crate_name)),
+            &TokenTree::Token(_, token::Ident(ref crate_name, _)),
             // DIAGNOSTICS ident.
-            &TokenTree::Token(_, token::Ident(ref name))
+            &TokenTree::Token(_, token::Ident(ref name, _))
         ) => (*&crate_name, name),
         _ => unreachable!()
     };
diff --git a/src/libsyntax/epoch.rs b/src/libsyntax/edition.rs
index 32cbc79c550..e579fc74b42 100644
--- a/src/libsyntax/epoch.rs
+++ b/src/libsyntax/edition.rs
@@ -11,58 +11,65 @@
 use std::fmt;
 use std::str::FromStr;
 
-/// The epoch of the compiler (RFC 2052)
+/// The edition of the compiler (RFC 2052)
 #[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug)]
 #[non_exhaustive]
-pub enum Epoch {
-    // epochs must be kept in order, newest to oldest
+pub enum Edition {
+    // editions must be kept in order, newest to oldest
 
-    /// The 2015 epoch
-    Epoch2015,
-    /// The 2018 epoch
-    Epoch2018,
+    /// The 2015 edition
+    Edition2015,
+    /// The 2018 edition
+    Edition2018,
 
-    // when adding new epochs, be sure to update:
+    // when adding new editions, be sure to update:
     //
-    // - the list in the `parse_epoch` static in librustc::session::config
+    // - the list in the `parse_edition` static in librustc::session::config
     // - add a `rust_####()` function to the session
     // - update the enum in Cargo's sources as well
     //
-    // When -Zepoch becomes --epoch, there will
-    // also be a check for the epoch being nightly-only
+    // When -Zedition becomes --edition, there will
+    // also be a check for the edition being nightly-only
     // somewhere. That will need to be updated
-    // whenever we're stabilizing/introducing a new epoch
+    // whenever we're stabilizing/introducing a new edition
     // as well as changing the default Cargo template.
 }
 
 // must be in order from oldest to newest
-pub const ALL_EPOCHS: &[Epoch] = &[Epoch::Epoch2015, Epoch::Epoch2018];
+pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];
 
-impl fmt::Display for Epoch {
+impl fmt::Display for Edition {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let s = match *self {
-            Epoch::Epoch2015 => "2015",
-            Epoch::Epoch2018 => "2018",
+            Edition::Edition2015 => "2015",
+            Edition::Edition2018 => "2018",
         };
         write!(f, "{}", s)
     }
 }
 
-impl Epoch {
+impl Edition {
     pub fn lint_name(&self) -> &'static str {
         match *self {
-            Epoch::Epoch2015 => "epoch_2015",
-            Epoch::Epoch2018 => "epoch_2018",
+            Edition::Edition2015 => "edition_2015",
+            Edition::Edition2018 => "edition_2018",
+        }
+    }
+
+    pub fn feature_name(&self) -> &'static str {
+        match *self {
+            Edition::Edition2015 => "rust_2015_preview",
+            Edition::Edition2018 => "rust_2018_preview",
         }
     }
 }
 
-impl FromStr for Epoch {
+impl FromStr for Edition {
     type Err = ();
     fn from_str(s: &str) -> Result<Self, ()> {
         match s {
-            "2015" => Ok(Epoch::Epoch2015),
-            "2018" => Ok(Epoch::Epoch2018),
+            "2015" => Ok(Edition::Edition2015),
+            "2018" => Ok(Edition::Edition2018),
             _ => Err(())
         }
     }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 23c42972912..d3157af984e 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -38,6 +38,8 @@ pub enum Annotatable {
     Item(P<ast::Item>),
     TraitItem(P<ast::TraitItem>),
     ImplItem(P<ast::ImplItem>),
+    Stmt(P<ast::Stmt>),
+    Expr(P<ast::Expr>),
 }
 
 impl HasAttrs for Annotatable {
@@ -46,6 +48,8 @@ impl HasAttrs for Annotatable {
             Annotatable::Item(ref item) => &item.attrs,
             Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
             Annotatable::ImplItem(ref impl_item) => &impl_item.attrs,
+            Annotatable::Stmt(ref stmt) => stmt.attrs(),
+            Annotatable::Expr(ref expr) => &expr.attrs,
         }
     }
 
@@ -54,6 +58,8 @@ impl HasAttrs for Annotatable {
             Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
             Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)),
             Annotatable::ImplItem(impl_item) => Annotatable::ImplItem(impl_item.map_attrs(f)),
+            Annotatable::Stmt(stmt) => Annotatable::Stmt(stmt.map_attrs(f)),
+            Annotatable::Expr(expr) => Annotatable::Expr(expr.map_attrs(f)),
         }
     }
 }
@@ -64,6 +70,8 @@ impl Annotatable {
             Annotatable::Item(ref item) => item.span,
             Annotatable::TraitItem(ref trait_item) => trait_item.span,
             Annotatable::ImplItem(ref impl_item) => impl_item.span,
+            Annotatable::Stmt(ref stmt) => stmt.span,
+            Annotatable::Expr(ref expr) => expr.span,
         }
     }
 
@@ -229,8 +237,9 @@ impl<F> TTMacroExpander for F
         impl Folder for AvoidInterpolatedIdents {
             fn fold_tt(&mut self, tt: tokenstream::TokenTree) -> tokenstream::TokenTree {
                 if let tokenstream::TokenTree::Token(_, token::Interpolated(ref nt)) = tt {
-                    if let token::NtIdent(ident) = nt.0 {
-                        return tokenstream::TokenTree::Token(ident.span, token::Ident(ident.node));
+                    if let token::NtIdent(ident, is_raw) = nt.0 {
+                        return tokenstream::TokenTree::Token(ident.span,
+                                                             token::Ident(ident.node, is_raw));
                     }
                 }
                 fold::noop_fold_tt(tt, self)
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 9b53553bf69..269517e998f 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -214,7 +214,7 @@ pub trait AstBuilder {
 
     fn arg(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> ast::Arg;
     // FIXME unused self
-    fn fn_decl(&self, inputs: Vec<ast::Arg> , output: P<ast::Ty>) -> P<ast::FnDecl>;
+    fn fn_decl(&self, inputs: Vec<ast::Arg> , output: ast::FunctionRetTy) -> P<ast::FnDecl>;
 
     fn item_fn_poly(&self,
                     span: Span,
@@ -924,7 +924,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
               -> P<ast::Expr> {
         let fn_decl = self.fn_decl(
             ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(),
-            self.ty_infer(span));
+            ast::FunctionRetTy::Default(span));
 
         // FIXME -- We are using `span` as the span of the `|...|`
         // part of the lambda, but it probably (maybe?) corresponds to
@@ -970,10 +970,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     }
 
     // FIXME unused self
-    fn fn_decl(&self, inputs: Vec<ast::Arg>, output: P<ast::Ty>) -> P<ast::FnDecl> {
+    fn fn_decl(&self, inputs: Vec<ast::Arg>, output: ast::FunctionRetTy) -> P<ast::FnDecl> {
         P(ast::FnDecl {
             inputs,
-            output: ast::FunctionRetTy::Ty(output),
+            output,
             variadic: false
         })
     }
@@ -1003,7 +1003,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         self.item(span,
                   name,
                   Vec::new(),
-                  ast::ItemKind::Fn(self.fn_decl(inputs, output),
+                  ast::ItemKind::Fn(self.fn_decl(inputs, ast::FunctionRetTy::Ty(output)),
                               ast::Unsafety::Normal,
                               dummy_spanned(ast::Constness::NotConst),
                               Abi::Rust,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 34dd7696168..864969c4075 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -435,6 +435,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             Annotatable::ImplItem(item) => {
                 Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap()))
             }
+            Annotatable::Stmt(stmt) => {
+                Annotatable::Stmt(stmt.map(|stmt| cfg.fold_stmt(stmt).pop().unwrap()))
+            }
+            Annotatable::Expr(expr) => {
+                Annotatable::Expr(cfg.fold_expr(expr))
+            }
         }
     }
 
@@ -503,6 +509,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     Annotatable::Item(item) => token::NtItem(item),
                     Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
                     Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()),
+                    Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
+                    Annotatable::Expr(expr) => token::NtExpr(expr),
                 })).into();
                 let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok);
                 self.parse_expansion(tok_result, kind, &attr.path, attr.span)
@@ -751,6 +759,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 Some(expansion)
             }
             Err(mut err) => {
+                err.set_span(span);
                 err.emit();
                 self.cx.trace_macros_diag();
                 kind.dummy(span)
@@ -796,7 +805,13 @@ impl<'a> Parser<'a> {
                 Expansion::Stmts(stmts)
             }
             ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?),
-            ExpansionKind::OptExpr => Expansion::OptExpr(Some(self.parse_expr()?)),
+            ExpansionKind::OptExpr => {
+                if self.token != token::Eof {
+                    Expansion::OptExpr(Some(self.parse_expr()?))
+                } else {
+                    Expansion::OptExpr(None)
+                }
+            },
             ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?),
             ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?),
         })
@@ -904,6 +919,18 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
         let mut expr = self.cfg.configure_expr(expr).into_inner();
         expr.node = self.cfg.configure_expr_kind(expr.node);
 
+        let (attr, derives, expr) = self.classify_item(expr);
+
+        if attr.is_some() || !derives.is_empty() {
+            // collect the invoc regardless of whether or not attributes are permitted here
+            // expansion will eat the attribute so it won't error later
+            attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
+
+            // ExpansionKind::Expr requires the macro to emit an expression
+            return self.collect_attr(attr, derives, Annotatable::Expr(P(expr)), ExpansionKind::Expr)
+                .make_expr();
+        }
+
         if let ast::ExprKind::Mac(mac) = expr.node {
             self.check_attributes(&expr.attrs);
             self.collect_bang(mac, expr.span, ExpansionKind::Expr).make_expr()
@@ -916,6 +943,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
         let mut expr = configure!(self, expr).into_inner();
         expr.node = self.cfg.configure_expr_kind(expr.node);
 
+        let (attr, derives, expr) = self.classify_item(expr);
+
+        if attr.is_some() || !derives.is_empty() {
+            attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
+
+            return self.collect_attr(attr, derives, Annotatable::Expr(P(expr)),
+                                     ExpansionKind::OptExpr)
+                .make_opt_expr();
+        }
+
         if let ast::ExprKind::Mac(mac) = expr.node {
             self.check_attributes(&expr.attrs);
             self.collect_bang(mac, expr.span, ExpansionKind::OptExpr).make_opt_expr()
@@ -938,33 +975,47 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
     }
 
     fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
-        let stmt = match self.cfg.configure_stmt(stmt) {
+        let mut stmt = match self.cfg.configure_stmt(stmt) {
             Some(stmt) => stmt,
             None => return SmallVector::new(),
         };
 
-        let (mac, style, attrs) = if let StmtKind::Mac(mac) = stmt.node {
-            mac.into_inner()
-        } else {
-            // The placeholder expander gives ids to statements, so we avoid folding the id here.
-            let ast::Stmt { id, node, span } = stmt;
-            return noop_fold_stmt_kind(node, self).into_iter().map(|node| {
-                ast::Stmt { id: id, node: node, span: span }
-            }).collect()
-        };
+        // we'll expand attributes on expressions separately
+        if !stmt.is_expr() {
+            let (attr, derives, stmt_) = self.classify_item(stmt);
+
+            if attr.is_some() || !derives.is_empty() {
+                return self.collect_attr(attr, derives,
+                                         Annotatable::Stmt(P(stmt_)), ExpansionKind::Stmts)
+                    .make_stmts();
+            }
 
-        self.check_attributes(&attrs);
-        let mut placeholder = self.collect_bang(mac, stmt.span, ExpansionKind::Stmts).make_stmts();
+            stmt = stmt_;
+        }
 
-        // If this is a macro invocation with a semicolon, then apply that
-        // semicolon to the final statement produced by expansion.
-        if style == MacStmtStyle::Semicolon {
-            if let Some(stmt) = placeholder.pop() {
-                placeholder.push(stmt.add_trailing_semicolon());
+        if let StmtKind::Mac(mac) = stmt.node {
+            let (mac, style, attrs) = mac.into_inner();
+            self.check_attributes(&attrs);
+            let mut placeholder = self.collect_bang(mac, stmt.span, ExpansionKind::Stmts)
+                                        .make_stmts();
+
+            // If this is a macro invocation with a semicolon, then apply that
+            // semicolon to the final statement produced by expansion.
+            if style == MacStmtStyle::Semicolon {
+                if let Some(stmt) = placeholder.pop() {
+                    placeholder.push(stmt.add_trailing_semicolon());
+                }
             }
+
+            return placeholder;
         }
 
-        placeholder
+        // The placeholder expander gives ids to statements, so we avoid folding the id here.
+        let ast::Stmt { id, node, span } = stmt;
+        noop_fold_stmt_kind(node, self).into_iter().map(|node| {
+            ast::Stmt { id, node, span }
+        }).collect()
+
     }
 
     fn fold_block(&mut self, block: P<Block>) -> P<Block> {
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index 6844532e7b3..540a03ff032 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -75,7 +75,7 @@ pub mod rt {
 
     impl ToTokens for ast::Ident {
         fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
-            vec![TokenTree::Token(DUMMY_SP, token::Ident(*self))]
+            vec![TokenTree::Token(DUMMY_SP, Token::from_ast_ident(*self))]
         }
     }
 
@@ -238,7 +238,9 @@ pub mod rt {
                 if i > 0 {
                     inner.push(TokenTree::Token(self.span, token::Colon).into());
                 }
-                inner.push(TokenTree::Token(self.span, token::Ident(segment.identifier)).into());
+                inner.push(TokenTree::Token(
+                    self.span, token::Token::from_ast_ident(segment.identifier)
+                ).into());
             }
             inner.push(self.tokens.clone());
 
@@ -658,10 +660,10 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
         token::Literal(token::ByteStr(i), suf) => return mk_lit!("ByteStr", suf, i),
         token::Literal(token::ByteStrRaw(i, n), suf) => return mk_lit!("ByteStrRaw", suf, i, n),
 
-        token::Ident(ident) => {
+        token::Ident(ident, is_raw) => {
             return cx.expr_call(sp,
                                 mk_token_path(cx, sp, "Ident"),
-                                vec![mk_ident(cx, sp, ident)]);
+                                vec![mk_ident(cx, sp, ident), cx.expr_bool(sp, is_raw)]);
         }
 
         token::Lifetime(ident) => {
@@ -720,7 +722,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
 
 fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, quoted: bool) -> Vec<ast::Stmt> {
     match *tt {
-        TokenTree::Token(sp, token::Ident(ident)) if quoted => {
+        TokenTree::Token(sp, token::Ident(ident, _)) if quoted => {
             // tt.extend($ident.to_tokens(ext_cx))
 
             let e_to_toks =
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 667653b5f7f..8cb331c65da 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -364,8 +364,8 @@ pub fn parse_failure_msg(tok: Token) -> String {
 
 /// Perform a token equality check, ignoring syntax context (that is, an unhygienic comparison)
 fn token_name_eq(t1: &Token, t2: &Token) -> bool {
-    if let (Some(id1), Some(id2)) = (t1.ident(), t2.ident()) {
-        id1.name == id2.name
+    if let (Some((id1, is_raw1)), Some((id2, is_raw2))) = (t1.ident(), t2.ident()) {
+        id1.name == id2.name && is_raw1 == is_raw2
     } else if let (&token::Lifetime(id1), &token::Lifetime(id2)) = (t1, t2) {
         id1.name == id2.name
     } else {
@@ -711,9 +711,10 @@ pub fn parse(
 
 /// The token is an identifier, but not `_`.
 /// We prohibit passing `_` to macros expecting `ident` for now.
-fn get_macro_ident(token: &Token) -> Option<Ident> {
+fn get_macro_ident(token: &Token) -> Option<(Ident, bool)> {
     match *token {
-        token::Ident(ident) if ident.name != keywords::Underscore.name() => Some(ident),
+        token::Ident(ident, is_raw) if ident.name != keywords::Underscore.name() =>
+            Some((ident, is_raw)),
         _ => None,
     }
 }
@@ -737,7 +738,7 @@ fn may_begin_with(name: &str, token: &Token) -> bool {
         "ident" => get_macro_ident(token).is_some(),
         "vis" => match *token {
             // The follow-set of :vis + "priv" keyword + interpolated
-            Token::Comma | Token::Ident(_) | Token::Interpolated(_) => true,
+            Token::Comma | Token::Ident(..) | Token::Interpolated(_) => true,
             _ => token.can_begin_type(),
         },
         "block" => match *token {
@@ -746,7 +747,7 @@ fn may_begin_with(name: &str, token: &Token) -> bool {
                 token::NtItem(_)
                 | token::NtPat(_)
                 | token::NtTy(_)
-                | token::NtIdent(_)
+                | token::NtIdent(..)
                 | token::NtMeta(_)
                 | token::NtPath(_)
                 | token::NtVis(_) => false, // none of these may start with '{'.
@@ -755,7 +756,7 @@ fn may_begin_with(name: &str, token: &Token) -> bool {
             _ => false,
         },
         "path" | "meta" => match *token {
-            Token::ModSep | Token::Ident(_) => true,
+            Token::ModSep | Token::Ident(..) => true,
             Token::Interpolated(ref nt) => match nt.0 {
                 token::NtPath(_) | token::NtMeta(_) => true,
                 _ => may_be_ident(&nt.0),
@@ -763,7 +764,7 @@ fn may_begin_with(name: &str, token: &Token) -> bool {
             _ => false,
         },
         "pat" => match *token {
-            Token::Ident(_) |               // box, ref, mut, and other identifiers (can stricten)
+            Token::Ident(..) |               // box, ref, mut, and other identifiers (can stricten)
             Token::OpenDelim(token::Paren) |    // tuple pattern
             Token::OpenDelim(token::Bracket) |  // slice pattern
             Token::BinOp(token::And) |          // reference
@@ -823,9 +824,9 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
         "expr" => token::NtExpr(panictry!(p.parse_expr())),
         "ty" => token::NtTy(panictry!(p.parse_ty())),
         // this could be handled like a token, since it is one
-        "ident" => if let Some(ident) = get_macro_ident(&p.token) {
+        "ident" => if let Some((ident, is_raw)) = get_macro_ident(&p.token) {
             p.bump();
-            token::NtIdent(respan(p.prev_span, ident))
+            token::NtIdent(respan(p.prev_span, ident), is_raw)
         } else {
             let token_str = pprust::token_to_string(&p.token);
             p.fatal(&format!("expected ident, found {}", &token_str)).emit();
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index a4b2c3990f5..10e5926eb9e 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -831,7 +831,7 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
             "pat" => match *tok {
                 TokenTree::Token(_, ref tok) => match *tok {
                     FatArrow | Comma | Eq | BinOp(token::Or) => Ok(true),
-                    Ident(i) if i.name == "if" || i.name == "in" => Ok(true),
+                    Ident(i, false) if i.name == "if" || i.name == "in" => Ok(true),
                     _ => Ok(false)
                 },
                 _ => Ok(false),
@@ -840,7 +840,7 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
                 TokenTree::Token(_, ref tok) => match *tok {
                     OpenDelim(token::DelimToken::Brace) | OpenDelim(token::DelimToken::Bracket) |
                     Comma | FatArrow | Colon | Eq | Gt | Semi | BinOp(token::Or) => Ok(true),
-                    Ident(i) if i.name == "as" || i.name == "where" => Ok(true),
+                    Ident(i, false) if i.name == "as" || i.name == "where" => Ok(true),
                     _ => Ok(false)
                 },
                 TokenTree::MetaVarDecl(_, _, frag) if frag.name == "block" => Ok(true),
@@ -860,7 +860,7 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
                 match *tok {
                     TokenTree::Token(_, ref tok) => match *tok {
                         Comma => Ok(true),
-                        Ident(i) if i.name != "priv" => Ok(true),
+                        Ident(i, is_raw) if is_raw || i.name != "priv" => Ok(true),
                         ref tok => Ok(tok.can_begin_type())
                     },
                     TokenTree::MetaVarDecl(_, _, frag) if frag.name == "ident"
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index 122bb9ba024..f324edeb117 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -200,7 +200,7 @@ pub fn parse(
                 let span = match trees.next() {
                     Some(tokenstream::TokenTree::Token(span, token::Colon)) => match trees.next() {
                         Some(tokenstream::TokenTree::Token(end_sp, ref tok)) => match tok.ident() {
-                            Some(kind) => {
+                            Some((kind, _)) => {
                                 let span = end_sp.with_lo(start_sp.lo());
                                 result.push(TokenTree::MetaVarDecl(span, ident, kind));
                                 continue;
@@ -289,14 +289,14 @@ where
             // `tree` is followed by an `ident`. This could be `$meta_var` or the `$crate` special
             // metavariable that names the crate of the invokation.
             Some(tokenstream::TokenTree::Token(ident_span, ref token)) if token.is_ident() => {
-                let ident = token.ident().unwrap();
+                let (ident, _) = token.ident().unwrap();
                 let span = ident_span.with_lo(span.lo());
                 if ident.name == keywords::Crate.name() {
                     let ident = ast::Ident {
                         name: keywords::DollarCrate.name(),
                         ..ident
                     };
-                    TokenTree::Token(span, token::Ident(ident))
+                    TokenTree::Token(span, token::Ident(ident, false))
                 } else {
                     TokenTree::MetaVar(span, ident)
                 }
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 7883c4bbc16..3f01d5ec6dd 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -169,7 +169,7 @@ pub fn transcribe(cx: &ExtCtxt,
                         Ident { ctxt: ident.ctxt.apply_mark(cx.current_expansion.mark), ..ident };
                     sp = sp.with_ctxt(sp.ctxt().apply_mark(cx.current_expansion.mark));
                     result.push(TokenTree::Token(sp, token::Dollar).into());
-                    result.push(TokenTree::Token(sp, token::Ident(ident)).into());
+                    result.push(TokenTree::Token(sp, token::Token::from_ast_ident(ident)).into());
                 }
             }
             quoted::TokenTree::Delimited(mut span, delimited) => {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 915396d29fe..0f039895dee 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -28,7 +28,7 @@ use self::AttributeGate::*;
 use abi::Abi;
 use ast::{self, NodeId, PatKind, RangeEnd};
 use attr;
-use epoch::Epoch;
+use edition::{ALL_EDITIONS, Edition};
 use codemap::Spanned;
 use syntax_pos::{Span, DUMMY_SP};
 use errors::{DiagnosticBuilder, Handler, FatalError};
@@ -55,13 +55,13 @@ macro_rules! set {
 }
 
 macro_rules! declare_features {
-    ($((active, $feature: ident, $ver: expr, $issue: expr, $epoch: expr),)+) => {
+    ($((active, $feature: ident, $ver: expr, $issue: expr, $edition: expr),)+) => {
         /// Represents active features that are currently being implemented or
         /// currently being considered for addition/removal.
         const ACTIVE_FEATURES:
                 &'static [(&'static str, &'static str, Option<u32>,
-                           Option<Epoch>, fn(&mut Features, Span))] =
-            &[$((stringify!($feature), $ver, $issue, $epoch, set!($feature))),+];
+                           Option<Edition>, fn(&mut Features, Span))] =
+            &[$((stringify!($feature), $ver, $issue, $edition, set!($feature))),+];
 
         /// A set of features to be used by later passes.
         #[derive(Clone)]
@@ -146,7 +146,6 @@ declare_features! (
     (active, rustc_diagnostic_macros, "1.0.0", None, None),
     (active, rustc_const_unstable, "1.0.0", None, None),
     (active, box_syntax, "1.0.0", Some(27779), None),
-    (active, placement_in_syntax, "1.0.0", Some(27779), None),
     (active, unboxed_closures, "1.0.0", Some(29625), None),
 
     (active, fundamental, "1.0.0", Some(29635), None),
@@ -194,7 +193,7 @@ declare_features! (
     (active, rustc_attrs, "1.0.0", Some(29642), None),
 
     // Allows the use of non lexical lifetimes; RFC 2094
-    (active, nll, "1.0.0", Some(43234), None),
+    (active, nll, "1.0.0", Some(43234), Some(Edition::Edition2018)),
 
     // Allows the use of #[allow_internal_unstable]. This is an
     // attribute on macro_rules! and can't use the attribute handling
@@ -276,12 +275,6 @@ declare_features! (
     // Allows cfg(target_has_atomic = "...").
     (active, cfg_target_has_atomic, "1.9.0", Some(32976), None),
 
-    // Allows `impl Trait` in function return types.
-    (active, conservative_impl_trait, "1.12.0", Some(34511), None),
-
-    // Allows `impl Trait` in function arguments.
-    (active, universal_impl_trait, "1.23.0", Some(34511), None),
-
     // Allows exhaustive pattern matching on types that contain uninhabited types.
     (active, exhaustive_patterns, "1.13.0", None, None),
 
@@ -295,9 +288,6 @@ declare_features! (
     // rustc internal
     (active, compiler_builtins, "1.13.0", None, None),
 
-    // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
-    (active, generic_param_attrs, "1.11.0", Some(34761), None),
-
     // Allows #[link(..., cfg(..))]
     (active, link_cfg, "1.14.0", Some(37406), None),
 
@@ -309,9 +299,6 @@ declare_features! (
     // `extern "ptx-*" fn()`
     (active, abi_ptx, "1.15.0", None, None),
 
-    // The `i128` type
-    (active, i128_type, "1.16.0", Some(35118), None),
-
     // The `repr(i128)` annotation for enums
     (active, repr128, "1.16.0", Some(35118), None),
 
@@ -391,10 +378,6 @@ declare_features! (
     // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
     (active, non_exhaustive, "1.22.0", Some(44109), None),
 
-    // Copy/Clone closures (RFC 2132)
-    (active, clone_closures, "1.22.0", Some(44490), None),
-    (active, copy_closures, "1.22.0", Some(44490), None),
-
     // allow `'_` placeholder lifetimes
     (active, underscore_lifetimes, "1.22.0", Some(44524), None),
 
@@ -402,10 +385,10 @@ declare_features! (
     (active, match_default_bindings, "1.22.0", Some(42640), None),
 
     // Trait object syntax with `dyn` prefix
-    (active, dyn_trait, "1.22.0", Some(44662), Some(Epoch::Epoch2018)),
+    (active, dyn_trait, "1.22.0", Some(44662), Some(Edition::Edition2018)),
 
     // `crate` as visibility modifier, synonymous to `pub(crate)`
-    (active, crate_visibility_modifier, "1.23.0", Some(45388), None),
+    (active, crate_visibility_modifier, "1.23.0", Some(45388), Some(Edition::Edition2018)),
 
     // extern types
     (active, extern_types, "1.23.0", Some(43467), None),
@@ -414,10 +397,10 @@ declare_features! (
     (active, arbitrary_self_types, "1.23.0", Some(44874), None),
 
     // `crate` in paths
-    (active, crate_in_paths, "1.23.0", Some(45477), None),
+    (active, crate_in_paths, "1.23.0", Some(45477), Some(Edition::Edition2018)),
 
     // In-band lifetime bindings (e.g. `fn foo(x: &'a u8) -> &'a u8`)
-    (active, in_band_lifetimes, "1.23.0", Some(44524), None),
+    (active, in_band_lifetimes, "1.23.0", Some(44524), Some(Edition::Edition2018)),
 
     // generic associated types (RFC 1598)
     (active, generic_associated_types, "1.23.0", Some(44265), None),
@@ -426,10 +409,10 @@ declare_features! (
     (active, extern_absolute_paths, "1.24.0", Some(44660), None),
 
     // `foo.rs` as an alternative to `foo/mod.rs`
-    (active, non_modrs_mods, "1.24.0", Some(44660), None),
+    (active, non_modrs_mods, "1.24.0", Some(44660), Some(Edition::Edition2018)),
 
-    // Termination trait in main (RFC 1937)
-    (active, termination_trait, "1.24.0", Some(43301), None),
+    // Termination trait in tests (RFC 1937)
+    (active, termination_trait_test, "1.24.0", Some(48854), Some(Edition::Edition2018)),
 
     // Allows use of the :lifetime macro fragment specifier
     (active, macro_lifetime_matcher, "1.24.0", Some(46895), None),
@@ -451,6 +434,15 @@ declare_features! (
 
     // `use path as _;` and `extern crate c as _;`
     (active, underscore_imports, "1.26.0", Some(48216), None),
+
+    // The #[wasm_custom_section] attribute
+    (active, wasm_custom_section, "1.26.0", None, None),
+
+    // The #![wasm_import_module] attribute
+    (active, wasm_import_module, "1.26.0", None, None),
+
+    // Allows keywords to be escaped for use as identifiers
+    (active, raw_identifiers, "1.26.0", Some(48589), None),
 );
 
 declare_features! (
@@ -556,6 +548,23 @@ declare_features! (
     (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None),
     // allow `..=` in patterns (RFC 1192)
     (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None),
+    // Termination trait in main (RFC 1937)
+    (accepted, termination_trait, "1.26.0", Some(43301), None),
+    // Copy/Clone closures (RFC 2132)
+    (accepted, clone_closures, "1.26.0", Some(44490), None),
+    (accepted, copy_closures, "1.26.0", Some(44490), None),
+    // Allows `impl Trait` in function arguments.
+    (accepted, universal_impl_trait, "1.26.0", Some(34511), None),
+    // Allows `impl Trait` in function return types.
+    (accepted, conservative_impl_trait, "1.26.0", Some(34511), None),
+    // The `i128` type
+    (accepted, i128_type, "1.26.0", Some(35118), None),
+    // Default match binding modes (RFC 2005)
+    (accepted, match_default_bindings, "1.26.0", Some(42640), None),
+    // allow `'_` placeholder lifetimes
+    (accepted, underscore_lifetimes, "1.26.0", Some(44524), None),
+    // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
+    (accepted, generic_param_attrs, "1.26.0", Some(48848), None),
 );
 
 // If you change this, please modify src/doc/unstable-book as well. You must
@@ -917,6 +926,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
         "the `#[no_debug]` attribute was an experimental feature that has been \
          deprecated due to lack of demand",
         cfg_fn!(no_debug))),
+    ("wasm_import_module", Normal, Gated(Stability::Unstable,
+                                 "wasm_import_module",
+                                 "experimental attribute",
+                                 cfg_fn!(wasm_import_module))),
     ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable,
                                                        "omit_gdb_pretty_printer_section",
                                                        "the `#[omit_gdb_pretty_printer_section]` \
@@ -1004,6 +1017,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                  "never will be stable",
                                  cfg_fn!(rustc_attrs))),
 
+    ("wasm_custom_section", Whitelisted, Gated(Stability::Unstable,
+                                 "wasm_custom_section",
+                                 "attribute is currently unstable",
+                                 cfg_fn!(wasm_custom_section))),
+
     // Crate level attributes
     ("crate_name", CrateLevel, Ungated),
     ("crate_type", CrateLevel, Ungated),
@@ -1230,7 +1248,7 @@ const EXPLAIN_BOX_SYNTAX: &'static str =
     "box expression syntax is experimental; you can call `Box::new` instead.";
 
 pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str =
-    "attributes on non-item statements and expressions are experimental.";
+    "attributes on expressions are experimental.";
 
 pub const EXPLAIN_ASM: &'static str =
     "inline assembly is not stable enough for use and is subject to change";
@@ -1267,9 +1285,6 @@ pub const EXPLAIN_VIS_MATCHER: &'static str =
 pub const EXPLAIN_LIFETIME_MATCHER: &'static str =
     ":lifetime fragment specifier is experimental and subject to change";
 
-pub const EXPLAIN_PLACEMENT_IN: &'static str =
-    "placement-in expression syntax is experimental and subject to change.";
-
 pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
     "Unsized tuple coercion is not stable enough for use and is subject to change";
 
@@ -1616,26 +1631,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 gate_feature_post!(&self, type_ascription, e.span,
                                   "type ascription is experimental");
             }
-            ast::ExprKind::InPlace(..) => {
-                gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
-            }
             ast::ExprKind::Yield(..) => {
                 gate_feature_post!(&self, generators,
                                   e.span,
                                   "yield syntax is experimental");
             }
-            ast::ExprKind::Lit(ref lit) => {
-                if let ast::LitKind::Int(_, ref ty) = lit.node {
-                    match *ty {
-                        ast::LitIntType::Signed(ast::IntTy::I128) |
-                        ast::LitIntType::Unsigned(ast::UintTy::U128) => {
-                            gate_feature_post!(&self, i128_type, e.span,
-                                               "128-bit integers are not stable");
-                        }
-                        _ => {}
-                    }
-                }
-            }
             ast::ExprKind::Catch(_) => {
                 gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
             }
@@ -1774,47 +1774,18 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         }
         visit::walk_vis(self, vis);
     }
-
-    fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
-        let (attrs, explain) = match *param {
-            ast::GenericParam::Lifetime(ref ld) =>
-                (&ld.attrs, "attributes on lifetime bindings are experimental"),
-            ast::GenericParam::Type(ref t) =>
-                (&t.attrs, "attributes on type parameter bindings are experimental"),
-        };
-
-        if !attrs.is_empty() {
-            gate_feature_post!(&self, generic_param_attrs, attrs[0].span, explain);
-        }
-
-        visit::walk_generic_param(self, param)
-    }
-
-    fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
-        if lt.ident.name == keywords::UnderscoreLifetime.name() {
-            gate_feature_post!(&self, underscore_lifetimes, lt.span,
-                               "underscore lifetimes are unstable");
-        }
-        visit::walk_lifetime(self, lt)
-    }
 }
 
 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
-                    epoch: Epoch) -> Features {
+                    crate_edition: Edition) -> Features {
+    fn feature_removed(span_handler: &Handler, span: Span) {
+        span_err!(span_handler, span, E0557, "feature has been removed");
+    }
+
     let mut features = Features::new();
 
     let mut feature_checker = FeatureChecker::default();
 
-    for &(.., f_epoch, set) in ACTIVE_FEATURES.iter() {
-        if let Some(f_epoch) = f_epoch {
-            if epoch >= f_epoch {
-                // FIXME(Manishearth) there is currently no way to set
-                // lang features by epoch
-                set(&mut features, DUMMY_SP);
-            }
-        }
-    }
-
     for attr in krate_attrs {
         if !attr.check_name("feature") {
             continue
@@ -1827,6 +1798,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
             }
             Some(list) => {
                 for mi in list {
+
                     let name = if let Some(word) = mi.word() {
                         word.name()
                     } else {
@@ -1844,11 +1816,26 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
                             .find(|& &(n, _, _)| name == n)
                         .or_else(|| STABLE_REMOVED_FEATURES.iter()
                             .find(|& &(n, _, _)| name == n)) {
-                        span_err!(span_handler, mi.span, E0557, "feature has been removed");
+                        feature_removed(span_handler, mi.span);
                     }
                     else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
                         .find(|& &(n, _, _)| name == n) {
                         features.declared_stable_lang_features.push((name, mi.span));
+                    } else if let Some(&edition) = ALL_EDITIONS.iter()
+                                                              .find(|e| name == e.feature_name()) {
+                        if edition <= crate_edition {
+                            feature_removed(span_handler, mi.span);
+                        } else {
+                            for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
+                                if let Some(f_edition) = f_edition {
+                                    if edition >= f_edition {
+                                        // FIXME(Manishearth) there is currently no way to set
+                                        // lib features by edition
+                                        set(&mut features, DUMMY_SP);
+                                    }
+                                }
+                            }
+                        }
                     } else {
                         features.declared_lib_features.push((name, mi.span));
                     }
@@ -1867,8 +1854,6 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
 struct FeatureChecker {
     proc_macro: Option<Span>,
     custom_attribute: Option<Span>,
-    copy_closures: Option<Span>,
-    clone_closures: Option<Span>,
 }
 
 impl FeatureChecker {
@@ -1884,14 +1869,6 @@ impl FeatureChecker {
         if features.custom_attribute {
             self.custom_attribute = self.custom_attribute.or(Some(span));
         }
-
-        if features.copy_closures {
-            self.copy_closures = self.copy_closures.or(Some(span));
-        }
-
-        if features.clone_closures {
-            self.clone_closures = self.clone_closures.or(Some(span));
-        }
     }
 
     fn check(self, handler: &Handler) {
@@ -1903,15 +1880,6 @@ impl FeatureChecker {
 
             FatalError.raise();
         }
-
-        if let (Some(span), None) = (self.copy_closures, self.clone_closures) {
-            handler.struct_span_err(span, "`#![feature(copy_closures)]` can only be used with \
-                                           `#![feature(clone_closures)]`")
-                  .span_note(span, "`#![feature(copy_closures)]` declared here")
-                  .emit();
-
-            FatalError.raise();
-        }
     }
 }
 
@@ -1926,6 +1894,17 @@ pub fn check_crate(krate: &ast::Crate,
         parse_sess: sess,
         plugin_attributes,
     };
+
+    if !features.raw_identifiers {
+        for &span in sess.raw_identifier_spans.borrow().iter() {
+            if !span.allows_unstable() {
+                gate_feature!(&ctx, raw_identifiers, span,
+                    "raw identifiers are experimental and subject to change"
+                );
+            }
+        }
+    }
+
     let visitor = &mut PostExpansionVisitor { context: &ctx };
     visitor.whole_crate_feature_gates(krate);
     visit::walk_crate(visitor, krate);
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 46e6027b094..e702bf56e7f 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -578,7 +578,7 @@ pub fn noop_fold_tts<T: Folder>(tts: TokenStream, fld: &mut T) -> TokenStream {
 // apply ident folder if it's an ident, apply other folds to interpolated nodes
 pub fn noop_fold_token<T: Folder>(t: token::Token, fld: &mut T) -> token::Token {
     match t {
-        token::Ident(id) => token::Ident(fld.fold_ident(id)),
+        token::Ident(id, is_raw) => token::Ident(fld.fold_ident(id), is_raw),
         token::Lifetime(id) => token::Lifetime(fld.fold_ident(id)),
         token::Interpolated(nt) => {
             let nt = match Lrc::try_unwrap(nt) {
@@ -630,7 +630,8 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T)
         token::NtPat(pat) => token::NtPat(fld.fold_pat(pat)),
         token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)),
         token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)),
-        token::NtIdent(id) => token::NtIdent(Spanned::<Ident>{node: fld.fold_ident(id.node), ..id}),
+        token::NtIdent(id, is_raw) =>
+            token::NtIdent(Spanned::<Ident>{node: fld.fold_ident(id.node), ..id}, is_raw),
         token::NtMeta(meta) => token::NtMeta(fld.fold_meta_item(meta)),
         token::NtPath(path) => token::NtPath(fld.fold_path(path)),
         token::NtTT(tt) => token::NtTT(fld.fold_tt(tt)),
@@ -1166,9 +1167,6 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
             ExprKind::Box(e) => {
                 ExprKind::Box(folder.fold_expr(e))
             }
-            ExprKind::InPlace(p, e) => {
-                ExprKind::InPlace(folder.fold_expr(p), folder.fold_expr(e))
-            }
             ExprKind::Array(exprs) => {
                 ExprKind::Array(folder.fold_exprs(exprs))
             }
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 5f58b3bc3a0..dc349c1a3e6 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -22,9 +22,9 @@
 
 #![feature(unicode)]
 #![feature(rustc_diagnostic_macros)]
-#![feature(match_default_bindings)]
+#![cfg_attr(stage0, feature(match_default_bindings))]
 #![feature(non_exhaustive)]
-#![feature(i128_type)]
+#![cfg_attr(stage0, feature(i128_type))]
 #![feature(const_atomic_usize_new)]
 #![feature(rustc_attrs)]
 
@@ -145,7 +145,7 @@ pub mod codemap;
 #[macro_use]
 pub mod config;
 pub mod entry;
-pub mod epoch;
+pub mod edition;
 pub mod feature_gate;
 pub mod fold;
 pub mod parse;
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 0e20eb49d39..068929c8948 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -14,7 +14,7 @@ use codemap::{CodeMap, FilePathMapping};
 use errors::{FatalError, DiagnosticBuilder};
 use parse::{token, ParseSess};
 use str::char_at;
-use symbol::Symbol;
+use symbol::{Symbol, keywords};
 use std_unicode::property::Pattern_White_Space;
 
 use std::borrow::Cow;
@@ -1115,26 +1115,53 @@ impl<'a> StringReader<'a> {
     /// token, and updates the interner
     fn next_token_inner(&mut self) -> Result<token::Token, ()> {
         let c = self.ch;
-        if ident_start(c) &&
-           match (c.unwrap(), self.nextch(), self.nextnextch()) {
-            // Note: r as in r" or r#" is part of a raw string literal,
-            // b as in b' is part of a byte literal.
-            // They are not identifiers, and are handled further down.
-            ('r', Some('"'), _) |
-            ('r', Some('#'), _) |
-            ('b', Some('"'), _) |
-            ('b', Some('\''), _) |
-            ('b', Some('r'), Some('"')) |
-            ('b', Some('r'), Some('#')) => false,
-            _ => true,
-        } {
-            let start = self.pos;
-            while ident_continue(self.ch) {
-                self.bump();
-            }
 
-            // FIXME: perform NFKC normalization here. (Issue #2253)
-            return Ok(self.with_str_from(start, |string| token::Ident(self.mk_ident(string))));
+        if ident_start(c) {
+            let (is_ident_start, is_raw_ident) =
+                match (c.unwrap(), self.nextch(), self.nextnextch()) {
+                    // r# followed by an identifier starter is a raw identifier.
+                    // This is an exception to the r# case below.
+                    ('r', Some('#'), x) if ident_start(x) => (true, true),
+                    // r as in r" or r#" is part of a raw string literal.
+                    // b as in b' is part of a byte literal.
+                    // They are not identifiers, and are handled further down.
+                    ('r', Some('"'), _) |
+                    ('r', Some('#'), _) |
+                    ('b', Some('"'), _) |
+                    ('b', Some('\''), _) |
+                    ('b', Some('r'), Some('"')) |
+                    ('b', Some('r'), Some('#')) => (false, false),
+                    _ => (true, false),
+                };
+            if is_ident_start {
+                let raw_start = self.pos;
+                if is_raw_ident {
+                    // Consume the 'r#' characters.
+                    self.bump();
+                    self.bump();
+                }
+
+                let start = self.pos;
+                while ident_continue(self.ch) {
+                    self.bump();
+                }
+
+                return Ok(self.with_str_from(start, |string| {
+                    // FIXME: perform NFKC normalization here. (Issue #2253)
+                    let ident = self.mk_ident(string);
+                    if is_raw_ident && (token::is_path_segment_keyword(ident) ||
+                                        ident.name == keywords::Underscore.name()) {
+                        self.fatal_span_(raw_start, self.pos,
+                            &format!("`r#{}` is not currently supported.", ident.name)
+                        ).raise();
+                    }
+                    if is_raw_ident {
+                        let span = self.mk_sp(raw_start, self.pos);
+                        self.sess.raw_identifier_spans.borrow_mut().push(span);
+                    }
+                    token::Ident(ident, is_raw_ident)
+                }));
+            }
         }
 
         if is_dec_digit(c) {
@@ -1773,6 +1800,7 @@ mod tests {
             included_mod_stack: RefCell::new(Vec::new()),
             code_map: cm,
             missing_fragment_specifiers: RefCell::new(HashSet::new()),
+            raw_identifier_spans: RefCell::new(Vec::new()),
             registered_diagnostics: Lock::new(ErrorMap::new()),
             non_modrs_mods: RefCell::new(vec![]),
         }
@@ -1801,7 +1829,7 @@ mod tests {
             assert_eq!(string_reader.next_token().tok, token::Whitespace);
             let tok1 = string_reader.next_token();
             let tok2 = TokenAndSpan {
-                tok: token::Ident(id),
+                tok: token::Ident(id, false),
                 sp: Span::new(BytePos(21), BytePos(23), NO_EXPANSION),
             };
             assert_eq!(tok1, tok2);
@@ -1811,7 +1839,7 @@ mod tests {
             // read another token:
             let tok3 = string_reader.next_token();
             let tok4 = TokenAndSpan {
-                tok: token::Ident(Ident::from_str("main")),
+                tok: mk_ident("main"),
                 sp: Span::new(BytePos(24), BytePos(28), NO_EXPANSION),
             };
             assert_eq!(tok3, tok4);
@@ -1830,7 +1858,7 @@ mod tests {
 
     // make the identifier by looking up the string in the interner
     fn mk_ident(id: &str) -> token::Token {
-        token::Ident(Ident::from_str(id))
+        token::Token::from_ast_ident(Ident::from_str(id))
     }
 
     #[test]
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index f7e5d40b524..1483691a1ea 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -40,7 +40,6 @@ pub mod attr;
 
 pub mod common;
 pub mod classify;
-pub mod obsolete;
 
 /// Info about a parsing session.
 pub struct ParseSess {
@@ -48,6 +47,9 @@ pub struct ParseSess {
     pub unstable_features: UnstableFeatures,
     pub config: CrateConfig,
     pub missing_fragment_specifiers: RefCell<HashSet<Span>>,
+    /// Places where raw identifiers were used. This is used for feature gating
+    /// raw identifiers
+    pub raw_identifier_spans: RefCell<Vec<Span>>,
     /// The registered diagnostics codes
     pub registered_diagnostics: Lock<ErrorMap>,
     // Spans where a `mod foo;` statement was included in a non-mod.rs file.
@@ -74,6 +76,7 @@ impl ParseSess {
             unstable_features: UnstableFeatures::from_environment(),
             config: HashSet::new(),
             missing_fragment_specifiers: RefCell::new(HashSet::new()),
+            raw_identifier_spans: RefCell::new(Vec::new()),
             registered_diagnostics: Lock::new(ErrorMap::new()),
             included_mod_stack: RefCell::new(vec![]),
             code_map,
@@ -298,7 +301,6 @@ pub fn str_lit(lit: &str, diag: Option<(Span, &Handler)>) -> String {
     debug!("parse_str_lit: given {}", escape_default(lit));
     let mut res = String::with_capacity(lit.len());
 
-    // FIXME #8372: This could be a for-loop if it didn't borrow the iterator
     let error = |i| format!("lexer should have rejected {} at {}", lit, i);
 
     /// Eat everything up to a non-whitespace
@@ -503,7 +505,6 @@ pub fn byte_lit(lit: &str) -> (u8, usize) {
 pub fn byte_str_lit(lit: &str) -> Lrc<Vec<u8>> {
     let mut res = Vec::with_capacity(lit.len());
 
-    // FIXME #8372: This could be a for-loop if it didn't borrow the iterator
     let error = |i| format!("lexer should have rejected {} at {}", lit, i);
 
     /// Eat everything up to a non-whitespace
@@ -741,9 +742,9 @@ mod tests {
             match (tts.len(), tts.get(0), tts.get(1), tts.get(2), tts.get(3)) {
                 (
                     4,
-                    Some(&TokenTree::Token(_, token::Ident(name_macro_rules))),
+                    Some(&TokenTree::Token(_, token::Ident(name_macro_rules, false))),
                     Some(&TokenTree::Token(_, token::Not)),
-                    Some(&TokenTree::Token(_, token::Ident(name_zip))),
+                    Some(&TokenTree::Token(_, token::Ident(name_zip, false))),
                     Some(&TokenTree::Delimited(_, ref macro_delimed)),
                 )
                 if name_macro_rules.name == "macro_rules"
@@ -762,7 +763,7 @@ mod tests {
                                 (
                                     2,
                                     Some(&TokenTree::Token(_, token::Dollar)),
-                                    Some(&TokenTree::Token(_, token::Ident(ident))),
+                                    Some(&TokenTree::Token(_, token::Ident(ident, false))),
                                 )
                                 if first_delimed.delim == token::Paren && ident.name == "a" => {},
                                 _ => panic!("value 3: {:?}", *first_delimed),
@@ -772,7 +773,7 @@ mod tests {
                                 (
                                     2,
                                     Some(&TokenTree::Token(_, token::Dollar)),
-                                    Some(&TokenTree::Token(_, token::Ident(ident))),
+                                    Some(&TokenTree::Token(_, token::Ident(ident, false))),
                                 )
                                 if second_delimed.delim == token::Paren
                                 && ident.name == "a" => {},
@@ -793,17 +794,18 @@ mod tests {
             let tts = string_to_stream("fn a (b : i32) { b; }".to_string());
 
             let expected = TokenStream::concat(vec![
-                TokenTree::Token(sp(0, 2), token::Ident(Ident::from_str("fn"))).into(),
-                TokenTree::Token(sp(3, 4), token::Ident(Ident::from_str("a"))).into(),
+                TokenTree::Token(sp(0, 2), token::Ident(Ident::from_str("fn"), false)).into(),
+                TokenTree::Token(sp(3, 4), token::Ident(Ident::from_str("a"), false)).into(),
                 TokenTree::Delimited(
                     sp(5, 14),
                     tokenstream::Delimited {
                         delim: token::DelimToken::Paren,
                         tts: TokenStream::concat(vec![
-                            TokenTree::Token(sp(6, 7), token::Ident(Ident::from_str("b"))).into(),
+                            TokenTree::Token(sp(6, 7),
+                                             token::Ident(Ident::from_str("b"), false)).into(),
                             TokenTree::Token(sp(8, 9), token::Colon).into(),
                             TokenTree::Token(sp(10, 13),
-                                             token::Ident(Ident::from_str("i32"))).into(),
+                                             token::Ident(Ident::from_str("i32"), false)).into(),
                         ]).into(),
                     }).into(),
                 TokenTree::Delimited(
@@ -811,7 +813,8 @@ mod tests {
                     tokenstream::Delimited {
                         delim: token::DelimToken::Brace,
                         tts: TokenStream::concat(vec![
-                            TokenTree::Token(sp(17, 18), token::Ident(Ident::from_str("b"))).into(),
+                            TokenTree::Token(sp(17, 18),
+                                             token::Ident(Ident::from_str("b"), false)).into(),
                             TokenTree::Token(sp(18, 19), token::Semi).into(),
                         ]).into(),
                     }).into()
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
deleted file mode 100644
index 49a697edf41..00000000000
--- a/src/libsyntax/parse/obsolete.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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.
-//
-// 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.
-
-//! Support for parsing unsupported, old syntaxes, for the purpose of reporting errors. Parsing of
-//! these syntaxes is tested by compile-test/obsolete-syntax.rs.
-//!
-//! Obsolete syntax that becomes too hard to parse can be removed.
-
-use syntax_pos::Span;
-use parse::parser;
-
-/// The specific types of unsupported syntax
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub enum ObsoleteSyntax {
-    // Nothing here at the moment
-}
-
-pub trait ParserObsoleteMethods {
-    /// Reports an obsolete syntax non-fatal error.
-    fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax);
-    fn report(&mut self,
-              sp: Span,
-              kind: ObsoleteSyntax,
-              kind_str: &str,
-              desc: &str,
-              error: bool);
-}
-
-impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
-    /// Reports an obsolete syntax non-fatal error.
-    #[allow(unused_variables)]
-    #[allow(unreachable_code)]
-    fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) {
-        let (kind_str, desc, error) = match kind {
-            // Nothing here at the moment
-        };
-
-        self.report(sp, kind, kind_str, desc, error);
-    }
-
-    fn report(&mut self,
-              sp: Span,
-              kind: ObsoleteSyntax,
-              kind_str: &str,
-              desc: &str,
-              error: bool) {
-        let mut err = if error {
-            self.diagnostic().struct_span_err(sp, &format!("obsolete syntax: {}", kind_str))
-        } else {
-            self.diagnostic().struct_span_warn(sp, &format!("obsolete syntax: {}", kind_str))
-        };
-
-        if !self.obsolete_set.contains(&kind) &&
-            (error || self.sess.span_diagnostic.flags.can_emit_warnings) {
-            err.note(desc);
-            self.obsolete_set.insert(kind);
-        }
-        err.emit();
-    }
-}
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 6d8975197d5..f5ab023b30e 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -48,7 +48,6 @@ use parse::{self, classify, token};
 use parse::common::SeqSep;
 use parse::lexer::TokenAndSpan;
 use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
-use parse::obsolete::ObsoleteSyntax;
 use parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership};
 use util::parser::{AssocOp, Fixity};
 use print::pprust;
@@ -59,7 +58,6 @@ use symbol::{Symbol, keywords};
 use util::ThinVec;
 
 use std::cmp;
-use std::collections::HashSet;
 use std::mem;
 use std::path::{self, Path, PathBuf};
 use std::slice;
@@ -229,9 +227,6 @@ pub struct Parser<'a> {
     /// the previous token kind
     prev_token_kind: PrevTokenKind,
     pub restrictions: Restrictions,
-    /// The set of seen errors about obsolete syntax. Used to suppress
-    /// extra detail when the same error is seen twice
-    pub obsolete_set: HashSet<ObsoleteSyntax>,
     /// Used to determine the path to externally loaded source files
     pub directory: Directory,
     /// Whether to parse sub-modules in other files.
@@ -358,7 +353,7 @@ impl TokenCursor {
 
         let body = TokenTree::Delimited(sp, Delimited {
             delim: token::Bracket,
-            tts: [TokenTree::Token(sp, token::Ident(ast::Ident::from_str("doc"))),
+            tts: [TokenTree::Token(sp, token::Ident(ast::Ident::from_str("doc"), false)),
                   TokenTree::Token(sp, token::Eq),
                   TokenTree::Token(sp, token::Literal(
                       token::StrRaw(Symbol::intern(&stripped), num_of_hashes), None))]
@@ -460,7 +455,7 @@ impl Error {
                                            ref dir_path } => {
                 let mut err = struct_span_err!(handler, sp, E0583,
                                                "file not found for module `{}`", mod_name);
-                err.help(&format!("name the file either {} or {} inside the directory {:?}",
+                err.help(&format!("name the file either {} or {} inside the directory \"{}\"",
                                   default_path,
                                   secondary_path,
                                   dir_path));
@@ -555,7 +550,6 @@ impl<'a> Parser<'a> {
             meta_var_span: None,
             prev_token_kind: PrevTokenKind::Other,
             restrictions: Restrictions::empty(),
-            obsolete_set: HashSet::new(),
             recurse_into_file_modules,
             directory: Directory {
                 path: PathBuf::new(),
@@ -784,7 +778,7 @@ impl<'a> Parser<'a> {
 
     fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> {
         match self.token {
-            token::Ident(i) => {
+            token::Ident(i, _) => {
                 if self.token.is_reserved_ident() {
                     let mut err = self.expected_ident_found();
                     if recover {
@@ -1925,7 +1919,7 @@ impl<'a> Parser<'a> {
 
     pub fn parse_path_segment_ident(&mut self) -> PResult<'a, ast::Ident> {
         match self.token {
-            token::Ident(sid) if self.token.is_path_segment_keyword() => {
+            token::Ident(sid, _) if self.token.is_path_segment_keyword() => {
                 self.bump();
                 Ok(sid)
             }
@@ -2740,11 +2734,14 @@ impl<'a> Parser<'a> {
     }
 
     pub fn process_potential_macro_variable(&mut self) {
-        let ident = match self.token {
+        let (ident, is_raw) = match self.token {
             token::Dollar if self.span.ctxt() != syntax_pos::hygiene::SyntaxContext::empty() &&
                              self.look_ahead(1, |t| t.is_ident()) => {
                 self.bump();
-                let name = match self.token { token::Ident(ident) => ident, _ => unreachable!() };
+                let name = match self.token {
+                    token::Ident(ident, _) => ident,
+                    _ => unreachable!()
+                };
                 let mut err = self.fatal(&format!("unknown macro variable `{}`", name));
                 err.span_label(self.span, "unknown macro variable");
                 err.emit();
@@ -2753,13 +2750,13 @@ impl<'a> Parser<'a> {
             token::Interpolated(ref nt) => {
                 self.meta_var_span = Some(self.span);
                 match nt.0 {
-                    token::NtIdent(ident) => ident,
+                    token::NtIdent(ident, is_raw) => (ident, is_raw),
                     _ => return,
                 }
             }
             _ => return,
         };
-        self.token = token::Ident(ident.node);
+        self.token = token::Ident(ident.node, is_raw);
         self.span = ident.span;
     }
 
@@ -2853,17 +2850,6 @@ impl<'a> Parser<'a> {
                 let (span, e) = self.interpolated_or_expr_span(e)?;
                 (lo.to(span), ExprKind::AddrOf(m, e))
             }
-            token::Ident(..) if self.token.is_keyword(keywords::In) => {
-                self.bump();
-                let place = self.parse_expr_res(
-                    Restrictions::NO_STRUCT_LITERAL,
-                    None,
-                )?;
-                let blk = self.parse_block()?;
-                let span = blk.span;
-                let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new());
-                (lo.to(span), ExprKind::InPlace(place, blk_expr))
-            }
             token::Ident(..) if self.token.is_keyword(keywords::Box) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
@@ -3026,8 +3012,6 @@ impl<'a> Parser<'a> {
                 }
                 AssocOp::Assign =>
                     self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()),
-                AssocOp::Inplace =>
-                    self.mk_expr(span, ExprKind::InPlace(lhs, rhs), ThinVec::new()),
                 AssocOp::AssignOp(k) => {
                     let aop = match k {
                         token::Plus =>    BinOpKind::Add,
@@ -3672,7 +3656,13 @@ impl<'a> Parser<'a> {
                 if self.token != token::CloseDelim(token::Brace) {
                     let token_str = self.this_token_to_string();
                     let mut err = self.fatal(&format!("expected `{}`, found `{}`", "}", token_str));
-                    err.span_label(self.span, "expected `}`");
+                    if self.token == token::Comma { // Issue #49257
+                        err.span_label(self.span,
+                                       "`..` must be in the last position, \
+                                        and cannot have a trailing comma");
+                    } else {
+                        err.span_label(self.span, "expected `}`");
+                    }
                     return Err(err);
                 }
                 etc = true;
@@ -4245,7 +4235,7 @@ impl<'a> Parser<'a> {
                      -> PResult<'a, Option<P<Item>>> {
         let token_lo = self.span;
         let (ident, def) = match self.token {
-            token::Ident(ident) if ident.name == keywords::Macro.name() => {
+            token::Ident(ident, false) if ident.name == keywords::Macro.name() => {
                 self.bump();
                 let ident = self.parse_ident()?;
                 let tokens = if self.check(&token::OpenDelim(token::Brace)) {
@@ -4273,7 +4263,7 @@ impl<'a> Parser<'a> {
 
                 (ident, ast::MacroDef { tokens: tokens.into(), legacy: false })
             }
-            token::Ident(ident) if ident.name == "macro_rules" &&
+            token::Ident(ident, _) if ident.name == "macro_rules" &&
                                    self.look_ahead(1, |t| *t == token::Not) => {
                 let prev_span = self.prev_span;
                 self.complain_if_pub_macro(&vis.node, prev_span);
@@ -4598,6 +4588,9 @@ impl<'a> Parser<'a> {
 
     /// Parse a statement, including the trailing semicolon.
     pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> {
+        // skip looking for a trailing semicolon when we have an interpolated statement
+        maybe_whole!(self, NtStmt, |x| Some(x));
+
         let mut stmt = match self.parse_stmt_without_recovery(macro_legacy_warnings)? {
             Some(stmt) => stmt,
             None => return Ok(None),
@@ -5078,7 +5071,9 @@ impl<'a> Parser<'a> {
     fn parse_self_arg(&mut self) -> PResult<'a, Option<Arg>> {
         let expect_ident = |this: &mut Self| match this.token {
             // Preserve hygienic context.
-            token::Ident(ident) => { let sp = this.span; this.bump(); codemap::respan(sp, ident) }
+            token::Ident(ident, _) => {
+                let sp = this.span; this.bump(); codemap::respan(sp, ident)
+            }
             _ => unreachable!()
         };
         let isolated_self = |this: &mut Self, n| {
@@ -5375,7 +5370,7 @@ impl<'a> Parser<'a> {
             VisibilityKind::Inherited => Ok(()),
             _ => {
                 let is_macro_rules: bool = match self.token {
-                    token::Ident(sid) => sid.name == Symbol::intern("macro_rules"),
+                    token::Ident(sid, _) => sid.name == Symbol::intern("macro_rules"),
                     _ => false,
                 };
                 if is_macro_rules {
@@ -7016,7 +7011,7 @@ impl<'a> Parser<'a> {
     fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
         if self.eat_keyword(keywords::As) {
             match self.token {
-                token::Ident(ident) if ident.name == keywords::Underscore.name() => {
+                token::Ident(ident, false) if ident.name == keywords::Underscore.name() => {
                     self.bump(); // `_`
                     Ok(Some(Ident { name: ident.name.gensymed(), ..ident }))
                 }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 4ada9e20f2c..e2dfca5d10a 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -91,8 +91,8 @@ impl Lit {
     }
 }
 
-fn ident_can_begin_expr(ident: ast::Ident) -> bool {
-    let ident_token: Token = Ident(ident);
+fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool {
+    let ident_token: Token = Ident(ident, is_raw);
 
     !ident_token.is_reserved_ident() ||
     ident_token.is_path_segment_keyword() ||
@@ -116,8 +116,8 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool {
     ].contains(&ident.name)
 }
 
-fn ident_can_begin_type(ident: ast::Ident) -> bool {
-    let ident_token: Token = Ident(ident);
+fn ident_can_begin_type(ident: ast::Ident, is_raw: bool) -> bool {
+    let ident_token: Token = Ident(ident, is_raw);
 
     !ident_token.is_reserved_ident() ||
     ident_token.is_path_segment_keyword() ||
@@ -132,6 +132,44 @@ fn ident_can_begin_type(ident: ast::Ident) -> bool {
     ].contains(&ident.name)
 }
 
+pub fn is_path_segment_keyword(id: ast::Ident) -> bool {
+    id.name == keywords::Super.name() ||
+    id.name == keywords::SelfValue.name() ||
+    id.name == keywords::SelfType.name() ||
+    id.name == keywords::Extern.name() ||
+    id.name == keywords::Crate.name() ||
+    id.name == keywords::CrateRoot.name() ||
+    id.name == keywords::DollarCrate.name()
+}
+
+// We see this identifier in a normal identifier position, like variable name or a type.
+// How was it written originally? Did it use the raw form? Let's try to guess.
+pub fn is_raw_guess(ident: ast::Ident) -> bool {
+    ident.name != keywords::Invalid.name() &&
+    is_reserved_ident(ident) && !is_path_segment_keyword(ident)
+}
+
+// Returns true for reserved identifiers used internally for elided lifetimes,
+// unnamed method parameters, crate root module, error recovery etc.
+pub fn is_special_ident(id: ast::Ident) -> bool {
+    id.name <= keywords::Underscore.name()
+}
+
+/// Returns `true` if the token is a keyword used in the language.
+pub fn is_used_keyword(id: ast::Ident) -> bool {
+    id.name >= keywords::As.name() && id.name <= keywords::While.name()
+}
+
+/// Returns `true` if the token is a keyword reserved for possible future use.
+pub fn is_unused_keyword(id: ast::Ident) -> bool {
+    id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name()
+}
+
+/// Returns `true` if the token is either a special identifier or a keyword.
+pub fn is_reserved_ident(id: ast::Ident) -> bool {
+    is_special_ident(id) || is_used_keyword(id) || is_unused_keyword(id)
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)]
 pub enum Token {
     /* Expression-operator symbols. */
@@ -175,7 +213,7 @@ pub enum Token {
     Literal(Lit, Option<ast::Name>),
 
     /* Name components */
-    Ident(ast::Ident),
+    Ident(ast::Ident, /* is_raw */ bool),
     Lifetime(ast::Ident),
 
     // The `LazyTokenStream` is a pure function of the `Nonterminal`,
@@ -203,6 +241,11 @@ impl Token {
         Token::Interpolated(Lrc::new((nt, LazyTokenStream::new())))
     }
 
+    /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary.
+    pub fn from_ast_ident(ident: ast::Ident) -> Token {
+        Ident(ident, is_raw_guess(ident))
+    }
+
     /// Returns `true` if the token starts with '>'.
     pub fn is_like_gt(&self) -> bool {
         match *self {
@@ -214,7 +257,8 @@ impl Token {
     /// Returns `true` if the token can appear at the start of an expression.
     pub fn can_begin_expr(&self) -> bool {
         match *self {
-            Ident(ident)                => ident_can_begin_expr(ident), // value name or keyword
+            Ident(ident, is_raw)              =>
+                ident_can_begin_expr(ident, is_raw), // value name or keyword
             OpenDelim(..)                     | // tuple, array or block
             Literal(..)                       | // literal
             Not                               | // operator not
@@ -239,7 +283,8 @@ impl Token {
     /// Returns `true` if the token can appear at the start of a type.
     pub fn can_begin_type(&self) -> bool {
         match *self {
-            Ident(ident)                => ident_can_begin_type(ident), // type name or keyword
+            Ident(ident, is_raw)        =>
+                ident_can_begin_type(ident, is_raw), // type name or keyword
             OpenDelim(Paren)            | // tuple
             OpenDelim(Bracket)          | // array
             Not                         | // never
@@ -272,11 +317,11 @@ impl Token {
         }
     }
 
-    pub fn ident(&self) -> Option<ast::Ident> {
+    pub fn ident(&self) -> Option<(ast::Ident, bool)> {
         match *self {
-            Ident(ident) => Some(ident),
+            Ident(ident, is_raw) => Some((ident, is_raw)),
             Interpolated(ref nt) => match nt.0 {
-                NtIdent(ident) => Some(ident.node),
+                NtIdent(ident, is_raw) => Some((ident.node, is_raw)),
                 _ => None,
             },
             _ => None,
@@ -351,19 +396,13 @@ impl Token {
 
     /// Returns `true` if the token is a given keyword, `kw`.
     pub fn is_keyword(&self, kw: keywords::Keyword) -> bool {
-        self.ident().map(|ident| ident.name == kw.name()).unwrap_or(false)
+        self.ident().map(|(ident, is_raw)| ident.name == kw.name() && !is_raw).unwrap_or(false)
     }
 
     pub fn is_path_segment_keyword(&self) -> bool {
         match self.ident() {
-            Some(id) => id.name == keywords::Super.name() ||
-                        id.name == keywords::SelfValue.name() ||
-                        id.name == keywords::SelfType.name() ||
-                        id.name == keywords::Extern.name() ||
-                        id.name == keywords::Crate.name() ||
-                        id.name == keywords::CrateRoot.name() ||
-                        id.name == keywords::DollarCrate.name(),
-            None => false,
+            Some((id, false)) => is_path_segment_keyword(id),
+            _ => false,
         }
     }
 
@@ -371,7 +410,7 @@ impl Token {
     // unnamed method parameters, crate root module, error recovery etc.
     pub fn is_special_ident(&self) -> bool {
         match self.ident() {
-            Some(id) => id.name <= keywords::Underscore.name(),
+            Some((id, false)) => is_special_ident(id),
             _ => false,
         }
     }
@@ -379,7 +418,7 @@ impl Token {
     /// Returns `true` if the token is a keyword used in the language.
     pub fn is_used_keyword(&self) -> bool {
         match self.ident() {
-            Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(),
+            Some((id, false)) => is_used_keyword(id),
             _ => false,
         }
     }
@@ -387,7 +426,7 @@ impl Token {
     /// Returns `true` if the token is a keyword reserved for possible future use.
     pub fn is_unused_keyword(&self) -> bool {
         match self.ident() {
-            Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(),
+            Some((id, false)) => is_unused_keyword(id),
             _ => false,
         }
     }
@@ -460,7 +499,10 @@ impl Token {
 
     /// Returns `true` if the token is either a special identifier or a keyword.
     pub fn is_reserved_ident(&self) -> bool {
-        self.is_special_ident() || self.is_used_keyword() || self.is_unused_keyword()
+        match self.ident() {
+            Some((id, false)) => is_reserved_ident(id),
+            _ => false,
+        }
     }
 
     pub fn interpolated_to_tokenstream(&self, sess: &ParseSess, span: Span)
@@ -496,8 +538,8 @@ impl Token {
             Nonterminal::NtImplItem(ref item) => {
                 tokens = prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span);
             }
-            Nonterminal::NtIdent(ident) => {
-                let token = Token::Ident(ident.node);
+            Nonterminal::NtIdent(ident, is_raw) => {
+                let token = Token::Ident(ident.node, is_raw);
                 tokens = Some(TokenTree::Token(ident.span, token).into());
             }
             Nonterminal::NtLifetime(lifetime) => {
@@ -529,7 +571,7 @@ pub enum Nonterminal {
     NtPat(P<ast::Pat>),
     NtExpr(P<ast::Expr>),
     NtTy(P<ast::Ty>),
-    NtIdent(ast::SpannedIdent),
+    NtIdent(ast::SpannedIdent, /* is_raw */ bool),
     /// Stuff inside brackets for attributes
     NtMeta(ast::MetaItem),
     NtPath(ast::Path),
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 7adb2848f8d..c3785c10f69 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -250,7 +250,8 @@ pub fn token_to_string(tok: &Token) -> String {
         }
 
         /* Name components */
-        token::Ident(s)             => s.to_string(),
+        token::Ident(s, false)      => s.to_string(),
+        token::Ident(s, true)       => format!("r#{}", s),
         token::Lifetime(s)          => s.to_string(),
 
         /* Other */
@@ -261,24 +262,25 @@ pub fn token_to_string(tok: &Token) -> String {
         token::Shebang(s)           => format!("/* shebang: {}*/", s),
 
         token::Interpolated(ref nt) => match nt.0 {
-            token::NtExpr(ref e)        => expr_to_string(e),
-            token::NtMeta(ref e)        => meta_item_to_string(e),
-            token::NtTy(ref e)          => ty_to_string(e),
-            token::NtPath(ref e)        => path_to_string(e),
-            token::NtItem(ref e)        => item_to_string(e),
-            token::NtBlock(ref e)       => block_to_string(e),
-            token::NtStmt(ref e)        => stmt_to_string(e),
-            token::NtPat(ref e)         => pat_to_string(e),
-            token::NtIdent(ref e)       => ident_to_string(e.node),
-            token::NtTT(ref tree)       => tt_to_string(tree.clone()),
-            token::NtArm(ref e)         => arm_to_string(e),
-            token::NtImplItem(ref e)    => impl_item_to_string(e),
-            token::NtTraitItem(ref e)   => trait_item_to_string(e),
-            token::NtGenerics(ref e)    => generic_params_to_string(&e.params),
-            token::NtWhereClause(ref e) => where_clause_to_string(e),
-            token::NtArg(ref e)         => arg_to_string(e),
-            token::NtVis(ref e)         => vis_to_string(e),
-            token::NtLifetime(ref e)    => lifetime_to_string(e),
+            token::NtExpr(ref e)         => expr_to_string(e),
+            token::NtMeta(ref e)         => meta_item_to_string(e),
+            token::NtTy(ref e)           => ty_to_string(e),
+            token::NtPath(ref e)         => path_to_string(e),
+            token::NtItem(ref e)         => item_to_string(e),
+            token::NtBlock(ref e)        => block_to_string(e),
+            token::NtStmt(ref e)         => stmt_to_string(e),
+            token::NtPat(ref e)          => pat_to_string(e),
+            token::NtIdent(ref e, false) => ident_to_string(e.node),
+            token::NtIdent(ref e, true)  => format!("r#{}", ident_to_string(e.node)),
+            token::NtTT(ref tree)        => tt_to_string(tree.clone()),
+            token::NtArm(ref e)          => arm_to_string(e),
+            token::NtImplItem(ref e)     => impl_item_to_string(e),
+            token::NtTraitItem(ref e)    => trait_item_to_string(e),
+            token::NtGenerics(ref e)     => generic_params_to_string(&e.params),
+            token::NtWhereClause(ref e)  => where_clause_to_string(e),
+            token::NtArg(ref e)          => arg_to_string(e),
+            token::NtVis(ref e)          => vis_to_string(e),
+            token::NtLifetime(ref e)     => lifetime_to_string(e),
         }
     }
 }
@@ -1875,16 +1877,6 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    fn print_expr_in_place(&mut self,
-                           place: &ast::Expr,
-                           expr: &ast::Expr) -> io::Result<()> {
-        let prec = AssocOp::Inplace.precedence() as i8;
-        self.print_expr_maybe_paren(place, prec + 1)?;
-        self.s.space()?;
-        self.word_space("<-")?;
-        self.print_expr_maybe_paren(expr, prec)
-    }
-
     fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>],
                       attrs: &[Attribute]) -> io::Result<()> {
         self.ibox(INDENT_UNIT)?;
@@ -2054,9 +2046,6 @@ impl<'a> State<'a> {
                 self.word_space("box")?;
                 self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)?;
             }
-            ast::ExprKind::InPlace(ref place, ref expr) => {
-                self.print_expr_in_place(place, expr)?;
-            }
             ast::ExprKind::Array(ref exprs) => {
                 self.print_expr_vec(&exprs[..], attrs)?;
             }
@@ -2371,7 +2360,11 @@ impl<'a> State<'a> {
     }
 
     pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
-        self.s.word(&ident.name.as_str())?;
+        if token::is_raw_guess(ident) {
+            self.s.word(&format!("r#{}", ident))?;
+        } else {
+            self.s.word(&ident.name.as_str())?;
+        }
         self.ann.post(self, NodeIdent(&ident))
     }
 
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 9edfa767d31..67a822e4e02 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -332,7 +332,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
             ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
                 // If the termination trait is active, the compiler will check that the output
                 // type implements the `Termination` trait as `libtest` enforces that.
-                let output_matches = if cx.features.termination_trait {
+                let output_matches = if cx.features.termination_trait_test {
                     true
                 } else {
                     let no_output = match decl.output {
@@ -359,7 +359,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
         match has_test_signature(cx, i) {
             Yes => true,
             No => {
-                if cx.features.termination_trait {
+                if cx.features.termination_trait_test {
                     diag.span_err(i.span, "functions used as tests can not have any arguments");
                 } else {
                     diag.span_err(i.span, "functions used as tests must have signature fn() -> ()");
@@ -388,7 +388,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
 
                 // If the termination trait is active, the compiler will check that the output
                 // type implements the `Termination` trait as `libtest` enforces that.
-                let output_matches = if cx.features.termination_trait {
+                let output_matches = if cx.features.termination_trait_test {
                     true
                 } else {
                     let no_output = match decl.output {
@@ -416,7 +416,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
     if has_bench_attr && !has_bench_signature {
         let diag = cx.span_diagnostic;
 
-        if cx.features.termination_trait {
+        if cx.features.termination_trait_test {
             diag.span_err(i.span, "functions used as benches must have signature \
                                    `fn(&mut Bencher) -> impl Termination`");
         } else {
@@ -547,7 +547,7 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> {
     // pub fn main() { ... }
     let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![]));
     let main_body = ecx.block(sp, vec![call_test_main]);
-    let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], main_ret_ty),
+    let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)),
                            ast::Unsafety::Normal,
                            dummy_spanned(ast::Constness::NotConst),
                            ::abi::Abi::Rust, ast::Generics::default(), main_body);
@@ -628,8 +628,15 @@ fn path_node(ids: Vec<Ident>) -> ast::Path {
 }
 
 fn path_name_i(idents: &[Ident]) -> String {
-    // FIXME: Bad copies (#2543 -- same for everything else that says "bad")
-    idents.iter().map(|i| i.to_string()).collect::<Vec<String>>().join("::")
+    let mut path_name = "".to_string();
+    let mut idents_iter = idents.iter().peekable();
+    while let Some(ident) = idents_iter.next() {
+        path_name.push_str(&ident.name.as_str());
+        if let Some(_) = idents_iter.peek() {
+            path_name.push_str("::")
+        }
+    }
+    path_name
 }
 
 fn mk_tests(cx: &TestCtxt) -> P<ast::Item> {
@@ -682,7 +689,6 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> {
     // gensym information.
 
     let span = ignored_span(cx, test.span);
-    let path = test.path.clone();
     let ecx = &cx.ext_cx;
     let self_id = ecx.ident_of("self");
     let test_id = ecx.ident_of("test");
@@ -694,10 +700,11 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> {
     // creates $name: $expr
     let field = |name, expr| ecx.field_imm(span, ecx.ident_of(name), expr);
 
-    debug!("encoding {}", path_name_i(&path[..]));
-
     // path to the #[test] function: "foo::bar::baz"
-    let path_string = path_name_i(&path[..]);
+    let path_string = path_name_i(&test.path[..]);
+
+    debug!("encoding {}", path_string);
+
     let name_expr = ecx.expr_str(span, Symbol::intern(&path_string));
 
     // self::test::StaticTestName($name_expr)
@@ -744,7 +751,7 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> {
             diag.bug("expected to find top-level re-export name, but found None");
         }
     };
-    visible_path.extend(path);
+    visible_path.extend_from_slice(&test.path[..]);
 
     // Rather than directly give the test function to the test
     // harness, we create a wrapper like one of the following:
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 1219e909e12..3a7a1b9a669 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -684,7 +684,7 @@ mod tests {
         with_globals(|| {
             let test0: TokenStream = Vec::<TokenTree>::new().into_iter().collect();
             let test1: TokenStream =
-                TokenTree::Token(sp(0, 1), Token::Ident(Ident::from_str("a"))).into();
+                TokenTree::Token(sp(0, 1), Token::Ident(Ident::from_str("a"), false)).into();
             let test2 = string_to_ts("foo(bar::baz)");
 
             assert_eq!(test0.is_empty(), true);
diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs
index 86963c4000b..4770273e8c4 100644
--- a/src/libsyntax/util/parser.rs
+++ b/src/libsyntax/util/parser.rs
@@ -56,8 +56,6 @@ pub enum AssocOp {
     GreaterEqual,
     /// `=`
     Assign,
-    /// `<-`
-    Inplace,
     /// `?=` where ? is one of the BinOpToken
     AssignOp(BinOpToken),
     /// `as`
@@ -86,7 +84,6 @@ impl AssocOp {
         use self::AssocOp::*;
         match *t {
             Token::BinOpEq(k) => Some(AssignOp(k)),
-            Token::LArrow => Some(Inplace),
             Token::Eq => Some(Assign),
             Token::BinOp(BinOpToken::Star) => Some(Multiply),
             Token::BinOp(BinOpToken::Slash) => Some(Divide),
@@ -156,7 +153,6 @@ impl AssocOp {
             LAnd => 6,
             LOr => 5,
             DotDot | DotDotEq => 4,
-            Inplace => 3,
             Assign | AssignOp(_) => 2,
         }
     }
@@ -166,7 +162,7 @@ impl AssocOp {
         use self::AssocOp::*;
         // NOTE: it is a bug to have an operators that has same precedence but different fixities!
         match *self {
-            Inplace | Assign | AssignOp(_) => Fixity::Right,
+            Assign | AssignOp(_) => Fixity::Right,
             As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd |
             BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual |
             LAnd | LOr | Colon => Fixity::Left,
@@ -178,7 +174,7 @@ impl AssocOp {
         use self::AssocOp::*;
         match *self {
             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
-            Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract |
+            Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract |
             ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr |
             DotDot | DotDotEq | Colon => false
         }
@@ -187,7 +183,7 @@ impl AssocOp {
     pub fn is_assign_like(&self) -> bool {
         use self::AssocOp::*;
         match *self {
-            Assign | AssignOp(_) | Inplace => true,
+            Assign | AssignOp(_) => true,
             Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide |
             Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd |
             LOr | DotDot | DotDotEq | Colon => false
@@ -215,7 +211,7 @@ impl AssocOp {
             BitOr => Some(BinOpKind::BitOr),
             LAnd => Some(BinOpKind::And),
             LOr => Some(BinOpKind::Or),
-            Inplace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
+            Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None
         }
     }
 }
@@ -242,7 +238,6 @@ pub enum ExprPrecedence {
 
     Binary(BinOpKind),
 
-    InPlace,
     Cast,
     Type,
 
@@ -310,7 +305,6 @@ impl ExprPrecedence {
 
             // Binop-like expr kinds, handled by `AssocOp`.
             ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
-            ExprPrecedence::InPlace => AssocOp::Inplace.precedence() as i8,
             ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
             ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index bbf1fe124f1..d8de78054ab 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -654,10 +654,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         ExprKind::Box(ref subexpression) => {
             visitor.visit_expr(subexpression)
         }
-        ExprKind::InPlace(ref place, ref subexpression) => {
-            visitor.visit_expr(place);
-            visitor.visit_expr(subexpression)
-        }
         ExprKind::Array(ref subexpressions) => {
             walk_list!(visitor, visit_expr, subexpressions);
         }