]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #53455 - llogiq:num-byte-conversion-docs, r=steveklabnik
authorkennytm <kennytm@gmail.com>
Fri, 7 Sep 2018 05:47:07 +0000 (13:47 +0800)
committerkennytm <kennytm@gmail.com>
Fri, 7 Sep 2018 07:26:37 +0000 (15:26 +0800)
Individual docs for {from,to}_*_bytes

61 files changed:
.gitmodules
.travis.yml
src/bootstrap/dist.rs
src/liballoc/tests/str.rs
src/libcompiler_builtins
src/libcore/macros.rs
src/libcore/str/mod.rs
src/librustc/ich/hcx.rs
src/librustc/ich/impls_ty.rs
src/librustc/mir/interpret/mod.rs
src/librustc/mir/interpret/value.rs
src/librustc/ty/mod.rs
src/librustc_codegen_llvm/back/lto.rs
src/librustc_codegen_llvm/back/write.rs
src/librustc_data_structures/stable_hasher.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/type_check/mod.rs
src/librustc_mir/const_eval.rs
src/librustc_mir/hair/pattern/_match.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/machine.rs
src/librustc_mir/interpret/memory.rs
src/librustc_mir/interpret/mod.rs
src/librustc_mir/interpret/operand.rs
src/librustc_mir/interpret/place.rs
src/librustc_mir/interpret/snapshot.rs [new file with mode: 0644]
src/librustc_mir/interpret/step.rs
src/librustc_privacy/lib.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/collect.rs
src/librustdoc/clean/mod.rs
src/libstd/fs.rs
src/libstd/io/util.rs
src/test/run-pass/redundant.rs [new file with mode: 0644]
src/test/run-pass/rfc-2008-non-exhaustive/enums.rs
src/test/ui/chalkify/lower_trait_where_clause.rs
src/test/ui/chalkify/lower_trait_where_clause.stderr
src/test/ui/consts/const-eval/issue-52475.rs [new file with mode: 0644]
src/test/ui/consts/const-eval/issue-52475.stderr [new file with mode: 0644]
src/test/ui/dst/dst-index.nll.stderr
src/test/ui/dst/dst-rvalue.nll.stderr
src/test/ui/error-codes/E0161.ast.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0161.astul.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0161.edition.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0161.editionul.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0161.nll.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0161.nllul.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0161.rs
src/test/ui/error-codes/E0161.zflags.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0161.zflagsul.stderr [new file with mode: 0644]
src/test/ui/rust-2018/uniform-paths/redundant.rs [deleted file]
src/test/ui/rust-2018/uniform-paths/redundant.stderr [deleted file]
src/test/ui/wf/wf-fn-where-clause.rs
src/test/ui/wf/wf-fn-where-clause.stderr
src/tools/clang
src/tools/lldb

index 1631daac76c2ce07b0cc807666e4f2287a9bcfa8..5753e9ed45eda9532f5d1fbc2a78d96c0abe49c9 100644 (file)
@@ -59,8 +59,8 @@
 [submodule "src/tools/lldb"]
        path = src/tools/lldb
        url = https://github.com/rust-lang-nursery/lldb/
-       branch = rust-release-70
+       branch = rust-release-80-v1
 [submodule "src/tools/clang"]
        path = src/tools/clang
        url = https://github.com/rust-lang-nursery/clang/
-       branch = release_70
+       branch = rust-release-80-v1
index 4a7c8f4b7cf41ff835111109689578aaedb56e21..b1701e4a65451aa82205f0c1af1211ef3e007ae2 100644 (file)
@@ -30,7 +30,7 @@ matrix:
 
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler"
+        RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler --enable-lldb"
         SRC=.
         DEPLOY_ALT=1
         RUSTC_RETRY_LINKER_ON_SEGFAULT=1
@@ -87,7 +87,7 @@ matrix:
     # OSX 10.7 and `xcode7` is the latest Xcode able to compile LLVM for 10.7.
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-full-tools --enable-profiler"
+        RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-full-tools --enable-profiler --enable-lldb"
         SRC=.
         DEPLOY=1
         RUSTC_RETRY_LINKER_ON_SEGFAULT=1
@@ -101,7 +101,7 @@ matrix:
 
     - env: >
         RUST_CHECK_TARGET=dist
-        RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler"
+        RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --enable-lldb"
         SRC=.
         DEPLOY=1
         RUSTC_RETRY_LINKER_ON_SEGFAULT=1
index 92c0a088b5eefbdb3ca0213f29da034e35d7529c..c3282275f6fd48969cf35df75113b5a946189f88 100644 (file)
@@ -1913,7 +1913,7 @@ fn maybe_install_llvm_dylib(builder: &Builder,
                    llvm_dylib_path.display(), e);
         });
 
-        let dst_libdir = image.join("lib");
+        let dst_libdir = image.join("lib/rustlib").join(&*target).join("lib");
         t!(fs::create_dir_all(&dst_libdir));
 
         builder.install(&llvm_dylib_path, &dst_libdir, 0o644);
@@ -1967,7 +1967,9 @@ fn run(self, builder: &Builder) -> Option<PathBuf> {
         let src_bindir = builder
             .llvm_out(target)
             .join("bin");
-        let dst_bindir = image.join("bin");
+        let dst_bindir = image.join("lib/rustlib")
+            .join(&*target)
+            .join("bin");
         t!(fs::create_dir_all(&dst_bindir));
         for tool in LLVM_TOOLS {
             let exe = src_bindir.join(exe(tool, &target));
index 6275c7bb112063dc2205fc75698a7d6f7b8d3ba1..a5fa7f0c4d938a96332bc64bf6ee64ad528698a8 100644 (file)
@@ -727,33 +727,33 @@ fn test_is_char_boundary() {
 }
 
 #[test]
-fn test_trim_left_matches() {
+fn test_trim_start_matches() {
     let v: &[char] = &[];
-    assert_eq!(" *** foo *** ".trim_left_matches(v), " *** foo *** ");
+    assert_eq!(" *** foo *** ".trim_start_matches(v), " *** foo *** ");
     let chars: &[char] = &['*', ' '];
-    assert_eq!(" *** foo *** ".trim_left_matches(chars), "foo *** ");
-    assert_eq!(" ***  *** ".trim_left_matches(chars), "");
-    assert_eq!("foo *** ".trim_left_matches(chars), "foo *** ");
+    assert_eq!(" *** foo *** ".trim_start_matches(chars), "foo *** ");
+    assert_eq!(" ***  *** ".trim_start_matches(chars), "");
+    assert_eq!("foo *** ".trim_start_matches(chars), "foo *** ");
 
-    assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
+    assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11");
     let chars: &[char] = &['1', '2'];
-    assert_eq!("12foo1bar12".trim_left_matches(chars), "foo1bar12");
-    assert_eq!("123foo1bar123".trim_left_matches(|c: char| c.is_numeric()), "foo1bar123");
+    assert_eq!("12foo1bar12".trim_start_matches(chars), "foo1bar12");
+    assert_eq!("123foo1bar123".trim_start_matches(|c: char| c.is_numeric()), "foo1bar123");
 }
 
 #[test]
-fn test_trim_right_matches() {
+fn test_trim_end_matches() {
     let v: &[char] = &[];
-    assert_eq!(" *** foo *** ".trim_right_matches(v), " *** foo *** ");
+    assert_eq!(" *** foo *** ".trim_end_matches(v), " *** foo *** ");
     let chars: &[char] = &['*', ' '];
-    assert_eq!(" *** foo *** ".trim_right_matches(chars), " *** foo");
-    assert_eq!(" ***  *** ".trim_right_matches(chars), "");
-    assert_eq!(" *** foo".trim_right_matches(chars), " *** foo");
+    assert_eq!(" *** foo *** ".trim_end_matches(chars), " *** foo");
+    assert_eq!(" ***  *** ".trim_end_matches(chars), "");
+    assert_eq!(" *** foo".trim_end_matches(chars), " *** foo");
 
-    assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
+    assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar");
     let chars: &[char] = &['1', '2'];
-    assert_eq!("12foo1bar12".trim_right_matches(chars), "12foo1bar");
-    assert_eq!("123foo1bar123".trim_right_matches(|c: char| c.is_numeric()), "123foo1bar");
+    assert_eq!("12foo1bar12".trim_end_matches(chars), "12foo1bar");
+    assert_eq!("123foo1bar123".trim_end_matches(|c: char| c.is_numeric()), "123foo1bar");
 }
 
 #[test]
@@ -772,23 +772,23 @@ fn test_trim_matches() {
 }
 
 #[test]
-fn test_trim_left() {
-    assert_eq!("".trim_left(), "");
-    assert_eq!("a".trim_left(), "a");
-    assert_eq!("    ".trim_left(), "");
-    assert_eq!("     blah".trim_left(), "blah");
-    assert_eq!("   \u{3000}  wut".trim_left(), "wut");
-    assert_eq!("hey ".trim_left(), "hey ");
+fn test_trim_start() {
+    assert_eq!("".trim_start(), "");
+    assert_eq!("a".trim_start(), "a");
+    assert_eq!("    ".trim_start(), "");
+    assert_eq!("     blah".trim_start(), "blah");
+    assert_eq!("   \u{3000}  wut".trim_start(), "wut");
+    assert_eq!("hey ".trim_start(), "hey ");
 }
 
 #[test]
-fn test_trim_right() {
-    assert_eq!("".trim_right(), "");
-    assert_eq!("a".trim_right(), "a");
-    assert_eq!("    ".trim_right(), "");
-    assert_eq!("blah     ".trim_right(), "blah");
-    assert_eq!("wut   \u{3000}  ".trim_right(), "wut");
-    assert_eq!(" hey".trim_right(), " hey");
+fn test_trim_end() {
+    assert_eq!("".trim_end(), "");
+    assert_eq!("a".trim_end(), "a");
+    assert_eq!("    ".trim_end(), "");
+    assert_eq!("blah     ".trim_end(), "blah");
+    assert_eq!("wut   \u{3000}  ".trim_end(), "wut");
+    assert_eq!(" hey".trim_end(), " hey");
 }
 
 #[test]
@@ -1518,12 +1518,20 @@ fn trim_ws() {
                     "a \t  ");
     assert_eq!(" \t  a \t  ".trim_right_matches(|c: char| c.is_whitespace()),
                " \t  a");
+    assert_eq!(" \t  a \t  ".trim_start_matches(|c: char| c.is_whitespace()),
+                    "a \t  ");
+    assert_eq!(" \t  a \t  ".trim_end_matches(|c: char| c.is_whitespace()),
+               " \t  a");
     assert_eq!(" \t  a \t  ".trim_matches(|c: char| c.is_whitespace()),
                     "a");
     assert_eq!(" \t   \t  ".trim_left_matches(|c: char| c.is_whitespace()),
                          "");
     assert_eq!(" \t   \t  ".trim_right_matches(|c: char| c.is_whitespace()),
                "");
+    assert_eq!(" \t   \t  ".trim_start_matches(|c: char| c.is_whitespace()),
+                         "");
+    assert_eq!(" \t   \t  ".trim_end_matches(|c: char| c.is_whitespace()),
+               "");
     assert_eq!(" \t   \t  ".trim_matches(|c: char| c.is_whitespace()),
                "");
 }
index f3a13eb2384c7cbb91b6db5b008377e9710d434c..0703bfa72524e01e414477657ca9b64794c5c1c3 160000 (submodule)
@@ -1 +1 @@
-Subproject commit f3a13eb2384c7cbb91b6db5b008377e9710d434c
+Subproject commit 0703bfa72524e01e414477657ca9b64794c5c1c3
index 0032bedc7ed1de518390c363f30171a5900cc274..a0c87f13e5d5a4debd4b5ad1728f3ffb2a320c3e 100644 (file)
@@ -349,6 +349,26 @@ macro_rules! try {
 /// write!(&mut v, "s = {:?}", s).unwrap(); // uses io::Write::write_fmt
 /// assert_eq!(v, b"s = \"abc 123\"");
 /// ```
+///
+/// Note: This macro can be used in `no_std` setups as well
+/// In a `no_std` setup you are responsible for the
+/// implementation details of the components.
+///
+/// ```no_run
+/// # extern crate core;
+/// use core::fmt::Write;
+///
+/// struct Example;
+///
+/// impl Write for Example {
+///     fn write_str(&mut self, _s: &str) -> core::fmt::Result {
+///          unimplemented!();
+///     }
+/// }
+///
+/// let mut m = Example{};
+/// write!(&mut m, "Hello World").expect("Not written");
+/// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 macro_rules! write {
index 4dcb65dc3f8443bde17fb5f3d4dd9fab72377610..2c941c28d4b80e938583864558c399e7a10f7ab2 100644 (file)
@@ -3563,6 +3563,76 @@ pub fn trim(&self) -> &str {
         self.trim_matches(|c: char| c.is_whitespace())
     }
 
+    /// Returns a string slice with leading whitespace removed.
+    ///
+    /// 'Whitespace' is defined according to the terms of the Unicode Derived
+    /// Core Property `White_Space`.
+    ///
+    /// # Text directionality
+    ///
+    /// A string is a sequence of bytes. `start` in this context means the first
+    /// position of that byte string; for a left-to-right language like English or
+    /// Russian, this will be left side; and for right-to-left languages like
+    /// like Arabic or Hebrew, this will be the right side.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// let s = " Hello\tworld\t";
+    /// assert_eq!("Hello\tworld\t", s.trim_start());
+    /// ```
+    ///
+    /// Directionality:
+    ///
+    /// ```
+    /// let s = "  English  ";
+    /// assert!(Some('E') == s.trim_start().chars().next());
+    ///
+    /// let s = "  ×¢×‘רית  ";
+    /// assert!(Some('×¢') == s.trim_start().chars().next());
+    /// ```
+    #[stable(feature = "trim_direction", since = "1.30.0")]
+    pub fn trim_start(&self) -> &str {
+        self.trim_start_matches(|c: char| c.is_whitespace())
+    }
+
+    /// Returns a string slice with trailing whitespace removed.
+    ///
+    /// 'Whitespace' is defined according to the terms of the Unicode Derived
+    /// Core Property `White_Space`.
+    ///
+    /// # Text directionality
+    ///
+    /// A string is a sequence of bytes. `end` in this context means the last
+    /// position of that byte string; for a left-to-right language like English or
+    /// Russian, this will be right side; and for right-to-left languages like
+    /// like Arabic or Hebrew, this will be the left side.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// let s = " Hello\tworld\t";
+    /// assert_eq!(" Hello\tworld", s.trim_end());
+    /// ```
+    ///
+    /// Directionality:
+    ///
+    /// ```
+    /// let s = "  English  ";
+    /// assert!(Some('h') == s.trim_end().chars().rev().next());
+    ///
+    /// let s = "  ×¢×‘רית  ";
+    /// assert!(Some('ת') == s.trim_end().chars().rev().next());
+    /// ```
+    #[stable(feature = "trim_direction", since = "1.30.0")]
+    pub fn trim_end(&self) -> &str {
+        self.trim_end_matches(|c: char| c.is_whitespace())
+    }
+
     /// Returns a string slice with leading whitespace removed.
     ///
     /// 'Whitespace' is defined according to the terms of the Unicode Derived
@@ -3595,8 +3665,9 @@ pub fn trim(&self) -> &str {
     /// assert!(Some('×¢') == s.trim_left().chars().next());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_deprecated(reason = "superseded by `trim_start`", since = "1.33.0")]
     pub fn trim_left(&self) -> &str {
-        self.trim_left_matches(|c: char| c.is_whitespace())
+        self.trim_start()
     }
 
     /// Returns a string slice with trailing whitespace removed.
@@ -3631,8 +3702,9 @@ pub fn trim_left(&self) -> &str {
     /// assert!(Some('ת') == s.trim_right().chars().rev().next());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_deprecated(reason = "superseded by `trim_end`", since = "1.33.0")]
     pub fn trim_right(&self) -> &str {
-        self.trim_right_matches(|c: char| c.is_whitespace())
+        self.trim_end()
     }
 
     /// Returns a string slice with all prefixes and suffixes that match a
@@ -3697,14 +3769,14 @@ pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
     /// Basic usage:
     ///
     /// ```
-    /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
-    /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
+    /// assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11");
+    /// assert_eq!("123foo1bar123".trim_start_matches(char::is_numeric), "foo1bar123");
     ///
     /// let x: &[_] = &['1', '2'];
-    /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
+    /// assert_eq!("12foo1bar12".trim_start_matches(x), "foo1bar12");
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
+    #[stable(feature = "trim_direction", since = "1.30.0")]
+    pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
         let mut i = self.len();
         let mut matcher = pat.into_searcher(self);
         if let Some((a, _)) = matcher.next_reject() {
@@ -3734,20 +3806,20 @@ pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
     /// Simple patterns:
     ///
     /// ```
-    /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
-    /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
+    /// assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar");
+    /// assert_eq!("123foo1bar123".trim_end_matches(char::is_numeric), "123foo1bar");
     ///
     /// let x: &[_] = &['1', '2'];
-    /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
+    /// assert_eq!("12foo1bar12".trim_end_matches(x), "12foo1bar");
     /// ```
     ///
     /// A more complex pattern, using a closure:
     ///
     /// ```
-    /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
+    /// assert_eq!("1fooX".trim_end_matches(|c| c == '1' || c == 'X'), "1foo");
     /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+    #[stable(feature = "trim_direction", since = "1.30.0")]
+    pub fn trim_end_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
         where P::Searcher: ReverseSearcher<'a>
     {
         let mut j = 0;
@@ -3761,6 +3833,78 @@ pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
         }
     }
 
+    /// Returns a string slice with all prefixes that match a pattern
+    /// repeatedly removed.
+    ///
+    /// The pattern can be a `&str`, [`char`], or a closure that determines if
+    /// a character matches.
+    ///
+    /// [`char`]: primitive.char.html
+    ///
+    /// # Text directionality
+    ///
+    /// A string is a sequence of bytes. 'Left' in this context means the first
+    /// position of that byte string; for a language like Arabic or Hebrew
+    /// which are 'right to left' rather than 'left to right', this will be
+    /// the _right_ side, not the left.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
+    /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
+    ///
+    /// let x: &[_] = &['1', '2'];
+    /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_deprecated(reason = "superseded by `trim_start_matches`", since = "1.33.0")]
+    pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
+        self.trim_start_matches(pat)
+    }
+
+    /// Returns a string slice with all suffixes that match a pattern
+    /// repeatedly removed.
+    ///
+    /// The pattern can be a `&str`, [`char`], or a closure that
+    /// determines if a character matches.
+    ///
+    /// [`char`]: primitive.char.html
+    ///
+    /// # Text directionality
+    ///
+    /// A string is a sequence of bytes. 'Right' in this context means the last
+    /// position of that byte string; for a language like Arabic or Hebrew
+    /// which are 'right to left' rather than 'left to right', this will be
+    /// the _left_ side, not the right.
+    ///
+    /// # Examples
+    ///
+    /// Simple patterns:
+    ///
+    /// ```
+    /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
+    /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
+    ///
+    /// let x: &[_] = &['1', '2'];
+    /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
+    /// ```
+    ///
+    /// A more complex pattern, using a closure:
+    ///
+    /// ```
+    /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_deprecated(reason = "superseded by `trim_end_matches`", since = "1.33.0")]
+    pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+        where P::Searcher: ReverseSearcher<'a>
+    {
+        self.trim_end_matches(pat)
+    }
+
     /// Parses this string slice into another type.
     ///
     /// Because `parse` is so general, it can cause problems with type
index 371f631737c9871001536c5f4e964f2f0a012736..1acc58948f413b71ecf72bf47a71884bb8b3a48e 100644 (file)
@@ -15,7 +15,6 @@
 use ich::{self, CachingSourceMapView, Fingerprint};
 use middle::cstore::CrateStore;
 use ty::{TyCtxt, fast_reject};
-use mir::interpret::AllocId;
 use session::Session;
 
 use std::cmp::Ord;
@@ -60,8 +59,6 @@ pub struct StableHashingContext<'a> {
     // CachingSourceMapView, so we initialize it lazily.
     raw_source_map: &'a SourceMap,
     caching_source_map: Option<CachingSourceMapView<'a>>,
-
-    pub(super) alloc_id_recursion_tracker: FxHashSet<AllocId>,
 }
 
 #[derive(PartialEq, Eq, Clone, Copy)]
@@ -105,7 +102,6 @@ pub fn new(sess: &'a Session,
             hash_spans: hash_spans_initial,
             hash_bodies: true,
             node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
-            alloc_id_recursion_tracker: Default::default(),
         }
     }
 
index 6250e12f43043beac2ba90a37fb0e8d286733542..68320dfddefbc04934d7a24581d4eb2e4b419f80 100644 (file)
@@ -344,13 +344,13 @@ fn hash_stable<W: StableHasherResult>(&self,
     }
 }
 
-impl_stable_hash_for!(struct ty::VariantDef {
-    did,
-    name,
-    discr,
-    fields,
-    ctor_kind
-});
+impl<'a> HashStable<StableHashingContext<'a>> for ty::VariantFlags {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        std_hash::Hash::hash(self, hasher);
+    }
+}
 
 impl_stable_hash_for!(enum ty::VariantDiscr {
     Explicit(def_id),
@@ -412,7 +412,7 @@ fn hash_stable<W: StableHasherResult>(
         ty::tls::with_opt(|tcx| {
             trace!("hashing {:?}", *self);
             let tcx = tcx.expect("can't hash AllocIds during hir lowering");
-            let alloc_kind = tcx.alloc_map.lock().get(*self).expect("no value for AllocId");
+            let alloc_kind = tcx.alloc_map.lock().get(*self);
             alloc_kind.hash_stable(hcx, hasher);
         });
     }
index d40dbae09d2cb60f8b27420e38b9453aeb39ec21..ccc5bba1ad61170e592665f3857073852191861e 100644 (file)
@@ -133,9 +133,14 @@ fn wrapping_signed_offset(self, val: u64, i: i64) -> u64 {
 impl<T: layout::HasDataLayout> PointerArithmetic for T {}
 
 
+/// Pointer is generic over the type that represents a reference to Allocations,
+/// thus making it possible for the most convenient representation to be used in
+/// each context.
+///
+/// Defaults to the index based and loosely coupled AllocId.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub struct Pointer {
-    pub alloc_id: AllocId,
+pub struct Pointer<Id=AllocId> {
+    pub alloc_id: Id,
     pub offset: Size,
 }
 
@@ -543,16 +548,16 @@ pub fn undef(size: Size, align: Align) -> Self {
 impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct Relocations(SortedMap<Size, AllocId>);
+pub struct Relocations<Id=AllocId>(SortedMap<Size, Id>);
 
-impl Relocations {
-    pub fn new() -> Relocations {
+impl<Id> Relocations<Id> {
+    pub fn new() -> Self {
         Relocations(SortedMap::new())
     }
 
     // The caller must guarantee that the given relocations are already sorted
     // by address and contain no duplicates.
-    pub fn from_presorted(r: Vec<(Size, AllocId)>) -> Relocations {
+    pub fn from_presorted(r: Vec<(Size, Id)>) -> Self {
         Relocations(SortedMap::from_presorted_elements(r))
     }
 }
index 11a4f8b884e7f1b46d3fa910e801f3e807563053..9982da483ce09968cd18a3b601312946d93125ec 100644 (file)
@@ -326,7 +326,7 @@ fn from(ptr: Pointer) -> Self {
 /// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
 /// of a simple value or a pointer into another `Allocation`
 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum Scalar {
+pub enum Scalar<Id=AllocId> {
     /// The raw bytes of a simple value.
     Bits {
         /// The first `size` bytes are the value.
@@ -338,12 +338,12 @@ pub enum Scalar {
     /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
     /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
     /// relocation and its associated offset together as a `Pointer` here.
-    Ptr(Pointer),
+    Ptr(Pointer<Id>),
 }
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum ScalarMaybeUndef {
-    Scalar(Scalar),
+pub enum ScalarMaybeUndef<Id=AllocId> {
+    Scalar(Scalar<Id>),
     Undef,
 }
 
index 63308ac46d10f4b7b28eb3a9e77756f6f587a5a0..5e2093d03566af5a4900b191f1de312719195984 100644 (file)
@@ -1692,12 +1692,17 @@ pub struct AdtFlags: u32 {
         const IS_FUNDAMENTAL      = 1 << 2;
         const IS_UNION            = 1 << 3;
         const IS_BOX              = 1 << 4;
-        /// Indicates whether this abstract data type will be expanded on in future (new
-        /// fields/variants) and as such, whether downstream crates must match exhaustively on the
-        /// fields/variants of this data type.
-        ///
-        /// See RFC 2008 (<https://github.com/rust-lang/rfcs/pull/2008>).
-        const IS_NON_EXHAUSTIVE   = 1 << 5;
+        /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
+        /// (i.e., this flag is never set unless this ADT is an enum).
+        const IS_VARIANT_LIST_NON_EXHAUSTIVE   = 1 << 5;
+    }
+}
+
+bitflags! {
+    pub struct VariantFlags: u32 {
+        const NO_VARIANT_FLAGS        = 0;
+        /// Indicates whether the field list of this variant is `#[non_exhaustive]`.
+        const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0;
     }
 }
 
@@ -1710,8 +1715,56 @@ pub struct VariantDef {
     pub discr: VariantDiscr,
     pub fields: Vec<FieldDef>,
     pub ctor_kind: CtorKind,
+    flags: VariantFlags,
 }
 
+impl<'a, 'gcx, 'tcx> VariantDef {
+    /// Create a new `VariantDef`.
+    ///
+    /// - `did` is the DefId used for the variant - for tuple-structs, it is the constructor DefId,
+    /// and for everything else, it is the variant DefId.
+    /// - `attribute_def_id` is the DefId that has the variant's attributes.
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+               did: DefId,
+               name: Name,
+               discr: VariantDiscr,
+               fields: Vec<FieldDef>,
+               adt_kind: AdtKind,
+               ctor_kind: CtorKind)
+               -> Self
+    {
+        debug!("VariantDef::new({:?}, {:?}, {:?}, {:?}, {:?}, {:?})", did, name, discr, fields,
+               adt_kind, ctor_kind);
+        let mut flags = VariantFlags::NO_VARIANT_FLAGS;
+        if adt_kind == AdtKind::Struct && tcx.has_attr(did, "non_exhaustive") {
+            debug!("found non-exhaustive field list for {:?}", did);
+            flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE;
+        }
+        VariantDef {
+            did,
+            name,
+            discr,
+            fields,
+            ctor_kind,
+            flags
+        }
+    }
+
+    #[inline]
+    pub fn is_field_list_non_exhaustive(&self) -> bool {
+        self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE)
+    }
+}
+
+impl_stable_hash_for!(struct VariantDef {
+    did,
+    name,
+    discr,
+    fields,
+    ctor_kind,
+    flags
+});
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum VariantDiscr {
     /// Explicit value for this variant, i.e. `X = 123`.
@@ -1850,7 +1903,7 @@ pub struct ReprFlags: u8 {
 
 
 /// Represents the repr options provided by the user,
-#[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)]
 pub struct ReprOptions {
     pub int: Option<attr::IntType>,
     pub align: u32,
@@ -1939,6 +1992,7 @@ fn new(tcx: TyCtxt,
            kind: AdtKind,
            variants: Vec<VariantDef>,
            repr: ReprOptions) -> Self {
+        debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
         let mut flags = AdtFlags::NO_ADT_FLAGS;
         let attrs = tcx.get_attrs(did);
         if attr::contains_name(&attrs, "fundamental") {
@@ -1950,8 +2004,9 @@ fn new(tcx: TyCtxt,
         if Some(did) == tcx.lang_items().owned_box() {
             flags = flags | AdtFlags::IS_BOX;
         }
-        if tcx.has_attr(did, "non_exhaustive") {
-            flags = flags | AdtFlags::IS_NON_EXHAUSTIVE;
+        if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
+            debug!("found non-exhaustive variant list for {:?}", did);
+            flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
         }
         match kind {
             AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
@@ -1982,8 +2037,8 @@ pub fn is_enum(&self) -> bool {
     }
 
     #[inline]
-    pub fn is_non_exhaustive(&self) -> bool {
-        self.flags.intersects(AdtFlags::IS_NON_EXHAUSTIVE)
+    pub fn is_variant_list_non_exhaustive(&self) -> bool {
+        self.flags.intersects(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
     }
 
     /// Returns the kind of the ADT - Struct or Enum.
index c1dda02264ed16749ce002324fa8b1ca8f1cec70..25bc662c408f65ca47e545e66b2de7ae029172bc 100644 (file)
@@ -29,7 +29,7 @@
 use libc;
 
 use std::ffi::{CStr, CString};
-use std::fs::{self, File};
+use std::fs;
 use std::ptr;
 use std::slice;
 use std::sync::Arc;
@@ -619,7 +619,7 @@ fn run_pass_manager(cgcx: &CodegenContext,
 pub enum SerializedModule {
     Local(ModuleBuffer),
     FromRlib(Vec<u8>),
-    FromUncompressedFile(memmap::Mmap, File),
+    FromUncompressedFile(memmap::Mmap),
 }
 
 impl SerializedModule {
@@ -627,7 +627,7 @@ fn data(&self) -> &[u8] {
         match *self {
             SerializedModule::Local(ref m) => m.data(),
             SerializedModule::FromRlib(ref m) => m,
-            SerializedModule::FromUncompressedFile(ref m, _) => m,
+            SerializedModule::FromUncompressedFile(ref m) => m,
         }
     }
 }
index 9c586504527cd352518771493d7594a04ddeb2bd..6b257ed4c3e94f8b23e386eab095afd3ad350e4c 100644 (file)
@@ -2494,7 +2494,7 @@ pub(crate) fn submit_pre_lto_module_to_llvm(tcx: TyCtxt,
 
     // Schedule the module to be loaded
     drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::AddImportOnlyModule {
-        module_data: SerializedModule::FromUncompressedFile(mmap, file),
+        module_data: SerializedModule::FromUncompressedFile(mmap),
         work_product: module.source,
     })));
 }
index 1024e69cc2b0e889b67d74b35ad75fbfba58240e..c70a0abe8c7e437e5ed2f92aac748d6dca74b1b3 100644 (file)
@@ -281,6 +281,23 @@ fn hash_stable<W: StableHasherResult>(&self,
     }
 }
 
+impl<T1, T2, T3, T4, CTX> HashStable<CTX> for (T1, T2, T3, T4)
+     where T1: HashStable<CTX>,
+           T2: HashStable<CTX>,
+           T3: HashStable<CTX>,
+           T4: HashStable<CTX>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        let (ref _0, ref _1, ref _2, ref _3) = *self;
+        _0.hash_stable(ctx, hasher);
+        _1.hash_stable(ctx, hasher);
+        _2.hash_stable(ctx, hasher);
+        _3.hash_stable(ctx, hasher);
+    }
+}
+
 impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
     default fn hash_stable<W: StableHasherResult>(&self,
                                                   ctx: &mut CTX,
index f4456b96027aeba2c9e3685c5b241250fdccf46a..9907df7ed02400094a1de14a4e2691184ced1f46 100644 (file)
@@ -542,7 +542,13 @@ pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
                           self.def_path_table.def_path_hash(item_id))
     }
 
-    fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef {
+    fn get_variant(&self,
+                   tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                   item: &Entry,
+                   index: DefIndex,
+                   adt_kind: ty::AdtKind)
+                   -> ty::VariantDef
+    {
         let data = match item.kind {
             EntryKind::Variant(data) |
             EntryKind::Struct(data, _) |
@@ -550,10 +556,12 @@ fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef {
             _ => bug!(),
         };
 
-        ty::VariantDef {
-            did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
-            name: self.item_name(index).as_symbol(),
-            fields: item.children.decode(self).map(|index| {
+        ty::VariantDef::new(
+            tcx,
+            self.local_def_id(data.struct_ctor.unwrap_or(index)),
+            self.item_name(index).as_symbol(),
+            data.discr,
+            item.children.decode(self).map(|index| {
                 let f = self.entry(index);
                 ty::FieldDef {
                     did: self.local_def_id(index),
@@ -561,9 +569,9 @@ fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef {
                     vis: f.visibility.decode(self)
                 }
             }).collect(),
-            discr: data.discr,
-            ctor_kind: data.ctor_kind,
-        }
+            adt_kind,
+            data.ctor_kind
+        )
     }
 
     pub fn get_adt_def(&self,
@@ -584,11 +592,11 @@ pub fn get_adt_def(&self,
             item.children
                 .decode(self)
                 .map(|index| {
-                    self.get_variant(&self.entry(index), index)
+                    self.get_variant(tcx, &self.entry(index), index, kind)
                 })
                 .collect()
         } else {
-            vec![self.get_variant(&item, item_id)]
+            vec![self.get_variant(tcx, &item, item_id, kind)]
         };
 
         tcx.alloc_adt_def(did, kind, variants, repr)
index 8219ec3df248aaebdbb096987fe6fae2cb5339d7..0fd43c592c8535dd3bfeae79456e6f7242a63cc9 100644 (file)
@@ -740,7 +740,9 @@ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<
 
         // If the structure is marked as non_exhaustive then lower the visibility
         // to within the crate.
-        if adt_def.is_non_exhaustive() && ctor_vis == ty::Visibility::Public {
+        if adt_def.non_enum_variant().is_field_list_non_exhaustive() &&
+            ctor_vis == ty::Visibility::Public
+        {
             ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
         }
 
index b80f9784d6f8757879ecff6571036725c581fe8b..693210da8d3a8d92d2d8b05e12fa29427e46ee88 100644 (file)
@@ -120,7 +120,6 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
         flow_inits,
         move_data,
         elements,
-        errors_buffer,
     );
 
     if let Some(all_facts) = &mut all_facts {
index 3a5857f775fa458b1be915c99cf2130a1fb5aee2..61c99832448c595df5690083932f92377420c558 100644 (file)
@@ -36,7 +36,6 @@
 use rustc::traits::query::{Fallible, NoSolution};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
-use rustc_errors::Diagnostic;
 use std::fmt;
 use std::rc::Rc;
 use syntax_pos::{Span, DUMMY_SP};
@@ -103,8 +102,7 @@ macro_rules! span_mirbug_and_err {
 /// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
 ///   constraints for the regions in the types of variables
 /// - `flow_inits` -- results of a maybe-init dataflow analysis
-/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
-/// - `errors_buffer` -- errors are sent here for future reporting
+/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysiss
 pub(crate) fn type_check<'gcx, 'tcx>(
     infcx: &InferCtxt<'_, 'gcx, 'tcx>,
     param_env: ty::ParamEnv<'gcx>,
@@ -117,7 +115,6 @@ pub(crate) fn type_check<'gcx, 'tcx>(
     flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
     move_data: &MoveData<'tcx>,
     elements: &Rc<RegionValueElements>,
-    errors_buffer: &mut Vec<Diagnostic>,
 ) -> MirTypeckResults<'tcx> {
     let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
     let mut constraints = MirTypeckRegionConstraints {
@@ -157,7 +154,6 @@ pub(crate) fn type_check<'gcx, 'tcx>(
             &region_bound_pairs,
             Some(implicit_region_bound),
             Some(&mut borrowck_context),
-            Some(errors_buffer),
             |cx| {
                 cx.equate_inputs_and_outputs(
                     mir,
@@ -185,7 +181,6 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>(
     region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
     implicit_region_bound: Option<ty::Region<'tcx>>,
     borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
-    errors_buffer: Option<&mut Vec<Diagnostic>>,
     mut extra: impl FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) -> R,
 ) -> R where {
     let mut checker = TypeChecker::new(
@@ -205,7 +200,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>(
 
     if !errors_reported {
         // if verifier failed, don't do further checks to avoid ICEs
-        checker.typeck_mir(mir, errors_buffer);
+        checker.typeck_mir(mir);
     }
 
     extra(&mut checker)
@@ -989,7 +984,6 @@ fn check_terminator(
         mir: &Mir<'tcx>,
         term: &Terminator<'tcx>,
         term_location: Location,
-        errors_buffer: &mut Option<&mut Vec<Diagnostic>>,
     ) {
         debug!("check_terminator: {:?}", term);
         let tcx = self.tcx();
@@ -1069,7 +1063,7 @@ fn check_terminator(
                     &sig,
                 );
                 let sig = self.normalize(sig, term_location);
-                self.check_call_dest(mir, term, &sig, destination, term_location, errors_buffer);
+                self.check_call_dest(mir, term, &sig, destination, term_location);
 
                 self.prove_predicates(
                     sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)),
@@ -1143,7 +1137,6 @@ fn check_call_dest(
         sig: &ty::FnSig<'tcx>,
         destination: &Option<(Place<'tcx>, BasicBlock)>,
         term_location: Location,
-        errors_buffer: &mut Option<&mut Vec<Diagnostic>>,
     ) {
         let tcx = self.tcx();
         match *destination {
@@ -1177,7 +1170,7 @@ fn check_call_dest(
                 // this check is done at `check_local`.
                 if self.tcx().features().unsized_locals {
                     let span = term.source_info.span;
-                    self.ensure_place_sized(dest_ty, span, errors_buffer);
+                    self.ensure_place_sized(dest_ty, span);
                 }
             }
             None => {
@@ -1330,7 +1323,6 @@ fn check_local(
         mir: &Mir<'tcx>,
         local: Local,
         local_decl: &LocalDecl<'tcx>,
-        errors_buffer: &mut Option<&mut Vec<Diagnostic>>,
     ) {
         match mir.local_kind(local) {
             LocalKind::ReturnPointer | LocalKind::Arg => {
@@ -1346,18 +1338,15 @@ fn check_local(
         }
 
         // When `#![feature(unsized_locals)]` is enabled, only function calls
-        // are checked in `check_call_dest`.
+        // and nullary ops are checked in `check_call_dest`.
         if !self.tcx().features().unsized_locals {
             let span = local_decl.source_info.span;
             let ty = local_decl.ty;
-            self.ensure_place_sized(ty, span, errors_buffer);
+            self.ensure_place_sized(ty, span);
         }
     }
 
-    fn ensure_place_sized(&mut self,
-                          ty: Ty<'tcx>,
-                          span: Span,
-                          errors_buffer: &mut Option<&mut Vec<Diagnostic>>) {
+    fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) {
         let tcx = self.tcx();
 
         // Erase the regions from `ty` to get a global type.  The
@@ -1379,15 +1368,13 @@ fn ensure_place_sized(&mut self,
                      cannot be statically determined",
                     ty
                 );
-                if let Some(ref mut errors_buffer) = *errors_buffer {
-                    diag.buffer(errors_buffer);
-                } else {
-                    // we're allowed to use emit() here because the
-                    // NLL migration will be turned on (and thus
-                    // errors will need to be buffered) *only if*
-                    // errors_buffer is Some.
-                    diag.emit();
-                }
+
+                // While this is located in `nll::typeck` this error is not
+                // an NLL error, it's a required check to prevent creation
+                // of unsized rvalues in certain cases:
+                // * operand of a box expression
+                // * callee in a call expression
+                diag.emit();
             }
         }
     }
@@ -1462,6 +1449,12 @@ fn check_rvalue(&mut self, mir: &Mir<'tcx>, rvalue: &Rvalue<'tcx>, location: Loc
             },
 
             Rvalue::NullaryOp(_, ty) => {
+                // Even with unsized locals cannot box an unsized value.
+                if self.tcx().features().unsized_locals {
+                    let span = mir.source_info(location).span;
+                    self.ensure_place_sized(ty, span);
+                }
+
                 let trait_ref = ty::TraitRef {
                     def_id: tcx.lang_items().sized_trait().unwrap(),
                     substs: tcx.mk_substs_trait(ty, &[]),
@@ -1895,12 +1888,12 @@ fn prove_predicate(&mut self, predicate: ty::Predicate<'tcx>, locations: Locatio
         })
     }
 
-    fn typeck_mir(&mut self, mir: &Mir<'tcx>, mut errors_buffer: Option<&mut Vec<Diagnostic>>) {
+    fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
         self.last_span = mir.span;
         debug!("run_on_mir: {:?}", mir.span);
 
         for (local, local_decl) in mir.local_decls.iter_enumerated() {
-            self.check_local(mir, local, local_decl, &mut errors_buffer);
+            self.check_local(mir, local, local_decl);
         }
 
         for (block, block_data) in mir.basic_blocks().iter_enumerated() {
@@ -1916,7 +1909,7 @@ fn typeck_mir(&mut self, mir: &Mir<'tcx>, mut errors_buffer: Option<&mut Vec<Dia
                 location.statement_index += 1;
             }
 
-            self.check_terminator(mir, block_data.terminator(), location, &mut errors_buffer);
+            self.check_terminator(mir, block_data.terminator(), location);
             self.check_iscleanup(mir, block_data);
         }
     }
@@ -1973,7 +1966,6 @@ fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &
                 &[],
                 None,
                 None,
-                None,
                 |_| (),
             );
 
index 70addf2c907e65ebeabff542e3a6c7b1735b013c..92ddd8777f733eb0398566b1c45fe9f1fccd6867 100644 (file)
@@ -196,6 +196,8 @@ fn into(self) -> EvalError<'tcx> {
     }
 }
 
+impl_stable_hash_for!(struct CompileTimeEvaluator {});
+
 #[derive(Clone, Debug)]
 enum ConstEvalError {
     NeedsRfc(String),
index e9d65caf08743ac486b4624c8b3d516e53af04da..d7fbbc88cc16d63e864e93c11e174b5163d852c9 100644 (file)
@@ -381,7 +381,7 @@ fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
 
     fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool {
         match ty.sty {
-            ty::Adt(adt_def, ..) => adt_def.is_enum() && adt_def.is_non_exhaustive(),
+            ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(),
             _ => false,
         }
     }
index 6e144ba7ed2ee7627e74d0b9fd87f5518127f916..f7277f8d27610b3fb5ac780e62caf498210da9d1 100644 (file)
@@ -9,12 +9,12 @@
 // except according to those terms.
 
 use std::fmt::Write;
-use std::hash::{Hash, Hasher};
 use std::mem;
 
 use rustc::hir::def_id::DefId;
 use rustc::hir::def::Def;
 use rustc::hir::map::definitions::DefPathData;
+use rustc::ich::StableHashingContext;
 use rustc::mir;
 use rustc::ty::layout::{
     self, Size, Align, HasDataLayout, LayoutOf, TyLayout
 use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::query::TyCtxtAt;
-use rustc_data_structures::fx::{FxHashSet, FxHasher};
 use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
 use rustc::mir::interpret::{
-    GlobalId, Scalar, FrameInfo,
+    GlobalId, Scalar, FrameInfo, AllocId,
     EvalResult, EvalErrorKind,
     ScalarMaybeUndef,
     truncate, sign_extend,
@@ -38,6 +38,8 @@
     Memory, Machine
 };
 
+use super::snapshot::InfiniteLoopDetector;
+
 pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
     /// Stores the `Machine` instance.
     pub machine: M,
@@ -95,7 +97,7 @@ pub struct Frame<'mir, 'tcx: 'mir> {
     /// The locals are stored as `Option<Value>`s.
     /// `None` represents a local that is currently dead, while a live local
     /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
-    pub locals: IndexVec<mir::Local, LocalValue>,
+    pub locals: IndexVec<mir::Local, LocalValue<AllocId>>,
 
     ////////////////////////////////////////////////////////////////////////////////
     // Current position within the function
@@ -108,38 +110,16 @@ pub struct Frame<'mir, 'tcx: 'mir> {
     pub stmt: usize,
 }
 
-impl<'mir, 'tcx: 'mir> Eq for Frame<'mir, 'tcx> {}
-
-impl<'mir, 'tcx: 'mir> PartialEq for Frame<'mir, 'tcx> {
-    fn eq(&self, other: &Self) -> bool {
-        let Frame {
-            mir: _,
-            instance,
-            span: _,
-            return_to_block,
-            return_place,
-            locals,
-            block,
-            stmt,
-        } = self;
-
-        // Some of these are constant during evaluation, but are included
-        // anyways for correctness.
-        *instance == other.instance
-            && *return_to_block == other.return_to_block
-            && *return_place == other.return_place
-            && *locals == other.locals
-            && *block == other.block
-            && *stmt == other.stmt
-    }
-}
+impl<'a, 'mir, 'tcx: 'mir> HashStable<StableHashingContext<'a>> for Frame<'mir, 'tcx> {
+    fn hash_stable<W: StableHasherResult>(
+        &self,
+        hcx: &mut StableHashingContext<'a>,
+        hasher: &mut StableHasher<W>) {
 
-impl<'mir, 'tcx: 'mir> Hash for Frame<'mir, 'tcx> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
         let Frame {
-            mir: _,
+            mir,
             instance,
-            span: _,
+            span,
             return_to_block,
             return_place,
             locals,
@@ -147,12 +127,8 @@ fn hash<H: Hasher>(&self, state: &mut H) {
             stmt,
         } = self;
 
-        instance.hash(state);
-        return_to_block.hash(state);
-        return_place.hash(state);
-        locals.hash(state);
-        block.hash(state);
-        stmt.hash(state);
+        (mir, instance, span, return_to_block).hash_stable(hcx, hasher);
+        (return_place, locals, block, stmt).hash_stable(hcx, hasher);
     }
 }
 
@@ -168,15 +144,27 @@ pub enum StackPopCleanup {
     None { cleanup: bool },
 }
 
+impl<'a> HashStable<StableHashingContext<'a>> for StackPopCleanup {
+    fn hash_stable<W: StableHasherResult>(
+        &self,
+        hcx: &mut StableHashingContext<'a>,
+        hasher: &mut StableHasher<W>) {
+        match self {
+            StackPopCleanup::Goto(ref block) => block.hash_stable(hcx, hasher),
+            StackPopCleanup::None { cleanup } => cleanup.hash_stable(hcx, hasher),
+        }
+    }
+}
+
 // State of a local variable
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub enum LocalValue {
+pub enum LocalValue<Id=AllocId> {
     Dead,
     // Mostly for convenience, we re-use the `Operand` type here.
     // This is an optimization over just always having a pointer here;
     // we can thus avoid doing an allocation when the local just stores
     // immediate values *and* never has its address taken.
-    Live(Operand),
+    Live(Operand<Id>),
 }
 
 impl<'tcx> LocalValue {
@@ -195,72 +183,10 @@ pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand> {
     }
 }
 
-/// The virtual machine state during const-evaluation at a given point in time.
-type EvalSnapshot<'a, 'mir, 'tcx, M>
-    = (M, Vec<Frame<'mir, 'tcx>>, Memory<'a, 'mir, 'tcx, M>);
-
-pub(super) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
-    /// The set of all `EvalSnapshot` *hashes* observed by this detector.
-    ///
-    /// When a collision occurs in this table, we store the full snapshot in
-    /// `snapshots`.
-    hashes: FxHashSet<u64>,
-
-    /// The set of all `EvalSnapshot`s observed by this detector.
-    ///
-    /// An `EvalSnapshot` will only be fully cloned once it has caused a
-    /// collision in `hashes`. As a result, the detector must observe at least
-    /// *two* full cycles of an infinite loop before it triggers.
-    snapshots: FxHashSet<EvalSnapshot<'a, 'mir, 'tcx, M>>,
-}
-
-impl<'a, 'mir, 'tcx, M> Default for InfiniteLoopDetector<'a, 'mir, 'tcx, M>
-    where M: Machine<'mir, 'tcx>,
-          'tcx: 'a + 'mir,
-{
-    fn default() -> Self {
-        InfiniteLoopDetector {
-            hashes: FxHashSet::default(),
-            snapshots: FxHashSet::default(),
-        }
-    }
-}
-
-impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M>
-    where M: Machine<'mir, 'tcx>,
-          'tcx: 'a + 'mir,
-{
-    /// Returns `true` if the loop detector has not yet observed a snapshot.
-    pub fn is_empty(&self) -> bool {
-        self.hashes.is_empty()
-    }
-
-    pub fn observe_and_analyze(
-        &mut self,
-        machine: &M,
-        stack: &Vec<Frame<'mir, 'tcx>>,
-        memory: &Memory<'a, 'mir, 'tcx, M>,
-    ) -> EvalResult<'tcx, ()> {
-        let snapshot = (machine, stack, memory);
-
-        let mut fx = FxHasher::default();
-        snapshot.hash(&mut fx);
-        let hash = fx.finish();
-
-        if self.hashes.insert(hash) {
-            // No collision
-            return Ok(())
-        }
-
-        if self.snapshots.insert((machine.clone(), stack.clone(), memory.clone())) {
-            // Spurious collision or first cycle
-            return Ok(())
-        }
-
-        // Second cycle
-        Err(EvalErrorKind::InfiniteLoop.into())
-    }
-}
+impl_stable_hash_for!(enum self::LocalValue {
+    Dead,
+    Live(x),
+});
 
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'a, 'mir, 'tcx, M> {
     #[inline]
index 57af63d63d9c47d074d9572b4c642b588c97345d..61963f6d3d354560828405c7cbdd9f4fa758b49f 100644 (file)
 use std::hash::Hash;
 
 use rustc::hir::def_id::DefId;
+use rustc::ich::StableHashingContext;
 use rustc::mir::interpret::{Allocation, EvalResult, Scalar};
 use rustc::mir;
 use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
+use rustc_data_structures::stable_hasher::HashStable;
 
 use super::{EvalContext, PlaceTy, OpTy};
 
 /// Methods of this trait signifies a point where CTFE evaluation would fail
 /// and some use case dependent behaviour can instead be applied
-pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash {
+pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash + for<'a> HashStable<StableHashingContext<'a>> {
     /// Additional data that can be accessed via the Memory
-    type MemoryData: Clone + Eq + Hash;
+    type MemoryData: Clone + Eq + Hash + for<'a> HashStable<StableHashingContext<'a>>;
 
     /// Additional memory kinds a machine wishes to distinguish from the builtin ones
     type MemoryKinds: ::std::fmt::Debug + Copy + Clone + Eq + Hash;
index 59bebbb87a7755289ffd46041ffdce433251a61d..9e61de92936bdb7cf2fdb84670e9b69b3c15d0f7 100644 (file)
@@ -17,7 +17,6 @@
 //! short-circuiting the empty case!
 
 use std::collections::VecDeque;
-use std::hash::{Hash, Hasher};
 use std::ptr;
 
 use rustc::ty::{self, Instance, query::TyCtxtAt};
@@ -26,7 +25,7 @@
                             EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
                             truncate};
 pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
-use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxHasher};
+use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 
 use syntax::ast::Mutability;
 
@@ -70,58 +69,6 @@ fn data_layout(&self) -> &TargetDataLayout {
     }
 }
 
-impl<'a, 'mir, 'tcx, M> Eq for Memory<'a, 'mir, 'tcx, M>
-    where M: Machine<'mir, 'tcx>,
-          'tcx: 'a + 'mir,
-{}
-
-impl<'a, 'mir, 'tcx, M> PartialEq for Memory<'a, 'mir, 'tcx, M>
-    where M: Machine<'mir, 'tcx>,
-          'tcx: 'a + 'mir,
-{
-    fn eq(&self, other: &Self) -> bool {
-        let Memory {
-            data,
-            alloc_map,
-            tcx: _,
-        } = self;
-
-        *data == other.data
-            && *alloc_map == other.alloc_map
-    }
-}
-
-impl<'a, 'mir, 'tcx, M> Hash for Memory<'a, 'mir, 'tcx, M>
-    where M: Machine<'mir, 'tcx>,
-          'tcx: 'a + 'mir,
-{
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        let Memory {
-            data,
-            alloc_map: _,
-            tcx: _,
-        } = self;
-
-        data.hash(state);
-
-        // We ignore some fields which don't change between evaluation steps.
-
-        // Since HashMaps which contain the same items may have different
-        // iteration orders, we use a commutative operation (in this case
-        // addition, but XOR would also work), to combine the hash of each
-        // `Allocation`.
-        self.alloc_map.iter()
-            .map(|(&id, alloc)| {
-                let mut h = FxHasher::default();
-                id.hash(&mut h);
-                alloc.hash(&mut h);
-                h.finish()
-            })
-            .fold(0u64, |hash, x| hash.wrapping_add(x))
-            .hash(state);
-    }
-}
-
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
         Memory {
index 462c4b8889dd1977dc06c8154a388ac92fe56c6e..1e8de02923240652af9a56a30e1b601b82a9f1c3 100644 (file)
@@ -17,6 +17,7 @@
 mod machine;
 mod memory;
 mod operator;
+mod snapshot;
 mod step;
 mod terminator;
 mod traits;
index 6f9e0cf3e37b60f8d4e0ac636121d23c5c554ed2..4093a6304b360d19e2d849a26c5da07db1a0165a 100644 (file)
 use rustc::{mir, ty};
 use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
 use rustc_data_structures::indexed_vec::Idx;
-
 use rustc::mir::interpret::{
-    GlobalId, ConstValue, Scalar, EvalResult, Pointer, ScalarMaybeUndef, EvalErrorKind
+    GlobalId, AllocId,
+    ConstValue, Pointer, Scalar, ScalarMaybeUndef,
+    EvalResult, EvalErrorKind
 };
 use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
 
@@ -31,9 +32,9 @@
 /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
 /// defined on `Value`, and do not have to work with a `Place`.
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Value {
-    Scalar(ScalarMaybeUndef),
-    ScalarPair(ScalarMaybeUndef, ScalarMaybeUndef),
+pub enum Value<Id=AllocId> {
+    Scalar(ScalarMaybeUndef<Id>),
+    ScalarPair(ScalarMaybeUndef<Id>, ScalarMaybeUndef<Id>),
 }
 
 impl<'tcx> Value {
@@ -81,6 +82,11 @@ pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar> {
     }
 }
 
+impl_stable_hash_for!(enum ::interpret::Value {
+    Scalar(x),
+    ScalarPair(x, y),
+});
+
 // ScalarPair needs a type to interpret, so we often have a value and a type together
 // as input for binary and cast operations.
 #[derive(Copy, Clone, Debug)]
@@ -101,9 +107,9 @@ fn deref(&self) -> &Value {
 /// or still in memory.  The latter is an optimization, to delay reading that chunk of
 /// memory and to avoid having to store arbitrary-sized data here.
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Operand {
-    Immediate(Value),
-    Indirect(MemPlace),
+pub enum Operand<Id=AllocId> {
+    Immediate(Value<Id>),
+    Indirect(MemPlace<Id>),
 }
 
 impl Operand {
@@ -126,6 +132,11 @@ pub fn to_immediate(self) -> Value {
     }
 }
 
+impl_stable_hash_for!(enum ::interpret::Operand {
+    Immediate(x),
+    Indirect(x),
+});
+
 #[derive(Copy, Clone, Debug)]
 pub struct OpTy<'tcx> {
     crate op: Operand, // ideally we'd make this private, but const_prop needs this
index 6ee768fde5fa376a36f8b191b46b7328a6e0ee79..51a4294452719656c0e14d0a56b48c7b56184ea7 100644 (file)
 
 use std::convert::TryFrom;
 
+use rustc::ich::StableHashingContext;
 use rustc::mir;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
 use rustc_data_structures::indexed_vec::Idx;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
 
 use rustc::mir::interpret::{
-    GlobalId, Scalar, EvalResult, Pointer, ScalarMaybeUndef, PointerArithmetic
+    GlobalId, AllocId, Scalar, EvalResult, Pointer, ScalarMaybeUndef, PointerArithmetic
 };
 use super::{EvalContext, Machine, Value, ValTy, Operand, OpTy, MemoryKind};
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub struct MemPlace {
+pub struct MemPlace<Id=AllocId> {
     /// A place may have an integral pointer for ZSTs, and since it might
     /// be turned back into a reference before ever being dereferenced.
     /// However, it may never be undef.
-    pub ptr: Scalar,
+    pub ptr: Scalar<Id>,
     pub align: Align,
     /// Metadata for unsized places.  Interpretation is up to the type.
     /// Must not be present for sized types, but can be missing for unsized types
     /// (e.g. `extern type`).
-    pub extra: Option<Scalar>,
+    pub extra: Option<Scalar<Id>>,
 }
 
+impl_stable_hash_for!(struct ::interpret::MemPlace {
+    ptr,
+    align,
+    extra,
+});
+
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Place {
+pub enum Place<Id=AllocId> {
     /// A place referring to a value allocated in the `Memory` system.
-    Ptr(MemPlace),
+    Ptr(MemPlace<Id>),
 
     /// To support alloc-free locals, we are able to write directly to a local.
     /// (Without that optimization, we'd just always be a `MemPlace`.)
@@ -50,6 +58,21 @@ pub enum Place {
     },
 }
 
+impl<'a> HashStable<StableHashingContext<'a>> for Place {
+    fn hash_stable<W: StableHasherResult>(
+        &self, hcx: &mut StableHashingContext<'a>,
+        hasher: &mut StableHasher<W>) {
+
+        match self {
+            Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher),
+
+            Place::Local { frame, local } => {
+                frame.hash_stable(hcx, hasher);
+                local.hash_stable(hcx, hasher);
+            },
+        }
+    }
+}
 #[derive(Copy, Clone, Debug)]
 pub struct PlaceTy<'tcx> {
     place: Place,
diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs
new file mode 100644 (file)
index 0000000..8aa053b
--- /dev/null
@@ -0,0 +1,411 @@
+//! This module contains the machinery necessary to detect infinite loops
+//! during const-evaluation by taking snapshots of the state of the interpreter
+//! at regular intervals.
+
+use std::hash::{Hash, Hasher};
+
+use rustc::ich::{StableHashingContext, StableHashingContextProvider};
+use rustc::mir;
+use rustc::mir::interpret::{
+    AllocId, Pointer, Scalar, ScalarMaybeUndef,
+    Relocations, Allocation, UndefMask,
+    EvalResult, EvalErrorKind,
+};
+
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::layout::Align;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
+use syntax::ast::Mutability;
+use syntax::source_map::Span;
+
+use super::eval_context::{LocalValue, StackPopCleanup};
+use super::{Frame, Memory, Machine, Operand, MemPlace, Place, Value};
+
+pub(super) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
+    /// The set of all `EvalSnapshot` *hashes* observed by this detector.
+    ///
+    /// When a collision occurs in this table, we store the full snapshot in
+    /// `snapshots`.
+    hashes: FxHashSet<u64>,
+
+    /// The set of all `EvalSnapshot`s observed by this detector.
+    ///
+    /// An `EvalSnapshot` will only be fully cloned once it has caused a
+    /// collision in `hashes`. As a result, the detector must observe at least
+    /// *two* full cycles of an infinite loop before it triggers.
+    snapshots: FxHashSet<EvalSnapshot<'a, 'mir, 'tcx, M>>,
+}
+
+impl<'a, 'mir, 'tcx, M> Default for InfiniteLoopDetector<'a, 'mir, 'tcx, M>
+    where M: Machine<'mir, 'tcx>,
+          'tcx: 'a + 'mir,
+{
+    fn default() -> Self {
+        InfiniteLoopDetector {
+            hashes: FxHashSet::default(),
+            snapshots: FxHashSet::default(),
+        }
+    }
+}
+
+impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M>
+    where M: Machine<'mir, 'tcx>,
+          'tcx: 'a + 'mir,
+{
+    /// Returns `true` if the loop detector has not yet observed a snapshot.
+    pub fn is_empty(&self) -> bool {
+        self.hashes.is_empty()
+    }
+
+    pub fn observe_and_analyze(
+        &mut self,
+        tcx: &TyCtxt<'b, 'tcx, 'tcx>,
+        machine: &M,
+        memory: &Memory<'a, 'mir, 'tcx, M>,
+        stack: &[Frame<'mir, 'tcx>],
+    ) -> EvalResult<'tcx, ()> {
+
+        let mut hcx = tcx.get_stable_hashing_context();
+        let mut hasher = StableHasher::<u64>::new();
+        (machine, stack).hash_stable(&mut hcx, &mut hasher);
+        let hash = hasher.finish();
+
+        if self.hashes.insert(hash) {
+            // No collision
+            return Ok(())
+        }
+
+        info!("snapshotting the state of the interpreter");
+
+        if self.snapshots.insert(EvalSnapshot::new(machine, memory, stack)) {
+            // Spurious collision or first cycle
+            return Ok(())
+        }
+
+        // Second cycle
+        Err(EvalErrorKind::InfiniteLoop.into())
+    }
+}
+
+trait SnapshotContext<'a> {
+    fn resolve(&'a self, id: &AllocId) -> Option<&'a Allocation>;
+}
+
+/// Taking a snapshot of the evaluation context produces a view of
+/// the state of the interpreter that is invariant to `AllocId`s.
+trait Snapshot<'a, Ctx: SnapshotContext<'a>> {
+    type Item;
+    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item;
+}
+
+macro_rules! __impl_snapshot_field {
+    ($field:ident, $ctx:expr) => ($field.snapshot($ctx));
+    ($field:ident, $ctx:expr, $delegate:expr) => ($delegate);
+}
+
+macro_rules! impl_snapshot_for {
+    // FIXME(mark-i-m): Some of these should be `?` rather than `*`.
+    (enum $enum_name:ident {
+        $( $variant:ident $( ( $($field:ident $(-> $delegate:expr)*),* ) )* ),* $(,)*
+    }) => {
+
+        impl<'a, Ctx> self::Snapshot<'a, Ctx> for $enum_name
+            where Ctx: self::SnapshotContext<'a>,
+        {
+            type Item = $enum_name<AllocIdSnapshot<'a>>;
+
+            #[inline]
+            fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
+                match *self {
+                    $(
+                        $enum_name::$variant $( ( $(ref $field),* ) )* =>
+                            $enum_name::$variant $(
+                                ( $( __impl_snapshot_field!($field, __ctx $(, $delegate)*) ),* ),
+                            )*
+                    )*
+                }
+            }
+        }
+    };
+
+    // FIXME(mark-i-m): same here.
+    (struct $struct_name:ident { $($field:ident $(-> $delegate:expr)*),*  $(,)* }) => {
+        impl<'a, Ctx> self::Snapshot<'a, Ctx> for $struct_name
+            where Ctx: self::SnapshotContext<'a>,
+        {
+            type Item = $struct_name<AllocIdSnapshot<'a>>;
+
+            #[inline]
+            fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
+                let $struct_name {
+                    $(ref $field),*
+                } = *self;
+
+                $struct_name {
+                    $( $field: __impl_snapshot_field!($field, __ctx $(, $delegate)*) ),*
+                }
+            }
+        }
+    };
+}
+
+impl<'a, Ctx, T> Snapshot<'a, Ctx> for Option<T>
+    where Ctx: SnapshotContext<'a>,
+          T: Snapshot<'a, Ctx>
+{
+    type Item = Option<<T as Snapshot<'a, Ctx>>::Item>;
+
+    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+        match self {
+            Some(x) => Some(x.snapshot(ctx)),
+            None => None,
+        }
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct AllocIdSnapshot<'a>(Option<AllocationSnapshot<'a>>);
+
+impl<'a, Ctx> Snapshot<'a, Ctx> for AllocId
+    where Ctx: SnapshotContext<'a>,
+{
+    type Item = AllocIdSnapshot<'a>;
+
+    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+        AllocIdSnapshot(ctx.resolve(self).map(|alloc| alloc.snapshot(ctx)))
+    }
+}
+
+impl_snapshot_for!(struct Pointer {
+    alloc_id,
+    offset -> *offset,
+});
+
+impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar
+    where Ctx: SnapshotContext<'a>,
+{
+    type Item = Scalar<AllocIdSnapshot<'a>>;
+
+    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+        match self {
+            Scalar::Ptr(p) => Scalar::Ptr(p.snapshot(ctx)),
+            Scalar::Bits{ size, bits } => Scalar::Bits {
+                size: *size,
+                bits: *bits,
+            },
+        }
+    }
+}
+
+impl_snapshot_for!(enum ScalarMaybeUndef {
+    Scalar(s),
+    Undef,
+});
+
+impl_snapshot_for!(struct MemPlace {
+    ptr,
+    extra,
+    align -> *align,
+});
+
+impl<'a, Ctx> Snapshot<'a, Ctx> for Place
+    where Ctx: SnapshotContext<'a>,
+{
+    type Item = Place<AllocIdSnapshot<'a>>;
+
+    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+        match self {
+            Place::Ptr(p) => Place::Ptr(p.snapshot(ctx)),
+
+            Place::Local{ frame, local } => Place::Local{
+                frame: *frame,
+                local: *local,
+            },
+        }
+    }
+}
+
+impl_snapshot_for!(enum Value {
+    Scalar(s),
+    ScalarPair(s, t),
+});
+
+impl_snapshot_for!(enum Operand {
+    Immediate(v),
+    Indirect(m),
+});
+
+impl_snapshot_for!(enum LocalValue {
+    Live(v),
+    Dead,
+});
+
+impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations
+    where Ctx: SnapshotContext<'a>,
+{
+    type Item = Relocations<AllocIdSnapshot<'a>>;
+
+    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+        Relocations::from_presorted(self.iter()
+            .map(|(size, id)| (*size, id.snapshot(ctx)))
+            .collect())
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct AllocationSnapshot<'a> {
+    bytes: &'a [u8],
+    relocations: Relocations<AllocIdSnapshot<'a>>,
+    undef_mask: &'a UndefMask,
+    align: &'a Align,
+    mutability: &'a Mutability,
+}
+
+impl<'a, Ctx> Snapshot<'a, Ctx> for &'a Allocation
+    where Ctx: SnapshotContext<'a>,
+{
+    type Item = AllocationSnapshot<'a>;
+
+    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+        let Allocation { bytes, relocations, undef_mask, align, mutability } = self;
+
+        AllocationSnapshot {
+            bytes,
+            undef_mask,
+            align,
+            mutability,
+            relocations: relocations.snapshot(ctx),
+        }
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct FrameSnapshot<'a, 'tcx: 'a> {
+    instance: &'a ty::Instance<'tcx>,
+    span: &'a Span,
+    return_to_block: &'a StackPopCleanup,
+    return_place: Place<AllocIdSnapshot<'a>>,
+    locals: IndexVec<mir::Local, LocalValue<AllocIdSnapshot<'a>>>,
+    block: &'a mir::BasicBlock,
+    stmt: usize,
+}
+
+impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
+    where Ctx: SnapshotContext<'a>,
+{
+    type Item = FrameSnapshot<'a, 'tcx>;
+
+    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
+        let Frame {
+            mir: _,
+            instance,
+            span,
+            return_to_block,
+            return_place,
+            locals,
+            block,
+            stmt,
+        } = self;
+
+        FrameSnapshot {
+            instance,
+            span,
+            return_to_block,
+            block,
+            stmt: *stmt,
+            return_place: return_place.snapshot(ctx),
+            locals: locals.iter().map(|local| local.snapshot(ctx)).collect(),
+        }
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct MemorySnapshot<'a, 'mir: 'a, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx> + 'a> {
+    data: &'a M::MemoryData,
+}
+
+impl<'a, 'mir, 'tcx, M> Memory<'a, 'mir, 'tcx, M>
+    where M: Machine<'mir, 'tcx>,
+{
+    fn snapshot<'b: 'a>(&'b self) -> MemorySnapshot<'b, 'mir, 'tcx, M> {
+        let Memory { data, .. } = self;
+        MemorySnapshot { data }
+    }
+}
+
+impl<'a, 'b, 'mir, 'tcx, M> SnapshotContext<'b> for Memory<'a, 'mir, 'tcx, M>
+    where M: Machine<'mir, 'tcx>,
+{
+    fn resolve(&'b self, id: &AllocId) -> Option<&'b Allocation> {
+        self.get(*id).ok()
+    }
+}
+
+/// The virtual machine state during const-evaluation at a given point in time.
+struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
+    machine: M,
+    memory: Memory<'a, 'mir, 'tcx, M>,
+    stack: Vec<Frame<'mir, 'tcx>>,
+}
+
+impl<'a, 'mir, 'tcx, M> EvalSnapshot<'a, 'mir, 'tcx, M>
+    where M: Machine<'mir, 'tcx>,
+{
+    fn new(
+        machine: &M,
+        memory: &Memory<'a, 'mir, 'tcx, M>,
+        stack: &[Frame<'mir, 'tcx>]) -> Self {
+
+        EvalSnapshot {
+            machine: machine.clone(),
+            memory: memory.clone(),
+            stack: stack.into(),
+        }
+    }
+
+    fn snapshot<'b: 'a>(&'b self)
+        -> (&'b M, MemorySnapshot<'b, 'mir, 'tcx, M>, Vec<FrameSnapshot<'a, 'tcx>>) {
+        let EvalSnapshot{ machine, memory, stack } = self;
+        (&machine, memory.snapshot(), stack.iter().map(|frame| frame.snapshot(memory)).collect())
+    }
+}
+
+impl<'a, 'mir, 'tcx, M> Hash for EvalSnapshot<'a, 'mir, 'tcx, M>
+    where M: Machine<'mir, 'tcx>,
+{
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        // Implement in terms of hash stable, so that k1 == k2 -> hash(k1) == hash(k2)
+        let mut hcx = self.memory.tcx.get_stable_hashing_context();
+        let mut hasher = StableHasher::<u64>::new();
+        self.hash_stable(&mut hcx, &mut hasher);
+        hasher.finish().hash(state)
+    }
+}
+
+impl<'a, 'b, 'mir, 'tcx, M> HashStable<StableHashingContext<'b>>
+    for EvalSnapshot<'a, 'mir, 'tcx, M>
+    where M: Machine<'mir, 'tcx>,
+{
+    fn hash_stable<W: StableHasherResult>(
+        &self,
+        hcx: &mut StableHashingContext<'b>,
+        hasher: &mut StableHasher<W>) {
+
+        let EvalSnapshot{ machine, memory, stack } = self;
+        (machine, &memory.data, stack).hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'mir, 'tcx, M> Eq for EvalSnapshot<'a, 'mir, 'tcx, M>
+    where M: Machine<'mir, 'tcx>,
+{}
+
+impl<'a, 'mir, 'tcx, M> PartialEq for EvalSnapshot<'a, 'mir, 'tcx, M>
+    where M: Machine<'mir, 'tcx>,
+{
+    fn eq(&self, other: &Self) -> bool {
+        self.snapshot() == other.snapshot()
+    }
+}
index 114ef093ec2fddd90327a2cfcbfe9326b36ad91c..545333e8791760fd29306e59154c4e51b972d271 100644 (file)
@@ -73,7 +73,12 @@ pub fn inc_step_counter_and_detect_loops(&mut self) -> EvalResult<'tcx, ()> {
                 "Constant evaluating a complex constant, this might take some time");
         }
 
-        self.loop_detector.observe_and_analyze(&self.machine, &self.stack, &self.memory)
+        self.loop_detector.observe_and_analyze(
+            &self.tcx,
+            &self.machine,
+            &self.memory,
+            &self.stack[..],
+        )
     }
 
     pub fn run(&mut self) -> EvalResult<'tcx> {
index 5166f69ba03304c49572d760cb514139184e2436..4245136ef213174cf3e16ffb8a8358636fa2d4f4 100644 (file)
@@ -686,7 +686,9 @@ fn def_id_visibility(&self, did: DefId) -> ty::Visibility {
                         // visibility to within the crate.
                         let struct_def_id = self.tcx.hir.get_parent_did(node_id);
                         let adt_def = self.tcx.adt_def(struct_def_id);
-                        if adt_def.is_non_exhaustive() && ctor_vis == ty::Visibility::Public {
+                        if adt_def.non_enum_variant().is_field_list_non_exhaustive()
+                            && ctor_vis == ty::Visibility::Public
+                        {
                             ctor_vis = ty::Visibility::Restricted(
                                 DefId::local(CRATE_DEF_INDEX));
                         }
index 80f6c263e199969648d80321edbe79fb49ad4612..37868a83e342168727f1623c8f2b0e7c5724cca4 100644 (file)
@@ -181,6 +181,23 @@ fn build_reduced_graph_for_use_tree(
                     self.session.features_untracked().uniform_paths);
 
             let source = module_path[0];
+
+            // HACK(eddyb) For `use x::{self, ...};`, use the ID of the
+            // `self` nested import for the canary. This allows the
+            // ambiguity reporting scope to ignore false positives
+            // in the same way it does for `use x;` (by comparing IDs).
+            let mut canary_id = id;
+            if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
+                for &(ref use_tree, id) in items {
+                    if let ast::UseTreeKind::Simple(..) = use_tree.kind {
+                        if use_tree.ident().name == keywords::SelfValue.name() {
+                            canary_id = id;
+                            break;
+                        }
+                    }
+                }
+            }
+
             // Helper closure to emit a canary with the given base path.
             let emit = |this: &mut Self, base: Option<Ident>| {
                 let subclass = SingleImport {
@@ -200,7 +217,7 @@ fn build_reduced_graph_for_use_tree(
                     base.into_iter().collect(),
                     subclass.clone(),
                     source.span,
-                    id,
+                    canary_id,
                     root_use_tree.span,
                     root_id,
                     ty::Visibility::Invisible,
index c60f9293d58e71428481cec776465b558a81d418..73c9af0d11c47f155046f52d018720fd4b2a6aee 100644 (file)
@@ -664,6 +664,14 @@ struct UniformPathsCanaryResult {
 
                 self.per_ns(|_, ns| {
                     if let Some(result) = result[ns].get().ok() {
+                        if let NameBindingKind::Import { directive, .. } = result.kind {
+                            // Skip canaries that resolve to the import itself.
+                            // These come from `use crate_name;`, which isn't really
+                            // ambiguous, as the import can't actually shadow itself.
+                            if directive.id == import.id {
+                                return;
+                            }
+                        }
                         if has_explicit_self {
                             // There should only be one `self::x` (module-scoped) canary.
                             assert_eq!(canary_results[ns].module_scope, None);
@@ -718,22 +726,6 @@ struct UniformPathsCanaryResult {
 
                 errors = true;
 
-                // Special-case the error when `self::x` finds its own `use x;`.
-                if has_external_crate &&
-                   results.module_scope == Some(span) &&
-                   results.block_scopes.is_empty() {
-                    let msg = format!("`{}` import is redundant", name);
-                    this.session.struct_span_err(span, &msg)
-                        .span_label(span,
-                            format!("refers to external crate `::{}`", name))
-                        .span_label(span,
-                            format!("defines `self::{}`, shadowing itself", name))
-                        .help(&format!("remove or write `::{}` explicitly instead", name))
-                        .note("relative `use` paths enabled by `#![feature(uniform_paths)]`")
-                        .emit();
-                    return;
-                }
-
                 let msg = format!("`{}` import is ambiguous", name);
                 let mut err = this.session.struct_span_err(span, &msg);
                 let mut suggestion_choices = String::new();
index 6b5abbfa4a6f75ea00f216596694b489605d3b7c..2a8ee4bd8df0eeeb9feb5e19bbecb337641271c0 100644 (file)
@@ -950,7 +950,7 @@ fn check_struct_pat_fields(&self,
         }
 
         // Require `..` if struct has non_exhaustive attribute.
-        if adt.is_struct() && adt.is_non_exhaustive() && !adt.did.is_local() && !etc {
+        if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc {
             span_err!(tcx.sess, span, E0638,
                       "`..` required with {} marked as non-exhaustive",
                       kind_name);
index 5cc87e12ed06959a712f745b4db84db26dc7e830..a45e5c8ec2a4511da865c1f128e0729ab0899ca3 100644 (file)
@@ -3471,7 +3471,7 @@ fn check_expr_struct_fields(&self,
         // re-link the regions that EIfEO can erase.
         self.demand_eqtype(span, adt_ty_hint, adt_ty);
 
-        let (substs, adt_kind, kind_name) = match &adt_ty.sty{
+        let (substs, adt_kind, kind_name) = match &adt_ty.sty {
             &ty::Adt(adt, substs) => {
                 (substs, adt.adt_kind(), adt.variant_descr())
             }
@@ -3645,13 +3645,13 @@ fn check_expr_struct(&self,
                          base_expr: &'gcx Option<P<hir::Expr>>) -> Ty<'tcx>
     {
         // Find the relevant variant
-        let (variant, struct_ty) =
-        if let Some(variant_ty) = self.check_struct_path(qpath, expr.id) {
-            variant_ty
-        } else {
-            self.check_struct_fields_on_error(fields, base_expr);
-            return self.tcx.types.err;
-        };
+        let (variant, adt_ty) =
+            if let Some(variant_ty) = self.check_struct_path(qpath, expr.id) {
+                variant_ty
+            } else {
+                self.check_struct_fields_on_error(fields, base_expr);
+                return self.tcx.types.err;
+            };
 
         let path_span = match *qpath {
             hir::QPath::Resolved(_, ref path) => path.span,
@@ -3659,23 +3659,22 @@ fn check_expr_struct(&self,
         };
 
         // Prohibit struct expressions when non exhaustive flag is set.
-        if let ty::Adt(adt, _) = struct_ty.sty {
-            if !adt.did.is_local() && adt.is_non_exhaustive() {
-                span_err!(self.tcx.sess, expr.span, E0639,
-                          "cannot create non-exhaustive {} using struct expression",
-                          adt.variant_descr());
-            }
+        let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");
+        if !adt.did.is_local() && variant.is_field_list_non_exhaustive() {
+            span_err!(self.tcx.sess, expr.span, E0639,
+                      "cannot create non-exhaustive {} using struct expression",
+                      adt.variant_descr());
         }
 
-        let error_happened = self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span,
+        let error_happened = self.check_expr_struct_fields(adt_ty, expected, expr.id, path_span,
                                                            variant, fields, base_expr.is_none());
         if let &Some(ref base_expr) = base_expr {
             // If check_expr_struct_fields hit an error, do not attempt to populate
             // the fields with the base_expr. This could cause us to hit errors later
             // when certain fields are assumed to exist that in fact do not.
             if !error_happened {
-                self.check_expr_has_type_or_error(base_expr, struct_ty);
-                match struct_ty.sty {
+                self.check_expr_has_type_or_error(base_expr, adt_ty);
+                match adt_ty.sty {
                     ty::Adt(adt, substs) if adt.is_struct() => {
                         let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| {
                             self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs))
@@ -3693,8 +3692,8 @@ fn check_expr_struct(&self,
                 }
             }
         }
-        self.require_type_is_sized(struct_ty, expr.span, traits::StructInitializerSized);
-        struct_ty
+        self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized);
+        adt_ty
     }
 
 
index b956c72b3a2da53c0d8fde1b847165a1a108b7ac..7997801a9a5fb435fead11d698c4eb8a761e098f 100644 (file)
@@ -549,12 +549,13 @@ fn convert_enum_variant_types<'a, 'tcx>(
     }
 }
 
-fn convert_struct_variant<'a, 'tcx>(
+fn convert_variant<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     did: DefId,
     name: ast::Name,
     discr: ty::VariantDiscr,
     def: &hir::VariantData,
+    adt_kind: ty::AdtKind
 ) -> ty::VariantDef {
     let mut seen_fields: FxHashMap<ast::Ident, Span> = FxHashMap();
     let node_id = tcx.hir.as_local_node_id(did).unwrap();
@@ -585,13 +586,13 @@ fn convert_struct_variant<'a, 'tcx>(
             }
         })
         .collect();
-    ty::VariantDef {
+    ty::VariantDef::new(tcx,
         did,
         name,
         discr,
         fields,
-        ctor_kind: CtorKind::from_hir(def),
-    }
+        adt_kind,
+        CtorKind::from_hir(def))
 }
 
 fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::AdtDef {
@@ -621,7 +622,7 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad
                         };
                         distance_from_explicit += 1;
 
-                        convert_struct_variant(tcx, did, v.node.name, discr, &v.node.data)
+                        convert_variant(tcx, did, v.node.name, discr, &v.node.data, AdtKind::Enum)
                     })
                     .collect(),
             )
@@ -635,23 +636,25 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad
             };
             (
                 AdtKind::Struct,
-                vec![convert_struct_variant(
+                vec![convert_variant(
                     tcx,
                     ctor_id.unwrap_or(def_id),
                     item.name,
                     ty::VariantDiscr::Relative(0),
                     def,
+                    AdtKind::Struct
                 )],
             )
         }
         ItemKind::Union(ref def, _) => (
             AdtKind::Union,
-            vec![convert_struct_variant(
+            vec![convert_variant(
                 tcx,
                 def_id,
                 item.name,
                 ty::VariantDiscr::Relative(0),
                 def,
+                AdtKind::Union
             )],
         ),
         _ => bug!(),
@@ -1796,6 +1799,21 @@ fn explicit_predicates_of<'a, 'tcx>(
             &hir::WherePredicate::BoundPredicate(ref bound_pred) => {
                 let ty = icx.to_ty(&bound_pred.bounded_ty);
 
+                // Keep the type around in a WF predicate, in case of no bounds.
+                // That way, `where Ty:` is not a complete noop (see #53696).
+                if bound_pred.bounds.is_empty() {
+                    if let ty::Param(_) = ty.sty {
+                        // This is a `where T:`, which can be in the HIR from the
+                        // transformation that moves `?Sized` to `T`'s declaration.
+                        // We can skip the predicate because type parameters are
+                        // trivially WF, but also we *should*, to avoid exposing
+                        // users who never wrote `where Type:,` themselves, to
+                        // compiler/tooling bugs from not handling WF predicates.
+                    } else {
+                        predicates.push(ty::Predicate::WellFormed(ty));
+                    }
+                }
+
                 for bound in bound_pred.bounds.iter() {
                     match bound {
                         &hir::GenericBound::Trait(ref poly_trait_ref, _) => {
index 5c23d0f6b399083a1172e7ee631ca9d5f721fde1..da18e3e6b91b39d52c18cafb7fa3991f06ed8dc7 100644 (file)
@@ -1312,7 +1312,13 @@ fn clean(&self, cx: &DocContext) -> WherePredicate {
             Predicate::RegionOutlives(ref pred) => pred.clean(cx),
             Predicate::TypeOutlives(ref pred) => pred.clean(cx),
             Predicate::Projection(ref pred) => pred.clean(cx),
-            Predicate::WellFormed(_) => panic!("not user writable"),
+            Predicate::WellFormed(ty) => {
+                // This comes from `where Ty:` (i.e. no bounds) (see #53696).
+                WherePredicate::BoundPredicate {
+                    ty: ty.clean(cx),
+                    bounds: vec![],
+                }
+            }
             Predicate::ObjectSafe(_) => panic!("not user writable"),
             Predicate::ClosureKind(..) => panic!("not user writable"),
             Predicate::ConstEvaluatable(..) => panic!("not user writable"),
index e177d4a988ae7d9c5ac943307f42f323ffe37a3b..f14d55cb2d34f1ea8c443b8a197846307d3c0360 100644 (file)
@@ -1566,6 +1566,12 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
 /// On success, the total number of bytes copied is returned and it is equal to
 /// the length of the `to` file as reported by `metadata`.
 ///
+/// If you’re wanting to copy the contents of one file to another and you’re
+/// working with [`File`]s, see the [`io::copy`] function.
+///
+/// [`io::copy`]: ../io/fn.copy.html
+/// [`File`]: ./struct.File.html
+///
 /// # Platform-specific behavior
 ///
 /// This function currently corresponds to the `open` function in Unix
index 33f741dbc38f22716aa2762b959be5108c9d7c4a..371e5b21c13b26c117b915b4ec04d22d8ad764b1 100644 (file)
 /// On success, the total number of bytes that were copied from
 /// `reader` to `writer` is returned.
 ///
+/// If you’re wanting to copy the contents of one file to another and you’re
+/// working with filesystem paths, see the [`fs::copy`] function.
+///
+/// [`fs::copy`]: ../fs/fn.copy.html
+///
 /// # Errors
 ///
 /// This function will return an error immediately if any call to `read` or
diff --git a/src/test/run-pass/redundant.rs b/src/test/run-pass/redundant.rs
new file mode 100644 (file)
index 0000000..39bd316
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+#![feature(uniform_paths)]
+
+use std;
+
+mod foo {
+    pub use std as my_std;
+}
+
+mod bar {
+    pub use std::{self};
+}
+
+fn main() {
+    self::std::io::stdout();
+    foo::my_std::io::stdout();
+    bar::std::io::stdout();
+}
index 9d41eca8fe5d2c742d13985aad8240a4e8167068..83fb24cda088cd1bdb7b600a6bcdfde6c9d67391 100644 (file)
@@ -30,4 +30,33 @@ fn main() {
     match enum_unit {
         _ => "no error with only wildcard"
     };
+
+
+    // issue #53549 - check that variant constructors can still be called normally.
+
+    match NonExhaustiveEnum::Unit {
+        NonExhaustiveEnum::Unit => {},
+        _ => {}
+    };
+
+    match NonExhaustiveEnum::Tuple(2) {
+        NonExhaustiveEnum::Tuple(2) => {},
+        _ => {}
+    };
+
+    match (NonExhaustiveEnum::Unit {}) {
+        NonExhaustiveEnum::Unit {} => {},
+        _ => {}
+    };
+
+    match (NonExhaustiveEnum::Tuple { 0: 2 }) {
+        NonExhaustiveEnum::Tuple { 0: 2 } => {},
+        _ => {}
+    };
+
+    match (NonExhaustiveEnum::Struct { field: 2 }) {
+        NonExhaustiveEnum::Struct { field: 2 } => {},
+        _ => {}
+    };
+
 }
index 57e95e39cd9960ee4547344836f0160b0848b706..5305591b8434547402ee4ca0e918403cf9b08e01 100644 (file)
 use std::borrow::Borrow;
 
 #[rustc_dump_program_clauses] //~ ERROR program clause dump
-trait Foo<'a, 'b, S, T, U> where S: Debug, T: Borrow<U>, U: ?Sized, 'a: 'b, U: 'b {
+trait Foo<'a, 'b, S, T, U>
+where
+    S: Debug,
+    T: Borrow<U>,
+    U: ?Sized,
+    'a: 'b,
+    U: 'b,
+    Vec<T>:, // NOTE(#53696) this checks an empty list of bounds.
+{
     fn s(_: S) -> S;
     fn t(_: T) -> T;
     fn u(_: U) -> U;
index 5ea397d424b63986b885c9c10fb5f5bf7a768611..ad3546da1a25b4e93432af8be214dcce119757c7 100644 (file)
@@ -11,7 +11,8 @@ LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump
    = note: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
    = note: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
    = note: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
-   = note: WellFormed(Self: Foo<'a, 'b, S, T, U>) :- Implemented(Self: Foo<'a, 'b, S, T, U>), WellFormed(S: std::marker::Sized), WellFormed(T: std::marker::Sized), WellFormed(S: std::fmt::Debug), WellFormed(T: std::borrow::Borrow<U>), RegionOutlives('a : 'b), TypeOutlives(U : 'b).
+   = note: WellFormed(Self: Foo<'a, 'b, S, T, U>) :- Implemented(Self: Foo<'a, 'b, S, T, U>), WellFormed(S: std::marker::Sized), WellFormed(T: std::marker::Sized), WellFormed(S: std::fmt::Debug), WellFormed(T: std::borrow::Borrow<U>), RegionOutlives('a : 'b), TypeOutlives(U : 'b), WellFormed(std::vec::Vec<T>).
+   = note: WellFormed(std::vec::Vec<T>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-eval/issue-52475.rs b/src/test/ui/consts/const-eval/issue-52475.rs
new file mode 100644 (file)
index 0000000..1c1e653
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_let)]
+
+fn main() {
+    let _ = [(); {
+        //~^ WARNING Constant evaluating a complex constant, this might take some time
+        //~| ERROR could not evaluate repeat length
+        let mut x = &0;
+        let mut n = 0;
+        while n < 5 { //~ ERROR constant contains unimplemented expression type
+            n = (n + 1) % 5;
+            x = &0; // Materialize a new AllocId
+        }
+        0
+    }];
+}
diff --git a/src/test/ui/consts/const-eval/issue-52475.stderr b/src/test/ui/consts/const-eval/issue-52475.stderr
new file mode 100644 (file)
index 0000000..f45587f
--- /dev/null
@@ -0,0 +1,42 @@
+error[E0019]: constant contains unimplemented expression type
+  --> $DIR/issue-52475.rs:19:9
+   |
+LL | /         while n < 5 { //~ ERROR constant contains unimplemented expression type
+LL | |             n = (n + 1) % 5;
+LL | |             x = &0; // Materialize a new AllocId
+LL | |         }
+   | |_________^
+
+warning: Constant evaluating a complex constant, this might take some time
+  --> $DIR/issue-52475.rs:14:18
+   |
+LL |       let _ = [(); {
+   |  __________________^
+LL | |         //~^ WARNING Constant evaluating a complex constant, this might take some time
+LL | |         //~| ERROR could not evaluate repeat length
+LL | |         let mut x = &0;
+...  |
+LL | |         0
+LL | |     }];
+   | |_____^
+
+error[E0080]: could not evaluate repeat length
+  --> $DIR/issue-52475.rs:14:18
+   |
+LL |       let _ = [(); {
+   |  __________________^
+LL | |         //~^ WARNING Constant evaluating a complex constant, this might take some time
+LL | |         //~| ERROR could not evaluate repeat length
+LL | |         let mut x = &0;
+...  |
+LL | |             n = (n + 1) % 5;
+   | |                 ----------- duplicate interpreter state observed here, const evaluation will never terminate
+...  |
+LL | |         0
+LL | |     }];
+   | |_____^
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0019, E0080.
+For more information about an error, try `rustc --explain E0019`.
index 767d8a84c041d2abbc78e67e94807d32b67e4999..0aa85d3ed7a3d36f248e6d25c10b99f68c55adbd 100644 (file)
@@ -4,18 +4,18 @@ error[E0161]: cannot move a value of type str: the size of str cannot be statica
 LL |     S[0];
    |     ^^^^
 
-error[E0507]: cannot move out of borrowed content
-  --> $DIR/dst-index.rs:41:5
-   |
-LL |     S[0];
-   |     ^^^^ cannot move out of borrowed content
-
 error[E0161]: cannot move a value of type dyn std::fmt::Debug: the size of dyn std::fmt::Debug cannot be statically determined
   --> $DIR/dst-index.rs:44:5
    |
 LL |     T[0];
    |     ^^^^
 
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dst-index.rs:41:5
+   |
+LL |     S[0];
+   |     ^^^^ cannot move out of borrowed content
+
 error[E0507]: cannot move out of borrowed content
   --> $DIR/dst-index.rs:44:5
    |
index 5eadcc3def5ff529ce20ad5412306da74f755221..b120da773a24a3448d80882dfaf46fa498d4be5d 100644 (file)
@@ -4,18 +4,18 @@ error[E0161]: cannot move a value of type str: the size of str cannot be statica
 LL |     let _x: Box<str> = box *"hello world";
    |                            ^^^^^^^^^^^^^^
 
-error[E0507]: cannot move out of borrowed content
-  --> $DIR/dst-rvalue.rs:16:28
-   |
-LL |     let _x: Box<str> = box *"hello world";
-   |                            ^^^^^^^^^^^^^^ cannot move out of borrowed content
-
 error[E0161]: cannot move a value of type [isize]: the size of [isize] cannot be statically determined
   --> $DIR/dst-rvalue.rs:21:32
    |
 LL |     let _x: Box<[isize]> = box *array;
    |                                ^^^^^^
 
+error[E0507]: cannot move out of borrowed content
+  --> $DIR/dst-rvalue.rs:16:28
+   |
+LL |     let _x: Box<str> = box *"hello world";
+   |                            ^^^^^^^^^^^^^^ cannot move out of borrowed content
+
 error[E0508]: cannot move out of type `[isize]`, a non-copy slice
   --> $DIR/dst-rvalue.rs:21:32
    |
diff --git a/src/test/ui/error-codes/E0161.ast.stderr b/src/test/ui/error-codes/E0161.ast.stderr
new file mode 100644 (file)
index 0000000..62e8676
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+  --> $DIR/E0161.rs:32:9
+   |
+LL |     box *x; //~ ERROR E0161
+   |         ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/error-codes/E0161.astul.stderr b/src/test/ui/error-codes/E0161.astul.stderr
new file mode 100644 (file)
index 0000000..79080fb
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+  --> $DIR/E0161.rs:32:5
+   |
+LL |     box *x; //~ ERROR E0161
+   |     ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/error-codes/E0161.edition.stderr b/src/test/ui/error-codes/E0161.edition.stderr
new file mode 100644 (file)
index 0000000..62e8676
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+  --> $DIR/E0161.rs:32:9
+   |
+LL |     box *x; //~ ERROR E0161
+   |         ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/error-codes/E0161.editionul.stderr b/src/test/ui/error-codes/E0161.editionul.stderr
new file mode 100644 (file)
index 0000000..79080fb
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+  --> $DIR/E0161.rs:32:5
+   |
+LL |     box *x; //~ ERROR E0161
+   |     ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/error-codes/E0161.nll.stderr b/src/test/ui/error-codes/E0161.nll.stderr
new file mode 100644 (file)
index 0000000..62e8676
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+  --> $DIR/E0161.rs:32:9
+   |
+LL |     box *x; //~ ERROR E0161
+   |         ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/error-codes/E0161.nllul.stderr b/src/test/ui/error-codes/E0161.nllul.stderr
new file mode 100644 (file)
index 0000000..79080fb
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+  --> $DIR/E0161.rs:32:5
+   |
+LL |     box *x; //~ ERROR E0161
+   |     ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
index 81adf9083024d62d4d1f41be911dfc1365ee178e..edc5a84a8436753e35a6757c5618946fb813ae29 100644 (file)
@@ -8,9 +8,28 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-compare-mode-nll
+
+// Check that E0161 is a hard error in all possible configurations that might
+// affect it.
+
+// revisions: ast nll zflags edition astul nllul zflagsul editionul
+//[zflags]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+//[edition]edition:2018
+//[zflagsul]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+//[editionul]edition:2018
+
+#![cfg_attr(nll, feature(nll))]
+#![cfg_attr(nllul, feature(nll))]
+#![cfg_attr(astul, feature(unsized_locals))]
+#![cfg_attr(zflagsul, feature(unsized_locals))]
+#![cfg_attr(nllul, feature(unsized_locals))]
+#![cfg_attr(editionul, feature(unsized_locals))]
+
 #![feature(box_syntax)]
 
-fn main() {
-    let _x: Box<str> = box *"hello"; //~ ERROR E0161
-                                     //~^ ERROR E0507
+fn foo(x: Box<[i32]>) {
+    box *x; //~ ERROR E0161
 }
+
+fn main() {}
diff --git a/src/test/ui/error-codes/E0161.zflags.stderr b/src/test/ui/error-codes/E0161.zflags.stderr
new file mode 100644 (file)
index 0000000..62e8676
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+  --> $DIR/E0161.rs:32:9
+   |
+LL |     box *x; //~ ERROR E0161
+   |         ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/error-codes/E0161.zflagsul.stderr b/src/test/ui/error-codes/E0161.zflagsul.stderr
new file mode 100644 (file)
index 0000000..79080fb
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0161]: cannot move a value of type [i32]: the size of [i32] cannot be statically determined
+  --> $DIR/E0161.rs:32:5
+   |
+LL |     box *x; //~ ERROR E0161
+   |     ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0161`.
diff --git a/src/test/ui/rust-2018/uniform-paths/redundant.rs b/src/test/ui/rust-2018/uniform-paths/redundant.rs
deleted file mode 100644 (file)
index 8f384b7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// edition:2018
-
-#![feature(uniform_paths)]
-
-use std;
-
-fn main() {}
diff --git a/src/test/ui/rust-2018/uniform-paths/redundant.stderr b/src/test/ui/rust-2018/uniform-paths/redundant.stderr
deleted file mode 100644 (file)
index dd38407..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: `std` import is redundant
-  --> $DIR/redundant.rs:15:5
-   |
-LL | use std;
-   |     ^^^
-   |     |
-   |     refers to external crate `::std`
-   |     defines `self::std`, shadowing itself
-   |
-   = help: remove or write `::std` explicitly instead
-   = note: relative `use` paths enabled by `#![feature(uniform_paths)]`
-
-error: aborting due to previous error
-
index 3ed9e5d9f1eb58123a5551b9bb75a29cbad3dfa7..59bb8326ddbf5ba07fe69d3785d38fff5f95e5e1 100644 (file)
@@ -10,7 +10,6 @@
 
 // Test that we check where-clauses on fn items.
 
-#![feature(associated_type_defaults)]
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
 
@@ -20,5 +19,9 @@ fn foo<T,U>() where T: ExtraCopy<U> //~ ERROR E0277
 {
 }
 
+fn bar() where Vec<dyn Copy>:, {}
+//~^ ERROR E0277
+//~| ERROR E0038
+
 #[rustc_error]
 fn main() { }
index 5f0f982577ee55bff7d5049f1620b055d2df17ac..21591419ec856becec482c916c136eecbfceebb3 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied
-  --> $DIR/wf-fn-where-clause.rs:19:1
+  --> $DIR/wf-fn-where-clause.rs:18:1
    |
 LL | / fn foo<T,U>() where T: ExtraCopy<U> //~ ERROR E0277
 LL | | {
@@ -8,11 +8,30 @@ LL | | }
    |
    = help: consider adding a `where U: std::marker::Copy` bound
 note: required by `ExtraCopy`
-  --> $DIR/wf-fn-where-clause.rs:17:1
+  --> $DIR/wf-fn-where-clause.rs:16:1
    |
 LL | trait ExtraCopy<T:Copy> { }
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error[E0277]: the size for values of type `(dyn std::marker::Copy + 'static)` cannot be known at compilation time
+  --> $DIR/wf-fn-where-clause.rs:22:1
+   |
+LL | fn bar() where Vec<dyn Copy>:, {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: required by `std::vec::Vec`
+
+error[E0038]: the trait `std::marker::Copy` cannot be made into an object
+  --> $DIR/wf-fn-where-clause.rs:22:1
+   |
+LL | fn bar() where Vec<dyn Copy>:, {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors occurred: E0038, E0277.
+For more information about an error, try `rustc --explain E0038`.
index 2a284a70e26997273c296afe06586ffdf3a142fd..d0fc1788123de9844c8088b977cd142021cea1f2 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2a284a70e26997273c296afe06586ffdf3a142fd
+Subproject commit d0fc1788123de9844c8088b977cd142021cea1f2
index 3dbe998969d457c5cef245f61b48bdaed0f5c059..7728fa22bebea288abfea3b70cf795c60b93df3a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3dbe998969d457c5cef245f61b48bdaed0f5c059
+Subproject commit 7728fa22bebea288abfea3b70cf795c60b93df3a