about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-11-03 14:51:05 +0000
committerbors <bors@rust-lang.org>2018-11-03 14:51:05 +0000
commit3d28ee3e34d100534062d0bc690779ed9b6927fe (patch)
treefa410dd9fe06391fba21ac86ccb239cb5e99af6c
parent2ad8c7b3502616aff142a4640cce911c6c2c5463 (diff)
parent723edf7793cd0953e12c677ac2f49bf2f67cfb1e (diff)
downloadrust-3d28ee3e34d100534062d0bc690779ed9b6927fe.tar.gz
rust-3d28ee3e34d100534062d0bc690779ed9b6927fe.zip
Auto merge of #55646 - GuillaumeGomez:rollup, r=GuillaumeGomez
Rollup of 5 pull requests

Successful merges:

 - #54162 (Hide default impls items)
 - #55555 (Make `-Z ls` list the actual filename of external dependencies)
 - #55567 (add test for deriving Debug on uninhabited enum)
 - #55568 (test that rustdoc doesn't overflow on a big enum)
 - #55598 (publish-toolstate: ping maintainers when a tool builds again)

Failed merges:

r? @ghost
-rw-r--r--src/librustc_metadata/decoder.rs2
-rw-r--r--src/librustdoc/clean/mod.rs8
-rw-r--r--src/librustdoc/html/render.rs66
-rw-r--r--src/librustdoc/html/static/main.js44
-rw-r--r--src/librustdoc/html/static/rustdoc.css31
-rw-r--r--src/librustdoc/html/static/storage.js16
-rw-r--r--src/test/rustdoc/assoc-consts.rs6
-rw-r--r--src/test/rustdoc/auxiliary/enum_primitive.rs210
-rw-r--r--src/test/rustdoc/manual_impl.rs2
-rw-r--r--src/test/rustdoc/no-stack-overflow-25295.rs46
-rw-r--r--src/test/ui/derive-uninhabited-enum-38885.rs27
-rw-r--r--src/test/ui/derive-uninhabited-enum-38885.stderr14
-rwxr-xr-xsrc/tools/publish_toolstate.py6
13 files changed, 429 insertions, 49 deletions
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 9864c1f3d7c..0854df5d126 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -400,7 +400,7 @@ impl<'a, 'tcx> MetadataBlob {
         for (i, dep) in root.crate_deps
                             .decode(self)
                             .enumerate() {
-            write!(out, "{} {}-{}\n", i + 1, dep.name, dep.hash)?;
+            write!(out, "{} {}{}\n", i + 1, dep.name, dep.extra_filename)?;
         }
         write!(out, "\n")?;
         Ok(())
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e71b3ccb01d..9f68fd56c5e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -552,6 +552,14 @@ impl ItemEnum {
             _ => return None,
         })
     }
+
+    pub fn is_associated(&self) -> bool {
+        match *self {
+            ItemEnum::TypedefItem(_, _) |
+            ItemEnum::AssociatedTypeItem(_, _) => true,
+            _ => false,
+        }
+    }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 3f0ef61f375..8ba299d2298 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2322,8 +2322,8 @@ fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Re
     if let Some(ref name) = item.name {
         info!("Documenting {}", name);
     }
-    document_stability(w, cx, item)?;
-    document_full(w, item, cx, "")?;
+    document_stability(w, cx, item, false)?;
+    document_full(w, item, cx, "", false)?;
     Ok(())
 }
 
@@ -2332,15 +2332,19 @@ fn render_markdown(w: &mut fmt::Formatter,
                    cx: &Context,
                    md_text: &str,
                    links: Vec<(String, String)>,
-                   prefix: &str)
+                   prefix: &str,
+                   is_hidden: bool)
                    -> fmt::Result {
     let mut ids = cx.id_map.borrow_mut();
-    write!(w, "<div class='docblock'>{}{}</div>",
-        prefix, Markdown(md_text, &links, RefCell::new(&mut ids), cx.codes))
+    write!(w, "<div class='docblock{}'>{}{}</div>",
+           if is_hidden { " hidden" } else { "" },
+           prefix,
+           Markdown(md_text, &links, RefCell::new(&mut ids),
+           cx.codes))
 }
 
 fn document_short(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, link: AssocItemLink,
-                  prefix: &str) -> fmt::Result {
+                  prefix: &str, is_hidden: bool) -> fmt::Result {
     if let Some(s) = item.doc_value() {
         let markdown = if s.contains('\n') {
             format!("{} [Read more]({})",
@@ -2348,28 +2352,33 @@ fn document_short(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, link
         } else {
             plain_summary_line(Some(s))
         };
-        render_markdown(w, cx, &markdown, item.links(), prefix)?;
+        render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden)?;
     } else if !prefix.is_empty() {
-        write!(w, "<div class='docblock'>{}</div>", prefix)?;
+        write!(w, "<div class='docblock{}'>{}</div>",
+               if is_hidden { " hidden" } else { "" },
+               prefix)?;
     }
     Ok(())
 }
 
 fn document_full(w: &mut fmt::Formatter, item: &clean::Item,
-                 cx: &Context, prefix: &str) -> fmt::Result {
+                 cx: &Context, prefix: &str, is_hidden: bool) -> fmt::Result {
     if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
         debug!("Doc block: =====\n{}\n=====", s);
-        render_markdown(w, cx, &*s, item.links(), prefix)?;
+        render_markdown(w, cx, &*s, item.links(), prefix, is_hidden)?;
     } else if !prefix.is_empty() {
-        write!(w, "<div class='docblock'>{}</div>", prefix)?;
+        write!(w, "<div class='docblock{}'>{}</div>",
+               if is_hidden { " hidden" } else { "" },
+               prefix)?;
     }
     Ok(())
 }
 
-fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
+fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
+                      is_hidden: bool) -> fmt::Result {
     let stabilities = short_stability(item, cx, true);
     if !stabilities.is_empty() {
-        write!(w, "<div class='stability'>")?;
+        write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" })?;
         for stability in stabilities {
             write!(w, "{}", stability)?;
         }
@@ -3934,14 +3943,21 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
             RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_),
         };
 
+        let (is_hidden, extra_class) = if trait_.is_none() ||
+                                          item.doc_value().is_some() ||
+                                          item.inner.is_associated() {
+            (false, "")
+        } else {
+            (true, " hidden")
+        };
         match item.inner {
             clean::MethodItem(clean::Method { ref decl, .. }) |
-            clean::TyMethodItem(clean::TyMethod{ ref decl, .. }) => {
+            clean::TyMethodItem(clean::TyMethod { ref decl, .. }) => {
                 // Only render when the method is not static or we allow static methods
                 if render_method_item {
                     let id = cx.derive_id(format!("{}.{}", item_type, name));
                     let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
-                    write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+                    write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
                     write!(w, "{}", spotlight_decl(decl)?)?;
                     write!(w, "<span id='{}' class='invisible'>", ns_id)?;
                     write!(w, "<table class='table-display'><tbody><tr><td><code>")?;
@@ -3963,7 +3979,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
             clean::TypedefItem(ref tydef, _) => {
                 let id = cx.derive_id(format!("{}.{}", ItemType::AssociatedType, name));
                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
-                write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+                write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
                 write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
                 assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?;
                 write!(w, "</code></span></h4>\n")?;
@@ -3971,7 +3987,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
             clean::AssociatedConstItem(ref ty, ref default) => {
                 let id = cx.derive_id(format!("{}.{}", item_type, name));
                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
-                write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+                write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
                 write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
                 assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?;
                 let src = if let Some(l) = (Item { cx, item }).src_href() {
@@ -3985,7 +4001,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
             clean::AssociatedTypeItem(ref bounds, ref default) => {
                 let id = cx.derive_id(format!("{}.{}", item_type, name));
                 let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
-                write!(w, "<h4 id='{}' class=\"{}\">", id, item_type)?;
+                write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?;
                 write!(w, "<span id='{}' class='invisible'><code>", ns_id)?;
                 assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?;
                 write!(w, "</code></span></h4>\n")?;
@@ -4002,25 +4018,25 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                     if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
                         // We need the stability of the item from the trait
                         // because impls can't have a stability.
-                        document_stability(w, cx, it)?;
+                        document_stability(w, cx, it, is_hidden)?;
                         if item.doc_value().is_some() {
-                            document_full(w, item, cx, "")?;
+                            document_full(w, item, cx, "", is_hidden)?;
                         } else if show_def_docs {
                             // In case the item isn't documented,
                             // provide short documentation from the trait.
-                            document_short(w, cx, it, link, "")?;
+                            document_short(w, cx, it, link, "", is_hidden)?;
                         }
                     }
                 } else {
-                    document_stability(w, cx, item)?;
+                    document_stability(w, cx, item, is_hidden)?;
                     if show_def_docs {
-                        document_full(w, item, cx, "")?;
+                        document_full(w, item, cx, "", is_hidden)?;
                     }
                 }
             } else {
-                document_stability(w, cx, item)?;
+                document_stability(w, cx, item, is_hidden)?;
                 if show_def_docs {
-                    document_short(w, cx, item, link, "")?;
+                    document_short(w, cx, item, link, "", is_hidden)?;
                 }
             }
         }
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index b3110071639..4425712eed7 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -2052,6 +2052,50 @@
     onEach(document.getElementsByClassName('method'), func);
     onEach(document.getElementsByClassName('associatedconstant'), func);
     onEach(document.getElementsByClassName('impl'), func);
+    onEach(document.getElementsByClassName('impl-items'), function(e) {
+        onEach(e.getElementsByClassName('associatedconstant'), func);
+        var hiddenElems = e.getElementsByClassName('hidden');
+        var needToggle = false;
+
+        for (var i = 0; i < hiddenElems.length; ++i) {
+            if (hasClass(hiddenElems[i], "content") === false &&
+                hasClass(hiddenElems[i], "docblock") === false) {
+                needToggle = true;
+                break;
+            }
+        }
+        if (needToggle === true) {
+            var newToggle = document.createElement('a');
+            newToggle.href = 'javascript:void(0)';
+            newToggle.className = 'collapse-toggle hidden-default collapsed';
+            newToggle.innerHTML = "[<span class='inner'>" + labelForToggleButton(true) + "</span>" +
+                                  "] Show hidden undocumented items";
+            newToggle.onclick = function() {
+                if (hasClass(this, "collapsed")) {
+                    removeClass(this, "collapsed");
+                    onEach(this.parentNode.getElementsByClassName("hidden"), function(x) {
+                        if (hasClass(x, "content") === false) {
+                            removeClass(x, "hidden");
+                            addClass(x, "x");
+                        }
+                    }, true);
+                    this.innerHTML = "[<span class='inner'>" + labelForToggleButton(false) +
+                                     "</span>] Hide undocumented items"
+                } else {
+                    addClass(this, "collapsed");
+                    onEach(this.parentNode.getElementsByClassName("x"), function(x) {
+                        if (hasClass(x, "content") === false) {
+                            addClass(x, "hidden");
+                            removeClass(x, "x");
+                        }
+                    }, true);
+                    this.innerHTML = "[<span class='inner'>" + labelForToggleButton(true) +
+                                     "</span>] Show hidden undocumented items";
+                }
+            };
+            e.insertBefore(newToggle, e.firstChild);
+        }
+    });
 
     function createToggle(otherMessage, fontSize, extraClass, show) {
         var span = document.createElement('span');
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index ad6cdfd3e73..8f679b4d22b 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -479,17 +479,6 @@ h4 > code, h3 > code, .invisible > code {
 	margin-bottom: 15px;
 }
 
-.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
-	margin-left: 20px;
-}
-.content .impl-items .docblock, .content .impl-items .stability {
-	margin-bottom: .6em;
-}
-
-.content .impl-items > .stability {
-	margin-left: 40px;
-}
-
 .content .docblock > .impl-items {
 	margin-left: 20px;
 	margin-top: -34px;
@@ -531,7 +520,20 @@ h4 > code, h3 > code, .invisible > code {
 	top: -9px;
 	left: -13px;
 }
-.methods > .stability {
+
+.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant {
+	margin-left: 20px;
+}
+
+.content .impl-items .docblock, .content .impl-items .stability {
+	margin-bottom: .6em;
+}
+
+.content .impl-items > .stability {
+	margin-left: 40px;
+}
+
+.methods > .stability, .content .impl-items > .stability {
 	margin-top: -8px;
 }
 
@@ -839,6 +841,11 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
 	text-align: center;
 }
 
+.collapse-toggle.hidden-default {
+	position: relative;
+	margin-left: 20px;
+}
+
 .ghost {
 	display: none;
 }
diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js
index e10e330402f..5f7a8c75d3c 100644
--- a/src/librustdoc/html/static/storage.js
+++ b/src/librustdoc/html/static/storage.js
@@ -15,11 +15,19 @@ var mainTheme = document.getElementById("mainThemeStyle");
 
 var savedHref = [];
 
-function onEach(arr, func) {
+function onEach(arr, func, reversed) {
     if (arr && arr.length > 0 && func) {
-        for (var i = 0; i < arr.length; i++) {
-            if (func(arr[i]) === true) {
-                return true;
+        if (reversed !== true) {
+            for (var i = 0; i < arr.length; ++i) {
+                if (func(arr[i]) === true) {
+                    return true;
+                }
+            }
+        } else {
+            for (var i = arr.length - 1; i >= 0; --i) {
+                if (func(arr[i]) === true) {
+                    return true;
+                }
             }
         }
     }
diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs
index cbb2a00214a..9ace8714918 100644
--- a/src/test/rustdoc/assoc-consts.rs
+++ b/src/test/rustdoc/assoc-consts.rs
@@ -75,8 +75,8 @@ pub trait Qux {
     /// Docs for QUX1 in trait.
     const QUX1: i8;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
-    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT0 in trait."
-    /// Docs for QUX_DEFAULT0 in trait.
+    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+    /// Docs for QUX_DEFAULT12 in trait.
     const QUX_DEFAULT0: u16 = 1;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
     // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in trait."
@@ -99,7 +99,7 @@ impl Qux for Bar {
     /// Docs for QUX1 in impl.
     const QUX1: i8 = 5;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
-    // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT0 in trait."
+    // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT12 in trait."
     const QUX_DEFAULT0: u16 = 6;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
     // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
diff --git a/src/test/rustdoc/auxiliary/enum_primitive.rs b/src/test/rustdoc/auxiliary/enum_primitive.rs
new file mode 100644
index 00000000000..c265ae44f0d
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/enum_primitive.rs
@@ -0,0 +1,210 @@
+// Copyright (c) 2015 Anders Kaseorg <andersk@mit.edu>
+
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// β€œSoftware”), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED β€œAS IS”, WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+//! This crate exports a macro `enum_from_primitive!` that wraps an
+//! `enum` declaration and automatically adds an implementation of
+//! `num::FromPrimitive` (reexported here), to allow conversion from
+//! primitive integers to the enum.  It therefore provides an
+//! alternative to the built-in `#[derive(FromPrimitive)]`, which
+//! requires the unstable `std::num::FromPrimitive` and is disabled in
+//! Rust 1.0.
+//!
+//! # Example
+//!
+//! ```
+//! #[macro_use] extern crate enum_primitive;
+//! extern crate num_traits;
+//! use num_traits::FromPrimitive;
+//!
+//! enum_from_primitive! {
+//! #[derive(Debug, PartialEq)]
+//! enum FooBar {
+//!     Foo = 17,
+//!     Bar = 42,
+//!     Baz,
+//! }
+//! }
+//!
+//! fn main() {
+//!     assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo));
+//!     assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar));
+//!     assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz));
+//!     assert_eq!(FooBar::from_i32(91), None);
+//! }
+//! ```
+
+
+pub mod num_traits {
+    pub trait FromPrimitive: Sized {
+        fn from_i64(n: i64) -> Option<Self>;
+        fn from_u64(n: u64) -> Option<Self>;
+    }
+}
+
+pub use std::option::Option;
+pub use num_traits::FromPrimitive;
+
+/// Helper macro for internal use by `enum_from_primitive!`.
+#[macro_export]
+macro_rules! enum_from_primitive_impl_ty {
+    ($meth:ident, $ty:ty, $name:ident, $( $variant:ident )*) => {
+        #[allow(non_upper_case_globals, unused)]
+        fn $meth(n: $ty) -> $crate::Option<Self> {
+            $( if n == $name::$variant as $ty {
+                $crate::Option::Some($name::$variant)
+            } else )* {
+                $crate::Option::None
+            }
+        }
+    };
+}
+
+/// Helper macro for internal use by `enum_from_primitive!`.
+#[macro_export]
+#[macro_use(enum_from_primitive_impl_ty)]
+macro_rules! enum_from_primitive_impl {
+    ($name:ident, $( $variant:ident )*) => {
+        impl $crate::FromPrimitive for $name {
+            enum_from_primitive_impl_ty! { from_i64, i64, $name, $( $variant )* }
+            enum_from_primitive_impl_ty! { from_u64, u64, $name, $( $variant )* }
+        }
+    };
+}
+
+/// Wrap this macro around an `enum` declaration to get an
+/// automatically generated implementation of `num::FromPrimitive`.
+#[macro_export]
+#[macro_use(enum_from_primitive_impl)]
+macro_rules! enum_from_primitive {
+    (
+        $( #[$enum_attr:meta] )*
+        enum $name:ident {
+            $( $( #[$variant_attr:meta] )* $variant:ident ),+
+            $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*
+        }
+    ) => {
+        $( #[$enum_attr] )*
+        enum $name {
+            $( $( #[$variant_attr] )* $variant ),+
+            $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*
+        }
+        enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+    };
+
+    (
+        $( #[$enum_attr:meta] )*
+        enum $name:ident {
+            $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),*
+        }
+    ) => {
+        $( #[$enum_attr] )*
+        enum $name {
+            $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),*
+        }
+        enum_from_primitive_impl! { $name, $( $( $variant )+ )* }
+    };
+
+    (
+        $( #[$enum_attr:meta] )*
+        enum $name:ident {
+            $( $( #[$variant_attr:meta] )* $variant:ident ),+
+            $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*,
+        }
+    ) => {
+        $( #[$enum_attr] )*
+        enum $name {
+            $( $( #[$variant_attr] )* $variant ),+
+            $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*,
+        }
+        enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+    };
+
+    (
+        $( #[$enum_attr:meta] )*
+        enum $name:ident {
+            $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+,
+        }
+    ) => {
+        $( #[$enum_attr] )*
+        enum $name {
+            $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+,
+        }
+        enum_from_primitive_impl! { $name, $( $( $variant )+ )+ }
+    };
+
+    (
+        $( #[$enum_attr:meta] )*
+        pub enum $name:ident {
+            $( $( #[$variant_attr:meta] )* $variant:ident ),+
+            $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*
+        }
+    ) => {
+        $( #[$enum_attr] )*
+        pub enum $name {
+            $( $( #[$variant_attr] )* $variant ),+
+            $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*
+        }
+        enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+    };
+
+    (
+        $( #[$enum_attr:meta] )*
+        pub enum $name:ident {
+            $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),*
+        }
+    ) => {
+        $( #[$enum_attr] )*
+        pub enum $name {
+            $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),*
+        }
+        enum_from_primitive_impl! { $name, $( $( $variant )+ )* }
+    };
+
+    (
+        $( #[$enum_attr:meta] )*
+        pub enum $name:ident {
+            $( $( #[$variant_attr:meta] )* $variant:ident ),+
+            $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*,
+        }
+    ) => {
+        $( #[$enum_attr] )*
+        pub enum $name {
+            $( $( #[$variant_attr] )* $variant ),+
+            $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*,
+        }
+        enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
+    };
+
+    (
+        $( #[$enum_attr:meta] )*
+        pub enum $name:ident {
+            $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+,
+        }
+    ) => {
+        $( #[$enum_attr] )*
+        pub enum $name {
+            $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+,
+        }
+        enum_from_primitive_impl! { $name, $( $( $variant )+ )+ }
+    };
+}
+
diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs
index db48a652523..949ef118288 100644
--- a/src/test/rustdoc/manual_impl.rs
+++ b/src/test/rustdoc/manual_impl.rs
@@ -73,7 +73,7 @@ impl T for S2 {
 // @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
-// @has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait a_method definition.'
 pub struct S3(usize);
 
 /// Docs associated with the S3 trait implementation.
diff --git a/src/test/rustdoc/no-stack-overflow-25295.rs b/src/test/rustdoc/no-stack-overflow-25295.rs
new file mode 100644
index 00000000000..37b0aca4b00
--- /dev/null
+++ b/src/test/rustdoc/no-stack-overflow-25295.rs
@@ -0,0 +1,46 @@
+// 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.
+
+// ensure this code doesn't stack overflow
+// aux-build:enum_primitive.rs
+
+#[macro_use] extern crate enum_primitive;
+
+enum_from_primitive! {
+    pub enum Test {
+        A1,A2,A3,A4,A5,A6,
+        B1,B2,B3,B4,B5,B6,
+        C1,C2,C3,C4,C5,C6,
+        D1,D2,D3,D4,D5,D6,
+        E1,E2,E3,E4,E5,E6,
+        F1,F2,F3,F4,F5,F6,
+        G1,G2,G3,G4,G5,G6,
+        H1,H2,H3,H4,H5,H6,
+        I1,I2,I3,I4,I5,I6,
+        J1,J2,J3,J4,J5,J6,
+        K1,K2,K3,K4,K5,K6,
+        L1,L2,L3,L4,L5,L6,
+        M1,M2,M3,M4,M5,M6,
+        N1,N2,N3,N4,N5,N6,
+        O1,O2,O3,O4,O5,O6,
+        P1,P2,P3,P4,P5,P6,
+        Q1,Q2,Q3,Q4,Q5,Q6,
+        R1,R2,R3,R4,R5,R6,
+        S1,S2,S3,S4,S5,S6,
+        T1,T2,T3,T4,T5,T6,
+        U1,U2,U3,U4,U5,U6,
+        V1,V2,V3,V4,V5,V6,
+        W1,W2,W3,W4,W5,W6,
+        X1,X2,X3,X4,X5,X6,
+        Y1,Y2,Y3,Y4,Y5,Y6,
+        Z1,Z2,Z3,Z4,Z5,Z6,
+    }
+}
+
diff --git a/src/test/ui/derive-uninhabited-enum-38885.rs b/src/test/ui/derive-uninhabited-enum-38885.rs
new file mode 100644
index 00000000000..dc7f5d60cd8
--- /dev/null
+++ b/src/test/ui/derive-uninhabited-enum-38885.rs
@@ -0,0 +1,27 @@
+// 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-pass
+// compile-flags: -Wunused
+
+// ensure there are no special warnings about uninhabited types
+// when deriving Debug on an empty enum
+
+#[derive(Debug)]
+enum Void {} //~ WARN never used
+
+#[derive(Debug)]
+enum Foo { //~ WARN never used
+    Bar(u8),
+    Void(Void),
+}
+
+fn main() {}
+
diff --git a/src/test/ui/derive-uninhabited-enum-38885.stderr b/src/test/ui/derive-uninhabited-enum-38885.stderr
new file mode 100644
index 00000000000..11032abfa12
--- /dev/null
+++ b/src/test/ui/derive-uninhabited-enum-38885.stderr
@@ -0,0 +1,14 @@
+warning: enum is never used: `Void`
+  --> $DIR/derive-uninhabited-enum-38885.rs:18:1
+   |
+LL | enum Void {} //~ WARN never used
+   | ^^^^^^^^^
+   |
+   = note: `-W dead-code` implied by `-W unused`
+
+warning: enum is never used: `Foo`
+  --> $DIR/derive-uninhabited-enum-38885.rs:21:1
+   |
+LL | enum Foo { //~ WARN never used
+   | ^^^^^^^^
+
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index c794e169fca..4ade87f5d65 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -26,7 +26,7 @@ except ImportError:
 MAINTAINERS = {
     'miri': '@oli-obk @RalfJung @eddyb',
     'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk',
-    'rls': '@nrc',
+    'rls': '@nrc @Xanewok',
     'rustfmt': '@nrc',
     'book': '@carols10cents @steveklabnik',
     'nomicon': '@frewsxcv @Gankro',
@@ -81,8 +81,8 @@ def update_latest(
                 status[os] = new
                 if new > old:
                     changed = True
-                    message += 'πŸŽ‰ {} on {}: {} β†’ {}.\n' \
-                        .format(tool, os, old, new)
+                    message += 'πŸŽ‰ {} on {}: {} β†’ {} (cc {}, @rust-lang/infra).\n' \
+                        .format(tool, os, old, new, MAINTAINERS.get(tool))
                 elif new < old:
                     changed = True
                     message += 'πŸ’” {} on {}: {} β†’ {} (cc {}, @rust-lang/infra).\n' \