about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/bootstrap/dist.rs21
-rw-r--r--src/doc/book/src/macros.md14
-rw-r--r--src/doc/book/src/procedural-macros.md2
-rw-r--r--src/etc/natvis/libcollections.natvis56
-rw-r--r--src/etc/natvis/libcore.natvis39
-rw-r--r--src/grammar/README.md6
-rw-r--r--src/libcollections/borrow.rs8
-rw-r--r--src/libcore/cell.rs124
-rw-r--r--src/librustc/traits/error_reporting.rs9
-rw-r--r--src/libstd/collections/hash/map.rs2
-rw-r--r--src/libstd/sys/mod.rs12
-rw-r--r--src/libstd/sys/windows/c.rs2
-rw-r--r--src/test/compile-fail/feature-gate-static_recursion.rs49
-rw-r--r--src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.rs37
-rw-r--r--src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr43
-rw-r--r--src/tools/tidy/src/features.rs2
16 files changed, 329 insertions, 97 deletions
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 52a7c63c904..319c61ece29 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -26,6 +26,12 @@ use std::process::{Command, Stdio};
 
 use build_helper::output;
 
+#[cfg(not(target_os = "solaris"))]
+const SH_CMD: &'static str = "sh";
+// On Solaris, sh is the historical bourne shell, not a POSIX shell, or bash.
+#[cfg(target_os = "solaris")]
+const SH_CMD: &'static str = "bash";
+
 use {Build, Compiler, Mode};
 use util::{cp_r, libdir, is_dylib, cp_filtered, copy};
 
@@ -69,7 +75,7 @@ pub fn docs(build: &Build, stage: u32, host: &str) {
     let src = build.out.join(host).join("doc");
     cp_r(&src, &dst);
 
-    let mut cmd = Command::new("sh");
+    let mut cmd = Command::new(SH_CMD);
     cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh")))
        .arg("--product-name=Rust-Documentation")
        .arg("--rel-manifest-dir=rustlib")
@@ -119,7 +125,7 @@ pub fn mingw(build: &Build, host: &str) {
        .arg(host);
     build.run(&mut cmd);
 
-    let mut cmd = Command::new("sh");
+    let mut cmd = Command::new(SH_CMD);
     cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh")))
        .arg("--product-name=Rust-MinGW")
        .arg("--rel-manifest-dir=rustlib")
@@ -185,7 +191,7 @@ pub fn rustc(build: &Build, stage: u32, host: &str) {
     }
 
     // Finally, wrap everything up in a nice tarball!
-    let mut cmd = Command::new("sh");
+    let mut cmd = Command::new(SH_CMD);
     cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh")))
        .arg("--product-name=Rust")
        .arg("--rel-manifest-dir=rustlib")
@@ -290,7 +296,7 @@ pub fn std(build: &Build, compiler: &Compiler, target: &str) {
     let src = build.sysroot(compiler).join("lib/rustlib");
     cp_r(&src.join(target), &dst);
 
-    let mut cmd = Command::new("sh");
+    let mut cmd = Command::new(SH_CMD);
     cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh")))
        .arg("--product-name=Rust")
        .arg("--rel-manifest-dir=rustlib")
@@ -343,9 +349,10 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
     let image_src = src.join("save-analysis");
     let dst = image.join("lib/rustlib").join(target).join("analysis");
     t!(fs::create_dir_all(&dst));
+    println!("image_src: {:?}, dst: {:?}", image_src, dst);
     cp_r(&image_src, &dst);
 
-    let mut cmd = Command::new("sh");
+    let mut cmd = Command::new(SH_CMD);
     cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh")))
        .arg("--product-name=Rust")
        .arg("--rel-manifest-dir=rustlib")
@@ -452,7 +459,7 @@ pub fn rust_src(build: &Build) {
     build.run(&mut cmd);
 
     // Create source tarball in rust-installer format
-    let mut cmd = Command::new("sh");
+    let mut cmd = Command::new(SH_CMD);
     cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh")))
        .arg("--product-name=Rust")
        .arg("--rel-manifest-dir=rustlib")
@@ -610,7 +617,7 @@ pub fn extended(build: &Build, stage: u32, target: &str) {
         input_tarballs.push_str(&sanitize_sh(&mingw_installer));
     }
 
-    let mut cmd = Command::new("sh");
+    let mut cmd = Command::new(SH_CMD);
     cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/combine-installers.sh")))
        .arg("--product-name=Rust")
        .arg("--rel-manifest-dir=rustlib")
diff --git a/src/doc/book/src/macros.md b/src/doc/book/src/macros.md
index 3ccbeb05f01..ae1e1c65dd2 100644
--- a/src/doc/book/src/macros.md
+++ b/src/doc/book/src/macros.md
@@ -261,36 +261,34 @@ The metavariable `$x` is parsed as a single expression node, and keeps its
 place in the syntax tree even after substitution.
 
 Another common problem in macro systems is ‘variable capture’. Here’s a C
-macro, using [a GNU C extension] to emulate Rust’s expression blocks.
-
-[a GNU C extension]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
+macro using a block with multiple statements.
 
 ```text
-#define LOG(msg) ({ \
+#define LOG(msg) do { \
     int state = get_log_state(); \
     if (state > 0) { \
         printf("log(%d): %s\n", state, msg); \
     } \
-})
+} while (0)
 ```
 
 Here’s a simple use case that goes terribly wrong:
 
 ```text
 const char *state = "reticulating splines";
-LOG(state)
+LOG(state);
 ```
 
 This expands to
 
 ```text
 const char *state = "reticulating splines";
-{
+do {
     int state = get_log_state();
     if (state > 0) {
         printf("log(%d): %s\n", state, state);
     }
-}
+} while (0);
 ```
 
 The second variable named `state` shadows the first one.  This is a problem
diff --git a/src/doc/book/src/procedural-macros.md b/src/doc/book/src/procedural-macros.md
index d286c3b7bdc..6c4700f9305 100644
--- a/src/doc/book/src/procedural-macros.md
+++ b/src/doc/book/src/procedural-macros.md
@@ -99,7 +99,7 @@ created, we'll add it to our toml:
 hello-world-derive = { path = "hello-world-derive" }
 ```
 
-As for our the source of our `hello-world-derive` crate, here's an example:
+As for the source of our `hello-world-derive` crate, here's an example:
 
 ```rust,ignore
 extern crate proc_macro;
diff --git a/src/etc/natvis/libcollections.natvis b/src/etc/natvis/libcollections.natvis
new file mode 100644
index 00000000000..821c52361f8
--- /dev/null
+++ b/src/etc/natvis/libcollections.natvis
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+  <Type Name="collections::vec::Vec&lt;*&gt;">
+    <DisplayString>{{ size={len} }}</DisplayString>
+    <Expand>
+      <Item Name="[size]" ExcludeView="simple">len</Item>
+      <Item Name="[capacity]" ExcludeView="simple">buf.cap</Item>
+      <ArrayItems>
+        <Size>len</Size>
+        <ValuePointer>buf.ptr.pointer.__0</ValuePointer>
+      </ArrayItems>
+    </Expand>
+  </Type>
+  <Type Name="collections::vec_deque::VecDeque&lt;*&gt;">
+    <DisplayString>{{ size={tail &lt;= head ? head - tail : buf.cap - tail + head} }}</DisplayString>
+    <Expand>
+      <Item Name="[size]" ExcludeView="simple">tail &lt;= head ? head - tail : buf.cap - tail + head</Item>
+      <Item Name="[capacity]" ExcludeView="simple">buf.cap</Item>
+      <CustomListItems>
+        <Variable Name="i" InitialValue="tail" />
+
+        <Size>tail &lt;= head ? head - tail : buf.cap - tail + head</Size>
+        <Loop>
+          <If Condition="i == head">
+            <Break/>
+          </If>
+          <Item>buf.ptr.pointer.__0 + i</Item>
+          <Exec>i = (i + 1 == buf.cap ? 0 : i + 1)</Exec>
+        </Loop>
+      </CustomListItems>
+    </Expand>
+  </Type>
+  <Type Name="collections::linked_list::LinkedList&lt;*&gt;">
+    <DisplayString>{{ size={len} }}</DisplayString>
+    <Expand>
+      <LinkedListItems>
+        <Size>len</Size>
+        <HeadPointer>*(collections::linked_list::Node&lt;$T1&gt; **)&amp;head</HeadPointer>
+        <NextPointer>*(collections::linked_list::Node&lt;$T1&gt; **)&amp;next</NextPointer>
+        <ValueNode>element</ValueNode>
+      </LinkedListItems>
+    </Expand>
+  </Type>
+  <Type Name="collections::string::String">
+    <DisplayString>{*(char**)this,[vec.len]}</DisplayString>
+    <StringView>*(char**)this,[vec.len]</StringView>
+    <Expand>
+      <Item Name="[size]" ExcludeView="simple">vec.len</Item>
+      <Item Name="[capacity]" ExcludeView="simple">vec.buf.cap</Item>
+      <ArrayItems>
+        <Size>vec.len</Size>
+        <ValuePointer>*(char**)this</ValuePointer>
+      </ArrayItems>
+    </Expand>
+  </Type>
+</AutoVisualizer>
\ No newline at end of file
diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis
new file mode 100644
index 00000000000..37d64be1ce9
--- /dev/null
+++ b/src/etc/natvis/libcore.natvis
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
+  <Type Name="core::ptr::Unique&lt;*&gt;">
+    <DisplayString>{{ Unique {*pointer.__0} }}</DisplayString>
+    <Expand>
+      <Item Name="[ptr]">pointer.__0</Item>
+    </Expand>
+  </Type>
+  <Type Name="core::ptr::Shared&lt;*&gt;">
+    <DisplayString>{{ Shared {*pointer.__0} }}</DisplayString>
+    <Expand>
+      <Item Name="[ptr]">pointer.__0</Item>
+    </Expand>
+  </Type>
+  <Type Name="core::option::Option&lt;*&gt;">
+    <DisplayString Condition="RUST$ENUM$DISR == 0x0">{{ None }}</DisplayString>
+    <DisplayString Condition="RUST$ENUM$DISR == 0x1">{{ Some {__0} }}</DisplayString>
+    <Expand>
+      <Item Name="[size]" ExcludeView="simple">(ULONG)(RUST$ENUM$DISR != 0)</Item>
+      <Item Name="[value]" ExcludeView="simple">__0</Item>
+      <ArrayItems>
+        <Size>(ULONG)(RUST$ENUM$DISR != 0)</Size>
+        <ValuePointer>&amp;__0</ValuePointer>
+      </ArrayItems>
+    </Expand>
+  </Type>
+  <Type Name="core::option::Option&lt;*&gt;" Priority="MediumLow">
+    <DisplayString Condition="*(PVOID *)this == nullptr">{{ None }}</DisplayString>
+    <DisplayString>{{ Some {($T1 *)this} }}</DisplayString>
+    <Expand>
+      <Item Name="[size]" ExcludeView="simple">(ULONG)(*(PVOID *)this != nullptr)</Item>
+      <Item Name="[value]" ExcludeView="simple" Condition="*(PVOID *)this != nullptr">($T1 *)this</Item>
+      <ArrayItems>
+        <Size>(ULONG)(*(PVOID *)this != nullptr)</Size>
+        <ValuePointer>($T1 *)this</ValuePointer>
+      </ArrayItems>
+    </Expand>
+  </Type>
+</AutoVisualizer>
\ No newline at end of file
diff --git a/src/grammar/README.md b/src/grammar/README.md
index cd2dd38de36..83808108ff8 100644
--- a/src/grammar/README.md
+++ b/src/grammar/README.md
@@ -8,7 +8,7 @@ The build of the rust part is included with `make tidy` and can be run with `mak
 
 # Manual build
 
-To use manually, assuming antlr4 ist installed at `/usr/share/java/antlr-complete.jar`:
+To use manually, assuming antlr4 is installed at `/usr/share/java/antlr-complete.jar`:
 
 ```
 antlr4 RustLexer.g4
@@ -20,8 +20,8 @@ for file in ../*/**.rs; do
 done
 ```
 
-Note That the `../*/**.rs` glob will match every `*.rs` file in the above
-directory and all of its recursive children. This is a zsh extension.
+Note that the `../*/**.rs` glob will match every `*.rs` file in the above
+directory and all of its recursive children. This is a Zsh extension.
 
 
 ## Cleanup
diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs
index e5bcf0d8e81..65056121f05 100644
--- a/src/libcollections/borrow.rs
+++ b/src/libcollections/borrow.rs
@@ -52,11 +52,11 @@ pub trait ToOwned {
     /// Basic usage:
     ///
     /// ```
-    /// let s = "a"; // &str
-    /// let ss = s.to_owned(); // String
+    /// let s: &str = "a";
+    /// let ss: String = s.to_owned();
     ///
-    /// let v = &[1, 2]; // slice
-    /// let vv = v.to_owned(); // Vec
+    /// let v: &[i32] = &[1, 2];
+    /// let vv: Vec<i32> = v.to_owned();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn to_owned(&self) -> Self::Owned;
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index d130b0279a2..736797d162b 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -213,66 +213,6 @@ impl<T:Copy> Cell<T> {
     pub fn get(&self) -> T {
         unsafe{ *self.value.get() }
     }
-
-    /// Returns a reference to the underlying `UnsafeCell`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(as_unsafe_cell)]
-    ///
-    /// use std::cell::Cell;
-    ///
-    /// let c = Cell::new(5);
-    ///
-    /// let uc = c.as_unsafe_cell();
-    /// ```
-    #[inline]
-    #[unstable(feature = "as_unsafe_cell", issue = "27708")]
-    #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")]
-    pub fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
-        &self.value
-    }
-
-    /// Returns a raw pointer to the underlying data in this cell.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::cell::Cell;
-    ///
-    /// let c = Cell::new(5);
-    ///
-    /// let ptr = c.as_ptr();
-    /// ```
-    #[inline]
-    #[stable(feature = "cell_as_ptr", since = "1.12.0")]
-    pub fn as_ptr(&self) -> *mut T {
-        self.value.get()
-    }
-
-    /// Returns a mutable reference to the underlying data.
-    ///
-    /// This call borrows `Cell` mutably (at compile-time) which guarantees
-    /// that we possess the only reference.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::cell::Cell;
-    ///
-    /// let mut c = Cell::new(5);
-    /// *c.get_mut() += 1;
-    ///
-    /// assert_eq!(c.get(), 6);
-    /// ```
-    #[inline]
-    #[stable(feature = "cell_get_mut", since = "1.11.0")]
-    pub fn get_mut(&mut self) -> &mut T {
-        unsafe {
-            &mut *self.value.get()
-        }
-    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -290,7 +230,7 @@ impl<T:Copy> Clone for Cell<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T:Default + Copy> Default for Cell<T> {
+impl<T:Default> Default for Cell<T> {
     /// Creates a `Cell<T>`, with the `Default` value for T.
     #[inline]
     fn default() -> Cell<T> {
@@ -346,7 +286,7 @@ impl<T:Ord + Copy> Ord for Cell<T> {
 }
 
 #[stable(feature = "cell_from", since = "1.12.0")]
-impl<T: Copy> From<T> for Cell<T> {
+impl<T> From<T> for Cell<T> {
     fn from(t: T) -> Cell<T> {
         Cell::new(t)
     }
@@ -370,6 +310,66 @@ impl<T> Cell<T> {
         }
     }
 
+    /// Returns a reference to the underlying `UnsafeCell`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(as_unsafe_cell)]
+    ///
+    /// use std::cell::Cell;
+    ///
+    /// let c = Cell::new(5);
+    ///
+    /// let uc = c.as_unsafe_cell();
+    /// ```
+    #[inline]
+    #[unstable(feature = "as_unsafe_cell", issue = "27708")]
+    #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")]
+    pub fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
+        &self.value
+    }
+
+    /// Returns a raw pointer to the underlying data in this cell.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::cell::Cell;
+    ///
+    /// let c = Cell::new(5);
+    ///
+    /// let ptr = c.as_ptr();
+    /// ```
+    #[inline]
+    #[stable(feature = "cell_as_ptr", since = "1.12.0")]
+    pub fn as_ptr(&self) -> *mut T {
+        self.value.get()
+    }
+
+    /// Returns a mutable reference to the underlying data.
+    ///
+    /// This call borrows `Cell` mutably (at compile-time) which guarantees
+    /// that we possess the only reference.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::cell::Cell;
+    ///
+    /// let mut c = Cell::new(5);
+    /// *c.get_mut() += 1;
+    ///
+    /// assert_eq!(c.get(), 6);
+    /// ```
+    #[inline]
+    #[stable(feature = "cell_get_mut", since = "1.11.0")]
+    pub fn get_mut(&mut self) -> &mut T {
+        unsafe {
+            &mut *self.value.get()
+        }
+    }
+
     /// Sets the contained value.
     ///
     /// # Examples
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 024c14ce9d9..70ca5fe83a9 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -36,7 +36,6 @@ use ty::fold::TypeFolder;
 use ty::subst::Subst;
 use util::nodemap::{FxHashMap, FxHashSet};
 
-use std::cmp;
 use std::fmt;
 use syntax::ast;
 use hir::{intravisit, Local, Pat};
@@ -392,12 +391,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             return;
         }
 
-        let end = cmp::min(4, impl_candidates.len());
+        let end = if impl_candidates.len() <= 5 {
+            impl_candidates.len()
+        } else {
+            4
+        };
         err.help(&format!("the following implementations were found:{}{}",
                           &impl_candidates[0..end].iter().map(|candidate| {
                               format!("\n  {:?}", candidate)
                           }).collect::<String>(),
-                          if impl_candidates.len() > 4 {
+                          if impl_candidates.len() > 5 {
                               format!("\nand {} others", impl_candidates.len() - 4)
                           } else {
                               "".to_owned()
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index ca9bdcfe2c2..45b5f7cac07 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -441,7 +441,7 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>)
 /// Perform robin hood bucket stealing at the given `bucket`. You must
 /// also pass that bucket's displacement so we don't have to recalculate it.
 ///
-/// `hash`, `k`, and `v` are the elements to "robin hood" into the hashtable.
+/// `hash`, `key`, and `val` are the elements to "robin hood" into the hashtable.
 fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
                                 mut displacement: usize,
                                 mut hash: SafeHash,
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
index 14da376efa9..ef4dc365dbe 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -13,11 +13,11 @@
 //! The `std::sys` module is the abstracted interface through which
 //! `std` talks to the underlying operating system. It has different
 //! implementations for different operating system families, today
-//! just Unix and Windows.
+//! just Unix and Windows, and initial support for Redox.
 //!
 //! The centralization of platform-specific code in this module is
 //! enforced by the "platform abstraction layer" tidy script in
-//! `tools/tidy/pal.rs`.
+//! `tools/tidy/src/pal.rs`.
 //!
 //! This module is closely related to the platform-independent system
 //! integration code in `std::sys_common`. See that module's
@@ -34,10 +34,6 @@
 
 pub use self::imp::*;
 
-#[cfg(target_os = "redox")]
-#[path = "redox/mod.rs"]
-mod imp;
-
 #[cfg(unix)]
 #[path = "unix/mod.rs"]
 mod imp;
@@ -45,3 +41,7 @@ mod imp;
 #[cfg(windows)]
 #[path = "windows/mod.rs"]
 mod imp;
+
+#[cfg(target_os = "redox")]
+#[path = "redox/mod.rs"]
+mod imp;
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index e5010ca3564..4daab31c28f 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -912,7 +912,7 @@ extern "system" {
     pub fn Sleep(dwMilliseconds: DWORD);
     pub fn GetProcessId(handle: HANDLE) -> DWORD;
     pub fn GetUserProfileDirectoryW(hToken: HANDLE,
-                                    lpProfileDir: LPCWSTR,
+                                    lpProfileDir: LPWSTR,
                                     lpcchSize: *mut DWORD) -> BOOL;
     pub fn SetHandleInformation(hObject: HANDLE,
                                 dwMask: DWORD,
diff --git a/src/test/compile-fail/feature-gate-static_recursion.rs b/src/test/compile-fail/feature-gate-static_recursion.rs
new file mode 100644
index 00000000000..bd20c891d8e
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-static_recursion.rs
@@ -0,0 +1,49 @@
+// 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.
+
+static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
+//~^ ERROR recursive static (see issue #29719)
+
+struct StaticDoubleLinked {
+    prev: &'static StaticDoubleLinked,
+    next: &'static StaticDoubleLinked,
+    data: i32,
+    head: bool,
+}
+
+static L1: StaticDoubleLinked = StaticDoubleLinked{prev: &L3, next: &L2, data: 1, head: true};
+//~^ ERROR recursive static (see issue #29719)
+//~^^ ERROR recursive static (see issue #29719)
+//~^^^ ERROR recursive static (see issue #29719)
+static L2: StaticDoubleLinked = StaticDoubleLinked{prev: &L1, next: &L3, data: 2, head: false};
+static L3: StaticDoubleLinked = StaticDoubleLinked{prev: &L2, next: &L1, data: 3, head: false};
+
+
+pub fn main() {
+    unsafe { assert_eq!(S, *(S as *const *const u8)); }
+
+    let mut test_vec = Vec::new();
+    let mut cur = &L1;
+    loop {
+        test_vec.push(cur.data);
+        cur = cur.next;
+        if cur.head { break }
+    }
+    assert_eq!(&test_vec, &[1,2,3]);
+
+    let mut test_vec = Vec::new();
+    let mut cur = &L1;
+    loop {
+        cur = cur.prev;
+        test_vec.push(cur.data);
+        if cur.head { break }
+    }
+    assert_eq!(&test_vec, &[3,2,1]);
+}
diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.rs b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.rs
new file mode 100644
index 00000000000..68b1f79c89b
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.rs
@@ -0,0 +1,37 @@
+// 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.
+
+trait Foo<B> {
+    fn bar(&self){}
+}
+
+impl Foo<u8> for i8 {}
+impl Foo<u16> for i8 {}
+impl Foo<u32> for i8 {}
+impl Foo<u64> for i8 {}
+impl Foo<bool> for i8 {}
+
+impl Foo<u16> for u8 {}
+impl Foo<u32> for u8 {}
+impl Foo<u64> for u8 {}
+impl Foo<bool> for u8 {}
+
+impl Foo<u8> for bool {}
+impl Foo<u16> for bool {}
+impl Foo<u32> for bool {}
+impl Foo<u64> for bool {}
+impl Foo<bool> for bool {}
+impl Foo<i8> for bool {}
+
+fn main() {
+    Foo::<i32>::bar(&1i8);
+    Foo::<i32>::bar(&1u8);
+    Foo::<i32>::bar(&true);
+}
diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr
new file mode 100644
index 00000000000..4ea4adfcfe0
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr
@@ -0,0 +1,43 @@
+error[E0277]: the trait bound `i8: Foo<i32>` is not satisfied
+  --> $DIR/issue-39802-show-5-trait-impls.rs:34:5
+   |
+34 |     Foo::<i32>::bar(&1i8);
+   |     ^^^^^^^^^^^^^^^ the trait `Foo<i32>` is not implemented for `i8`
+   |
+   = help: the following implementations were found:
+             <i8 as Foo<u8>>
+             <i8 as Foo<u16>>
+             <i8 as Foo<u32>>
+             <i8 as Foo<u64>>
+             <i8 as Foo<bool>>
+   = note: required by `Foo::bar`
+
+error[E0277]: the trait bound `u8: Foo<i32>` is not satisfied
+  --> $DIR/issue-39802-show-5-trait-impls.rs:35:5
+   |
+35 |     Foo::<i32>::bar(&1u8);
+   |     ^^^^^^^^^^^^^^^ the trait `Foo<i32>` is not implemented for `u8`
+   |
+   = help: the following implementations were found:
+             <u8 as Foo<u16>>
+             <u8 as Foo<u32>>
+             <u8 as Foo<u64>>
+             <u8 as Foo<bool>>
+   = note: required by `Foo::bar`
+
+error[E0277]: the trait bound `bool: Foo<i32>` is not satisfied
+  --> $DIR/issue-39802-show-5-trait-impls.rs:36:5
+   |
+36 |     Foo::<i32>::bar(&true);
+   |     ^^^^^^^^^^^^^^^ the trait `Foo<i32>` is not implemented for `bool`
+   |
+   = help: the following implementations were found:
+             <bool as Foo<u8>>
+             <bool as Foo<u16>>
+             <bool as Foo<u32>>
+             <bool as Foo<u64>>
+           and 2 others
+   = note: required by `Foo::bar`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index cb6e73237d5..13f272517b1 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -166,7 +166,7 @@ pub fn check(path: &Path, bad: &mut bool) {
 
     // FIXME get this whitelist empty.
     let whitelist = vec![
-        "abi_ptx", "simd", "static_recursion",
+        "abi_ptx", "simd",
         "cfg_target_has_atomic",
         "unboxed_closures", "stmt_expr_attributes",
         "cfg_target_thread_local", "unwind_attributes",