diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 16f4b29dcceef..de785b13d067d 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -272,6 +272,12 @@ impl Step for TheBook {
             name: INTERNER.intern_string(format!("{}/second-edition", name)),
         });
 
+        // build book 2018 edition
+        builder.ensure(Rustbook {
+            target,
+            name: INTERNER.intern_string(format!("{}/2018-edition", name)),
+        });
+
         // build the version info page and CSS
         builder.ensure(Standalone {
             compiler,
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index e53fef0678613..f64161fb0272c 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -592,12 +592,20 @@ impl Build {
             Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target))
         } else {
             let base = self.llvm_out(self.config.build).join("build");
-            let exe = exe("FileCheck", &*target);
-            if !self.config.ninja && self.config.build.contains("msvc") {
-                base.join("Release/bin").join(exe)
+            let base = if !self.config.ninja && self.config.build.contains("msvc") {
+                if self.config.llvm_optimize {
+                    if self.config.llvm_release_debuginfo {
+                        base.join("RelWithDebInfo")
+                    } else {
+                        base.join("Release")
+                    }
+                } else {
+                    base.join("Debug")
+                }
             } else {
-                base.join("bin").join(exe)
-            }
+                base
+            };
+            base.join("bin").join(exe("FileCheck", &*target))
         }
     }
 
diff --git a/src/doc/book b/src/doc/book
index f51127530d46b..36d65d00164d1 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit f51127530d46b9acbf4747c859da185e771cfcf3
+Subproject commit 36d65d00164d1750f6fa7f8b0f52dabc3fea500b
diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs
index 4427ac004f97a..161493f389226 100644
--- a/src/liballoc/slice.rs
+++ b/src/liballoc/slice.rs
@@ -119,8 +119,8 @@ pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
 pub use core::slice::{RSplit, RSplitMut};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::slice::{from_raw_parts, from_raw_parts_mut};
-#[unstable(feature = "from_ref", issue = "45703")]
-pub use core::slice::{from_ref, from_ref_mut};
+#[stable(feature = "from_ref", since = "1.28.0")]
+pub use core::slice::{from_ref, from_mut};
 #[unstable(feature = "slice_get_slice", issue = "35729")]
 pub use core::slice::SliceIndex;
 #[unstable(feature = "exact_chunks", issue = "47115")]
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 9a46c6106db57..d50ad580ed574 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -1257,7 +1257,7 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> {
 /// To assist with proper design, the following scenarios are explicitly declared legal
 /// for single-threaded code:
 ///
-/// 1. A `&T` reference can be released to safe code and there it can co-exit with other `&T`
+/// 1. A `&T` reference can be released to safe code and there it can co-exist with other `&T`
 /// references, but not with a `&mut T`
 ///
 /// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T`
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 77b5488084d99..d37629ced11db 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -119,6 +119,9 @@
 #![feature(powerpc_target_feature)]
 #![feature(mips_target_feature)]
 #![feature(aarch64_target_feature)]
+#![feature(const_slice_len)]
+#![feature(const_str_as_bytes)]
+#![feature(const_str_len)]
 
 #[prelude_import]
 #[allow(unused)]
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 3b19a401859ee..ab986e4c86d88 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -59,9 +59,16 @@ mod rotate;
 mod sort;
 
 #[repr(C)]
-struct Repr<T> {
-    pub data: *const T,
-    pub len: usize,
+union Repr<'a, T: 'a> {
+    rust: &'a [T],
+    rust_mut: &'a mut [T],
+    raw: FatPtr<T>,
+}
+
+#[repr(C)]
+struct FatPtr<T> {
+    data: *const T,
+    len: usize,
 }
 
 //
@@ -119,9 +126,10 @@ impl<T> [T] {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn len(&self) -> usize {
+    #[rustc_const_unstable(feature = "const_slice_len")]
+    pub const fn len(&self) -> usize {
         unsafe {
-            mem::transmute::<&[T], Repr<T>>(self).len
+            Repr { rust: self }.raw.len
         }
     }
 
@@ -135,7 +143,8 @@ impl<T> [T] {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn is_empty(&self) -> bool {
+    #[rustc_const_unstable(feature = "const_slice_len")]
+    pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
@@ -418,7 +427,8 @@ impl<T> [T] {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn as_ptr(&self) -> *const T {
+    #[rustc_const_unstable(feature = "const_slice_as_ptr")]
+    pub const fn as_ptr(&self) -> *const T {
         self as *const [T] as *const T
     }
 
@@ -3856,8 +3866,8 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> {
 /// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] {
-    mem::transmute(Repr { data: p, len: len })
+pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
+    Repr { raw: FatPtr { data, len } }.rust
 }
 
 /// Performs the same functionality as `from_raw_parts`, except that a mutable
@@ -3869,12 +3879,12 @@ pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] {
 /// `from_raw_parts`.
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] {
-    mem::transmute(Repr { data: p, len: len })
+pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
+    Repr { raw: FatPtr { data, len} }.rust_mut
 }
 
 /// Converts a reference to T into a slice of length 1 (without copying).
-#[unstable(feature = "from_ref", issue = "45703")]
+#[stable(feature = "from_ref", since = "1.28.0")]
 pub fn from_ref<T>(s: &T) -> &[T] {
     unsafe {
         from_raw_parts(s, 1)
@@ -3882,8 +3892,8 @@ pub fn from_ref<T>(s: &T) -> &[T] {
 }
 
 /// Converts a reference to T into a slice of length 1 (without copying).
-#[unstable(feature = "from_ref", issue = "45703")]
-pub fn from_ref_mut<T>(s: &mut T) -> &mut [T] {
+#[stable(feature = "from_ref", since = "1.28.0")]
+pub fn from_mut<T>(s: &mut T) -> &mut [T] {
     unsafe {
         from_raw_parts_mut(s, 1)
     }
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 82bead0ab4676..70aaf10f4213e 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -2166,7 +2166,8 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn len(&self) -> usize {
+    #[rustc_const_unstable(feature = "const_str_len")]
+    pub const fn len(&self) -> usize {
         self.as_bytes().len()
     }
 
@@ -2185,7 +2186,8 @@ impl str {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn is_empty(&self) -> bool {
+    #[rustc_const_unstable(feature = "const_str_len")]
+    pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
@@ -2242,8 +2244,15 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline(always)]
-    pub fn as_bytes(&self) -> &[u8] {
-        unsafe { &*(self as *const str as *const [u8]) }
+    #[rustc_const_unstable(feature="const_str_as_bytes")]
+    pub const fn as_bytes(&self) -> &[u8] {
+        unsafe {
+            union Slices<'a> {
+                str: &'a str,
+                slice: &'a [u8],
+            }
+            Slices { str: self }.slice
+        }
     }
 
     /// Converts a mutable string slice to a mutable byte slice. To convert the
@@ -2303,7 +2312,8 @@ impl str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn as_ptr(&self) -> *const u8 {
+    #[rustc_const_unstable(feature = "const_str_as_ptr")]
+    pub const fn as_ptr(&self) -> *const u8 {
         self as *const str as *const u8
     }
 
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 66b08f5c3b00b..ffb8031b83bc6 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -948,7 +948,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             Drop { target: ref mut t, unwind: Some(ref mut u), .. } |
             Assert { target: ref mut t, cleanup: Some(ref mut u), .. } |
             FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
-                Some(t).into_iter().chain(slice::from_ref_mut(u))
+                Some(t).into_iter().chain(slice::from_mut(u))
             }
             SwitchInt { ref mut targets, .. } => {
                 None.into_iter().chain(&mut targets[..])
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index c3b5b8e6fb35f..7a52a5cbf5acc 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -3356,13 +3356,28 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     predicate: predicate.value
                 }))
         }).collect();
+
         // We are performing deduplication here to avoid exponential blowups
         // (#38528) from happening, but the real cause of the duplication is
         // unknown. What we know is that the deduplication avoids exponential
-        // amount of predicates being propogated when processing deeply nested
+        // amount of predicates being propagated when processing deeply nested
         // types.
-        let mut seen = FxHashSet();
-        predicates.retain(|i| seen.insert(i.clone()));
+        //
+        // This code is hot enough that it's worth avoiding the allocation
+        // required for the FxHashSet when possible. Special-casing lengths 0,
+        // 1 and 2 covers roughly 75--80% of the cases.
+        if predicates.len() <= 1 {
+            // No possibility of duplicates.
+        } else if predicates.len() == 2 {
+            // Only two elements. Drop the second if they are equal.
+            if predicates[0] == predicates[1] {
+                predicates.truncate(1);
+            }
+        } else {
+            // Three or more elements. Use a general deduplication process.
+            let mut seen = FxHashSet();
+            predicates.retain(|i| seen.insert(i.clone()));
+        }
         self.infcx().plug_leaks(skol_map, snapshot, predicates)
     }
 }
diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs
index 065b7939ac362..c43b7e95b35e3 100644
--- a/src/librustc/ty/maps/plumbing.rs
+++ b/src/librustc/ty/maps/plumbing.rs
@@ -105,6 +105,10 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> {
     /// start executing the query, or it returns with the result of the query.
     /// If the query is executing elsewhere, this will wait for it.
     /// If the query panicked, this will silently panic.
+    ///
+    /// This function is inlined because that results in a noticeable speedup
+    /// for some compile-time benchmarks.
+    #[inline(always)]
     pub(super) fn try_get(
         tcx: TyCtxt<'a, 'tcx, '_>,
         span: Span,
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 5d6d4619c5e05..4ec75d3b5ec74 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -1853,6 +1853,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     for index in ii {
                         if flow_state.ever_inits.contains(index) {
                             self.used_mut.insert(*local);
+                            break;
                         }
                     }
                 }
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index ac37937509eac..4719f00b4d259 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -82,7 +82,8 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
             hir::ExprLoop(ref b, _, source) => {
                 self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
             }
-            hir::ExprClosure(.., b, _, _) => {
+            hir::ExprClosure(_, ref function_decl, b, _, _) => {
+                self.visit_fn_decl(&function_decl);
                 self.with_context(Closure, |v| v.visit_nested_body(b));
             }
             hir::ExprBlock(ref b, Some(_label)) => {
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 5b3484dcccb85..76219c6971b22 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -537,8 +537,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
         let mut selcx = traits::SelectionContext::new(self);
 
-        // Use a FIFO queue for this custom fulfillment procedure.
-        let mut queue = VecDeque::new();
+        // Use a FIFO queue for this custom fulfillment procedure. (The maximum
+        // length is almost always 1.)
+        let mut queue = VecDeque::with_capacity(1);
 
         // Create an obligation for `Source: CoerceUnsized<Target>`.
         let cause = ObligationCause::misc(self.cause.span, self.body_id);
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index d5e0f95ddf435..dceb04a7daa2b 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -138,7 +138,7 @@ impl Cfg {
 
     /// Renders the configuration for human display, as a short HTML description.
     pub(crate) fn render_short_html(&self) -> String {
-        let mut msg = ShortHtml(self).to_string();
+        let mut msg = Html(self, true).to_string();
         if self.should_capitalize_first_letter() {
             if let Some(i) = msg.find(|c: char| c.is_ascii_alphanumeric()) {
                 msg[i .. i+1].make_ascii_uppercase();
@@ -155,7 +155,7 @@ impl Cfg {
             "on"
         };
 
-        let mut msg = format!("This is supported {} <strong>{}</strong>", on, Html(self));
+        let mut msg = format!("This is supported {} <strong>{}</strong>", on, Html(self, false));
         if self.should_append_only_to_description() {
             msg.push_str(" only");
         }
@@ -265,7 +265,9 @@ impl ops::BitOr for Cfg {
     }
 }
 
-struct Html<'a>(&'a Cfg);
+/// Pretty-print wrapper for a `Cfg`. Also indicates whether the "short-form" rendering should be
+/// used.
+struct Html<'a>(&'a Cfg, bool);
 
 fn write_with_opt_paren<T: fmt::Display>(
     fmt: &mut fmt::Formatter,
@@ -295,12 +297,12 @@ impl<'a> fmt::Display for Html<'a> {
                     };
                     for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
                         fmt.write_str(if i == 0 { "neither " } else { separator })?;
-                        write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg))?;
+                        write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg, self.1))?;
                     }
                     Ok(())
                 }
-                ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Html(simple)),
-                ref c => write!(fmt, "not ({})", Html(c)),
+                ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Html(simple, self.1)),
+                ref c => write!(fmt, "not ({})", Html(c, self.1)),
             },
 
             Cfg::Any(ref sub_cfgs) => {
@@ -313,7 +315,7 @@ impl<'a> fmt::Display for Html<'a> {
                     if i != 0 {
                         fmt.write_str(separator)?;
                     }
-                    write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg))?;
+                    write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg, self.1))?;
                 }
                 Ok(())
             },
@@ -323,7 +325,7 @@ impl<'a> fmt::Display for Html<'a> {
                     if i != 0 {
                         fmt.write_str(" and ")?;
                     }
-                    write_with_opt_paren(fmt, !sub_cfg.is_simple(), Html(sub_cfg))?;
+                    write_with_opt_paren(fmt, !sub_cfg.is_simple(), Html(sub_cfg, self.1))?;
                 }
                 Ok(())
             },
@@ -390,7 +392,11 @@ impl<'a> fmt::Display for Html<'a> {
                     ("target_endian", Some(endian)) => return write!(fmt, "{}-endian", endian),
                     ("target_pointer_width", Some(bits)) => return write!(fmt, "{}-bit", bits),
                     ("target_feature", Some(feat)) =>
-                        return write!(fmt, "target feature <code>{}</code>", feat),
+                        if self.1 {
+                            return write!(fmt, "<code>{}</code>", feat);
+                        } else {
+                            return write!(fmt, "target feature <code>{}</code>", feat);
+                        },
                     _ => "",
                 };
                 if !human_readable.is_empty() {
@@ -405,19 +411,6 @@ impl<'a> fmt::Display for Html<'a> {
     }
 }
 
-struct ShortHtml<'a>(&'a Cfg);
-
-impl<'a> fmt::Display for ShortHtml<'a> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        match *self.0 {
-            Cfg::Cfg(ref name, Some(ref vendor)) if name == &"target_feature" => {
-                write!(fmt, "<code>{}</code>", vendor)
-            },
-            ref cfg => write!(fmt, "{}", Html(cfg)),
-        }
-    }
-}
-
 #[cfg(test)]
 mod test {
     use super::Cfg;
@@ -740,6 +733,13 @@ mod test {
                 name_value_cfg("target_feature", "sse2").render_short_html(),
                 "<code>sse2</code>"
             );
+            assert_eq!(
+                (
+                    name_value_cfg("target_arch", "x86_64") &
+                    name_value_cfg("target_feature", "sse2")
+                ).render_short_html(),
+                "x86-64 and <code>sse2</code>"
+            );
         })
     }
 
@@ -818,6 +818,14 @@ mod test {
                 name_value_cfg("target_feature", "sse2").render_long_html(),
                 "This is supported with <strong>target feature <code>sse2</code></strong> only."
             );
+            assert_eq!(
+                (
+                    name_value_cfg("target_arch", "x86_64") &
+                    name_value_cfg("target_feature", "sse2")
+                ).render_long_html(),
+                "This is supported on <strong>x86-64 and target feature \
+                <code>sse2</code></strong> only."
+            );
         })
     }
 }
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index d6b3ab26af8ae..4939505c53144 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -1010,6 +1010,8 @@ span.since {
 
 pre.rust {
 	position: relative;
+	tab-width: 4;
+	-moz-tab-width: 4;
 }
 
 .search-failed {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 729ad491fd544..62d007b424025 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5807,9 +5807,18 @@ impl<'a> Parser<'a> {
                     return Err(err);
                 }
             }
-            _ => return Err(self.span_fatal_help(self.span,
-                    &format!("expected `,`, or `}}`, found `{}`", self.this_token_to_string()),
-                    "struct fields should be separated by commas")),
+            _ => {
+                let sp = self.sess.codemap().next_point(self.prev_span);
+                let mut err = self.struct_span_err(sp, &format!("expected `,`, or `}}`, found `{}`",
+                                                                self.this_token_to_string()));
+                if self.token.is_ident() {
+                    // This is likely another field; emit the diagnostic and keep going
+                    err.span_suggestion(sp, "try adding a comma", ",".into());
+                    err.emit();
+                } else {
+                    return Err(err)
+                }
+            }
         }
         Ok(a_var)
     }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 034be6a6864ce..ed28d5f33b921 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -22,6 +22,7 @@ use serialize::{Decodable, Decoder, Encodable, Encoder};
 use symbol::keywords;
 use syntax::parse::parse_stream_from_source_str;
 use syntax_pos::{self, Span, FileName};
+use syntax_pos::symbol::{self, Symbol};
 use tokenstream::{TokenStream, TokenTree};
 use tokenstream;
 
@@ -478,7 +479,13 @@ impl Token {
                 _ => return None,
             },
             SingleQuote => match joint {
-                Ident(ident, false) => Lifetime(ident),
+                Ident(ident, false) => {
+                    let name = Symbol::intern(&format!("'{}", ident));
+                    Lifetime(symbol::Ident {
+                        name,
+                        span: ident.span,
+                    })
+                }
                 _ => return None,
             },
 
diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs
index 99e7bb4baeff4..cbd6a257b77e8 100644
--- a/src/libsyntax_ext/deriving/default.rs
+++ b/src/libsyntax_ext/deriving/default.rs
@@ -76,8 +76,8 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructur
             }
         }
         StaticEnum(..) => {
-            cx.span_err(trait_span,
-                        "`Default` cannot be derived for enums, only structs");
+            span_err_if_not_stage0!(cx, trait_span, E0665,
+                                    "`Default` cannot be derived for enums, only structs");
             // let compilation continue
             cx.expr_usize(trait_span, 0)
         }
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index 6bc4ee0b399f9..0dd55f8d77738 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -19,6 +19,17 @@ use syntax::ptr::P;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
 
+macro_rules! span_err_if_not_stage0 {
+    ($cx:expr, $sp:expr, $code:ident, $text:tt) => {
+        #[cfg(not(stage0))] {
+            span_err!($cx, $sp, $code, $text)
+        }
+        #[cfg(stage0)] {
+            $cx.span_err($sp, $text)
+        }
+    }
+}
+
 macro path_local($x:ident) {
     generic::ty::Path::new_local(stringify!($x))
 }
diff --git a/src/libsyntax_ext/diagnostics.rs b/src/libsyntax_ext/diagnostics.rs
index 33ae24c37e53f..f99a6c3c2166d 100644
--- a/src/libsyntax_ext/diagnostics.rs
+++ b/src/libsyntax_ext/diagnostics.rs
@@ -82,7 +82,7 @@ A clobber was surrounded by braces in the `asm` macro.
 
 Erroneous code example:
 
-```compile_fail,E0663
+```compile_fail,E0664
 asm!("mov $$0x200, %eax"
      :
      :
@@ -94,4 +94,38 @@ Considering that this would be a long explanation, we instead recommend you to
 take a look at the unstable book:
 https://doc.rust-lang.org/unstable-book/language-features/asm.html
 "##,
+
+E0665: r##"
+The `Default` trait was derived on an enum.
+
+Erroneous code example:
+
+```compile_fail,E0665
+#[derive(Default)]
+enum Food {
+    Sweet,
+    Salty,
+}
+```
+
+The `Default` cannot be derived on an enum for the simple reason that the
+compiler doesn't know which value to pick by default whereas it can for a
+struct as long as all its fields implement the `Default` trait as well.
+
+If you still want to implement `Default` on your enum, you'll have to do it "by
+hand":
+
+```
+enum Food {
+    Sweet,
+    Salty,
+}
+
+impl Default for Food {
+    fn default() -> Food {
+        Food::Sweet
+    }
+}
+```
+"##,
 }
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 15fcfac13adf2..af3ef181c59dc 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -31,8 +31,12 @@ extern crate rustc_target;
 
 mod diagnostics;
 
-mod assert;
+#[macro_use]
+// for custom_derive
+pub mod deriving;
+
 mod asm;
+mod assert;
 mod cfg;
 mod compile_error;
 mod concat;
@@ -46,8 +50,6 @@ mod trace_macros;
 
 pub mod proc_macro_registrar;
 
-// for custom_derive
-pub mod deriving;
 
 pub mod proc_macro_impl;
 
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/gen-lifetime-token.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/gen-lifetime-token.rs
new file mode 100644
index 0000000000000..e288050a928b0
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/gen-lifetime-token.rs
@@ -0,0 +1,35 @@
+// Copyright 2018 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn bar(_input: TokenStream) -> TokenStream {
+    let mut ret = Vec::<TokenTree>::new();
+    ret.push(Ident::new("static", Span::call_site()).into());
+    ret.push(Ident::new("FOO", Span::call_site()).into());
+    ret.push(Punct::new(':', Spacing::Alone).into());
+    ret.push(Punct::new('&', Spacing::Alone).into());
+    ret.push(Punct::new('\'', Spacing::Joint).into());
+    ret.push(Ident::new("static", Span::call_site()).into());
+    ret.push(Ident::new("i32", Span::call_site()).into());
+    ret.push(Punct::new('=', Spacing::Alone).into());
+    ret.push(Punct::new('&', Spacing::Alone).into());
+    ret.push(Literal::i32_unsuffixed(1).into());
+    ret.push(Punct::new(';', Spacing::Alone).into());
+    ret.into_iter().collect()
+}
diff --git a/src/test/run-pass-fulldeps/proc-macro/gen-lifetime-token.rs b/src/test/run-pass-fulldeps/proc-macro/gen-lifetime-token.rs
new file mode 100644
index 0000000000000..539e3aa8ecbb2
--- /dev/null
+++ b/src/test/run-pass-fulldeps/proc-macro/gen-lifetime-token.rs
@@ -0,0 +1,22 @@
+// Copyright 2018 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.
+
+// aux-build:gen-lifetime-token.rs
+
+#![feature(proc_macro)]
+
+extern crate gen_lifetime_token as bar;
+
+bar::bar!();
+
+fn main() {
+    let x: &'static i32 = FOO;
+    assert_eq!(*x, 1);
+}
diff --git a/src/test/ui/E0665.rs b/src/test/ui/E0665.rs
new file mode 100644
index 0000000000000..8888bedf01687
--- /dev/null
+++ b/src/test/ui/E0665.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 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.
+
+// ignore-stage1
+
+#[derive(Default)] //~ ERROR E0665
+enum Food {
+    Sweet,
+    Salty,
+}
+
+fn main() {
+}
diff --git a/src/test/ui/E0665.stderr b/src/test/ui/E0665.stderr
new file mode 100644
index 0000000000000..c97e9e5ea89d0
--- /dev/null
+++ b/src/test/ui/E0665.stderr
@@ -0,0 +1,9 @@
+error[E0665]: `Default` cannot be derived for enums, only structs
+  --> $DIR/E0665.rs:13:10
+   |
+LL | #[derive(Default)] //~ ERROR E0665
+   |          ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0665`.
diff --git a/src/test/ui/const-eval/strlen.rs b/src/test/ui/const-eval/strlen.rs
new file mode 100644
index 0000000000000..dfa41c491fa89
--- /dev/null
+++ b/src/test/ui/const-eval/strlen.rs
@@ -0,0 +1,33 @@
+// Copyright 2018 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.
+
+// run-pass
+
+#![feature(const_str_len, const_str_as_bytes)]
+
+const S: &str = "foo";
+pub const B: &[u8] = S.as_bytes();
+
+pub fn foo() -> [u8; S.len()] {
+    let mut buf = [0; S.len()];
+    for (i, &c) in S.as_bytes().iter().enumerate() {
+        buf[i] = c;
+    }
+    buf
+}
+
+fn main() {
+    assert_eq!(&foo()[..], b"foo");
+    assert_eq!(foo().len(), S.len());
+    const LEN: usize = S.len();
+    assert_eq!(LEN, S.len());
+    assert_eq!(B, foo());
+    assert_eq!(B, b"foo");
+}
diff --git a/src/test/ui/struct-missing-comma.rs b/src/test/ui/struct-missing-comma.rs
new file mode 100644
index 0000000000000..87ae8ab26051a
--- /dev/null
+++ b/src/test/ui/struct-missing-comma.rs
@@ -0,0 +1,23 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+
+// Issue #50636
+
+struct S {
+    foo: u32 //~ expected `,`, or `}`, found `bar`
+    //     ~^ HELP try adding a comma: ','
+    bar: u32
+}
+
+fn main() {
+    let s = S { foo: 5, bar: 6 };
+}
diff --git a/src/test/ui/struct-missing-comma.stderr b/src/test/ui/struct-missing-comma.stderr
new file mode 100644
index 0000000000000..28283bfb71364
--- /dev/null
+++ b/src/test/ui/struct-missing-comma.stderr
@@ -0,0 +1,8 @@
+error: expected `,`, or `}`, found `bar`
+  --> $DIR/struct-missing-comma.rs:16:13
+   |
+LL |     foo: u32 //~ expected `,`, or `}`, found `bar`
+   |             ^ help: try adding a comma: `,`
+
+error: aborting due to previous error
+