]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #59129 - sanxiyn:visit-impl-trait, r=varkor
authorMazdak Farrokhzad <twingoow@gmail.com>
Wed, 13 Mar 2019 02:33:53 +0000 (03:33 +0100)
committerGitHub <noreply@github.com>
Wed, 13 Mar 2019 02:33:53 +0000 (03:33 +0100)
Visit impl Trait for dead_code lint

Fix #59085.

115 files changed:
Cargo.lock
src/bootstrap/builder.rs
src/bootstrap/test.rs
src/liballoc/boxed.rs
src/liballoc/rc.rs
src/liballoc/string.rs
src/liballoc/vec.rs
src/libcore/array.rs
src/libcore/cmp.rs
src/libcore/convert.rs
src/libcore/internal_macros.rs
src/libcore/num/mod.rs
src/libcore/ops/range.rs
src/libcore/ptr.rs
src/libcore/result.rs
src/libcore/tests/fmt/num.rs
src/librustc/lint/builtin.rs
src/librustc/ty/context.rs
src/librustc_codegen_llvm/debuginfo/doc.rs
src/librustc_incremental/Cargo.toml
src/librustc_incremental/persist/load.rs
src/librustc_interface/Cargo.toml
src/librustc_lint/lib.rs
src/librustc_mir/build/matches/simplify.rs
src/librustc_passes/ast_validation.rs
src/librustc_typeck/check/compare_method.rs
src/libstd/collections/hash/set.rs
src/libstd/error.rs
src/libstd/ffi/c_str.rs
src/libstd/ffi/os_str.rs
src/libstd/path.rs
src/libstd/sys/cloudabi/shims/net.rs
src/libstd/sys/redox/net/mod.rs
src/libstd/sys/sgx/net.rs
src/libstd/sys/unix/l4re.rs
src/libstd/sys/wasm/net.rs
src/libstd/sys_common/net.rs
src/libsyntax/parse/lexer/mod.rs
src/test/rustdoc-js-std/alias-1.js [new file with mode: 0644]
src/test/rustdoc-js-std/alias-2.js [new file with mode: 0644]
src/test/rustdoc-js-std/alias-3.js [new file with mode: 0644]
src/test/rustdoc-js-std/alias.js [new file with mode: 0644]
src/test/rustdoc-js-std/basic.js [new file with mode: 0644]
src/test/rustdoc-js-std/deduplication.js [new file with mode: 0644]
src/test/rustdoc-js-std/enum-option.js [new file with mode: 0644]
src/test/rustdoc-js-std/filter-crate.js [new file with mode: 0644]
src/test/rustdoc-js-std/fn-forget.js [new file with mode: 0644]
src/test/rustdoc-js-std/from_u.js [new file with mode: 0644]
src/test/rustdoc-js-std/keyword.js [new file with mode: 0644]
src/test/rustdoc-js-std/macro-check.js [new file with mode: 0644]
src/test/rustdoc-js-std/macro-print.js [new file with mode: 0644]
src/test/rustdoc-js-std/multi-query.js [new file with mode: 0644]
src/test/rustdoc-js-std/never.js [new file with mode: 0644]
src/test/rustdoc-js-std/quoted.js [new file with mode: 0644]
src/test/rustdoc-js-std/should-fail.js [new file with mode: 0644]
src/test/rustdoc-js-std/string-from_ut.js [new file with mode: 0644]
src/test/rustdoc-js-std/struct-vec.js [new file with mode: 0644]
src/test/rustdoc-js-std/vec-new.js [new file with mode: 0644]
src/test/rustdoc-js/alias-1.js [deleted file]
src/test/rustdoc-js/alias-2.js [deleted file]
src/test/rustdoc-js/alias-3.js [deleted file]
src/test/rustdoc-js/alias.js [deleted file]
src/test/rustdoc-js/basic.js
src/test/rustdoc-js/basic.rs [new file with mode: 0644]
src/test/rustdoc-js/deduplication.js [deleted file]
src/test/rustdoc-js/enum-option.js [deleted file]
src/test/rustdoc-js/filter-crate.js [deleted file]
src/test/rustdoc-js/fn-forget.js [deleted file]
src/test/rustdoc-js/from_u.js [deleted file]
src/test/rustdoc-js/keyword.js [deleted file]
src/test/rustdoc-js/macro-check.js [deleted file]
src/test/rustdoc-js/macro-print.js [deleted file]
src/test/rustdoc-js/multi-query.js [deleted file]
src/test/rustdoc-js/never.js [deleted file]
src/test/rustdoc-js/quoted.js [deleted file]
src/test/rustdoc-js/should-fail.js [deleted file]
src/test/rustdoc-js/string-from_ut.js [deleted file]
src/test/rustdoc-js/struct-vec.js [deleted file]
src/test/rustdoc-js/vec-new.js [deleted file]
src/test/ui/associated-const/associated-const-generic-obligations.rs
src/test/ui/associated-const/associated-const-generic-obligations.stderr
src/test/ui/associated-const/associated-const-trait-bound.rs [new file with mode: 0644]
src/test/ui/block-expression-remove-semicolon.rs [new file with mode: 0644]
src/test/ui/block-expression-remove-semicolon.stderr [new file with mode: 0644]
src/test/ui/borrowck/issue-10876.rs [new file with mode: 0644]
src/test/ui/impl-trait/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs [new file with mode: 0644]
src/test/ui/impl-trait/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr [new file with mode: 0644]
src/test/ui/impl-trait/issue-57979-impl-trait-in-path.rs [new file with mode: 0644]
src/test/ui/impl-trait/issue-57979-impl-trait-in-path.stderr [new file with mode: 0644]
src/test/ui/impl-trait/issue-57979-nested-impl-trait-in-assoc-proj.rs [new file with mode: 0644]
src/test/ui/impl-trait/issue-57979-nested-impl-trait-in-assoc-proj.stderr [new file with mode: 0644]
src/test/ui/issues/issue-26448-1.rs [new file with mode: 0644]
src/test/ui/issues/issue-26448-2.rs [new file with mode: 0644]
src/test/ui/issues/issue-26448-3.rs [new file with mode: 0644]
src/test/ui/issues/issue-26619.nll.stderr [new file with mode: 0644]
src/test/ui/issues/issue-26619.rs [new file with mode: 0644]
src/test/ui/issues/issue-26619.stderr [new file with mode: 0644]
src/test/ui/issues/issue-44127.rs [new file with mode: 0644]
src/test/ui/issues/issue-44255.rs [new file with mode: 0644]
src/test/ui/issues/issue-46101.rs [new file with mode: 0644]
src/test/ui/issues/issue-46101.stderr [new file with mode: 0644]
src/test/ui/issues/issue-55731.rs [new file with mode: 0644]
src/test/ui/issues/issue-55731.stderr [new file with mode: 0644]
src/test/ui/issues/issue-57781.rs [new file with mode: 0644]
src/test/ui/issues/issue-57979.rs [deleted file]
src/test/ui/issues/issue-57979.stderr [deleted file]
src/test/ui/nll/trait-associated-constant.rs
src/test/ui/nll/trait-associated-constant.stderr
src/test/ui/parser/numeric-lifetime.rs [new file with mode: 0644]
src/test/ui/parser/numeric-lifetime.stderr [new file with mode: 0644]
src/test/ui/primitive-binop-lhs-mut.rs [new file with mode: 0644]
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/runtest.rs
src/tools/rustdoc-js-std/tester.js [new file with mode: 0644]
src/tools/rustdoc-js/tester.js

index db2a5f9ec7c3480fd138c420e2b8a5966bdc70e3..39ecc880097e3a9d62049c0d517ba58ce5790e36 100644 (file)
@@ -2747,7 +2747,7 @@ version = "0.0.0"
 dependencies = [
  "graphviz 0.0.0",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_fs_util 0.0.0",
@@ -2778,7 +2778,7 @@ dependencies = [
  "rustc_resolve 0.0.0",
  "rustc_traits 0.0.0",
  "rustc_typeck 0.0.0",
- "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serialize 0.0.0",
  "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntax 0.0.0",
index eb1a2a59fa3c52590de053f125b07b86f1904476..ffd23e72e80a68cd206f7e43c1943a06ee61bde6 100644 (file)
@@ -405,7 +405,8 @@ macro_rules! describe {
                 test::Miri,
                 test::Clippy,
                 test::CompiletestTest,
-                test::RustdocJS,
+                test::RustdocJSStd,
+                test::RustdocJSNotStd,
                 test::RustdocTheme,
                 // Run bootstrap close to the end as it's unlikely to fail
                 test::Bootstrap,
index 51412f79c3d0c85789ac2dddffc172339c716338..b7323b2eadc3dd21b798158f999404cfa4edc193 100644 (file)
@@ -574,22 +574,22 @@ fn run(self, builder: &Builder<'_>) {
 }
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub struct RustdocJS {
+pub struct RustdocJSStd {
     pub host: Interned<String>,
     pub target: Interned<String>,
 }
 
-impl Step for RustdocJS {
+impl Step for RustdocJSStd {
     type Output = ();
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/test/rustdoc-js")
+        run.path("src/test/rustdoc-js-std")
     }
 
     fn make_run(run: RunConfig<'_>) {
-        run.builder.ensure(RustdocJS {
+        run.builder.ensure(RustdocJSStd {
             host: run.host,
             target: run.target,
         });
@@ -598,12 +598,55 @@ fn make_run(run: RunConfig<'_>) {
     fn run(self, builder: &Builder<'_>) {
         if let Some(ref nodejs) = builder.config.nodejs {
             let mut command = Command::new(nodejs);
-            command.args(&["src/tools/rustdoc-js/tester.js", &*self.host]);
+            command.args(&["src/tools/rustdoc-js-std/tester.js", &*self.host]);
             builder.ensure(crate::doc::Std {
                 target: self.target,
                 stage: builder.top_stage,
             });
             builder.run(&mut command);
+        } else {
+            builder.info(
+                "No nodejs found, skipping \"src/test/rustdoc-js-std\" tests"
+            );
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct RustdocJSNotStd {
+    pub host: Interned<String>,
+    pub target: Interned<String>,
+    pub compiler: Compiler,
+}
+
+impl Step for RustdocJSNotStd {
+    type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/test/rustdoc-js")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        let compiler = run.builder.compiler(run.builder.top_stage, run.host);
+        run.builder.ensure(RustdocJSNotStd {
+            host: run.host,
+            target: run.target,
+            compiler,
+        });
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        if builder.config.nodejs.is_some() {
+            builder.ensure(Compiletest {
+                compiler: self.compiler,
+                target: self.target,
+                mode: "js-doc-test",
+                suite: "rustdoc-js",
+                path: None,
+                compare_mode: None,
+            });
         } else {
             builder.info(
                 "No nodejs found, skipping \"src/test/rustdoc-js\" tests"
@@ -990,12 +1033,13 @@ fn run(self, builder: &Builder<'_>) {
             .arg(builder.sysroot_libdir(compiler, target));
         cmd.arg("--rustc-path").arg(builder.rustc(compiler));
 
-        let is_rustdoc_ui = suite.ends_with("rustdoc-ui");
+        let is_rustdoc = suite.ends_with("rustdoc-ui") || suite.ends_with("rustdoc-js");
 
         // Avoid depending on rustdoc when we don't need it.
         if mode == "rustdoc"
             || (mode == "run-make" && suite.ends_with("fulldeps"))
-            || (mode == "ui" && is_rustdoc_ui)
+            || (mode == "ui" && is_rustdoc)
+            || mode == "js-doc-test"
         {
             cmd.arg("--rustdoc-path")
                 .arg(builder.rustdoc(compiler.host));
@@ -1029,12 +1073,12 @@ fn run(self, builder: &Builder<'_>) {
             cmd.arg("--nodejs").arg(nodejs);
         }
 
-        let mut flags = if is_rustdoc_ui {
+        let mut flags = if is_rustdoc {
             Vec::new()
         } else {
             vec!["-Crpath".to_string()]
         };
-        if !is_rustdoc_ui {
+        if !is_rustdoc {
             if builder.config.rust_optimize_tests {
                 flags.push("-O".to_string());
             }
index 74325a69e15ef0f57db4d60376ff0a89dfc02162..9bce142b483f22f06c996aa8269a20eb19c7d59b 100644 (file)
@@ -489,7 +489,7 @@ fn from(boxed: Box<T>) -> Self {
 }
 
 #[stable(feature = "box_from_slice", since = "1.17.0")]
-impl<'a, T: Copy> From<&'a [T]> for Box<[T]> {
+impl<T: Copy> From<&[T]> for Box<[T]> {
     /// Converts a `&[T]` into a `Box<[T]>`
     ///
     /// This conversion allocates on the heap
@@ -503,7 +503,7 @@ impl<'a, T: Copy> From<&'a [T]> for Box<[T]> {
     ///
     /// println!("{:?}", boxed_slice);
     /// ```
-    fn from(slice: &'a [T]) -> Box<[T]> {
+    fn from(slice: &[T]) -> Box<[T]> {
         let mut boxed = unsafe { RawVec::with_capacity(slice.len()).into_box() };
         boxed.copy_from_slice(slice);
         boxed
@@ -511,7 +511,7 @@ fn from(slice: &'a [T]) -> Box<[T]> {
 }
 
 #[stable(feature = "box_from_slice", since = "1.17.0")]
-impl<'a> From<&'a str> for Box<str> {
+impl From<&str> for Box<str> {
     /// Converts a `&str` into a `Box<str>`
     ///
     /// This conversion allocates on the heap
@@ -523,7 +523,7 @@ impl<'a> From<&'a str> for Box<str> {
     /// println!("{}", boxed);
     /// ```
     #[inline]
-    fn from(s: &'a str) -> Box<str> {
+    fn from(s: &str) -> Box<str> {
         unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) }
     }
 }
index 12f75d84211e6f03e555b4c7e32e2aabc7c5255c..68eecd97ea11ad1996f42eecbfb3441cb335d249 100644 (file)
@@ -1145,7 +1145,7 @@ fn from(t: T) -> Self {
 }
 
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
-impl<'a, T: Clone> From<&'a [T]> for Rc<[T]> {
+impl<T: Clone> From<&[T]> for Rc<[T]> {
     #[inline]
     fn from(v: &[T]) -> Rc<[T]> {
         <Self as RcFromSlice<T>>::from_slice(v)
@@ -1153,7 +1153,7 @@ fn from(v: &[T]) -> Rc<[T]> {
 }
 
 #[stable(feature = "shared_from_slice", since = "1.21.0")]
-impl<'a> From<&'a str> for Rc<str> {
+impl From<&str> for Rc<str> {
     #[inline]
     fn from(v: &str) -> Rc<str> {
         let rc = Rc::<[u8]>::from(v.as_bytes());
index b714df5d36b6a8866f2ec867401376ef688b89b7..a3e2098695f70c851478c99be85bd59947d51a6d 100644 (file)
@@ -2172,9 +2172,9 @@ fn as_ref(&self) -> &[u8] {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> From<&'a str> for String {
+impl From<&str> for String {
     #[inline]
-    fn from(s: &'a str) -> String {
+    fn from(s: &str) -> String {
         s.to_owned()
     }
 }
index adcd3d84f4832ebd79d53578d6467b567ed3e479..cd62c3e05244c4399693864ee51fef8311b13c14 100644 (file)
@@ -2182,25 +2182,25 @@ fn as_mut(&mut self) -> &mut [T] {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: Clone> From<&'a [T]> for Vec<T> {
+impl<T: Clone> From<&[T]> for Vec<T> {
     #[cfg(not(test))]
-    fn from(s: &'a [T]) -> Vec<T> {
+    fn from(s: &[T]) -> Vec<T> {
         s.to_vec()
     }
     #[cfg(test)]
-    fn from(s: &'a [T]) -> Vec<T> {
+    fn from(s: &[T]) -> Vec<T> {
         crate::slice::to_vec(s)
     }
 }
 
 #[stable(feature = "vec_from_mut", since = "1.19.0")]
-impl<'a, T: Clone> From<&'a mut [T]> for Vec<T> {
+impl<T: Clone> From<&mut [T]> for Vec<T> {
     #[cfg(not(test))]
-    fn from(s: &'a mut [T]) -> Vec<T> {
+    fn from(s: &mut [T]) -> Vec<T> {
         s.to_vec()
     }
     #[cfg(test)]
-    fn from(s: &'a mut [T]) -> Vec<T> {
+    fn from(s: &mut [T]) -> Vec<T> {
         crate::slice::to_vec(s)
     }
 }
@@ -2231,8 +2231,8 @@ fn from(v: Vec<T>) -> Box<[T]> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> From<&'a str> for Vec<u8> {
-    fn from(s: &'a str) -> Vec<u8> {
+impl From<&str> for Vec<u8> {
+    fn from(s: &str) -> Vec<u8> {
         From::from(s.as_bytes())
     }
 }
index 9c6ecc4350246ebbfe5165bc5dbda656bca1b5f6..dcd9ce6dad756b669fafdaf60ae750516095805d 100644 (file)
@@ -139,7 +139,7 @@ fn borrow_mut(&mut self) -> &mut [T] {
             }
 
             #[stable(feature = "try_from", since = "1.34.0")]
-            impl<'a, T> TryFrom<&'a [T]> for [T; $N] where T: Copy {
+            impl<T> TryFrom<&[T]> for [T; $N] where T: Copy {
                 type Error = TryFromSliceError;
 
                 fn try_from(slice: &[T]) -> Result<[T; $N], TryFromSliceError> {
index 81fcdeee12d29e96614069f3b52e9ae79c2b8790..94bed3708369a6999699553eb024a8c0aa465578 100644 (file)
@@ -1004,26 +1004,26 @@ fn cmp(&self, _: &!) -> Ordering {
     // & pointers
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<&'b B> for &'a A where A: PartialEq<B> {
+    impl<A: ?Sized, B: ?Sized> PartialEq<&B> for &A where A: PartialEq<B> {
         #[inline]
-        fn eq(&self, other: & &'b B) -> bool { PartialEq::eq(*self, *other) }
+        fn eq(&self, other: & &B) -> bool { PartialEq::eq(*self, *other) }
         #[inline]
-        fn ne(&self, other: & &'b B) -> bool { PartialEq::ne(*self, *other) }
+        fn ne(&self, other: & &B) -> bool { PartialEq::ne(*self, *other) }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<'a, 'b, A: ?Sized, B: ?Sized> PartialOrd<&'b B> for &'a A where A: PartialOrd<B> {
+    impl<A: ?Sized, B: ?Sized> PartialOrd<&B> for &A where A: PartialOrd<B> {
         #[inline]
-        fn partial_cmp(&self, other: &&'b B) -> Option<Ordering> {
+        fn partial_cmp(&self, other: &&B) -> Option<Ordering> {
             PartialOrd::partial_cmp(*self, *other)
         }
         #[inline]
-        fn lt(&self, other: & &'b B) -> bool { PartialOrd::lt(*self, *other) }
+        fn lt(&self, other: & &B) -> bool { PartialOrd::lt(*self, *other) }
         #[inline]
-        fn le(&self, other: & &'b B) -> bool { PartialOrd::le(*self, *other) }
+        fn le(&self, other: & &B) -> bool { PartialOrd::le(*self, *other) }
         #[inline]
-        fn ge(&self, other: & &'b B) -> bool { PartialOrd::ge(*self, *other) }
+        fn ge(&self, other: & &B) -> bool { PartialOrd::ge(*self, *other) }
         #[inline]
-        fn gt(&self, other: & &'b B) -> bool { PartialOrd::gt(*self, *other) }
+        fn gt(&self, other: & &B) -> bool { PartialOrd::gt(*self, *other) }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
     impl<A: ?Sized> Ord for &A where A: Ord {
@@ -1036,26 +1036,26 @@ impl<A: ?Sized> Eq for &A where A: Eq {}
     // &mut pointers
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<&'b mut B> for &'a mut A where A: PartialEq<B> {
+    impl<A: ?Sized, B: ?Sized> PartialEq<&mut B> for &mut A where A: PartialEq<B> {
         #[inline]
-        fn eq(&self, other: &&'b mut B) -> bool { PartialEq::eq(*self, *other) }
+        fn eq(&self, other: &&mut B) -> bool { PartialEq::eq(*self, *other) }
         #[inline]
-        fn ne(&self, other: &&'b mut B) -> bool { PartialEq::ne(*self, *other) }
+        fn ne(&self, other: &&mut B) -> bool { PartialEq::ne(*self, *other) }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<'a, 'b, A: ?Sized, B: ?Sized> PartialOrd<&'b mut B> for &'a mut A where A: PartialOrd<B> {
+    impl<A: ?Sized, B: ?Sized> PartialOrd<&mut B> for &mut A where A: PartialOrd<B> {
         #[inline]
-        fn partial_cmp(&self, other: &&'b mut B) -> Option<Ordering> {
+        fn partial_cmp(&self, other: &&mut B) -> Option<Ordering> {
             PartialOrd::partial_cmp(*self, *other)
         }
         #[inline]
-        fn lt(&self, other: &&'b mut B) -> bool { PartialOrd::lt(*self, *other) }
+        fn lt(&self, other: &&mut B) -> bool { PartialOrd::lt(*self, *other) }
         #[inline]
-        fn le(&self, other: &&'b mut B) -> bool { PartialOrd::le(*self, *other) }
+        fn le(&self, other: &&mut B) -> bool { PartialOrd::le(*self, *other) }
         #[inline]
-        fn ge(&self, other: &&'b mut B) -> bool { PartialOrd::ge(*self, *other) }
+        fn ge(&self, other: &&mut B) -> bool { PartialOrd::ge(*self, *other) }
         #[inline]
-        fn gt(&self, other: &&'b mut B) -> bool { PartialOrd::gt(*self, *other) }
+        fn gt(&self, other: &&mut B) -> bool { PartialOrd::gt(*self, *other) }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
     impl<A: ?Sized> Ord for &mut A where A: Ord {
@@ -1066,18 +1066,18 @@ fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(*self, *other) }
     impl<A: ?Sized> Eq for &mut A where A: Eq {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<&'b mut B> for &'a A where A: PartialEq<B> {
+    impl<A: ?Sized, B: ?Sized> PartialEq<&mut B> for &A where A: PartialEq<B> {
         #[inline]
-        fn eq(&self, other: &&'b mut B) -> bool { PartialEq::eq(*self, *other) }
+        fn eq(&self, other: &&mut B) -> bool { PartialEq::eq(*self, *other) }
         #[inline]
-        fn ne(&self, other: &&'b mut B) -> bool { PartialEq::ne(*self, *other) }
+        fn ne(&self, other: &&mut B) -> bool { PartialEq::ne(*self, *other) }
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<&'b B> for &'a mut A where A: PartialEq<B> {
+    impl<A: ?Sized, B: ?Sized> PartialEq<&B> for &mut A where A: PartialEq<B> {
         #[inline]
-        fn eq(&self, other: &&'b B) -> bool { PartialEq::eq(*self, *other) }
+        fn eq(&self, other: &&B) -> bool { PartialEq::eq(*self, *other) }
         #[inline]
-        fn ne(&self, other: &&'b B) -> bool { PartialEq::ne(*self, *other) }
+        fn ne(&self, other: &&B) -> bool { PartialEq::ne(*self, *other) }
     }
 }
index 5ecfa9cde032e67b84d275dbdffbb8bb3dfdff24..774d648558b48ebd80f30dc519b4f253c7e619c1 100644 (file)
@@ -361,11 +361,17 @@ pub trait From<T>: Sized {
 /// An attempted conversion that consumes `self`, which may or may not be
 /// expensive.
 ///
-/// Library authors should not directly implement this trait, but should prefer
-/// implementing the [`TryFrom`] trait, which offers greater flexibility and
-/// provides an equivalent `TryInto` implementation for free, thanks to a
-/// blanket implementation in the standard library. For more information on this,
-/// see the documentation for [`Into`].
+/// Library authors should usually not directly implement this trait,
+/// but should prefer implementing the [`TryFrom`] trait, which offers
+/// greater flexibility and provides an equivalent `TryInto`
+/// implementation for free, thanks to a blanket implementation in the
+/// standard library. For more information on this, see the
+/// documentation for [`Into`].
+///
+/// # Implementing `TryInto`
+///
+/// This suffers the same restrictions and reasoning as implementing
+/// [`Into`], see there for details.
 ///
 /// [`TryFrom`]: trait.TryFrom.html
 /// [`Into`]: trait.Into.html
@@ -380,7 +386,55 @@ pub trait TryInto<T>: Sized {
     fn try_into(self) -> Result<T, Self::Error>;
 }
 
-/// Attempt to construct `Self` via a conversion.
+/// Simple and safe type conversions that may fail in a controlled
+/// way under some circumstances. It is the reciprocal of [`TryInto`].
+///
+/// This is useful when you are doing a type conversion that may
+/// trivially succeed but may also need special handling.
+/// For example, there is no way to convert an `i64` into an `i32`
+/// using the [`From`] trait, because an `i64` may contain a value
+/// that an `i32` cannot represent and so the conversion would lose data.
+/// This might be handled by truncating the `i64` to an `i32` (essentially
+/// giving the `i64`'s value modulo `i32::MAX`) or by simply returning
+/// `i32::MAX`, or by some other method.  The `From` trait is intended
+/// for perfect conversions, so the `TryFrom` trait informs the
+/// programmer when a type conversion could go bad and lets them
+/// decide how to handle it.
+///
+/// # Generic Implementations
+///
+/// - `TryFrom<T> for U` implies [`TryInto<U>`]` for T`
+/// - [`try_from`] is reflexive, which means that `TryFrom<T> for T`
+/// is implemented and cannot fail -- the associated `Error` type for
+/// calling `T::try_from()` on a value of type `T` is `Infallible`.
+/// When the `!` type is stablized `Infallible` and `!` will be
+/// equivalent.
+///
+/// # Examples
+///
+/// As described, [`i32`] implements `TryFrom<i64>`:
+///
+/// ```
+/// use std::convert::TryFrom;
+///
+/// let big_number = 1_000_000_000_000i64;
+/// // Silently truncates `big_number`, requires detecting
+/// // and handling the truncation after the fact.
+/// let smaller_number = big_number as i32;
+/// assert_eq!(smaller_number, -727379968);
+///
+/// // Returns an error because `big_number` is too big to
+/// // fit in an `i32`.
+/// let try_smaller_number = i32::try_from(big_number);
+/// assert!(try_smaller_number.is_err());
+///
+/// // Returns `Ok(3)`.
+/// let try_successful_smaller_number = i32::try_from(3);
+/// assert!(try_successful_smaller_number.is_ok());
+/// ```
+///
+/// [`try_from`]: trait.TryFrom.html#tymethod.try_from
+/// [`TryInto`]: trait.TryInto.html
 #[stable(feature = "try_from", since = "1.34.0")]
 pub trait TryFrom<T>: Sized {
     /// The type returned in the event of a conversion error.
index faca785e488c39cc32f5239cf5fd6f022600a121..b5c20582986b262368344a8df54b27b495c59f5d 100644 (file)
@@ -37,21 +37,21 @@ fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
         }
 
         #[$attr]
-        impl<'a> $imp<&'a $u> for $t {
+        impl $imp<&$u> for $t {
             type Output = <$t as $imp<$u>>::Output;
 
             #[inline]
-            fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
+            fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
                 $imp::$method(self, *other)
             }
         }
 
         #[$attr]
-        impl<'a, 'b> $imp<&'a $u> for &'b $t {
+        impl $imp<&$u> for &$t {
             type Output = <$t as $imp<$u>>::Output;
 
             #[inline]
-            fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
+            fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
                 $imp::$method(*self, *other)
             }
         }
@@ -67,9 +67,9 @@ macro_rules! forward_ref_op_assign {
     };
     (impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
         #[$attr]
-        impl<'a> $imp<&'a $u> for $t {
+        impl $imp<&$u> for $t {
             #[inline]
-            fn $method(&mut self, other: &'a $u) {
+            fn $method(&mut self, other: &$u) {
                 $imp::$method(self, *other);
             }
         }
index 98b5fcd3ee4f06fbcc4eeb22d393dcfda16d7584..d93cfbc2a28acd571b4a621af2aa2875ffc58844 100644 (file)
@@ -1979,10 +1979,10 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 ```
 use std::convert::TryInto;
 
-fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
+fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
     let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
     *input = rest;
-    ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
+    ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
@@ -2020,10 +2020,10 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 ```
 use std::convert::TryInto;
 
-fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
+fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
     let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
     *input = rest;
-    ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
+    ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
@@ -3695,10 +3695,10 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 ```
 use std::convert::TryInto;
 
-fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
+fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
     let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
     *input = rest;
-    ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
+    ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
@@ -3736,10 +3736,10 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 ```
 use std::convert::TryInto;
 
-fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
+fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
     let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());
     *input = rest;
-    ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())
+    ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
@@ -4442,6 +4442,9 @@ macro_rules! try_from_unbounded {
         impl TryFrom<$source> for $target {
             type Error = TryFromIntError;
 
+            /// Try to create the target number type from a source
+            /// number type. This returns an error if the source value
+            /// is outside of the range of the target type.
             #[inline]
             fn try_from(value: $source) -> Result<Self, Self::Error> {
                 Ok(value as $target)
@@ -4457,6 +4460,9 @@ macro_rules! try_from_lower_bounded {
         impl TryFrom<$source> for $target {
             type Error = TryFromIntError;
 
+            /// Try to create the target number type from a source
+            /// number type. This returns an error if the source value
+            /// is outside of the range of the target type.
             #[inline]
             fn try_from(u: $source) -> Result<$target, TryFromIntError> {
                 if u >= 0 {
@@ -4476,6 +4482,9 @@ macro_rules! try_from_upper_bounded {
         impl TryFrom<$source> for $target {
             type Error = TryFromIntError;
 
+            /// Try to create the target number type from a source
+            /// number type. This returns an error if the source value
+            /// is outside of the range of the target type.
             #[inline]
             fn try_from(u: $source) -> Result<$target, TryFromIntError> {
                 if u > (<$target>::max_value() as $source) {
@@ -4495,6 +4504,9 @@ macro_rules! try_from_both_bounded {
         impl TryFrom<$source> for $target {
             type Error = TryFromIntError;
 
+            /// Try to create the target number type from a source
+            /// number type. This returns an error if the source value
+            /// is outside of the range of the target type.
             #[inline]
             fn try_from(u: $source) -> Result<$target, TryFromIntError> {
                 let min = <$target>::min_value() as $source;
index 998b597d5e113a12a63e54436f5ec0e1d98e9211..81a8d001dd9cb4237d256eb9b470c5ece38012c7 100644 (file)
 /// Used as a [slicing index], `RangeFull` produces the full array as a slice.
 ///
 /// ```
-/// let arr = [0, 1, 2, 3];
-/// assert_eq!(arr[ .. ], [0,1,2,3]);  // RangeFull
-/// assert_eq!(arr[ ..3], [0,1,2  ]);
-/// assert_eq!(arr[1.. ], [  1,2,3]);
-/// assert_eq!(arr[1..3], [  1,2  ]);
+/// let arr = [0, 1, 2, 3, 4];
+/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);  // RangeFull
+/// assert_eq!(arr[ .. 3], [0,1,2    ]);
+/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);
+/// assert_eq!(arr[1..  ], [  1,2,3,4]);
+/// assert_eq!(arr[1.. 3], [  1,2    ]);
+/// assert_eq!(arr[1..=3], [  1,2,3  ]);
 /// ```
 ///
 /// [`IntoIterator`]: ../iter/trait.Iterator.html
@@ -60,11 +62,13 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 /// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 });
 /// assert_eq!(3 + 4 + 5, (3..6).sum());
 ///
-/// let arr = ['a', 'b', 'c', 'd'];
-/// assert_eq!(arr[ .. ], ['a', 'b', 'c', 'd']);
-/// assert_eq!(arr[ ..3], ['a', 'b', 'c',    ]);
-/// assert_eq!(arr[1.. ], [     'b', 'c', 'd']);
-/// assert_eq!(arr[1..3], [     'b', 'c'     ]);  // Range
+/// let arr = [0, 1, 2, 3, 4];
+/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);
+/// assert_eq!(arr[ .. 3], [0,1,2    ]);
+/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);
+/// assert_eq!(arr[1..  ], [  1,2,3,4]);
+/// assert_eq!(arr[1.. 3], [  1,2    ]);  // Range
+/// assert_eq!(arr[1..=3], [  1,2,3  ]);
 /// ```
 #[doc(alias = "..")]
 #[derive(Clone, PartialEq, Eq, Hash)]  // not Copy -- see #27186
@@ -160,11 +164,13 @@ pub fn is_empty(&self) -> bool {
 /// assert_eq!((2..), std::ops::RangeFrom { start: 2 });
 /// assert_eq!(2 + 3 + 4, (2..).take(3).sum());
 ///
-/// let arr = [0, 1, 2, 3];
-/// assert_eq!(arr[ .. ], [0,1,2,3]);
-/// assert_eq!(arr[ ..3], [0,1,2  ]);
-/// assert_eq!(arr[1.. ], [  1,2,3]);  // RangeFrom
-/// assert_eq!(arr[1..3], [  1,2  ]);
+/// let arr = [0, 1, 2, 3, 4];
+/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);
+/// assert_eq!(arr[ .. 3], [0,1,2    ]);
+/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);
+/// assert_eq!(arr[1..  ], [  1,2,3,4]);  // RangeFrom
+/// assert_eq!(arr[1.. 3], [  1,2    ]);
+/// assert_eq!(arr[1..=3], [  1,2,3  ]);
 /// ```
 ///
 /// [`Iterator`]: ../iter/trait.IntoIterator.html
@@ -240,11 +246,13 @@ pub fn contains<U>(&self, item: &U) -> bool
 /// elements before the index indicated by `end`.
 ///
 /// ```
-/// let arr = [0, 1, 2, 3];
-/// assert_eq!(arr[ .. ], [0,1,2,3]);
-/// assert_eq!(arr[ ..3], [0,1,2  ]);  // RangeTo
-/// assert_eq!(arr[1.. ], [  1,2,3]);
-/// assert_eq!(arr[1..3], [  1,2  ]);
+/// let arr = [0, 1, 2, 3, 4];
+/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);
+/// assert_eq!(arr[ .. 3], [0,1,2    ]);  // RangeTo
+/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);
+/// assert_eq!(arr[1..  ], [  1,2,3,4]);
+/// assert_eq!(arr[1.. 3], [  1,2    ]);
+/// assert_eq!(arr[1..=3], [  1,2,3  ]);
 /// ```
 ///
 /// [`IntoIterator`]: ../iter/trait.Iterator.html
@@ -312,9 +320,13 @@ pub fn contains<U>(&self, item: &U) -> bool
 /// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5));
 /// assert_eq!(3 + 4 + 5, (3..=5).sum());
 ///
-/// let arr = [0, 1, 2, 3];
-/// assert_eq!(arr[ ..=2], [0,1,2  ]);
-/// assert_eq!(arr[1..=2], [  1,2  ]);  // RangeInclusive
+/// let arr = [0, 1, 2, 3, 4];
+/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);
+/// assert_eq!(arr[ .. 3], [0,1,2    ]);
+/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);
+/// assert_eq!(arr[1..  ], [  1,2,3,4]);
+/// assert_eq!(arr[1.. 3], [  1,2    ]);
+/// assert_eq!(arr[1..=3], [  1,2,3  ]);  // RangeInclusive
 /// ```
 #[doc(alias = "..=")]
 #[derive(Clone)]  // not Copy -- see #27186
@@ -569,9 +581,13 @@ pub(crate) fn compute_is_empty(&mut self) {
 /// array elements up to and including the index indicated by `end`.
 ///
 /// ```
-/// let arr = [0, 1, 2, 3];
-/// assert_eq!(arr[ ..=2], [0,1,2  ]);  // RangeToInclusive
-/// assert_eq!(arr[1..=2], [  1,2  ]);
+/// let arr = [0, 1, 2, 3, 4];
+/// assert_eq!(arr[ ..  ], [0,1,2,3,4]);
+/// assert_eq!(arr[ .. 3], [0,1,2    ]);
+/// assert_eq!(arr[ ..=3], [0,1,2,3  ]);  // RangeToInclusive
+/// assert_eq!(arr[1..  ], [  1,2,3,4]);
+/// assert_eq!(arr[1.. 3], [  1,2    ]);
+/// assert_eq!(arr[1..=3], [  1,2,3  ]);
 /// ```
 ///
 /// [`IntoIterator`]: ../iter/trait.Iterator.html
@@ -676,7 +692,7 @@ pub enum Bound<T> {
 
 #[stable(feature = "collections_range", since = "1.28.0")]
 /// `RangeBounds` is implemented by Rust's built-in range types, produced
-/// by range syntax like `..`, `a..`, `..b` or `c..d`.
+/// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`.
 pub trait RangeBounds<T: ?Sized> {
     /// Start index bound.
     ///
index 53d41976030685c74620b76c1ee565b2dfef414c..d288ca449dff3116579f923e4eaba4f503beefb0 100644 (file)
@@ -2837,15 +2837,15 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 #[unstable(feature = "ptr_internals", issue = "0")]
-impl<'a, T: ?Sized> From<&'a mut T> for Unique<T> {
-    fn from(reference: &'a mut T) -> Self {
+impl<T: ?Sized> From<&mut T> for Unique<T> {
+    fn from(reference: &mut T) -> Self {
         unsafe { Unique { pointer: reference as *mut T, _marker: PhantomData } }
     }
 }
 
 #[unstable(feature = "ptr_internals", issue = "0")]
-impl<'a, T: ?Sized> From<&'a T> for Unique<T> {
-    fn from(reference: &'a T) -> Self {
+impl<T: ?Sized> From<&T> for Unique<T> {
+    fn from(reference: &T) -> Self {
         unsafe { Unique { pointer: reference as *const T, _marker: PhantomData } }
     }
 }
@@ -3049,17 +3049,17 @@ fn from(unique: Unique<T>) -> Self {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
+impl<T: ?Sized> From<&mut T> for NonNull<T> {
     #[inline]
-    fn from(reference: &'a mut T) -> Self {
+    fn from(reference: &mut T) -> Self {
         unsafe { NonNull { pointer: reference as *mut T } }
     }
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<'a, T: ?Sized> From<&'a T> for NonNull<T> {
+impl<T: ?Sized> From<&T> for NonNull<T> {
     #[inline]
-    fn from(reference: &'a T) -> Self {
+    fn from(reference: &T) -> Self {
         unsafe { NonNull { pointer: reference as *const T } }
     }
 }
index 92d29f6ee8a30c83ba9ec50c9cbf7983c61fc22b..2bd6b536301e8de10241cbbbf0e74a7b2777ad8a 100644 (file)
@@ -1200,7 +1200,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
     /// let res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32|
     ///     x.checked_add(1).ok_or("Overflow!")
     /// ).collect();
-    /// assert!(res == Ok(vec![2, 3]));
+    /// assert_eq!(res, Ok(vec![2, 3]));
     /// ```
     #[inline]
     fn from_iter<I: IntoIterator<Item=Result<A, E>>>(iter: I) -> Result<V, E> {
index 6d9494ec289aaa3bcf13e53f8396f51dfc59bf3a..10fcf8b76ccb4bd7c8e47a8d842bcd03feecc678 100644 (file)
@@ -3,146 +3,146 @@ fn test_format_int() {
     // Formatting integers should select the right implementation based off
     // the type of the argument. Also, hex/octal/binary should be defined
     // for integers, but they shouldn't emit the negative sign.
-    assert!(format!("{}", 1isize) == "1");
-    assert!(format!("{}", 1i8) == "1");
-    assert!(format!("{}", 1i16) == "1");
-    assert!(format!("{}", 1i32) == "1");
-    assert!(format!("{}", 1i64) == "1");
-    assert!(format!("{}", -1isize) == "-1");
-    assert!(format!("{}", -1i8) == "-1");
-    assert!(format!("{}", -1i16) == "-1");
-    assert!(format!("{}", -1i32) == "-1");
-    assert!(format!("{}", -1i64) == "-1");
-    assert!(format!("{:?}", 1isize) == "1");
-    assert!(format!("{:?}", 1i8) == "1");
-    assert!(format!("{:?}", 1i16) == "1");
-    assert!(format!("{:?}", 1i32) == "1");
-    assert!(format!("{:?}", 1i64) == "1");
-    assert!(format!("{:b}", 1isize) == "1");
-    assert!(format!("{:b}", 1i8) == "1");
-    assert!(format!("{:b}", 1i16) == "1");
-    assert!(format!("{:b}", 1i32) == "1");
-    assert!(format!("{:b}", 1i64) == "1");
-    assert!(format!("{:x}", 1isize) == "1");
-    assert!(format!("{:x}", 1i8) == "1");
-    assert!(format!("{:x}", 1i16) == "1");
-    assert!(format!("{:x}", 1i32) == "1");
-    assert!(format!("{:x}", 1i64) == "1");
-    assert!(format!("{:X}", 1isize) == "1");
-    assert!(format!("{:X}", 1i8) == "1");
-    assert!(format!("{:X}", 1i16) == "1");
-    assert!(format!("{:X}", 1i32) == "1");
-    assert!(format!("{:X}", 1i64) == "1");
-    assert!(format!("{:o}", 1isize) == "1");
-    assert!(format!("{:o}", 1i8) == "1");
-    assert!(format!("{:o}", 1i16) == "1");
-    assert!(format!("{:o}", 1i32) == "1");
-    assert!(format!("{:o}", 1i64) == "1");
+    assert_eq!(format!("{}", 1isize), "1");
+    assert_eq!(format!("{}", 1i8), "1");
+    assert_eq!(format!("{}", 1i16), "1");
+    assert_eq!(format!("{}", 1i32), "1");
+    assert_eq!(format!("{}", 1i64), "1");
+    assert_eq!(format!("{}", -1isize), "-1");
+    assert_eq!(format!("{}", -1i8), "-1");
+    assert_eq!(format!("{}", -1i16), "-1");
+    assert_eq!(format!("{}", -1i32), "-1");
+    assert_eq!(format!("{}", -1i64), "-1");
+    assert_eq!(format!("{:?}", 1isize), "1");
+    assert_eq!(format!("{:?}", 1i8), "1");
+    assert_eq!(format!("{:?}", 1i16), "1");
+    assert_eq!(format!("{:?}", 1i32), "1");
+    assert_eq!(format!("{:?}", 1i64), "1");
+    assert_eq!(format!("{:b}", 1isize), "1");
+    assert_eq!(format!("{:b}", 1i8), "1");
+    assert_eq!(format!("{:b}", 1i16), "1");
+    assert_eq!(format!("{:b}", 1i32), "1");
+    assert_eq!(format!("{:b}", 1i64), "1");
+    assert_eq!(format!("{:x}", 1isize), "1");
+    assert_eq!(format!("{:x}", 1i8), "1");
+    assert_eq!(format!("{:x}", 1i16), "1");
+    assert_eq!(format!("{:x}", 1i32), "1");
+    assert_eq!(format!("{:x}", 1i64), "1");
+    assert_eq!(format!("{:X}", 1isize), "1");
+    assert_eq!(format!("{:X}", 1i8), "1");
+    assert_eq!(format!("{:X}", 1i16), "1");
+    assert_eq!(format!("{:X}", 1i32), "1");
+    assert_eq!(format!("{:X}", 1i64), "1");
+    assert_eq!(format!("{:o}", 1isize), "1");
+    assert_eq!(format!("{:o}", 1i8), "1");
+    assert_eq!(format!("{:o}", 1i16), "1");
+    assert_eq!(format!("{:o}", 1i32), "1");
+    assert_eq!(format!("{:o}", 1i64), "1");
 
-    assert!(format!("{}", 1usize) == "1");
-    assert!(format!("{}", 1u8) == "1");
-    assert!(format!("{}", 1u16) == "1");
-    assert!(format!("{}", 1u32) == "1");
-    assert!(format!("{}", 1u64) == "1");
-    assert!(format!("{:?}", 1usize) == "1");
-    assert!(format!("{:?}", 1u8) == "1");
-    assert!(format!("{:?}", 1u16) == "1");
-    assert!(format!("{:?}", 1u32) == "1");
-    assert!(format!("{:?}", 1u64) == "1");
-    assert!(format!("{:b}", 1usize) == "1");
-    assert!(format!("{:b}", 1u8) == "1");
-    assert!(format!("{:b}", 1u16) == "1");
-    assert!(format!("{:b}", 1u32) == "1");
-    assert!(format!("{:b}", 1u64) == "1");
-    assert!(format!("{:x}", 1usize) == "1");
-    assert!(format!("{:x}", 1u8) == "1");
-    assert!(format!("{:x}", 1u16) == "1");
-    assert!(format!("{:x}", 1u32) == "1");
-    assert!(format!("{:x}", 1u64) == "1");
-    assert!(format!("{:X}", 1usize) == "1");
-    assert!(format!("{:X}", 1u8) == "1");
-    assert!(format!("{:X}", 1u16) == "1");
-    assert!(format!("{:X}", 1u32) == "1");
-    assert!(format!("{:X}", 1u64) == "1");
-    assert!(format!("{:o}", 1usize) == "1");
-    assert!(format!("{:o}", 1u8) == "1");
-    assert!(format!("{:o}", 1u16) == "1");
-    assert!(format!("{:o}", 1u32) == "1");
-    assert!(format!("{:o}", 1u64) == "1");
+    assert_eq!(format!("{}", 1usize), "1");
+    assert_eq!(format!("{}", 1u8), "1");
+    assert_eq!(format!("{}", 1u16), "1");
+    assert_eq!(format!("{}", 1u32), "1");
+    assert_eq!(format!("{}", 1u64), "1");
+    assert_eq!(format!("{:?}", 1usize), "1");
+    assert_eq!(format!("{:?}", 1u8), "1");
+    assert_eq!(format!("{:?}", 1u16), "1");
+    assert_eq!(format!("{:?}", 1u32), "1");
+    assert_eq!(format!("{:?}", 1u64), "1");
+    assert_eq!(format!("{:b}", 1usize), "1");
+    assert_eq!(format!("{:b}", 1u8), "1");
+    assert_eq!(format!("{:b}", 1u16), "1");
+    assert_eq!(format!("{:b}", 1u32), "1");
+    assert_eq!(format!("{:b}", 1u64), "1");
+    assert_eq!(format!("{:x}", 1usize), "1");
+    assert_eq!(format!("{:x}", 1u8), "1");
+    assert_eq!(format!("{:x}", 1u16), "1");
+    assert_eq!(format!("{:x}", 1u32), "1");
+    assert_eq!(format!("{:x}", 1u64), "1");
+    assert_eq!(format!("{:X}", 1usize), "1");
+    assert_eq!(format!("{:X}", 1u8), "1");
+    assert_eq!(format!("{:X}", 1u16), "1");
+    assert_eq!(format!("{:X}", 1u32), "1");
+    assert_eq!(format!("{:X}", 1u64), "1");
+    assert_eq!(format!("{:o}", 1usize), "1");
+    assert_eq!(format!("{:o}", 1u8), "1");
+    assert_eq!(format!("{:o}", 1u16), "1");
+    assert_eq!(format!("{:o}", 1u32), "1");
+    assert_eq!(format!("{:o}", 1u64), "1");
 
     // Test a larger number
-    assert!(format!("{:b}", 55) == "110111");
-    assert!(format!("{:o}", 55) == "67");
-    assert!(format!("{}", 55) == "55");
-    assert!(format!("{:x}", 55) == "37");
-    assert!(format!("{:X}", 55) == "37");
+    assert_eq!(format!("{:b}", 55), "110111");
+    assert_eq!(format!("{:o}", 55), "67");
+    assert_eq!(format!("{}", 55), "55");
+    assert_eq!(format!("{:x}", 55), "37");
+    assert_eq!(format!("{:X}", 55), "37");
 }
 
 #[test]
 fn test_format_int_zero() {
-    assert!(format!("{}", 0) == "0");
-    assert!(format!("{:?}", 0) == "0");
-    assert!(format!("{:b}", 0) == "0");
-    assert!(format!("{:o}", 0) == "0");
-    assert!(format!("{:x}", 0) == "0");
-    assert!(format!("{:X}", 0) == "0");
+    assert_eq!(format!("{}", 0), "0");
+    assert_eq!(format!("{:?}", 0), "0");
+    assert_eq!(format!("{:b}", 0), "0");
+    assert_eq!(format!("{:o}", 0), "0");
+    assert_eq!(format!("{:x}", 0), "0");
+    assert_eq!(format!("{:X}", 0), "0");
 
-    assert!(format!("{}", 0u32) == "0");
-    assert!(format!("{:?}", 0u32) == "0");
-    assert!(format!("{:b}", 0u32) == "0");
-    assert!(format!("{:o}", 0u32) == "0");
-    assert!(format!("{:x}", 0u32) == "0");
-    assert!(format!("{:X}", 0u32) == "0");
+    assert_eq!(format!("{}", 0u32), "0");
+    assert_eq!(format!("{:?}", 0u32), "0");
+    assert_eq!(format!("{:b}", 0u32), "0");
+    assert_eq!(format!("{:o}", 0u32), "0");
+    assert_eq!(format!("{:x}", 0u32), "0");
+    assert_eq!(format!("{:X}", 0u32), "0");
 }
 
 #[test]
 fn test_format_int_flags() {
-    assert!(format!("{:3}", 1) == "  1");
-    assert!(format!("{:>3}", 1) == "  1");
-    assert!(format!("{:>+3}", 1) == " +1");
-    assert!(format!("{:<3}", 1) == "1  ");
-    assert!(format!("{:#}", 1) == "1");
-    assert!(format!("{:#x}", 10) == "0xa");
-    assert!(format!("{:#X}", 10) == "0xA");
-    assert!(format!("{:#5x}", 10) == "  0xa");
-    assert!(format!("{:#o}", 10) == "0o12");
-    assert!(format!("{:08x}", 10) == "0000000a");
-    assert!(format!("{:8x}", 10) == "       a");
-    assert!(format!("{:<8x}", 10) == "a       ");
-    assert!(format!("{:>8x}", 10) == "       a");
-    assert!(format!("{:#08x}", 10) == "0x00000a");
-    assert!(format!("{:08}", -10) == "-0000010");
-    assert!(format!("{:x}", !0u8) == "ff");
-    assert!(format!("{:X}", !0u8) == "FF");
-    assert!(format!("{:b}", !0u8) == "11111111");
-    assert!(format!("{:o}", !0u8) == "377");
-    assert!(format!("{:#x}", !0u8) == "0xff");
-    assert!(format!("{:#X}", !0u8) == "0xFF");
-    assert!(format!("{:#b}", !0u8) == "0b11111111");
-    assert!(format!("{:#o}", !0u8) == "0o377");
+    assert_eq!(format!("{:3}", 1), "  1");
+    assert_eq!(format!("{:>3}", 1), "  1");
+    assert_eq!(format!("{:>+3}", 1), " +1");
+    assert_eq!(format!("{:<3}", 1), "1  ");
+    assert_eq!(format!("{:#}", 1), "1");
+    assert_eq!(format!("{:#x}", 10), "0xa");
+    assert_eq!(format!("{:#X}", 10), "0xA");
+    assert_eq!(format!("{:#5x}", 10), "  0xa");
+    assert_eq!(format!("{:#o}", 10), "0o12");
+    assert_eq!(format!("{:08x}", 10), "0000000a");
+    assert_eq!(format!("{:8x}", 10), "       a");
+    assert_eq!(format!("{:<8x}", 10), "a       ");
+    assert_eq!(format!("{:>8x}", 10), "       a");
+    assert_eq!(format!("{:#08x}", 10), "0x00000a");
+    assert_eq!(format!("{:08}", -10), "-0000010");
+    assert_eq!(format!("{:x}", !0u8), "ff");
+    assert_eq!(format!("{:X}", !0u8), "FF");
+    assert_eq!(format!("{:b}", !0u8), "11111111");
+    assert_eq!(format!("{:o}", !0u8), "377");
+    assert_eq!(format!("{:#x}", !0u8), "0xff");
+    assert_eq!(format!("{:#X}", !0u8), "0xFF");
+    assert_eq!(format!("{:#b}", !0u8), "0b11111111");
+    assert_eq!(format!("{:#o}", !0u8), "0o377");
 }
 
 #[test]
 fn test_format_int_sign_padding() {
-    assert!(format!("{:+5}", 1) == "   +1");
-    assert!(format!("{:+5}", -1) == "   -1");
-    assert!(format!("{:05}", 1) == "00001");
-    assert!(format!("{:05}", -1) == "-0001");
-    assert!(format!("{:+05}", 1) == "+0001");
-    assert!(format!("{:+05}", -1) == "-0001");
+    assert_eq!(format!("{:+5}", 1), "   +1");
+    assert_eq!(format!("{:+5}", -1), "   -1");
+    assert_eq!(format!("{:05}", 1), "00001");
+    assert_eq!(format!("{:05}", -1), "-0001");
+    assert_eq!(format!("{:+05}", 1), "+0001");
+    assert_eq!(format!("{:+05}", -1), "-0001");
 }
 
 #[test]
 fn test_format_int_twos_complement() {
-    use core::{i8, i16, i32, i64};
-    assert!(format!("{}", i8::MIN) == "-128");
-    assert!(format!("{}", i16::MIN) == "-32768");
-    assert!(format!("{}", i32::MIN) == "-2147483648");
-    assert!(format!("{}", i64::MIN) == "-9223372036854775808");
+    use core::{i16, i32, i64, i8};
+    assert_eq!(format!("{}", i8::MIN), "-128");
+    assert_eq!(format!("{}", i16::MIN), "-32768");
+    assert_eq!(format!("{}", i32::MIN), "-2147483648");
+    assert_eq!(format!("{}", i64::MIN), "-9223372036854775808");
 }
 
 #[test]
 fn test_format_debug_hex() {
-    assert!(format!("{:02x?}", b"Foo\0") == "[46, 6f, 6f, 00]");
-    assert!(format!("{:02X?}", b"Foo\0") == "[46, 6F, 6F, 00]");
+    assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]");
+    assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]");
 }
index 655707ff9bd0da0f962192f28c0bd5d0eb690818..ad0ed39185c1c4b19c017de63080a870f566c308 100644 (file)
@@ -386,6 +386,12 @@ pub mod parser {
     "ambiguous associated items"
 }
 
+declare_lint! {
+    pub NESTED_IMPL_TRAIT,
+    Warn,
+    "nested occurrence of `impl Trait` type"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// that are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -457,6 +463,7 @@ fn get_lints(&self) -> LintArray {
             parser::ILL_FORMED_ATTRIBUTE_INPUT,
             DEPRECATED_IN_FUTURE,
             AMBIGUOUS_ASSOCIATED_ITEMS,
+            NESTED_IMPL_TRAIT,
         )
     }
 }
@@ -474,6 +481,7 @@ pub enum BuiltinLintDiagnostics {
     ElidedLifetimesInPaths(usize, Span, bool, Span, String),
     UnknownCrateTypes(Span, String, String),
     UnusedImports(String, Vec<(Span, String)>),
+    NestedImplTrait { outer_impl_trait_span: Span, inner_impl_trait_span: Span },
 }
 
 impl BuiltinLintDiagnostics {
@@ -564,6 +572,12 @@ pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder<'_>) {
                     );
                 }
             }
+            BuiltinLintDiagnostics::NestedImplTrait {
+                outer_impl_trait_span, inner_impl_trait_span
+            } => {
+                db.span_label(outer_impl_trait_span, "outer `impl Trait`");
+                db.span_label(inner_impl_trait_span, "nested `impl Trait` here");
+            }
         }
     }
 }
index b705968ce8aeded42ac39e98f0f190d38a15942e..08b595c5eaa5aa1e7665860ea171e3e1521af6c0 100644 (file)
@@ -1443,16 +1443,6 @@ pub fn allocate_metadata_dep_nodes(self) {
         }
     }
 
-    // This method exercises the `in_scope_traits_map` query for all possible
-    // values so that we have their fingerprints available in the DepGraph.
-    // This is only required as long as we still use the old dependency tracking
-    // which needs to have the fingerprints of all input nodes beforehand.
-    pub fn precompute_in_scope_traits_hashes(self) {
-        for &def_index in self.trait_map.keys() {
-            self.in_scope_traits_map(def_index);
-        }
-    }
-
     pub fn serialize_query_result_cache<E>(self,
                                            encoder: &mut E)
                                            -> Result<(), E::Error>
index cf18b995b61dadbf125a58793b13509dceb10ca6..daccfc9b242f924da3e63444abd4c2c1b029334a 100644 (file)
@@ -1,13 +1,13 @@
 //! # Debug Info Module
 //!
 //! This module serves the purpose of generating debug symbols. We use LLVM's
-//! [source level debugging](http://!llvm.org/docs/SourceLevelDebugging.html)
+//! [source level debugging](https://llvm.org/docs/SourceLevelDebugging.html)
 //! features for generating the debug information. The general principle is
 //! this:
 //!
 //! Given the right metadata in the LLVM IR, the LLVM code generator is able to
 //! create DWARF debug symbols for the given code. The
-//! [metadata](http://!llvm.org/docs/LangRef.html#metadata-type) is structured
+//! [metadata](https://llvm.org/docs/LangRef.html#metadata-type) is structured
 //! much like DWARF *debugging information entries* (DIE), representing type
 //! information such as datatype layout, function signatures, block layout,
 //! variable location and scope information, etc. It is the purpose of this
@@ -15,7 +15,7 @@
 //!
 //! As the exact format of metadata trees may change between different LLVM
 //! versions, we now use LLVM
-//! [DIBuilder](http://!llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html)
+//! [DIBuilder](https://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html)
 //! to create metadata where possible. This will hopefully ease the adaption of
 //! this module to future LLVM versions.
 //!
index 10b448b7fec3f90f752ee8f26c76d7b158aa1977..df971ec5bdb85c9d0740a3afc5eef44f3db05a31 100644 (file)
@@ -12,7 +12,7 @@ crate-type = ["dylib"]
 [dependencies]
 graphviz = { path = "../libgraphviz" }
 log = "0.4"
-rand = "0.5"
+rand = "0.6"
 rustc = { path = "../librustc" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 serialize = { path = "../libserialize" }
index 4295034692958a0bbc8c19720a2519ce4e0c8fcf..255a3899d1183e23b9e5af9c0acd011e5a6997fc 100644 (file)
@@ -21,7 +21,6 @@ pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     }
 
     tcx.allocate_metadata_dep_nodes();
-    tcx.precompute_in_scope_traits_hashes();
 }
 
 type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;
index 1acd3dfc7656a86f36a38d8e20bc1675e2bf03e0..294e23dc6177c74b7eba6a8bc50d8e910766f60f 100644 (file)
@@ -12,7 +12,7 @@ crate-type = ["dylib"]
 log = "0.4"
 rustc-rayon = "0.1.1"
 smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
-scoped-tls = { version = "0.1.1", features = ["nightly"] }
+scoped-tls = "1.0"
 syntax = { path = "../libsyntax" }
 syntax_ext = { path = "../libsyntax_ext" }
 syntax_pos = { path = "../libsyntax_pos" }
index 5e375dcaa068173a416f748edc241d2a5e6a397e..73a32f6d2003a40f2ffadf2ab59436ff0dd5b168 100644 (file)
@@ -353,6 +353,11 @@ macro_rules! register_passes {
             reference: "issue #57593 <https://github.com/rust-lang/rust/issues/57593>",
             edition: None,
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(NESTED_IMPL_TRAIT),
+            reference: "issue #59014 <https://github.com/rust-lang/rust/issues/59014>",
+            edition: None,
+        },
         ]);
 
     // Register renamed and removed lints.
index 01f8cbfbe8e2b2a4d727647966bf8ed412ed73ba..d60a0941b5979048653a32b293a469049daf40a9 100644 (file)
@@ -19,6 +19,7 @@
 use rustc::ty::layout::{Integer, IntegerExt, Size};
 use syntax::attr::{SignedInt, UnsignedInt};
 use rustc::hir::RangeEnd;
+use rustc::mir::interpret::truncate;
 
 use std::mem;
 
@@ -115,14 +116,14 @@ fn simplify_match_pair<'pat>(&mut self,
                     ty::Int(ity) => {
                         // FIXME(49937): refactor these bit manipulations into interpret.
                         let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
-                        let max = !0u128 >> (128 - size.bits());
+                        let max = truncate(u128::max_value(), size);
                         let bias = 1u128 << (size.bits() - 1);
                         (Some((0, max, size)), bias)
                     }
                     ty::Uint(uty) => {
                         // FIXME(49937): refactor these bit manipulations into interpret.
                         let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
-                        let max = !0u128 >> (128 - size.bits());
+                        let max = truncate(u128::max_value(), size);
                         (Some((0, max, size)), 0)
                     }
                     _ => (None, 0),
index f96fc3b897f80bc4e85d40d225f737ae1dd77885..b85429cd3cfdc7963fcb17119ff9ff53dfe35229 100644 (file)
@@ -9,6 +9,7 @@
 use std::mem;
 use syntax::print::pprust;
 use rustc::lint;
+use rustc::lint::builtin::{BuiltinLintDiagnostics, NESTED_IMPL_TRAIT};
 use rustc::session::Session;
 use rustc_data_structures::fx::FxHashMap;
 use syntax::ast::*;
 use errors::Applicability;
 use log::debug;
 
+#[derive(Copy, Clone, Debug)]
+struct OuterImplTrait {
+    span: Span,
+
+    /// rust-lang/rust#57979: a bug in original implementation caused
+    /// us to fail sometimes to record an outer `impl Trait`.
+    /// Therefore, in order to reliably issue a warning (rather than
+    /// an error) in the *precise* places where we are newly injecting
+    /// the diagnostic, we have to distinguish between the places
+    /// where the outer `impl Trait` has always been recorded, versus
+    /// the places where it has only recently started being recorded.
+    only_recorded_since_pull_request_57730: bool,
+}
+
+impl OuterImplTrait {
+    /// This controls whether we should downgrade the nested impl
+    /// trait diagnostic to a warning rather than an error, based on
+    /// whether the outer impl trait had been improperly skipped in
+    /// earlier implementations of the analysis on the stable
+    /// compiler.
+    fn should_warn_instead_of_error(&self) -> bool {
+        self.only_recorded_since_pull_request_57730
+    }
+}
+
 struct AstValidator<'a> {
     session: &'a Session,
     has_proc_macro_decls: bool,
@@ -31,31 +57,83 @@ struct AstValidator<'a> {
     // Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
     // Nested `impl Trait` _is_ allowed in associated type position,
     // e.g `impl Iterator<Item=impl Debug>`
-    outer_impl_trait: Option<Span>,
+    outer_impl_trait: Option<OuterImplTrait>,
 
     // Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
     // or `Foo::Bar<impl Trait>`
     is_impl_trait_banned: bool,
+
+    // rust-lang/rust#57979: the ban of nested `impl Trait` was buggy
+    // until PRs #57730 and #57981 landed: it would jump directly to
+    // walk_ty rather than visit_ty (or skip recurring entirely for
+    // impl trait in projections), and thus miss some cases. We track
+    // whether we should downgrade to a warning for short-term via
+    // these booleans.
+    warning_period_57979_didnt_record_next_impl_trait: bool,
+    warning_period_57979_impl_trait_in_proj: bool,
 }
 
 impl<'a> AstValidator<'a> {
+    fn with_impl_trait_in_proj_warning<T>(&mut self, v: bool, f: impl FnOnce(&mut Self) -> T) -> T {
+        let old = mem::replace(&mut self.warning_period_57979_impl_trait_in_proj, v);
+        let ret = f(self);
+        self.warning_period_57979_impl_trait_in_proj = old;
+        ret
+    }
+
     fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
         let old = mem::replace(&mut self.is_impl_trait_banned, true);
         f(self);
         self.is_impl_trait_banned = old;
     }
 
-    fn with_impl_trait(&mut self, outer_impl_trait: Option<Span>, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.outer_impl_trait, outer_impl_trait);
+    fn with_impl_trait(&mut self, outer: Option<OuterImplTrait>, f: impl FnOnce(&mut Self)) {
+        let old = mem::replace(&mut self.outer_impl_trait, outer);
         f(self);
         self.outer_impl_trait = old;
     }
 
+    fn visit_assoc_type_binding_from_generic_args(&mut self, type_binding: &'a TypeBinding) {
+        // rust-lang/rust#57979: bug in old visit_generic_args called
+        // walk_ty rather than visit_ty, skipping outer `impl Trait`
+        // if it happened to occur at `type_binding.ty`
+        if let TyKind::ImplTrait(..) = type_binding.ty.node {
+            self.warning_period_57979_didnt_record_next_impl_trait = true;
+        }
+        self.visit_assoc_type_binding(type_binding);
+    }
+
+    fn visit_ty_from_generic_args(&mut self, ty: &'a Ty) {
+        // rust-lang/rust#57979: bug in old visit_generic_args called
+        // walk_ty rather than visit_ty, skippping outer `impl Trait`
+        // if it happened to occur at `ty`
+        if let TyKind::ImplTrait(..) = ty.node {
+            self.warning_period_57979_didnt_record_next_impl_trait = true;
+        }
+        self.visit_ty(ty);
+    }
+
+    fn outer_impl_trait(&mut self, span: Span) -> OuterImplTrait {
+        let only_recorded_since_pull_request_57730 =
+            self.warning_period_57979_didnt_record_next_impl_trait;
+
+        // (this flag is designed to be set to true and then only
+        // reach the construction point for the outer impl trait once,
+        // so its safe and easiest to unconditionally reset it to
+        // false)
+        self.warning_period_57979_didnt_record_next_impl_trait = false;
+
+        OuterImplTrait {
+            span, only_recorded_since_pull_request_57730,
+        }
+    }
+
     // Mirrors visit::walk_ty, but tracks relevant state
     fn walk_ty(&mut self, t: &'a Ty) {
         match t.node {
             TyKind::ImplTrait(..) => {
-                self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
+                let outer_impl_trait = self.outer_impl_trait(t.span);
+                self.with_impl_trait(Some(outer_impl_trait), |this| visit::walk_ty(this, t))
             }
             TyKind::Path(ref qself, ref path) => {
                 // We allow these:
@@ -406,22 +484,41 @@ fn visit_ty(&mut self, ty: &'a Ty) {
             }
             TyKind::ImplTrait(_, ref bounds) => {
                 if self.is_impl_trait_banned {
-                    struct_span_err!(self.session, ty.span, E0667,
-                        "`impl Trait` is not allowed in path parameters").emit();
+                    if self.warning_period_57979_impl_trait_in_proj {
+                        self.session.buffer_lint(
+                            NESTED_IMPL_TRAIT, ty.id, ty.span,
+                            "`impl Trait` is not allowed in path parameters");
+                    } else {
+                        struct_span_err!(self.session, ty.span, E0667,
+                            "`impl Trait` is not allowed in path parameters").emit();
+                    }
                 }
 
                 if let Some(outer_impl_trait) = self.outer_impl_trait {
-                    struct_span_err!(self.session, ty.span, E0666,
-                                    "nested `impl Trait` is not allowed")
-                        .span_label(outer_impl_trait, "outer `impl Trait`")
-                        .span_label(ty.span, "nested `impl Trait` here")
-                        .emit();
-
+                    if outer_impl_trait.should_warn_instead_of_error() {
+                        self.session.buffer_lint_with_diagnostic(
+                            NESTED_IMPL_TRAIT, ty.id, ty.span,
+                            "nested `impl Trait` is not allowed",
+                            BuiltinLintDiagnostics::NestedImplTrait {
+                                outer_impl_trait_span: outer_impl_trait.span,
+                                inner_impl_trait_span: ty.span,
+                            });
+                    } else {
+                        struct_span_err!(self.session, ty.span, E0666,
+                            "nested `impl Trait` is not allowed")
+                            .span_label(outer_impl_trait.span, "outer `impl Trait`")
+                            .span_label(ty.span, "nested `impl Trait` here")
+                            .emit();
+                    }
                 }
+
                 if !bounds.iter()
                           .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) {
                     self.err_handler().span_err(ty.span, "at least one trait must be specified");
                 }
+
+                self.with_impl_trait_in_proj_warning(true, |this| this.walk_ty(ty));
+                return;
             }
             _ => {}
         }
@@ -606,10 +703,11 @@ fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
                         GenericArg::Const(..) => ParamKindOrd::Const,
                     }, arg.span(), None)
                 }), GenericPosition::Arg, generic_args.span());
+
                 // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
                 // are allowed to contain nested `impl Trait`.
                 self.with_impl_trait(None, |this| {
-                    walk_list!(this, visit_assoc_type_binding, &data.bindings);
+                    walk_list!(this, visit_assoc_type_binding_from_generic_args, &data.bindings);
                 });
             }
             GenericArgs::Parenthesized(ref data) => {
@@ -617,7 +715,7 @@ fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
                 if let Some(ref type_) = data.output {
                     // `-> Foo` syntax is essentially an associated type binding,
                     // so it is also allowed to contain nested `impl Trait`.
-                    self.with_impl_trait(None, |this| this.visit_ty(type_));
+                    self.with_impl_trait(None, |this| this.visit_ty_from_generic_args(type_));
                 }
             }
         }
@@ -719,6 +817,8 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) {
         has_global_allocator: false,
         outer_impl_trait: None,
         is_impl_trait_banned: false,
+        warning_period_57979_didnt_record_next_impl_trait: false,
+        warning_period_57979_impl_trait_in_proj: false,
     };
     visit::walk_crate(&mut validator, krate);
 
index 1e5f5d244e9c4895db89c2279a2b560f051de9b0..f79bf4e999d5492dc158cca4a8ae47f29fa7a441 100644 (file)
@@ -917,7 +917,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
 
     tcx.infer_ctxt().enter(|infcx| {
-        let param_env = ty::ParamEnv::empty();
+        let param_env = tcx.param_env(impl_c.def_id);
         let inh = Inherited::new(infcx, impl_c.def_id);
         let infcx = &inh.infcx;
 
index 8a599c11b2095985dd2cda4dd700dd3548361a06..f2111f2d9e0281f60b838fe650a2fea579b1879a 100644 (file)
@@ -850,7 +850,7 @@ fn default() -> HashSet<T, S> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, T, S> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S>
+impl<T, S> BitOr<&HashSet<T, S>> for &HashSet<T, S>
     where T: Eq + Hash + Clone,
           S: BuildHasher + Default
 {
@@ -882,7 +882,7 @@ fn bitor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, T, S> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S>
+impl<T, S> BitAnd<&HashSet<T, S>> for &HashSet<T, S>
     where T: Eq + Hash + Clone,
           S: BuildHasher + Default
 {
@@ -914,7 +914,7 @@ fn bitand(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, T, S> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S>
+impl<T, S> BitXor<&HashSet<T, S>> for &HashSet<T, S>
     where T: Eq + Hash + Clone,
           S: BuildHasher + Default
 {
@@ -946,7 +946,7 @@ fn bitxor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, T, S> Sub<&'b HashSet<T, S>> for &'a HashSet<T, S>
+impl<T, S> Sub<&HashSet<T, S>> for &HashSet<T, S>
     where T: Eq + Hash + Clone,
           S: BuildHasher + Default
 {
index 2858308e8f8d59a4303eac8aff88492d4d2f423e..3eb289501cb0fd080ccea3d7f3df479ede4ef8eb 100644 (file)
@@ -337,7 +337,7 @@ fn from(str_err: String) -> Box<dyn Error> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b> From<&'b str> for Box<dyn Error + Send + Sync + 'a> {
+impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
     /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
     ///
     /// # Examples
@@ -351,13 +351,13 @@ impl<'a, 'b> From<&'b str> for Box<dyn Error + Send + Sync + 'a> {
     /// assert!(
     ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
     /// ```
-    fn from(err: &'b str) -> Box<dyn Error + Send + Sync + 'a> {
+    fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
         From::from(String::from(err))
     }
 }
 
 #[stable(feature = "string_box_error", since = "1.6.0")]
-impl<'a> From<&'a str> for Box<dyn Error> {
+impl From<&str> for Box<dyn Error> {
     /// Converts a [`str`] into a box of dyn [`Error`].
     ///
     /// # Examples
@@ -370,7 +370,7 @@ impl<'a> From<&'a str> for Box<dyn Error> {
     /// let a_boxed_error = Box::<Error>::from(a_str_error);
     /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
     /// ```
-    fn from(err: &'a str) -> Box<dyn Error> {
+    fn from(err: &str) -> Box<dyn Error> {
         From::from(String::from(err))
     }
 }
index 139680e526fd6b2fc24ad1a94f308f00b71bf9d4..ad3f45bfadaf4df0903fb4b5ec469f76fcf99053 100644 (file)
@@ -690,8 +690,8 @@ fn from(s: Cow<'a, CStr>) -> Self {
 }
 
 #[stable(feature = "box_from_c_str", since = "1.17.0")]
-impl<'a> From<&'a CStr> for Box<CStr> {
-    fn from(s: &'a CStr) -> Box<CStr> {
+impl From<&CStr> for Box<CStr> {
+    fn from(s: &CStr) -> Box<CStr> {
         let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul());
         unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
     }
@@ -767,7 +767,7 @@ fn from(s: CString) -> Arc<CStr> {
 }
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
-impl<'a> From<&'a CStr> for Arc<CStr> {
+impl From<&CStr> for Arc<CStr> {
     #[inline]
     fn from(s: &CStr) -> Arc<CStr> {
         let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul());
@@ -789,7 +789,7 @@ fn from(s: CString) -> Rc<CStr> {
 }
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
-impl<'a> From<&'a CStr> for Rc<CStr> {
+impl From<&CStr> for Rc<CStr> {
     #[inline]
     fn from(s: &CStr) -> Rc<CStr> {
         let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul());
@@ -1268,8 +1268,8 @@ fn to_owned(&self) -> CString {
 }
 
 #[stable(feature = "cstring_asref", since = "1.7.0")]
-impl<'a> From<&'a CStr> for CString {
-    fn from(s: &'a CStr) -> CString {
+impl From<&CStr> for CString {
+    fn from(s: &CStr) -> CString {
         s.to_owned()
     }
 }
index f68eaeb9c7e1f20d3169abe13e03e478452b9de3..3a0590021c917bc1cdaf6e7fa69ba590c926c926 100644 (file)
@@ -357,8 +357,8 @@ fn from(s: String) -> OsString {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for OsString {
-    fn from(s: &'a T) -> OsString {
+impl<T: ?Sized + AsRef<OsStr>> From<&T> for OsString {
+    fn from(s: &T) -> OsString {
         s.as_ref().to_os_string()
     }
 }
@@ -421,8 +421,8 @@ fn eq(&self, other: &OsString) -> bool {
 }
 
 #[stable(feature = "os_str_str_ref_eq", since = "1.29.0")]
-impl<'a> PartialEq<&'a str> for OsString {
-    fn eq(&self, other: &&'a str) -> bool {
+impl PartialEq<&str> for OsString {
+    fn eq(&self, other: &&str) -> bool {
         **self == **other
     }
 }
@@ -656,8 +656,8 @@ fn bytes(&self) -> &[u8] {
 }
 
 #[stable(feature = "box_from_os_str", since = "1.17.0")]
-impl<'a> From<&'a OsStr> for Box<OsStr> {
-    fn from(s: &'a OsStr) -> Box<OsStr> {
+impl From<&OsStr> for Box<OsStr> {
+    fn from(s: &OsStr) -> Box<OsStr> {
         let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr;
         unsafe { Box::from_raw(rw) }
     }
@@ -707,7 +707,7 @@ fn from(s: OsString) -> Arc<OsStr> {
 }
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
-impl<'a> From<&'a OsStr> for Arc<OsStr> {
+impl From<&OsStr> for Arc<OsStr> {
     #[inline]
     fn from(s: &OsStr) -> Arc<OsStr> {
         let arc = s.inner.into_arc();
@@ -729,7 +729,7 @@ fn from(s: OsString) -> Rc<OsStr> {
 }
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
-impl<'a> From<&'a OsStr> for Rc<OsStr> {
+impl From<&OsStr> for Rc<OsStr> {
     #[inline]
     fn from(s: &OsStr) -> Rc<OsStr> {
         let rc = s.inner.into_rc();
index 858a5778b8161f593a9fbc22d3728daeb41a7e67..ea3fcd8ce28597df108ef63dd077a81c4245240f 100644 (file)
@@ -1456,8 +1456,8 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
 }
 
 #[stable(feature = "box_from_path", since = "1.17.0")]
-impl<'a> From<&'a Path> for Box<Path> {
-    fn from(path: &'a Path) -> Box<Path> {
+impl From<&Path> for Box<Path> {
+    fn from(path: &Path) -> Box<Path> {
         let boxed: Box<OsStr> = path.inner.into();
         let rw = Box::into_raw(boxed) as *mut Path;
         unsafe { Box::from_raw(rw) }
@@ -1494,8 +1494,8 @@ fn clone(&self) -> Self {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for PathBuf {
-    fn from(s: &'a T) -> PathBuf {
+impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
+    fn from(s: &T) -> PathBuf {
         PathBuf::from(s.as_ref().to_os_string())
     }
 }
@@ -1630,7 +1630,7 @@ fn from(s: PathBuf) -> Arc<Path> {
 }
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
-impl<'a> From<&'a Path> for Arc<Path> {
+impl From<&Path> for Arc<Path> {
     /// Converts a Path into a Rc by copying the Path data into a new Rc buffer.
     #[inline]
     fn from(s: &Path) -> Arc<Path> {
@@ -1650,7 +1650,7 @@ fn from(s: PathBuf) -> Rc<Path> {
 }
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
-impl<'a> From<&'a Path> for Rc<Path> {
+impl From<&Path> for Rc<Path> {
     /// Converts a Path into a Rc by copying the Path data into a new Rc buffer.
     #[inline]
     fn from(s: &Path) -> Rc<Path> {
index 50d72dc7b240bdf2c7d4d6adc545fcbe546bcaa8..6d2a4962ab44467959c8914341a42db69339d70d 100644 (file)
@@ -297,10 +297,10 @@ fn next(&mut self) -> Option<SocketAddr> {
     }
 }
 
-impl<'a> TryFrom<&'a str> for LookupHost {
+impl TryFrom<&str> for LookupHost {
     type Error = io::Error;
 
-    fn try_from(_v: &'a str) -> io::Result<LookupHost> {
+    fn try_from(_v: &str) -> io::Result<LookupHost> {
         unsupported()
     }
 }
index a172763f61313b771e06082b9f2f2a2e4a36f3ad..dbaa140ed8a0f9c39a1aa940b6cb0c5367999ced 100644 (file)
@@ -35,7 +35,7 @@ fn next(&mut self) -> Option<Self::Item> {
     }
 }
 
-impl<'a> TryFrom<&'a str> for LookupHost {
+impl TryFrom<&str> for LookupHost {
     type Error = io::Error;
 
     fn try_from(s: &str) -> io::Result<LookupHost> {
index ab8b2681393f89a4fea26b6261e4b4f1182cacfc..e5e42e3d0b04867cb5309797df653cbaa10e0800 100644 (file)
@@ -420,10 +420,10 @@ fn next(&mut self) -> Option<SocketAddr> {
     }
 }
 
-impl<'a> TryFrom<&'a str> for LookupHost {
+impl TryFrom<&str> for LookupHost {
     type Error = io::Error;
 
-    fn try_from(v: &'a str) -> io::Result<LookupHost> {
+    fn try_from(v: &str) -> io::Result<LookupHost> {
         LookupHost::new(v.to_owned())
     }
 }
index b6e8cc738946b9a1a4429471598b46ca8eb2ef82..b9e725371a36edcd9494779549f54777e193df34 100644 (file)
@@ -447,10 +447,10 @@ unsafe impl Sync for LookupHost {}
     unsafe impl Send for LookupHost {}
 
 
-    impl<'a> TryFrom<&'a str> for LookupHost {
+    impl TryFrom<&str> for LookupHost {
         type Error = io::Error;
 
-        fn try_from(_v: &'a str) -> io::Result<LookupHost> {
+        fn try_from(_v: &str) -> io::Result<LookupHost> {
             unimpl!();
         }
     }
index 1249832fb09d2db0b232df85e58a775a562b23da..a2ea2dfbbc0326d13a12f1a86212d110354d12b5 100644 (file)
@@ -298,10 +298,10 @@ fn next(&mut self) -> Option<SocketAddr> {
     }
 }
 
-impl<'a> TryFrom<&'a str> for LookupHost {
+impl TryFrom<&str> for LookupHost {
     type Error = io::Error;
 
-    fn try_from(_v: &'a str) -> io::Result<LookupHost> {
+    fn try_from(_v: &str) -> io::Result<LookupHost> {
         unsupported()
     }
 }
index 36721171b17334e111346faebd5254f9ff7e253d..b9505aaa69ba59b4785ac9546fd1c1c66bc0c639 100644 (file)
@@ -157,7 +157,7 @@ fn drop(&mut self) {
     }
 }
 
-impl<'a> TryFrom<&'a str> for LookupHost {
+impl TryFrom<&str> for LookupHost {
     type Error = io::Error;
 
     fn try_from(s: &str) -> io::Result<LookupHost> {
index db5b8dcda4eab7daadddc04514043510a00b683b..01e3b2929031896a97fdcec9a0b058e8d94b3f93 100644 (file)
@@ -1423,15 +1423,17 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
 
                 // If the character is an ident start not followed by another single
                 // quote, then this is a lifetime name:
-                if ident_start(Some(c2)) && !self.ch_is('\'') {
+                if (ident_start(Some(c2)) || c2.is_numeric()) && !self.ch_is('\'') {
                     while ident_continue(self.ch) {
                         self.bump();
                     }
                     // lifetimes shouldn't end with a single quote
                     // if we find one, then this is an invalid character literal
                     if self.ch_is('\'') {
-                        self.err_span_(start_with_quote, self.next_pos,
-                                "character literal may only contain one codepoint");
+                        self.err_span_(
+                            start_with_quote,
+                            self.next_pos,
+                            "character literal may only contain one codepoint");
                         self.bump();
                         return Ok(token::Literal(token::Err(Symbol::intern("??")), None))
 
@@ -1444,6 +1446,15 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                         self.mk_ident(&format!("'{}", lifetime_name))
                     });
 
+                    if c2.is_numeric() {
+                        // this is a recovered lifetime written `'1`, error but accept it
+                        self.err_span_(
+                            start_with_quote,
+                            self.pos,
+                            "lifetimes cannot start with a number",
+                        );
+                    }
+
                     return Ok(token::Lifetime(ident));
                 }
 
@@ -1873,6 +1884,7 @@ fn is_block_doc_comment(s: &str) -> bool {
     res
 }
 
+/// Determine whether `c` is a valid start for an ident.
 fn ident_start(c: Option<char>) -> bool {
     let c = match c {
         Some(c) => c,
diff --git a/src/test/rustdoc-js-std/alias-1.js b/src/test/rustdoc-js-std/alias-1.js
new file mode 100644 (file)
index 0000000..7c6327f
--- /dev/null
@@ -0,0 +1,7 @@
+const QUERY = '&';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std', 'name': 'reference' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/alias-2.js b/src/test/rustdoc-js-std/alias-2.js
new file mode 100644 (file)
index 0000000..f3c6713
--- /dev/null
@@ -0,0 +1,10 @@
+// ignore-order
+
+const QUERY = '+';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::ops', 'name': 'AddAssign' },
+        { 'path': 'std::ops', 'name': 'Add' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/alias-3.js b/src/test/rustdoc-js-std/alias-3.js
new file mode 100644 (file)
index 0000000..392b1e8
--- /dev/null
@@ -0,0 +1,7 @@
+const QUERY = '!';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std', 'name': 'never' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/alias.js b/src/test/rustdoc-js-std/alias.js
new file mode 100644 (file)
index 0000000..2b709c9
--- /dev/null
@@ -0,0 +1,11 @@
+// ignore-order
+
+const QUERY = '[';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std', 'name': 'slice' },
+        { 'path': 'std::ops', 'name': 'IndexMut' },
+        { 'path': 'std::ops', 'name': 'Index' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/basic.js b/src/test/rustdoc-js-std/basic.js
new file mode 100644 (file)
index 0000000..824cac7
--- /dev/null
@@ -0,0 +1,15 @@
+const QUERY = 'String';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::string', 'name': 'String' },
+        { 'path': 'std::ffi', 'name': 'CString' },
+        { 'path': 'std::ffi', 'name': 'OsString' },
+    ],
+    'in_args': [
+        { 'path': 'std::str', 'name': 'eq' },
+    ],
+    'returned': [
+        { 'path': 'std::string::String', 'name': 'add' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/deduplication.js b/src/test/rustdoc-js-std/deduplication.js
new file mode 100644 (file)
index 0000000..f02f6cf
--- /dev/null
@@ -0,0 +1,11 @@
+// ignore-order
+
+const QUERY = 'is_nan';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::f32', 'name': 'is_nan' },
+        { 'path': 'std::f64', 'name': 'is_nan' },
+        { 'path': 'std::option::Option', 'name': 'is_none' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/enum-option.js b/src/test/rustdoc-js-std/enum-option.js
new file mode 100644 (file)
index 0000000..902e090
--- /dev/null
@@ -0,0 +1,7 @@
+const QUERY = 'enum:Option';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::option', 'name': 'Option' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/filter-crate.js b/src/test/rustdoc-js-std/filter-crate.js
new file mode 100644 (file)
index 0000000..2e0330c
--- /dev/null
@@ -0,0 +1,9 @@
+// exact-check
+
+const QUERY = 'hashmap';
+const FILTER_CRATE = 'core';
+
+const EXPECTED = {
+    'others': [
+    ],
+};
diff --git a/src/test/rustdoc-js-std/fn-forget.js b/src/test/rustdoc-js-std/fn-forget.js
new file mode 100644 (file)
index 0000000..66a5fca
--- /dev/null
@@ -0,0 +1,8 @@
+const QUERY = 'fn:forget';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::mem', 'name': 'forget' },
+        { 'path': 'std::fmt', 'name': 'format' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/from_u.js b/src/test/rustdoc-js-std/from_u.js
new file mode 100644 (file)
index 0000000..e3f3cd4
--- /dev/null
@@ -0,0 +1,9 @@
+const QUERY = 'from_u';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::char', 'name': 'from_u32' },
+        { 'path': 'std::str', 'name': 'from_utf8' },
+        { 'path': 'std::string::String', 'name': 'from_utf8' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/keyword.js b/src/test/rustdoc-js-std/keyword.js
new file mode 100644 (file)
index 0000000..868ddd7
--- /dev/null
@@ -0,0 +1,10 @@
+// ignore-order
+
+const QUERY = 'fn';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std', 'name': 'fn', ty: 15 }, // 15 is for primitive types
+        { 'path': 'std', 'name': 'fn', ty: 21 }, // 21 is for keywords
+    ],
+};
diff --git a/src/test/rustdoc-js-std/macro-check.js b/src/test/rustdoc-js-std/macro-check.js
new file mode 100644 (file)
index 0000000..242e0cb
--- /dev/null
@@ -0,0 +1,10 @@
+// ignore-order
+
+const QUERY = 'panic';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std', 'name': 'panic', ty: 14 }, // 15 is for macros
+        { 'path': 'std', 'name': 'panic', ty: 0 }, // 0 is for modules
+    ],
+};
diff --git a/src/test/rustdoc-js-std/macro-print.js b/src/test/rustdoc-js-std/macro-print.js
new file mode 100644 (file)
index 0000000..858046e
--- /dev/null
@@ -0,0 +1,10 @@
+const QUERY = 'macro:print';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std', 'name': 'print' },
+        { 'path': 'std', 'name': 'eprint' },
+        { 'path': 'std', 'name': 'println' },
+        { 'path': 'std', 'name': 'eprintln' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/multi-query.js b/src/test/rustdoc-js-std/multi-query.js
new file mode 100644 (file)
index 0000000..01e5406
--- /dev/null
@@ -0,0 +1,9 @@
+const QUERY = 'str,u8';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std', 'name': 'str' },
+        { 'path': 'std', 'name': 'u8' },
+        { 'path': 'std::ffi', 'name': 'CStr' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/never.js b/src/test/rustdoc-js-std/never.js
new file mode 100644 (file)
index 0000000..392b1e8
--- /dev/null
@@ -0,0 +1,7 @@
+const QUERY = '!';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std', 'name': 'never' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/quoted.js b/src/test/rustdoc-js-std/quoted.js
new file mode 100644 (file)
index 0000000..924129f
--- /dev/null
@@ -0,0 +1,13 @@
+const QUERY = '"error"';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std', 'name': 'error' },
+        { 'path': 'std::fmt', 'name': 'Error' },
+        { 'path': 'std::io', 'name': 'Error' },
+    ],
+    'in_args': [],
+    'returned': [
+        { 'path': 'std::fmt::LowerExp', 'name': 'fmt' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/should-fail.js b/src/test/rustdoc-js-std/should-fail.js
new file mode 100644 (file)
index 0000000..b85a47d
--- /dev/null
@@ -0,0 +1,9 @@
+// should-fail
+
+const QUERY = 'fn';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std', 'name': 'fn', ty: 14 },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/string-from_ut.js b/src/test/rustdoc-js-std/string-from_ut.js
new file mode 100644 (file)
index 0000000..f9edf44
--- /dev/null
@@ -0,0 +1,11 @@
+const QUERY = 'String::from_ut';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::string::String', 'name': 'from_utf8' },
+        { 'path': 'std::string::String', 'name': 'from_utf8' },
+        { 'path': 'std::string::String', 'name': 'from_utf8_lossy' },
+        { 'path': 'std::string::String', 'name': 'from_utf16_lossy' },
+        { 'path': 'std::string::String', 'name': 'from_utf8_unchecked' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/struct-vec.js b/src/test/rustdoc-js-std/struct-vec.js
new file mode 100644 (file)
index 0000000..2c80814
--- /dev/null
@@ -0,0 +1,8 @@
+const QUERY = 'struct:Vec';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::vec', 'name': 'Vec' },
+        { 'path': 'std::collections', 'name': 'VecDeque' },
+    ],
+};
diff --git a/src/test/rustdoc-js-std/vec-new.js b/src/test/rustdoc-js-std/vec-new.js
new file mode 100644 (file)
index 0000000..e4daa50
--- /dev/null
@@ -0,0 +1,8 @@
+const QUERY = 'Vec::new';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::vec::Vec', 'name': 'new' },
+        { 'path': 'std::vec::Vec', 'name': 'ne' },
+    ],
+};
diff --git a/src/test/rustdoc-js/alias-1.js b/src/test/rustdoc-js/alias-1.js
deleted file mode 100644 (file)
index 7c6327f..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-const QUERY = '&';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'reference' },
-    ],
-};
diff --git a/src/test/rustdoc-js/alias-2.js b/src/test/rustdoc-js/alias-2.js
deleted file mode 100644 (file)
index f3c6713..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// ignore-order
-
-const QUERY = '+';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std::ops', 'name': 'AddAssign' },
-        { 'path': 'std::ops', 'name': 'Add' },
-    ],
-};
diff --git a/src/test/rustdoc-js/alias-3.js b/src/test/rustdoc-js/alias-3.js
deleted file mode 100644 (file)
index 392b1e8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-const QUERY = '!';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'never' },
-    ],
-};
diff --git a/src/test/rustdoc-js/alias.js b/src/test/rustdoc-js/alias.js
deleted file mode 100644 (file)
index 2b709c9..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// ignore-order
-
-const QUERY = '[';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'slice' },
-        { 'path': 'std::ops', 'name': 'IndexMut' },
-        { 'path': 'std::ops', 'name': 'Index' },
-    ],
-};
index 824cac71083328dd8e001f8a137c78d7d219db66..d99b23468b60cfa94361eac46317304aa7ae8332 100644 (file)
@@ -1,15 +1,7 @@
-const QUERY = 'String';
+const QUERY = 'Fo';
 
 const EXPECTED = {
     'others': [
-        { 'path': 'std::string', 'name': 'String' },
-        { 'path': 'std::ffi', 'name': 'CString' },
-        { 'path': 'std::ffi', 'name': 'OsString' },
-    ],
-    'in_args': [
-        { 'path': 'std::str', 'name': 'eq' },
-    ],
-    'returned': [
-        { 'path': 'std::string::String', 'name': 'add' },
+        { 'path': 'basic', 'name': 'Foo' },
     ],
 };
diff --git a/src/test/rustdoc-js/basic.rs b/src/test/rustdoc-js/basic.rs
new file mode 100644 (file)
index 0000000..1b4963f
--- /dev/null
@@ -0,0 +1,2 @@
+/// Foo
+pub struct Foo;
diff --git a/src/test/rustdoc-js/deduplication.js b/src/test/rustdoc-js/deduplication.js
deleted file mode 100644 (file)
index f02f6cf..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// ignore-order
-
-const QUERY = 'is_nan';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std::f32', 'name': 'is_nan' },
-        { 'path': 'std::f64', 'name': 'is_nan' },
-        { 'path': 'std::option::Option', 'name': 'is_none' },
-    ],
-};
diff --git a/src/test/rustdoc-js/enum-option.js b/src/test/rustdoc-js/enum-option.js
deleted file mode 100644 (file)
index 902e090..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-const QUERY = 'enum:Option';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std::option', 'name': 'Option' },
-    ],
-};
diff --git a/src/test/rustdoc-js/filter-crate.js b/src/test/rustdoc-js/filter-crate.js
deleted file mode 100644 (file)
index 2e0330c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// exact-check
-
-const QUERY = 'hashmap';
-const FILTER_CRATE = 'core';
-
-const EXPECTED = {
-    'others': [
-    ],
-};
diff --git a/src/test/rustdoc-js/fn-forget.js b/src/test/rustdoc-js/fn-forget.js
deleted file mode 100644 (file)
index 66a5fca..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-const QUERY = 'fn:forget';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std::mem', 'name': 'forget' },
-        { 'path': 'std::fmt', 'name': 'format' },
-    ],
-};
diff --git a/src/test/rustdoc-js/from_u.js b/src/test/rustdoc-js/from_u.js
deleted file mode 100644 (file)
index e3f3cd4..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-const QUERY = 'from_u';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std::char', 'name': 'from_u32' },
-        { 'path': 'std::str', 'name': 'from_utf8' },
-        { 'path': 'std::string::String', 'name': 'from_utf8' },
-    ],
-};
diff --git a/src/test/rustdoc-js/keyword.js b/src/test/rustdoc-js/keyword.js
deleted file mode 100644 (file)
index 868ddd7..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// ignore-order
-
-const QUERY = 'fn';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'fn', ty: 15 }, // 15 is for primitive types
-        { 'path': 'std', 'name': 'fn', ty: 21 }, // 21 is for keywords
-    ],
-};
diff --git a/src/test/rustdoc-js/macro-check.js b/src/test/rustdoc-js/macro-check.js
deleted file mode 100644 (file)
index 242e0cb..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// ignore-order
-
-const QUERY = 'panic';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'panic', ty: 14 }, // 15 is for macros
-        { 'path': 'std', 'name': 'panic', ty: 0 }, // 0 is for modules
-    ],
-};
diff --git a/src/test/rustdoc-js/macro-print.js b/src/test/rustdoc-js/macro-print.js
deleted file mode 100644 (file)
index 858046e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-const QUERY = 'macro:print';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'print' },
-        { 'path': 'std', 'name': 'eprint' },
-        { 'path': 'std', 'name': 'println' },
-        { 'path': 'std', 'name': 'eprintln' },
-    ],
-};
diff --git a/src/test/rustdoc-js/multi-query.js b/src/test/rustdoc-js/multi-query.js
deleted file mode 100644 (file)
index 01e5406..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-const QUERY = 'str,u8';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'str' },
-        { 'path': 'std', 'name': 'u8' },
-        { 'path': 'std::ffi', 'name': 'CStr' },
-    ],
-};
diff --git a/src/test/rustdoc-js/never.js b/src/test/rustdoc-js/never.js
deleted file mode 100644 (file)
index 392b1e8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-const QUERY = '!';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'never' },
-    ],
-};
diff --git a/src/test/rustdoc-js/quoted.js b/src/test/rustdoc-js/quoted.js
deleted file mode 100644 (file)
index 924129f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-const QUERY = '"error"';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'error' },
-        { 'path': 'std::fmt', 'name': 'Error' },
-        { 'path': 'std::io', 'name': 'Error' },
-    ],
-    'in_args': [],
-    'returned': [
-        { 'path': 'std::fmt::LowerExp', 'name': 'fmt' },
-    ],
-};
diff --git a/src/test/rustdoc-js/should-fail.js b/src/test/rustdoc-js/should-fail.js
deleted file mode 100644 (file)
index b85a47d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// should-fail
-
-const QUERY = 'fn';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'fn', ty: 14 },
-    ],
-};
diff --git a/src/test/rustdoc-js/string-from_ut.js b/src/test/rustdoc-js/string-from_ut.js
deleted file mode 100644 (file)
index f9edf44..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-const QUERY = 'String::from_ut';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std::string::String', 'name': 'from_utf8' },
-        { 'path': 'std::string::String', 'name': 'from_utf8' },
-        { 'path': 'std::string::String', 'name': 'from_utf8_lossy' },
-        { 'path': 'std::string::String', 'name': 'from_utf16_lossy' },
-        { 'path': 'std::string::String', 'name': 'from_utf8_unchecked' },
-    ],
-};
diff --git a/src/test/rustdoc-js/struct-vec.js b/src/test/rustdoc-js/struct-vec.js
deleted file mode 100644 (file)
index 2c80814..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-const QUERY = 'struct:Vec';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std::vec', 'name': 'Vec' },
-        { 'path': 'std::collections', 'name': 'VecDeque' },
-    ],
-};
diff --git a/src/test/rustdoc-js/vec-new.js b/src/test/rustdoc-js/vec-new.js
deleted file mode 100644 (file)
index e4daa50..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-const QUERY = 'Vec::new';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std::vec::Vec', 'name': 'new' },
-        { 'path': 'std::vec::Vec', 'name': 'ne' },
-    ],
-};
index e0b502edaa15ed3c248e3b6496eb5dbe4c0f6e40..498e315b5c83cf4cef698f15596353ee8612eed8 100644 (file)
@@ -12,7 +12,7 @@ trait Bar: Foo {
 
 impl<T: Foo> Bar for T {
     const FROM: &'static str = "foo";
-    //~^ ERROR the trait bound `T: Foo` is not satisfied [E0277]
+    //~^ ERROR implemented const `FROM` has an incompatible type for trait [E0326]
 }
 
 fn main() {}
index e4b86d84cafc9713efe50cad42799503c3665892..eeee26a75671f062f261caad1ad139a4038c98a8 100644 (file)
@@ -1,11 +1,15 @@
-error[E0277]: the trait bound `T: Foo` is not satisfied
-  --> $DIR/associated-const-generic-obligations.rs:14:5
+error[E0326]: implemented const `FROM` has an incompatible type for trait
+  --> $DIR/associated-const-generic-obligations.rs:14:17
    |
+LL |     const FROM: Self::Out;
+   |                 --------- type in trait
+...
 LL |     const FROM: &'static str = "foo";
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+   |                 ^^^^^^^^^^^^ expected associated type, found reference
    |
-   = help: consider adding a `where T: Foo` bound
+   = note: expected type `<T as Foo>::Out`
+              found type `&'static str`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0326`.
diff --git a/src/test/ui/associated-const/associated-const-trait-bound.rs b/src/test/ui/associated-const/associated-const-trait-bound.rs
new file mode 100644 (file)
index 0000000..0ce46d3
--- /dev/null
@@ -0,0 +1,21 @@
+// compile-pass
+
+trait ConstDefault {
+    const DEFAULT: Self;
+}
+
+trait Foo: Sized {}
+
+trait FooExt: Foo {
+    type T: ConstDefault;
+}
+
+trait Bar<F: FooExt> {
+    const T: F::T;
+}
+
+impl<F: FooExt> Bar<F> for () {
+    const T: F::T = <F::T as ConstDefault>::DEFAULT;
+}
+
+fn main() {}
diff --git a/src/test/ui/block-expression-remove-semicolon.rs b/src/test/ui/block-expression-remove-semicolon.rs
new file mode 100644 (file)
index 0000000..afa10b3
--- /dev/null
@@ -0,0 +1,10 @@
+fn foo() -> i32 {
+   0
+}
+
+fn main() {
+    let x: i32 = {
+        //~^ ERROR mismatched types
+        foo(); //~ HELP consider removing this semicolon
+    };
+}
diff --git a/src/test/ui/block-expression-remove-semicolon.stderr b/src/test/ui/block-expression-remove-semicolon.stderr
new file mode 100644 (file)
index 0000000..51942f3
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/block-expression-remove-semicolon.rs:6:18
+   |
+LL |       let x: i32 = {
+   |  __________________^
+LL | |
+LL | |         foo();
+   | |              - help: consider removing this semicolon
+LL | |     };
+   | |_____^ expected i32, found ()
+   |
+   = note: expected type `i32`
+              found type `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/borrowck/issue-10876.rs b/src/test/ui/borrowck/issue-10876.rs
new file mode 100644 (file)
index 0000000..d8fff5f
--- /dev/null
@@ -0,0 +1,19 @@
+// run-pass
+
+#![feature(nll)]
+
+enum Nat {
+    S(Box<Nat>),
+    Z
+}
+fn test(x: &mut Nat) {
+    let mut p = &mut *x;
+    loop {
+        match p {
+            &mut Nat::Z => break,
+            &mut Nat::S(ref mut n) => p = &mut *n
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs b/src/test/ui/impl-trait/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs
new file mode 100644 (file)
index 0000000..5eef6a3
--- /dev/null
@@ -0,0 +1,42 @@
+// rust-lang/rust#57979 : the initial support for `impl Trait` didn't
+// properly check syntax hidden behind an associated type projection,
+// but it did catch *some cases*. This is checking that we continue to
+// properly emit errors for those, even with the new
+// future-incompatibility warnings.
+//
+// issue-57979-nested-impl-trait-in-assoc-proj.rs shows the main case
+// that we were previously failing to catch.
+
+struct Deeper<T>(T);
+
+mod allowed {
+    #![allow(nested_impl_trait)]
+
+    pub trait Foo<T> { }
+    pub trait Bar { }
+    pub trait Quux { type Assoc; }
+    pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
+    //~^ ERROR nested `impl Trait` is not allowed
+}
+
+mod warned {
+    #![warn(nested_impl_trait)]
+
+    pub trait Foo<T> { }
+    pub trait Bar { }
+    pub trait Quux { type Assoc; }
+    pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
+    //~^ ERROR nested `impl Trait` is not allowed
+}
+
+mod denied {
+    #![deny(nested_impl_trait)]
+
+    pub trait Foo<T> { }
+    pub trait Bar { }
+    pub trait Quux { type Assoc; }
+    pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
+    //~^ ERROR nested `impl Trait` is not allowed
+}
+
+fn main() { }
diff --git a/src/test/ui/impl-trait/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr b/src/test/ui/impl-trait/issue-57979-deeply-nested-impl-trait-in-assoc-proj.stderr
new file mode 100644 (file)
index 0000000..2b6f15e
--- /dev/null
@@ -0,0 +1,30 @@
+error[E0666]: nested `impl Trait` is not allowed
+  --> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:18:59
+   |
+LL |     pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
+   |                                                  ---------^^^^^^^^-
+   |                                                  |        |
+   |                                                  |        nested `impl Trait` here
+   |                                                  outer `impl Trait`
+
+error[E0666]: nested `impl Trait` is not allowed
+  --> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:28:59
+   |
+LL |     pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
+   |                                                  ---------^^^^^^^^-
+   |                                                  |        |
+   |                                                  |        nested `impl Trait` here
+   |                                                  outer `impl Trait`
+
+error[E0666]: nested `impl Trait` is not allowed
+  --> $DIR/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs:38:59
+   |
+LL |     pub fn demo(_: impl Quux<Assoc=super::Deeper<impl Foo<impl Bar>>>) { }
+   |                                                  ---------^^^^^^^^-
+   |                                                  |        |
+   |                                                  |        nested `impl Trait` here
+   |                                                  outer `impl Trait`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0666`.
diff --git a/src/test/ui/impl-trait/issue-57979-impl-trait-in-path.rs b/src/test/ui/impl-trait/issue-57979-impl-trait-in-path.rs
new file mode 100644 (file)
index 0000000..84fcb5e
--- /dev/null
@@ -0,0 +1,37 @@
+// rust-lang/rust#57979 : the initial support for `impl Trait` didn't
+// properly check syntax hidden behind an associated type projection.
+// Here we test behavior of occurrences of `impl Trait` within a path
+// component in that context.
+
+mod allowed {
+    #![allow(nested_impl_trait)]
+
+    pub trait Bar { }
+    pub trait Quux<T> { type Assoc; }
+    pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
+    impl<T> Quux<T> for () { type Assoc = u32; }
+}
+
+mod warned {
+    #![warn(nested_impl_trait)]
+
+    pub trait Bar { }
+    pub trait Quux<T> { type Assoc; }
+    pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
+    //~^ WARN `impl Trait` is not allowed in path parameters
+    //~| WARN will become a hard error in a future release!
+    impl<T> Quux<T> for () { type Assoc = u32; }
+}
+
+mod denied {
+    #![deny(nested_impl_trait)]
+
+    pub trait Bar { }
+    pub trait Quux<T> { type Assoc; }
+    pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
+    //~^ ERROR `impl Trait` is not allowed in path parameters
+    //~| WARN will become a hard error in a future release!
+    impl<T> Quux<T> for () { type Assoc = u32; }
+}
+
+fn main() { }
diff --git a/src/test/ui/impl-trait/issue-57979-impl-trait-in-path.stderr b/src/test/ui/impl-trait/issue-57979-impl-trait-in-path.stderr
new file mode 100644 (file)
index 0000000..982ecba
--- /dev/null
@@ -0,0 +1,30 @@
+warning: `impl Trait` is not allowed in path parameters
+  --> $DIR/issue-57979-impl-trait-in-path.rs:20:52
+   |
+LL |     pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
+   |                                                    ^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/issue-57979-impl-trait-in-path.rs:16:13
+   |
+LL |     #![warn(nested_impl_trait)]
+   |             ^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #59014 <https://github.com/rust-lang/rust/issues/59014>
+
+error: `impl Trait` is not allowed in path parameters
+  --> $DIR/issue-57979-impl-trait-in-path.rs:31:52
+   |
+LL |     pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
+   |                                                    ^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/issue-57979-impl-trait-in-path.rs:27:13
+   |
+LL |     #![deny(nested_impl_trait)]
+   |             ^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #59014 <https://github.com/rust-lang/rust/issues/59014>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/issue-57979-nested-impl-trait-in-assoc-proj.rs b/src/test/ui/impl-trait/issue-57979-nested-impl-trait-in-assoc-proj.rs
new file mode 100644 (file)
index 0000000..5c20ffc
--- /dev/null
@@ -0,0 +1,37 @@
+// rust-lang/rust#57979 : the initial support for `impl Trait` didn't
+// properly check syntax hidden behind an associated type projection.
+// Here we test behavior of occurrences of `impl Trait` within an
+// `impl Trait` in that context.
+
+mod allowed {
+    #![allow(nested_impl_trait)]
+
+    pub trait Foo<T> { }
+    pub trait Bar { }
+    pub trait Quux { type Assoc; }
+    pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
+}
+
+mod warned {
+    #![warn(nested_impl_trait)]
+
+    pub trait Foo<T> { }
+    pub trait Bar { }
+    pub trait Quux { type Assoc; }
+    pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
+    //~^ WARN nested `impl Trait` is not allowed
+    //~| WARN will become a hard error in a future release!
+}
+
+mod denied {
+    #![deny(nested_impl_trait)]
+
+    pub trait Foo<T> { }
+    pub trait Bar { }
+    pub trait Quux { type Assoc; }
+    pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
+    //~^ ERROR nested `impl Trait` is not allowed
+    //~| WARN will become a hard error in a future release!
+}
+
+fn main() { }
diff --git a/src/test/ui/impl-trait/issue-57979-nested-impl-trait-in-assoc-proj.stderr b/src/test/ui/impl-trait/issue-57979-nested-impl-trait-in-assoc-proj.stderr
new file mode 100644 (file)
index 0000000..508aea2
--- /dev/null
@@ -0,0 +1,36 @@
+warning: nested `impl Trait` is not allowed
+  --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:21:45
+   |
+LL |     pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
+   |                                    ---------^^^^^^^^-
+   |                                    |        |
+   |                                    |        nested `impl Trait` here
+   |                                    outer `impl Trait`
+   |
+note: lint level defined here
+  --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:16:13
+   |
+LL |     #![warn(nested_impl_trait)]
+   |             ^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #59014 <https://github.com/rust-lang/rust/issues/59014>
+
+error: nested `impl Trait` is not allowed
+  --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:32:45
+   |
+LL |     pub fn demo(_: impl Quux<Assoc=impl Foo<impl Bar>>) { }
+   |                                    ---------^^^^^^^^-
+   |                                    |        |
+   |                                    |        nested `impl Trait` here
+   |                                    outer `impl Trait`
+   |
+note: lint level defined here
+  --> $DIR/issue-57979-nested-impl-trait-in-assoc-proj.rs:27:13
+   |
+LL |     #![deny(nested_impl_trait)]
+   |             ^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #59014 <https://github.com/rust-lang/rust/issues/59014>
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-26448-1.rs b/src/test/ui/issues/issue-26448-1.rs
new file mode 100644 (file)
index 0000000..7d2d75b
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+
+pub trait Foo<T> {
+    fn foo(self) -> T;
+}
+
+impl<'a, T> Foo<T> for &'a str where &'a str: Into<T> {
+    fn foo(self) -> T {
+        panic!();
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-26448-2.rs b/src/test/ui/issues/issue-26448-2.rs
new file mode 100644 (file)
index 0000000..17e7c1f
--- /dev/null
@@ -0,0 +1,21 @@
+// run-pass
+
+pub struct Bar<T> {
+    items: Vec<&'static str>,
+    inner: T,
+}
+
+pub trait IntoBar<T> {
+    fn into_bar(self) -> Bar<T>;
+}
+
+impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> {
+    fn into_bar(self) -> Bar<T> {
+        Bar {
+            items: Vec::new(),
+            inner: self.into(),
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-26448-3.rs b/src/test/ui/issues/issue-26448-3.rs
new file mode 100644 (file)
index 0000000..e57352e
--- /dev/null
@@ -0,0 +1,25 @@
+// run-pass
+
+pub struct Item {
+    _inner: &'static str,
+}
+
+pub struct Bar<T> {
+    items: Vec<Item>,
+    inner: T,
+}
+
+pub trait IntoBar<T> {
+    fn into_bar(self) -> Bar<T>;
+}
+
+impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> {
+    fn into_bar(self) -> Bar<T> {
+        Bar {
+            items: Vec::new(),
+            inner: self.into(),
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-26619.nll.stderr b/src/test/ui/issues/issue-26619.nll.stderr
new file mode 100644 (file)
index 0000000..d1157cd
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0515]: cannot return value referencing function parameter
+  --> $DIR/issue-26619.rs:7:76
+   |
+LL |         for s in vec!["1|2".to_string()].into_iter().filter_map(|ref line| self.make_entry(line)) {
+   |                                                                  --------  ^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
+   |                                                                  |
+   |                                                                  function parameter borrowed here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0515`.
diff --git a/src/test/ui/issues/issue-26619.rs b/src/test/ui/issues/issue-26619.rs
new file mode 100644 (file)
index 0000000..cd89c67
--- /dev/null
@@ -0,0 +1,24 @@
+#![feature(slice_patterns)]
+
+pub struct History<'a> { pub _s: &'a str }
+
+impl<'a> History<'a> {
+    pub fn get_page(&self) {
+        for s in vec!["1|2".to_string()].into_iter().filter_map(|ref line| self.make_entry(line)) {
+            //~^ ERROR borrowed value does not live long enough
+            println!("{:?}", s);
+        }
+    }
+
+    fn make_entry(&self, s: &'a String) -> Option<&str> {
+        let parts: Vec<_> = s.split('|').collect();
+        println!("{:?} -> {:?}", s, parts);
+
+        if let [commit, ..] = &parts[..] { Some(commit) } else { None }
+    }
+}
+
+fn main() {
+    let h = History{ _s: "" };
+    h.get_page();
+}
diff --git a/src/test/ui/issues/issue-26619.stderr b/src/test/ui/issues/issue-26619.stderr
new file mode 100644 (file)
index 0000000..3ac6c4e
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/issue-26619.rs:7:66
+   |
+LL |         for s in vec!["1|2".to_string()].into_iter().filter_map(|ref line| self.make_entry(line)) {
+   |                                                                  ^^^^^^^^                      -- temporary value needs to live until here
+   |                                                                  |                             |
+   |                                                                  |                             temporary value dropped here while still borrowed
+   |                                                                  temporary value does not live long enough
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/issues/issue-44127.rs b/src/test/ui/issues/issue-44127.rs
new file mode 100644 (file)
index 0000000..21b2e68
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+
+#![feature(decl_macro)]
+
+pub struct Foo {
+    bar: u32,
+}
+pub macro pattern($a:pat) {
+    Foo { bar: $a }
+}
+
+fn main() {
+    match (Foo { bar: 3 }) {
+        pattern!(3) => println!("Test OK"),
+        _ => unreachable!(),
+    }
+}
diff --git a/src/test/ui/issues/issue-44255.rs b/src/test/ui/issues/issue-44255.rs
new file mode 100644 (file)
index 0000000..2245032
--- /dev/null
@@ -0,0 +1,29 @@
+// run-pass
+
+use std::marker::PhantomData;
+
+fn main() {
+    let _arr = [1; <Multiply<Five, Five>>::VAL];
+}
+
+trait TypeVal<T> {
+    const VAL: T;
+}
+
+struct Five;
+
+impl TypeVal<usize> for Five {
+    const VAL: usize = 5;
+}
+
+struct Multiply<N, M> {
+    _n: PhantomData<N>,
+    _m: PhantomData<M>,
+}
+
+impl<N, M> TypeVal<usize> for Multiply<N, M>
+    where N: TypeVal<usize>,
+          M: TypeVal<usize>,
+{
+    const VAL: usize = N::VAL * M::VAL;
+}
diff --git a/src/test/ui/issues/issue-46101.rs b/src/test/ui/issues/issue-46101.rs
new file mode 100644 (file)
index 0000000..2d9111e
--- /dev/null
@@ -0,0 +1,4 @@
+#![feature(use_extern_macros)]
+trait Foo {}
+#[derive(Foo::Anything)] //~ ERROR failed to resolve: partially resolved path in a derive macro
+struct S;
diff --git a/src/test/ui/issues/issue-46101.stderr b/src/test/ui/issues/issue-46101.stderr
new file mode 100644 (file)
index 0000000..3ad5383
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0433]: failed to resolve: partially resolved path in a derive macro
+  --> $DIR/issue-46101.rs:3:10
+   |
+LL | #[derive(Foo::Anything)]
+   |          ^^^^^^^^^^^^^ partially resolved path in a derive macro
+
+error[E0601]: `main` function not found in crate `issue_46101`
+   |
+   = note: consider adding a `main` function to `$DIR/issue-46101.rs`
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0433, E0601.
+For more information about an error, try `rustc --explain E0433`.
diff --git a/src/test/ui/issues/issue-55731.rs b/src/test/ui/issues/issue-55731.rs
new file mode 100644 (file)
index 0000000..7b4f4e2
--- /dev/null
@@ -0,0 +1,52 @@
+use std::marker::PhantomData;
+
+trait DistributedIterator {
+    fn reduce(self)
+    where
+        Self: Sized,
+    {
+        unreachable!()
+    }
+}
+
+trait DistributedIteratorMulti<Source> {
+    type Item;
+}
+
+struct Connect<I>(PhantomData<fn(I)>);
+impl<I: for<'a> DistributedIteratorMulti<&'a ()>> DistributedIterator for Connect<I> where {}
+
+struct Cloned<Source>(PhantomData<fn(Source)>);
+impl<'a, Source> DistributedIteratorMulti<&'a Source> for Cloned<&'a Source> {
+    type Item = ();
+}
+
+struct Map<I, F> {
+    i: I,
+    f: F,
+}
+impl<I: DistributedIteratorMulti<Source>, F, Source> DistributedIteratorMulti<Source> for Map<I, F>
+where
+    F: A<<I as DistributedIteratorMulti<Source>>::Item>,
+{
+    type Item = ();
+}
+
+trait A<B> {}
+
+struct X;
+impl A<()> for X {}
+
+fn multi<I>(_reducer: I)
+where
+    I: for<'a> DistributedIteratorMulti<&'a ()>,
+{
+    DistributedIterator::reduce(Connect::<I>(PhantomData))
+}
+
+fn main() {
+    multi(Map { //~ ERROR implementation of `DistributedIteratorMulti` is not general enough
+        i: Cloned(PhantomData),
+        f: X,
+    });
+}
diff --git a/src/test/ui/issues/issue-55731.stderr b/src/test/ui/issues/issue-55731.stderr
new file mode 100644 (file)
index 0000000..f25e18e
--- /dev/null
@@ -0,0 +1,11 @@
+error: implementation of `DistributedIteratorMulti` is not general enough
+  --> $DIR/issue-55731.rs:48:5
+   |
+LL |     multi(Map {
+   |     ^^^^^
+   |
+   = note: `DistributedIteratorMulti<&'0 ()>` would have to be implemented for the type `Cloned<&()>`, for any lifetime `'0`
+   = note: but `DistributedIteratorMulti<&'1 ()>` is actually implemented for the type `Cloned<&'1 ()>`, for some specific lifetime `'1`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/issues/issue-57781.rs b/src/test/ui/issues/issue-57781.rs
new file mode 100644 (file)
index 0000000..f5015aa
--- /dev/null
@@ -0,0 +1,20 @@
+// run-pass
+
+use std::cell::UnsafeCell;
+use std::collections::HashMap;
+
+struct OnceCell<T> {
+    _value: UnsafeCell<Option<T>>,
+}
+
+impl<T> OnceCell<T> {
+    const INIT: OnceCell<T> = OnceCell {
+        _value: UnsafeCell::new(None),
+    };
+}
+
+pub fn crash<K, T>() {
+    let _ = OnceCell::<HashMap<K, T>>::INIT;
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-57979.rs b/src/test/ui/issues/issue-57979.rs
deleted file mode 100644 (file)
index abd46b6..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// Regression test for #57979. This situation is meant to be an error.
-// As noted in the issue thread, we decided to forbid nested impl
-// trait of this kind:
-//
-// ```rust
-// fn foo() -> impl Foo<impl Bar> { .. }
-// ```
-//
-// Basically there are two hidden variables here, let's call them `X`
-// and `Y`, and we must prove that:
-//
-// ```
-// X: Foo<Y>
-// Y: Bar
-// ```
-//
-// However, the user is only giving us the return type `X`. It's true
-// that in some cases, we can infer `Y` from `X`, because `X` only
-// implements `Foo` for one type (and indeed the compiler does
-// inference of this kind), but I do recall that we intended to forbid
-// this -- in part because such inference is fragile, and there is not
-// necessarily a way for the user to be more explicit should the
-// inference fail (so you could get stuck with no way to port your
-// code forward if, for example, more impls are added to an existing
-// type).
-//
-// The same seems to apply in this situation. Here there are three impl traits, so we have
-//
-// ```
-// X: IntoIterator<Item = Y>
-// Y: Borrow<Data<Z>>
-// Z: AsRef<[u8]>
-// ```
-
-use std::borrow::Borrow;
-
-pub struct Data<TBody>(TBody);
-
-pub fn collect(_: impl IntoIterator<Item = impl Borrow<Data<impl AsRef<[u8]>>>>) {
-    //~^ ERROR
-    unimplemented!()
-}
diff --git a/src/test/ui/issues/issue-57979.stderr b/src/test/ui/issues/issue-57979.stderr
deleted file mode 100644 (file)
index 488f30a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0666]: nested `impl Trait` is not allowed
-  --> $DIR/issue-57979.rs:39:61
-   |
-LL | pub fn collect(_: impl IntoIterator<Item = impl Borrow<Data<impl AsRef<[u8]>>>>) {
-   |                                            -----------------^^^^^^^^^^^^^^^^--
-   |                                            |                |
-   |                                            |                nested `impl Trait` here
-   |                                            outer `impl Trait`
-
-error[E0601]: `main` function not found in crate `issue_57979`
-   |
-   = note: consider adding a `main` function to `$DIR/issue-57979.rs`
-
-error: aborting due to 2 previous errors
-
-Some errors occurred: E0601, E0666.
-For more information about an error, try `rustc --explain E0601`.
index 9d3e1a690f001a1eea337a9c4a811448420ba3f2..31dc58185e90ab0bb38d941c68c74915e785438d 100644 (file)
@@ -9,24 +9,23 @@ trait Anything<'a: 'b, 'b> {
     const AC: Option<&'b str>;
 }
 
-struct OKStruct { }
+struct OKStruct1 { }
 
-impl<'a: 'b, 'b> Anything<'a, 'b> for OKStruct {
+impl<'a: 'b, 'b> Anything<'a, 'b> for OKStruct1 {
     const AC: Option<&'b str> = None;
 }
 
-struct FailStruct1 { }
+struct FailStruct { }
 
-impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 {
+impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct {
     const AC: Option<&'c str> = None;
     //~^ ERROR: mismatched types
 }
 
-struct FailStruct2 { }
+struct OKStruct2 { }
 
-impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 {
+impl<'a: 'b, 'b> Anything<'a, 'b> for OKStruct2 {
     const AC: Option<&'a str> = None;
-    //~^ ERROR: mismatched types
 }
 
 fn main() {}
index 78ef513f3eecb6dced2bba98c842957866d58826..f39f668e2329a5c61ad69b7eb5008321335e29a9 100644 (file)
@@ -9,33 +9,14 @@ LL |     const AC: Option<&'c str> = None;
 note: the lifetime 'c as defined on the impl at 20:18...
   --> $DIR/trait-associated-constant.rs:20:18
    |
-LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 {
+LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct {
    |                  ^^
 note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 20:14
   --> $DIR/trait-associated-constant.rs:20:14
    |
-LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 {
+LL | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct {
    |              ^^
 
-error[E0308]: mismatched types
-  --> $DIR/trait-associated-constant.rs:28:5
-   |
-LL |     const AC: Option<&'a str> = None;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
-   |
-   = note: expected type `std::option::Option<&'b str>`
-              found type `std::option::Option<&'a str>`
-note: the lifetime 'a as defined on the impl at 27:6...
-  --> $DIR/trait-associated-constant.rs:27:6
-   |
-LL | impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 {
-   |      ^^
-note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 27:14
-  --> $DIR/trait-associated-constant.rs:27:14
-   |
-LL | impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 {
-   |              ^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/numeric-lifetime.rs b/src/test/ui/parser/numeric-lifetime.rs
new file mode 100644 (file)
index 0000000..2d82354
--- /dev/null
@@ -0,0 +1,8 @@
+struct S<'1> { s: &'1 usize }
+//~^ ERROR lifetimes cannot start with a number
+//~| ERROR lifetimes cannot start with a number
+fn main() {
+    // verify that the parse error doesn't stop type checking
+    let x: usize = "";
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/parser/numeric-lifetime.stderr b/src/test/ui/parser/numeric-lifetime.stderr
new file mode 100644 (file)
index 0000000..4018b24
--- /dev/null
@@ -0,0 +1,24 @@
+error: lifetimes cannot start with a number
+  --> $DIR/numeric-lifetime.rs:1:10
+   |
+LL | struct S<'1> { s: &'1 usize }
+   |          ^^
+
+error: lifetimes cannot start with a number
+  --> $DIR/numeric-lifetime.rs:1:20
+   |
+LL | struct S<'1> { s: &'1 usize }
+   |                    ^^
+
+error[E0308]: mismatched types
+  --> $DIR/numeric-lifetime.rs:6:20
+   |
+LL |     let x: usize = "";
+   |                    ^^ expected usize, found reference
+   |
+   = note: expected type `usize`
+              found type `&'static str`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/primitive-binop-lhs-mut.rs b/src/test/ui/primitive-binop-lhs-mut.rs
new file mode 100644 (file)
index 0000000..4f1c456
--- /dev/null
@@ -0,0 +1,6 @@
+// run-pass
+
+fn main() {
+    let x = Box::new(0);
+    assert_eq!(0, *x + { drop(x); let _ = Box::new(main); 0 });
+}
index 6b3117a1f74f473b2fda9b325dc236f13ca00fc2..f0991c8cdb5477f827c91388a5c52f570ab4147d 100644 (file)
@@ -24,6 +24,7 @@ pub enum Mode {
     Incremental,
     RunMake,
     Ui,
+    JsDocTest,
     MirOpt,
 }
 
@@ -59,6 +60,7 @@ fn from_str(s: &str) -> Result<Mode, ()> {
             "incremental" => Ok(Incremental),
             "run-make" => Ok(RunMake),
             "ui" => Ok(Ui),
+            "js-doc-test" => Ok(JsDocTest),
             "mir-opt" => Ok(MirOpt),
             _ => Err(()),
         }
@@ -82,6 +84,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             Incremental => "incremental",
             RunMake => "run-make",
             Ui => "ui",
+            JsDocTest => "js-doc-test",
             MirOpt => "mir-opt",
         };
         fmt::Display::fmt(s, f)
index 68ecc0527bc7c326941e765f74db9bc774991f37..84dd671fa7ddb1e1902672ed9f284cd13fd441c3 100644 (file)
@@ -4,7 +4,7 @@
 use crate::common::{Codegen, CodegenUnits, DebugInfoBoth, DebugInfoGdb, DebugInfoLldb, Rustdoc};
 use crate::common::{CompileFail, Pretty, RunFail, RunPass, RunPassValgrind};
 use crate::common::{Config, TestPaths};
-use crate::common::{Incremental, MirOpt, RunMake, Ui};
+use crate::common::{Incremental, MirOpt, RunMake, Ui, JsDocTest};
 use diff;
 use crate::errors::{self, Error, ErrorKind};
 use filetime::FileTime;
@@ -275,6 +275,7 @@ fn run_revision(&self) {
             RunMake => self.run_rmake_test(),
             RunPass | Ui => self.run_ui_test(),
             MirOpt => self.run_mir_opt_test(),
+            JsDocTest => self.run_js_doc_test(),
         }
     }
 
@@ -291,6 +292,7 @@ fn should_compile_successfully(&self) -> bool {
         match self.config.mode {
             CompileFail => self.props.compile_pass,
             RunPass => true,
+            JsDocTest => true,
             Ui => self.props.compile_pass,
             Incremental => {
                 let revision = self.revision
@@ -1712,7 +1714,8 @@ fn compose_and_run(
     }
 
     fn make_compile_args(&self, input_file: &Path, output_file: TargetLocation) -> Command {
-        let is_rustdoc = self.config.src_base.ends_with("rustdoc-ui");
+        let is_rustdoc = self.config.src_base.ends_with("rustdoc-ui") ||
+                         self.config.src_base.ends_with("rustdoc-js");
         let mut rustc = if !is_rustdoc {
             Command::new(&self.config.rustc_path)
         } else {
@@ -1802,7 +1805,7 @@ fn make_compile_args(&self, input_file: &Path, output_file: TargetLocation) -> C
                 rustc.arg(dir_opt);
             }
             RunFail | RunPassValgrind | Pretty | DebugInfoBoth | DebugInfoGdb | DebugInfoLldb
-            | Codegen | Rustdoc | RunMake | CodegenUnits => {
+            | Codegen | Rustdoc | RunMake | CodegenUnits | JsDocTest => {
                 // do not use JSON output
             }
         }
@@ -2710,6 +2713,27 @@ fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> {
         fs::remove_dir(path)
     }
 
+    fn run_js_doc_test(&self) {
+        if let Some(nodejs) = &self.config.nodejs {
+            let out_dir = self.output_base_dir();
+
+            self.document(&out_dir);
+
+            let root = self.config.find_rust_src_root().unwrap();
+            let res = self.cmd2procres(
+                Command::new(&nodejs)
+                    .arg(root.join("src/tools/rustdoc-js/tester.js"))
+                    .arg(out_dir.parent().expect("no parent"))
+                    .arg(&self.testpaths.file.file_stem().expect("couldn't get file stem")),
+            );
+            if !res.status.success() {
+                self.fatal_proc_rec("rustdoc-js test failed!", &res);
+            }
+        } else {
+            self.fatal("no nodeJS");
+        }
+    }
+
     fn run_ui_test(&self) {
         // if the user specified a format in the ui test
         // print the output to the stderr file, otherwise extract
diff --git a/src/tools/rustdoc-js-std/tester.js b/src/tools/rustdoc-js-std/tester.js
new file mode 100644 (file)
index 0000000..d5f0ab9
--- /dev/null
@@ -0,0 +1,344 @@
+const fs = require('fs');
+
+const TEST_FOLDER = 'src/test/rustdoc-js-std/';
+
+function getNextStep(content, pos, stop) {
+    while (pos < content.length && content[pos] !== stop &&
+           (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) {
+        pos += 1;
+    }
+    if (pos >= content.length) {
+        return null;
+    }
+    if (content[pos] !== stop) {
+        return pos * -1;
+    }
+    return pos;
+}
+
+// Stupid function extractor based on indent. Doesn't support block
+// comments. If someone puts a ' or an " in a block comment this
+// will blow up. Template strings are not tested and might also be
+// broken.
+function extractFunction(content, functionName) {
+    var indent = 0;
+    var splitter = "function " + functionName + "(";
+
+    while (true) {
+        var start = content.indexOf(splitter);
+        if (start === -1) {
+            break;
+        }
+        var pos = start;
+        while (pos < content.length && content[pos] !== ')') {
+            pos += 1;
+        }
+        if (pos >= content.length) {
+            break;
+        }
+        pos = getNextStep(content, pos + 1, '{');
+        if (pos === null) {
+            break;
+        } else if (pos < 0) {
+            content = content.slice(-pos);
+            continue;
+        }
+        while (pos < content.length) {
+            // Eat single-line comments
+            if (content[pos] === '/' && pos > 0 && content[pos-1] === '/') {
+                do {
+                    pos += 1;
+                } while (pos < content.length && content[pos] !== '\n');
+
+            // Eat quoted strings
+            } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
+                var stop = content[pos];
+                var is_escaped = false;
+                do {
+                    if (content[pos] === '\\') {
+                        pos += 2;
+                    } else {
+                        pos += 1;
+                    }
+                } while (pos < content.length &&
+                         (content[pos] !== stop || content[pos - 1] === '\\'));
+
+            // Otherwise, check for indent
+            } else if (content[pos] === '{') {
+                indent += 1;
+            } else if (content[pos] === '}') {
+                indent -= 1;
+                if (indent === 0) {
+                    return content.slice(start, pos + 1);
+                }
+            }
+            pos += 1;
+        }
+        content = content.slice(start + 1);
+    }
+    return null;
+}
+
+// Stupid function extractor for array.
+function extractArrayVariable(content, arrayName) {
+    var splitter = "var " + arrayName;
+    while (true) {
+        var start = content.indexOf(splitter);
+        if (start === -1) {
+            break;
+        }
+        var pos = getNextStep(content, start, '=');
+        if (pos === null) {
+            break;
+        } else if (pos < 0) {
+            content = content.slice(-pos);
+            continue;
+        }
+        pos = getNextStep(content, pos, '[');
+        if (pos === null) {
+            break;
+        } else if (pos < 0) {
+            content = content.slice(-pos);
+            continue;
+        }
+        while (pos < content.length) {
+            if (content[pos] === '"' || content[pos] === "'") {
+                var stop = content[pos];
+                do {
+                    if (content[pos] === '\\') {
+                        pos += 2;
+                    } else {
+                        pos += 1;
+                    }
+                } while (pos < content.length &&
+                         (content[pos] !== stop || content[pos - 1] === '\\'));
+            } else if (content[pos] === ']' &&
+                       pos + 1 < content.length &&
+                       content[pos + 1] === ';') {
+                return content.slice(start, pos + 2);
+            }
+            pos += 1;
+        }
+        content = content.slice(start + 1);
+    }
+    return null;
+}
+
+// Stupid function extractor for variable.
+function extractVariable(content, varName) {
+    var splitter = "var " + varName;
+    while (true) {
+        var start = content.indexOf(splitter);
+        if (start === -1) {
+            break;
+        }
+        var pos = getNextStep(content, start, '=');
+        if (pos === null) {
+            break;
+        } else if (pos < 0) {
+            content = content.slice(-pos);
+            continue;
+        }
+        while (pos < content.length) {
+            if (content[pos] === '"' || content[pos] === "'") {
+                var stop = content[pos];
+                do {
+                    if (content[pos] === '\\') {
+                        pos += 2;
+                    } else {
+                        pos += 1;
+                    }
+                } while (pos < content.length &&
+                         (content[pos] !== stop || content[pos - 1] === '\\'));
+            } else if (content[pos] === ';') {
+                return content.slice(start, pos + 1);
+            }
+            pos += 1;
+        }
+        content = content.slice(start + 1);
+    }
+    return null;
+}
+
+function loadContent(content) {
+    var Module = module.constructor;
+    var m = new Module();
+    m._compile(content, "tmp.js");
+    m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1 ||
+        content.startsWith("// ignore-order\n");
+    m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1 ||
+        content.startsWith("// exact-check\n");
+    m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1 ||
+        content.startsWith("// should-fail\n");
+    return m.exports;
+}
+
+function readFile(filePath) {
+    return fs.readFileSync(filePath, 'utf8');
+}
+
+function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) {
+    var content = '';
+    for (var i = 0; i < thingsToLoad.length; ++i) {
+        var tmp = funcToCall(fileContent, thingsToLoad[i]);
+        if (tmp === null) {
+            console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
+            process.exit(1);
+        }
+        content += tmp;
+        content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';';
+    }
+    return content;
+}
+
+function lookForEntry(entry, data) {
+    for (var i = 0; i < data.length; ++i) {
+        var allGood = true;
+        for (var key in entry) {
+            if (!entry.hasOwnProperty(key)) {
+                continue;
+            }
+            var value = data[i][key];
+            // To make our life easier, if there is a "parent" type, we add it to the path.
+            if (key === 'path' && data[i]['parent'] !== undefined) {
+                if (value.length > 0) {
+                    value += '::' + data[i]['parent']['name'];
+                } else {
+                    value = data[i]['parent']['name'];
+                }
+            }
+            if (value !== entry[key]) {
+                allGood = false;
+                break;
+            }
+        }
+        if (allGood === true) {
+            return i;
+        }
+    }
+    return null;
+}
+
+function findFile(dir, name, extension) {
+    var entries = fs.readdirSync(dir);
+    for (var i = 0; i < entries.length; ++i) {
+        var entry = entries[i];
+        var file_type = fs.statSync(dir + entry);
+        if (file_type.isDirectory()) {
+            continue;
+        }
+        if (entry.startsWith(name) && entry.endsWith(extension)) {
+            return entry;
+        }
+    }
+    return null;
+}
+
+function readFileMatching(dir, name, extension) {
+    if (dir.endsWith("/") === false) {
+        dir += "/";
+    }
+    var f = findFile(dir, name, extension);
+    if (f === null) {
+        return "";
+    }
+    return readFile(dir + f);
+}
+
+function main(argv) {
+    if (argv.length !== 3) {
+        console.error("Expected toolchain to check as argument (for example \
+                       'x86_64-apple-darwin')");
+        return 1;
+    }
+    var toolchain = argv[2];
+
+    var mainJs = readFileMatching("build/" + toolchain + "/doc/", "main", ".js");
+    var ALIASES = readFileMatching("build/" + toolchain + "/doc/", "aliases", ".js");
+    var searchIndex = readFileMatching("build/" + toolchain + "/doc/",
+                                       "search-index", ".js").split("\n");
+    if (searchIndex[searchIndex.length - 1].length === 0) {
+        searchIndex.pop();
+    }
+    searchIndex.pop();
+    searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;');
+    finalJS = "";
+
+    var arraysToLoad = ["itemTypes"];
+    var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS",
+                           "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA",
+                           "TY_PRIMITIVE", "TY_KEYWORD",
+                           "levenshtein_row2"];
+    // execQuery first parameter is built in getQuery (which takes in the search input).
+    // execQuery last parameter is built in buildIndex.
+    // buildIndex requires the hashmap from search-index.
+    var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
+                           "getQuery", "buildIndex", "execQuery", "execSearch"];
+
+    finalJS += 'window = { "currentCrate": "std" };\n';
+    finalJS += 'var rootPath = "../";\n';
+    finalJS += ALIASES;
+    finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
+    finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
+    finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);
+
+    var loaded = loadContent(finalJS);
+    var index = loaded.buildIndex(searchIndex.searchIndex);
+
+    var errors = 0;
+
+    fs.readdirSync(TEST_FOLDER).forEach(function(file) {
+        var loadedFile = loadContent(readFile(TEST_FOLDER + file) +
+                               'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
+        const expected = loadedFile.EXPECTED;
+        const query = loadedFile.QUERY;
+        const filter_crate = loadedFile.FILTER_CRATE;
+        const ignore_order = loadedFile.ignore_order;
+        const exact_check = loadedFile.exact_check;
+        const should_fail = loadedFile.should_fail;
+        var results = loaded.execSearch(loaded.getQuery(query), index);
+        process.stdout.write('Checking "' + file + '" ... ');
+        var error_text = [];
+        for (var key in expected) {
+            if (!expected.hasOwnProperty(key)) {
+                continue;
+            }
+            if (!results.hasOwnProperty(key)) {
+                error_text.push('==> Unknown key "' + key + '"');
+                break;
+            }
+            var entry = expected[key];
+            var prev_pos = -1;
+            for (var i = 0; i < entry.length; ++i) {
+                var entry_pos = lookForEntry(entry[i], results[key]);
+                if (entry_pos === null) {
+                    error_text.push("==> Result not found in '" + key + "': '" +
+                                    JSON.stringify(entry[i]) + "'");
+                } else if (exact_check === true && prev_pos + 1 !== entry_pos) {
+                    error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " +
+                                    "expected '" + JSON.stringify(entry[i]) + "' but found '" +
+                                    JSON.stringify(results[key][i]) + "'");
+                } else if (ignore_order === false && entry_pos < prev_pos) {
+                    error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " +
+                                    " before '" + JSON.stringify(results[key][entry_pos]) + "'");
+                } else {
+                    prev_pos = entry_pos;
+                }
+            }
+        }
+        if (error_text.length === 0 && should_fail === true) {
+            errors += 1;
+            console.error("FAILED");
+            console.error("==> Test was supposed to fail but all items were found...");
+        } else if (error_text.length !== 0 && should_fail === false) {
+            errors += 1;
+            console.error("FAILED");
+            console.error(error_text.join("\n"));
+        } else {
+            console.log("OK");
+        }
+    });
+    return errors;
+}
+
+process.exit(main(process.argv));
index c41da93a9831026d90420c234c3c95f548cdfab3..833ce5d1370471f8544f8d23353477abc5f80c37 100644 (file)
@@ -1,4 +1,5 @@
 const fs = require('fs');
+const { spawnSync } = require('child_process');
 
 const TEST_FOLDER = 'src/test/rustdoc-js/';
 
@@ -219,16 +220,10 @@ function lookForEntry(entry, data) {
     return null;
 }
 
-function main(argv) {
-    if (argv.length !== 3) {
-        console.error("Expected toolchain to check as argument (for example 'x86_64-apple-darwin'");
-        return 1;
-    }
-    var toolchain = argv[2];
-
-    var mainJs = readFile("build/" + toolchain + "/doc/main.js");
-    var ALIASES = readFile("build/" + toolchain + "/doc/aliases.js");
-    var searchIndex = readFile("build/" + toolchain + "/doc/search-index.js").split("\n");
+function load_files(out_folder, crate) {
+    var mainJs = readFile(out_folder + "/main.js");
+    var ALIASES = readFile(out_folder + "/aliases.js");
+    var searchIndex = readFile(out_folder + "/search-index.js").split("\n");
     if (searchIndex[searchIndex.length - 1].length === 0) {
         searchIndex.pop();
     }
@@ -247,7 +242,7 @@ function main(argv) {
     var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
                            "getQuery", "buildIndex", "execQuery", "execSearch"];
 
-    finalJS += 'window = { "currentCrate": "std" };\n';
+    finalJS += 'window = { "currentCrate": "' + crate + '" };\n';
     finalJS += 'var rootPath = "../";\n';
     finalJS += ALIASES;
     finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
@@ -255,12 +250,36 @@ function main(argv) {
     finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);
 
     var loaded = loadContent(finalJS);
-    var index = loaded.buildIndex(searchIndex.searchIndex);
+    return [loaded, loaded.buildIndex(searchIndex.searchIndex)];
+}
+
+function main(argv) {
+    if (argv.length < 4) {
+        console.error("USAGE: node tester.js OUT_FOLDER [TESTS]");
+        return 1;
+    }
+    if (argv[2].substr(-1) !== "/") {
+        argv[2] += "/";
+    }
+    const out_folder = argv[2];
 
     var errors = 0;
 
-    fs.readdirSync(TEST_FOLDER).forEach(function(file) {
-        var loadedFile = loadContent(readFile(TEST_FOLDER + file) +
+    for (var j = 3; j < argv.length; ++j) {
+        const test_name = argv[j];
+
+        process.stdout.write('Checking "' + test_name + '" ... ');
+        if (!fs.existsSync(TEST_FOLDER + test_name + ".js")) {
+            errors += 1;
+            console.error("FAILED");
+            console.error("==> Missing '" + test_name + ".js' file...");
+            continue;
+        }
+
+        const test_out_folder = out_folder + test_name;
+
+        var [loaded, index] = load_files(test_out_folder, test_name);
+        var loadedFile = loadContent(readFile(TEST_FOLDER + test_name + ".js") +
                                'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
         const expected = loadedFile.EXPECTED;
         const query = loadedFile.QUERY;
@@ -269,7 +288,6 @@ function main(argv) {
         const exact_check = loadedFile.exact_check;
         const should_fail = loadedFile.should_fail;
         var results = loaded.execSearch(loaded.getQuery(query), index);
-        process.stdout.write('Checking "' + file + '" ... ');
         var error_text = [];
         for (var key in expected) {
             if (!expected.hasOwnProperty(key)) {
@@ -309,7 +327,7 @@ function main(argv) {
         } else {
             console.log("OK");
         }
-    });
+    }
     return errors;
 }