summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2015-04-30 22:30:50 +1200
committerNick Cameron <ncameron@mozilla.com>2015-04-30 22:30:50 +1200
commitb2ddd937b20d8fc26132cb7ec665784422d92926 (patch)
treecf257df60ded1b45616d797b8feb71178cab0142 /src/libsyntax
parentc0a42aecbc85298fb6351253c4cd1824567b7a42 (diff)
parentf0bd14f7b15b978f8bf32bb368f63faa0f26c02e (diff)
downloadrust-b2ddd937b20d8fc26132cb7ec665784422d92926.tar.gz
rust-b2ddd937b20d8fc26132cb7ec665784422d92926.zip
Merge branch 'master' into mulit-decor
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs16
-rw-r--r--src/libsyntax/ast_map/blocks.rs3
-rw-r--r--src/libsyntax/ast_map/mod.rs8
-rw-r--r--src/libsyntax/ast_util.rs4
-rw-r--r--src/libsyntax/codemap.rs2
-rw-r--r--src/libsyntax/diagnostics/metadata.rs155
-rw-r--r--src/libsyntax/diagnostics/plugin.rs96
-rw-r--r--src/libsyntax/ext/expand.rs2
-rw-r--r--src/libsyntax/ext/quote.rs363
-rw-r--r--src/libsyntax/feature_gate.rs38
-rw-r--r--src/libsyntax/fold.rs20
-rw-r--r--src/libsyntax/lib.rs4
-rw-r--r--src/libsyntax/parse/lexer/comments.rs2
-rw-r--r--src/libsyntax/parse/lexer/mod.rs109
-rw-r--r--src/libsyntax/parse/mod.rs74
-rw-r--r--src/libsyntax/parse/parser.rs292
-rw-r--r--src/libsyntax/parse/token.rs17
-rw-r--r--src/libsyntax/print/pprust.rs155
-rw-r--r--src/libsyntax/util/parser_testing.rs2
-rw-r--r--src/libsyntax/util/small_vector.rs2
-rw-r--r--src/libsyntax/visit.rs14
21 files changed, 718 insertions, 660 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 399810cb7f5..3b7bfb1043a 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -89,12 +89,6 @@ impl Ident {
     pub fn as_str<'a>(&'a self) -> &'a str {
         self.name.as_str()
     }
-
-    pub fn encode_with_hygiene(&self) -> String {
-        format!("\x00name_{},ctxt_{}\x00",
-                self.name.usize(),
-                self.ctxt)
-    }
 }
 
 impl fmt::Debug for Ident {
@@ -599,6 +593,12 @@ pub enum Pat_ {
     /// "None" means a * pattern where we don't bind the fields to names.
     PatEnum(Path, Option<Vec<P<Pat>>>),
 
+    /// An associated const named using the qualified path `<T>::CONST` or
+    /// `<T as Trait>::CONST`. Associated consts from inherent impls can be
+    /// refered to as simply `T::CONST`, in which case they will end up as
+    /// PatEnum, and the resolver will have to sort that out.
+    PatQPath(QSelf, Path),
+
     /// Destructuring of a struct, e.g. `Foo {x, y, ..}`
     /// The `bool` is `true` in the presence of a `..`
     PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
@@ -1236,6 +1236,7 @@ pub struct TraitItem {
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum TraitItem_ {
+    ConstTraitItem(P<Ty>, Option<P<Expr>>),
     MethodTraitItem(MethodSig, Option<P<Block>>),
     TypeTraitItem(TyParamBounds, Option<P<Ty>>),
 }
@@ -1252,6 +1253,7 @@ pub struct ImplItem {
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum ImplItem_ {
+    ConstImplItem(P<Ty>, P<Expr>),
     MethodImplItem(MethodSig, P<Block>),
     TypeImplItem(P<Ty>),
     MacImplItem(Mac),
@@ -1869,7 +1871,7 @@ pub struct MacroDef {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use serialize;
     use super::*;
 
diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs
index 1505d1e91b8..36a7f3a9381 100644
--- a/src/libsyntax/ast_map/blocks.rs
+++ b/src/libsyntax/ast_map/blocks.rs
@@ -222,8 +222,7 @@ impl<'a> FnLikeNode<'a> {
                     ast::MethodImplItem(ref sig, ref body) => {
                         method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span)
                     }
-                    ast::TypeImplItem(_) |
-                    ast::MacImplItem(_) => {
+                    _ => {
                         panic!("impl method FnLikeNode that is not fn-like")
                     }
                 }
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index 2a9a609ecd1..795391d4009 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -940,6 +940,12 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
         }
         Some(NodeImplItem(ii)) => {
             match ii.node {
+                ConstImplItem(..) => {
+                    format!("assoc const {} in {}{}",
+                            token::get_ident(ii.ident),
+                            map.path_to_string(id),
+                            id_str)
+                }
                 MethodImplItem(..) => {
                     format!("method {} in {}{}",
                             token::get_ident(ii.ident),
@@ -959,9 +965,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
         }
         Some(NodeTraitItem(ti)) => {
             let kind = match ti.node {
+                ConstTraitItem(..) => "assoc constant",
                 MethodTraitItem(..) => "trait method",
                 TypeTraitItem(..) => "assoc type",
-//                 ConstTraitItem(..) => "assoc constant"
             };
 
             format!("{} {} in {}{}",
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 78f06ce5fd5..8471fef3487 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -579,7 +579,7 @@ pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool {
             }
             PatMac(_) => panic!("attempted to analyze unexpanded pattern"),
             PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) |
-            PatEnum(_, _) => {
+            PatEnum(_, _) | PatQPath(_, _) => {
                 true
             }
         }
@@ -632,7 +632,7 @@ pub fn lit_is_str(lit: &Lit) -> bool {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use ast::*;
     use super::*;
 
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 34ad192845c..5e0cb647c8b 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -949,7 +949,7 @@ pub struct MalformedCodemapPositions {
 //
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
     use std::rc::Rc;
 
diff --git a/src/libsyntax/diagnostics/metadata.rs b/src/libsyntax/diagnostics/metadata.rs
new file mode 100644
index 00000000000..6cb4f70b860
--- /dev/null
+++ b/src/libsyntax/diagnostics/metadata.rs
@@ -0,0 +1,155 @@
+// Copyright 2015 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.
+
+//! This module contains utilities for outputting metadata for diagnostic errors.
+//!
+//! Each set of errors is mapped to a metadata file by a name, which is
+//! currently always a crate name.
+
+use std::collections::BTreeMap;
+use std::env;
+use std::path::PathBuf;
+use std::fs::{read_dir, create_dir_all, OpenOptions, File};
+use std::io::{Read, Write};
+use std::error::Error;
+use rustc_serialize::json::{self, as_json};
+
+use codemap::Span;
+use ext::base::ExtCtxt;
+use diagnostics::plugin::{ErrorMap, ErrorInfo};
+
+pub use self::Uniqueness::*;
+
+// Default metadata directory to use for extended error JSON.
+const ERROR_METADATA_DIR_DEFAULT: &'static str = "tmp/extended-errors";
+
+// The name of the environment variable that sets the metadata dir.
+const ERROR_METADATA_VAR: &'static str = "ERROR_METADATA_DIR";
+
+/// JSON encodable/decodable version of `ErrorInfo`.
+#[derive(PartialEq, RustcDecodable, RustcEncodable)]
+pub struct ErrorMetadata {
+    pub description: Option<String>,
+    pub use_site: Option<ErrorLocation>
+}
+
+/// Mapping from error codes to metadata that can be (de)serialized.
+pub type ErrorMetadataMap = BTreeMap<String, ErrorMetadata>;
+
+/// JSON encodable error location type with filename and line number.
+#[derive(PartialEq, RustcDecodable, RustcEncodable)]
+pub struct ErrorLocation {
+    pub filename: String,
+    pub line: usize
+}
+
+impl ErrorLocation {
+    /// Create an error location from a span.
+    pub fn from_span(ecx: &ExtCtxt, sp: Span) -> ErrorLocation {
+        let loc = ecx.codemap().lookup_char_pos_adj(sp.lo);
+        ErrorLocation {
+            filename: loc.filename,
+            line: loc.line
+        }
+    }
+}
+
+/// Type for describing the uniqueness of a set of error codes, as returned by `check_uniqueness`.
+pub enum Uniqueness {
+    /// All errors in the set checked are unique according to the metadata files checked.
+    Unique,
+    /// One or more errors in the set occur in another metadata file.
+    /// This variant contains the first duplicate error code followed by the name
+    /// of the metadata file where the duplicate appears.
+    Duplicate(String, String)
+}
+
+/// Get the directory where metadata files should be stored.
+pub fn get_metadata_dir() -> PathBuf {
+    match env::var(ERROR_METADATA_VAR) {
+        Ok(v) => From::from(v),
+        Err(_) => From::from(ERROR_METADATA_DIR_DEFAULT)
+    }
+}
+
+/// Get the path where error metadata for the set named by `name` should be stored.
+fn get_metadata_path(name: &str) -> PathBuf {
+    get_metadata_dir().join(format!("{}.json", name))
+}
+
+/// Check that the errors in `err_map` aren't present in any metadata files in the
+/// metadata directory except the metadata file corresponding to `name`.
+pub fn check_uniqueness(name: &str, err_map: &ErrorMap) -> Result<Uniqueness, Box<Error>> {
+    let metadata_dir = get_metadata_dir();
+    let metadata_path = get_metadata_path(name);
+
+    // Create the error directory if it does not exist.
+    try!(create_dir_all(&metadata_dir));
+
+    // Check each file in the metadata directory.
+    for entry in try!(read_dir(&metadata_dir)) {
+        let path = try!(entry).path();
+
+        // Skip any existing file for this set.
+        if path == metadata_path {
+            continue;
+        }
+
+        // Read the metadata file into a string.
+        let mut metadata_str = String::new();
+        try!(
+            File::open(&path).and_then(|mut f|
+            f.read_to_string(&mut metadata_str))
+        );
+
+        // Parse the JSON contents.
+        let metadata: ErrorMetadataMap = try!(json::decode(&metadata_str));
+
+        // Check for duplicates.
+        for err in err_map.keys() {
+            let err_code = err.as_str();
+            if metadata.contains_key(err_code) {
+                return Ok(Duplicate(
+                    err_code.to_string(),
+                    path.to_string_lossy().into_owned()
+                ));
+            }
+        }
+    }
+
+    Ok(Unique)
+}
+
+/// Write metadata for the errors in `err_map` to disk, to a file corresponding to `name`.
+pub fn output_metadata(ecx: &ExtCtxt, name: &str, err_map: &ErrorMap)
+    -> Result<(), Box<Error>>
+{
+    let metadata_path = get_metadata_path(name);
+
+    // Open the dump file.
+    let mut dump_file = try!(OpenOptions::new()
+        .write(true)
+        .create(true)
+        .open(&metadata_path)
+    );
+
+    // Construct a serializable map.
+    let json_map = err_map.iter().map(|(k, &ErrorInfo { description, use_site })| {
+        let key = k.as_str().to_string();
+        let value = ErrorMetadata {
+            description: description.map(|n| n.as_str().to_string()),
+            use_site: use_site.map(|sp| ErrorLocation::from_span(ecx, sp))
+        };
+        (key, value)
+    }).collect::<ErrorMetadataMap>();
+
+    try!(write!(&mut dump_file, "{}", as_json(&json_map)));
+    Ok(())
+}
diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs
index 6de4edafa0b..16841bd9039 100644
--- a/src/libsyntax/diagnostics/plugin.rs
+++ b/src/libsyntax/diagnostics/plugin.rs
@@ -14,6 +14,7 @@ use std::collections::BTreeMap;
 use ast;
 use ast::{Ident, Name, TokenTree};
 use codemap::Span;
+use diagnostics::metadata::{check_uniqueness, output_metadata, Duplicate};
 use ext::base::{ExtCtxt, MacEager, MacResult};
 use ext::build::AstBuilder;
 use parse::token;
@@ -24,32 +25,28 @@ use util::small_vector::SmallVector;
 const MAX_DESCRIPTION_WIDTH: usize = 80;
 
 thread_local! {
-    static REGISTERED_DIAGNOSTICS: RefCell<BTreeMap<Name, Option<Name>>> = {
+    static REGISTERED_DIAGNOSTICS: RefCell<ErrorMap> = {
         RefCell::new(BTreeMap::new())
     }
 }
-thread_local! {
-    static USED_DIAGNOSTICS: RefCell<BTreeMap<Name, Span>> = {
-        RefCell::new(BTreeMap::new())
-    }
+
+/// Error information type.
+pub struct ErrorInfo {
+    pub description: Option<Name>,
+    pub use_site: Option<Span>
 }
 
+/// Mapping from error codes to metadata.
+pub type ErrorMap = BTreeMap<Name, ErrorInfo>;
+
 fn with_registered_diagnostics<T, F>(f: F) -> T where
-    F: FnOnce(&mut BTreeMap<Name, Option<Name>>) -> T,
+    F: FnOnce(&mut ErrorMap) -> T,
 {
     REGISTERED_DIAGNOSTICS.with(move |slot| {
         f(&mut *slot.borrow_mut())
     })
 }
 
-fn with_used_diagnostics<T, F>(f: F) -> T where
-    F: FnOnce(&mut BTreeMap<Name, Span>) -> T,
-{
-    USED_DIAGNOSTICS.with(move |slot| {
-        f(&mut *slot.borrow_mut())
-    })
-}
-
 pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt,
                                    span: Span,
                                    token_tree: &[TokenTree])
@@ -58,23 +55,26 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt,
         (1, Some(&ast::TtToken(_, token::Ident(code, _)))) => code,
         _ => unreachable!()
     };
-    with_used_diagnostics(|diagnostics| {
-        match diagnostics.insert(code.name, span) {
-            Some(previous_span) => {
+
+    with_registered_diagnostics(|diagnostics| {
+        match diagnostics.get_mut(&code.name) {
+            // Previously used errors.
+            Some(&mut ErrorInfo { description: _, use_site: Some(previous_span) }) => {
                 ecx.span_warn(span, &format!(
                     "diagnostic code {} already used", &token::get_ident(code)
                 ));
                 ecx.span_note(previous_span, "previous invocation");
-            },
-            None => ()
-        }
-        ()
-    });
-    with_registered_diagnostics(|diagnostics| {
-        if !diagnostics.contains_key(&code.name) {
-            ecx.span_err(span, &format!(
-                "used diagnostic code {} not registered", &token::get_ident(code)
-            ));
+            }
+            // Newly used errors.
+            Some(ref mut info) => {
+                info.use_site = Some(span);
+            }
+            // Unregistered errors.
+            None => {
+                ecx.span_err(span, &format!(
+                    "used diagnostic code {} not registered", &token::get_ident(code)
+                ));
+            }
         }
     });
     MacEager::expr(ecx.expr_tuple(span, Vec::new()))
@@ -116,10 +116,14 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt,
                 token::get_ident(*code), MAX_DESCRIPTION_WIDTH
             ));
         }
-        raw_msg
     });
+    // Add the error to the map.
     with_registered_diagnostics(|diagnostics| {
-        if diagnostics.insert(code.name, description).is_some() {
+        let info = ErrorInfo {
+            description: description,
+            use_site: None
+        };
+        if diagnostics.insert(code.name, info).is_some() {
             ecx.span_err(span, &format!(
                 "diagnostic code {} already registered", &token::get_ident(*code)
             ));
@@ -143,19 +147,43 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
                                           span: Span,
                                           token_tree: &[TokenTree])
                                           -> Box<MacResult+'cx> {
-    let name = match (token_tree.len(), token_tree.get(0)) {
-        (1, Some(&ast::TtToken(_, token::Ident(ref name, _)))) => name,
+    assert_eq!(token_tree.len(), 3);
+    let (crate_name, name) = match (&token_tree[0], &token_tree[2]) {
+        (
+            // Crate name.
+            &ast::TtToken(_, token::Ident(ref crate_name, _)),
+            // DIAGNOSTICS ident.
+            &ast::TtToken(_, token::Ident(ref name, _))
+        ) => (crate_name.as_str(), name),
         _ => unreachable!()
     };
 
+    // Check uniqueness of errors and output metadata.
+    with_registered_diagnostics(|diagnostics| {
+        match check_uniqueness(crate_name, &*diagnostics) {
+            Ok(Duplicate(err, location)) => {
+                ecx.span_err(span, &format!(
+                    "error {} from `{}' also found in `{}'",
+                    err, crate_name, location
+                ));
+            },
+            Ok(_) => (),
+            Err(e) => panic!("{}", e.description())
+        }
+
+        output_metadata(&*ecx, crate_name, &*diagnostics).ok().expect("metadata output error");
+    });
+
+    // Construct the output expression.
     let (count, expr) =
         with_registered_diagnostics(|diagnostics| {
             let descriptions: Vec<P<ast::Expr>> =
-                diagnostics.iter().filter_map(|(code, description)| {
-                    description.map(|description| {
+                diagnostics.iter().filter_map(|(code, info)| {
+                    info.description.map(|description| {
                         ecx.expr_tuple(span, vec![
                             ecx.expr_str(span, token::get_name(*code)),
-                            ecx.expr_str(span, token::get_name(description))])
+                            ecx.expr_str(span, token::get_name(description))
+                        ])
                     })
                 }).collect();
             (descriptions.len(), ecx.expr_vec(span, descriptions))
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 5033f406da0..b8a79b0658d 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1580,7 +1580,7 @@ impl<'a, 'v> Visitor<'v> for MacroExterminator<'a> {
 
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::{pattern_bindings, expand_crate};
     use super::{PatIdentFinder, IdentRenamer, PatIdentRenamer, ExpansionConfig};
     use ast;
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index 5776fa99740..e100b7705d8 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -30,16 +30,16 @@ pub mod rt {
     use ext::base::ExtCtxt;
     use parse::token;
     use parse;
-    use print::pprust;
     use ptr::P;
+    use std::rc::Rc;
 
-    use ast::{TokenTree, Generics, Expr};
+    use ast::{TokenTree, Expr};
 
     pub use parse::new_parser_from_tts;
-    pub use codemap::{BytePos, Span, dummy_spanned};
+    pub use codemap::{BytePos, Span, dummy_spanned, DUMMY_SP};
 
     pub trait ToTokens {
-        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> ;
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
     }
 
     impl ToTokens for TokenTree {
@@ -70,277 +70,189 @@ pub mod rt {
         }
     }
 
-    /* Should be (when bugs in default methods are fixed):
-
-    trait ToSource : ToTokens {
-        // Takes a thing and generates a string containing rust code for it.
-        pub fn to_source() -> String;
-
-        // If you can make source, you can definitely make tokens.
-        pub fn to_tokens(cx: &ExtCtxt) -> ~[TokenTree] {
-            cx.parse_tts(self.to_source())
+    impl ToTokens for ast::Ident {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(DUMMY_SP, token::Ident(*self, token::Plain))]
         }
     }
 
-    */
-
-    // FIXME: Move this trait to pprust and get rid of *_to_str?
-    pub trait ToSource {
-        // Takes a thing and generates a string containing rust code for it.
-        fn to_source(&self) -> String;
+    impl ToTokens for ast::Path {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtPath(Box::new(self.clone()))))]
+        }
     }
 
-    // FIXME (Issue #16472): This should go away after ToToken impls
-    // are revised to go directly to token-trees.
-    trait ToSourceWithHygiene : ToSource {
-        // Takes a thing and generates a string containing rust code
-        // for it, encoding Idents as special byte sequences to
-        // maintain hygiene across serialization and deserialization.
-        fn to_source_with_hygiene(&self) -> String;
+    impl ToTokens for ast::Ty {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtTy(P(self.clone()))))]
+        }
     }
 
-    macro_rules! impl_to_source {
-        (P<$t:ty>, $pp:ident) => (
-            impl ToSource for P<$t> {
-                fn to_source(&self) -> String {
-                    pprust::$pp(&**self)
-                }
-            }
-            impl ToSourceWithHygiene for P<$t> {
-                fn to_source_with_hygiene(&self) -> String {
-                    pprust::with_hygiene::$pp(&**self)
-                }
-            }
-        );
-        ($t:ty, $pp:ident) => (
-            impl ToSource for $t {
-                fn to_source(&self) -> String {
-                    pprust::$pp(self)
-                }
-            }
-            impl ToSourceWithHygiene for $t {
-                fn to_source_with_hygiene(&self) -> String {
-                    pprust::with_hygiene::$pp(self)
-                }
-            }
-        );
+    impl ToTokens for ast::Block {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtBlock(P(self.clone()))))]
+        }
     }
 
-    fn slice_to_source<'a, T: ToSource>(sep: &'static str, xs: &'a [T]) -> String {
-        xs.iter()
-            .map(|i| i.to_source())
-            .collect::<Vec<String>>()
-            .connect(sep)
-            .to_string()
+    impl ToTokens for P<ast::Item> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtItem(self.clone())))]
+        }
     }
 
-    fn slice_to_source_with_hygiene<'a, T: ToSourceWithHygiene>(
-        sep: &'static str, xs: &'a [T]) -> String {
-        xs.iter()
-            .map(|i| i.to_source_with_hygiene())
-            .collect::<Vec<String>>()
-            .connect(sep)
-            .to_string()
+    impl ToTokens for P<ast::ImplItem> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtImplItem(self.clone())))]
+        }
     }
 
-    macro_rules! impl_to_source_slice {
-        ($t:ty, $sep:expr) => (
-            impl ToSource for [$t] {
-                fn to_source(&self) -> String {
-                    slice_to_source($sep, self)
-                }
-            }
-
-            impl ToSourceWithHygiene for [$t] {
-                fn to_source_with_hygiene(&self) -> String {
-                    slice_to_source_with_hygiene($sep, self)
-                }
-            }
-        )
+    impl ToTokens for P<ast::TraitItem> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtTraitItem(self.clone())))]
+        }
     }
 
-    impl ToSource for ast::Ident {
-        fn to_source(&self) -> String {
-            token::get_ident(*self).to_string()
+    impl ToTokens for P<ast::Stmt> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtStmt(self.clone())))]
         }
     }
 
-    impl ToSourceWithHygiene for ast::Ident {
-        fn to_source_with_hygiene(&self) -> String {
-            self.encode_with_hygiene()
+    impl ToTokens for P<ast::Expr> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtExpr(self.clone())))]
         }
     }
 
-    impl_to_source! { ast::Path, path_to_string }
-    impl_to_source! { ast::Ty, ty_to_string }
-    impl_to_source! { ast::Block, block_to_string }
-    impl_to_source! { ast::Arg, arg_to_string }
-    impl_to_source! { Generics, generics_to_string }
-    impl_to_source! { ast::WhereClause, where_clause_to_string }
-    impl_to_source! { P<ast::Item>, item_to_string }
-    impl_to_source! { P<ast::ImplItem>, impl_item_to_string }
-    impl_to_source! { P<ast::TraitItem>, trait_item_to_string }
-    impl_to_source! { P<ast::Stmt>, stmt_to_string }
-    impl_to_source! { P<ast::Expr>, expr_to_string }
-    impl_to_source! { P<ast::Pat>, pat_to_string }
-    impl_to_source! { ast::Arm, arm_to_string }
-    impl_to_source_slice! { ast::Ty, ", " }
-    impl_to_source_slice! { P<ast::Item>, "\n\n" }
-
-    impl ToSource for ast::Attribute_ {
-        fn to_source(&self) -> String {
-            pprust::attribute_to_string(&dummy_spanned(self.clone()))
+    impl ToTokens for P<ast::Pat> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(self.span, token::Interpolated(token::NtPat(self.clone())))]
         }
     }
-    impl ToSourceWithHygiene for ast::Attribute_ {
-        fn to_source_with_hygiene(&self) -> String {
-            self.to_source()
+
+    impl ToTokens for ast::Arm {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))]
         }
     }
 
-    impl ToSource for str {
-        fn to_source(&self) -> String {
-            let lit = dummy_spanned(ast::LitStr(
-                    token::intern_and_get_ident(self), ast::CookedStr));
-            pprust::lit_to_string(&lit)
-        }
+    macro_rules! impl_to_tokens_slice {
+        ($t: ty, $sep: expr) => {
+            impl ToTokens for [$t] {
+                fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+                    let mut v = vec![];
+                    for (i, x) in self.iter().enumerate() {
+                        if i > 0 {
+                            v.push_all(&$sep);
+                        }
+                        v.extend(x.to_tokens(cx));
+                    }
+                    v
+                }
+            }
+        };
     }
-    impl ToSourceWithHygiene for str {
-        fn to_source_with_hygiene(&self) -> String {
-            self.to_source()
+
+    impl_to_tokens_slice! { ast::Ty, [ast::TtToken(DUMMY_SP, token::Comma)] }
+    impl_to_tokens_slice! { P<ast::Item>, [] }
+
+    impl ToTokens for P<ast::MetaItem> {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtToken(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))]
         }
     }
 
-    impl ToSource for () {
-        fn to_source(&self) -> String {
-            "()".to_string()
+    impl ToTokens for ast::Attribute {
+        fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+            let mut r = vec![];
+            // FIXME: The spans could be better
+            r.push(ast::TtToken(self.span, token::Pound));
+            if self.node.style == ast::AttrInner {
+                r.push(ast::TtToken(self.span, token::Not));
+            }
+            r.push(ast::TtDelimited(self.span, Rc::new(ast::Delimited {
+                delim: token::Bracket,
+                open_span: self.span,
+                tts: self.node.value.to_tokens(cx),
+                close_span: self.span,
+            })));
+            r
         }
     }
-    impl ToSourceWithHygiene for () {
-        fn to_source_with_hygiene(&self) -> String {
-            self.to_source()
+
+    impl ToTokens for str {
+        fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+            let lit = ast::LitStr(
+                token::intern_and_get_ident(self), ast::CookedStr);
+            dummy_spanned(lit).to_tokens(cx)
         }
     }
 
-    impl ToSource for bool {
-        fn to_source(&self) -> String {
-            let lit = dummy_spanned(ast::LitBool(*self));
-            pprust::lit_to_string(&lit)
+    impl ToTokens for () {
+        fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
+            vec![ast::TtDelimited(DUMMY_SP, Rc::new(ast::Delimited {
+                delim: token::Paren,
+                open_span: DUMMY_SP,
+                tts: vec![],
+                close_span: DUMMY_SP,
+            }))]
         }
     }
-    impl ToSourceWithHygiene for bool {
-        fn to_source_with_hygiene(&self) -> String {
-            self.to_source()
+
+    impl ToTokens for ast::Lit {
+        fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+            // FIXME: This is wrong
+            P(ast::Expr {
+                id: ast::DUMMY_NODE_ID,
+                node: ast::ExprLit(P(self.clone())),
+                span: DUMMY_SP,
+            }).to_tokens(cx)
         }
     }
 
-    impl ToSource for char {
-        fn to_source(&self) -> String {
-            let lit = dummy_spanned(ast::LitChar(*self));
-            pprust::lit_to_string(&lit)
+    impl ToTokens for bool {
+        fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+            dummy_spanned(ast::LitBool(*self)).to_tokens(cx)
         }
     }
-    impl ToSourceWithHygiene for char {
-        fn to_source_with_hygiene(&self) -> String {
-            self.to_source()
+
+    impl ToTokens for char {
+        fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
+            dummy_spanned(ast::LitChar(*self)).to_tokens(cx)
         }
     }
 
-    macro_rules! impl_to_source_int {
+    macro_rules! impl_to_tokens_int {
         (signed, $t:ty, $tag:expr) => (
-            impl ToSource for $t {
-                fn to_source(&self) -> String {
+            impl ToTokens for $t {
+                fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                     let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag,
                                                                           ast::Sign::new(*self)));
-                    pprust::lit_to_string(&dummy_spanned(lit))
-                }
-            }
-            impl ToSourceWithHygiene for $t {
-                fn to_source_with_hygiene(&self) -> String {
-                    self.to_source()
+                    dummy_spanned(lit).to_tokens(cx)
                 }
             }
         );
         (unsigned, $t:ty, $tag:expr) => (
-            impl ToSource for $t {
-                fn to_source(&self) -> String {
+            impl ToTokens for $t {
+                fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
                     let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
-                    pprust::lit_to_string(&dummy_spanned(lit))
-                }
-            }
-            impl ToSourceWithHygiene for $t {
-                fn to_source_with_hygiene(&self) -> String {
-                    self.to_source()
+                    dummy_spanned(lit).to_tokens(cx)
                 }
             }
         );
     }
 
-    impl_to_source_int! { signed, isize, ast::TyIs }
-    impl_to_source_int! { signed, i8,  ast::TyI8 }
-    impl_to_source_int! { signed, i16, ast::TyI16 }
-    impl_to_source_int! { signed, i32, ast::TyI32 }
-    impl_to_source_int! { signed, i64, ast::TyI64 }
-
-    impl_to_source_int! { unsigned, usize, ast::TyUs }
-    impl_to_source_int! { unsigned, u8,   ast::TyU8 }
-    impl_to_source_int! { unsigned, u16,  ast::TyU16 }
-    impl_to_source_int! { unsigned, u32,  ast::TyU32 }
-    impl_to_source_int! { unsigned, u64,  ast::TyU64 }
-
-    // Alas ... we write these out instead. All redundant.
-
-    macro_rules! impl_to_tokens {
-        ($t:ty) => (
-            impl ToTokens for $t {
-                fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
-                    cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
-                }
-            }
-        )
-    }
+    impl_to_tokens_int! { signed, isize, ast::TyIs }
+    impl_to_tokens_int! { signed, i8,  ast::TyI8 }
+    impl_to_tokens_int! { signed, i16, ast::TyI16 }
+    impl_to_tokens_int! { signed, i32, ast::TyI32 }
+    impl_to_tokens_int! { signed, i64, ast::TyI64 }
 
-    macro_rules! impl_to_tokens_lifetime {
-        ($t:ty) => (
-            impl<'a> ToTokens for $t {
-                fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
-                    cx.parse_tts_with_hygiene(self.to_source_with_hygiene())
-                }
-            }
-        )
-    }
-
-    impl_to_tokens! { ast::Ident }
-    impl_to_tokens! { ast::Path }
-    impl_to_tokens! { P<ast::Item> }
-    impl_to_tokens! { P<ast::ImplItem> }
-    impl_to_tokens! { P<ast::TraitItem> }
-    impl_to_tokens! { P<ast::Pat> }
-    impl_to_tokens! { ast::Arm }
-    impl_to_tokens_lifetime! { &'a [P<ast::Item>] }
-    impl_to_tokens! { ast::Ty }
-    impl_to_tokens_lifetime! { &'a [ast::Ty] }
-    impl_to_tokens! { Generics }
-    impl_to_tokens! { ast::WhereClause }
-    impl_to_tokens! { P<ast::Stmt> }
-    impl_to_tokens! { P<ast::Expr> }
-    impl_to_tokens! { ast::Block }
-    impl_to_tokens! { ast::Arg }
-    impl_to_tokens! { ast::Attribute_ }
-    impl_to_tokens_lifetime! { &'a str }
-    impl_to_tokens! { () }
-    impl_to_tokens! { char }
-    impl_to_tokens! { bool }
-    impl_to_tokens! { isize }
-    impl_to_tokens! { i8 }
-    impl_to_tokens! { i16 }
-    impl_to_tokens! { i32 }
-    impl_to_tokens! { i64 }
-    impl_to_tokens! { usize }
-    impl_to_tokens! { u8 }
-    impl_to_tokens! { u16 }
-    impl_to_tokens! { u32 }
-    impl_to_tokens! { u64 }
+    impl_to_tokens_int! { unsigned, usize, ast::TyUs }
+    impl_to_tokens_int! { unsigned, u8,   ast::TyU8 }
+    impl_to_tokens_int! { unsigned, u16,  ast::TyU16 }
+    impl_to_tokens_int! { unsigned, u32,  ast::TyU32 }
+    impl_to_tokens_int! { unsigned, u64,  ast::TyU64 }
 
     pub trait ExtParseUtils {
         fn parse_item(&self, s: String) -> P<ast::Item>;
@@ -349,12 +261,6 @@ pub mod rt {
         fn parse_tts(&self, s: String) -> Vec<ast::TokenTree>;
     }
 
-    trait ExtParseUtilsWithHygiene {
-        // FIXME (Issue #16472): This should go away after ToToken impls
-        // are revised to go directly to token-trees.
-        fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree>;
-    }
-
     impl<'a> ExtParseUtils for ExtCtxt<'a> {
 
         fn parse_item(&self, s: String) -> P<ast::Item> {
@@ -386,19 +292,6 @@ pub mod rt {
                                              self.parse_sess())
         }
     }
-
-    impl<'a> ExtParseUtilsWithHygiene for ExtCtxt<'a> {
-
-        fn parse_tts_with_hygiene(&self, s: String) -> Vec<ast::TokenTree> {
-            use parse::with_hygiene::parse_tts_from_source_str;
-            parse_tts_from_source_str("<quote expansion>".to_string(),
-                                      s,
-                                      self.cfg(),
-                                      self.parse_sess())
-        }
-
-    }
-
 }
 
 pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index d0975c76e93..28deb4eec3f 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -93,10 +93,6 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
 
     ("fundamental", "1.0.0", Active),
 
-    // Deprecate after snapshot
-    // SNAP 5520801
-    ("unsafe_destructor", "1.0.0", Active),
-
     // A temporary feature gate used to enable parser extensions needed
     // to bootstrap fix for #5723.
     ("issue_5723_bootstrap", "1.0.0", Accepted),
@@ -155,6 +151,10 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
 
     // Allows use of unary negate on unsigned integers, e.g. -e for e: u8
     ("negate_unsigned", "1.0.0", Active),
+
+    // Allows the definition of associated constants in `trait` or `impl`
+    // blocks.
+    ("associated_consts", "1.0.0", Active),
 ];
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -205,8 +205,6 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[
     ("link_args", Normal),
     ("macro_escape", Normal),
 
-    ("unsafe_destructor", Gated("unsafe_destructor",
-                                "`#[unsafe_destructor]` does nothing anymore")),
     ("staged_api", Gated("staged_api",
                          "staged_api is for use by rustc only")),
     ("plugin", Gated("plugin",
@@ -394,7 +392,7 @@ impl<'a> Context<'a> {
                                are reserved for internal compiler diagnostics");
         } else if name.starts_with("derive_") {
             self.gate_feature("custom_derive", attr.span,
-                              "attributes of the form `#[derive_*]` are reserved
+                              "attributes of the form `#[derive_*]` are reserved \
                                for the compiler");
         } else {
             self.gate_feature("custom_attribute", attr.span,
@@ -620,7 +618,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
                                   pattern.span,
                                   "multiple-element slice matches anywhere \
                                    but at the end of a slice (e.g. \
-                                   `[0, ..xs, 0]` are experimental")
+                                   `[0, ..xs, 0]`) are experimental")
             }
             ast::PatVec(..) => {
                 self.gate_feature("slice_patterns",
@@ -659,6 +657,30 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
         }
         visit::walk_fn(self, fn_kind, fn_decl, block, span);
     }
+
+    fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
+        match ti.node {
+            ast::ConstTraitItem(..) => {
+                self.gate_feature("associated_consts",
+                                  ti.span,
+                                  "associated constants are experimental")
+            }
+            _ => {}
+        }
+        visit::walk_trait_item(self, ti);
+    }
+
+    fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
+        match ii.node {
+            ast::ConstImplItem(..) => {
+                self.gate_feature("associated_consts",
+                                  ii.span,
+                                  "associated constants are experimental")
+            }
+            _ => {}
+        }
+        visit::walk_impl_item(self, ii);
+    }
 }
 
 fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 8ba36cefc65..adfda988b23 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -682,6 +682,13 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T)
         token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)),
         token::NtPath(path) => token::NtPath(Box::new(fld.fold_path(*path))),
         token::NtTT(tt) => token::NtTT(P(fld.fold_tt(&*tt))),
+        token::NtArm(arm) => token::NtArm(fld.fold_arm(arm)),
+        token::NtImplItem(arm) =>
+            token::NtImplItem(fld.fold_impl_item(arm)
+                              .expect_one("expected fold to produce exactly one item")),
+        token::NtTraitItem(arm) =>
+            token::NtTraitItem(fld.fold_trait_item(arm)
+                               .expect_one("expected fold to produce exactly one item")),
     }
 }
 
@@ -973,6 +980,10 @@ pub fn noop_fold_trait_item<T: Folder>(i: P<TraitItem>, folder: &mut T)
         ident: folder.fold_ident(ident),
         attrs: fold_attrs(attrs, folder),
         node: match node {
+            ConstTraitItem(ty, default) => {
+                ConstTraitItem(folder.fold_ty(ty),
+                               default.map(|x| folder.fold_expr(x)))
+            }
             MethodTraitItem(sig, body) => {
                 MethodTraitItem(noop_fold_method_sig(sig, folder),
                                 body.map(|x| folder.fold_block(x)))
@@ -994,6 +1005,9 @@ pub fn noop_fold_impl_item<T: Folder>(i: P<ImplItem>, folder: &mut T)
         attrs: fold_attrs(attrs, folder),
         vis: vis,
         node: match node  {
+            ConstImplItem(ty, expr) => {
+                ConstImplItem(folder.fold_ty(ty), folder.fold_expr(expr))
+            }
             MethodImplItem(sig, body) => {
                 MethodImplItem(noop_fold_method_sig(sig, folder),
                                folder.fold_block(body))
@@ -1127,6 +1141,10 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
                 PatEnum(folder.fold_path(pth),
                         pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
             }
+            PatQPath(qself, pth) => {
+                let qself = QSelf {ty: folder.fold_ty(qself.ty), .. qself};
+                PatQPath(qself, folder.fold_path(pth))
+            }
             PatStruct(pth, fields, etc) => {
                 let pth = folder.fold_path(pth);
                 let fs = fields.move_map(|f| {
@@ -1343,7 +1361,7 @@ pub fn noop_fold_stmt<T: Folder>(Spanned {node, span}: Stmt, folder: &mut T)
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use std::io;
     use ast;
     use util::parser_testing::{string_to_crate, matches_codepattern};
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index d8beeb6a550..275400009f5 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -25,13 +25,14 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/nightly/")]
 
+#![feature(associated_consts)]
 #![feature(collections)]
 #![feature(core)]
 #![feature(libc)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(unicode)]
 #![feature(str_char)]
+#![feature(unicode)]
 
 extern crate arena;
 extern crate fmt_macros;
@@ -69,6 +70,7 @@ pub mod diagnostics {
     pub mod macros;
     pub mod plugin;
     pub mod registry;
+    pub mod metadata;
 }
 
 pub mod syntax {
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index fb3a96f4c28..1577b50ad76 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -383,7 +383,7 @@ pub fn gather_comments_and_literals(span_diagnostic: &diagnostic::SpanHandler,
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     #[test] fn test_block_doc_comment_1() {
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 8e37b983e21..6b0674c9a41 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -19,7 +19,6 @@ use str::char_at;
 
 use std::borrow::Cow;
 use std::char;
-use std::fmt;
 use std::mem::replace;
 use std::rc::Rc;
 
@@ -71,11 +70,6 @@ pub struct StringReader<'a> {
     pub peek_tok: token::Token,
     pub peek_span: Span,
 
-    // FIXME (Issue #16472): This field should go away after ToToken impls
-    // are revised to go directly to token-trees.
-    /// Is \x00<name>,<ctxt>\x00 is interpreted as encoded ast::Ident?
-    read_embedded_ident: bool,
-
     // cache a direct reference to the source text, so that we don't have to
     // retrieve it via `self.filemap.src.as_ref().unwrap()` all the time.
     source_text: Rc<String>
@@ -130,17 +124,6 @@ impl<'a> Reader for TtReader<'a> {
     }
 }
 
-// FIXME (Issue #16472): This function should go away after
-// ToToken impls are revised to go directly to token-trees.
-pub fn make_reader_with_embedded_idents<'b>(span_diagnostic: &'b SpanHandler,
-                                            filemap: Rc<codemap::FileMap>)
-                                            -> StringReader<'b> {
-    let mut sr = StringReader::new_raw(span_diagnostic, filemap);
-    sr.read_embedded_ident = true;
-    sr.advance_token();
-    sr
-}
-
 impl<'a> StringReader<'a> {
     /// For comments.rs, which hackily pokes into pos and curr
     pub fn new_raw<'b>(span_diagnostic: &'b SpanHandler,
@@ -162,7 +145,6 @@ impl<'a> StringReader<'a> {
             /* dummy values; not read */
             peek_tok: token::Eof,
             peek_span: codemap::DUMMY_SP,
-            read_embedded_ident: false,
             source_text: source_text
         };
         sr.bump();
@@ -578,81 +560,6 @@ impl<'a> StringReader<'a> {
         })
     }
 
-    // FIXME (Issue #16472): The scan_embedded_hygienic_ident function
-    // should go away after we revise the syntax::ext::quote::ToToken
-    // impls to go directly to token-trees instead of thing -> string
-    // -> token-trees.  (The function is currently used to resolve
-    // Issues #15750 and #15962.)
-    //
-    // Since this function is only used for certain internal macros,
-    // and the functionality it provides is not exposed to end user
-    // programs, pnkfelix deliberately chose to write it in a way that
-    // favors rustc debugging effectiveness over runtime efficiency.
-
-    /// Scan through input of form \x00name_NNNNNN,ctxt_CCCCCCC\x00
-    /// whence: `NNNNNN` is a string of characters forming an integer
-    /// (the name) and `CCCCCCC` is a string of characters forming an
-    /// integer (the ctxt), separate by a comma and delimited by a
-    /// `\x00` marker.
-    #[inline(never)]
-    fn scan_embedded_hygienic_ident(&mut self) -> ast::Ident {
-        fn bump_expecting_char<'a,D:fmt::Debug>(r: &mut StringReader<'a>,
-                                                c: char,
-                                                described_c: D,
-                                                whence: &str) {
-            match r.curr {
-                Some(r_c) if r_c == c => r.bump(),
-                Some(r_c) => panic!("expected {:?}, hit {:?}, {}", described_c, r_c, whence),
-                None      => panic!("expected {:?}, hit EOF, {}", described_c, whence),
-            }
-        }
-
-        let whence = "while scanning embedded hygienic ident";
-
-        // skip over the leading `\x00`
-        bump_expecting_char(self, '\x00', "nul-byte", whence);
-
-        // skip over the "name_"
-        for c in "name_".chars() {
-            bump_expecting_char(self, c, c, whence);
-        }
-
-        let start_bpos = self.last_pos;
-        let base = 10;
-
-        // find the integer representing the name
-        self.scan_digits(base, base);
-        let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
-            u32::from_str_radix(s, 10).unwrap_or_else(|_| {
-                panic!("expected digits representing a name, got {:?}, {}, range [{:?},{:?}]",
-                      s, whence, start_bpos, self.last_pos);
-            })
-        });
-
-        // skip over the `,`
-        bump_expecting_char(self, ',', "comma", whence);
-
-        // skip over the "ctxt_"
-        for c in "ctxt_".chars() {
-            bump_expecting_char(self, c, c, whence);
-        }
-
-        // find the integer representing the ctxt
-        let start_bpos = self.last_pos;
-        self.scan_digits(base, base);
-        let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
-            u32::from_str_radix(s, 10).unwrap_or_else(|_| {
-                panic!("expected digits representing a ctxt, got {:?}, {}", s, whence);
-            })
-        });
-
-        // skip over the `\x00`
-        bump_expecting_char(self, '\x00', "nul-byte", whence);
-
-        ast::Ident { name: ast::Name(encoded_name),
-                     ctxt: encoded_ctxt, }
-    }
-
     /// Scan through any digits (base `scan_radix`) or underscores,
     /// and return how many digits there were.
     ///
@@ -1020,20 +927,6 @@ impl<'a> StringReader<'a> {
             return token::Literal(num, suffix)
         }
 
-        if self.read_embedded_ident {
-            match (c.unwrap(), self.nextch(), self.nextnextch()) {
-                ('\x00', Some('n'), Some('a')) => {
-                    let ast_ident = self.scan_embedded_hygienic_ident();
-                    return if self.curr_is(':') && self.nextch_is(':') {
-                        token::Ident(ast_ident, token::ModName)
-                    } else {
-                        token::Ident(ast_ident, token::Plain)
-                    };
-                }
-                _ => {}
-            }
-        }
-
         match c.expect("next_token_inner called at EOF") {
           // One-byte tokens.
           ';' => { self.bump(); return token::Semi; }
@@ -1501,7 +1394,7 @@ fn ident_continue(c: Option<char>) -> bool {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     use codemap::{BytePos, CodeMap, Span, NO_EXPANSION};
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 1a1713a8ba6..8c9ce5f78d4 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -166,9 +166,6 @@ pub fn parse_stmt_from_source_str(name: String,
     maybe_aborted(p.parse_stmt(), p)
 }
 
-// Note: keep in sync with `with_hygiene::parse_tts_from_source_str`
-// until #16472 is resolved.
-//
 // Warning: This parses with quote_depth > 0, which is not the default.
 pub fn parse_tts_from_source_str(name: String,
                                  source: String,
@@ -186,8 +183,6 @@ pub fn parse_tts_from_source_str(name: String,
     maybe_aborted(panictry!(p.parse_all_token_trees()),p)
 }
 
-// Note: keep in sync with `with_hygiene::new_parser_from_source_str`
-// until #16472 is resolved.
 // Create a new parser from a source string
 pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess,
                                       cfg: ast::CrateConfig,
@@ -220,8 +215,6 @@ pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess,
     p
 }
 
-// Note: keep this in sync with `with_hygiene::filemap_to_parser` until
-// #16472 is resolved.
 /// Given a filemap and config, return a parser
 pub fn filemap_to_parser<'a>(sess: &'a ParseSess,
                              filemap: Rc<FileMap>,
@@ -277,8 +270,6 @@ pub fn string_to_filemap(sess: &ParseSess, source: String, path: String)
     sess.span_diagnostic.cm.new_filemap(path, source)
 }
 
-// Note: keep this in sync with `with_hygiene::filemap_to_tts` (apart
-// from the StringReader constructor), until #16472 is resolved.
 /// Given a filemap, produce a sequence of token-trees
 pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
     -> Vec<ast::TokenTree> {
@@ -300,69 +291,6 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess,
     p
 }
 
-// FIXME (Issue #16472): The `with_hygiene` mod should go away after
-// ToToken impls are revised to go directly to token-trees.
-pub mod with_hygiene {
-    use ast;
-    use codemap::FileMap;
-    use parse::parser::Parser;
-    use std::rc::Rc;
-    use super::ParseSess;
-    use super::{maybe_aborted, string_to_filemap, tts_to_parser};
-
-    // Note: keep this in sync with `super::parse_tts_from_source_str` until
-    // #16472 is resolved.
-    //
-    // Warning: This parses with quote_depth > 0, which is not the default.
-    pub fn parse_tts_from_source_str(name: String,
-                                     source: String,
-                                     cfg: ast::CrateConfig,
-                                     sess: &ParseSess) -> Vec<ast::TokenTree> {
-        let mut p = new_parser_from_source_str(
-            sess,
-            cfg,
-            name,
-            source
-        );
-        p.quote_depth += 1;
-        // right now this is re-creating the token trees from ... token trees.
-        maybe_aborted(panictry!(p.parse_all_token_trees()),p)
-    }
-
-    // Note: keep this in sync with `super::new_parser_from_source_str` until
-    // #16472 is resolved.
-    // Create a new parser from a source string
-    fn new_parser_from_source_str<'a>(sess: &'a ParseSess,
-                                      cfg: ast::CrateConfig,
-                                      name: String,
-                                      source: String) -> Parser<'a> {
-        filemap_to_parser(sess, string_to_filemap(sess, source, name), cfg)
-    }
-
-    // Note: keep this in sync with `super::filemap_to_parserr` until
-    // #16472 is resolved.
-    /// Given a filemap and config, return a parser
-    fn filemap_to_parser<'a>(sess: &'a ParseSess,
-                             filemap: Rc<FileMap>,
-                             cfg: ast::CrateConfig) -> Parser<'a> {
-        tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg)
-    }
-
-    // Note: keep this in sync with `super::filemap_to_tts` until
-    // #16472 is resolved.
-    /// Given a filemap, produce a sequence of token-trees
-    fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
-                      -> Vec<ast::TokenTree> {
-        // it appears to me that the cfg doesn't matter here... indeed,
-        // parsing tt's probably shouldn't require a parser at all.
-        use super::lexer::make_reader_with_embedded_idents as make_reader;
-        let cfg = Vec::new();
-        let srdr = make_reader(&sess.span_diagnostic, filemap);
-        let mut p1 = Parser::new(sess, cfg, Box::new(srdr));
-        panictry!(p1.parse_all_token_trees())
-    }
-}
-
 /// Abort if necessary
 pub fn maybe_aborted<T>(result: T, p: Parser) -> T {
     p.abort_if_errors();
@@ -761,7 +689,7 @@ pub fn integer_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) ->
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
     use std::rc::Rc;
     use codemap::{Span, BytePos, Pos, Spanned, NO_EXPANSION};
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 68006a8979a..5f76c214927 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -17,8 +17,8 @@ use ast::{Public, Unsafety};
 use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
 use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block};
 use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause};
-use ast::{Crate, CrateConfig, Decl, DeclItem};
-use ast::{DeclLocal, DefaultBlock, DefaultReturn};
+use ast::{ConstImplItem, ConstTraitItem, Crate, CrateConfig};
+use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn};
 use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
 use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
 use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
@@ -40,8 +40,9 @@ use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces};
 use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource};
 use ast::{MutTy, BiMul, Mutability};
 use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
-use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatMac, PatRange, PatRegion};
-use ast::{PatStruct, PatTup, PatVec, PatWild, PatWildMulti, PatWildSingle};
+use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange};
+use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild, PatWildMulti};
+use ast::PatWildSingle;
 use ast::{PolyTraitRef, QSelf};
 use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
 use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
@@ -87,9 +88,9 @@ use std::slice;
 
 bitflags! {
     flags Restrictions: u8 {
-        const UNRESTRICTED                  = 0b0000,
-        const RESTRICTION_STMT_EXPR         = 0b0001,
-        const RESTRICTION_NO_STRUCT_LITERAL = 0b0010,
+        const UNRESTRICTED                  = 0,
+        const RESTRICTION_STMT_EXPR         = 1 << 0,
+        const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1,
     }
 }
 
@@ -109,6 +110,15 @@ pub enum PathParsingMode {
     LifetimeAndTypesWithColons,
 }
 
+/// How to parse a qualified path, whether to allow trailing parameters.
+#[derive(Copy, Clone, PartialEq)]
+pub enum QPathParsingMode {
+    /// No trailing parameters, e.g. `<T as Trait>::Item`
+    NoParameters,
+    /// Optional parameters, e.g. `<T as Trait>::item::<'a, U>`
+    MaybeParameters,
+}
+
 /// How to parse a bound, whether to allow bound modifiers such as `?`.
 #[derive(Copy, Clone, PartialEq)]
 pub enum BoundParsingMode {
@@ -329,7 +339,7 @@ impl<'a> Parser<'a> {
             buffer_start: 0,
             buffer_end: 0,
             tokens_consumed: 0,
-            restrictions: UNRESTRICTED,
+            restrictions: Restrictions::UNRESTRICTED,
             quote_depth: 0,
             obsolete_set: HashSet::new(),
             mod_path_stack: Vec::new(),
@@ -902,7 +912,9 @@ impl<'a> Parser<'a> {
     pub fn bump(&mut self) -> PResult<()> {
         self.last_span = self.span;
         // Stash token for error recovery (sometimes; clone is not necessarily cheap).
-        self.last_token = if self.token.is_ident() || self.token.is_path() {
+        self.last_token = if self.token.is_ident() ||
+                          self.token.is_path() ||
+                          self.token == token::Comma {
             Some(Box::new(self.token.clone()))
         } else {
             None
@@ -1150,7 +1162,8 @@ impl<'a> Parser<'a> {
             &token::OpenDelim(token::Brace),
             &token::CloseDelim(token::Brace),
             seq_sep_none(),
-            |p| {
+            |p| -> PResult<P<TraitItem>> {
+            maybe_whole!(no_clone p, NtTraitItem);
             let mut attrs = p.parse_outer_attributes();
             let lo = p.span.lo;
 
@@ -1158,6 +1171,20 @@ impl<'a> Parser<'a> {
                 let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param());
                 try!(p.expect(&token::Semi));
                 (ident, TypeTraitItem(bounds, default))
+            } else if try!(p.eat_keyword(keywords::Const)) {
+                let ident = try!(p.parse_ident());
+                try!(p.expect(&token::Colon));
+                let ty = try!(p.parse_ty_sum());
+                let default = if p.check(&token::Eq) {
+                    try!(p.bump());
+                    let expr = try!(p.parse_expr_nopanic());
+                    try!(p.commit_expr_expecting(&expr, token::Semi));
+                    Some(expr)
+                } else {
+                    try!(p.expect(&token::Semi));
+                    None
+                };
+                (ident, ConstTraitItem(ty, default))
             } else {
                 let style = try!(p.parse_unsafety());
                 let abi = if try!(p.eat_keyword(keywords::Extern)) {
@@ -1331,36 +1358,9 @@ impl<'a> Parser<'a> {
             try!(self.expect(&token::CloseDelim(token::Paren)));
             TyTypeof(e)
         } else if try!(self.eat_lt()) {
-            // QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
-            let self_type = try!(self.parse_ty_sum());
-
-            let mut path = if try!(self.eat_keyword(keywords::As) ){
-                try!(self.parse_path(LifetimeAndTypesWithoutColons))
-            } else {
-                ast::Path {
-                    span: self.span,
-                    global: false,
-                    segments: vec![]
-                }
-            };
-
-            let qself = QSelf {
-                ty: self_type,
-                position: path.segments.len()
-            };
 
-            try!(self.expect(&token::Gt));
-            try!(self.expect(&token::ModSep));
-
-            path.segments.push(ast::PathSegment {
-                identifier: try!(self.parse_ident()),
-                parameters: ast::PathParameters::none()
-            });
-
-            if path.segments.len() == 1 {
-                path.span.lo = self.last_span.lo;
-            }
-            path.span.hi = self.last_span.hi;
+            let (qself, path) =
+                 try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
 
             TyPath(Some(qself), path)
         } else if self.check(&token::ModSep) ||
@@ -1577,6 +1577,61 @@ impl<'a> Parser<'a> {
         }
     }
 
+    // QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]`
+    // Assumes that the leading `<` has been parsed already.
+    pub fn parse_qualified_path(&mut self, mode: QPathParsingMode)
+                                -> PResult<(QSelf, ast::Path)> {
+        let self_type = try!(self.parse_ty_sum());
+        let mut path = if try!(self.eat_keyword(keywords::As)) {
+            try!(self.parse_path(LifetimeAndTypesWithoutColons))
+        } else {
+            ast::Path {
+                span: self.span,
+                global: false,
+                segments: vec![]
+            }
+        };
+
+        let qself = QSelf {
+            ty: self_type,
+            position: path.segments.len()
+        };
+
+        try!(self.expect(&token::Gt));
+        try!(self.expect(&token::ModSep));
+
+        let item_name = try!(self.parse_ident());
+        let parameters = match mode {
+            QPathParsingMode::NoParameters => ast::PathParameters::none(),
+            QPathParsingMode::MaybeParameters => {
+                if try!(self.eat(&token::ModSep)) {
+                    try!(self.expect_lt());
+                    // Consumed `item::<`, go look for types
+                    let (lifetimes, types, bindings) =
+                        try!(self.parse_generic_values_after_lt());
+                    ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
+                        lifetimes: lifetimes,
+                        types: OwnedSlice::from_vec(types),
+                        bindings: OwnedSlice::from_vec(bindings),
+                    })
+                } else {
+                    ast::PathParameters::none()
+                }
+            }
+        };
+        path.segments.push(ast::PathSegment {
+            identifier: item_name,
+            parameters: parameters
+        });
+
+        if path.segments.len() == 1 {
+            path.span.lo = self.last_span.lo;
+        }
+        path.span.hi = self.last_span.hi;
+
+        Ok((qself, path))
+    }
+
     /// Parses a path and optional type parameter bounds, depending on the
     /// mode. The `mode` parameter determines whether lifetimes, types, and/or
     /// bounds are permitted and whether `::` must precede type parameter
@@ -2040,49 +2095,10 @@ impl<'a> Parser<'a> {
             }
             _ => {
                 if try!(self.eat_lt()){
-                    // QUALIFIED PATH `<TYPE as TRAIT_REF>::item::<'a, T>`
-                    let self_type = try!(self.parse_ty_sum());
-                    let mut path = if try!(self.eat_keyword(keywords::As) ){
-                        try!(self.parse_path(LifetimeAndTypesWithoutColons))
-                    } else {
-                        ast::Path {
-                            span: self.span,
-                            global: false,
-                            segments: vec![]
-                        }
-                    };
-                    let qself = QSelf {
-                        ty: self_type,
-                        position: path.segments.len()
-                    };
-                    try!(self.expect(&token::Gt));
-                    try!(self.expect(&token::ModSep));
 
-                    let item_name = try!(self.parse_ident());
-                    let parameters = if try!(self.eat(&token::ModSep) ){
-                        try!(self.expect_lt());
-                        // Consumed `item::<`, go look for types
-                        let (lifetimes, types, bindings) =
-                            try!(self.parse_generic_values_after_lt());
-                        ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
-                            lifetimes: lifetimes,
-                            types: OwnedSlice::from_vec(types),
-                            bindings: OwnedSlice::from_vec(bindings),
-                        })
-                    } else {
-                        ast::PathParameters::none()
-                    };
-                    path.segments.push(ast::PathSegment {
-                        identifier: item_name,
-                        parameters: parameters
-                    });
-
-                    if path.segments.len() == 1 {
-                        path.span.lo = self.last_span.lo;
-                    }
-                    path.span.hi = self.last_span.hi;
+                    let (qself, path) =
+                        try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters));
 
-                    let hi = self.span.hi;
                     return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
                 }
                 if try!(self.eat_keyword(keywords::Move) ){
@@ -2182,7 +2198,10 @@ impl<'a> Parser<'a> {
                     if self.check(&token::OpenDelim(token::Brace)) {
                         // This is a struct literal, unless we're prohibited
                         // from parsing struct literals here.
-                        if !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL) {
+                        let prohibited = self.restrictions.contains(
+                            Restrictions::RESTRICTION_NO_STRUCT_LITERAL
+                        );
+                        if !prohibited {
                             // It's a struct literal.
                             try!(self.bump());
                             let mut fields = Vec::new();
@@ -2743,7 +2762,7 @@ impl<'a> Parser<'a> {
     }
 
     pub fn parse_assign_expr_with(&mut self, lhs: P<Expr>) -> PResult<P<Expr>> {
-        let restrictions = self.restrictions & RESTRICTION_NO_STRUCT_LITERAL;
+        let restrictions = self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL;
         let op_span = self.span;
         match self.token {
           token::Eq => {
@@ -2798,7 +2817,7 @@ impl<'a> Parser<'a> {
         if self.token.can_begin_expr() {
             // parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
             if self.token == token::OpenDelim(token::Brace) {
-                return !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL);
+                return !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL);
             }
             true
         } else {
@@ -2812,7 +2831,7 @@ impl<'a> Parser<'a> {
             return self.parse_if_let_expr();
         }
         let lo = self.last_span.lo;
-        let cond = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let thn = try!(self.parse_block());
         let mut els: Option<P<Expr>> = None;
         let mut hi = thn.span.hi;
@@ -2830,7 +2849,7 @@ impl<'a> Parser<'a> {
         try!(self.expect_keyword(keywords::Let));
         let pat = try!(self.parse_pat_nopanic());
         try!(self.expect(&token::Eq));
-        let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let thn = try!(self.parse_block());
         let (hi, els) = if try!(self.eat_keyword(keywords::Else) ){
             let expr = try!(self.parse_else_expr());
@@ -2889,7 +2908,7 @@ impl<'a> Parser<'a> {
         let lo = self.last_span.lo;
         let pat = try!(self.parse_pat_nopanic());
         try!(self.expect_keyword(keywords::In));
-        let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let loop_block = try!(self.parse_block());
         let hi = self.last_span.hi;
 
@@ -2902,7 +2921,7 @@ impl<'a> Parser<'a> {
             return self.parse_while_let_expr(opt_ident);
         }
         let lo = self.last_span.lo;
-        let cond = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let body = try!(self.parse_block());
         let hi = body.span.hi;
         return Ok(self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident)));
@@ -2914,7 +2933,7 @@ impl<'a> Parser<'a> {
         try!(self.expect_keyword(keywords::Let));
         let pat = try!(self.parse_pat_nopanic());
         try!(self.expect(&token::Eq));
-        let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         let body = try!(self.parse_block());
         let hi = body.span.hi;
         return Ok(self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident)));
@@ -2929,7 +2948,7 @@ impl<'a> Parser<'a> {
 
     fn parse_match_expr(&mut self) -> PResult<P<Expr>> {
         let lo = self.last_span.lo;
-        let discriminant = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL));
+        let discriminant = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
         try!(self.commit_expr_expecting(&*discriminant, token::OpenDelim(token::Brace)));
         let mut arms: Vec<Arm> = Vec::new();
         while self.token != token::CloseDelim(token::Brace) {
@@ -2941,6 +2960,8 @@ impl<'a> Parser<'a> {
     }
 
     pub fn parse_arm_nopanic(&mut self) -> PResult<Arm> {
+        maybe_whole!(no_clone self, NtArm);
+
         let attrs = self.parse_outer_attributes();
         let pats = try!(self.parse_pats());
         let mut guard = None;
@@ -2948,7 +2969,7 @@ impl<'a> Parser<'a> {
             guard = Some(try!(self.parse_expr_nopanic()));
         }
         try!(self.expect(&token::FatArrow));
-        let expr = try!(self.parse_expr_res(RESTRICTION_STMT_EXPR));
+        let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR));
 
         let require_comma =
             !classify::expr_is_simple_block(&*expr)
@@ -2970,7 +2991,7 @@ impl<'a> Parser<'a> {
 
     /// Parse an expression
     pub fn parse_expr_nopanic(&mut self) -> PResult<P<Expr>> {
-        return self.parse_expr_res(UNRESTRICTED);
+        return self.parse_expr_res(Restrictions::UNRESTRICTED);
     }
 
     /// Parse an expression, subject to the given restrictions
@@ -3153,16 +3174,25 @@ impl<'a> Parser<'a> {
     fn parse_pat_range_end(&mut self) -> PResult<P<Expr>> {
         if self.is_path_start() {
             let lo = self.span.lo;
-            let path = try!(self.parse_path(LifetimeAndTypesWithColons));
+            let (qself, path) = if try!(self.eat_lt()) {
+                // Parse a qualified path
+                let (qself, path) =
+                    try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
+                (Some(qself), path)
+            } else {
+                // Parse an unqualified path
+                (None, try!(self.parse_path(LifetimeAndTypesWithColons)))
+            };
             let hi = self.last_span.hi;
-            Ok(self.mk_expr(lo, hi, ExprPath(None, path)))
+            Ok(self.mk_expr(lo, hi, ExprPath(qself, path)))
         } else {
             self.parse_literal_maybe_minus()
         }
     }
 
     fn is_path_start(&self) -> bool {
-        (self.token == token::ModSep || self.token.is_ident() || self.token.is_path())
+        (self.token == token::Lt || self.token == token::ModSep
+            || self.token.is_ident() || self.token.is_path())
             && !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False)
     }
 
@@ -3238,25 +3268,44 @@ impl<'a> Parser<'a> {
                         pat = try!(self.parse_pat_ident(BindByValue(MutImmutable)));
                     }
                 } else {
-                    // Parse as a general path
-                    let path = try!(self.parse_path(LifetimeAndTypesWithColons));
+                    let (qself, path) = if try!(self.eat_lt()) {
+                        // Parse a qualified path
+                        let (qself, path) =
+                            try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
+                        (Some(qself), path)
+                    } else {
+                        // Parse an unqualified path
+                        (None, try!(self.parse_path(LifetimeAndTypesWithColons)))
+                    };
                     match self.token {
                       token::DotDotDot => {
                         // Parse range
                         let hi = self.last_span.hi;
-                        let begin = self.mk_expr(lo, hi, ExprPath(None, path));
+                        let begin = self.mk_expr(lo, hi, ExprPath(qself, path));
                         try!(self.bump());
                         let end = try!(self.parse_pat_range_end());
                         pat = PatRange(begin, end);
                       }
                       token::OpenDelim(token::Brace) => {
-                        // Parse struct pattern
+                         if qself.is_some() {
+                            let span = self.span;
+                            self.span_err(span,
+                                          "unexpected `{` after qualified path");
+                            self.abort_if_errors();
+                        }
+                       // Parse struct pattern
                         try!(self.bump());
                         let (fields, etc) = try!(self.parse_pat_fields());
                         try!(self.bump());
                         pat = PatStruct(path, fields, etc);
                       }
                       token::OpenDelim(token::Paren) => {
+                        if qself.is_some() {
+                            let span = self.span;
+                            self.span_err(span,
+                                          "unexpected `(` after qualified path");
+                            self.abort_if_errors();
+                        }
                         // Parse tuple struct or enum pattern
                         if self.look_ahead(1, |t| *t == token::DotDot) {
                             // This is a "top constructor only" pat
@@ -3273,6 +3322,10 @@ impl<'a> Parser<'a> {
                             pat = PatEnum(path, Some(args));
                         }
                       }
+                      _ if qself.is_some() => {
+                        // Parse qualified path
+                        pat = PatQPath(qself.unwrap(), path);
+                      }
                       _ => {
                         // Parse nullary enum
                         pat = PatEnum(path, Some(vec![]));
@@ -3514,7 +3567,7 @@ impl<'a> Parser<'a> {
                     }
 
                     // Remainder are line-expr stmts.
-                    let e = try!(self.parse_expr_res(RESTRICTION_STMT_EXPR));
+                    let e = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR));
                     spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID))
                 }
             }
@@ -3523,7 +3576,7 @@ impl<'a> Parser<'a> {
 
     /// Is this expression a successfully-parsed statement?
     fn expr_is_complete(&mut self, e: &Expr) -> bool {
-        self.restrictions.contains(RESTRICTION_STMT_EXPR) &&
+        self.restrictions.contains(Restrictions::RESTRICTION_STMT_EXPR) &&
             !classify::expr_requires_semi_to_be_stmt(e)
     }
 
@@ -3807,8 +3860,37 @@ impl<'a> Parser<'a> {
     fn parse_generic_values_after_lt(&mut self) -> PResult<(Vec<ast::Lifetime>,
                                                             Vec<P<Ty>>,
                                                             Vec<P<TypeBinding>>)> {
+        let span_lo = self.span.lo;
         let lifetimes = try!(self.parse_lifetimes(token::Comma));
 
+        let missing_comma = !lifetimes.is_empty() &&
+                            !self.token.is_like_gt() &&
+                            self.last_token
+                                .as_ref().map_or(true,
+                                                 |x| &**x != &token::Comma);
+
+        if missing_comma {
+
+            let msg = format!("expected `,` or `>` after lifetime \
+                              name, found `{}`",
+                              self.this_token_to_string());
+            self.span_err(self.span, &msg);
+
+            let span_hi = self.span.hi;
+            let span_hi = if self.parse_ty_nopanic().is_ok() {
+                self.span.hi
+            } else {
+                span_hi
+            };
+
+            let msg = format!("did you mean a single argument type &'a Type, \
+                              or did you mean the comma-separated arguments \
+                              'a, Type?");
+            self.span_note(mk_sp(span_lo, span_hi), &msg);
+
+            self.abort_if_errors()
+        }
+
         // First parse types.
         let (types, returned) = try!(self.parse_seq_to_gt_or_return(
             Some(token::Comma),
@@ -4304,6 +4386,8 @@ impl<'a> Parser<'a> {
 
     /// Parse an impl item.
     pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> {
+        maybe_whole!(no_clone self, NtImplItem);
+
         let mut attrs = self.parse_outer_attributes();
         let lo = self.span.lo;
         let vis = try!(self.parse_visibility());
@@ -4313,6 +4397,14 @@ impl<'a> Parser<'a> {
             let typ = try!(self.parse_ty_sum());
             try!(self.expect(&token::Semi));
             (name, TypeImplItem(typ))
+        } else if try!(self.eat_keyword(keywords::Const)) {
+            let name = try!(self.parse_ident());
+            try!(self.expect(&token::Colon));
+            let typ = try!(self.parse_ty_sum());
+            try!(self.expect(&token::Eq));
+            let expr = try!(self.parse_expr_nopanic());
+            try!(self.commit_expr_expecting(&expr, token::Semi));
+            (name, ConstImplItem(typ, expr))
         } else {
             let (name, inner_attrs, node) = try!(self.parse_impl_method(vis));
             attrs.extend(inner_attrs.into_iter());
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 2bb74944ce9..0106de913bb 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -173,6 +173,14 @@ pub enum Token {
 }
 
 impl Token {
+    /// Returns `true` if the token starts with '>'.
+    pub fn is_like_gt(&self) -> bool {
+        match *self {
+            BinOp(Shr) | BinOpEq(Shr) | Gt | Ge => true,
+            _ => false,
+        }
+    }
+
     /// Returns `true` if the token can appear at the start of an expression.
     pub fn can_begin_expr(&self) -> bool {
         match *self {
@@ -373,6 +381,10 @@ pub enum Nonterminal {
     NtMeta(P<ast::MetaItem>),
     NtPath(Box<ast::Path>),
     NtTT(P<ast::TokenTree>), // needs P'ed to break a circularity
+    // These is not exposed to macros, but is used by quasiquote.
+    NtArm(ast::Arm),
+    NtImplItem(P<ast::ImplItem>),
+    NtTraitItem(P<ast::TraitItem>),
 }
 
 impl fmt::Debug for Nonterminal {
@@ -388,6 +400,9 @@ impl fmt::Debug for Nonterminal {
             NtMeta(..) => f.pad("NtMeta(..)"),
             NtPath(..) => f.pad("NtPath(..)"),
             NtTT(..) => f.pad("NtTT(..)"),
+            NtArm(..) => f.pad("NtArm(..)"),
+            NtImplItem(..) => f.pad("NtImplItem(..)"),
+            NtTraitItem(..) => f.pad("NtTraitItem(..)"),
         }
     }
 }
@@ -746,7 +761,7 @@ pub fn fresh_mark() -> ast::Mrk {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
     use ast;
     use ext::mtwt;
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index b56ecf7ae80..828a334a40f 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -66,7 +66,6 @@ pub struct State<'a> {
     cur_cmnt_and_lit: CurrentCommentAndLiteral,
     boxes: Vec<pp::Breaks>,
     ann: &'a (PpAnn+'a),
-    encode_idents_with_hygiene: bool,
 }
 
 pub fn rust_printer<'a>(writer: Box<Write+'a>) -> State<'a> {
@@ -87,7 +86,6 @@ pub fn rust_printer_annotated<'a>(writer: Box<Write+'a>,
         },
         boxes: Vec::new(),
         ann: ann,
-        encode_idents_with_hygiene: false,
     }
 }
 
@@ -179,7 +177,6 @@ impl<'a> State<'a> {
             },
             boxes: Vec::new(),
             ann: ann,
-            encode_idents_with_hygiene: false,
         }
     }
 }
@@ -290,103 +287,99 @@ pub fn token_to_string(tok: &Token) -> String {
         token::SpecialVarNt(var)    => format!("${}", var.as_str()),
 
         token::Interpolated(ref nt) => match *nt {
-            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(..)     => "an interpolated item".to_string(),
-            token::NtBlock(..)    => "an interpolated block".to_string(),
-            token::NtStmt(..)     => "an interpolated statement".to_string(),
-            token::NtPat(..)      => "an interpolated pattern".to_string(),
-            token::NtIdent(..)    => "an interpolated identifier".to_string(),
-            token::NtTT(..)       => "an interpolated tt".to_string(),
+            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(..)      => "an interpolated item".to_string(),
+            token::NtBlock(..)     => "an interpolated block".to_string(),
+            token::NtStmt(..)      => "an interpolated statement".to_string(),
+            token::NtPat(..)       => "an interpolated pattern".to_string(),
+            token::NtIdent(..)     => "an interpolated identifier".to_string(),
+            token::NtTT(..)        => "an interpolated tt".to_string(),
+            token::NtArm(..)       => "an interpolated arm".to_string(),
+            token::NtImplItem(..)  => "an interpolated impl item".to_string(),
+            token::NtTraitItem(..) => "an interpolated trait item".to_string(),
         }
     }
 }
 
-// FIXME (Issue #16472): the thing_to_string_impls macro should go away
-// after we revise the syntax::ext::quote::ToToken impls to go directly
-// to token-trees instead of thing -> string -> token-trees.
-
-macro_rules! thing_to_string_impls {
-    ($to_string:ident) => {
-
 pub fn ty_to_string(ty: &ast::Ty) -> String {
-    $to_string(|s| s.print_type(ty))
+    to_string(|s| s.print_type(ty))
 }
 
 pub fn bounds_to_string(bounds: &[ast::TyParamBound]) -> String {
-    $to_string(|s| s.print_bounds("", bounds))
+    to_string(|s| s.print_bounds("", bounds))
 }
 
 pub fn pat_to_string(pat: &ast::Pat) -> String {
-    $to_string(|s| s.print_pat(pat))
+    to_string(|s| s.print_pat(pat))
 }
 
 pub fn arm_to_string(arm: &ast::Arm) -> String {
-    $to_string(|s| s.print_arm(arm))
+    to_string(|s| s.print_arm(arm))
 }
 
 pub fn expr_to_string(e: &ast::Expr) -> String {
-    $to_string(|s| s.print_expr(e))
+    to_string(|s| s.print_expr(e))
 }
 
 pub fn lifetime_to_string(e: &ast::Lifetime) -> String {
-    $to_string(|s| s.print_lifetime(e))
+    to_string(|s| s.print_lifetime(e))
 }
 
 pub fn tt_to_string(tt: &ast::TokenTree) -> String {
-    $to_string(|s| s.print_tt(tt))
+    to_string(|s| s.print_tt(tt))
 }
 
 pub fn tts_to_string(tts: &[ast::TokenTree]) -> String {
-    $to_string(|s| s.print_tts(tts))
+    to_string(|s| s.print_tts(tts))
 }
 
 pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
-    $to_string(|s| s.print_stmt(stmt))
+    to_string(|s| s.print_stmt(stmt))
 }
 
 pub fn attr_to_string(attr: &ast::Attribute) -> String {
-    $to_string(|s| s.print_attribute(attr))
+    to_string(|s| s.print_attribute(attr))
 }
 
 pub fn item_to_string(i: &ast::Item) -> String {
-    $to_string(|s| s.print_item(i))
+    to_string(|s| s.print_item(i))
 }
 
 pub fn impl_item_to_string(i: &ast::ImplItem) -> String {
-    $to_string(|s| s.print_impl_item(i))
+    to_string(|s| s.print_impl_item(i))
 }
 
 pub fn trait_item_to_string(i: &ast::TraitItem) -> String {
-    $to_string(|s| s.print_trait_item(i))
+    to_string(|s| s.print_trait_item(i))
 }
 
 pub fn generics_to_string(generics: &ast::Generics) -> String {
-    $to_string(|s| s.print_generics(generics))
+    to_string(|s| s.print_generics(generics))
 }
 
 pub fn where_clause_to_string(i: &ast::WhereClause) -> String {
-    $to_string(|s| s.print_where_clause(i))
+    to_string(|s| s.print_where_clause(i))
 }
 
 pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
-    $to_string(|s| s.print_fn_block_args(p))
+    to_string(|s| s.print_fn_block_args(p))
 }
 
 pub fn path_to_string(p: &ast::Path) -> String {
-    $to_string(|s| s.print_path(p, false, 0))
+    to_string(|s| s.print_path(p, false, 0))
 }
 
 pub fn ident_to_string(id: &ast::Ident) -> String {
-    $to_string(|s| s.print_ident(*id))
+    to_string(|s| s.print_ident(*id))
 }
 
 pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, name: ast::Ident,
                   opt_explicit_self: Option<&ast::ExplicitSelf_>,
                   generics: &ast::Generics) -> String {
-    $to_string(|s| {
+    to_string(|s| {
         try!(s.head(""));
         try!(s.print_fn(decl, unsafety, abi::Rust, Some(name),
                         generics, opt_explicit_self, ast::Inherited));
@@ -396,7 +389,7 @@ pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, name: ast::Ide
 }
 
 pub fn block_to_string(blk: &ast::Block) -> String {
-    $to_string(|s| {
+    to_string(|s| {
         // containing cbox, will be closed by print-block at }
         try!(s.cbox(indent_unit));
         // head-ibox, will be closed by print-block after {
@@ -406,59 +399,31 @@ pub fn block_to_string(blk: &ast::Block) -> String {
 }
 
 pub fn meta_item_to_string(mi: &ast::MetaItem) -> String {
-    $to_string(|s| s.print_meta_item(mi))
+    to_string(|s| s.print_meta_item(mi))
 }
 
 pub fn attribute_to_string(attr: &ast::Attribute) -> String {
-    $to_string(|s| s.print_attribute(attr))
+    to_string(|s| s.print_attribute(attr))
 }
 
 pub fn lit_to_string(l: &ast::Lit) -> String {
-    $to_string(|s| s.print_literal(l))
+    to_string(|s| s.print_literal(l))
 }
 
 pub fn explicit_self_to_string(explicit_self: &ast::ExplicitSelf_) -> String {
-    $to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {}))
+    to_string(|s| s.print_explicit_self(explicit_self, ast::MutImmutable).map(|_| {}))
 }
 
 pub fn variant_to_string(var: &ast::Variant) -> String {
-    $to_string(|s| s.print_variant(var))
+    to_string(|s| s.print_variant(var))
 }
 
 pub fn arg_to_string(arg: &ast::Arg) -> String {
-    $to_string(|s| s.print_arg(arg))
+    to_string(|s| s.print_arg(arg))
 }
 
 pub fn mac_to_string(arg: &ast::Mac) -> String {
-    $to_string(|s| s.print_mac(arg, ::parse::token::Paren))
-}
-
-} }
-
-thing_to_string_impls! { to_string }
-
-// FIXME (Issue #16472): the whole `with_hygiene` mod should go away
-// after we revise the syntax::ext::quote::ToToken impls to go directly
-// to token-trees instea of thing -> string -> token-trees.
-
-pub mod with_hygiene {
-    use abi;
-    use ast;
-    use std::io;
-    use super::indent_unit;
-
-    // This function is the trick that all the rest of the routines
-    // hang on.
-    pub fn to_string_hyg<F>(f: F) -> String where
-        F: FnOnce(&mut super::State) -> io::Result<()>,
-    {
-        super::to_string(move |s| {
-            s.encode_idents_with_hygiene = true;
-            f(s)
-        })
-    }
-
-    thing_to_string_impls! { to_string_hyg }
+    to_string(|s| s.print_mac(arg, ::parse::token::Paren))
 }
 
 pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
@@ -796,6 +761,26 @@ impl<'a> State<'a> {
         }
     }
 
+    fn print_associated_const(&mut self,
+                              ident: ast::Ident,
+                              ty: &ast::Ty,
+                              default: Option<&ast::Expr>,
+                              vis: ast::Visibility)
+                              -> io::Result<()>
+    {
+        try!(word(&mut self.s, &visibility_qualified(vis, "")));
+        try!(self.word_space("const"));
+        try!(self.print_ident(ident));
+        try!(self.word_space(":"));
+        try!(self.print_type(ty));
+        if let Some(expr) = default {
+            try!(space(&mut self.s));
+            try!(self.word_space("="));
+            try!(self.print_expr(expr));
+        }
+        word(&mut self.s, ";")
+    }
+
     fn print_associated_type(&mut self,
                              ident: ast::Ident,
                              bounds: Option<&ast::TyParamBounds>,
@@ -1268,6 +1253,11 @@ impl<'a> State<'a> {
         try!(self.maybe_print_comment(ti.span.lo));
         try!(self.print_outer_attributes(&ti.attrs));
         match ti.node {
+            ast::ConstTraitItem(ref ty, ref default) => {
+                try!(self.print_associated_const(ti.ident, &ty,
+                                                 default.as_ref().map(|expr| &**expr),
+                                                 ast::Inherited));
+            }
             ast::MethodTraitItem(ref sig, ref body) => {
                 if body.is_some() {
                     try!(self.head(""));
@@ -1294,6 +1284,9 @@ impl<'a> State<'a> {
         try!(self.maybe_print_comment(ii.span.lo));
         try!(self.print_outer_attributes(&ii.attrs));
         match ii.node {
+            ast::ConstImplItem(ref ty, ref expr) => {
+                try!(self.print_associated_const(ii.ident, &ty, Some(&expr), ii.vis));
+            }
             ast::MethodImplItem(ref sig, ref body) => {
                 try!(self.head(""));
                 try!(self.print_method_sig(ii.ident, sig, ii.vis));
@@ -2005,12 +1998,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
-        if self.encode_idents_with_hygiene {
-            let encoded = ident.encode_with_hygiene();
-            try!(word(&mut self.s, &encoded[..]))
-        } else {
-            try!(word(&mut self.s, &token::get_ident(ident)))
-        }
+        try!(word(&mut self.s, &token::get_ident(ident)));
         self.ann.post(self, NodeIdent(&ident))
     }
 
@@ -2191,6 +2179,9 @@ impl<'a> State<'a> {
                     }
                 }
             }
+            ast::PatQPath(ref qself, ref path) => {
+                try!(self.print_qpath(path, qself, false));
+            }
             ast::PatStruct(ref path, ref fields, etc) => {
                 try!(self.print_path(path, true, 0));
                 try!(self.nbsp());
@@ -3007,7 +2998,7 @@ impl<'a> State<'a> {
 fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     use ast;
diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs
index 6adeb30a94e..d016eb39239 100644
--- a/src/libsyntax/util/parser_testing.rs
+++ b/src/libsyntax/util/parser_testing.rs
@@ -142,7 +142,7 @@ pub fn is_whitespace(c: char) -> bool {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     #[test] fn eqmodws() {
diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs
index 153f9d4a26d..5353d12b678 100644
--- a/src/libsyntax/util/small_vector.rs
+++ b/src/libsyntax/util/small_vector.rs
@@ -204,7 +204,7 @@ impl<T> MoveMap<T> for SmallVector<T> {
 }
 
 #[cfg(test)]
-mod test {
+mod tests {
     use super::*;
 
     #[test]
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 4c70fc9f81f..6cf791b10be 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -464,6 +464,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
                 }
             }
         }
+        PatQPath(ref qself, ref path) => {
+            visitor.visit_ty(&qself.ty);
+            visitor.visit_path(path, pattern.id)
+        }
         PatStruct(ref path, ref fields, _) => {
             visitor.visit_path(path, pattern.id);
             for field in fields {
@@ -619,6 +623,12 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
         visitor.visit_attribute(attr);
     }
     match trait_item.node {
+        ConstTraitItem(ref ty, ref default) => {
+            visitor.visit_ty(ty);
+            if let Some(ref expr) = *default {
+                visitor.visit_expr(expr);
+            }
+        }
         MethodTraitItem(ref sig, None) => {
             visitor.visit_explicit_self(&sig.explicit_self);
             visitor.visit_generics(&sig.generics);
@@ -641,6 +651,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
         visitor.visit_attribute(attr);
     }
     match impl_item.node {
+        ConstImplItem(ref ty, ref expr) => {
+            visitor.visit_ty(ty);
+            visitor.visit_expr(expr);
+        }
         MethodImplItem(ref sig, ref body) => {
             visitor.visit_fn(FkMethod(impl_item.ident, sig, Some(impl_item.vis)), &sig.decl,
                              body, impl_item.span, impl_item.id);