]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #50709 - alexcrichton:revert-musl, r=sfackler
authorbors <bors@rust-lang.org>
Sat, 19 May 2018 03:10:53 +0000 (03:10 +0000)
committerbors <bors@rust-lang.org>
Sat, 19 May 2018 03:10:53 +0000 (03:10 +0000)
Revert #50105 until regression is fixed

Discovered at https://github.com/rust-lang/rust/pull/50105#issuecomment-388630750 it looks like this caused a regression with i686 musl, so let's revert in the meantime while a fix is worked out

195 files changed:
src/Cargo.lock
src/bootstrap/bin/rustc.rs
src/bootstrap/builder.rs
src/bootstrap/channel.rs
src/bootstrap/compile.rs
src/bootstrap/flags.rs
src/bootstrap/test.rs
src/bootstrap/tool.rs
src/doc/grammar.md
src/doc/tutorial.md
src/liballoc/Cargo.toml
src/liballoc/alloc.rs
src/liballoc/lib.rs
src/liballoc/slice.rs
src/liballoc/str.rs
src/liballoc/tests/lib.rs
src/liballoc/vec.rs
src/liballoc_jemalloc/lib.rs
src/liballoc_system/lib.rs
src/libarena/lib.rs
src/libcore/Cargo.toml
src/libcore/clone.rs
src/libcore/internal_macros.rs
src/libcore/intrinsics.rs
src/libcore/lib.rs
src/libcore/marker.rs
src/libcore/num/f32.rs
src/libcore/num/f64.rs
src/libcore/num/mod.rs
src/libcore/ops/range.rs
src/libcore/option.rs
src/libcore/prelude/v1.rs
src/libcore/ptr.rs
src/libcore/slice/mod.rs
src/libcore/str/mod.rs
src/libcore/tests/lib.rs
src/libcore/tests/num/uint_macros.rs
src/libcore/tests/ptr.rs
src/libcore/tests/slice.rs
src/libfmt_macros/lib.rs
src/libproc_macro/lib.rs
src/librustc/hir/lowering.rs
src/librustc/hir/print.rs
src/librustc/ich/impls_syntax.rs
src/librustc/lib.rs
src/librustc/lint/builtin.rs
src/librustc/middle/cstore.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/region.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/fulfill.rs
src/librustc/traits/project.rs
src/librustc_allocator/expand.rs
src/librustc_codegen_llvm/intrinsic.rs
src/librustc_codegen_llvm/lib.rs
src/librustc_data_structures/bitvec.rs
src/librustc_data_structures/snapshot_map/mod.rs
src/librustc_driver/lib.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/schema.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/dfs.rs [deleted file]
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/values.rs
src/librustc_mir/lib.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/util/pretty.rs
src/librustc_passes/ast_validation.rs
src/librustc_plugin/registry.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_resolve/resolve_imports.rs
src/librustc_target/lib.rs
src/librustc_traits/normalize_projection_ty.rs
src/librustc_typeck/check/autoderef.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/lib.rs
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/lib.rs
src/libstd/alloc.rs
src/libstd/f32.rs
src/libstd/f64.rs
src/libstd/lib.rs
src/libsyntax/ast.rs
src/libsyntax/edition.rs [deleted file]
src/libsyntax/ext/base.rs
src/libsyntax/ext/derive.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/lib.rs
src/libsyntax/parse/lexer/comments.rs
src/libsyntax/parse/lexer/mod.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax/std_inject.rs
src/libsyntax/str.rs
src/libsyntax/test.rs
src/libsyntax_ext/asm.rs
src/libsyntax_ext/format.rs
src/libsyntax_ext/lib.rs
src/libsyntax_ext/proc_macro_registrar.rs
src/libsyntax_pos/edition.rs [new file with mode: 0644]
src/libsyntax_pos/hygiene.rs
src/libsyntax_pos/lib.rs
src/libsyntax_pos/symbol.rs
src/libtest/formatters/pretty.rs
src/libtest/formatters/terse.rs
src/rtstartup/rsbegin.rs
src/rustc/Cargo.toml
src/stage0.txt
src/test/COMPILER_TESTS.md
src/test/compile-fail/array_const_index-0.rs
src/test/compile-fail/array_const_index-1.rs
src/test/compile-fail/const-slice-oob.rs
src/test/compile-fail/eval-enum.rs
src/test/incremental/warnings-reemitted.rs
src/test/mir-opt/end_region_destruction_extents_1.rs
src/test/mir-opt/match_false_edges.rs
src/test/mir-opt/nll/region-liveness-two-disjoint-uses.rs
src/test/run-fail/overflowing-add.rs
src/test/run-fail/overflowing-mul.rs
src/test/run-fail/overflowing-neg.rs
src/test/run-fail/overflowing-sub.rs
src/test/run-pass-fulldeps/auxiliary/plugin_args.rs
src/test/run-pass/align-offset-sign.rs [deleted file]
src/test/run-pass/auxiliary/edition-kw-macro-2015.rs [new file with mode: 0644]
src/test/run-pass/auxiliary/edition-kw-macro-2018.rs [new file with mode: 0644]
src/test/run-pass/edition-keywords-2015-2015.rs [new file with mode: 0644]
src/test/run-pass/edition-keywords-2015-2018.rs [new file with mode: 0644]
src/test/run-pass/edition-keywords-2018-2015.rs [new file with mode: 0644]
src/test/run-pass/edition-keywords-2018-2018.rs [new file with mode: 0644]
src/test/run-pass/issue-49955-2.rs [new file with mode: 0644]
src/test/run-pass/issue-49955.rs [new file with mode: 0644]
src/test/run-pass/nll/get_default.rs [deleted file]
src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs [new file with mode: 0644]
src/test/rustdoc/auto-impl-primitive.rs [new file with mode: 0644]
src/test/ui/E0508.ast.nll.stderr [new file with mode: 0644]
src/test/ui/E0508.ast.stderr [new file with mode: 0644]
src/test/ui/E0508.mir.stderr [new file with mode: 0644]
src/test/ui/E0508.rs [new file with mode: 0644]
src/test/ui/auxiliary/edition-kw-macro-2015.rs [new file with mode: 0644]
src/test/ui/auxiliary/edition-kw-macro-2018.rs [new file with mode: 0644]
src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr
src/test/ui/const-eval-overflow-2.rs
src/test/ui/const-eval-overflow-4.rs
src/test/ui/const-eval-overflow-4.stderr
src/test/ui/const-eval/conditional_array_execution.rs
src/test/ui/const-eval/conditional_array_execution.stderr
src/test/ui/const-eval/issue-43197.rs
src/test/ui/const-eval/issue-43197.stderr
src/test/ui/const-eval/issue-44578.rs
src/test/ui/const-eval/issue-44578.stderr
src/test/ui/const-eval/promoted_errors.rs
src/test/ui/const-eval/promoted_errors.stderr
src/test/ui/const-eval/pub_const_err.rs
src/test/ui/const-eval/pub_const_err.stderr
src/test/ui/const-eval/pub_const_err_bin.rs
src/test/ui/const-eval/pub_const_err_bin.stderr
src/test/ui/const-len-underflow-separate-spans.rs
src/test/ui/const-len-underflow-separate-spans.stderr
src/test/ui/edition-keywords-2015-2015-expansion.rs [new file with mode: 0644]
src/test/ui/edition-keywords-2015-2015-parsing.rs [new file with mode: 0644]
src/test/ui/edition-keywords-2015-2015-parsing.stderr [new file with mode: 0644]
src/test/ui/edition-keywords-2015-2018-expansion.rs [new file with mode: 0644]
src/test/ui/edition-keywords-2015-2018-expansion.stderr [new file with mode: 0644]
src/test/ui/edition-keywords-2015-2018-parsing.rs [new file with mode: 0644]
src/test/ui/edition-keywords-2015-2018-parsing.stderr [new file with mode: 0644]
src/test/ui/edition-keywords-2018-2015-expansion.rs [new file with mode: 0644]
src/test/ui/edition-keywords-2018-2015-parsing.rs [new file with mode: 0644]
src/test/ui/edition-keywords-2018-2015-parsing.stderr [new file with mode: 0644]
src/test/ui/edition-keywords-2018-2018-expansion.rs [new file with mode: 0644]
src/test/ui/edition-keywords-2018-2018-expansion.stderr [new file with mode: 0644]
src/test/ui/edition-keywords-2018-2018-parsing.rs [new file with mode: 0644]
src/test/ui/edition-keywords-2018-2018-parsing.stderr [new file with mode: 0644]
src/test/ui/error-codes/E0080.stderr
src/test/ui/fmt/format-string-error.rs
src/test/ui/fmt/format-string-error.stderr
src/test/ui/nll/get_default.nll.stderr
src/test/ui/nll/get_default.rs
src/test/ui/nll/get_default.stderr
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/main.rs
src/tools/compiletest/src/runtest.rs
src/tools/rls
src/tools/rustdoc/Cargo.toml
src/tools/rustfmt

index 00cc530e6324abddd5ae5a1ec7b596e246a283d3..70e34c34b999634454ec5aa62f6238e5236abae8 100644 (file)
@@ -1478,16 +1478,17 @@ dependencies = [
 
 [[package]]
 name = "racer"
-version = "2.0.13"
+version = "2.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1632,12 +1633,12 @@ dependencies = [
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "racer 2.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-rustc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustfmt-nightly 0.7.0",
@@ -1645,6 +1646,7 @@ dependencies = [
  "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1678,7 +1680,7 @@ dependencies = [
 
 [[package]]
 name = "rls-rustc"
-version = "0.2.2"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -1696,7 +1698,7 @@ name = "rls-vfs"
 version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "racer 2.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2736,14 +2738,6 @@ dependencies = [
  "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "toml"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "toml"
 version = "0.4.6"
@@ -3098,7 +3092,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
-"checksum racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "40d44bc30fc8d403b665286b2c9a83466ddbf69297668fb02b785c3e58eb8e0d"
+"checksum racer 2.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "e713729f45f12df5c5e182d39506766f76c09133fb661d3622e0ddf8078911c2"
 "checksum radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "03d0d770481e8af620ca61d3d304bf014f965d7f78e923dc58545e6a545070a9"
 "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
 "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
@@ -3114,7 +3108,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da9794cd1f80f2cb888c00641a32f9855d0226c954ee31cef145784914c7142e"
 "checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2"
 "checksum rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd20763e1c60ae8945384c8a8fa4ac44f8afa7b0a817511f5e8927e5d24f988"
-"checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea"
+"checksum rls-rustc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ed5342b2bbbe8663c04600af506c8902b6b4d3e627b006eb1bd65aa14805f4d"
 "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
 "checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb"
 "checksum rustc-ap-rustc_cratesio_shim 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7374a2b466e6e3ce489e045302e304849355faf7fd033d4d95e6e86e48c313b4"
@@ -3171,7 +3165,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
 "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
 "checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
-"checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4"
 "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9"
 "checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8"
 "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
index 3f97accaa4d84088ecbd8524e359d653dda4aa6c..6f27402233f987e617b61df7cdb3305afa652348 100644 (file)
@@ -288,7 +288,12 @@ fn main() {
     }
 
     if verbose > 1 {
-        eprintln!("rustc command: {:?}", cmd);
+        eprintln!(
+            "rustc command: {:?}={:?} {:?}",
+            bootstrap::util::dylib_path_var(),
+            env::join_paths(&dylib_path).unwrap(),
+            cmd,
+        );
         eprintln!("sysroot: {:?}", sysroot);
         eprintln!("libdir: {:?}", libdir);
     }
index c482adbb390790a6ef3a35507f5739c6ac626330..84d294006693138f4516c260c8a073c972b0cfc7 100644 (file)
@@ -584,11 +584,10 @@ pub fn cargo(&self,
             cargo.env("RUST_CHECK", "1");
         }
 
-        // If we were invoked from `make` then that's already got a jobserver
-        // set up for us so no need to tell Cargo about jobs all over again.
-        if env::var_os("MAKEFLAGS").is_none() && env::var_os("MFLAGS").is_none() {
-             cargo.arg("-j").arg(self.jobs().to_string());
-        }
+        cargo.arg("-j").arg(self.jobs().to_string());
+        // Remove make-related flags to ensure Cargo can correctly set things up
+        cargo.env_remove("MAKEFLAGS");
+        cargo.env_remove("MFLAGS");
 
         // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
         // Force cargo to output binaries with disambiguating hashes in the name
@@ -1457,6 +1456,7 @@ fn test_with_no_doc_stage0() {
             rustc_args: vec![],
             fail_fast: true,
             doc_tests: DocTests::No,
+            bless: false,
         };
 
         let build = Build::new(config);
index 3453933a9652c0881188919706c5db4799ab43e2..a2495f68c1fa3148d2ee07aebda3b18cb9a8cfaa 100644 (file)
@@ -24,7 +24,7 @@
 use config::Config;
 
 // The version number
-pub const CFG_RELEASE_NUM: &str = "1.27.0";
+pub const CFG_RELEASE_NUM: &str = "1.28.0";
 
 pub struct GitInfo {
     inner: Option<Info>,
index 8e0227f8fe143737a4ed6f47366183a6e153ea54..231ed9d40d2de2660492a0a6cc4e431875b5e7a2 100644 (file)
@@ -972,7 +972,7 @@ fn run(self, builder: &Builder) -> Compiler {
 
         // Link the compiler binary itself into place
         let out_dir = builder.cargo_out(build_compiler, Mode::Librustc, host);
-        let rustc = out_dir.join(exe("rustc", &*host));
+        let rustc = out_dir.join(exe("rustc_binary", &*host));
         let bindir = sysroot.join("bin");
         t!(fs::create_dir_all(&bindir));
         let compiler = builder.rustc(target_compiler);
index 5315a3028ffa9c05fa8d3839ff52b223ddad9a4d..90dd5d819b0da2a79330881bb85d5c425a584fc0 100644 (file)
@@ -59,6 +59,8 @@ pub enum Subcommand {
     },
     Test {
         paths: Vec<PathBuf>,
+        /// Whether to automatically update stderr/stdout files
+        bless: bool,
         test_args: Vec<String>,
         rustc_args: Vec<String>,
         fail_fast: bool,
@@ -173,6 +175,7 @@ pub fn parse(args: &[String]) -> Flags {
                 );
                 opts.optflag("", "no-doc", "do not run doc tests");
                 opts.optflag("", "doc", "only run doc tests");
+                opts.optflag("", "bless", "update all stderr/stdout files of failing ui tests");
             },
             "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
             "clean" => { opts.optflag("", "all", "clean all build artifacts"); },
@@ -258,6 +261,7 @@ pub fn parse(args: &[String]) -> Flags {
         ./x.py test src/test/run-pass
         ./x.py test src/libstd --test-args hash_map
         ./x.py test src/libstd --stage 0
+        ./x.py test src/test/ui --bless
 
     If no arguments are passed then the complete artifacts for that stage are
     compiled and tested.
@@ -322,6 +326,7 @@ pub fn parse(args: &[String]) -> Flags {
             "test" => {
                 Subcommand::Test {
                     paths,
+                    bless: matches.opt_present("bless"),
                     test_args: matches.opt_strs("test-args"),
                     rustc_args: matches.opt_strs("rustc-args"),
                     fail_fast: !matches.opt_present("no-fail-fast"),
@@ -424,6 +429,13 @@ pub fn doc_tests(&self) -> DocTests {
             _ => DocTests::Yes,
         }
     }
+
+    pub fn bless(&self) -> bool {
+        match *self {
+            Subcommand::Test { bless, .. } => bless,
+            _ => false,
+        }
+    }
 }
 
 fn split(s: Vec<String>) -> Vec<String> {
index 1f81a617237cc0b82bd3cc1383b3accec1abd077..7a4924f03c8d23eef3cb1ee26cb5b6c690673fcb 100644 (file)
@@ -47,6 +47,16 @@ pub enum TestKind {
     Bench,
 }
 
+impl From<Kind> for TestKind {
+    fn from(kind: Kind) -> Self {
+        match kind {
+            Kind::Test => TestKind::Test,
+            Kind::Bench => TestKind::Bench,
+            _ => panic!("unexpected kind in crate: {:?}", kind)
+        }
+    }
+}
+
 impl TestKind {
     // Return the cargo subcommand for this test kind
     fn subcommand(self) -> &'static str {
@@ -951,6 +961,10 @@ fn run(self, builder: &Builder) {
         cmd.arg("--host").arg(&*compiler.host);
         cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
 
+        if builder.config.cmd.bless() {
+            cmd.arg("--bless");
+        }
+
         if let Some(ref nodejs) = builder.config.nodejs {
             cmd.arg("--nodejs").arg(nodejs);
         }
@@ -1342,13 +1356,7 @@ fn make_run(run: RunConfig) {
 
         for krate in builder.in_tree_crates("rustc-main") {
             if run.path.ends_with(&krate.path) {
-                let test_kind = if builder.kind == Kind::Test {
-                    TestKind::Test
-                } else if builder.kind == Kind::Bench {
-                    TestKind::Bench
-                } else {
-                    panic!("unexpected builder.kind in crate: {:?}", builder.kind);
-                };
+                let test_kind = builder.kind.into();
 
                 builder.ensure(CrateLibrustc {
                     compiler,
@@ -1394,13 +1402,7 @@ fn make_run(run: RunConfig) {
         let builder = run.builder;
         let compiler = builder.compiler(builder.top_stage, run.host);
 
-        let test_kind = if builder.kind == Kind::Test {
-            TestKind::Test
-        } else if builder.kind == Kind::Bench {
-            TestKind::Bench
-        } else {
-            panic!("unexpected builder.kind in crate: {:?}", builder.kind);
-        };
+        let test_kind = builder.kind.into();
 
         builder.ensure(CrateNotDefault {
             compiler,
@@ -1461,13 +1463,7 @@ fn make_run(run: RunConfig) {
         let compiler = builder.compiler(builder.top_stage, run.host);
 
         let make = |mode: Mode, krate: &CargoCrate| {
-            let test_kind = if builder.kind == Kind::Test {
-                TestKind::Test
-            } else if builder.kind == Kind::Bench {
-                TestKind::Bench
-            } else {
-                panic!("unexpected builder.kind in crate: {:?}", builder.kind);
-            };
+            let test_kind = builder.kind.into();
 
             builder.ensure(Crate {
                 compiler,
@@ -1625,13 +1621,7 @@ fn should_run(run: ShouldRun) -> ShouldRun {
     fn make_run(run: RunConfig) {
         let builder = run.builder;
 
-        let test_kind = if builder.kind == Kind::Test {
-            TestKind::Test
-        } else if builder.kind == Kind::Bench {
-            TestKind::Bench
-        } else {
-            panic!("unexpected builder.kind in crate: {:?}", builder.kind);
-        };
+        let test_kind = builder.kind.into();
 
         builder.ensure(CrateRustdoc {
             host: run.host,
index 4b6e266f1e55c5ec35c60fc1370be789a1b97740..29f37b36e2a8c096398e028138a3143b397fca1f 100644 (file)
@@ -431,7 +431,7 @@ fn run(self, builder: &Builder) -> PathBuf {
         // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
         // rustdoc a different name.
         let tool_rustdoc = builder.cargo_out(build_compiler, Mode::Tool, target)
-            .join(exe("rustdoc-tool-binary", &target_compiler.host));
+            .join(exe("rustdoc_tool_binary", &target_compiler.host));
 
         // don't create a stage0-sysroot/bin directory.
         if target_compiler.stage > 0 {
index 78432b6a9659370cac1ae373770e795f0b8469b7..ee9135b6578f6071e7f43fbbe6f2214f1253dbf6 100644 (file)
@@ -101,29 +101,24 @@ properties: `ident`, `non_null`, `non_eol`, `non_single_quote` and
 
 ### Identifiers
 
-The `ident` production is any nonempty Unicode[^non_ascii_idents] string of
+The `ident` production is any nonempty Unicode string of
 the following form:
 
-[^non_ascii_idents]: Non-ASCII characters in identifiers are currently feature
-  gated. This is expected to improve soon.
+- The first character is in one of the following ranges `U+0041` to `U+005A`
+("A" to "Z"), `U+0061` to `U+007A` ("a" to "z"), or `U+005F` ("\_").
+- The remaining characters are in the range `U+0030` to `U+0039` ("0" to "9"),
+or any of the prior valid initial characters.
 
-- The first character has property `XID_start`
-- The remaining characters have property `XID_continue`
-
-that does _not_ occur in the set of [keywords](#keywords).
-
-> **Note**: `XID_start` and `XID_continue` as character properties cover the
-> character ranges used to form the more familiar C and Java language-family
-> identifiers.
+as long as the identifier does _not_ occur in the set of [keywords](#keywords).
 
 ### Delimiter-restricted productions
 
 Some productions are defined by exclusion of particular Unicode characters:
 
 - `non_null` is any single Unicode character aside from `U+0000` (null)
-- `non_eol` is `non_null` restricted to exclude `U+000A` (`'\n'`)
-- `non_single_quote` is `non_null` restricted to exclude `U+0027`  (`'`)
-- `non_double_quote` is `non_null` restricted to exclude `U+0022` (`"`)
+- `non_eol` is any single Unicode character aside from `U+000A` (`'\n'`)
+- `non_single_quote` is any single Unicode character aside from `U+0027`  (`'`)
+- `non_double_quote` is any single Unicode character aside from `U+0022` (`"`)
 
 ## Comments
 
index 87f3a0c765c5ef4fbef558902e5e8c60c2aacdeb..320283f31b51feb3e3fd24a632195fcb42a5181a 100644 (file)
@@ -1,3 +1,3 @@
 % The Rust Tutorial
 
-This tutorial has been deprecated in favor of [the Book](book/index.html). Go check that out instead!
+This tutorial has been deprecated in favor of [the Book](book/index.html), which is available free online and in dead tree form. Go check that out instead!
index 6383bd1e941ed48c4ae5c02fbc0c9b9bdfe02720..ada21e04b306cc9c0662611b1dafb0e998b2284f 100644 (file)
@@ -2,6 +2,8 @@
 authors = ["The Rust Project Developers"]
 name = "alloc"
 version = "0.0.0"
+autotests = false
+autobenches = false
 
 [lib]
 name = "alloc"
index 09d16b265208372b1124c42a69882e5cc7551cc3..79607b06f9468465c6a376bc2c9a344be7b98539 100644 (file)
 #[doc(inline)]
 pub use core::alloc::*;
 
-#[cfg(stage0)]
-extern "Rust" {
-    #[allocator]
-    #[rustc_allocator_nounwind]
-    fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
-    #[cold]
-    #[rustc_allocator_nounwind]
-    fn __rust_oom(err: *const u8) -> !;
-    #[rustc_allocator_nounwind]
-    fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
-    #[rustc_allocator_nounwind]
-    fn __rust_realloc(ptr: *mut u8,
-                      old_size: usize,
-                      old_align: usize,
-                      new_size: usize,
-                      new_align: usize,
-                      err: *mut u8) -> *mut u8;
-    #[rustc_allocator_nounwind]
-    fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
-}
-
-#[cfg(not(stage0))]
 extern "Rust" {
     #[allocator]
     #[rustc_allocator_nounwind]
@@ -74,10 +52,7 @@ fn __rust_realloc(ptr: *mut u8,
 unsafe impl GlobalAlloc for Global {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
-        #[cfg(not(stage0))]
         let ptr = __rust_alloc(layout.size(), layout.align());
-        #[cfg(stage0)]
-        let ptr = __rust_alloc(layout.size(), layout.align(), &mut 0);
         ptr as *mut Opaque
     }
 
@@ -88,20 +63,13 @@ unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
-        #[cfg(not(stage0))]
         let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size);
-        #[cfg(stage0)]
-        let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(),
-                                 new_size, layout.align(), &mut 0);
         ptr as *mut Opaque
     }
 
     #[inline]
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
-        #[cfg(not(stage0))]
         let ptr = __rust_alloc_zeroed(layout.size(), layout.align());
-        #[cfg(stage0)]
-        let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0);
         ptr as *mut Opaque
     }
 }
@@ -152,14 +120,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     }
 }
 
-#[cfg(stage0)]
-#[lang = "box_free"]
-#[inline]
-unsafe fn old_box_free<T: ?Sized>(ptr: *mut T) {
-    box_free(Unique::new_unchecked(ptr))
-}
-
-#[cfg_attr(not(any(test, stage0)), lang = "box_free")]
+#[cfg_attr(not(test), lang = "box_free")]
 #[inline]
 pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
     let ptr = ptr.as_ptr();
@@ -172,12 +133,6 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
     }
 }
 
-#[cfg(stage0)]
-pub fn oom() -> ! {
-    unsafe { ::core::intrinsics::abort() }
-}
-
-#[cfg(not(stage0))]
 pub fn oom() -> ! {
     extern {
         #[lang = "oom"]
index f7dd9d4f010a4235162b6239e93c893314f8fc14..91de3ad0c390bb1fe292c7788cc4037cdbddb927 100644 (file)
@@ -75,7 +75,6 @@
 #![deny(missing_debug_implementations)]
 
 #![cfg_attr(test, allow(deprecated))] // rand
-#![cfg_attr(all(not(test), stage0), feature(float_internals))]
 #![cfg_attr(not(test), feature(exact_size_is_empty))]
 #![cfg_attr(not(test), feature(generator_trait))]
 #![cfg_attr(test, feature(rand, test))]
 #![feature(collections_range)]
 #![feature(const_fn)]
 #![feature(core_intrinsics)]
-#![cfg_attr(stage0, feature(core_slice_ext))]
-#![cfg_attr(stage0, feature(core_str_ext))]
 #![feature(custom_attribute)]
 #![feature(dropck_eyepatch)]
 #![feature(exact_size_is_empty)]
 #![feature(fmt_internals)]
-#![cfg_attr(stage0, feature(fn_must_use))]
 #![feature(from_ref)]
 #![feature(fundamental)]
 #![feature(lang_items)]
 #![feature(exact_chunks)]
 #![feature(pointer_methods)]
 #![feature(inclusive_range_methods)]
-#![cfg_attr(stage0, feature(generic_param_attrs))]
 #![feature(rustc_const_unstable)]
 #![feature(const_vec_new)]
 
@@ -157,15 +152,10 @@ pub mod allocator {
 #[unstable(feature = "allocator_api", issue = "32838")]
 #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
 /// Use the `alloc` module instead.
-#[cfg(not(stage0))]
 pub mod heap {
     pub use alloc::*;
 }
 
-#[unstable(feature = "allocator_api", issue = "32838")]
-#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
-#[cfg(stage0)]
-pub mod heap;
 
 // Primitive types using the heaps above
 
index 6caf12aa7eb81983b9ff6d15c649bf2c7d26edc8..4427ac004f97aa4bef998b973534b6847c4e3f94 100644 (file)
 use core::mem::size_of;
 use core::mem;
 use core::ptr;
-#[cfg(stage0)] use core::slice::SliceExt;
 use core::{u8, u16, u32};
 
 use borrow::{Borrow, BorrowMut, ToOwned};
@@ -171,13 +170,9 @@ pub fn to_vec<T>(s: &[T]) -> Vec<T>
     }
 }
 
-#[cfg_attr(stage0, lang = "slice")]
-#[cfg_attr(not(stage0), lang = "slice_alloc")]
+#[lang = "slice_alloc"]
 #[cfg(not(test))]
 impl<T> [T] {
-    #[cfg(stage0)]
-    slice_core_methods!();
-
     /// Sorts the slice.
     ///
     /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case.
@@ -467,8 +462,7 @@ pub fn repeat(&self, n: usize) -> Vec<T> where T: Copy {
     }
 }
 
-#[cfg_attr(stage0, lang = "slice_u8")]
-#[cfg_attr(not(stage0), lang = "slice_u8_alloc")]
+#[lang = "slice_u8_alloc"]
 #[cfg(not(test))]
 impl [u8] {
     /// Returns a vector containing a copy of this slice where each byte
@@ -504,9 +498,6 @@ pub fn to_ascii_lowercase(&self) -> Vec<u8> {
         me.make_ascii_lowercase();
         me
     }
-
-    #[cfg(stage0)]
-    slice_u8_core_methods!();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
index 42efdea74b1ab6aa2b912c3e555e2d74d789850a..c10c0a69433920ba0ff45f6054cab8e4e5e27603 100644 (file)
@@ -40,7 +40,6 @@
 
 use core::fmt;
 use core::str as core_str;
-#[cfg(stage0)] use core::str::StrExt;
 use core::str::pattern::Pattern;
 use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
 use core::mem;
@@ -158,13 +157,9 @@ fn clone_into(&self, target: &mut String) {
 }
 
 /// Methods for string slices.
-#[cfg_attr(stage0, lang = "str")]
-#[cfg_attr(not(stage0), lang = "str_alloc")]
+#[lang = "str_alloc"]
 #[cfg(not(test))]
 impl str {
-    #[cfg(stage0)]
-    str_core_methods!();
-
     /// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
     ///
     /// # Examples
index 1c8ff316e55aab6fdaf4aae5ff8872ad835c9f5d..081c473768f1fe4666fdeb42e230fd1284629d54 100644 (file)
@@ -25,7 +25,6 @@
 #![feature(try_reserve)]
 #![feature(unboxed_closures)]
 #![feature(exact_chunks)]
-#![feature(inclusive_range_methods)]
 
 extern crate alloc_system;
 extern crate core;
index d30f8cd0fca20fb7f67cd2950a2a28f063d8d668..bf89b377b7eefcf4fb64326c6362443b7a1f50b1 100644 (file)
@@ -73,9 +73,6 @@
 use core::iter::{FromIterator, FusedIterator, TrustedLen};
 use core::marker::PhantomData;
 use core::mem;
-#[cfg(not(test))]
-#[cfg(stage0)]
-use core::num::Float;
 use core::ops::Bound::{Excluded, Included, Unbounded};
 use core::ops::{Index, IndexMut, RangeBounds};
 use core::ops;
index 4b8755877de4bf7e044d8047054f076e0e4d3984..ce856eccd837b8f4298dbd0ef057638ce83c5c75 100644 (file)
@@ -97,13 +97,6 @@ fn align_to_flags(align: usize, size: usize) -> c_int {
         ptr
     }
 
-    #[cfg(stage0)]
-    #[no_mangle]
-    #[rustc_std_internal_symbol]
-    pub unsafe extern fn __rde_oom() -> ! {
-        ::core::intrinsics::abort();
-    }
-
     #[no_mangle]
     #[rustc_std_internal_symbol]
     pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
index 7376ac0f15dd0fd7a61b62e2826bca468008c8e5..9490b54e675df562e737188bc5a76a52702fe903 100644 (file)
@@ -73,33 +73,6 @@ unsafe fn realloc(&mut self,
     }
 }
 
-#[cfg(stage0)]
-#[unstable(feature = "allocator_api", issue = "32838")]
-unsafe impl<'a> Alloc for &'a System {
-    #[inline]
-    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
-        NonNull::new(GlobalAlloc::alloc(*self, layout)).ok_or(AllocErr)
-    }
-
-    #[inline]
-    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
-        NonNull::new(GlobalAlloc::alloc_zeroed(*self, layout)).ok_or(AllocErr)
-    }
-
-    #[inline]
-    unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) {
-        GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout)
-    }
-
-    #[inline]
-    unsafe fn realloc(&mut self,
-                      ptr: NonNull<Opaque>,
-                      layout: Layout,
-                      new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
-        NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
-    }
-}
-
 #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
 mod realloc_fallback {
     use core::alloc::{GlobalAlloc, Opaque, Layout};
index c79e0e14e3d8b4d1ab65050153537f716e37508b..f7143a4f981555a4ee1383983e6408b9b7d5abd1 100644 (file)
@@ -26,7 +26,6 @@
 #![feature(alloc)]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
-#![cfg_attr(stage0, feature(generic_param_attrs))]
 #![cfg_attr(test, feature(test))]
 
 #![allow(deprecated)]
index 24529f7a9d8d42161d2a943ad95878e9f4569e98..321ed892ea9a986337baa7ea902215e27202f816 100644 (file)
@@ -2,6 +2,8 @@
 authors = ["The Rust Project Developers"]
 name = "core"
 version = "0.0.0"
+autotests = false
+autobenches = false
 
 [lib]
 name = "core"
index f79f73516989f1597f4a55b425bd33009daddd66..3b15ba2b4ab1fbc5167e73d73808191a6467b9de 100644 (file)
@@ -153,7 +153,6 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T
 ///
 /// Implementations that cannot be described in Rust
 /// are implemented in `SelectionContext::copy_clone_conditions()` in librustc.
-#[cfg(not(stage0))]
 mod impls {
 
     use super::Clone;
index 58eef6492877a4b0d6430d614eb119498289a6ce..db75f9bf210fc399bc7a02917b3b5ae0db6fae46 100644 (file)
@@ -86,17 +86,3 @@ fn $method(&mut self, other: &'a $u) {
         }
     }
 }
-
-#[cfg(stage0)]
-macro_rules! public_in_stage0 {
-    ( { $(#[$attr:meta])* } $($Item: tt)*) => {
-        $(#[$attr])* pub $($Item)*
-    }
-}
-
-#[cfg(not(stage0))]
-macro_rules! public_in_stage0 {
-    ( { $(#[$attr:meta])* } $($Item: tt)*) => {
-        $(#[$attr])* pub(crate) $($Item)*
-    }
-}
index 5ec6cb6c710541c3aa61a499adc13a8ac9024150..2e3f5cb65c9263f3c37285209dcc1693b6f79b4e 100644 (file)
     /// value is not necessarily valid to be used to actually access memory.
     pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
 
-    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
-    /// and destination must *not* overlap.
+    /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
+    /// and destination may *not* overlap.
     ///
-    /// For regions of memory which might overlap, use [`copy`] instead.
-    ///
-    /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`].
-    ///
-    /// [`copy`]: ./fn.copy.html
-    /// [`memcpy`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memcpy
+    /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`.
     ///
     /// # Safety
     ///
-    /// Behavior is undefined if any of the following conditions are violated:
-    ///
-    /// * The region of memory which begins at `src` and has a length of
-    ///   `count * size_of::<T>()` bytes must be *both* valid and initialized.
-    ///
-    /// * The region of memory which begins at `dst` and has a length of
-    ///   `count * size_of::<T>()` bytes must be valid (but may or may not be
-    ///   initialized).
-    ///
-    /// * The two regions of memory must *not* overlap.
-    ///
-    /// * `src` must be properly aligned.
-    ///
-    /// * `dst` must be properly aligned.
-    ///
-    /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the
-    /// region at `dst` can be used or dropped after calling
-    /// `copy_nonoverlapping`.  `copy_nonoverlapping` creates bitwise copies of
-    /// `T`, regardless of whether `T: Copy`, which can result in undefined
-    /// behavior if both copies are used.
-    ///
-    /// [`Copy`]: ../marker/trait.Copy.html
+    /// Beyond requiring that the program must be allowed to access both regions
+    /// of memory, it is Undefined Behavior for source and destination to
+    /// overlap. Care must also be taken with the ownership of `src` and
+    /// `dst`. This method semantically moves the values of `src` into `dst`.
+    /// However it does not drop the contents of `dst`, or prevent the contents
+    /// of `src` from being dropped or used.
     ///
     /// # Examples
     ///
-    /// Manually implement [`Vec::append`]:
+    /// A safe swap function:
     ///
     /// ```
+    /// use std::mem;
     /// use std::ptr;
     ///
-    /// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
-    /// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
-    ///     let src_len = src.len();
-    ///     let dst_len = dst.len();
-    ///
-    ///     // Ensure that `dst` has enough capacity to hold all of `src`.
-    ///     dst.reserve(src_len);
-    ///
+    /// # #[allow(dead_code)]
+    /// fn swap<T>(x: &mut T, y: &mut T) {
     ///     unsafe {
-    ///         // The call to offset is always safe because `Vec` will never
-    ///         // allocate more than `isize::MAX` bytes.
-    ///         let dst = dst.as_mut_ptr().offset(dst_len as isize);
-    ///         let src = src.as_ptr();
-    ///
-    ///         // The two regions cannot overlap becuase mutable references do
-    ///         // not alias, and two different vectors cannot own the same
-    ///         // memory.
-    ///         ptr::copy_nonoverlapping(src, dst, src_len);
-    ///     }
+    ///         // Give ourselves some scratch space to work with
+    ///         let mut t: T = mem::uninitialized();
     ///
-    ///     unsafe {
-    ///         // Truncate `src` without dropping its contents.
-    ///         src.set_len(0);
+    ///         // Perform the swap, `&mut` pointers never alias
+    ///         ptr::copy_nonoverlapping(x, &mut t, 1);
+    ///         ptr::copy_nonoverlapping(y, x, 1);
+    ///         ptr::copy_nonoverlapping(&t, y, 1);
     ///
-    ///         // Notify `dst` that it now holds the contents of `src`.
-    ///         dst.set_len(dst_len + src_len);
+    ///         // y and t now point to the same thing, but we need to completely forget `t`
+    ///         // because it's no longer relevant.
+    ///         mem::forget(t);
     ///     }
     /// }
-    ///
-    /// let mut a = vec!['r'];
-    /// let mut b = vec!['u', 's', 't'];
-    ///
-    /// append(&mut a, &mut b);
-    ///
-    /// assert_eq!(a, &['r', 'u', 's', 't']);
-    /// assert!(b.is_empty());
     /// ```
-    ///
-    /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
 
-    /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+    /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
     /// and destination may overlap.
     ///
-    /// If the source and destination will *never* overlap,
-    /// [`copy_nonoverlapping`] can be used instead.
-    ///
-    /// `copy` is semantically equivalent to C's [`memmove`].
-    ///
-    /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html
-    /// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove
+    /// `copy` is semantically equivalent to C's `memmove`.
     ///
     /// # Safety
     ///
-    /// Behavior is undefined if any of the following conditions are violated:
-    ///
-    /// * The region of memory which begins at `src` and has a length of
-    ///   `count * size_of::<T>()` bytes must be *both* valid and initialized.
-    ///
-    /// * The region of memory which begins at `dst` and has a length of
-    ///   `count * size_of::<T>()` bytes must be valid (but may or may not be
-    ///   initialized).
-    ///
-    /// * `src` must be properly aligned.
-    ///
-    /// * `dst` must be properly aligned.
-    ///
-    /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the
-    /// region at `dst` can be used or dropped after calling `copy`. `copy`
-    /// creates bitwise copies of `T`, regardless of whether `T: Copy`, which
-    /// can result in undefined behavior if both copies are used.
-    ///
-    /// [`Copy`]: ../marker/trait.Copy.html
+    /// Care must be taken with the ownership of `src` and `dst`.
+    /// This method semantically moves the values of `src` into `dst`.
+    /// However it does not drop the contents of `dst`, or prevent the contents of `src`
+    /// from being dropped or used.
     ///
     /// # Examples
     ///
     ///     dst
     /// }
     /// ```
+    ///
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
 
-    /// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
-    /// `val`.
-    ///
-    /// `write_bytes` is semantically equivalent to C's [`memset`].
-    ///
-    /// [`memset`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memset
-    ///
-    /// # Safety
-    ///
-    /// Behavior is undefined if any of the following conditions are violated:
-    ///
-    /// * The region of memory which begins at `dst` and has a length of
-    ///   `count` bytes must be valid.
-    ///
-    /// * `dst` must be properly aligned.
-    ///
-    /// Additionally, the caller must ensure that writing `count` bytes to the
-    /// given region of memory results in a valid value of `T`. Creating an
-    /// invalid value of `T` can result in undefined behavior. An example is
-    /// provided below.
+    /// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
+    /// bytes of memory starting at `dst` to `val`.
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
     /// use std::ptr;
     ///
     /// }
     /// assert_eq!(vec, [b'a', b'a', 0, 0]);
     /// ```
-    ///
-    /// Creating an invalid value:
-    ///
-    /// ```no_run
-    /// use std::{mem, ptr};
-    ///
-    /// let mut v = Box::new(0i32);
-    ///
-    /// unsafe {
-    ///     // Leaks the previously held value by overwriting the `Box<T>` with
-    ///     // a null pointer.
-    ///     ptr::write_bytes(&mut v, 0, mem::size_of::<Box<i32>>());
-    /// }
-    ///
-    /// // At this point, using or dropping `v` results in undefined behavior.
-    /// // v = Box::new(0i32); // ERROR
-    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
 
@@ -1463,38 +1364,8 @@ pub fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T,
     /// source as well as std's catch implementation.
     pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32;
 
-    /// Computes the byte offset that needs to be applied to `ptr` in order to
-    /// make it aligned to `align`.
-    /// If it is not possible to align `ptr`, the implementation returns
-    /// `usize::max_value()`.
-    ///
-    /// There are no guarantees whatsover that offsetting the pointer will not
-    /// overflow or go beyond the allocation that `ptr` points into.
-    /// It is up to the caller to ensure that the returned offset is correct
-    /// in all terms other than alignment.
-    ///
-    /// # Examples
-    ///
-    /// Accessing adjacent `u8` as `u16`
-    ///
-    /// ```
-    /// # #![feature(core_intrinsics)]
-    /// # fn foo(n: usize) {
-    /// # use std::intrinsics::align_offset;
-    /// # use std::mem::align_of;
-    /// # unsafe {
-    /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
-    /// let ptr = &x[n] as *const u8;
-    /// let offset = align_offset(ptr as *const (), align_of::<u16>());
-    /// if offset < x.len() - n - 1 {
-    ///     let u16_ptr = ptr.offset(offset as isize) as *const u16;
-    ///     assert_ne!(*u16_ptr, 500);
-    /// } else {
-    ///     // while the pointer can be aligned via `offset`, it would point
-    ///     // outside the allocation
-    /// }
-    /// # } }
-    /// ```
+    #[cfg(stage0)]
+    /// docs my friends, its friday!
     pub fn align_offset(ptr: *const (), align: usize) -> usize;
 
     /// Emits a `!nontemporal` store according to LLVM (see their docs).
index 06fbfcecba801d31c2a2c3a34ef12ae10e433884..77b5488084d99c1b5b786aab51bbb3349a5d4fbd 100644 (file)
 #![feature(unwind_attributes)]
 #![feature(doc_alias)]
 #![feature(inclusive_range_methods)]
-
-#![cfg_attr(not(stage0), feature(mmx_target_feature))]
-#![cfg_attr(not(stage0), feature(tbm_target_feature))]
-#![cfg_attr(not(stage0), feature(sse4a_target_feature))]
-#![cfg_attr(not(stage0), feature(arm_target_feature))]
-#![cfg_attr(not(stage0), feature(powerpc_target_feature))]
-#![cfg_attr(not(stage0), feature(mips_target_feature))]
-#![cfg_attr(not(stage0), feature(aarch64_target_feature))]
-
-#![cfg_attr(stage0, feature(target_feature))]
-#![cfg_attr(stage0, feature(cfg_target_feature))]
-#![cfg_attr(stage0, feature(fn_must_use))]
+#![feature(mmx_target_feature)]
+#![feature(tbm_target_feature)]
+#![feature(sse4a_target_feature)]
+#![feature(arm_target_feature)]
+#![feature(powerpc_target_feature)]
+#![feature(mips_target_feature)]
+#![feature(aarch64_target_feature)]
 
 #[prelude_import]
 #[allow(unused)]
index db5f50a99cadc3471b33d531670cbc2c8f016ddf..6c8ee0eda11e93f30e11b277dcc2fb47d24f429f 100644 (file)
@@ -611,7 +611,6 @@ unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
 ///
 /// Implementations that cannot be described in Rust
 /// are implemented in `SelectionContext::copy_clone_conditions()` in librustc.
-#[cfg(not(stage0))]
 mod copy_impls {
 
     use super::Copy;
index 4a7dc13f0f2ca69e881e3707d819f8d323c41feb..718dd42a61535f6fd59fc405203709b8e6f39b1f 100644 (file)
@@ -19,7 +19,7 @@
 
 use mem;
 use num::Float;
-#[cfg(not(stage0))] use num::FpCategory;
+use num::FpCategory;
 use num::FpCategory as Fp;
 
 /// The radix or base of the internal representation of `f32`.
@@ -277,7 +277,6 @@ fn from_bits(v: u32) -> Self {
 
 // FIXME: remove (inline) this macro and the Float trait
 // when updating to a bootstrap compiler that has the new lang items.
-#[cfg_attr(stage0, macro_export)]
 #[unstable(feature = "core_float", issue = "32110")]
 macro_rules! f32_core_methods { () => {
     /// Returns `true` if this value is `NaN` and false otherwise.
@@ -553,7 +552,6 @@ pub fn from_bits(v: u32) -> Self {
 
 #[lang = "f32"]
 #[cfg(not(test))]
-#[cfg(not(stage0))]
 impl f32 {
     f32_core_methods!();
 }
index 801de5e87bd10b002c9c1974bfa871fd4ee83dec..f128c55c78afa2aa59aaa12144d3c7478bfd9bbc 100644 (file)
@@ -19,7 +19,7 @@
 
 use mem;
 use num::Float;
-#[cfg(not(stage0))] use num::FpCategory;
+use num::FpCategory;
 use num::FpCategory as Fp;
 
 /// The radix or base of the internal representation of `f64`.
@@ -276,7 +276,6 @@ fn from_bits(v: u64) -> Self {
 
 // FIXME: remove (inline) this macro and the Float trait
 // when updating to a bootstrap compiler that has the new lang items.
-#[cfg_attr(stage0, macro_export)]
 #[unstable(feature = "core_float", issue = "32110")]
 macro_rules! f64_core_methods { () => {
     /// Returns `true` if this value is `NaN` and false otherwise.
@@ -562,7 +561,6 @@ pub fn from_bits(v: u64) -> Self {
 
 #[lang = "f64"]
 #[cfg(not(test))]
-#[cfg(not(stage0))]
 impl f64 {
     f64_core_methods!();
 }
index 6df8ca98ba92c45976fa477b31ae53660891a9d3..58d45b107f169598866d1506374ff230e0cce7fe 100644 (file)
@@ -422,7 +422,6 @@ pub fn swap_bytes(self) -> Self {
         /// assert_eq!(m, -22016);
         /// ```
         #[unstable(feature = "reverse_bits", issue = "48763")]
-        #[cfg(not(stage0))]
         #[inline]
         pub fn reverse_bits(self) -> Self {
             (self as $UnsignedT).reverse_bits() as Self
@@ -2194,7 +2193,6 @@ pub fn swap_bytes(self) -> Self {
         /// assert_eq!(m, 43520);
         /// ```
         #[unstable(feature = "reverse_bits", issue = "48763")]
-        #[cfg(not(stage0))]
         #[inline]
         pub fn reverse_bits(self) -> Self {
             unsafe { intrinsics::bitreverse(self as $ActualT) as Self }
index 697e6a3efde284356e5ce023691e2b0de8a3dc29..7c6e2447bdb7f39b707c1c80e62f6420ca0d7e5b 100644 (file)
@@ -318,8 +318,6 @@ pub fn contains<U>(&self, item: &U) -> bool
 /// # Examples
 ///
 /// ```
-/// #![feature(inclusive_range_methods)]
-///
 /// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5));
 /// assert_eq!(3 + 4 + 5, (3..=5).sum());
 ///
@@ -335,18 +333,8 @@ pub struct RangeInclusive<Idx> {
     // but it is known that LLVM is not able to optimize loops following that RFC.
     // Consider adding an extra `bool` field to indicate emptiness of the range.
     // See #45222 for performance test cases.
-    #[cfg(not(stage0))]
     pub(crate) start: Idx,
-    #[cfg(not(stage0))]
     pub(crate) end: Idx,
-    /// The lower bound of the range (inclusive).
-    #[cfg(stage0)]
-    #[unstable(feature = "inclusive_range_fields", issue = "49022")]
-    pub start: Idx,
-    /// The upper bound of the range (inclusive).
-    #[cfg(stage0)]
-    #[unstable(feature = "inclusive_range_fields", issue = "49022")]
-    pub end: Idx,
 }
 
 impl<Idx> RangeInclusive<Idx> {
@@ -355,12 +343,11 @@ impl<Idx> RangeInclusive<Idx> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(inclusive_range_methods)]
     /// use std::ops::RangeInclusive;
     ///
     /// assert_eq!(3..=5, RangeInclusive::new(3, 5));
     /// ```
-    #[unstable(feature = "inclusive_range_methods", issue = "49022")]
+    #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     pub const fn new(start: Idx, end: Idx) -> Self {
         Self { start, end }
@@ -373,17 +360,18 @@ pub const fn new(start: Idx, end: Idx) -> Self {
     /// whether the inclusive range is empty, use the [`is_empty()`] method
     /// instead of comparing `start() > end()`.
     ///
+    /// Note: the value returned by this method is unspecified after the range
+    /// has been iterated to exhaustion.
+    ///
     /// [`end()`]: #method.end
     /// [`is_empty()`]: #method.is_empty
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(inclusive_range_methods)]
-    ///
     /// assert_eq!((3..=5).start(), &3);
     /// ```
-    #[unstable(feature = "inclusive_range_methods", issue = "49022")]
+    #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     pub fn start(&self) -> &Idx {
         &self.start
@@ -396,32 +384,34 @@ pub fn start(&self) -> &Idx {
     /// whether the inclusive range is empty, use the [`is_empty()`] method
     /// instead of comparing `start() > end()`.
     ///
+    /// Note: the value returned by this method is unspecified after the range
+    /// has been iterated to exhaustion.
+    ///
     /// [`start()`]: #method.start
     /// [`is_empty()`]: #method.is_empty
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(inclusive_range_methods)]
-    ///
     /// assert_eq!((3..=5).end(), &5);
     /// ```
-    #[unstable(feature = "inclusive_range_methods", issue = "49022")]
+    #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     pub fn end(&self) -> &Idx {
         &self.end
     }
 
-    /// Destructures the RangeInclusive into (lower bound, upper (inclusive) bound).
+    /// Destructures the `RangeInclusive` into (lower bound, upper (inclusive) bound).
+    ///
+    /// Note: the value returned by this method is unspecified after the range
+    /// has been iterated to exhaustion.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(inclusive_range_methods)]
-    ///
     /// assert_eq!((3..=5).into_inner(), (3, 5));
     /// ```
-    #[unstable(feature = "inclusive_range_methods", issue = "49022")]
+    #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     pub fn into_inner(self) -> (Idx, Idx) {
         (self.start, self.end)
index 0dfdabee03182e18ab9553b0473a84eb27962f03..28f37f72d6f9df33172b5eced84265de40414126 100644 (file)
@@ -705,6 +705,42 @@ pub fn or_else<F: FnOnce() -> Option<T>>(self, f: F) -> Option<T> {
         }
     }
 
+    /// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns `None`.
+    ///
+    /// [`Some`]: #variant.Some
+    /// [`None`]: #variant.None
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(option_xor)]
+    ///
+    /// let x = Some(2);
+    /// let y: Option<u32> = None;
+    /// assert_eq!(x.xor(y), Some(2));
+    ///
+    /// let x: Option<u32> = None;
+    /// let y = Some(2);
+    /// assert_eq!(x.xor(y), Some(2));
+    ///
+    /// let x = Some(2);
+    /// let y = Some(2);
+    /// assert_eq!(x.xor(y), None);
+    ///
+    /// let x: Option<u32> = None;
+    /// let y: Option<u32> = None;
+    /// assert_eq!(x.xor(y), None);
+    /// ```
+    #[inline]
+    #[unstable(feature = "option_xor", issue = "50512")]
+    pub fn xor(self, optb: Option<T>) -> Option<T> {
+        match (self, optb) {
+            (Some(a), None) => Some(a),
+            (None, Some(b)) => Some(b),
+            _ => None,
+        }
+    }
+
     /////////////////////////////////////////////////////////////////////////
     // Entry-like operations to insert if None and return a reference
     /////////////////////////////////////////////////////////////////////////
index 8212648f2d8fb308f054ea49e2f94b9c70eb9250..45f629a64424cd526c0a17d27525f10c58f8bc1d 100644 (file)
 #[stable(feature = "core_prelude", since = "1.4.0")]
 #[doc(no_inline)]
 pub use result::Result::{self, Ok, Err};
-
-// Re-exported extension traits for primitive types
-#[stable(feature = "core_prelude", since = "1.4.0")]
-#[doc(no_inline)]
-#[cfg(stage0)]
-pub use slice::SliceExt;
-#[stable(feature = "core_prelude", since = "1.4.0")]
-#[doc(no_inline)]
-#[cfg(stage0)]
-pub use str::StrExt;
index 63bcc024020155fe753716f68dc2d6f1e2e2c046..6c0709caa084b045eda0ac1f7d8cc63e02f3651e 100644 (file)
@@ -10,7 +10,7 @@
 
 // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory
 
-//! Manually manage memory through raw pointers.
+//! Raw, unsafe pointers, `*const T`, and `*mut T`.
 //!
 //! *[See also the pointer primitive types](../../std/primitive.pointer.html).*
 
 
 /// Executes the destructor (if any) of the pointed-to value.
 ///
-/// This is semantically equivalent to calling [`ptr::read`] and discarding
-/// the result, but has the following advantages:
+/// This has two use cases:
 ///
 /// * It is *required* to use `drop_in_place` to drop unsized types like
 ///   trait objects, because they can't be read out onto the stack and
 ///   dropped normally.
 ///
-/// * It is friendlier to the optimizer to do this over [`ptr::read`] when
+/// * It is friendlier to the optimizer to do this over `ptr::read` when
 ///   dropping manually allocated memory (e.g. when writing Box/Rc/Vec),
 ///   as the compiler doesn't need to prove that it's sound to elide the
 ///   copy.
 ///
-/// [`ptr::read`]: ../ptr/fn.read.html
-///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `to_drop` must point to valid memory.
-///
-/// * `to_drop` must be properly aligned.
-///
-/// Additionally, if `T` is not [`Copy`], using the pointed-to value after
-/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop =
-/// foo` counts as a use because it will cause the the value to be dropped
-/// again. [`write`] can be used to overwrite data without causing it to be
-/// dropped.
-///
-/// [`Copy`]: ../marker/trait.Copy.html
-/// [`write`]: ../ptr/fn.write.html
-///
-/// # Examples
-///
-/// Manually remove the last item from a vector:
-///
-/// ```
-/// use std::ptr;
-/// use std::rc::Rc;
-///
-/// let last = Rc::new(1);
-/// let weak = Rc::downgrade(&last);
-///
-/// let mut v = vec![Rc::new(0), last];
-///
-/// unsafe {
-///     // Without a call `drop_in_place`, the last item would never be dropped,
-///     // and the memory it manages would be leaked.
-///     ptr::drop_in_place(&mut v[1]);
-///     v.set_len(1);
-/// }
-///
-/// assert_eq!(v, &[0.into()]);
-///
-/// // Ensure that the last item was dropped.
-/// assert!(weak.upgrade().is_none());
-/// ```
+/// This has all the same safety problems as `ptr::read` with respect to
+/// invalid pointers, types, and double drops.
 #[stable(feature = "drop_in_place", since = "1.8.0")]
 #[lang = "drop_in_place"]
 #[allow(unconditional_recursion)]
@@ -134,25 +93,17 @@ pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
 /// Swaps the values at two mutable locations of the same type, without
 /// deinitializing either.
 ///
-/// But for the following two exceptions, this function is semantically
-/// equivalent to [`mem::swap`]:
-///
-/// * It operates on raw pointers instead of references. When references are
-///   available, [`mem::swap`] should be preferred.
-///
-/// * The two pointed-to values may overlap. If the values do overlap, then the
-///   overlapping region of memory from `x` will be used. This is demonstrated
-///   in the examples below.
-///
-/// [`mem::swap`]: ../mem/fn.swap.html
+/// The values pointed at by `x` and `y` may overlap, unlike `mem::swap` which
+/// is otherwise equivalent. If the values do overlap, then the overlapping
+/// region of memory from `x` will be used. This is demonstrated in the
+/// examples section below.
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
+/// This function copies the memory through the raw pointers passed to it
+/// as arguments.
 ///
-/// * `x` and `y` must point to valid, initialized memory.
-///
-/// * `x` and `y` must be properly aligned.
+/// Ensure that these pointers are valid before calling `swap`.
 ///
 /// # Examples
 ///
@@ -288,39 +239,13 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
     }
 }
 
-/// Replaces the value at `dest` with `src`, returning the old value, without
-/// dropping either.
-///
-/// This function is semantically equivalent to [`mem::replace`] except that it
-/// operates on raw pointers instead of references. When references are
-/// available, [`mem::replace`] should be preferred.
-///
-/// [`mem::replace`]: ../mem/fn.replace.html
+/// Replaces the value at `dest` with `src`, returning the old
+/// value, without dropping either.
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `dest` must point to valid, initialized memory.
-///
-/// * `dest` must be properly aligned.
-///
-/// # Examples
-///
-/// ```
-/// use std::ptr;
-///
-/// let mut rust = vec!['b', 'u', 's', 't'];
-///
-/// // `mem::replace` would have the same effect without requiring the unsafe
-/// // block.
-/// let b = unsafe {
-///     ptr::replace(&mut rust[0], 'r')
-/// };
-///
-/// assert_eq!(b, 'b');
-/// assert_eq!(rust, &['r', 'u', 's', 't']);
-/// ```
+/// This is only unsafe because it accepts a raw pointer.
+/// Otherwise, this operation is identical to `mem::replace`.
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
@@ -333,23 +258,14 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must point to valid, initialized memory.
+/// Beyond accepting a raw pointer, this is unsafe because it semantically
+/// moves the value out of `src` without preventing further usage of `src`.
+/// If `T` is not `Copy`, then care must be taken to ensure that the value at
+/// `src` is not used before the data is overwritten again (e.g. with `write`,
+/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
+/// because it will attempt to drop the value previously at `*src`.
 ///
-/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the
-///   case.
-///
-/// Additionally, if `T` is not [`Copy`], only the returned value *or* the
-/// pointed-to value can be used or dropped after calling `read`. `read` creates
-/// a bitwise copy of `T`, regardless of whether `T: Copy`, which can result
-/// in undefined behavior if both copies are used. Note that `*src = foo` counts
-/// as a use because it will attempt to drop the value previously at `*src`.
-/// [`write`] can be used to overwrite data without causing it to be dropped.
-///
-/// [`Copy`]: ../marker/trait.Copy.html
-/// [`read_unaligned`]: ./fn.read_unaligned.html
-/// [`write`]: ./fn.write.html
+/// The pointer must be aligned; use `read_unaligned` if that is not the case.
 ///
 /// # Examples
 ///
@@ -363,44 +279,6 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
 ///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
-///
-/// Manually implement [`mem::swap`]:
-///
-/// ```
-/// use std::ptr;
-///
-/// fn swap<T>(a: &mut T, b: &mut T) {
-///     unsafe {
-///         // Create a bitwise copy of the value at `a` in `tmp`.
-///         let tmp = ptr::read(a);
-///
-///         // Exiting at this point (either by explicitly returning or by
-///         // calling a function which panics) would cause the value in `tmp` to
-///         // be dropped while the same value is still referenced by `a`. This
-///         // could trigger undefined behavior if `T` is not `Copy`.
-///
-///         // Create a bitwise copy of the value at `b` in `a`.
-///         // This is safe because mutable references cannot alias.
-///         ptr::copy_nonoverlapping(b, a, 1);
-///
-///         // As above, exiting here could trigger undefined behavior because
-///         // the same value is referenced by `a` and `b`.
-///
-///         // Move `tmp` into `b`.
-///         ptr::write(b, tmp);
-///     }
-/// }
-///
-/// let mut foo = "foo".to_owned();
-/// let mut bar = "bar".to_owned();
-///
-/// swap(&mut foo, &mut bar);
-///
-/// assert_eq!(foo, "bar");
-/// assert_eq!(bar, "foo");
-/// ```
-///
-/// [`mem::swap`]: ../mem/fn.swap.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn read<T>(src: *const T) -> T {
@@ -412,62 +290,28 @@ pub unsafe fn read<T>(src: *const T) -> T {
 /// Reads the value from `src` without moving it. This leaves the
 /// memory in `src` unchanged.
 ///
-/// Unlike [`read`], `read_unaligned` works with unaligned pointers.
-///
-/// [`read`]: ./fn.read.html
+/// Unlike `read`, the pointer may be unaligned.
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must point to valid, initialized memory.
-///
-/// Additionally, if `T` is not [`Copy`], only the returned value *or* the
-/// pointed-to value can be used or dropped after calling `read_unaligned`.
-/// `read_unaligned` creates a bitwise copy of `T`, regardless of whether `T:
-/// Copy`, and this can result in undefined behavior if both copies are used.
-/// Note that `*src = foo` counts as a use because it will attempt to drop the
-/// value previously at `*src`.  [`write_unaligned`] can be used to overwrite
-/// data without causing it to be dropped.
-///
-/// [`Copy`]: ../marker/trait.Copy.html
-/// [`write_unaligned`]: ./fn.write_unaligned.html
+/// Beyond accepting a raw pointer, this is unsafe because it semantically
+/// moves the value out of `src` without preventing further usage of `src`.
+/// If `T` is not `Copy`, then care must be taken to ensure that the value at
+/// `src` is not used before the data is overwritten again (e.g. with `write`,
+/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
+/// because it will attempt to drop the value previously at `*src`.
 ///
 /// # Examples
 ///
-/// Access members of a packed struct by reference:
+/// Basic usage:
 ///
 /// ```
-/// use std::ptr;
+/// let x = 12;
+/// let y = &x as *const i32;
 ///
-/// #[repr(packed, C)]
-/// #[derive(Default)]
-/// struct Packed {
-///     _padding: u8,
-///     unaligned: u32,
+/// unsafe {
+///     assert_eq!(std::ptr::read_unaligned(y), 12);
 /// }
-///
-/// let x = Packed {
-///     _padding: 0x00,
-///     unaligned: 0x01020304,
-/// };
-///
-/// let v = unsafe {
-///     // Take a reference to a 32-bit integer which is not aligned.
-///     let unaligned = &x.unaligned;
-///
-///     // Dereferencing normally will emit an unaligned load instruction,
-///     // causing undefined behavior.
-///     // let v = *unaligned; // ERROR
-///
-///     // Instead, use `read_unaligned` to read improperly aligned values.
-///     let v = ptr::read_unaligned(unaligned);
-///
-///     v
-/// };
-///
-/// // Accessing unaligned values directly is safe.
-/// assert!(x.unaligned == v);
 /// ```
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
@@ -482,7 +326,11 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 /// Overwrites a memory location with the given value without reading or
 /// dropping the old value.
 ///
-/// `write` does not drop the contents of `dst`. This is safe, but it could leak
+/// # Safety
+///
+/// This operation is marked unsafe because it accepts a raw pointer.
+///
+/// It does not drop the contents of `dst`. This is safe, but it could leak
 /// allocations or resources, so care must be taken not to overwrite an object
 /// that should be dropped.
 ///
@@ -490,20 +338,9 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 /// location pointed to by `dst`.
 ///
 /// This is appropriate for initializing uninitialized memory, or overwriting
-/// memory that has previously been [`read`] from.
+/// memory that has previously been `read` from.
 ///
-/// [`read`]: ./fn.read.html
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `dst` must point to valid memory.
-///
-/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the
-///   case.
-///
-/// [`write_unaligned`]: ./fn.write_unaligned.html
+/// The pointer must be aligned; use `write_unaligned` if that is not the case.
 ///
 /// # Examples
 ///
@@ -519,30 +356,6 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 ///     assert_eq!(std::ptr::read(y), 12);
 /// }
 /// ```
-///
-/// Manually implement [`mem::swap`]:
-///
-/// ```
-/// use std::ptr;
-///
-/// fn swap<T>(a: &mut T, b: &mut T) {
-///     unsafe {
-///         let tmp = ptr::read(a);
-///         ptr::copy_nonoverlapping(b, a, 1);
-///         ptr::write(b, tmp);
-///     }
-/// }
-///
-/// let mut foo = "foo".to_owned();
-/// let mut bar = "bar".to_owned();
-///
-/// swap(&mut foo, &mut bar);
-///
-/// assert_eq!(foo, "bar");
-/// assert_eq!(bar, "foo");
-/// ```
-///
-/// [`mem::swap`]: ../mem/fn.swap.html
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn write<T>(dst: *mut T, src: T) {
@@ -552,58 +365,36 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
 /// Overwrites a memory location with the given value without reading or
 /// dropping the old value.
 ///
-/// Unlike [`write`], the pointer may be unaligned.
+/// Unlike `write`, the pointer may be unaligned.
+///
+/// # Safety
+///
+/// This operation is marked unsafe because it accepts a raw pointer.
 ///
-/// `write_unaligned` does not drop the contents of `dst`. This is safe, but it
-/// could leak allocations or resources, so care must be taken not to overwrite
-/// an object that should be dropped.
+/// It does not drop the contents of `dst`. This is safe, but it could leak
+/// allocations or resources, so care must be taken not to overwrite an object
+/// that should be dropped.
 ///
 /// Additionally, it does not drop `src`. Semantically, `src` is moved into the
 /// location pointed to by `dst`.
 ///
 /// This is appropriate for initializing uninitialized memory, or overwriting
-/// memory that has previously been read with [`read_unaligned`].
-///
-/// [`write`]: ./fn.write.html
-/// [`read_unaligned`]: ./fn.read_unaligned.html
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `dst` must point to valid memory.
+/// memory that has previously been `read` from.
 ///
 /// # Examples
 ///
-/// Access fields in a packed struct:
+/// Basic usage:
 ///
 /// ```
-/// use std::{mem, ptr};
-///
-/// #[repr(packed, C)]
-/// #[derive(Default)]
-/// struct Packed {
-///     _padding: u8,
-///     unaligned: u32,
-/// }
-///
-/// let v = 0x01020304;
-/// let mut x: Packed = unsafe { mem::zeroed() };
+/// let mut x = 0;
+/// let y = &mut x as *mut i32;
+/// let z = 12;
 ///
 /// unsafe {
-///     // Take a reference to a 32-bit integer which is not aligned.
-///     let unaligned = &mut x.unaligned;
-///
-///     // Dereferencing normally will emit an unaligned store instruction,
-///     // causing undefined behavior.
-///     // *unaligned = v; // ERROR
-///
-///     // Instead, use `write_unaligned` to write improperly aligned values.
-///     ptr::write_unaligned(unaligned, v);
+///     std::ptr::write_unaligned(y, z);
+///     assert_eq!(std::ptr::read_unaligned(y), 12);
 /// }
-///
-/// // Accessing unaligned values directly is safe.
-/// assert!(x.unaligned == v);
+/// ```
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
@@ -620,11 +411,6 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 /// to not be elided or reordered by the compiler across other volatile
 /// operations.
 ///
-/// Memory read with `read_volatile` should almost always be written to using
-/// [`write_volatile`].
-///
-/// [`write_volatile`]: ./fn.write_volatile.html
-///
 /// # Notes
 ///
 /// Rust does not currently have a rigorously and formally defined memory model,
@@ -641,19 +427,12 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `src` must point to valid, initialized memory.
-///
-/// * `src` must be properly aligned.
-///
-/// Like [`read`], `read_volatile` creates a bitwise copy of the pointed-to
-/// object, regardless of whether `T` is [`Copy`]. Using both values can cause
-/// undefined behavior. However, storing non-[`Copy`] data in I/O memory is
-/// almost certainly incorrect.
-///
-/// [`Copy`]: ../marker/trait.Copy.html
-/// [`read`]: ./fn.read.html
+/// Beyond accepting a raw pointer, this is unsafe because it semantically
+/// moves the value out of `src` without preventing further usage of `src`.
+/// If `T` is not `Copy`, then care must be taken to ensure that the value at
+/// `src` is not used before the data is overwritten again (e.g. with `write`,
+/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
+/// because it will attempt to drop the value previously at `*src`.
 ///
 /// # Examples
 ///
@@ -680,18 +459,6 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 /// to not be elided or reordered by the compiler across other volatile
 /// operations.
 ///
-/// Memory written with `write_volatile` should almost always be read from using
-/// [`read_volatile`].
-///
-/// `write_volatile` does not drop the contents of `dst`. This is safe, but it
-/// could leak allocations or resources, so care must be taken not to overwrite
-/// an object that should be dropped.
-///
-/// Additionally, it does not drop `src`. Semantically, `src` is moved into the
-/// location pointed to by `dst`.
-///
-/// [`read_volatile`]: ./fn.read_volatile.html
-///
 /// # Notes
 ///
 /// Rust does not currently have a rigorously and formally defined memory model,
@@ -708,11 +475,14 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 ///
 /// # Safety
 ///
-/// Behavior is undefined if any of the following conditions are violated:
+/// This operation is marked unsafe because it accepts a raw pointer.
 ///
-/// * `dst` must point to valid memory.
+/// It does not drop the contents of `dst`. This is safe, but it could leak
+/// allocations or resources, so care must be taken not to overwrite an object
+/// that should be dropped.
 ///
-/// * `dst` must be properly aligned.
+/// This is appropriate for initializing uninitialized memory, or overwriting
+/// memory that has previously been `read` from.
 ///
 /// # Examples
 ///
@@ -1433,15 +1203,22 @@ pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
         copy_nonoverlapping(self, dest, count)
     }
 
-    /// Computes the byte offset that needs to be applied in order to
-    /// make the pointer aligned to `align`.
+    /// Computes the offset that needs to be applied to the pointer in order to make it aligned to
+    /// `align`.
+    ///
     /// If it is not possible to align the pointer, the implementation returns
     /// `usize::max_value()`.
     ///
-    /// There are no guarantees whatsover that offsetting the pointer will not
-    /// overflow or go beyond the allocation that the pointer points into.
-    /// It is up to the caller to ensure that the returned offset is correct
-    /// in all terms other than alignment.
+    /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
+    /// used with the `offset` or `offset_to` methods.
+    ///
+    /// There are no guarantees whatsover that offsetting the pointer will not overflow or go
+    /// beyond the allocation that the pointer points into. It is up to the caller to ensure that
+    /// the returned offset is correct in all terms other than alignment.
+    ///
+    /// # Panics
+    ///
+    /// The function panics if `align` is not a power-of-two.
     ///
     /// # Examples
     ///
@@ -1465,13 +1242,30 @@ pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
     /// # } }
     /// ```
     #[unstable(feature = "align_offset", issue = "44488")]
-    pub fn align_offset(self, align: usize) -> usize {
+    #[cfg(not(stage0))]
+    pub fn align_offset(self, align: usize) -> usize where T: Sized {
+        if !align.is_power_of_two() {
+            panic!("align_offset: align is not a power-of-two");
+        }
         unsafe {
-            intrinsics::align_offset(self as *const _, align)
+            align_offset(self, align)
+        }
+    }
+
+    /// definitely docs.
+    #[unstable(feature = "align_offset", issue = "44488")]
+    #[cfg(stage0)]
+    pub fn align_offset(self, align: usize) -> usize where T: Sized {
+        if !align.is_power_of_two() {
+            panic!("align_offset: align is not a power-of-two");
+        }
+        unsafe {
+            intrinsics::align_offset(self as *const (), align)
         }
     }
 }
 
+
 #[lang = "mut_ptr"]
 impl<T: ?Sized> *mut T {
     /// Returns `true` if the pointer is null.
@@ -1804,44 +1598,6 @@ pub fn wrapping_offset_from(self, origin: *const T) -> isize where T: Sized {
         (self as *const T).wrapping_offset_from(origin)
     }
 
-    /// Computes the byte offset that needs to be applied in order to
-    /// make the pointer aligned to `align`.
-    /// If it is not possible to align the pointer, the implementation returns
-    /// `usize::max_value()`.
-    ///
-    /// There are no guarantees whatsover that offsetting the pointer will not
-    /// overflow or go beyond the allocation that the pointer points into.
-    /// It is up to the caller to ensure that the returned offset is correct
-    /// in all terms other than alignment.
-    ///
-    /// # Examples
-    ///
-    /// Accessing adjacent `u8` as `u16`
-    ///
-    /// ```
-    /// # #![feature(align_offset)]
-    /// # fn foo(n: usize) {
-    /// # use std::mem::align_of;
-    /// # unsafe {
-    /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
-    /// let ptr = &x[n] as *const u8;
-    /// let offset = ptr.align_offset(align_of::<u16>());
-    /// if offset < x.len() - n - 1 {
-    ///     let u16_ptr = ptr.offset(offset as isize) as *const u16;
-    ///     assert_ne!(*u16_ptr, 500);
-    /// } else {
-    ///     // while the pointer can be aligned via `offset`, it would point
-    ///     // outside the allocation
-    /// }
-    /// # } }
-    /// ```
-    #[unstable(feature = "align_offset", issue = "44488")]
-    pub fn align_offset(self, align: usize) -> usize {
-        unsafe {
-            intrinsics::align_offset(self as *const _, align)
-        }
-    }
-
     /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
     ///
     /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
@@ -2511,8 +2267,200 @@ pub unsafe fn swap(self, with: *mut T)
     {
         swap(self, with)
     }
+
+    /// Computes the offset that needs to be applied to the pointer in order to make it aligned to
+    /// `align`.
+    ///
+    /// If it is not possible to align the pointer, the implementation returns
+    /// `usize::max_value()`.
+    ///
+    /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be
+    /// used with the `offset` or `offset_to` methods.
+    ///
+    /// There are no guarantees whatsover that offsetting the pointer will not overflow or go
+    /// beyond the allocation that the pointer points into. It is up to the caller to ensure that
+    /// the returned offset is correct in all terms other than alignment.
+    ///
+    /// # Panics
+    ///
+    /// The function panics if `align` is not a power-of-two.
+    ///
+    /// # Examples
+    ///
+    /// Accessing adjacent `u8` as `u16`
+    ///
+    /// ```
+    /// # #![feature(align_offset)]
+    /// # fn foo(n: usize) {
+    /// # use std::mem::align_of;
+    /// # unsafe {
+    /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
+    /// let ptr = &x[n] as *const u8;
+    /// let offset = ptr.align_offset(align_of::<u16>());
+    /// if offset < x.len() - n - 1 {
+    ///     let u16_ptr = ptr.offset(offset as isize) as *const u16;
+    ///     assert_ne!(*u16_ptr, 500);
+    /// } else {
+    ///     // while the pointer can be aligned via `offset`, it would point
+    ///     // outside the allocation
+    /// }
+    /// # } }
+    /// ```
+    #[unstable(feature = "align_offset", issue = "44488")]
+    #[cfg(not(stage0))]
+    pub fn align_offset(self, align: usize) -> usize where T: Sized {
+        if !align.is_power_of_two() {
+            panic!("align_offset: align is not a power-of-two");
+        }
+        unsafe {
+            align_offset(self, align)
+        }
+    }
+
+    /// definitely docs.
+    #[unstable(feature = "align_offset", issue = "44488")]
+    #[cfg(stage0)]
+    pub fn align_offset(self, align: usize) -> usize where T: Sized {
+        if !align.is_power_of_two() {
+            panic!("align_offset: align is not a power-of-two");
+        }
+        unsafe {
+            intrinsics::align_offset(self as *const (), align)
+        }
+    }
+}
+
+/// Align pointer `p`.
+///
+/// Calculate offset (in terms of elements of `stride` stride) that has to be applied
+/// to pointer `p` so that pointer `p` would get aligned to `a`.
+///
+/// Note: This implementation has been carefully tailored to not panic. It is UB for this to panic.
+/// The only real change that can be made here is change of `INV_TABLE_MOD_16` and associated
+/// constants.
+///
+/// If we ever decide to make it possible to call the intrinsic with `a` that is not a
+/// power-of-two, it will probably be more prudent to just change to a naive implementation rather
+/// than trying to adapt this to accomodate that change.
+///
+/// Any questions go to @nagisa.
+#[lang="align_offset"]
+#[cfg(not(stage0))]
+pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
+    /// Calculate multiplicative modular inverse of `x` modulo `m`.
+    ///
+    /// This implementation is tailored for align_offset and has following preconditions:
+    ///
+    /// * `m` is a power-of-two;
+    /// * `x < m`; (if `x ≥ m`, pass in `x % m` instead)
+    ///
+    /// Implementation of this function shall not panic. Ever.
+    #[inline]
+    fn mod_inv(x: usize, m: usize) -> usize {
+        /// Multiplicative modular inverse table modulo 2⁴ = 16.
+        ///
+        /// Note, that this table does not contain values where inverse does not exist (i.e. for
+        /// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.)
+        const INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15];
+        /// Modulo for which the `INV_TABLE_MOD_16` is intended.
+        const INV_TABLE_MOD: usize = 16;
+        /// INV_TABLE_MOD²
+        const INV_TABLE_MOD_SQUARED: usize = INV_TABLE_MOD * INV_TABLE_MOD;
+
+        let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1];
+        if m <= INV_TABLE_MOD {
+            return table_inverse & (m - 1);
+        } else {
+            // We iterate "up" using the following formula:
+            //
+            // $$ xy ≡ 1 (mod 2ⁿ) → xy (2 - xy) ≡ 1 (mod 2²ⁿ) $$
+            //
+            // until 2²ⁿ ≥ m. Then we can reduce to our desired `m` by taking the result `mod m`.
+            let mut inverse = table_inverse;
+            let mut going_mod = INV_TABLE_MOD_SQUARED;
+            loop {
+                // y = y * (2 - xy) mod n
+                //
+                // Note, that we use wrapping operations here intentionally – the original formula
+                // uses e.g. subtraction `mod n`. It is entirely fine to do them `mod
+                // usize::max_value()` instead, because we take the result `mod n` at the end
+                // anyway.
+                inverse = inverse.wrapping_mul(
+                    2usize.wrapping_sub(x.wrapping_mul(inverse))
+                ) & (going_mod - 1);
+                if going_mod > m {
+                    return inverse & (m - 1);
+                }
+                going_mod = going_mod.wrapping_mul(going_mod);
+            }
+        }
+    }
+
+    let stride = ::mem::size_of::<T>();
+    let a_minus_one = a.wrapping_sub(1);
+    let pmoda = p as usize & a_minus_one;
+
+    if pmoda == 0 {
+        // Already aligned. Yay!
+        return 0;
+    }
+
+    if stride <= 1 {
+        return if stride == 0 {
+            // If the pointer is not aligned, and the element is zero-sized, then no amount of
+            // elements will ever align the pointer.
+            !0
+        } else {
+            a.wrapping_sub(pmoda)
+        };
+    }
+
+    let smoda = stride & a_minus_one;
+    // a is power-of-two so cannot be 0. stride = 0 is handled above.
+    let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a));
+    let gcd = 1usize << gcdpow;
+
+    if gcd == 1 {
+        // This branch solves for the variable $o$ in following linear congruence equation:
+        //
+        // ⎰ p + o ≡ 0 (mod a)   # $p + o$ must be aligned to specified alignment $a$
+        // ⎱     o ≡ 0 (mod s)   # offset $o$ must be a multiple of stride $s$
+        //
+        // where
+        //
+        // * a, s are co-prime
+        //
+        // This gives us the formula below:
+        //
+        // o = (a - (p mod a)) * (s⁻¹ mod a) * s
+        //
+        // The first term is “the relative alignment of p to a”, the second term is “how does
+        // incrementing p by one s change the relative alignment of p”, the third term is
+        // translating change in units of s to a byte count.
+        //
+        // Furthermore, the result produced by this solution is not “minimal”, so it is necessary
+        // to take the result $o mod lcm(s, a)$. Since $s$ and $a$ are co-prime (i.e. $gcd(s, a) =
+        // 1$) and $lcm(s, a) = s * a / gcd(s, a)$, we can replace $lcm(s, a)$ with just a $s * a$.
+        //
+        // (Author note: we decided later on to express the offset in "elements" rather than bytes,
+        // which drops the multiplication by `s` on both sides of the modulo.)
+        return intrinsics::unchecked_rem(a.wrapping_sub(pmoda).wrapping_mul(mod_inv(smoda, a)), a);
+    }
+
+    if p as usize & (gcd - 1) == 0 {
+        // This can be aligned, but `a` and `stride` are not co-prime, so a somewhat adapted
+        // formula is used.
+        let j = a.wrapping_sub(pmoda) >> gcdpow;
+        let k = smoda >> gcdpow;
+        return intrinsics::unchecked_rem(j.wrapping_mul(mod_inv(k, a)), a >> gcdpow);
+    }
+
+    // Cannot be aligned at all.
+    return usize::max_value();
 }
 
+
+
 // Equality for pointers
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialEq for *const T {
index 93ebc23ac0b0e33f45d3e6ed87519a57902be728..fdc9aa473e8b8ed2247225eecf8495ea96af1eba 100644 (file)
@@ -68,701 +68,47 @@ struct Repr<T> {
 // Extension traits
 //
 
-public_in_stage0! {
-{
-/// Extension methods for slices.
-#[unstable(feature = "core_slice_ext",
-           reason = "stable interface provided by `impl [T]` in later crates",
-           issue = "32110")]
-#[allow(missing_docs)] // documented elsewhere
-}
-trait SliceExt {
-    type Item;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_at(&self, mid: usize) -> (&[Self::Item], &[Self::Item]);
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn iter(&self) -> Iter<Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split<P>(&self, pred: P) -> Split<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "slice_rsplit", since = "1.27.0")]
-    fn rsplit<P>(&self, pred: P) -> RSplit<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn splitn<P>(&self, n: usize, pred: P) -> SplitN<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rsplitn<P>(&self,  n: usize, pred: P) -> RSplitN<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn windows(&self, size: usize) -> Windows<Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn chunks(&self, size: usize) -> Chunks<Self::Item>;
-
-    #[unstable(feature = "exact_chunks", issue = "47115")]
-    fn exact_chunks(&self, size: usize) -> ExactChunks<Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn get<I>(&self, index: I) -> Option<&I::Output>
-        where I: SliceIndex<Self>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn first(&self) -> Option<&Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_first(&self) -> Option<(&Self::Item, &[Self::Item])>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_last(&self) -> Option<(&Self::Item, &[Self::Item])>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn last(&self) -> Option<&Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
-        where I: SliceIndex<Self>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn as_ptr(&self) -> *const Self::Item;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn binary_search(&self, x: &Self::Item) -> Result<usize, usize>
-        where Self::Item: Ord;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
-        where F: FnMut(&'a Self::Item) -> Ordering;
-
-    #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
-    fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
-        where F: FnMut(&'a Self::Item) -> B,
-              B: Ord;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn len(&self) -> usize;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn is_empty(&self) -> bool { self.len() == 0 }
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
-        where I: SliceIndex<Self>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn iter_mut(&mut self) -> IterMut<Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn first_mut(&mut self) -> Option<&mut Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_first_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_last_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn last_mut(&mut self) -> Option<&mut Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_mut<P>(&mut self, pred: P) -> SplitMut<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "slice_rsplit", since = "1.27.0")]
-    fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rsplitn_mut<P>(&mut self,  n: usize, pred: P) -> RSplitNMut<Self::Item, P>
-        where P: FnMut(&Self::Item) -> bool;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<Self::Item>;
-
-    #[unstable(feature = "exact_chunks", issue = "47115")]
-    fn exact_chunks_mut(&mut self, size: usize) -> ExactChunksMut<Self::Item>;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn swap(&mut self, a: usize, b: usize);
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_at_mut(&mut self, mid: usize) -> (&mut [Self::Item], &mut [Self::Item]);
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn reverse(&mut self);
-
-    #[stable(feature = "core", since = "1.6.0")]
-    unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
-        where I: SliceIndex<Self>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn as_mut_ptr(&mut self) -> *mut Self::Item;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn contains(&self, x: &Self::Item) -> bool where Self::Item: PartialEq;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn starts_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq;
-
-    #[stable(feature = "slice_rotate", since = "1.26.0")]
-    fn rotate_left(&mut self, mid: usize);
-
-    #[stable(feature = "slice_rotate", since = "1.26.0")]
-    fn rotate_right(&mut self, k: usize);
-
-    #[stable(feature = "clone_from_slice", since = "1.7.0")]
-    fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone;
-
-    #[stable(feature = "copy_from_slice", since = "1.9.0")]
-    fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy;
-
-    #[stable(feature = "swap_with_slice", since = "1.27.0")]
-    fn swap_with_slice(&mut self, src: &mut [Self::Item]);
-
-    #[stable(feature = "sort_unstable", since = "1.20.0")]
-    fn sort_unstable(&mut self)
-        where Self::Item: Ord;
-
-    #[stable(feature = "sort_unstable", since = "1.20.0")]
-    fn sort_unstable_by<F>(&mut self, compare: F)
-        where F: FnMut(&Self::Item, &Self::Item) -> Ordering;
-
-    #[stable(feature = "sort_unstable", since = "1.20.0")]
-    fn sort_unstable_by_key<B, F>(&mut self, f: F)
-        where F: FnMut(&Self::Item) -> B,
-              B: Ord;
-}}
-
-// Use macros to be generic over const/mut
-macro_rules! slice_offset {
-    ($ptr:expr, $by:expr) => {{
-        let ptr = $ptr;
-        if size_from_ptr(ptr) == 0 {
-            (ptr as *mut i8).wrapping_offset($by) as _
-        } else {
-            ptr.offset($by)
-        }
-    }};
-}
-
-// make a &T from a *const T
-macro_rules! make_ref {
-    ($ptr:expr) => {{
-        let ptr = $ptr;
-        if size_from_ptr(ptr) == 0 {
-            // Use a non-null pointer value
-            &*(1 as *mut _)
-        } else {
-            &*ptr
-        }
-    }};
-}
-
-// make a &mut T from a *mut T
-macro_rules! make_ref_mut {
-    ($ptr:expr) => {{
-        let ptr = $ptr;
-        if size_from_ptr(ptr) == 0 {
-            // Use a non-null pointer value
-            &mut *(1 as *mut _)
-        } else {
-            &mut *ptr
-        }
-    }};
-}
-
-#[unstable(feature = "core_slice_ext",
-           reason = "stable interface provided by `impl [T]` in later crates",
-           issue = "32110")]
-impl<T> SliceExt for [T] {
-    type Item = T;
-
-    #[inline]
-    fn split_at(&self, mid: usize) -> (&[T], &[T]) {
-        (&self[..mid], &self[mid..])
-    }
-
-    #[inline]
-    fn iter(&self) -> Iter<T> {
-        unsafe {
-            let p = if mem::size_of::<T>() == 0 {
-                1 as *const _
-            } else {
-                let p = self.as_ptr();
-                assume(!p.is_null());
-                p
-            };
-
-            Iter {
-                ptr: p,
-                end: slice_offset!(p, self.len() as isize),
-                _marker: marker::PhantomData
-            }
-        }
-    }
-
-    #[inline]
-    fn split<P>(&self, pred: P) -> Split<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        Split {
-            v: self,
-            pred,
-            finished: false
-        }
-    }
-
-    #[inline]
-    fn rsplit<P>(&self, pred: P) -> RSplit<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        RSplit { inner: self.split(pred) }
-    }
-
-    #[inline]
-    fn splitn<P>(&self, n: usize, pred: P) -> SplitN<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        SplitN {
-            inner: GenericSplitN {
-                iter: self.split(pred),
-                count: n
-            }
-        }
-    }
-
-    #[inline]
-    fn rsplitn<P>(&self, n: usize, pred: P) -> RSplitN<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        RSplitN {
-            inner: GenericSplitN {
-                iter: self.rsplit(pred),
-                count: n
-            }
-        }
-    }
-
-    #[inline]
-    fn windows(&self, size: usize) -> Windows<T> {
-        assert!(size != 0);
-        Windows { v: self, size: size }
-    }
-
-    #[inline]
-    fn chunks(&self, chunk_size: usize) -> Chunks<T> {
-        assert!(chunk_size != 0);
-        Chunks { v: self, chunk_size: chunk_size }
-    }
-
-    #[inline]
-    fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
-        assert!(chunk_size != 0);
-        let rem = self.len() % chunk_size;
-        let len = self.len() - rem;
-        ExactChunks { v: &self[..len], chunk_size: chunk_size}
-    }
-
-    #[inline]
-    fn get<I>(&self, index: I) -> Option<&I::Output>
-        where I: SliceIndex<[T]>
-    {
-        index.get(self)
-    }
-
-    #[inline]
-    fn first(&self) -> Option<&T> {
-        if self.is_empty() { None } else { Some(&self[0]) }
-    }
-
-    #[inline]
-    fn split_first(&self) -> Option<(&T, &[T])> {
-        if self.is_empty() { None } else { Some((&self[0], &self[1..])) }
-    }
-
-    #[inline]
-    fn split_last(&self) -> Option<(&T, &[T])> {
-        let len = self.len();
-        if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) }
-    }
-
-    #[inline]
-    fn last(&self) -> Option<&T> {
-        if self.is_empty() { None } else { Some(&self[self.len() - 1]) }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
-        where I: SliceIndex<[T]>
-    {
-        index.get_unchecked(self)
-    }
-
-    #[inline]
-    fn as_ptr(&self) -> *const T {
-        self as *const [T] as *const T
-    }
-
-    fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
-        where F: FnMut(&'a T) -> Ordering
-    {
-        let s = self;
-        let mut size = s.len();
-        if size == 0 {
-            return Err(0);
-        }
-        let mut base = 0usize;
-        while size > 1 {
-            let half = size / 2;
-            let mid = base + half;
-            // mid is always in [0, size), that means mid is >= 0 and < size.
-            // mid >= 0: by definition
-            // mid < size: mid = size / 2 + size / 4 + size / 8 ...
-            let cmp = f(unsafe { s.get_unchecked(mid) });
-            base = if cmp == Greater { base } else { mid };
-            size -= half;
-        }
-        // base is always in [0, size) because base <= mid.
-        let cmp = f(unsafe { s.get_unchecked(base) });
-        if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) }
-    }
-
-    #[inline]
-    fn len(&self) -> usize {
-        unsafe {
-            mem::transmute::<&[T], Repr<T>>(self).len
-        }
-    }
-
-    #[inline]
-    fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
-        where I: SliceIndex<[T]>
-    {
-        index.get_mut(self)
-    }
-
-    #[inline]
-    fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
-        let len = self.len();
-        let ptr = self.as_mut_ptr();
-
-        unsafe {
-            assert!(mid <= len);
-
-            (from_raw_parts_mut(ptr, mid),
-             from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
-        }
-    }
-
-    #[inline]
-    fn iter_mut(&mut self) -> IterMut<T> {
-        unsafe {
-            let p = if mem::size_of::<T>() == 0 {
-                1 as *mut _
-            } else {
-                let p = self.as_mut_ptr();
-                assume(!p.is_null());
-                p
-            };
-
-            IterMut {
-                ptr: p,
-                end: slice_offset!(p, self.len() as isize),
-                _marker: marker::PhantomData
-            }
-        }
-    }
-
-    #[inline]
-    fn last_mut(&mut self) -> Option<&mut T> {
-        let len = self.len();
-        if len == 0 { return None; }
-        Some(&mut self[len - 1])
-    }
-
-    #[inline]
-    fn first_mut(&mut self) -> Option<&mut T> {
-        if self.is_empty() { None } else { Some(&mut self[0]) }
-    }
-
-    #[inline]
-    fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
-        if self.is_empty() { None } else {
-            let split = self.split_at_mut(1);
-            Some((&mut split.0[0], split.1))
-        }
-    }
-
-    #[inline]
-    fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
-        let len = self.len();
-        if len == 0 { None } else {
-            let split = self.split_at_mut(len - 1);
-            Some((&mut split.1[0], split.0))
-        }
-    }
-
-    #[inline]
-    fn split_mut<P>(&mut self, pred: P) -> SplitMut<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        SplitMut { v: self, pred: pred, finished: false }
-    }
-
-    #[inline]
-    fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        RSplitMut { inner: self.split_mut(pred) }
-    }
-
-    #[inline]
-    fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<T, P>
-        where P: FnMut(&T) -> bool
-    {
-        SplitNMut {
-            inner: GenericSplitN {
-                iter: self.split_mut(pred),
-                count: n
-            }
-        }
-    }
-
-    #[inline]
-    fn rsplitn_mut<P>(&mut self, n: usize, pred: P) -> RSplitNMut<T, P> where
-        P: FnMut(&T) -> bool,
-    {
-        RSplitNMut {
-            inner: GenericSplitN {
-                iter: self.rsplit_mut(pred),
-                count: n
-            }
-        }
-    }
-
-    #[inline]
-    fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
-        assert!(chunk_size != 0);
-        ChunksMut { v: self, chunk_size: chunk_size }
-    }
-
-    #[inline]
-    fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
-        assert!(chunk_size != 0);
-        let rem = self.len() % chunk_size;
-        let len = self.len() - rem;
-        ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size}
-    }
-
-    #[inline]
-    fn swap(&mut self, a: usize, b: usize) {
-        unsafe {
-            // Can't take two mutable loans from one vector, so instead just cast
-            // them to their raw pointers to do the swap
-            let pa: *mut T = &mut self[a];
-            let pb: *mut T = &mut self[b];
-            ptr::swap(pa, pb);
-        }
-    }
-
-    fn reverse(&mut self) {
-        let mut i: usize = 0;
-        let ln = self.len();
-
-        // For very small types, all the individual reads in the normal
-        // path perform poorly.  We can do better, given efficient unaligned
-        // load/store, by loading a larger chunk and reversing a register.
-
-        // Ideally LLVM would do this for us, as it knows better than we do
-        // whether unaligned reads are efficient (since that changes between
-        // different ARM versions, for example) and what the best chunk size
-        // would be.  Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls
-        // the loop, so we need to do this ourselves.  (Hypothesis: reverse
-        // is troublesome because the sides can be aligned differently --
-        // will be, when the length is odd -- so there's no way of emitting
-        // pre- and postludes to use fully-aligned SIMD in the middle.)
-
-        let fast_unaligned =
-            cfg!(any(target_arch = "x86", target_arch = "x86_64"));
-
-        if fast_unaligned && mem::size_of::<T>() == 1 {
-            // Use the llvm.bswap intrinsic to reverse u8s in a usize
-            let chunk = mem::size_of::<usize>();
-            while i + chunk - 1 < ln / 2 {
-                unsafe {
-                    let pa: *mut T = self.get_unchecked_mut(i);
-                    let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
-                    let va = ptr::read_unaligned(pa as *mut usize);
-                    let vb = ptr::read_unaligned(pb as *mut usize);
-                    ptr::write_unaligned(pa as *mut usize, vb.swap_bytes());
-                    ptr::write_unaligned(pb as *mut usize, va.swap_bytes());
-                }
-                i += chunk;
-            }
-        }
-
-        if fast_unaligned && mem::size_of::<T>() == 2 {
-            // Use rotate-by-16 to reverse u16s in a u32
-            let chunk = mem::size_of::<u32>() / 2;
-            while i + chunk - 1 < ln / 2 {
-                unsafe {
-                    let pa: *mut T = self.get_unchecked_mut(i);
-                    let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
-                    let va = ptr::read_unaligned(pa as *mut u32);
-                    let vb = ptr::read_unaligned(pb as *mut u32);
-                    ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16));
-                    ptr::write_unaligned(pb as *mut u32, va.rotate_left(16));
-                }
-                i += chunk;
-            }
-        }
-
-        while i < ln / 2 {
-            // Unsafe swap to avoid the bounds check in safe swap.
-            unsafe {
-                let pa: *mut T = self.get_unchecked_mut(i);
-                let pb: *mut T = self.get_unchecked_mut(ln - i - 1);
-                ptr::swap(pa, pb);
-            }
-            i += 1;
-        }
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
-        where I: SliceIndex<[T]>
-    {
-        index.get_unchecked_mut(self)
-    }
-
-    #[inline]
-    fn as_mut_ptr(&mut self) -> *mut T {
-        self as *mut [T] as *mut T
-    }
-
-    #[inline]
-    fn contains(&self, x: &T) -> bool where T: PartialEq {
-        x.slice_contains(self)
-    }
-
-    #[inline]
-    fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq {
-        let n = needle.len();
-        self.len() >= n && needle == &self[..n]
-    }
-
-    #[inline]
-    fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq {
-        let (m, n) = (self.len(), needle.len());
-        m >= n && needle == &self[m-n..]
-    }
-
-    fn binary_search(&self, x: &T) -> Result<usize, usize>
-        where T: Ord
-    {
-        self.binary_search_by(|p| p.cmp(x))
-    }
-
-    fn rotate_left(&mut self, mid: usize) {
-        assert!(mid <= self.len());
-        let k = self.len() - mid;
-
-        unsafe {
-            let p = self.as_mut_ptr();
-            rotate::ptr_rotate(mid, p.offset(mid as isize), k);
-        }
-    }
-
-    fn rotate_right(&mut self, k: usize) {
-        assert!(k <= self.len());
-        let mid = self.len() - k;
-
-        unsafe {
-            let p = self.as_mut_ptr();
-            rotate::ptr_rotate(mid, p.offset(mid as isize), k);
-        }
-    }
-
-    #[inline]
-    fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
-        assert!(self.len() == src.len(),
-                "destination and source slices have different lengths");
-        // NOTE: We need to explicitly slice them to the same length
-        // for bounds checking to be elided, and the optimizer will
-        // generate memcpy for simple cases (for example T = u8).
-        let len = self.len();
-        let src = &src[..len];
-        for i in 0..len {
-            self[i].clone_from(&src[i]);
+// Use macros to be generic over const/mut
+macro_rules! slice_offset {
+    ($ptr:expr, $by:expr) => {{
+        let ptr = $ptr;
+        if size_from_ptr(ptr) == 0 {
+            (ptr as *mut i8).wrapping_offset($by) as _
+        } else {
+            ptr.offset($by)
         }
-    }
+    }};
+}
 
-    #[inline]
-    fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
-        assert!(self.len() == src.len(),
-                "destination and source slices have different lengths");
-        unsafe {
-            ptr::copy_nonoverlapping(
-                src.as_ptr(), self.as_mut_ptr(), self.len());
+// make a &T from a *const T
+macro_rules! make_ref {
+    ($ptr:expr) => {{
+        let ptr = $ptr;
+        if size_from_ptr(ptr) == 0 {
+            // Use a non-null pointer value
+            &*(1 as *mut _)
+        } else {
+            &*ptr
         }
-    }
+    }};
+}
 
-    #[inline]
-    fn swap_with_slice(&mut self, src: &mut [T]) {
-        assert!(self.len() == src.len(),
-                "destination and source slices have different lengths");
-        unsafe {
-            ptr::swap_nonoverlapping(
-                self.as_mut_ptr(), src.as_mut_ptr(), self.len());
+// make a &mut T from a *mut T
+macro_rules! make_ref_mut {
+    ($ptr:expr) => {{
+        let ptr = $ptr;
+        if size_from_ptr(ptr) == 0 {
+            // Use a non-null pointer value
+            &mut *(1 as *mut _)
+        } else {
+            &mut *ptr
         }
-    }
-
-    #[inline]
-    fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
-        where F: FnMut(&'a Self::Item) -> B,
-              B: Ord
-    {
-        self.binary_search_by(|k| f(k).cmp(b))
-    }
-
-    #[inline]
-    fn sort_unstable(&mut self)
-        where Self::Item: Ord
-    {
-        sort::quicksort(self, |a, b| a.lt(b));
-    }
-
-    #[inline]
-    fn sort_unstable_by<F>(&mut self, mut compare: F)
-        where F: FnMut(&Self::Item, &Self::Item) -> Ordering
-    {
-        sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less);
-    }
-
-    #[inline]
-    fn sort_unstable_by_key<B, F>(&mut self, mut f: F)
-        where F: FnMut(&Self::Item) -> B,
-              B: Ord
-    {
-        sort::quicksort(self, |a, b| f(a).lt(&f(b)));
-    }
+    }};
 }
 
-// FIXME: remove (inline) this macro and the SliceExt trait
-// when updating to a bootstrap compiler that has the new lang items.
-#[cfg_attr(stage0, macro_export)]
-#[unstable(feature = "core_slice_ext", issue = "32110")]
-macro_rules! slice_core_methods { () => {
+#[lang = "slice"]
+#[cfg(not(test))]
+impl<T> [T] {
     /// Returns the number of elements in the slice.
     ///
     /// # Examples
@@ -774,7 +120,9 @@ macro_rules! slice_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn len(&self) -> usize {
-        SliceExt::len(self)
+        unsafe {
+            mem::transmute::<&[T], Repr<T>>(self).len
+        }
     }
 
     /// Returns `true` if the slice has a length of 0.
@@ -788,7 +136,7 @@ pub fn len(&self) -> usize {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn is_empty(&self) -> bool {
-        SliceExt::is_empty(self)
+        self.len() == 0
     }
 
     /// Returns the first element of the slice, or `None` if it is empty.
@@ -805,7 +153,7 @@ pub fn is_empty(&self) -> bool {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn first(&self) -> Option<&T> {
-        SliceExt::first(self)
+        if self.is_empty() { None } else { Some(&self[0]) }
     }
 
     /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty.
@@ -823,7 +171,7 @@ pub fn first(&self) -> Option<&T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn first_mut(&mut self) -> Option<&mut T> {
-        SliceExt::first_mut(self)
+        if self.is_empty() { None } else { Some(&mut self[0]) }
     }
 
     /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
@@ -841,7 +189,7 @@ pub fn first_mut(&mut self) -> Option<&mut T> {
     #[stable(feature = "slice_splits", since = "1.5.0")]
     #[inline]
     pub fn split_first(&self) -> Option<(&T, &[T])> {
-        SliceExt::split_first(self)
+        if self.is_empty() { None } else { Some((&self[0], &self[1..])) }
     }
 
     /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
@@ -861,7 +209,10 @@ pub fn split_first(&self) -> Option<(&T, &[T])> {
     #[stable(feature = "slice_splits", since = "1.5.0")]
     #[inline]
     pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
-        SliceExt::split_first_mut(self)
+        if self.is_empty() { None } else {
+            let split = self.split_at_mut(1);
+            Some((&mut split.0[0], split.1))
+        }
     }
 
     /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
@@ -879,7 +230,8 @@ pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
     #[stable(feature = "slice_splits", since = "1.5.0")]
     #[inline]
     pub fn split_last(&self) -> Option<(&T, &[T])> {
-        SliceExt::split_last(self)
+        let len = self.len();
+        if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) }
     }
 
     /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
@@ -899,7 +251,12 @@ pub fn split_last(&self) -> Option<(&T, &[T])> {
     #[stable(feature = "slice_splits", since = "1.5.0")]
     #[inline]
     pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
-        SliceExt::split_last_mut(self)
+        let len = self.len();
+        if len == 0 { None } else {
+            let split = self.split_at_mut(len - 1);
+            Some((&mut split.1[0], split.0))
+        }
+
     }
 
     /// Returns the last element of the slice, or `None` if it is empty.
@@ -916,7 +273,7 @@ pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn last(&self) -> Option<&T> {
-        SliceExt::last(self)
+        if self.is_empty() { None } else { Some(&self[self.len() - 1]) }
     }
 
     /// Returns a mutable pointer to the last item in the slice.
@@ -934,7 +291,9 @@ pub fn last(&self) -> Option<&T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn last_mut(&mut self) -> Option<&mut T> {
-        SliceExt::last_mut(self)
+        let len = self.len();
+        if len == 0 { return None; }
+        Some(&mut self[len - 1])
     }
 
     /// Returns a reference to an element or subslice depending on the type of
@@ -959,7 +318,7 @@ pub fn last_mut(&mut self) -> Option<&mut T> {
     pub fn get<I>(&self, index: I) -> Option<&I::Output>
         where I: SliceIndex<Self>
     {
-        SliceExt::get(self, index)
+        index.get(self)
     }
 
     /// Returns a mutable reference to an element or subslice depending on the
@@ -982,7 +341,7 @@ pub fn get<I>(&self, index: I) -> Option<&I::Output>
     pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
         where I: SliceIndex<Self>
     {
-        SliceExt::get_mut(self, index)
+        index.get_mut(self)
     }
 
     /// Returns a reference to an element or subslice, without doing bounds
@@ -1007,7 +366,7 @@ pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
     pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
         where I: SliceIndex<Self>
     {
-        SliceExt::get_unchecked(self, index)
+        index.get_unchecked(self)
     }
 
     /// Returns a mutable reference to an element or subslice, without doing
@@ -1034,7 +393,7 @@ pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
     pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
         where I: SliceIndex<Self>
     {
-        SliceExt::get_unchecked_mut(self, index)
+        index.get_unchecked_mut(self)
     }
 
     /// Returns a raw pointer to the slice's buffer.
@@ -1060,7 +419,7 @@ pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn as_ptr(&self) -> *const T {
-        SliceExt::as_ptr(self)
+        self as *const [T] as *const T
     }
 
     /// Returns an unsafe mutable pointer to the slice's buffer.
@@ -1087,7 +446,7 @@ pub fn as_ptr(&self) -> *const T {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn as_mut_ptr(&mut self) -> *mut T {
-        SliceExt::as_mut_ptr(self)
+        self as *mut [T] as *mut T
     }
 
     /// Swaps two elements in the slice.
@@ -1111,22 +470,87 @@ pub fn as_mut_ptr(&mut self) -> *mut T {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn swap(&mut self, a: usize, b: usize) {
-        SliceExt::swap(self, a, b)
+        unsafe {
+            // Can't take two mutable loans from one vector, so instead just cast
+            // them to their raw pointers to do the swap
+            let pa: *mut T = &mut self[a];
+            let pb: *mut T = &mut self[b];
+            ptr::swap(pa, pb);
+        }
     }
 
-    /// Reverses the order of elements in the slice, in place.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut v = [1, 2, 3];
-    /// v.reverse();
-    /// assert!(v == [3, 2, 1]);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[inline]
-    pub fn reverse(&mut self) {
-        SliceExt::reverse(self)
+    /// Reverses the order of elements in the slice, in place.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut v = [1, 2, 3];
+    /// v.reverse();
+    /// assert!(v == [3, 2, 1]);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[inline]
+    pub fn reverse(&mut self) {
+        let mut i: usize = 0;
+        let ln = self.len();
+
+        // For very small types, all the individual reads in the normal
+        // path perform poorly.  We can do better, given efficient unaligned
+        // load/store, by loading a larger chunk and reversing a register.
+
+        // Ideally LLVM would do this for us, as it knows better than we do
+        // whether unaligned reads are efficient (since that changes between
+        // different ARM versions, for example) and what the best chunk size
+        // would be.  Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls
+        // the loop, so we need to do this ourselves.  (Hypothesis: reverse
+        // is troublesome because the sides can be aligned differently --
+        // will be, when the length is odd -- so there's no way of emitting
+        // pre- and postludes to use fully-aligned SIMD in the middle.)
+
+        let fast_unaligned =
+            cfg!(any(target_arch = "x86", target_arch = "x86_64"));
+
+        if fast_unaligned && mem::size_of::<T>() == 1 {
+            // Use the llvm.bswap intrinsic to reverse u8s in a usize
+            let chunk = mem::size_of::<usize>();
+            while i + chunk - 1 < ln / 2 {
+                unsafe {
+                    let pa: *mut T = self.get_unchecked_mut(i);
+                    let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
+                    let va = ptr::read_unaligned(pa as *mut usize);
+                    let vb = ptr::read_unaligned(pb as *mut usize);
+                    ptr::write_unaligned(pa as *mut usize, vb.swap_bytes());
+                    ptr::write_unaligned(pb as *mut usize, va.swap_bytes());
+                }
+                i += chunk;
+            }
+        }
+
+        if fast_unaligned && mem::size_of::<T>() == 2 {
+            // Use rotate-by-16 to reverse u16s in a u32
+            let chunk = mem::size_of::<u32>() / 2;
+            while i + chunk - 1 < ln / 2 {
+                unsafe {
+                    let pa: *mut T = self.get_unchecked_mut(i);
+                    let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
+                    let va = ptr::read_unaligned(pa as *mut u32);
+                    let vb = ptr::read_unaligned(pb as *mut u32);
+                    ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16));
+                    ptr::write_unaligned(pb as *mut u32, va.rotate_left(16));
+                }
+                i += chunk;
+            }
+        }
+
+        while i < ln / 2 {
+            // Unsafe swap to avoid the bounds check in safe swap.
+            unsafe {
+                let pa: *mut T = self.get_unchecked_mut(i);
+                let pb: *mut T = self.get_unchecked_mut(ln - i - 1);
+                ptr::swap(pa, pb);
+            }
+            i += 1;
+        }
     }
 
     /// Returns an iterator over the slice.
@@ -1145,7 +569,21 @@ pub fn reverse(&mut self) {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn iter(&self) -> Iter<T> {
-        SliceExt::iter(self)
+        unsafe {
+            let p = if mem::size_of::<T>() == 0 {
+                1 as *const _
+            } else {
+                let p = self.as_ptr();
+                assume(!p.is_null());
+                p
+            };
+
+            Iter {
+                ptr: p,
+                end: slice_offset!(p, self.len() as isize),
+                _marker: marker::PhantomData
+            }
+        }
     }
 
     /// Returns an iterator that allows modifying each value.
@@ -1162,7 +600,21 @@ pub fn iter(&self) -> Iter<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn iter_mut(&mut self) -> IterMut<T> {
-        SliceExt::iter_mut(self)
+        unsafe {
+            let p = if mem::size_of::<T>() == 0 {
+                1 as *mut _
+            } else {
+                let p = self.as_mut_ptr();
+                assume(!p.is_null());
+                p
+            };
+
+            IterMut {
+                ptr: p,
+                end: slice_offset!(p, self.len() as isize),
+                _marker: marker::PhantomData
+            }
+        }
     }
 
     /// Returns an iterator over all contiguous windows of length
@@ -1194,7 +646,8 @@ pub fn iter_mut(&mut self) -> IterMut<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn windows(&self, size: usize) -> Windows<T> {
-        SliceExt::windows(self, size)
+        assert!(size != 0);
+        Windows { v: self, size: size }
     }
 
     /// Returns an iterator over `chunk_size` elements of the slice at a
@@ -1224,7 +677,8 @@ pub fn windows(&self, size: usize) -> Windows<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
-        SliceExt::chunks(self, chunk_size)
+        assert!(chunk_size != 0);
+        Chunks { v: self, chunk_size: chunk_size }
     }
 
     /// Returns an iterator over `chunk_size` elements of the slice at a
@@ -1256,7 +710,10 @@ pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
     #[unstable(feature = "exact_chunks", issue = "47115")]
     #[inline]
     pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
-        SliceExt::exact_chunks(self, chunk_size)
+        assert!(chunk_size != 0);
+        let rem = self.len() % chunk_size;
+        let len = self.len() - rem;
+        ExactChunks { v: &self[..len], chunk_size: chunk_size}
     }
 
     /// Returns an iterator over `chunk_size` elements of the slice at a time.
@@ -1290,7 +747,8 @@ pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
-        SliceExt::chunks_mut(self, chunk_size)
+        assert!(chunk_size != 0);
+        ChunksMut { v: self, chunk_size: chunk_size }
     }
 
     /// Returns an iterator over `chunk_size` elements of the slice at a time.
@@ -1328,7 +786,10 @@ pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
     #[unstable(feature = "exact_chunks", issue = "47115")]
     #[inline]
     pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
-        SliceExt::exact_chunks_mut(self, chunk_size)
+        assert!(chunk_size != 0);
+        let rem = self.len() % chunk_size;
+        let len = self.len() - rem;
+        ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size}
     }
 
     /// Divides one slice into two at an index.
@@ -1367,7 +828,7 @@ pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
-        SliceExt::split_at(self, mid)
+        (&self[..mid], &self[mid..])
     }
 
     /// Divides one mutable slice into two at an index.
@@ -1397,7 +858,15 @@ pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
-        SliceExt::split_at_mut(self, mid)
+        let len = self.len();
+        let ptr = self.as_mut_ptr();
+
+        unsafe {
+            assert!(mid <= len);
+
+            (from_raw_parts_mut(ptr, mid),
+             from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
+        }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1445,7 +914,11 @@ pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
     pub fn split<F>(&self, pred: F) -> Split<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::split(self, pred)
+        Split {
+            v: self,
+            pred,
+            finished: false
+        }
     }
 
     /// Returns an iterator over mutable subslices separated by elements that
@@ -1466,7 +939,7 @@ pub fn split<F>(&self, pred: F) -> Split<T, F>
     pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::split_mut(self, pred)
+        SplitMut { v: self, pred: pred, finished: false }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1501,7 +974,7 @@ pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
     pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::rsplit(self, pred)
+        RSplit { inner: self.split(pred) }
     }
 
     /// Returns an iterator over mutable subslices separated by elements that
@@ -1526,7 +999,7 @@ pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F>
     pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::rsplit_mut(self, pred)
+        RSplitMut { inner: self.split_mut(pred) }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1553,7 +1026,12 @@ pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F>
     pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::splitn(self, n, pred)
+        SplitN {
+            inner: GenericSplitN {
+                iter: self.split(pred),
+                count: n
+            }
+        }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1578,7 +1056,12 @@ pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F>
     pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::splitn_mut(self, n, pred)
+        SplitNMut {
+            inner: GenericSplitN {
+                iter: self.split_mut(pred),
+                count: n
+            }
+        }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1606,7 +1089,12 @@ pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
     pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::rsplitn(self, n, pred)
+        RSplitN {
+            inner: GenericSplitN {
+                iter: self.rsplit(pred),
+                count: n
+            }
+        }
     }
 
     /// Returns an iterator over subslices separated by elements that match
@@ -1632,7 +1120,12 @@ pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F>
     pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
         where F: FnMut(&T) -> bool
     {
-        SliceExt::rsplitn_mut(self, n, pred)
+        RSplitNMut {
+            inner: GenericSplitN {
+                iter: self.rsplit_mut(pred),
+                count: n
+            }
+        }
     }
 
     /// Returns `true` if the slice contains an element with the given value.
@@ -1648,7 +1141,7 @@ pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
     pub fn contains(&self, x: &T) -> bool
         where T: PartialEq
     {
-        SliceExt::contains(self, x)
+        x.slice_contains(self)
     }
 
     /// Returns `true` if `needle` is a prefix of the slice.
@@ -1675,7 +1168,8 @@ pub fn contains(&self, x: &T) -> bool
     pub fn starts_with(&self, needle: &[T]) -> bool
         where T: PartialEq
     {
-        SliceExt::starts_with(self, needle)
+        let n = needle.len();
+        self.len() >= n && needle == &self[..n]
     }
 
     /// Returns `true` if `needle` is a suffix of the slice.
@@ -1702,7 +1196,8 @@ pub fn starts_with(&self, needle: &[T]) -> bool
     pub fn ends_with(&self, needle: &[T]) -> bool
         where T: PartialEq
     {
-        SliceExt::ends_with(self, needle)
+        let (m, n) = (self.len(), needle.len());
+        m >= n && needle == &self[m-n..]
     }
 
     /// Binary searches this sorted slice for a given element.
@@ -1731,7 +1226,7 @@ pub fn ends_with(&self, needle: &[T]) -> bool
     pub fn binary_search(&self, x: &T) -> Result<usize, usize>
         where T: Ord
     {
-        SliceExt::binary_search(self, x)
+        self.binary_search_by(|p| p.cmp(x))
     }
 
     /// Binary searches this sorted slice with a comparator function.
@@ -1767,10 +1262,29 @@ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
+    pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
         where F: FnMut(&'a T) -> Ordering
     {
-        SliceExt::binary_search_by(self, f)
+        let s = self;
+        let mut size = s.len();
+        if size == 0 {
+            return Err(0);
+        }
+        let mut base = 0usize;
+        while size > 1 {
+            let half = size / 2;
+            let mid = base + half;
+            // mid is always in [0, size), that means mid is >= 0 and < size.
+            // mid >= 0: by definition
+            // mid < size: mid = size / 2 + size / 4 + size / 8 ...
+            let cmp = f(unsafe { s.get_unchecked(mid) });
+            base = if cmp == Greater { base } else { mid };
+            size -= half;
+        }
+        // base is always in [0, size) because base <= mid.
+        let cmp = f(unsafe { s.get_unchecked(base) });
+        if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) }
+
     }
 
     /// Binary searches this sorted slice with a key extraction function.
@@ -1805,11 +1319,11 @@ pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
     /// ```
     #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
     #[inline]
-    pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
+    pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
         where F: FnMut(&'a T) -> B,
               B: Ord
     {
-        SliceExt::binary_search_by_key(self, b, f)
+        self.binary_search_by(|k| f(k).cmp(b))
     }
 
     /// Sorts the slice, but may not preserve the order of equal elements.
@@ -1843,7 +1357,7 @@ pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, us
     pub fn sort_unstable(&mut self)
         where T: Ord
     {
-        SliceExt::sort_unstable(self);
+        sort::quicksort(self, |a, b| a.lt(b));
     }
 
     /// Sorts the slice with a comparator function, but may not preserve the order of equal
@@ -1878,10 +1392,10 @@ pub fn sort_unstable(&mut self)
     /// [pdqsort]: https://github.com/orlp/pdqsort
     #[stable(feature = "sort_unstable", since = "1.20.0")]
     #[inline]
-    pub fn sort_unstable_by<F>(&mut self, compare: F)
+    pub fn sort_unstable_by<F>(&mut self, mut compare: F)
         where F: FnMut(&T, &T) -> Ordering
     {
-        SliceExt::sort_unstable_by(self, compare);
+        sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less);
     }
 
     /// Sorts the slice with a key extraction function, but may not preserve the order of equal
@@ -1910,10 +1424,10 @@ pub fn sort_unstable_by<F>(&mut self, compare: F)
     /// [pdqsort]: https://github.com/orlp/pdqsort
     #[stable(feature = "sort_unstable", since = "1.20.0")]
     #[inline]
-    pub fn sort_unstable_by_key<K, F>(&mut self, f: F)
+    pub fn sort_unstable_by_key<K, F>(&mut self, mut f: F)
         where F: FnMut(&T) -> K, K: Ord
     {
-        SliceExt::sort_unstable_by_key(self, f);
+        sort::quicksort(self, |a, b| f(a).lt(&f(b)));
     }
 
     /// Rotates the slice in-place such that the first `mid` elements of the
@@ -1948,7 +1462,13 @@ pub fn sort_unstable_by_key<K, F>(&mut self, f: F)
    /// ```
     #[stable(feature = "slice_rotate", since = "1.26.0")]
     pub fn rotate_left(&mut self, mid: usize) {
-        SliceExt::rotate_left(self, mid);
+        assert!(mid <= self.len());
+        let k = self.len() - mid;
+
+        unsafe {
+            let p = self.as_mut_ptr();
+            rotate::ptr_rotate(mid, p.offset(mid as isize), k);
+        }
     }
 
     /// Rotates the slice in-place such that the first `self.len() - k`
@@ -1983,7 +1503,13 @@ pub fn rotate_left(&mut self, mid: usize) {
     /// ```
     #[stable(feature = "slice_rotate", since = "1.26.0")]
     pub fn rotate_right(&mut self, k: usize) {
-        SliceExt::rotate_right(self, k);
+        assert!(k <= self.len());
+        let mid = self.len() - k;
+
+        unsafe {
+            let p = self.as_mut_ptr();
+            rotate::ptr_rotate(mid, p.offset(mid as isize), k);
+        }
     }
 
     /// Copies the elements from `src` into `self`.
@@ -2040,7 +1566,17 @@ pub fn rotate_right(&mut self, k: usize) {
     /// [`split_at_mut`]: #method.split_at_mut
     #[stable(feature = "clone_from_slice", since = "1.7.0")]
     pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
-        SliceExt::clone_from_slice(self, src)
+        assert!(self.len() == src.len(),
+                "destination and source slices have different lengths");
+        // NOTE: We need to explicitly slice them to the same length
+        // for bounds checking to be elided, and the optimizer will
+        // generate memcpy for simple cases (for example T = u8).
+        let len = self.len();
+        let src = &src[..len];
+        for i in 0..len {
+            self[i].clone_from(&src[i]);
+        }
+
     }
 
     /// Copies all elements from `src` into `self`, using a memcpy.
@@ -2096,7 +1632,12 @@ pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
     /// [`split_at_mut`]: #method.split_at_mut
     #[stable(feature = "copy_from_slice", since = "1.9.0")]
     pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
-        SliceExt::copy_from_slice(self, src)
+        assert!(self.len() == src.len(),
+                "destination and source slices have different lengths");
+        unsafe {
+            ptr::copy_nonoverlapping(
+                src.as_ptr(), self.as_mut_ptr(), self.len());
+        }
     }
 
     /// Swaps all elements in `self` with those in `other`.
@@ -2148,22 +1689,185 @@ pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
     /// [`split_at_mut`]: #method.split_at_mut
     #[stable(feature = "swap_with_slice", since = "1.27.0")]
     pub fn swap_with_slice(&mut self, other: &mut [T]) {
-        SliceExt::swap_with_slice(self, other)
+        assert!(self.len() == other.len(),
+                "destination and source slices have different lengths");
+        unsafe {
+            ptr::swap_nonoverlapping(
+                self.as_mut_ptr(), other.as_mut_ptr(), self.len());
+        }
     }
-}}
 
-#[lang = "slice"]
-#[cfg(not(test))]
-#[cfg(not(stage0))]
-impl<T> [T] {
-    slice_core_methods!();
+    /// Function to calculate lenghts of the middle and trailing slice for `align_to{,_mut}`.
+    fn align_to_offsets<U>(&self) -> (usize, usize) {
+        // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a
+        // lowest number of `T`s. And how many `T`s we need for each such "multiple".
+        //
+        // Consider for example T=u8 U=u16. Then we can put 1 U in 2 Ts. Simple. Now, consider
+        // for example a case where size_of::<T> = 16, size_of::<U> = 24. We can put 2 Us in
+        // place of every 3 Ts in the `rest` slice. A bit more complicated.
+        //
+        // Formula to calculate this is:
+        //
+        // Us = lcm(size_of::<T>, size_of::<U>) / size_of::<U>
+        // Ts = lcm(size_of::<T>, size_of::<U>) / size_of::<T>
+        //
+        // Expanded and simplified:
+        //
+        // Us = size_of::<T> / gcd(size_of::<T>, size_of::<U>)
+        // Ts = size_of::<U> / gcd(size_of::<T>, size_of::<U>)
+        //
+        // Luckily since all this is constant-evaluated... performance here matters not!
+        #[inline]
+        fn gcd(a: usize, b: usize) -> usize {
+            // iterative stein’s algorithm
+            // We should still make this `const fn` (and revert to recursive algorithm if we do)
+            // because relying on llvm to consteval all this is… well, it makes me
+            let (ctz_a, mut ctz_b) = unsafe {
+                if a == 0 { return b; }
+                if b == 0 { return a; }
+                (::intrinsics::cttz_nonzero(a), ::intrinsics::cttz_nonzero(b))
+            };
+            let k = ctz_a.min(ctz_b);
+            let mut a = a >> ctz_a;
+            let mut b = b;
+            loop {
+                // remove all factors of 2 from b
+                b >>= ctz_b;
+                if a > b {
+                    ::mem::swap(&mut a, &mut b);
+                }
+                b = b - a;
+                unsafe {
+                    if b == 0 {
+                        break;
+                    }
+                    ctz_b = ::intrinsics::cttz_nonzero(b);
+                }
+            }
+            return a << k;
+        }
+        let gcd: usize = gcd(::mem::size_of::<T>(), ::mem::size_of::<U>());
+        let ts: usize = ::mem::size_of::<U>() / gcd;
+        let us: usize = ::mem::size_of::<T>() / gcd;
+
+        // Armed with this knowledge, we can find how many `U`s we can fit!
+        let us_len = self.len() / ts * us;
+        // And how many `T`s will be in the trailing slice!
+        let ts_len = self.len() % ts;
+        return (us_len, ts_len);
+    }
+
+    /// Transmute the slice to a slice of another type, ensuring aligment of the types is
+    /// maintained.
+    ///
+    /// This method splits the slice into three distinct slices: prefix, correctly aligned middle
+    /// slice of a new type, and the suffix slice. The middle slice will have the greatest length
+    /// possible for a given type and input slice.
+    ///
+    /// This method has no purpose when either input element `T` or output element `U` are
+    /// zero-sized and will return the original slice without splitting anything.
+    ///
+    /// # Unsafety
+    ///
+    /// This method is essentially a `transmute` with respect to the elements in the returned
+    /// middle slice, so all the usual caveats pertaining to `transmute::<T, U>` also apply here.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # #![feature(slice_align_to)]
+    /// unsafe {
+    ///     let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
+    ///     let (prefix, shorts, suffix) = bytes.align_to::<u16>();
+    ///     // less_efficient_algorithm_for_bytes(prefix);
+    ///     // more_efficient_algorithm_for_aligned_shorts(shorts);
+    ///     // less_efficient_algorithm_for_bytes(suffix);
+    /// }
+    /// ```
+    #[unstable(feature = "slice_align_to", issue = "44488")]
+    #[cfg(not(stage0))]
+    pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T]) {
+        // Note that most of this function will be constant-evaluated,
+        if ::mem::size_of::<U>() == 0 || ::mem::size_of::<T>() == 0 {
+            // handle ZSTs specially, which is – don't handle them at all.
+            return (self, &[], &[]);
+        }
+
+        // First, find at what point do we split between the first and 2nd slice. Easy with
+        // ptr.align_offset.
+        let ptr = self.as_ptr();
+        let offset = ::ptr::align_offset(ptr, ::mem::align_of::<U>());
+        if offset > self.len() {
+            return (self, &[], &[]);
+        } else {
+            let (left, rest) = self.split_at(offset);
+            let (us_len, ts_len) = rest.align_to_offsets::<U>();
+            return (left,
+                    from_raw_parts(rest.as_ptr() as *const U, us_len),
+                    from_raw_parts(rest.as_ptr().offset((rest.len() - ts_len) as isize), ts_len))
+        }
+    }
+
+    /// Transmute the slice to a slice of another type, ensuring aligment of the types is
+    /// maintained.
+    ///
+    /// This method splits the slice into three distinct slices: prefix, correctly aligned middle
+    /// slice of a new type, and the suffix slice. The middle slice will have the greatest length
+    /// possible for a given type and input slice.
+    ///
+    /// This method has no purpose when either input element `T` or output element `U` are
+    /// zero-sized and will return the original slice without splitting anything.
+    ///
+    /// # Unsafety
+    ///
+    /// This method is essentially a `transmute` with respect to the elements in the returned
+    /// middle slice, so all the usual caveats pertaining to `transmute::<T, U>` also apply here.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # #![feature(slice_align_to)]
+    /// unsafe {
+    ///     let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
+    ///     let (prefix, shorts, suffix) = bytes.align_to_mut::<u16>();
+    ///     // less_efficient_algorithm_for_bytes(prefix);
+    ///     // more_efficient_algorithm_for_aligned_shorts(shorts);
+    ///     // less_efficient_algorithm_for_bytes(suffix);
+    /// }
+    /// ```
+    #[unstable(feature = "slice_align_to", issue = "44488")]
+    #[cfg(not(stage0))]
+    pub unsafe fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T]) {
+        // Note that most of this function will be constant-evaluated,
+        if ::mem::size_of::<U>() == 0 || ::mem::size_of::<T>() == 0 {
+            // handle ZSTs specially, which is – don't handle them at all.
+            return (self, &mut [], &mut []);
+        }
+
+        // First, find at what point do we split between the first and 2nd slice. Easy with
+        // ptr.align_offset.
+        let ptr = self.as_ptr();
+        let offset = ::ptr::align_offset(ptr, ::mem::align_of::<U>());
+        if offset > self.len() {
+            return (self, &mut [], &mut []);
+        } else {
+            let (left, rest) = self.split_at_mut(offset);
+            let (us_len, ts_len) = rest.align_to_offsets::<U>();
+            let mut_ptr = rest.as_mut_ptr();
+            return (left,
+                    from_raw_parts_mut(mut_ptr as *mut U, us_len),
+                    from_raw_parts_mut(mut_ptr.offset((rest.len() - ts_len) as isize), ts_len))
+        }
+    }
 }
 
-// FIXME: remove (inline) this macro
-// when updating to a bootstrap compiler that has the new lang items.
-#[cfg_attr(stage0, macro_export)]
-#[unstable(feature = "core_slice_ext", issue = "32110")]
-macro_rules! slice_u8_core_methods { () => {
+#[lang = "slice_u8"]
+#[cfg(not(test))]
+impl [u8] {
     /// Checks if all bytes in this slice are within the ASCII range.
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
     #[inline]
@@ -2217,13 +1921,7 @@ pub fn make_ascii_lowercase(&mut self) {
             byte.make_ascii_lowercase();
         }
     }
-}}
 
-#[lang = "slice_u8"]
-#[cfg(not(test))]
-#[cfg(not(stage0))]
-impl [u8] {
-    slice_u8_core_methods!();
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
index df7b2f25a86df19820db40788ec3b27f53e4e33a..82bead0ab467699f04025ac1ef8c406d5ac315ff 100644 (file)
@@ -2097,119 +2097,7 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
             (..self.end+1).index_mut(slice)
         }
     }
-
-}
-
-public_in_stage0! {
-{
-/// Methods for string slices
-#[allow(missing_docs)]
-#[doc(hidden)]
-#[unstable(feature = "core_str_ext",
-           reason = "stable interface provided by `impl str` in later crates",
-           issue = "32110")]
 }
-trait StrExt {
-    // NB there are no docs here are they're all located on the StrExt trait in
-    // liballoc, not here.
-
-    #[stable(feature = "core", since = "1.6.0")]
-    fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn chars(&self) -> Chars;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn bytes(&self) -> Bytes;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn char_indices(&self) -> CharIndices;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn lines(&self) -> Lines;
-    #[stable(feature = "core", since = "1.6.0")]
-    #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")]
-    #[allow(deprecated)]
-    fn lines_any(&self) -> LinesAny;
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output>;
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output>;
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output;
-    #[stable(feature = "str_checked_slicing", since = "1.20.0")]
-    unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output;
-    #[stable(feature = "core", since = "1.6.0")]
-    unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str;
-    #[stable(feature = "core", since = "1.6.0")]
-    unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
-        where P::Searcher: DoubleEndedSearcher<'a>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
-        where P::Searcher: ReverseSearcher<'a>;
-    #[stable(feature = "is_char_boundary", since = "1.9.0")]
-    fn is_char_boundary(&self, index: usize) -> bool;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn as_bytes(&self) -> &[u8];
-    #[stable(feature = "str_mut_extras", since = "1.20.0")]
-    unsafe fn as_bytes_mut(&mut self) -> &mut [u8];
-    #[stable(feature = "core", since = "1.6.0")]
-    fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
-        where P::Searcher: ReverseSearcher<'a>;
-    fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_at(&self, mid: usize) -> (&str, &str);
-    #[stable(feature = "core", since = "1.6.0")]
-    fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str);
-    #[stable(feature = "core", since = "1.6.0")]
-    fn as_ptr(&self) -> *const u8;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn len(&self) -> usize;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn is_empty(&self) -> bool;
-    #[stable(feature = "core", since = "1.6.0")]
-    fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
-    #[stable(feature = "split_whitespace", since = "1.1.0")]
-    fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>;
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn trim(&self) -> &str;
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn trim_left(&self) -> &str;
-    #[stable(feature = "rust1", since = "1.0.0")]
-    fn trim_right(&self) -> &str;
-}}
 
 // truncate `&str` to length at most equal to `max`
 // return `true` if it were truncated, and the new str.
@@ -2255,307 +2143,9 @@ fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
            index, ch, char_range, s_trunc, ellipsis);
 }
 
-#[stable(feature = "core", since = "1.6.0")]
-impl StrExt for str {
-    #[inline]
-    fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
-        pat.is_contained_in(self)
-    }
-
-    #[inline]
-    fn chars(&self) -> Chars {
-        Chars{iter: self.as_bytes().iter()}
-    }
-
-    #[inline]
-    fn bytes(&self) -> Bytes {
-        Bytes(self.as_bytes().iter().cloned())
-    }
-
-    #[inline]
-    fn char_indices(&self) -> CharIndices {
-        CharIndices { front_offset: 0, iter: self.chars() }
-    }
-
-    #[inline]
-    fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
-        Split(SplitInternal {
-            start: 0,
-            end: self.len(),
-            matcher: pat.into_searcher(self),
-            allow_trailing_empty: true,
-            finished: false,
-        })
-    }
-
-    #[inline]
-    fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        RSplit(self.split(pat).0)
-    }
-
-    #[inline]
-    fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
-        SplitN(SplitNInternal {
-            iter: self.split(pat).0,
-            count,
-        })
-    }
-
-    #[inline]
-    fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        RSplitN(self.splitn(count, pat).0)
-    }
-
-    #[inline]
-    fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
-        SplitTerminator(SplitInternal {
-            allow_trailing_empty: false,
-            ..self.split(pat).0
-        })
-    }
-
-    #[inline]
-    fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        RSplitTerminator(self.split_terminator(pat).0)
-    }
-
-    #[inline]
-    fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
-        Matches(MatchesInternal(pat.into_searcher(self)))
-    }
-
-    #[inline]
-    fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        RMatches(self.matches(pat).0)
-    }
-
-    #[inline]
-    fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
-        MatchIndices(MatchIndicesInternal(pat.into_searcher(self)))
-    }
-
-    #[inline]
-    fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        RMatchIndices(self.match_indices(pat).0)
-    }
-    #[inline]
-    fn lines(&self) -> Lines {
-        Lines(self.split_terminator('\n').map(LinesAnyMap))
-    }
-
-    #[inline]
-    #[allow(deprecated)]
-    fn lines_any(&self) -> LinesAny {
-        LinesAny(self.lines())
-    }
-
-    #[inline]
-    fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
-        i.get(self)
-    }
-
-    #[inline]
-    fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
-        i.get_mut(self)
-    }
-
-    #[inline]
-    unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
-        i.get_unchecked(self)
-    }
-
-    #[inline]
-    unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
-        i.get_unchecked_mut(self)
-    }
-
-    #[inline]
-    unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
-        (begin..end).get_unchecked(self)
-    }
-
-    #[inline]
-    unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
-        (begin..end).get_unchecked_mut(self)
-    }
-
-    #[inline]
-    fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
-        pat.is_prefix_of(self)
-    }
-
-    #[inline]
-    fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        pat.is_suffix_of(self)
-    }
-
-    #[inline]
-    fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
-        where P::Searcher: DoubleEndedSearcher<'a>
-    {
-        let mut i = 0;
-        let mut j = 0;
-        let mut matcher = pat.into_searcher(self);
-        if let Some((a, b)) = matcher.next_reject() {
-            i = a;
-            j = b; // Remember earliest known match, correct it below if
-                   // last match is different
-        }
-        if let Some((_, b)) = matcher.next_reject_back() {
-            j = b;
-        }
-        unsafe {
-            // Searcher is known to return valid indices
-            self.slice_unchecked(i, j)
-        }
-    }
-
-    #[inline]
-    fn trim_left_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() {
-            i = a;
-        }
-        unsafe {
-            // Searcher is known to return valid indices
-            self.slice_unchecked(i, self.len())
-        }
-    }
-
-    #[inline]
-    fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        let mut j = 0;
-        let mut matcher = pat.into_searcher(self);
-        if let Some((_, b)) = matcher.next_reject_back() {
-            j = b;
-        }
-        unsafe {
-            // Searcher is known to return valid indices
-            self.slice_unchecked(0, j)
-        }
-    }
-
-    #[inline]
-    fn is_char_boundary(&self, index: usize) -> bool {
-        // 0 and len are always ok.
-        // Test for 0 explicitly so that it can optimize out the check
-        // easily and skip reading string data for that case.
-        if index == 0 || index == self.len() { return true; }
-        match self.as_bytes().get(index) {
-            None => false,
-            // This is bit magic equivalent to: b < 128 || b >= 192
-            Some(&b) => (b as i8) >= -0x40,
-        }
-    }
-
-    #[inline]
-    fn as_bytes(&self) -> &[u8] {
-        unsafe { &*(self as *const str as *const [u8]) }
-    }
-
-    #[inline]
-    unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
-        &mut *(self as *mut str as *mut [u8])
-    }
-
-    fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
-        pat.into_searcher(self).next_match().map(|(i, _)| i)
-    }
-
-    fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
-        where P::Searcher: ReverseSearcher<'a>
-    {
-        pat.into_searcher(self).next_match_back().map(|(i, _)| i)
-    }
-
-    fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
-        self.find(pat)
-    }
-
-    #[inline]
-    fn split_at(&self, mid: usize) -> (&str, &str) {
-        // is_char_boundary checks that the index is in [0, .len()]
-        if self.is_char_boundary(mid) {
-            unsafe {
-                (self.slice_unchecked(0, mid),
-                 self.slice_unchecked(mid, self.len()))
-            }
-        } else {
-            slice_error_fail(self, 0, mid)
-        }
-    }
-
-    fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
-        // is_char_boundary checks that the index is in [0, .len()]
-        if self.is_char_boundary(mid) {
-            let len = self.len();
-            let ptr = self.as_ptr() as *mut u8;
-            unsafe {
-                (from_raw_parts_mut(ptr, mid),
-                 from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
-            }
-        } else {
-            slice_error_fail(self, 0, mid)
-        }
-    }
-
-    #[inline]
-    fn as_ptr(&self) -> *const u8 {
-        self as *const str as *const u8
-    }
-
-    #[inline]
-    fn len(&self) -> usize {
-        self.as_bytes().len()
-    }
-
-    #[inline]
-    fn is_empty(&self) -> bool { self.len() == 0 }
-
-    #[inline]
-    fn parse<T: FromStr>(&self) -> Result<T, T::Err> { FromStr::from_str(self) }
-
-    #[inline]
-    fn split_whitespace(&self) -> SplitWhitespace {
-        SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) }
-    }
-
-    #[inline]
-    fn trim(&self) -> &str {
-        self.trim_matches(|c: char| c.is_whitespace())
-    }
-
-    #[inline]
-    fn trim_left(&self) -> &str {
-        self.trim_left_matches(|c: char| c.is_whitespace())
-    }
-
-    #[inline]
-    fn trim_right(&self) -> &str {
-        self.trim_right_matches(|c: char| c.is_whitespace())
-    }
-}
-
-// FIXME: remove (inline) this macro and the SliceExt trait
-// when updating to a bootstrap compiler that has the new lang items.
-#[cfg_attr(stage0, macro_export)]
-#[unstable(feature = "core_str_ext", issue = "32110")]
-macro_rules! str_core_methods { () => {
+#[lang = "str"]
+#[cfg(not(test))]
+impl str {
     /// Returns the length of `self`.
     ///
     /// This length is in bytes, not [`char`]s or graphemes. In other words,
@@ -2577,7 +2167,7 @@ macro_rules! str_core_methods { () => {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn len(&self) -> usize {
-        StrExt::len(self)
+        self.as_bytes().len()
     }
 
     /// Returns `true` if `self` has a length of zero bytes.
@@ -2596,7 +2186,7 @@ pub fn len(&self) -> usize {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_empty(&self) -> bool {
-        StrExt::is_empty(self)
+        self.len() == 0
     }
 
     /// Checks that `index`-th byte lies at the start and/or end of a
@@ -2626,7 +2216,15 @@ pub fn is_empty(&self) -> bool {
     #[stable(feature = "is_char_boundary", since = "1.9.0")]
     #[inline]
     pub fn is_char_boundary(&self, index: usize) -> bool {
-        StrExt::is_char_boundary(self, index)
+        // 0 and len are always ok.
+        // Test for 0 explicitly so that it can optimize out the check
+        // easily and skip reading string data for that case.
+        if index == 0 || index == self.len() { return true; }
+        match self.as_bytes().get(index) {
+            None => false,
+            // This is bit magic equivalent to: b < 128 || b >= 192
+            Some(&b) => (b as i8) >= -0x40,
+        }
     }
 
     /// Converts a string slice to a byte slice. To convert the byte slice back
@@ -2645,7 +2243,7 @@ pub fn is_char_boundary(&self, index: usize) -> bool {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline(always)]
     pub fn as_bytes(&self) -> &[u8] {
-        StrExt::as_bytes(self)
+        unsafe { &*(self as *const str as *const [u8]) }
     }
 
     /// Converts a mutable string slice to a mutable byte slice. To convert the
@@ -2684,7 +2282,7 @@ pub fn as_bytes(&self) -> &[u8] {
     #[stable(feature = "str_mut_extras", since = "1.20.0")]
     #[inline(always)]
     pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
-        StrExt::as_bytes_mut(self)
+        &mut *(self as *mut str as *mut [u8])
     }
 
     /// Converts a string slice to a raw pointer.
@@ -2706,7 +2304,7 @@ pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn as_ptr(&self) -> *const u8 {
-        StrExt::as_ptr(self)
+        self as *const str as *const u8
     }
 
     /// Returns a subslice of `str`.
@@ -2733,7 +2331,7 @@ pub fn as_ptr(&self) -> *const u8 {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
-        StrExt::get(self, i)
+        i.get(self)
     }
 
     /// Returns a mutable subslice of `str`.
@@ -2767,7 +2365,7 @@ pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
-        StrExt::get_mut(self, i)
+        i.get_mut(self)
     }
 
     /// Returns a unchecked subslice of `str`.
@@ -2799,7 +2397,7 @@ pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
-        StrExt::get_unchecked(self, i)
+        i.get_unchecked(self)
     }
 
     /// Returns a mutable, unchecked subslice of `str`.
@@ -2831,7 +2429,7 @@ pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
     #[stable(feature = "str_checked_slicing", since = "1.20.0")]
     #[inline]
     pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
-        StrExt::get_unchecked_mut(self, i)
+        i.get_unchecked_mut(self)
     }
 
     /// Creates a string slice from another string slice, bypassing safety
@@ -2880,7 +2478,7 @@ pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
-        StrExt::slice_unchecked(self, begin, end)
+        (begin..end).get_unchecked(self)
     }
 
     /// Creates a string slice from another string slice, bypassing safety
@@ -2910,7 +2508,7 @@ pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
     #[stable(feature = "str_slice_mut", since = "1.5.0")]
     #[inline]
     pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
-        StrExt::slice_mut_unchecked(self, begin, end)
+        (begin..end).get_unchecked_mut(self)
     }
 
     /// Divide one string slice into two at an index.
@@ -2946,7 +2544,15 @@ pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut s
     #[inline]
     #[stable(feature = "str_split_at", since = "1.4.0")]
     pub fn split_at(&self, mid: usize) -> (&str, &str) {
-        StrExt::split_at(self, mid)
+        // is_char_boundary checks that the index is in [0, .len()]
+        if self.is_char_boundary(mid) {
+            unsafe {
+                (self.slice_unchecked(0, mid),
+                 self.slice_unchecked(mid, self.len()))
+            }
+        } else {
+            slice_error_fail(self, 0, mid)
+        }
     }
 
     /// Divide one mutable string slice into two at an index.
@@ -2983,7 +2589,17 @@ pub fn split_at(&self, mid: usize) -> (&str, &str) {
     #[inline]
     #[stable(feature = "str_split_at", since = "1.4.0")]
     pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
-        StrExt::split_at_mut(self, mid)
+        // is_char_boundary checks that the index is in [0, .len()]
+        if self.is_char_boundary(mid) {
+            let len = self.len();
+            let ptr = self.as_ptr() as *mut u8;
+            unsafe {
+                (from_raw_parts_mut(ptr, mid),
+                 from_raw_parts_mut(ptr.offset(mid as isize), len - mid))
+            }
+        } else {
+            slice_error_fail(self, 0, mid)
+        }
     }
 
     /// Returns an iterator over the [`char`]s of a string slice.
@@ -3035,8 +2651,9 @@ pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn chars(&self) -> Chars {
-        StrExt::chars(self)
+        Chars{iter: self.as_bytes().iter()}
     }
+
     /// Returns an iterator over the [`char`]s of a string slice, and their
     /// positions.
     ///
@@ -3091,7 +2708,7 @@ pub fn chars(&self) -> Chars {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn char_indices(&self) -> CharIndices {
-        StrExt::char_indices(self)
+        CharIndices { front_offset: 0, iter: self.chars() }
     }
 
     /// An iterator over the bytes of a string slice.
@@ -3116,7 +2733,7 @@ pub fn char_indices(&self) -> CharIndices {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn bytes(&self) -> Bytes {
-        StrExt::bytes(self)
+        Bytes(self.as_bytes().iter().cloned())
     }
 
     /// Split a string slice by whitespace.
@@ -3156,7 +2773,7 @@ pub fn bytes(&self) -> Bytes {
     #[stable(feature = "split_whitespace", since = "1.1.0")]
     #[inline]
     pub fn split_whitespace(&self) -> SplitWhitespace {
-        StrExt::split_whitespace(self)
+        SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) }
     }
 
     /// An iterator over the lines of a string, as string slices.
@@ -3198,7 +2815,7 @@ pub fn split_whitespace(&self) -> SplitWhitespace {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn lines(&self) -> Lines {
-        StrExt::lines(self)
+        Lines(self.split_terminator('\n').map(LinesAnyMap))
     }
 
     /// An iterator over the lines of a string.
@@ -3207,7 +2824,7 @@ pub fn lines(&self) -> Lines {
     #[inline]
     #[allow(deprecated)]
     pub fn lines_any(&self) -> LinesAny {
-        StrExt::lines_any(self)
+        LinesAny(self.lines())
     }
 
     /// Returns an iterator of `u16` over the string encoded as UTF-16.
@@ -3226,7 +2843,7 @@ pub fn lines_any(&self) -> LinesAny {
     /// ```
     #[stable(feature = "encode_utf16", since = "1.8.0")]
     pub fn encode_utf16(&self) -> EncodeUtf16 {
-        EncodeUtf16::new(self)
+        EncodeUtf16 { chars: self.chars(), extra: 0 }
     }
 
     /// Returns `true` if the given pattern matches a sub-slice of
@@ -3247,7 +2864,7 @@ pub fn encode_utf16(&self) -> EncodeUtf16 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
-        StrExt::contains(self, pat)
+        pat.is_contained_in(self)
     }
 
     /// Returns `true` if the given pattern matches a prefix of this
@@ -3267,7 +2884,7 @@ pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
-        StrExt::starts_with(self, pat)
+        pat.is_prefix_of(self)
     }
 
     /// Returns `true` if the given pattern matches a suffix of this
@@ -3289,7 +2906,7 @@ pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
     pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::ends_with(self, pat)
+        pat.is_suffix_of(self)
     }
 
     /// Returns the byte index of the first character of this string slice that
@@ -3337,7 +2954,7 @@ pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
-        StrExt::find(self, pat)
+        pat.into_searcher(self).next_match().map(|(i, _)| i)
     }
 
     /// Returns the byte index of the last character of this string slice that
@@ -3384,7 +3001,7 @@ pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
     pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rfind(self, pat)
+        pat.into_searcher(self).next_match_back().map(|(i, _)| i)
     }
 
     /// An iterator over substrings of this string slice, separated by
@@ -3496,7 +3113,13 @@ pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
-        StrExt::split(self, pat)
+        Split(SplitInternal {
+            start: 0,
+            end: self.len(),
+            matcher: pat.into_searcher(self),
+            allow_trailing_empty: true,
+            finished: false,
+        })
     }
 
     /// An iterator over substrings of the given string slice, separated by
@@ -3548,7 +3171,7 @@ pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
     pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rsplit(self, pat)
+        RSplit(self.split(pat).0)
     }
 
     /// An iterator over substrings of the given string slice, separated by
@@ -3593,7 +3216,10 @@ pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
-        StrExt::split_terminator(self, pat)
+        SplitTerminator(SplitInternal {
+            allow_trailing_empty: false,
+            ..self.split(pat).0
+        })
     }
 
     /// An iterator over substrings of `self`, separated by characters
@@ -3639,7 +3265,7 @@ pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator
     pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rsplit_terminator(self, pat)
+        RSplitTerminator(self.split_terminator(pat).0)
     }
 
     /// An iterator over substrings of the given string slice, separated by a
@@ -3690,7 +3316,10 @@ pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminat
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
-        StrExt::splitn(self, n, pat)
+        SplitN(SplitNInternal {
+            iter: self.split(pat).0,
+            count: n,
+        })
     }
 
     /// An iterator over substrings of this string slice, separated by a
@@ -3740,7 +3369,7 @@ pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
     pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rsplitn(self, n, pat)
+        RSplitN(self.splitn(n, pat).0)
     }
 
     /// An iterator over the disjoint matches of a pattern within the given string
@@ -3779,7 +3408,7 @@ pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
     #[stable(feature = "str_matches", since = "1.2.0")]
     #[inline]
     pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
-        StrExt::matches(self, pat)
+        Matches(MatchesInternal(pat.into_searcher(self)))
     }
 
     /// An iterator over the disjoint matches of a pattern within this string slice,
@@ -3818,7 +3447,7 @@ pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
     pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rmatches(self, pat)
+        RMatches(self.matches(pat).0)
     }
 
     /// An iterator over the disjoint matches of a pattern within this string
@@ -3862,7 +3491,7 @@ pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
     #[stable(feature = "str_match_indices", since = "1.5.0")]
     #[inline]
     pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
-        StrExt::match_indices(self, pat)
+        MatchIndices(MatchIndicesInternal(pat.into_searcher(self)))
     }
 
     /// An iterator over the disjoint matches of a pattern within `self`,
@@ -3907,7 +3536,7 @@ pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P
     pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::rmatch_indices(self, pat)
+        RMatchIndices(self.match_indices(pat).0)
     }
 
     /// Returns a string slice with leading and trailing whitespace removed.
@@ -3926,7 +3555,7 @@ pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a,
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn trim(&self) -> &str {
-        StrExt::trim(self)
+        self.trim_matches(|c: char| c.is_whitespace())
     }
 
     /// Returns a string slice with leading whitespace removed.
@@ -3962,7 +3591,7 @@ pub fn trim(&self) -> &str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn trim_left(&self) -> &str {
-        StrExt::trim_left(self)
+        self.trim_left_matches(|c: char| c.is_whitespace())
     }
 
     /// Returns a string slice with trailing whitespace removed.
@@ -3998,7 +3627,7 @@ pub fn trim_left(&self) -> &str {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn trim_right(&self) -> &str {
-        StrExt::trim_right(self)
+        self.trim_right_matches(|c: char| c.is_whitespace())
     }
 
     /// Returns a string slice with all prefixes and suffixes that match a
@@ -4030,7 +3659,21 @@ pub fn trim_right(&self) -> &str {
     pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
         where P::Searcher: DoubleEndedSearcher<'a>
     {
-        StrExt::trim_matches(self, pat)
+        let mut i = 0;
+        let mut j = 0;
+        let mut matcher = pat.into_searcher(self);
+        if let Some((a, b)) = matcher.next_reject() {
+            i = a;
+            j = b; // Remember earliest known match, correct it below if
+                   // last match is different
+        }
+        if let Some((_, b)) = matcher.next_reject_back() {
+            j = b;
+        }
+        unsafe {
+            // Searcher is known to return valid indices
+            self.slice_unchecked(i, j)
+        }
     }
 
     /// Returns a string slice with all prefixes that match a pattern
@@ -4061,7 +3704,15 @@ pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
-        StrExt::trim_left_matches(self, pat)
+        let mut i = self.len();
+        let mut matcher = pat.into_searcher(self);
+        if let Some((a, _)) = matcher.next_reject() {
+            i = a;
+        }
+        unsafe {
+            // Searcher is known to return valid indices
+            self.slice_unchecked(i, self.len())
+        }
     }
 
     /// Returns a string slice with all suffixes that match a pattern
@@ -4100,7 +3751,15 @@ pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
     pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
         where P::Searcher: ReverseSearcher<'a>
     {
-        StrExt::trim_right_matches(self, pat)
+        let mut j = 0;
+        let mut matcher = pat.into_searcher(self);
+        if let Some((_, b)) = matcher.next_reject_back() {
+            j = b;
+        }
+        unsafe {
+            // Searcher is known to return valid indices
+            self.slice_unchecked(0, j)
+        }
     }
 
     /// Parses this string slice into another type.
@@ -4150,7 +3809,7 @@ pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
-        StrExt::parse(self)
+        FromStr::from_str(self)
     }
 
     /// Checks if all characters in this string are within the ASCII range.
@@ -4220,16 +3879,8 @@ pub fn make_ascii_lowercase(&mut self) {
         let me = unsafe { self.as_bytes_mut() };
         me.make_ascii_lowercase()
     }
-}}
-
-#[lang = "str"]
-#[cfg(not(test))]
-#[cfg(not(stage0))]
-impl str {
-    str_core_methods!();
 }
 
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl AsRef<[u8]> for str {
     #[inline]
@@ -4332,17 +3983,6 @@ pub struct EncodeUtf16<'a> {
     extra: u16,
 }
 
-// FIXME: remove (inline) this method
-// when updating to a bootstrap compiler that has the new lang items.
-// For grepping purpose: #[cfg(stage0)]
-impl<'a> EncodeUtf16<'a> {
-    #[unstable(feature = "core_str_ext", issue = "32110")]
-    #[doc(hidden)]
-    pub fn new(s: &'a str) -> Self {
-        EncodeUtf16 { chars: s.chars(), extra: 0 }
-    }
-}
-
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<'a> fmt::Debug for EncodeUtf16<'a> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
index 7fb4b503c01efea48e8acc5e46bb5efc8c356486..13189d532aba1c92708cca8a32fb92f86e25b090 100644 (file)
@@ -41,9 +41,9 @@
 #![feature(try_from)]
 #![feature(try_trait)]
 #![feature(exact_chunks)]
-#![cfg_attr(stage0, feature(atomic_nand))]
+#![feature(slice_align_to)]
+#![feature(align_offset)]
 #![feature(reverse_bits)]
-#![feature(inclusive_range_methods)]
 #![feature(iterator_find_map)]
 #![feature(slice_internals)]
 
index 257f6ea20d4eab7aa12a87ab53874d44bbefc86c..ca6906f731047c62e0091c3a3212756cff2b5c23 100644 (file)
@@ -98,7 +98,6 @@ fn test_swap_bytes() {
     }
 
     #[test]
-    #[cfg(not(stage0))]
     fn test_reverse_bits() {
         assert_eq!(A.reverse_bits().reverse_bits(), A);
         assert_eq!(B.reverse_bits().reverse_bits(), B);
index 00f87336f3c80c863f2b3bdff684d429e9b50411..31bc1d677686a59c8ee11ffc92882dc0cb80d9e5 100644 (file)
@@ -296,3 +296,92 @@ fn drop(&mut self) {
     }
     DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
 }
+
+#[test]
+fn align_offset_zst() {
+    // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
+    // all, because no amount of elements will align the pointer.
+    let mut p = 1;
+    while p < 1024 {
+        assert_eq!((p as *const ()).align_offset(p), 0);
+        if p != 1 {
+            assert_eq!(((p + 1) as *const ()).align_offset(p), !0);
+        }
+        p = (p + 1).next_power_of_two();
+    }
+}
+
+#[test]
+fn align_offset_stride1() {
+    // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
+    // number of bytes.
+    let mut align = 1;
+    while align < 1024 {
+        for ptr in 1..2*align {
+            let expected = ptr % align;
+            let offset = if expected == 0 { 0 } else { align - expected };
+            assert_eq!((ptr as *const u8).align_offset(align), offset,
+            "ptr = {}, align = {}, size = 1", ptr, align);
+        }
+        align = (align + 1).next_power_of_two();
+    }
+}
+
+#[test]
+fn align_offset_weird_strides() {
+    #[repr(packed)]
+    struct A3(u16, u8);
+    struct A4(u32);
+    #[repr(packed)]
+    struct A5(u32, u8);
+    #[repr(packed)]
+    struct A6(u32, u16);
+    #[repr(packed)]
+    struct A7(u32, u16, u8);
+    #[repr(packed)]
+    struct A8(u32, u32);
+    #[repr(packed)]
+    struct A9(u32, u32, u8);
+    #[repr(packed)]
+    struct A10(u32, u32, u16);
+
+    unsafe fn test_weird_stride<T>(ptr: *const T, align: usize) -> bool {
+        let numptr = ptr as usize;
+        let mut expected = usize::max_value();
+        // Naive but definitely correct way to find the *first* aligned element of stride::<T>.
+        for el in 0..align {
+            if (numptr + el * ::std::mem::size_of::<T>()) % align == 0 {
+                expected = el;
+                break;
+            }
+        }
+        let got = ptr.align_offset(align);
+        if got != expected {
+            eprintln!("aligning {:p} (with stride of {}) to {}, expected {}, got {}", ptr,
+                      ::std::mem::size_of::<T>(), align, expected, got);
+            return true;
+        }
+        return false;
+    }
+
+    // For pointers of stride != 1, we verify the algorithm against the naivest possible
+    // implementation
+    let mut align = 1;
+    let mut x = false;
+    while align < 1024 {
+        for ptr in 1usize..4*align {
+            unsafe {
+                x |= test_weird_stride::<A3>(ptr as *const A3, align);
+                x |= test_weird_stride::<A4>(ptr as *const A4, align);
+                x |= test_weird_stride::<A5>(ptr as *const A5, align);
+                x |= test_weird_stride::<A6>(ptr as *const A6, align);
+                x |= test_weird_stride::<A7>(ptr as *const A7, align);
+                x |= test_weird_stride::<A8>(ptr as *const A8, align);
+                x |= test_weird_stride::<A9>(ptr as *const A9, align);
+                x |= test_weird_stride::<A10>(ptr as *const A10, align);
+            }
+        }
+        align = (align + 1).next_power_of_two();
+    }
+    assert!(!x);
+}
index 19b5c86c4740627b90b953dfb4c51801a690f997..fcd79222e1699882aee57f3f54528967dbbb646e 100644 (file)
@@ -812,3 +812,37 @@ fn each_alignment_reversed() {
         }
     }
 }
+
+#[test]
+fn test_align_to_simple() {
+    let bytes = [1u8, 2, 3, 4, 5, 6, 7];
+    let (prefix, aligned, suffix) = unsafe { bytes.align_to::<u16>() };
+    assert_eq!(aligned.len(), 3);
+    assert!(prefix == [1] || suffix == [7]);
+    let expect1 = [1 << 8 | 2, 3 << 8 | 4, 5 << 8 | 6];
+    let expect2 = [1 | 2 << 8, 3 | 4 << 8, 5 | 6 << 8];
+    let expect3 = [2 << 8 | 3, 4 << 8 | 5, 6 << 8 | 7];
+    let expect4 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8];
+    assert!(aligned == expect1 || aligned == expect2 || aligned == expect3 || aligned == expect4,
+            "aligned={:?} expected={:?} || {:?} || {:?} || {:?}",
+            aligned, expect1, expect2, expect3, expect4);
+}
+
+#[test]
+fn test_align_to_zst() {
+    let bytes = [1, 2, 3, 4, 5, 6, 7];
+    let (prefix, aligned, suffix) = unsafe { bytes.align_to::<()>() };
+    assert_eq!(aligned.len(), 0);
+    assert!(prefix == [1, 2, 3, 4, 5, 6, 7] || suffix == [1, 2, 3, 4, 5, 6, 7]);
+}
+
+#[test]
+fn test_align_to_non_trivial() {
+    #[repr(align(8))] struct U64(u64, u64);
+    #[repr(align(8))] struct U64U64U32(u64, u64, u32);
+    let data = [U64(1, 2), U64(3, 4), U64(5, 6), U64(7, 8), U64(9, 10), U64(11, 12), U64(13, 14),
+                U64(15, 16)];
+    let (prefix, aligned, suffix) = unsafe { data.align_to::<U64U64U32>() };
+    assert_eq!(aligned.len(), 4);
+    assert_eq!(prefix.len() + suffix.len(), 2);
+}
index a551b1b770a68f1b7fa90cdfdf9f20812e6c86da..a77751d65d08c3c7f164526688356acd35fd82ce 100644 (file)
@@ -127,6 +127,14 @@ pub enum Count<'a> {
     CountImplied,
 }
 
+pub struct ParseError {
+    pub description: string::String,
+    pub note: Option<string::String>,
+    pub label: string::String,
+    pub start: usize,
+    pub end: usize,
+}
+
 /// The parser structure for interpreting the input format string. This is
 /// modeled as an iterator over `Piece` structures to form a stream of tokens
 /// being output.
@@ -137,7 +145,7 @@ pub struct Parser<'a> {
     input: &'a str,
     cur: iter::Peekable<str::CharIndices<'a>>,
     /// Error messages accumulated during parsing
-    pub errors: Vec<(string::String, Option<string::String>)>,
+    pub errors: Vec<ParseError>,
     /// Current position of implicit positional argument pointer
     curarg: usize,
 }
@@ -160,12 +168,17 @@ fn next(&mut self) -> Option<Piece<'a>> {
                 }
                 '}' => {
                     self.cur.next();
+                    let pos = pos + 1;
                     if self.consume('}') {
-                        Some(String(self.string(pos + 1)))
+                        Some(String(self.string(pos)))
                     } else {
-                        self.err_with_note("unmatched `}` found",
-                                           "if you intended to print `}`, \
-                                           you can escape it using `}}`");
+                        self.err_with_note(
+                            "unmatched `}` found",
+                            "unmatched `}`",
+                            "if you intended to print `}`, you can escape it using `}}`",
+                            pos,
+                            pos,
+                        );
                         None
                     }
                 }
@@ -191,15 +204,40 @@ pub fn new(s: &'a str) -> Parser<'a> {
     /// Notifies of an error. The message doesn't actually need to be of type
     /// String, but I think it does when this eventually uses conditions so it
     /// might as well start using it now.
-    fn err(&mut self, msg: &str) {
-        self.errors.push((msg.to_owned(), None));
+    fn err<S1: Into<string::String>, S2: Into<string::String>>(
+        &mut self,
+        description: S1,
+        label: S2,
+        start: usize,
+        end: usize,
+    ) {
+        self.errors.push(ParseError {
+            description: description.into(),
+            note: None,
+            label: label.into(),
+            start,
+            end,
+        });
     }
 
     /// Notifies of an error. The message doesn't actually need to be of type
     /// String, but I think it does when this eventually uses conditions so it
     /// might as well start using it now.
-    fn err_with_note(&mut self, msg: &str, note: &str) {
-        self.errors.push((msg.to_owned(), Some(note.to_owned())));
+    fn err_with_note<S1: Into<string::String>, S2: Into<string::String>, S3: Into<string::String>>(
+        &mut self,
+        description: S1,
+        label: S2,
+        note: S3,
+        start: usize,
+        end: usize,
+    ) {
+        self.errors.push(ParseError {
+            description: description.into(),
+            note: Some(note.into()),
+            label: label.into(),
+            start,
+            end,
+        });
     }
 
     /// Optionally consumes the specified character. If the character is not at
@@ -222,19 +260,26 @@ fn consume(&mut self, c: char) -> bool {
     /// found, an error is emitted.
     fn must_consume(&mut self, c: char) {
         self.ws();
-        if let Some(&(_, maybe)) = self.cur.peek() {
+        if let Some(&(pos, maybe)) = self.cur.peek() {
             if c == maybe {
                 self.cur.next();
             } else {
-                self.err(&format!("expected `{:?}`, found `{:?}`", c, maybe));
+                self.err(format!("expected `{:?}`, found `{:?}`", c, maybe),
+                         format!("expected `{}`", c),
+                         pos + 1,
+                         pos + 1);
             }
         } else {
-            let msg = &format!("expected `{:?}` but string was terminated", c);
+            let msg = format!("expected `{:?}` but string was terminated", c);
+            let pos = self.input.len() + 1; // point at closing `"`
             if c == '}' {
                 self.err_with_note(msg,
-                                   "if you intended to print `{`, you can escape it using `{{`");
+                                   format!("expected `{:?}`", c),
+                                   "if you intended to print `{`, you can escape it using `{{`",
+                                   pos,
+                                   pos);
             } else {
-                self.err(msg);
+                self.err(msg, format!("expected `{:?}`", c), pos, pos);
             }
         }
     }
@@ -300,6 +345,15 @@ fn position(&mut self) -> Option<Position<'a>> {
         } else {
             match self.cur.peek() {
                 Some(&(_, c)) if c.is_alphabetic() => Some(ArgumentNamed(self.word())),
+                Some(&(pos, c)) if c == '_' => {
+                    let invalid_name = self.string(pos);
+                    self.err_with_note(format!("invalid argument name `{}`", invalid_name),
+                                       "invalid argument name",
+                                       "argument names cannot start with an underscore",
+                                       pos + 1, // add 1 to account for leading `{`
+                                       pos + 1 + invalid_name.len());
+                    Some(ArgumentNamed(invalid_name))
+                },
 
                 // This is an `ArgumentNext`.
                 // Record the fact and do the resolution after parsing the
index 610a9a2a39486580743152b98967c55d6061ccba..bcab61680965afc3aa1b381216e5ac4d1aebaf30 100644 (file)
@@ -818,7 +818,7 @@ pub fn new(string: &str, span: Span) -> Ident {
     pub fn new_raw(string: &str, span: Span) -> Ident {
         let mut ident = Ident::new(string, span);
         if ident.sym == keywords::Underscore.name() ||
-           token::is_path_segment_keyword(ast::Ident::with_empty_ctxt(ident.sym)) {
+           ast::Ident::with_empty_ctxt(ident.sym).is_path_segment_keyword() {
             panic!("`{:?}` is not a valid raw identifier", string)
         }
         ident.is_raw = true;
index 0f4871954d669bbe231ba9cdf6344381d8701f62..45d429612a1dbd4723060010dec29c2905018ad3 100644 (file)
@@ -593,6 +593,7 @@ fn allow_internal_unstable(&self, reason: CompilerDesugaringKind, span: Span) ->
                 span: Some(span),
                 allow_internal_unstable: true,
                 allow_internal_unsafe: false,
+                edition: codemap::hygiene::default_edition(),
             },
         });
         span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
index 9cd9e0dce54e35d487d2d1fe2db8cde85f4607fe..940a68e8ce5ca7f6c7d6b9c81520e012d383ec0b 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_target::spec::abi::Abi;
 use syntax::ast;
 use syntax::codemap::{CodeMap, Spanned};
-use syntax::parse::{token, ParseSess};
+use syntax::parse::ParseSess;
 use syntax::parse::lexer::comments;
 use syntax::print::pp::{self, Breaks};
 use syntax::print::pp::Breaks::{Consistent, Inconsistent};
@@ -1559,7 +1559,7 @@ pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
     }
 
     pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
-        if token::is_raw_guess(ast::Ident::with_empty_ctxt(name)) {
+        if name.to_ident().is_raw_guess() {
             self.s.word(&format!("r#{}", name))?;
         } else {
             self.s.word(&name.as_str())?;
index f56d701b028794fc629569d6529896db43eab697..3a37c1c18c8d9fcd976e55d5bfe5958712f99cd3 100644 (file)
@@ -131,6 +131,15 @@ fn to_stable_hash_key(&self,
     rustc_const_unstable
 });
 
+impl<'a> HashStable<StableHashingContext<'a>>
+for ::syntax::edition::Edition {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+    }
+}
+
 impl<'a> HashStable<StableHashingContext<'a>>
 for ::syntax::attr::StabilityLevel {
     fn hash_stable<W: StableHasherResult>(&self,
@@ -389,6 +398,7 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>(
     format,
     allow_internal_unstable,
     allow_internal_unsafe,
+    edition,
     span
 });
 
index ac6ff6831adb804ceb61a80d6a0cbf16abfb13d3..1d53a305193fae50cb8e05d735b4985076ce3fd9 100644 (file)
@@ -46,7 +46,6 @@
 #![feature(core_intrinsics)]
 #![feature(drain_filter)]
 #![feature(entry_or_default)]
-#![cfg_attr(stage0, feature(dyn_trait))]
 #![feature(from_ref)]
 #![feature(fs_read_write)]
 #![feature(iterator_find_map)]
@@ -69,7 +68,6 @@
 #![feature(trusted_len)]
 #![feature(catch_expr)]
 #![feature(test)]
-#![feature(inclusive_range_methods)]
 
 #![recursion_limit="512"]
 
index 5ebea52f3c5ad9a8e2d09ab6076554c0de27821f..c55c71f85dab78582fd0c433c28d74846a96bcc3 100644 (file)
@@ -27,7 +27,7 @@
 
 declare_lint! {
     pub CONST_ERR,
-    Warn,
+    Deny,
     "constant evaluation detected erroneous expression"
 }
 
index 61c8470b616f833f2284fede138d1002232b44c2..518021f412574dcb73c849f370f31f0a2181a9a3 100644 (file)
@@ -34,6 +34,7 @@
 use std::any::Any;
 use std::path::{Path, PathBuf};
 use syntax::ast;
+use syntax::edition::Edition;
 use syntax::ext::base::SyntaxExtension;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
@@ -235,6 +236,7 @@ pub trait CrateStore {
     fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
     fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
     fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
+    fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition;
     fn struct_field_names_untracked(&self, def: DefId) -> Vec<ast::Name>;
     fn item_children_untracked(&self, did: DefId, sess: &Session) -> Vec<def::Export>;
     fn load_macro_untracked(&self, did: DefId, sess: &Session) -> LoadedMacro;
@@ -309,6 +311,7 @@ fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator {
         bug!("crate_disambiguator")
     }
     fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh { bug!("crate_hash") }
+    fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition { bug!("crate_edition_untracked") }
 
     // resolve
     fn def_key(&self, def: DefId) -> DefKey { bug!("def_key") }
index 95e92e21b09dcdd50129bad5151257cbe62bb725..d70f994e87ba7f878cf3cc208ee4117759b7fa09 100644 (file)
@@ -348,6 +348,9 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
     I128ShroFnLangItem,              "i128_shro",               i128_shro_fn;
     U128ShroFnLangItem,              "u128_shro",               u128_shro_fn;
 
+    // Align offset for stride != 1, must not panic.
+    AlignOffsetLangItem,             "align_offset",            align_offset_fn;
+
     TerminationTraitLangItem,        "termination",             termination;
 }
 
index 71d7abed6c95a8e1359787a8ce350afd030aefda..42a08afe305a5acfff45baeb68996b42612414ce 100644 (file)
@@ -542,18 +542,6 @@ fn record_closure_parent(&mut self,
         assert!(previous.is_none());
     }
 
-    fn closure_is_enclosed_by(&self,
-                              mut sub_closure: hir::ItemLocalId,
-                              sup_closure: hir::ItemLocalId) -> bool {
-        loop {
-            if sub_closure == sup_closure { return true; }
-            match self.closure_tree.get(&sub_closure) {
-                Some(&s) => { sub_closure = s; }
-                None => { return false; }
-            }
-        }
-    }
-
     fn record_var_scope(&mut self, var: hir::ItemLocalId, lifetime: Scope) {
         debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
         assert!(var != lifetime.item_local_id());
@@ -688,65 +676,37 @@ pub fn nearest_common_ancestor(&self,
         // requires a hash table lookup, and we often have very long scope
         // chains (10s or 100s of scopes) that only differ by a few elements at
         // the start. So this algorithm is faster.
-        let mut ma = Some(scope_a);
-        let mut mb = Some(scope_b);
-        let mut seen_a: SmallVec<[Scope; 32]> = SmallVec::new();
-        let mut seen_b: SmallVec<[Scope; 32]> = SmallVec::new();
+
+        let mut ma = Some(&scope_a);
+        let mut mb = Some(&scope_b);
+
+        // A HashSet<Scope> is a more obvious choice for these, but SmallVec is
+        // faster because the set size is normally small so linear search is
+        // as good or better than a hash table lookup, plus the size is usually
+        // small enough to avoid a heap allocation.
+        let mut seen_a: SmallVec<[&Scope; 32]> = SmallVec::new();
+        let mut seen_b: SmallVec<[&Scope; 32]> = SmallVec::new();
+
         loop {
             if let Some(a) = ma {
-                if seen_b.iter().position(|s| *s == a).is_some() {
-                    return a;
+                if seen_b.iter().any(|s| *s == a) {
+                    return *a;
                 }
                 seen_a.push(a);
-                ma = self.parent_map.get(&a).map(|s| *s);
+                ma = self.parent_map.get(&a);
             }
 
             if let Some(b) = mb {
-                if seen_a.iter().position(|s| *s == b).is_some() {
-                    return b;
+                if seen_a.iter().any(|s| *s == b) {
+                    return *b;
                 }
                 seen_b.push(b);
-                mb = self.parent_map.get(&b).map(|s| *s);
+                mb = self.parent_map.get(&b);
             }
 
             if ma.is_none() && mb.is_none() {
-                break;
-            }
-        };
-
-        fn outermost_scope(parent_map: &FxHashMap<Scope, Scope>, scope: Scope) -> Scope {
-            let mut scope = scope;
-            loop {
-               match parent_map.get(&scope) {
-                   Some(&superscope) => scope = superscope,
-                   None => break scope,
-               }
-            }
-        }
-
-        // In this (rare) case, the two regions belong to completely different
-        // functions. Compare those fn for lexical nesting. The reasoning
-        // behind this is subtle. See the "Modeling closures" section of the
-        // README in infer::region_constraints for more details.
-        let a_root_scope = outermost_scope(&self.parent_map, scope_a);
-        let b_root_scope = outermost_scope(&self.parent_map, scope_b);
-        match (a_root_scope.data(), b_root_scope.data()) {
-            (ScopeData::Destruction(a_root_id),
-             ScopeData::Destruction(b_root_id)) => {
-                if self.closure_is_enclosed_by(a_root_id, b_root_id) {
-                    // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
-                    scope_b
-                } else if self.closure_is_enclosed_by(b_root_id, a_root_id) {
-                    // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b`
-                    scope_a
-                } else {
-                    // neither fn encloses the other
-                    bug!()
-                }
-            }
-            _ => {
-                // root ids are always Node right now
-                bug!()
+                // No nearest common ancestor found.
+                bug!();
             }
         }
     }
index e4520bce68199a5ea233cc1053ffc2a4ead7464b..97ce730c59ec508f76e16a0c824529207e2270d0 100644 (file)
@@ -203,17 +203,19 @@ fn report_projection_error(&self,
                     obligation.cause.span,
                     infer::LateBoundRegionConversionTime::HigherRankedType,
                     data);
-                let normalized = super::normalize_projection_type(
+                let mut obligations = vec![];
+                let normalized_ty = super::normalize_projection_type(
                     &mut selcx,
                     obligation.param_env,
                     data.projection_ty,
                     obligation.cause.clone(),
-                    0
+                    0,
+                    &mut obligations
                 );
                 if let Err(error) = self.at(&obligation.cause, obligation.param_env)
-                                        .eq(normalized.value, data.ty) {
+                                        .eq(normalized_ty, data.ty) {
                     values = Some(infer::ValuePairs::Types(ExpectedFound {
-                        expected: normalized.value,
+                        expected: normalized_ty,
                         found: data.ty,
                     }));
                     err_buf = error;
index 94ee39470772fe7165cb5f803d3da602aedf38a1..4447a2b6ed14081086f05b13cf1adfea05674f08 100644 (file)
@@ -161,19 +161,18 @@ fn normalize_projection_type<'a, 'gcx>(&mut self,
         // FIXME(#20304) -- cache
 
         let mut selcx = SelectionContext::new(infcx);
-        let normalized = project::normalize_projection_type(&mut selcx,
-                                                            param_env,
-                                                            projection_ty,
-                                                            cause,
-                                                            0);
-
-        for obligation in normalized.obligations {
-            self.register_predicate_obligation(infcx, obligation);
-        }
-
-        debug!("normalize_projection_type: result={:?}", normalized.value);
-
-        normalized.value
+        let mut obligations = vec![];
+        let normalized_ty = project::normalize_projection_type(&mut selcx,
+                                                               param_env,
+                                                               projection_ty,
+                                                               cause,
+                                                               0,
+                                                               &mut obligations);
+        self.register_predicate_obligations(infcx, obligations);
+
+        debug!("normalize_projection_type: result={:?}", normalized_ty);
+
+        normalized_ty
     }
 
     /// Requires that `ty` must implement the trait with `def_id` in
index 270e06a872bcb0b15e025e060fbf328dd4b6e726..174c35d1d69bfc5bc25b4ec5e9db82c90fd3c9d6 100644 (file)
@@ -225,12 +225,14 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
     debug!("project_and_unify_type(obligation={:?})",
            obligation);
 
-    let Normalized { value: normalized_ty, mut obligations } =
+    let mut obligations = vec![];
+    let normalized_ty =
         match opt_normalize_projection_type(selcx,
                                             obligation.param_env,
                                             obligation.predicate.projection_ty,
                                             obligation.cause.clone(),
-                                            obligation.recursion_depth) {
+                                            obligation.recursion_depth,
+                                            &mut obligations) {
             Some(n) => n,
             None => return Ok(None),
         };
@@ -386,16 +388,15 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 // binder). It would be better to normalize in a
                 // binding-aware fashion.
 
-                let Normalized { value: normalized_ty, obligations } =
-                    normalize_projection_type(self.selcx,
-                                              self.param_env,
-                                              data.clone(),
-                                              self.cause.clone(),
-                                              self.depth);
-                debug!("AssociatedTypeNormalizer: depth={} normalized {:?} to {:?} \
-                        with {} add'l obligations",
-                       self.depth, ty, normalized_ty, obligations.len());
-                self.obligations.extend(obligations);
+                let normalized_ty = normalize_projection_type(self.selcx,
+                                                              self.param_env,
+                                                              data.clone(),
+                                                              self.cause.clone(),
+                                                              self.depth,
+                                                              &mut self.obligations);
+                debug!("AssociatedTypeNormalizer: depth={} normalized {:?} to {:?}, \
+                        now with {} obligations",
+                       self.depth, ty, normalized_ty, self.obligations.len());
                 normalized_ty
             }
 
@@ -471,10 +472,12 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     projection_ty: ty::ProjectionTy<'tcx>,
     cause: ObligationCause<'tcx>,
-    depth: usize)
-    -> NormalizedTy<'tcx>
+    depth: usize,
+    obligations: &mut Vec<PredicateObligation<'tcx>>)
+    -> Ty<'tcx>
 {
-    opt_normalize_projection_type(selcx, param_env, projection_ty.clone(), cause.clone(), depth)
+    opt_normalize_projection_type(selcx, param_env, projection_ty.clone(), cause.clone(), depth,
+                                  obligations)
         .unwrap_or_else(move || {
             // if we bottom out in ambiguity, create a type variable
             // and a deferred predicate to resolve this when more type
@@ -490,10 +493,8 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             });
             let obligation = Obligation::with_depth(
                 cause, depth + 1, param_env, projection.to_predicate());
-            Normalized {
-                value: ty_var,
-                obligations: vec![obligation]
-            }
+            obligations.push(obligation);
+            ty_var
         })
 }
 
@@ -501,13 +502,20 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
 /// as Trait>::Item`. The result is always a type (and possibly
 /// additional obligations). Returns `None` in the case of ambiguity,
 /// which indicates that there are unbound type variables.
+///
+/// This function used to return `Option<NormalizedTy<'tcx>>`, which contains a
+/// `Ty<'tcx>` and an obligations vector. But that obligation vector was very
+/// often immediately appended to another obligations vector. So now this
+/// function takes an obligations vector and appends to it directly, which is
+/// slightly uglier but avoids the need for an extra short-lived allocation.
 fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
     selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     projection_ty: ty::ProjectionTy<'tcx>,
     cause: ObligationCause<'tcx>,
-    depth: usize)
-    -> Option<NormalizedTy<'tcx>>
+    depth: usize,
+    obligations: &mut Vec<PredicateObligation<'tcx>>)
+    -> Option<Ty<'tcx>>
 {
     let infcx = selcx.infcx();
 
@@ -579,7 +587,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                                                     projection_ty);
             selcx.infcx().report_overflow_error(&obligation, false);
         }
-        Err(ProjectionCacheEntry::NormalizedTy(mut ty)) => {
+        Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
+            // This is the hottest path in this function.
+            //
             // If we find the value in the cache, then return it along
             // with the obligations that went along with it. Note
             // that, when using a fulfillment context, these
@@ -596,29 +606,32 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             // Once we have inferred everything we need to know, we
             // can ignore the `obligations` from that point on.
             if !infcx.any_unresolved_type_vars(&ty.value) {
-                infcx.projection_cache.borrow_mut().complete(cache_key);
-                ty.obligations = vec![];
+                infcx.projection_cache.borrow_mut().complete_normalized(cache_key, &ty);
+                // No need to extend `obligations`.
+            } else {
+                obligations.extend(ty.obligations);
             }
 
-            push_paranoid_cache_value_obligation(infcx,
-                                                 param_env,
-                                                 projection_ty,
-                                                 cause,
-                                                 depth,
-                                                 &mut ty);
-
-            return Some(ty);
+            obligations.push(get_paranoid_cache_value_obligation(infcx,
+                                                                 param_env,
+                                                                 projection_ty,
+                                                                 cause,
+                                                                 depth));
+            return Some(ty.value);
         }
         Err(ProjectionCacheEntry::Error) => {
             debug!("opt_normalize_projection_type: \
                     found error");
-            return Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth));
+            let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
+            obligations.extend(result.obligations);
+            return Some(result.value)
         }
     }
 
     let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
     match project_type(selcx, &obligation) {
-        Ok(ProjectedTy::Progress(Progress { ty: projected_ty, mut obligations })) => {
+        Ok(ProjectedTy::Progress(Progress { ty: projected_ty,
+                                            obligations: mut projected_obligations })) => {
             // if projection succeeded, then what we get out of this
             // is also non-normalized (consider: it was derived from
             // an impl, where-clause etc) and hence we must
@@ -627,10 +640,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             debug!("opt_normalize_projection_type: \
                     projected_ty={:?} \
                     depth={} \
-                    obligations={:?}",
+                    projected_obligations={:?}",
                    projected_ty,
                    depth,
-                   obligations);
+                   projected_obligations);
 
             let result = if projected_ty.has_projections() {
                 let mut normalizer = AssociatedTypeNormalizer::new(selcx,
@@ -644,22 +657,22 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                        normalized_ty,
                        depth);
 
-                obligations.extend(normalizer.obligations);
+                projected_obligations.extend(normalizer.obligations);
                 Normalized {
                     value: normalized_ty,
-                    obligations,
+                    obligations: projected_obligations,
                 }
             } else {
                 Normalized {
                     value: projected_ty,
-                    obligations,
+                    obligations: projected_obligations,
                 }
             };
 
             let cache_value = prune_cache_value_obligations(infcx, &result);
             infcx.projection_cache.borrow_mut().insert_ty(cache_key, cache_value);
-
-            Some(result)
+            obligations.extend(result.obligations);
+            Some(result.value)
         }
         Ok(ProjectedTy::NoProgress(projected_ty)) => {
             debug!("opt_normalize_projection_type: \
@@ -670,7 +683,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                 obligations: vec![]
             };
             infcx.projection_cache.borrow_mut().insert_ty(cache_key, result.clone());
-            Some(result)
+            // No need to extend `obligations`.
+            Some(result.value)
         }
         Err(ProjectionTyError::TooManyCandidates) => {
             debug!("opt_normalize_projection_type: \
@@ -688,7 +702,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
 
             infcx.projection_cache.borrow_mut()
                                   .error(cache_key);
-            Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth))
+            let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
+            obligations.extend(result.obligations);
+            Some(result.value)
         }
     }
 }
@@ -737,7 +753,7 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx,
 /// may or may not be necessary -- in principle, all the obligations
 /// that must be proven to show that `T: Trait` were also returned
 /// when the cache was first populated. But there are some vague concerns,
-/// and so we take the precatuionary measure of including `T: Trait` in
+/// and so we take the precautionary measure of including `T: Trait` in
 /// the result:
 ///
 /// Concern #1. The current setup is fragile. Perhaps someone could
@@ -754,19 +770,21 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx,
 /// that may yet turn out to be wrong.  This *may* lead to some sort
 /// of trouble, though we don't have a concrete example of how that
 /// can occur yet.  But it seems risky at best.
-fn push_paranoid_cache_value_obligation<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
-                                                        param_env: ty::ParamEnv<'tcx>,
-                                                        projection_ty: ty::ProjectionTy<'tcx>,
-                                                        cause: ObligationCause<'tcx>,
-                                                        depth: usize,
-                                                        result: &mut NormalizedTy<'tcx>)
+fn get_paranoid_cache_value_obligation<'a, 'gcx, 'tcx>(
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    projection_ty: ty::ProjectionTy<'tcx>,
+    cause: ObligationCause<'tcx>,
+    depth: usize)
+    -> PredicateObligation<'tcx>
 {
     let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref();
-    let trait_obligation = Obligation { cause,
-                                        recursion_depth: depth,
-                                        param_env,
-                                        predicate: trait_ref.to_predicate() };
-    result.obligations.push(trait_obligation);
+    Obligation {
+        cause,
+        recursion_depth: depth,
+        param_env,
+        predicate: trait_ref.to_predicate(),
+    }
 }
 
 /// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
@@ -1682,6 +1700,23 @@ pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) {
         }));
     }
 
+    /// A specialized version of `complete` for when the key's value is known
+    /// to be a NormalizedTy.
+    pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) {
+        // We want to insert `ty` with no obligations. If the existing value
+        // already has no obligations (as is common) we can use `insert_noop`
+        // to do a minimal amount of work -- the HashMap insertion is skipped,
+        // and minimal changes are made to the undo log.
+        if ty.obligations.is_empty() {
+            self.map.insert_noop();
+        } else {
+            self.map.insert(key, ProjectionCacheEntry::NormalizedTy(Normalized {
+                value: ty.value,
+                obligations: vec![]
+            }));
+        }
+    }
+
     /// Indicates that trying to normalize `key` resulted in
     /// ambiguity. No point in trying it again then until we gain more
     /// type information (in which case, the "fully resolved" key will
index de8814d3d6a73244721a3f50eb2db355f603b28f..497d5fdcac70288b94d5f92df52692676537506d 100644 (file)
@@ -21,7 +21,7 @@
 use syntax::ext::base::Resolver;
 use syntax::ext::build::AstBuilder;
 use syntax::ext::expand::ExpansionConfig;
-use syntax::ext::hygiene::{Mark, SyntaxContext};
+use syntax::ext::hygiene::{self, Mark, SyntaxContext};
 use syntax::fold::{self, Folder};
 use syntax::parse::ParseSess;
 use syntax::ptr::P;
@@ -86,6 +86,7 @@ fn fold_item(&mut self, item: P<Item>) -> SmallVector<P<Item>> {
                 span: None,
                 allow_internal_unstable: true,
                 allow_internal_unsafe: false,
+                edition: hygiene::default_edition(),
             },
         });
         let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
index ba04cc7fad5e96806056ec17a4f402f31207f4c0..cffe7f79e970c91e44eb93817b8bd19050f88172 100644 (file)
@@ -389,18 +389,6 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
             args[0].deref(bx.cx).codegen_get_discr(bx, ret_ty)
         }
 
-        "align_offset" => {
-            // `ptr as usize`
-            let ptr_val = bx.ptrtoint(args[0].immediate(), bx.cx.isize_ty);
-            // `ptr_val % align`
-            let align = args[1].immediate();
-            let offset = bx.urem(ptr_val, align);
-            let zero = C_null(bx.cx.isize_ty);
-            // `offset == 0`
-            let is_zero = bx.icmp(llvm::IntPredicate::IntEQ, offset, zero);
-            // `if offset == 0 { 0 } else { align - offset }`
-            bx.select(is_zero, zero, bx.sub(align, offset))
-        }
         name if name.starts_with("simd_") => {
             match generic_simd_intrinsic(bx, name,
                                          callee_ty,
index bd053da4bd3034ddade089159bc57511c6d8d794..0b0bab96dfdfd94f018ed1c22088046305524a13 100644 (file)
@@ -29,7 +29,6 @@
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_sort_by_cached_key)]
 #![feature(optin_builtin_traits)]
-#![feature(inclusive_range_methods)]
 
 use rustc::dep_graph::WorkProduct;
 use syntax_pos::symbol::Symbol;
index 28e3180063c170d83a497e4d0307e5d1bbd8c72d..a22dd1fececea5024fe76d917ad85c20d249f425 100644 (file)
@@ -8,11 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::collections::BTreeMap;
+use indexed_vec::{Idx, IndexVec};
 use std::collections::btree_map::Entry;
-use std::marker::PhantomData;
+use std::collections::BTreeMap;
 use std::iter::FromIterator;
-use indexed_vec::{Idx, IndexVec};
+use std::marker::PhantomData;
 
 type Word = u128;
 const WORD_BITS: usize = 128;
@@ -317,14 +317,25 @@ pub fn merge(&mut self, read: R, write: R) -> bool {
         if read != write {
             let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write);
 
-            for read_val in bit_set_read.iter() {
-                changed = changed | bit_set_write.insert(read_val);
+            for read_chunk in bit_set_read.chunks() {
+                changed = changed | bit_set_write.insert_chunk(read_chunk).any();
             }
         }
 
         changed
     }
 
+    /// True if `sub` is a subset of `sup`
+    pub fn is_subset(&self, sub: R, sup: R) -> bool {
+        sub == sup || {
+            let bit_set_sub = &self.vector[sub];
+            let bit_set_sup = &self.vector[sup];
+            bit_set_sub
+                .chunks()
+                .all(|read_chunk| read_chunk.bits_eq(bit_set_sup.contains_chunk(read_chunk)))
+        }
+    }
+
     /// Iterates through all the columns set to true in a given row of
     /// the matrix.
     pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
@@ -346,6 +357,7 @@ pub struct SparseChunk<I> {
 }
 
 impl<I: Idx> SparseChunk<I> {
+    #[inline]
     pub fn one(index: I) -> Self {
         let index = index.index();
         let key_usize = index / 128;
@@ -358,10 +370,16 @@ pub fn one(index: I) -> Self {
         }
     }
 
+    #[inline]
     pub fn any(&self) -> bool {
         self.bits != 0
     }
 
+    #[inline]
+    pub fn bits_eq(&self, other: SparseChunk<I>) -> bool {
+        self.bits == other.bits
+    }
+
     pub fn iter(&self) -> impl Iterator<Item = I> {
         let base = self.key as usize * 128;
         let mut bits = self.bits;
@@ -394,6 +412,10 @@ pub fn capacity(&self) -> usize {
         self.chunk_bits.len() * 128
     }
 
+    /// Returns a chunk containing only those bits that are already
+    /// present. You can test therefore if `self` contains all the
+    /// bits in chunk already by doing `chunk ==
+    /// self.contains_chunk(chunk)`.
     pub fn contains_chunk(&self, chunk: SparseChunk<I>) -> SparseChunk<I> {
         SparseChunk {
             bits: self.chunk_bits
@@ -403,6 +425,11 @@ pub fn contains_chunk(&self, chunk: SparseChunk<I>) -> SparseChunk<I> {
         }
     }
 
+    /// Modifies `self` to contain all the bits from `chunk` (in
+    /// addition to any pre-existing bits); returns a new chunk that
+    /// contains only those bits that were newly added. You can test
+    /// if anything was inserted by invoking `any()` on the returned
+    /// value.
     pub fn insert_chunk(&mut self, chunk: SparseChunk<I>) -> SparseChunk<I> {
         if chunk.bits == 0 {
             return chunk;
index cede6f147821bf8e3c2e49c72e0068229a9e5fc1..6ee8c3579f5437c4d0f4602dd5bc339a2abebaee 100644 (file)
@@ -67,6 +67,12 @@ pub fn insert(&mut self, key: K, value: V) -> bool {
         }
     }
 
+    pub fn insert_noop(&mut self) {
+        if !self.undo_log.is_empty() {
+            self.undo_log.push(UndoLog::Noop);
+        }
+    }
+
     pub fn remove(&mut self, key: K) -> bool {
         match self.map.remove(&key) {
             Some(old_value) => {
index 0b4b090f1f0b3e7c705d6fad1efee44816015754..2f89814032ef6eb55c43b3ce7986ca4c0c9477f1 100644 (file)
 use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
 use syntax::feature_gate::{GatedCfg, UnstableFeatures};
 use syntax::parse::{self, PResult};
-use syntax_pos::{DUMMY_SP, MultiSpan, FileName};
+use syntax_pos::{hygiene, DUMMY_SP, MultiSpan, FileName};
 
 #[cfg(test)]
 mod test;
@@ -466,6 +466,7 @@ pub fn run_compiler<'a>(args: &[String],
         };
 
         let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
+        hygiene::set_default_edition(sopts.edition);
 
         driver::spawn_thread_pool(sopts, |sopts| {
             run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest)
index 87b3a2dc69ff91fc5f3bc4f5bb9b98ff7ecbb45d..6c1f72f5f9cd66b6fc9a4a38744e8bf8eab01d2e 100644 (file)
@@ -35,6 +35,7 @@
 
 use syntax::ast;
 use syntax::attr;
+use syntax::edition::Edition;
 use syntax::ext::base::SyntaxExtension;
 use syntax::symbol::Symbol;
 use syntax::visit;
@@ -535,7 +536,10 @@ fn load_derive_macros(&mut self, root: &CrateRoot, dylib: Option<PathBuf>, span:
             mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
         };
 
-        struct MyRegistrar(Vec<(ast::Name, Lrc<SyntaxExtension>)>);
+        struct MyRegistrar {
+            extensions: Vec<(ast::Name, Lrc<SyntaxExtension>)>,
+            edition: Edition,
+        }
 
         impl Registry for MyRegistrar {
             fn register_custom_derive(&mut self,
@@ -544,36 +548,38 @@ fn register_custom_derive(&mut self,
                                       attributes: &[&'static str]) {
                 let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
                 let derive = ProcMacroDerive::new(expand, attrs.clone());
-                let derive = SyntaxExtension::ProcMacroDerive(Box::new(derive), attrs);
-                self.0.push((Symbol::intern(trait_name), Lrc::new(derive)));
+                let derive = SyntaxExtension::ProcMacroDerive(
+                    Box::new(derive), attrs, self.edition
+                );
+                self.extensions.push((Symbol::intern(trait_name), Lrc::new(derive)));
             }
 
             fn register_attr_proc_macro(&mut self,
                                         name: &str,
                                         expand: fn(TokenStream, TokenStream) -> TokenStream) {
                 let expand = SyntaxExtension::AttrProcMacro(
-                    Box::new(AttrProcMacro { inner: expand })
+                    Box::new(AttrProcMacro { inner: expand }), self.edition
                 );
-                self.0.push((Symbol::intern(name), Lrc::new(expand)));
+                self.extensions.push((Symbol::intern(name), Lrc::new(expand)));
             }
 
             fn register_bang_proc_macro(&mut self,
                                         name: &str,
                                         expand: fn(TokenStream) -> TokenStream) {
                 let expand = SyntaxExtension::ProcMacro(
-                    Box::new(BangProcMacro { inner: expand })
+                    Box::new(BangProcMacro { inner: expand }), self.edition
                 );
-                self.0.push((Symbol::intern(name), Lrc::new(expand)));
+                self.extensions.push((Symbol::intern(name), Lrc::new(expand)));
             }
         }
 
-        let mut my_registrar = MyRegistrar(Vec::new());
+        let mut my_registrar = MyRegistrar { extensions: Vec::new(), edition: root.edition };
         registrar(&mut my_registrar);
 
         // Intentionally leak the dynamic library. We can't ever unload it
         // since the library can make things that will live arbitrarily long.
         mem::forget(lib);
-        my_registrar.0
+        my_registrar.extensions
     }
 
     /// Look for a plugin registrar. Returns library path, crate
index 9bbce563b61dc15d145e32aea675d50f52f30581..f2d2d090e0ab38cd1effe3ac7c6b8704ddc2b4f5 100644 (file)
@@ -24,6 +24,7 @@
 
 use rustc_data_structures::sync::{Lrc, RwLock, Lock};
 use syntax::{ast, attr};
+use syntax::edition::Edition;
 use syntax::ext::base::SyntaxExtension;
 use syntax::symbol::Symbol;
 use syntax_pos;
@@ -234,4 +235,8 @@ pub fn is_no_builtins(&self, sess: &Session) -> bool {
     pub fn panic_strategy(&self) -> PanicStrategy {
         self.root.panic_strategy.clone()
     }
+
+    pub fn edition(&self) -> Edition {
+        self.root.edition
+    }
 }
index fdfe2a98bf9b935a259eaa1e6dcde776a8ff6d7d..c8f25f935e9fe13807ea87dc9dbdb071719c933a 100644 (file)
@@ -38,6 +38,7 @@
 use syntax::ast;
 use syntax::attr;
 use syntax::codemap;
+use syntax::edition::Edition;
 use syntax::ext::base::SyntaxExtension;
 use syntax::parse::filemap_to_stream;
 use syntax::symbol::Symbol;
@@ -464,6 +465,11 @@ fn crate_hash_untracked(&self, cnum: CrateNum) -> hir::svh::Svh
         self.get_crate_data(cnum).hash()
     }
 
+    fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition
+    {
+        self.get_crate_data(cnum).edition()
+    }
+
     /// Returns the `DefKey` for a given `DefId`. This indicates the
     /// parent `DefId` as well as some idea of what kind of data the
     /// `DefId` refers to.
@@ -512,7 +518,8 @@ fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
             return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone());
         } else if data.name == "proc_macro" &&
                   self.get_crate_data(id.krate).item_name(id.index) == "quote" {
-            let ext = SyntaxExtension::ProcMacro(Box::new(::proc_macro::__internal::Quoter));
+            let ext = SyntaxExtension::ProcMacro(Box::new(::proc_macro::__internal::Quoter),
+                                                 data.edition());
             return LoadedMacro::ProcMacro(Lrc::new(ext));
         }
 
index bbc4120f0600d3d2f26f34563f17da6ec8c042bc..d00f4f32c109f61422897b952a563147b8976575 100644 (file)
@@ -44,7 +44,7 @@
 use syntax::codemap::Spanned;
 use syntax::attr;
 use syntax::symbol::Symbol;
-use syntax_pos::{self, FileName, FileMap, Span, DUMMY_SP};
+use syntax_pos::{self, hygiene, FileName, FileMap, Span, DUMMY_SP};
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -496,6 +496,7 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
             hash: link_meta.crate_hash,
             disambiguator: tcx.sess.local_crate_disambiguator(),
             panic_strategy: tcx.sess.panic_strategy(),
+            edition: hygiene::default_edition(),
             has_global_allocator: has_global_allocator,
             has_default_lib_allocator: has_default_lib_allocator,
             plugin_registrar_fn: tcx.sess
index c9949389aceea5d3910d9bc0f5ab96f717f89dc3..8e17b7f8d692d94194627f66d56342a4c1bb9682 100644 (file)
@@ -23,6 +23,7 @@
 
 use rustc_serialize as serialize;
 use syntax::{ast, attr};
+use syntax::edition::Edition;
 use syntax::symbol::Symbol;
 use syntax_pos::{self, Span};
 
@@ -189,6 +190,7 @@ pub struct CrateRoot {
     pub hash: hir::svh::Svh,
     pub disambiguator: CrateDisambiguator,
     pub panic_strategy: PanicStrategy,
+    pub edition: Edition,
     pub has_global_allocator: bool,
     pub has_default_lib_allocator: bool,
     pub plugin_registrar_fn: Option<DefIndex>,
index 1cc69351b4750578633dbfb8992f9f7e2f68f3a1..5d6d4619c5e0520d63e41c982863044bc8c8a1b3 100644 (file)
@@ -10,7 +10,7 @@
 
 //! This query borrow-checks the MIR to (further) ensure it is not broken.
 
-use borrow_check::nll::region_infer::{RegionCausalInfo, RegionInferenceContext};
+use borrow_check::nll::region_infer::RegionInferenceContext;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::definitions::DefPathData;
@@ -248,7 +248,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         nonlexical_regioncx: regioncx,
         used_mut: FxHashSet(),
         used_mut_upvars: SmallVec::new(),
-        nonlexical_cause_info: None,
         borrow_set,
         dominators,
     };
@@ -367,7 +366,6 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     /// contains the results from region inference and lets us e.g.
     /// find out which CFG points are contained in each borrow region.
     nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
-    nonlexical_cause_info: Option<RegionCausalInfo>,
 
     /// The set of borrows extracted from the MIR
     borrow_set: Rc<BorrowSet<'tcx>>,
@@ -1810,9 +1808,9 @@ fn check_access_permissions(
                 }
             }
             Reservation(WriteKind::Move)
+            | Write(WriteKind::Move)
             | Reservation(WriteKind::StorageDeadOrDrop)
             | Reservation(WriteKind::MutableBorrow(BorrowKind::Shared))
-            | Write(WriteKind::Move)
             | Write(WriteKind::StorageDeadOrDrop)
             | Write(WriteKind::MutableBorrow(BorrowKind::Shared)) => {
                 if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) {
@@ -1851,8 +1849,11 @@ fn add_used_mut<'d>(
                     // mutated, then it is justified to be annotated with the `mut`
                     // keyword, since the mutation may be a possible reassignment.
                     let mpi = self.move_data.rev_lookup.find_local(*local);
-                    if flow_state.inits.contains(&mpi) {
-                        self.used_mut.insert(*local);
+                    let ii = &self.move_data.init_path_map[mpi];
+                    for index in ii {
+                        if flow_state.ever_inits.contains(index) {
+                            self.used_mut.insert(*local);
+                        }
                     }
                 }
             }
index 56e388a5b6094b81d87df6e46a7006a359ba72ca..2807a4e8857e0b91421dbf09506b2598f16fb48a 100644 (file)
@@ -32,13 +32,9 @@ pub(in borrow_check) fn explain_why_borrow_contains_point(
         let regioncx = &&self.nonlexical_regioncx;
         let mir = self.mir;
 
-        if self.nonlexical_cause_info.is_none() {
-            self.nonlexical_cause_info = Some(regioncx.compute_causal_info(mir));
-        }
-
-        let cause_info = self.nonlexical_cause_info.as_ref().unwrap();
-        if let Some(cause) = cause_info.why_region_contains_point(borrow.region, context.loc) {
-            match *cause.root_cause() {
+        let borrow_region_vid = regioncx.to_region_vid(borrow.region);
+        if let Some(cause) = regioncx.why_region_contains_point(borrow_region_vid, context.loc) {
+            match cause {
                 Cause::LiveVar(local, location) => {
                     match find_regular_use(mir, regioncx, borrow, location, local) {
                         Some(p) => {
index 0b1729294d8494b3ba74e8c61b482015f0789977..a162ef36a6054669e0da2992c59f257d1c14a542 100644 (file)
@@ -240,11 +240,11 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
     });
 
     // Also dump the inference graph constraints as a graphviz file.
-    let _: io::Result<()> = do_catch! {{
+    let _: io::Result<()> = do catch {
         let mut file =
             pretty::create_dump_file(infcx.tcx, "regioncx.dot", None, "nll", &0, source)?;
         regioncx.dump_graphviz(&mut file)?;
-    }};
+    };
 }
 
 fn dump_annotation<'a, 'gcx, 'tcx>(
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs b/src/librustc_mir/borrow_check/nll/region_infer/dfs.rs
deleted file mode 100644 (file)
index f68394d..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2017 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.
-
-//! Module defining the `dfs` method on `RegionInferenceContext`, along with
-//! its associated helper traits.
-
-use borrow_check::nll::universal_regions::UniversalRegions;
-use borrow_check::nll::region_infer::RegionInferenceContext;
-use borrow_check::nll::region_infer::values::{RegionElementIndex, RegionValueElements,
-                                              RegionValues};
-use syntax::codemap::Span;
-use rustc::mir::{Location, Mir};
-use rustc::ty::RegionVid;
-use rustc_data_structures::bitvec::BitVector;
-use rustc_data_structures::indexed_vec::Idx;
-
-pub(super) struct DfsStorage {
-    stack: Vec<Location>,
-    visited: BitVector,
-}
-
-impl<'tcx> RegionInferenceContext<'tcx> {
-    /// Creates dfs storage for use by dfs; this should be shared
-    /// across as many calls to dfs as possible to amortize allocation
-    /// costs.
-    pub(super) fn new_dfs_storage(&self) -> DfsStorage {
-        let num_elements = self.elements.num_elements();
-        DfsStorage {
-            stack: vec![],
-            visited: BitVector::new(num_elements),
-        }
-    }
-
-    /// Function used to satisfy or test a `R1: R2 @ P`
-    /// constraint. The core idea is that it performs a DFS starting
-    /// from `P`. The precise actions *during* that DFS depend on the
-    /// `op` supplied, so see (e.g.) `CopyFromSourceToTarget` for more
-    /// details.
-    ///
-    /// Returns:
-    ///
-    /// - `Ok(true)` if the walk was completed and something changed
-    ///   along the way;
-    /// - `Ok(false)` if the walk was completed with no changes;
-    /// - `Err(early)` if the walk was existed early by `op`. `earlyelem` is the
-    ///   value that `op` returned.
-    #[inline(never)] // ensure dfs is identifiable in profiles
-    pub(super) fn dfs<C>(
-        &self,
-        mir: &Mir<'tcx>,
-        dfs: &mut DfsStorage,
-        mut op: C,
-    ) -> Result<bool, C::Early>
-    where
-        C: DfsOp,
-    {
-        let mut changed = false;
-
-        dfs.visited.clear();
-        dfs.stack.push(op.start_point());
-        while let Some(p) = dfs.stack.pop() {
-            let point_index = self.elements.index(p);
-
-            if !op.source_region_contains(point_index) {
-                debug!("            not in from-region");
-                continue;
-            }
-
-            if !dfs.visited.insert(point_index.index()) {
-                debug!("            already visited");
-                continue;
-            }
-
-            let new = op.add_to_target_region(point_index)?;
-            changed |= new;
-
-            let block_data = &mir[p.block];
-
-            let start_stack_len = dfs.stack.len();
-
-            if p.statement_index < block_data.statements.len() {
-                dfs.stack.push(Location {
-                    statement_index: p.statement_index + 1,
-                    ..p
-                });
-            } else {
-                dfs.stack.extend(
-                    block_data
-                        .terminator()
-                        .successors()
-                        .map(|&basic_block| Location {
-                            statement_index: 0,
-                            block: basic_block,
-                        }),
-                );
-            }
-
-            if dfs.stack.len() == start_stack_len {
-                // If we reach the END point in the graph, then copy
-                // over any skolemized end points in the `from_region`
-                // and make sure they are included in the `to_region`.
-                changed |= op.add_universal_regions_outlived_by_source_to_target()?;
-            }
-        }
-
-        Ok(changed)
-    }
-}
-
-/// Customizes the operation of the `dfs` function. This function is
-/// used during inference to satisfy a `R1: R2 @ P` constraint.
-pub(super) trait DfsOp {
-    /// If this op stops the walk early, what type does it propagate?
-    type Early;
-
-    /// Returns the point from which to start the DFS.
-    fn start_point(&self) -> Location;
-
-    /// Returns true if the source region contains the given point.
-    fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool;
-
-    /// Adds the given point to the target region, returning true if
-    /// something has changed. Returns `Err` if we should abort the
-    /// walk early.
-    fn add_to_target_region(
-        &mut self,
-        point_index: RegionElementIndex,
-    ) -> Result<bool, Self::Early>;
-
-    /// Adds all universal regions in the source region to the target region, returning
-    /// true if something has changed.
-    fn add_universal_regions_outlived_by_source_to_target(&mut self) -> Result<bool, Self::Early>;
-}
-
-/// Used during inference to enforce a `R1: R2 @ P` constraint.  For
-/// each point Q we reach along the DFS, we check if Q is in R2 (the
-/// "source region"). If not, we stop the walk. Otherwise, we add Q to
-/// R1 (the "target region") and continue to Q's successors. If we
-/// reach the end of the graph, then we add any universal regions from
-/// R2 into R1.
-pub(super) struct CopyFromSourceToTarget<'v> {
-    pub source_region: RegionVid,
-    pub target_region: RegionVid,
-    pub inferred_values: &'v mut RegionValues,
-    pub constraint_point: Location,
-    pub constraint_span: Span,
-}
-
-impl<'v> DfsOp for CopyFromSourceToTarget<'v> {
-    /// We never stop the walk early.
-    type Early = !;
-
-    fn start_point(&self) -> Location {
-        self.constraint_point
-    }
-
-    fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool {
-        self.inferred_values
-            .contains(self.source_region, point_index)
-    }
-
-    fn add_to_target_region(&mut self, point_index: RegionElementIndex) -> Result<bool, !> {
-        Ok(self.inferred_values.add_due_to_outlives(
-            self.source_region,
-            self.target_region,
-            point_index,
-            self.constraint_point,
-            self.constraint_span,
-        ))
-    }
-
-    fn add_universal_regions_outlived_by_source_to_target(&mut self) -> Result<bool, !> {
-        Ok(self.inferred_values.add_universal_regions_outlived_by(
-            self.source_region,
-            self.target_region,
-            self.constraint_point,
-            self.constraint_span,
-        ))
-    }
-}
-
-/// Used after inference to *test* a `R1: R2 @ P` constraint.  For
-/// each point Q we reach along the DFS, we check if Q in R2 is also
-/// contained in R1. If not, we abort the walk early with an `Err`
-/// condition. Similarly, if we reach the end of the graph and find
-/// that R1 contains some universal region that R2 does not contain,
-/// we abort the walk early.
-pub(super) struct TestTargetOutlivesSource<'v, 'tcx: 'v> {
-    pub source_region: RegionVid,
-    pub target_region: RegionVid,
-    pub elements: &'v RegionValueElements,
-    pub universal_regions: &'v UniversalRegions<'tcx>,
-    pub inferred_values: &'v RegionValues,
-    pub constraint_point: Location,
-}
-
-impl<'v, 'tcx> DfsOp for TestTargetOutlivesSource<'v, 'tcx> {
-    /// The element that was not found within R2.
-    type Early = RegionElementIndex;
-
-    fn start_point(&self) -> Location {
-        self.constraint_point
-    }
-
-    fn source_region_contains(&mut self, point_index: RegionElementIndex) -> bool {
-        self.inferred_values
-            .contains(self.source_region, point_index)
-    }
-
-    fn add_to_target_region(
-        &mut self,
-        point_index: RegionElementIndex,
-    ) -> Result<bool, RegionElementIndex> {
-        if !self.inferred_values
-            .contains(self.target_region, point_index)
-        {
-            return Err(point_index);
-        }
-
-        Ok(false)
-    }
-
-    fn add_universal_regions_outlived_by_source_to_target(
-        &mut self,
-    ) -> Result<bool, RegionElementIndex> {
-        // For all `ur_in_source` in `source_region`.
-        for ur_in_source in self.inferred_values
-            .universal_regions_outlived_by(self.source_region)
-        {
-            // Check that `target_region` outlives `ur_in_source`.
-
-            // If `ur_in_source` is a member of `target_region`, OK.
-            //
-            // (This is implied by the loop below, actually, just an
-            // irresistible micro-opt. Mm. Premature optimization. So
-            // tasty.)
-            if self.inferred_values
-                .contains(self.target_region, ur_in_source)
-            {
-                continue;
-            }
-
-            // If there is some other element X such that `target_region: X` and
-            // `X: ur_in_source`, OK.
-            if self.inferred_values
-                .universal_regions_outlived_by(self.target_region)
-                .any(|ur_in_target| self.universal_regions.outlives(ur_in_target, ur_in_source))
-            {
-                continue;
-            }
-
-            // Otherwise, not known to be true.
-            return Err(self.elements.index(ur_in_source));
-        }
-
-        Ok(false)
-    }
-}
index 57b8824191f7b86ab50e1e02148e1eb35c129fcc..5a1ab73b2b81409186a03d1df66188b99a3a88ed 100644 (file)
@@ -9,16 +9,19 @@
 // except according to those terms.
 
 use super::universal_regions::UniversalRegions;
+use borrow_check::nll::region_infer::values::ToElementIndex;
 use rustc::hir::def_id::DefId;
+use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
+use rustc::infer::region_constraints::{GenericKind, VarInfos};
 use rustc::infer::InferCtxt;
 use rustc::infer::NLLRegionVariableOrigin;
 use rustc::infer::RegionObligation;
 use rustc::infer::RegionVariableOrigin;
 use rustc::infer::SubregionOrigin;
-use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
-use rustc::infer::region_constraints::{GenericKind, VarInfos};
-use rustc::mir::{ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
-                 Local, Location, Mir};
+use rustc::mir::{
+    ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location,
+    Mir,
+};
 use rustc::traits::ObligationCause;
 use rustc::ty::{self, RegionVid, Ty, TypeFoldable};
 use rustc::util::common::{self, ErrorReported};
@@ -30,8 +33,6 @@
 use syntax_pos::Span;
 
 mod annotation;
-mod dfs;
-use self::dfs::{CopyFromSourceToTarget, TestTargetOutlivesSource};
 mod dump_mir;
 mod graphviz;
 mod values;
@@ -100,7 +101,7 @@ struct RegionDefinition<'tcx> {
 /// NB: The variants in `Cause` are intentionally ordered. Lower
 /// values are preferred when it comes to error messages. Do not
 /// reorder willy nilly.
-#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
 pub(crate) enum Cause {
     /// point inserted because Local was live at the given Location
     LiveVar(Local, Location),
@@ -114,23 +115,6 @@ pub(crate) enum Cause {
 
     /// part of the initial set of values for a universally quantified region
     UniversalRegion(RegionVid),
-
-    /// Element E was added to R because there was some
-    /// outlives obligation `R: R1 @ P` and `R1` contained `E`.
-    Outlives {
-        /// the reason that R1 had E
-        original_cause: Rc<Cause>,
-
-        /// the point P from the relation
-        constraint_location: Location,
-
-        /// The span indicating why we added the outlives constraint.
-        constraint_span: Span,
-    },
-}
-
-pub(crate) struct RegionCausalInfo {
-    inferred_values: RegionValues,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -325,7 +309,7 @@ fn init_universal_regions(&mut self) {
 
             // Add all nodes in the CFG to liveness constraints
             for point_index in self.elements.all_point_indices() {
-                self.liveness_constraints.add(
+                self.liveness_constraints.add_element(
                     variable,
                     point_index,
                     &Cause::UniversalRegion(variable),
@@ -333,8 +317,11 @@ fn init_universal_regions(&mut self) {
             }
 
             // Add `end(X)` into the set for X.
-            self.liveness_constraints
-                .add(variable, variable, &Cause::UniversalRegion(variable));
+            self.liveness_constraints.add_element(
+                variable,
+                variable,
+                &Cause::UniversalRegion(variable),
+            );
         }
     }
 
@@ -383,7 +370,7 @@ pub(super) fn add_live_point(&mut self, v: RegionVid, point: Location, cause: &C
         debug!("add_live_point: @{:?} Adding cause {:?}", point, cause);
 
         let element = self.elements.index(point);
-        if self.liveness_constraints.add(v, element, &cause) {
+        if self.liveness_constraints.add_element(v, element, &cause) {
             true
         } else {
             false
@@ -438,9 +425,7 @@ fn solve_inner<'gcx>(
     ) -> Option<ClosureRegionRequirements<'gcx>> {
         assert!(self.inferred_values.is_none(), "values already inferred");
 
-        let dfs_storage = &mut self.new_dfs_storage();
-
-        self.propagate_constraints(mir, dfs_storage);
+        self.propagate_constraints(mir);
 
         // If this is a closure, we can propagate unsatisfied
         // `outlives_requirements` to our creator, so create a vector
@@ -453,13 +438,7 @@ fn solve_inner<'gcx>(
             None
         };
 
-        self.check_type_tests(
-            infcx,
-            mir,
-            dfs_storage,
-            mir_def_id,
-            outlives_requirements.as_mut(),
-        );
+        self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut());
 
         self.check_universal_regions(infcx, mir_def_id, outlives_requirements.as_mut());
 
@@ -476,31 +455,18 @@ fn solve_inner<'gcx>(
         }
     }
 
-    /// Re-execute the region inference, this time tracking causal information.
-    /// This is significantly slower, so it is done only when an error is being reported.
-    pub(super) fn compute_causal_info(&self, mir: &Mir<'tcx>) -> RegionCausalInfo {
-        let dfs_storage = &mut self.new_dfs_storage();
-        let inferred_values = self.compute_region_values(mir, dfs_storage, TrackCauses(true));
-        RegionCausalInfo { inferred_values }
-    }
-
     /// Propagate the region constraints: this will grow the values
     /// for each region variable until all the constraints are
     /// satisfied. Note that some values may grow **too** large to be
     /// feasible, but we check this later.
-    fn propagate_constraints(&mut self, mir: &Mir<'tcx>, dfs_storage: &mut dfs::DfsStorage) {
+    fn propagate_constraints(&mut self, mir: &Mir<'tcx>) {
         self.dependency_map = Some(self.build_dependency_map());
-        let inferred_values = self.compute_region_values(mir, dfs_storage, TrackCauses(false));
+        let inferred_values = self.compute_region_values(mir);
         self.inferred_values = Some(inferred_values);
     }
 
     #[inline(never)] // ensure dfs is identifiable in profiles
-    fn compute_region_values(
-        &self,
-        mir: &Mir<'tcx>,
-        dfs_storage: &mut dfs::DfsStorage,
-        track_causes: TrackCauses,
-    ) -> RegionValues {
+    fn compute_region_values(&self, _mir: &Mir<'tcx>) -> RegionValues {
         debug!("compute_region_values()");
         debug!("compute_region_values: constraints={:#?}", {
             let mut constraints: Vec<_> = self.constraints.iter().collect();
@@ -510,7 +476,7 @@ fn compute_region_values(
 
         // The initial values for each region are derived from the liveness
         // constraints we have accumulated.
-        let mut inferred_values = self.liveness_constraints.duplicate(track_causes);
+        let mut inferred_values = self.liveness_constraints.duplicate(TrackCauses(false));
 
         let dependency_map = self.dependency_map.as_ref().unwrap();
 
@@ -527,21 +493,7 @@ fn compute_region_values(
             let constraint = &self.constraints[constraint_idx];
             debug!("propagate_constraints: constraint={:?}", constraint);
 
-            // Grow the value as needed to accommodate the
-            // outlives constraint.
-            let Ok(made_changes) = self.dfs(
-                mir,
-                dfs_storage,
-                CopyFromSourceToTarget {
-                    source_region: constraint.sub,
-                    target_region: constraint.sup,
-                    inferred_values: &mut inferred_values,
-                    constraint_point: constraint.point,
-                    constraint_span: constraint.span,
-                },
-            );
-
-            if made_changes {
+            if inferred_values.add_region(constraint.sup, constraint.sub) {
                 debug!("propagate_constraints:   sub={:?}", constraint.sub);
                 debug!("propagate_constraints:   sup={:?}", constraint.sup);
 
@@ -586,7 +538,6 @@ fn check_type_tests<'gcx>(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
         mir: &Mir<'tcx>,
-        dfs_storage: &mut dfs::DfsStorage,
         mir_def_id: DefId,
         mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
     ) {
@@ -595,13 +546,7 @@ fn check_type_tests<'gcx>(
         for type_test in &self.type_tests {
             debug!("check_type_test: {:?}", type_test);
 
-            if self.eval_region_test(
-                mir,
-                dfs_storage,
-                type_test.point,
-                type_test.lower_bound,
-                &type_test.test,
-            ) {
+            if self.eval_region_test(mir, type_test.point, type_test.lower_bound, &type_test.test) {
                 continue;
             }
 
@@ -858,7 +803,6 @@ fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
     fn eval_region_test(
         &self,
         mir: &Mir<'tcx>,
-        dfs_storage: &mut dfs::DfsStorage,
         point: Location,
         lower_bound: RegionVid,
         test: &RegionTest,
@@ -871,27 +815,26 @@ fn eval_region_test(
         match test {
             RegionTest::IsOutlivedByAllRegionsIn(regions) => regions
                 .iter()
-                .all(|&r| self.eval_outlives(mir, dfs_storage, r, lower_bound, point)),
+                .all(|&r| self.eval_outlives(mir, r, lower_bound, point)),
 
             RegionTest::IsOutlivedByAnyRegionIn(regions) => regions
                 .iter()
-                .any(|&r| self.eval_outlives(mir, dfs_storage, r, lower_bound, point)),
+                .any(|&r| self.eval_outlives(mir, r, lower_bound, point)),
 
             RegionTest::Any(tests) => tests
                 .iter()
-                .any(|test| self.eval_region_test(mir, dfs_storage, point, lower_bound, test)),
+                .any(|test| self.eval_region_test(mir, point, lower_bound, test)),
 
             RegionTest::All(tests) => tests
                 .iter()
-                .all(|test| self.eval_region_test(mir, dfs_storage, point, lower_bound, test)),
+                .all(|test| self.eval_region_test(mir, point, lower_bound, test)),
         }
     }
 
     // Evaluate whether `sup_region: sub_region @ point`.
     fn eval_outlives(
         &self,
-        mir: &Mir<'tcx>,
-        dfs_storage: &mut dfs::DfsStorage,
+        _mir: &Mir<'tcx>,
         sup_region: RegionVid,
         sub_region: RegionVid,
         point: Location,
@@ -901,36 +844,46 @@ fn eval_outlives(
             sup_region, sub_region, point
         );
 
-        // Roughly speaking, do a DFS of all region elements reachable
-        // from `point` contained in `sub_region`. If any of those are
-        // *not* present in `sup_region`, the DFS will abort early and
-        // yield an `Err` result.
-        match self.dfs(
-            mir,
-            dfs_storage,
-            TestTargetOutlivesSource {
-                source_region: sub_region,
-                target_region: sup_region,
-                constraint_point: point,
-                elements: &self.elements,
-                universal_regions: &self.universal_regions,
-                inferred_values: self.inferred_values.as_ref().unwrap(),
-            },
-        ) {
-            Ok(_) => {
-                debug!("eval_outlives: true");
-                true
-            }
+        let inferred_values = self.inferred_values
+            .as_ref()
+            .expect("values for regions not yet inferred");
 
-            Err(elem) => {
-                debug!(
-                    "eval_outlives: false because `{:?}` is not present in `{:?}`",
-                    self.elements.to_element(elem),
-                    sup_region
-                );
-                false
-            }
+        debug!(
+            "eval_outlives: sup_region's value = {:?}",
+            inferred_values.region_value_str(sup_region),
+        );
+        debug!(
+            "eval_outlives: sub_region's value = {:?}",
+            inferred_values.region_value_str(sub_region),
+        );
+
+        // Both the `sub_region` and `sup_region` consist of the union
+        // of some number of universal regions (along with the union
+        // of various points in the CFG; ignore those points for
+        // now). Therefore, the sup-region outlives the sub-region if,
+        // for each universal region R1 in the sub-region, there
+        // exists some region R2 in the sup-region that outlives R1.
+        let universal_outlives = inferred_values
+            .universal_regions_outlived_by(sub_region)
+            .all(|r1| {
+                inferred_values
+                    .universal_regions_outlived_by(sup_region)
+                    .any(|r2| self.universal_regions.outlives(r2, r1))
+            });
+
+        if !universal_outlives {
+            return false;
+        }
+
+        // Now we have to compare all the points in the sub region and make
+        // sure they exist in the sup region.
+
+        if self.universal_regions.is_universal_region(sup_region) {
+            // Micro-opt: universal regions contain all points.
+            return true;
         }
+
+        inferred_values.contains_points(sup_region, sub_region)
     }
 
     /// Once regions have been propagated, this method is used to see
@@ -1007,7 +960,8 @@ fn check_universal_region<'gcx>(
                 longer_fr, shorter_fr,
             );
 
-            let blame_span = self.blame_span(longer_fr, shorter_fr);
+            let blame_index = self.blame_constraint(longer_fr, shorter_fr);
+            let blame_span = self.constraints[blame_index].span;
 
             if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
                 // Shrink `fr` until we find a non-local region (if we do).
@@ -1093,9 +1047,20 @@ fn report_error(
         diag.emit();
     }
 
+    crate fn why_region_contains_point(&self, fr1: RegionVid, elem: Location) -> Option<Cause> {
+        // Find some constraint `X: Y` where:
+        // - `fr1: X` transitively
+        // - and `Y` is live at `elem`
+        let index = self.blame_constraint(fr1, elem);
+        let region_sub = self.constraints[index].sub;
+
+        // then return why `Y` was live at `elem`
+        self.liveness_constraints.cause(region_sub, elem)
+    }
+
     /// Tries to finds a good span to blame for the fact that `fr1`
     /// contains `fr2`.
-    fn blame_span(&self, fr1: RegionVid, fr2: RegionVid) -> Span {
+    fn blame_constraint(&self, fr1: RegionVid, elem: impl ToElementIndex) -> ConstraintIndex {
         // Find everything that influenced final value of `fr`.
         let influenced_fr1 = self.dependencies(fr1);
 
@@ -1108,23 +1073,23 @@ fn blame_span(&self, fr1: RegionVid, fr2: RegionVid) -> Span {
         // of dependencies, which doesn't account for the locations of
         // contraints at all. But it will do for now.
         let relevant_constraint = self.constraints
-                .iter()
-                .filter_map(|constraint| {
-                    if constraint.sub != fr2 {
-                        None
-                    } else {
-                        influenced_fr1[constraint.sup]
-                            .map(|distance| (distance, constraint.span))
-                    }
-                })
-                .min() // constraining fr1 with fewer hops *ought* to be more obvious
-                .map(|(_dist, span)| span);
+            .iter_enumerated()
+            .filter_map(|(i, constraint)| {
+                if !self.liveness_constraints.contains(constraint.sub, elem) {
+                    None
+                } else {
+                    influenced_fr1[constraint.sup]
+                        .map(|distance| (distance, i))
+                }
+            })
+            .min() // constraining fr1 with fewer hops *ought* to be more obvious
+            .map(|(_dist, i)| i);
 
         relevant_constraint.unwrap_or_else(|| {
             bug!(
                 "could not find any constraint to blame for {:?}: {:?}",
                 fr1,
-                fr2
+                elem,
             );
         })
     }
@@ -1161,16 +1126,6 @@ fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
     }
 }
 
-impl RegionCausalInfo {
-    /// Returns the *reason* that the region `r` contains the given point.
-    pub(super) fn why_region_contains_point<R>(&self, r: R, p: Location) -> Option<Rc<Cause>>
-    where
-        R: ToRegionVid,
-    {
-        self.inferred_values.cause(r.to_region_vid(), p)
-    }
-}
-
 impl<'tcx> RegionDefinition<'tcx> {
     fn new(origin: RegionVariableOrigin) -> Self {
         // Create a new region definition. Note that, for free
@@ -1314,31 +1269,3 @@ fn subst_closure_mapping<T>(
         })
     }
 }
-
-trait CauseExt {
-    fn outlives(&self, constraint_location: Location, constraint_span: Span) -> Cause;
-}
-
-impl CauseExt for Rc<Cause> {
-    /// Creates a derived cause due to an outlives constraint.
-    fn outlives(&self, constraint_location: Location, constraint_span: Span) -> Cause {
-        Cause::Outlives {
-            original_cause: self.clone(),
-            constraint_location,
-            constraint_span,
-        }
-    }
-}
-
-impl Cause {
-    pub(crate) fn root_cause(&self) -> &Cause {
-        match self {
-            Cause::LiveVar(..)
-            | Cause::DropVar(..)
-            | Cause::LiveOther(..)
-            | Cause::UniversalRegion(..) => self,
-
-            Cause::Outlives { original_cause, .. } => original_cause.root_cause(),
-        }
-    }
-}
index d15d85792d99dc93964a96ffcbaed29eb05009e0..e914be52db08c83776f95e929b1b950d77d4dda7 100644 (file)
@@ -8,16 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::rc::Rc;
+use borrow_check::nll::region_infer::TrackCauses;
+use rustc::mir::{BasicBlock, Location, Mir};
+use rustc::ty::RegionVid;
 use rustc_data_structures::bitvec::SparseBitMatrix;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::indexed_vec::IndexVec;
-use rustc::mir::{BasicBlock, Location, Mir};
-use rustc::ty::{self, RegionVid};
-use syntax::codemap::Span;
+use std::fmt::Debug;
+use std::rc::Rc;
 
-use super::{Cause, CauseExt, TrackCauses};
+use super::Cause;
 
 /// Maps between the various kinds of elements of a region value to
 /// the internal indices that w use.
@@ -72,11 +73,6 @@ pub(super) fn all_point_indices<'a>(&'a self) -> impl Iterator<Item = RegionElem
         (0..self.num_points).map(move |i| RegionElementIndex::new(i + self.num_universal_regions))
     }
 
-    /// Iterates over the `RegionElementIndex` for all points in the CFG.
-    pub(super) fn all_universal_region_indices(&self) -> impl Iterator<Item = RegionElementIndex> {
-        (0..self.num_universal_regions).map(move |i| RegionElementIndex::new(i))
-    }
-
     /// Converts a particular `RegionElementIndex` to the `RegionElement` it represents.
     pub(super) fn to_element(&self, i: RegionElementIndex) -> RegionElement {
         debug!("to_element(i={:?})", i);
@@ -152,7 +148,7 @@ pub(super) enum RegionElement {
     UniversalRegion(RegionVid),
 }
 
-pub(super) trait ToElementIndex {
+pub(super) trait ToElementIndex: Debug + Copy {
     fn to_element_index(self, elements: &RegionValueElements) -> RegionElementIndex;
 }
 
@@ -195,7 +191,7 @@ pub(super) struct RegionValues {
     causes: Option<CauseMap>,
 }
 
-type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Rc<Cause>>;
+type CauseMap = FxHashMap<(RegionVid, RegionElementIndex), Cause>;
 
 impl RegionValues {
     /// Creates a new set of "region values" that tracks causal information.
@@ -237,11 +233,22 @@ pub(super) fn duplicate(&self, track_causes: TrackCauses) -> Self {
 
     /// Adds the given element to the value for the given region. Returns true if
     /// the element is newly added (i.e., was not already present).
-    pub(super) fn add<E: ToElementIndex>(&mut self, r: RegionVid, elem: E, cause: &Cause) -> bool {
+    pub(super) fn add_element<E: ToElementIndex>(
+        &mut self,
+        r: RegionVid,
+        elem: E,
+        cause: &Cause,
+    ) -> bool {
         let i = self.elements.index(elem);
         self.add_internal(r, i, |_| cause.clone())
     }
 
+    /// Add all elements in `r_from` to `r_to` (because e.g. `r_to:
+    /// r_from`).
+    pub(super) fn add_region(&mut self, r_to: RegionVid, r_from: RegionVid) -> bool {
+        self.matrix.merge(r_from, r_to)
+    }
+
     /// Internal method to add an element to a region.
     ///
     /// Takes a "lazy" cause -- this function will return the cause, but it will only
@@ -254,7 +261,7 @@ fn add_internal<F>(&mut self, r: RegionVid, i: RegionElementIndex, make_cause: F
             debug!("add(r={:?}, i={:?})", r, self.elements.to_element(i));
 
             if let Some(causes) = &mut self.causes {
-                let cause = Rc::new(make_cause(causes));
+                let cause = make_cause(causes);
                 causes.insert((r, i), cause);
             }
 
@@ -266,15 +273,8 @@ fn add_internal<F>(&mut self, r: RegionVid, i: RegionElementIndex, make_cause: F
                 // #49998: compare using root cause alone to avoid
                 // useless traffic from similar outlives chains.
 
-                let overwrite = if ty::tls::with(|tcx| {
-                    tcx.sess.opts.debugging_opts.nll_subminimal_causes
-                }) {
-                    cause.root_cause() < old_cause.root_cause()
-                } else {
-                    cause < **old_cause
-                };
-                if overwrite {
-                    *old_cause = Rc::new(cause);
+                if cause < *old_cause {
+                    *old_cause = cause;
                     return true;
                 }
             }
@@ -283,62 +283,22 @@ fn add_internal<F>(&mut self, r: RegionVid, i: RegionElementIndex, make_cause: F
         }
     }
 
-    /// Adds `elem` to `to_region` because of a relation:
-    ///
-    ///     to_region: from_region @ constraint_location
-    ///
-    /// that was added by the cod at `constraint_span`.
-    pub(super) fn add_due_to_outlives<T: ToElementIndex>(
-        &mut self,
-        from_region: RegionVid,
-        to_region: RegionVid,
-        elem: T,
-        constraint_location: Location,
-        constraint_span: Span,
-    ) -> bool {
-        let elem = self.elements.index(elem);
-        self.add_internal(to_region, elem, |causes| {
-            causes[&(from_region, elem)].outlives(constraint_location, constraint_span)
-        })
-    }
-
-    /// Adds all the universal regions outlived by `from_region` to
-    /// `to_region`.
-    pub(super) fn add_universal_regions_outlived_by(
-        &mut self,
-        from_region: RegionVid,
-        to_region: RegionVid,
-        constraint_location: Location,
-        constraint_span: Span,
-    ) -> bool {
-        // We could optimize this by improving `SparseBitMatrix::merge` so
-        // it does not always merge an entire row. That would
-        // complicate causal tracking though.
-        debug!(
-            "add_universal_regions_outlived_by(from_region={:?}, to_region={:?})",
-            from_region, to_region
-        );
-        let mut changed = false;
-        for elem in self.elements.all_universal_region_indices() {
-            if self.contains(from_region, elem) {
-                changed |= self.add_due_to_outlives(
-                    from_region,
-                    to_region,
-                    elem,
-                    constraint_location,
-                    constraint_span,
-                );
-            }
-        }
-        changed
-    }
-
     /// True if the region `r` contains the given element.
     pub(super) fn contains<E: ToElementIndex>(&self, r: RegionVid, elem: E) -> bool {
         let i = self.elements.index(elem);
         self.matrix.contains(r, i)
     }
 
+    /// True if `sup_region` contains all the CFG points that
+    /// `sub_region` contains. Ignores universal regions.
+    pub(super) fn contains_points(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
+        // This could be done faster by comparing the bitsets. But I
+        // am lazy.
+        self.element_indices_contained_in(sub_region)
+            .skip_while(|&i| self.elements.to_universal_region(i).is_some())
+            .all(|e| self.contains(sup_region, e))
+    }
+
     /// Iterate over the value of the region `r`, yielding up element
     /// indices. You may prefer `universal_regions_outlived_by` or
     /// `elements_contained_in`.
@@ -444,7 +404,7 @@ fn push_location_range(str: &mut String, location1: Location, location2: Locatio
     ///
     /// Returns None if cause tracking is disabled or `elem` is not
     /// actually found in `r`.
-    pub(super) fn cause<T: ToElementIndex>(&self, r: RegionVid, elem: T) -> Option<Rc<Cause>> {
+    pub(super) fn cause<T: ToElementIndex>(&self, r: RegionVid, elem: T) -> Option<Cause> {
         let index = self.elements.index(elem);
         if let Some(causes) = &self.causes {
             causes.get(&(r, index)).cloned()
index ecced1b81682e94d365b34389a4234a4ff868700..3bf9453fb513c82a5d2a69f2caa9620cce8ed4bd 100644 (file)
 #![feature(const_fn)]
 #![feature(core_intrinsics)]
 #![feature(decl_macro)]
-#![cfg_attr(stage0, feature(dyn_trait))]
 #![feature(fs_read_write)]
 #![feature(macro_vis_matcher)]
 #![feature(exhaustive_patterns)]
 #![feature(range_contains)]
 #![feature(rustc_diagnostic_macros)]
-#![feature(inclusive_range_methods)]
 #![feature(crate_visibility_modifier)]
 #![feature(never_type)]
 #![feature(specialization)]
-#![cfg_attr(stage0, feature(try_trait))]
+#![feature(try_trait)]
 
 extern crate arena;
 #[macro_use]
 extern crate rustc_apfloat;
 extern crate byteorder;
 
-#[cfg(stage0)]
-macro_rules! do_catch {
-  ($t:expr) => { (|| ::std::ops::Try::from_ok($t) )() }
-}
-
-#[cfg(not(stage0))]
-macro_rules! do_catch {
-  ($t:expr) => { do catch { $t } }
-}
-
 mod diagnostics;
 
 mod borrow_check;
index b732eeb624c6dd3cefb5e8e61d36e54a5949da74..5af19ab36469677e2a01a3e56adc3d25d634ac45 100644 (file)
 use rustc::mir::*;
 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
 use rustc::mir::traversal::ReversePostorder;
-use rustc::ty::TyCtxt;
+use rustc::ty::{self, TyCtxt};
 use syntax_pos::Span;
 
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 
-use std::iter;
-use std::mem;
-use std::usize;
+use std::{cmp, iter, mem, usize};
 
 /// State of a temporary during collection and promotion.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -150,9 +148,11 @@ pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Local, T
 }
 
 struct Promoter<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     source: &'a mut Mir<'tcx>,
     promoted: Mir<'tcx>,
     temps: &'a mut IndexVec<Local, TempState>,
+    extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>,
 
     /// If true, all nested temps are also kept in the
     /// source MIR, not moved to the promoted MIR.
@@ -288,38 +288,90 @@ fn promote_temp(&mut self, temp: Local) -> Local {
     }
 
     fn promote_candidate(mut self, candidate: Candidate) {
-        let span = self.promoted.span;
-        let new_operand = Operand::Constant(box Constant {
-            span,
-            ty: self.promoted.return_ty(),
-            literal: Literal::Promoted {
+        let mut rvalue = {
+            let promoted = &mut self.promoted;
+            let literal = Literal::Promoted {
                 index: Promoted::new(self.source.promoted.len())
-            }
-        });
-        let mut rvalue = match candidate {
-            Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
-                let ref mut statement = self.source[bb].statements[stmt_idx];
-                match statement.kind {
-                    StatementKind::Assign(_, ref mut rvalue) => {
-                        mem::replace(rvalue, Rvalue::Use(new_operand))
+            };
+            let operand = |ty, span| {
+                promoted.span = span;
+                promoted.local_decls[RETURN_PLACE] =
+                    LocalDecl::new_return_place(ty, span);
+                Operand::Constant(box Constant {
+                    span,
+                    ty,
+                    literal
+                })
+            };
+            let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
+            match candidate {
+                Candidate::Ref(loc) => {
+                    let ref mut statement = blocks[loc.block].statements[loc.statement_index];
+                    match statement.kind {
+                        StatementKind::Assign(_, Rvalue::Ref(r, bk, ref mut place)) => {
+                            // Find the underlying local for this (necessarilly interior) borrow.
+                            // HACK(eddyb) using a recursive function because of mutable borrows.
+                            fn interior_base<'a, 'tcx>(place: &'a mut Place<'tcx>)
+                                                       -> &'a mut Place<'tcx> {
+                                if let Place::Projection(ref mut proj) = *place {
+                                    assert_ne!(proj.elem, ProjectionElem::Deref);
+                                    return interior_base(&mut proj.base);
+                                }
+                                place
+                            }
+                            let place = interior_base(place);
+
+                            let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx);
+                            let ref_ty = self.tcx.mk_ref(r,
+                                ty::TypeAndMut {
+                                    ty,
+                                    mutbl: bk.to_mutbl_lossy()
+                                }
+                            );
+                            let span = statement.source_info.span;
+
+                            // Create a temp to hold the promoted reference.
+                            // This is because `*r` requires `r` to be a local,
+                            // otherwise we would use the `promoted` directly.
+                            let mut promoted_ref = LocalDecl::new_temp(ref_ty, span);
+                            promoted_ref.source_info = statement.source_info;
+                            let promoted_ref = local_decls.push(promoted_ref);
+                            assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
+                            self.extra_statements.push((loc, Statement {
+                                source_info: statement.source_info,
+                                kind: StatementKind::Assign(
+                                    Place::Local(promoted_ref),
+                                    Rvalue::Use(operand(ref_ty, span)),
+                                )
+                            }));
+                            let promoted_place = Place::Local(promoted_ref).deref();
+
+                            Rvalue::Ref(r, bk, mem::replace(place, promoted_place))
+                        }
+                        _ => bug!()
                     }
-                    _ => bug!()
                 }
-            }
-            Candidate::Argument { bb, index } => {
-                match self.source[bb].terminator_mut().kind {
-                    TerminatorKind::Call { ref mut args, .. } => {
-                        Rvalue::Use(mem::replace(&mut args[index], new_operand))
+                Candidate::Argument { bb, index } => {
+                    let terminator = blocks[bb].terminator_mut();
+                    match terminator.kind {
+                        TerminatorKind::Call { ref mut args, .. } => {
+                            let ty = args[index].ty(local_decls, self.tcx);
+                            let span = terminator.source_info.span;
+                            Rvalue::Use(mem::replace(&mut args[index], operand(ty, span)))
+                        }
+                        _ => bug!()
                     }
-                    _ => bug!()
                 }
             }
         };
+
+        assert_eq!(self.new_block(), START_BLOCK);
         self.visit_rvalue(&mut rvalue, Location {
             block: BasicBlock::new(0),
             statement_index: usize::MAX
         });
 
+        let span = self.promoted.span;
         self.assign(RETURN_PLACE, rvalue, span);
         self.source.promoted.push(self.promoted);
     }
@@ -343,43 +395,29 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                                     candidates: Vec<Candidate>) {
     // Visit candidates in reverse, in case they're nested.
     debug!("promote_candidates({:?})", candidates);
+
+    let mut extra_statements = vec![];
     for candidate in candidates.into_iter().rev() {
-        let (span, ty) = match candidate {
-            Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
-                let statement = &mir[bb].statements[stmt_idx];
-                let dest = match statement.kind {
-                    StatementKind::Assign(ref dest, _) => dest,
-                    _ => {
-                        span_bug!(statement.source_info.span,
-                                  "expected assignment to promote");
-                    }
-                };
-                if let Place::Local(index) = *dest {
-                    if temps[index] == TempState::PromotedOut {
-                        // Already promoted.
-                        continue;
+        match candidate {
+            Candidate::Ref(Location { block, statement_index }) => {
+                match mir[block].statements[statement_index].kind {
+                    StatementKind::Assign(Place::Local(local), _) => {
+                        if temps[local] == TempState::PromotedOut {
+                            // Already promoted.
+                            continue;
+                        }
                     }
+                    _ => {}
                 }
-                (statement.source_info.span, dest.ty(mir, tcx).to_ty(tcx))
-            }
-            Candidate::Argument { bb, index } => {
-                let terminator = mir[bb].terminator();
-                let ty = match terminator.kind {
-                    TerminatorKind::Call { ref args, .. } => {
-                        args[index].ty(mir, tcx)
-                    }
-                    _ => {
-                        span_bug!(terminator.source_info.span,
-                                  "expected call argument to promote");
-                    }
-                };
-                (terminator.source_info.span, ty)
             }
-        };
+            Candidate::Argument { .. } => {}
+        }
+
 
-        // Declare return place local
-        let initial_locals = iter::once(LocalDecl::new_return_place(ty, span))
-            .collect();
+        // Declare return place local so that `Mir::new` doesn't complain.
+        let initial_locals = iter::once(
+            LocalDecl::new_return_place(tcx.types.never, mir.span)
+        ).collect();
 
         let mut promoter = Promoter {
             promoted: Mir::new(
@@ -393,16 +431,24 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
                 initial_locals,
                 0,
                 vec![],
-                span
+                mir.span
             ),
+            tcx,
             source: mir,
             temps: &mut temps,
+            extra_statements: &mut extra_statements,
             keep_original: false
         };
-        assert_eq!(promoter.new_block(), START_BLOCK);
         promoter.promote_candidate(candidate);
     }
 
+    // Insert each of `extra_statements` before its indicated location, which
+    // has to be done in reverse location order, to not invalidate the rest.
+    extra_statements.sort_by_key(|&(loc, _)| cmp::Reverse(loc));
+    for (loc, statement) in extra_statements {
+        mir[loc.block].statements.insert(loc.statement_index, statement);
+    }
+
     // Eliminate assignments to, and drops of promoted temps.
     let promoted = |index: Local| temps[index] == TempState::PromotedOut;
     for block in mir.basic_blocks_mut() {
index 28ab3d6a8574fb3543cf27bc40e15f42192cb97d..fd4ba1d75625a0787bd097f28f9d57fa31a818d5 100644 (file)
@@ -229,12 +229,12 @@ fn nest<F: FnOnce(&mut Self)>(&mut self, f: F) {
     }
 
     /// Check if a Local with the current qualifications is promotable.
-    fn can_promote(&mut self) -> bool {
+    fn can_promote(&self, qualif: Qualif) -> bool {
         // References to statics are allowed, but only in other statics.
         if self.mode == Mode::Static || self.mode == Mode::StaticMut {
-            (self.qualif - Qualif::STATIC_REF).is_empty()
+            (qualif - Qualif::STATIC_REF).is_empty()
         } else {
-            self.qualif.is_empty()
+            qualif.is_empty()
         }
     }
 
@@ -679,24 +679,31 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                 }
 
                 let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
+
+                // Default to forbidding the borrow and/or its promotion,
+                // due to the potential for direct or interior mutability,
+                // and only proceed by setting `forbidden_mut` to `false`.
+                let mut forbidden_mut = true;
+
                 if let BorrowKind::Mut { .. } = kind {
                     // In theory, any zero-sized value could be borrowed
                     // mutably without consequences. However, only &mut []
                     // is allowed right now, and only in functions.
-                    let allow = if self.mode == Mode::StaticMut {
+                    if self.mode == Mode::StaticMut {
                         // Inside a `static mut`, &mut [...] is also allowed.
                         match ty.sty {
-                            ty::TyArray(..) | ty::TySlice(_) => true,
-                            _ => false
+                            ty::TyArray(..) | ty::TySlice(_) => forbidden_mut = false,
+                            _ => {}
                         }
                     } else if let ty::TyArray(_, len) = ty.sty {
-                        len.unwrap_usize(self.tcx) == 0 &&
-                            self.mode == Mode::Fn
-                    } else {
-                        false
-                    };
+                        // FIXME(eddyb) the `self.mode == Mode::Fn` condition
+                        // seems unnecessary, given that this is merely a ZST.
+                        if len.unwrap_usize(self.tcx) == 0 && self.mode == Mode::Fn {
+                            forbidden_mut = false;
+                        }
+                    }
 
-                    if !allow {
+                    if forbidden_mut {
                         self.add(Qualif::NOT_CONST);
                         if self.mode != Mode::Fn {
                             let mut err = struct_span_err!(self.tcx.sess,  self.span, E0017,
@@ -722,25 +729,46 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
                     // it means that our "silent insertion of statics" could change
                     // initializer values (very bad).
                     if self.qualif.intersects(Qualif::MUTABLE_INTERIOR) {
-                        // Replace MUTABLE_INTERIOR with NOT_CONST to avoid
+                        // A reference of a MUTABLE_INTERIOR place is instead
+                        // NOT_CONST (see `if forbidden_mut` below), to avoid
                         // duplicate errors (from reborrowing, for example).
                         self.qualif = self.qualif - Qualif::MUTABLE_INTERIOR;
-                        self.add(Qualif::NOT_CONST);
                         if self.mode != Mode::Fn {
                             span_err!(self.tcx.sess, self.span, E0492,
                                       "cannot borrow a constant which may contain \
                                        interior mutability, create a static instead");
                         }
+                    } else {
+                        // We allow immutable borrows of frozen data.
+                        forbidden_mut = false;
                     }
                 }
 
-                // We might have a candidate for promotion.
-                let candidate = Candidate::Ref(location);
-                if self.can_promote() {
-                    // We can only promote direct borrows of temps.
+                if forbidden_mut {
+                    self.add(Qualif::NOT_CONST);
+                } else {
+                    // We might have a candidate for promotion.
+                    let candidate = Candidate::Ref(location);
+                    // We can only promote interior borrows of promotable temps.
+                    let mut place = place;
+                    while let Place::Projection(ref proj) = *place {
+                        if proj.elem == ProjectionElem::Deref {
+                            break;
+                        }
+                        place = &proj.base;
+                    }
                     if let Place::Local(local) = *place {
                         if self.mir.local_kind(local) == LocalKind::Temp {
-                            self.promotion_candidates.push(candidate);
+                            if let Some(qualif) = self.temp_qualif[local] {
+                                // `forbidden_mut` is false, so we can safely ignore
+                                // `MUTABLE_INTERIOR` from the local's qualifications.
+                                // This allows borrowing fields which don't have
+                                // `MUTABLE_INTERIOR`, from a type that does, e.g.:
+                                // `let _: &'static _ = &(Cell::new(1), 2).1;`
+                                if self.can_promote(qualif - Qualif::MUTABLE_INTERIOR) {
+                                    self.promotion_candidates.push(candidate);
+                                }
+                            }
                         }
                     }
                 }
@@ -897,7 +925,7 @@ fn visit_terminator_kind(&mut self,
                     }
                     let candidate = Candidate::Argument { bb, index: i };
                     if is_shuffle && i == 2 {
-                        if this.can_promote() {
+                        if this.can_promote(this.qualif) {
                             this.promotion_candidates.push(candidate);
                         } else {
                             span_err!(this.tcx.sess, this.span, E0526,
@@ -913,7 +941,7 @@ fn visit_terminator_kind(&mut self,
                     if !constant_arguments.contains(&i) {
                         return
                     }
-                    if this.can_promote() {
+                    if this.can_promote(this.qualif) {
                         this.promotion_candidates.push(candidate);
                     } else {
                         this.tcx.sess.span_err(this.span,
index 9d74ad0830f0c236178cc1227b48e0a81ac1fa45..9e1ce9b2851dea4f01e813acfcb721c8b7dd8d58 100644 (file)
@@ -137,7 +137,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
 ) where
     F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>,
 {
-    let _: io::Result<()> = do_catch! {{
+    let _: io::Result<()> = do catch {
         let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?;
         writeln!(file, "// MIR for `{}`", node_path)?;
         writeln!(file, "// source = {:?}", source)?;
@@ -150,14 +150,14 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>(
         extra_data(PassWhere::BeforeCFG, &mut file)?;
         write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?;
         extra_data(PassWhere::AfterCFG, &mut file)?;
-    }};
+    };
 
     if tcx.sess.opts.debugging_opts.dump_mir_graphviz {
-        let _: io::Result<()> = do_catch! {{
+        let _: io::Result<()> = do catch {
             let mut file =
                 create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?;
             write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?;
-        }};
+        };
     }
 }
 
index 4789e2e50ca540cc2d99f565b4bb330c07652302..4f239a0868ebfaa87e49086f779ffae35c2df58d 100644 (file)
@@ -21,7 +21,6 @@
 use syntax::ast::*;
 use syntax::attr;
 use syntax::codemap::Spanned;
-use syntax::parse::token;
 use syntax::symbol::keywords;
 use syntax::visit::{self, Visitor};
 use syntax_pos::Span;
@@ -40,14 +39,13 @@ fn check_lifetime(&self, ident: Ident) {
         let valid_names = [keywords::UnderscoreLifetime.name(),
                            keywords::StaticLifetime.name(),
                            keywords::Invalid.name()];
-        if !valid_names.contains(&ident.name) &&
-            token::is_reserved_ident(ident.without_first_quote()) {
+        if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
             self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
         }
     }
 
     fn check_label(&self, ident: Ident) {
-        if token::is_reserved_ident(ident.without_first_quote()) {
+        if ident.without_first_quote().is_reserved() {
             self.err_handler()
                 .span_err(ident.span, &format!("invalid label name `{}`", ident.name));
         }
index 7e3c411c1d2474d920d3cd2806dbde6672e4a86b..ea15f4c75b96c73bb0bd7336242812ac7be2f398 100644 (file)
@@ -15,6 +15,7 @@
 
 use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT};
 use syntax::ext::base::MacroExpanderFn;
+use syntax::ext::hygiene;
 use syntax::symbol::Symbol;
 use syntax::ast;
 use syntax::feature_gate::AttributeType;
@@ -107,7 +108,8 @@ pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxEx
                 def_info: _,
                 allow_internal_unstable,
                 allow_internal_unsafe,
-                unstable_feature
+                unstable_feature,
+                edition,
             } => {
                 let nid = ast::CRATE_NODE_ID;
                 NormalTT {
@@ -115,7 +117,8 @@ pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxEx
                     def_info: Some((nid, self.krate_span)),
                     allow_internal_unstable,
                     allow_internal_unsafe,
-                    unstable_feature
+                    unstable_feature,
+                    edition,
                 }
             }
             IdentTT(ext, _, allow_internal_unstable) => {
@@ -150,6 +153,7 @@ pub fn register_macro(&mut self, name: &str, expander: MacroExpanderFn) {
             allow_internal_unstable: false,
             allow_internal_unsafe: false,
             unstable_feature: None,
+            edition: hygiene::default_edition(),
         });
     }
 
index ef5cc95828372f46f5499c65913324a001a3b11f..d3cc533cd36a460661ab60423b3d317c12ed086b 100644 (file)
@@ -588,7 +588,8 @@ pub fn get_macro(&mut self, def: Def) -> Lrc<SyntaxExtension> {
 
         let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
                                                &self.session.features_untracked(),
-                                               &macro_def));
+                                               &macro_def,
+                                               self.cstore.crate_edition_untracked(def_id.krate)));
         self.macro_map.insert(def_id, ext.clone());
         ext
     }
index 5a5f5ce2e3862ced35e702215ad345e9eff85919..e13e6bc6b745677f9b60009920a89a60626102b5 100644 (file)
@@ -58,7 +58,6 @@
 use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
 use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
 use syntax::feature_gate::{feature_err, GateIssue};
-use syntax::parse::token;
 use syntax::ptr::P;
 
 use syntax_pos::{Span, DUMMY_SP, MultiSpan};
@@ -3274,7 +3273,7 @@ fn resolve_path(&mut self,
                     // `$crate::a::b`
                     module = Some(self.resolve_crate_root(ident.span.ctxt(), true));
                     continue
-                } else if i == 1 && !token::is_path_segment_keyword(ident) {
+                } else if i == 1 && !ident.is_path_segment_keyword() {
                     let prev_name = path[0].name;
                     if prev_name == keywords::Extern.name() ||
                        prev_name == keywords::CrateRoot.name() &&
index 4afc621ad8b3e2751c8d6cccd2daac8ef9c2e51b..0fc963a1367126180e043a40fdf953063dda190b 100644 (file)
@@ -24,7 +24,7 @@
 use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator};
 use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
 use syntax::ext::expand::{Expansion, ExpansionKind, Invocation, InvocationKind, find_attr_invoc};
-use syntax::ext::hygiene::{Mark, MarkKind};
+use syntax::ext::hygiene::{self, Mark, MarkKind};
 use syntax::ext::placeholders::placeholder;
 use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{self, emit_feature_err, GateIssue};
@@ -328,7 +328,7 @@ fn check_unused_macros(&self) {
         for did in self.unused_macros.iter() {
             let id_span = match *self.macro_map[did] {
                 SyntaxExtension::NormalTT { def_info, .. } => def_info,
-                SyntaxExtension::DeclMacro(.., osp) => osp,
+                SyntaxExtension::DeclMacro(.., osp, _) => osp,
                 _ => None,
             };
             if let Some((id, span)) = id_span {
@@ -371,7 +371,7 @@ fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: b
         };
         for path in traits {
             match self.resolve_macro(scope, path, MacroKind::Derive, force) {
-                Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext {
+                Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
                     if inert_attrs.contains(&attr_name) {
                         // FIXME(jseyfried) Avoid `mem::replace` here.
                         let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
@@ -755,7 +755,7 @@ pub fn define_macro(&mut self,
         let def_id = self.definitions.local_def_id(item.id);
         let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
                                                &self.session.features_untracked(),
-                                               item));
+                                               item, hygiene::default_edition()));
         self.macro_map.insert(def_id, ext);
 
         let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() };
@@ -803,14 +803,15 @@ fn err_if_macro_use_proc_macro(&mut self, name: Name, use_span: Span,
 
         match *ext {
             // If `ext` is a procedural macro, check if we've already warned about it
-            AttrProcMacro(_) | ProcMacro(_) => if !self.warned_proc_macros.insert(name) { return; },
+            AttrProcMacro(..) | ProcMacro(..) =>
+                if !self.warned_proc_macros.insert(name) { return; },
             _ => return,
         }
 
         let warn_msg = match *ext {
-            AttrProcMacro(_) => "attribute procedural macros cannot be \
-                                 imported with `#[macro_use]`",
-            ProcMacro(_) => "procedural macros cannot be imported with `#[macro_use]`",
+            AttrProcMacro(..) => "attribute procedural macros cannot be \
+                                  imported with `#[macro_use]`",
+            ProcMacro(..) => "procedural macros cannot be imported with `#[macro_use]`",
             _ => return,
         };
 
index 09c421fba47b1abb5140bc962e5a10181e688434..16d5d3fa0437f3dec6d0b5e977918d5bc9948ef6 100644 (file)
@@ -27,7 +27,6 @@
 use syntax::ast::{Ident, Name, NodeId};
 use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
 use syntax::ext::hygiene::Mark;
-use syntax::parse::token;
 use syntax::symbol::keywords;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::Span;
@@ -667,7 +666,7 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa
                         } else {
                             Some(self.resolve_crate_root(source.span.ctxt().modern(), false))
                         }
-                    } else if is_extern && !token::is_path_segment_keyword(source) {
+                    } else if is_extern && !source.is_path_segment_keyword() {
                         let crate_id =
                             self.resolver.crate_loader.process_use_extern(
                                 source.name,
@@ -715,8 +714,8 @@ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Spa
             }
             PathResult::Failed(span, msg, true) => {
                 let (mut self_path, mut self_result) = (module_path.clone(), None);
-                let is_special = |ident| token::is_path_segment_keyword(ident) &&
-                                         ident.name != keywords::CrateRoot.name();
+                let is_special = |ident: Ident| ident.is_path_segment_keyword() &&
+                                                ident.name != keywords::CrateRoot.name();
                 if !self_path.is_empty() && !is_special(self_path[0]) &&
                    !(self_path.len() > 1 && is_special(self_path[1])) {
                     self_path[0].name = keywords::SelfValue.name();
index 45f2ee13bbdc94e29f5e5922564f24314351d1ff..8f4911574398ba84d2f6874f334e371d8e93666f 100644 (file)
@@ -29,7 +29,6 @@
 #![feature(const_fn)]
 #![feature(fs_read_write)]
 #![feature(inclusive_range)]
-#![feature(inclusive_range_methods)]
 #![feature(slice_patterns)]
 
 #[macro_use]
index 8fc00c937e69c18fb393d40e3721ad55e9a481c5..a9ac53972e4756cad51c3490b767a73936b89b10 100644 (file)
@@ -9,8 +9,7 @@
 // except according to those terms.
 
 use rustc::infer::canonical::{Canonical, QueryResult};
-use rustc::traits::{self, FulfillmentContext, Normalized, ObligationCause,
-                    SelectionContext};
+use rustc::traits::{self, FulfillmentContext, ObligationCause, SelectionContext};
 use rustc::traits::query::{CanonicalProjectionGoal, NoSolution, normalize::NormalizationResult};
 use rustc::ty::{ParamEnvAnd, TyCtxt};
 use rustc_data_structures::sync::Lrc;
         let fulfill_cx = &mut FulfillmentContext::new();
         let selcx = &mut SelectionContext::new(infcx);
         let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID);
-        let Normalized {
-            value: answer,
-            obligations,
-        } = traits::normalize_projection_type(selcx, param_env, goal, cause, 0);
+        let mut obligations = vec![];
+        let answer =
+            traits::normalize_projection_type(selcx, param_env, goal, cause, 0, &mut obligations);
         fulfill_cx.register_predicate_obligations(infcx, obligations);
 
         // Now that we have fulfilled as much as we can, create a solution
index e1ce6073ce43698e0947d77b9be65e7dcc8bb9d8..4274e5c1e1f7562d75d70d54059f5f758b3c68ac 100644 (file)
@@ -129,20 +129,20 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         }
 
         let mut selcx = traits::SelectionContext::new(self.fcx);
-        let normalized = traits::normalize_projection_type(&mut selcx,
-                                                           self.fcx.param_env,
-                                                           ty::ProjectionTy::from_ref_and_name(
-                                                               tcx,
-                                                               trait_ref,
-                                                               Symbol::intern("Target"),
-                                                           ),
-                                                           cause,
-                                                           0);
-
-        debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized);
-        self.obligations.extend(normalized.obligations);
-
-        Some(self.fcx.resolve_type_vars_if_possible(&normalized.value))
+        let normalized_ty = traits::normalize_projection_type(&mut selcx,
+                                                              self.fcx.param_env,
+                                                              ty::ProjectionTy::from_ref_and_name(
+                                                                  tcx,
+                                                                  trait_ref,
+                                                                  Symbol::intern("Target"),
+                                                              ),
+                                                              cause,
+                                                              0,
+                                                              &mut self.obligations);
+
+        debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized_ty);
+
+        Some(self.fcx.resolve_type_vars_if_possible(&normalized_ty))
     }
 
     /// Returns the final type, generating an error if it is an
index feb26e76162573dab1cad4d7f546057e721d72cd..af1f1044edf2f79c5586f8110067c7e3c7a141ef 100644 (file)
@@ -314,11 +314,6 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
             }
 
-            "align_offset" => {
-                let ptr_ty = tcx.mk_imm_ptr(tcx.mk_nil());
-                (0, vec![ptr_ty, tcx.types.usize], tcx.types.usize)
-            },
-
             "nontemporal_store" => {
                 (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil())
             }
index 350b53a406bc885268e54a37783b1c381fa79ce5..ef79517d06a4577f936f354035ecf0381687ae6a 100644 (file)
@@ -71,8 +71,6 @@
 
 #![allow(non_camel_case_types)]
 
-#![cfg_attr(stage0, feature(dyn_trait))]
-
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
index d7646ce7bfc5ca4fb24dded85c7ca43bfb765438..73a7e0e690fe92399e9ced4f24d6f0d870fe980d 100644 (file)
@@ -35,10 +35,29 @@ pub fn get_with_def_id(&self, def_id: DefId) -> Vec<Item> {
                 AdtKind::Enum => Def::Enum,
                 AdtKind::Union => Def::Union,
             }
-            _ => panic!("Unexpected type {:?}", def_id),
+            ty::TyInt(_) |
+            ty::TyUint(_) |
+            ty::TyFloat(_) |
+            ty::TyStr |
+            ty::TyBool |
+            ty::TyChar => return self.get_auto_trait_impls(def_id, &move |_: DefId| {
+                match ty.sty {
+                    ty::TyInt(x) => Def::PrimTy(hir::TyInt(x)),
+                    ty::TyUint(x) => Def::PrimTy(hir::TyUint(x)),
+                    ty::TyFloat(x) => Def::PrimTy(hir::TyFloat(x)),
+                    ty::TyStr => Def::PrimTy(hir::TyStr),
+                    ty::TyBool => Def::PrimTy(hir::TyBool),
+                    ty::TyChar => Def::PrimTy(hir::TyChar),
+                    _ => unreachable!(),
+                }
+            }, None),
+            _ => {
+                debug!("Unexpected type {:?}", def_id);
+                return Vec::new()
+            }
         };
 
-        self.get_auto_trait_impls(def_id, def_ctor, None)
+        self.get_auto_trait_impls(def_id, &def_ctor, None)
     }
 
     pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec<Item> {
@@ -52,15 +71,16 @@ pub fn get_with_node_id(&self, id: ast::NodeId, name: String) -> Vec<Item> {
             _ => panic!("Unexpected type {:?} {:?}", item, id),
         };
 
-        self.get_auto_trait_impls(did, def_ctor, Some(name))
+        self.get_auto_trait_impls(did, &def_ctor, Some(name))
     }
 
-    pub fn get_auto_trait_impls(
+    pub fn get_auto_trait_impls<F>(
         &self,
         def_id: DefId,
-        def_ctor: fn(DefId) -> Def,
+        def_ctor: &F,
         name: Option<String>,
-    ) -> Vec<Item> {
+    ) -> Vec<Item>
+    where F: Fn(DefId) -> Def {
         if self.cx
             .tcx
             .get_attrs(def_id)
@@ -68,9 +88,9 @@ pub fn get_auto_trait_impls(
             .has_word("hidden")
         {
             debug!(
-                "get_auto_trait_impls(def_id={:?}, def_ctor={:?}): item has doc('hidden'), \
+                "get_auto_trait_impls(def_id={:?}, def_ctor=...): item has doc('hidden'), \
                  aborting",
-                def_id, def_ctor
+                def_id
             );
             return Vec::new();
         }
@@ -79,8 +99,8 @@ pub fn get_auto_trait_impls(
         let generics = self.cx.tcx.generics_of(def_id);
 
         debug!(
-            "get_auto_trait_impls(def_id={:?}, def_ctor={:?}, generics={:?}",
-            def_id, def_ctor, generics
+            "get_auto_trait_impls(def_id={:?}, def_ctor=..., generics={:?}",
+            def_id, generics
         );
         let auto_traits: Vec<_> = self.cx
             .send_trait
@@ -110,23 +130,24 @@ pub fn get_auto_trait_impls(
         auto_traits
     }
 
-    fn get_auto_trait_impl_for(
+    fn get_auto_trait_impl_for<F>(
         &self,
         def_id: DefId,
         name: Option<String>,
         generics: ty::Generics,
-        def_ctor: fn(DefId) -> Def,
+        def_ctor: &F,
         trait_def_id: DefId,
-    ) -> Option<Item> {
+    ) -> Option<Item>
+    where F: Fn(DefId) -> Def {
         if !self.cx
             .generated_synthetics
             .borrow_mut()
             .insert((def_id, trait_def_id))
         {
             debug!(
-                "get_auto_trait_impl_for(def_id={:?}, generics={:?}, def_ctor={:?}, \
+                "get_auto_trait_impl_for(def_id={:?}, generics={:?}, def_ctor=..., \
                  trait_def_id={:?}): already generated, aborting",
-                def_id, generics, def_ctor, trait_def_id
+                def_id, generics, trait_def_id
             );
             return None;
         }
index a8f4848bf89f2a0394aadc9b6bdd7863e827631d..da04068107d3f7088133d4ccc5d025f0768a515a 100644 (file)
@@ -302,6 +302,14 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean:
     for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
         if !def_id.is_local() {
             build_impl(cx, def_id, &mut impls);
+
+            let auto_impls = get_auto_traits_with_def_id(cx, def_id);
+            let mut renderinfo = cx.renderinfo.borrow_mut();
+
+            let new_impls: Vec<clean::Item> = auto_impls.into_iter()
+                .filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
+
+            impls.extend(new_impls);
         }
     }
 
index c233e57a8018eb5af05b226117be975b99f3d4e7..6beb64dced16ea1a7ea16ca8f24380fba381f7a1 100644 (file)
@@ -4183,7 +4183,8 @@ pub fn path_to_def(tcx: &TyCtxt, path: &[&str]) -> Option<DefId> {
     }
 }
 
-fn get_path_for_type(tcx: TyCtxt, def_id: DefId, def_ctor: fn(DefId) -> Def) -> hir::Path {
+fn get_path_for_type<F>(tcx: TyCtxt, def_id: DefId, def_ctor: F) -> hir::Path
+where F: Fn(DefId) -> Def {
     struct AbsolutePathBuffer {
         names: Vec<String>,
     }
index 3ce95c78a9000bba69587e3e96e0523a5040fa26..1b713a446a0ec7af0492dae4583d965e95a0b469 100644 (file)
@@ -13,8 +13,6 @@
        html_root_url = "https://doc.rust-lang.org/nightly/",
        html_playground_url = "https://play.rust-lang.org/")]
 
-#![cfg_attr(stage0, feature(dyn_trait))]
-
 #![feature(ascii_ctype)]
 #![feature(rustc_private)]
 #![feature(box_patterns)]
index a8578404467b1d3185b4322abf2eb2ed9374f748..78d3d6d5e60cc6e4a3b4c895ed41664d34f48ff6 100644 (file)
@@ -17,7 +17,6 @@
 #[doc(inline)] pub use alloc_system::System;
 #[doc(inline)] pub use core::alloc::*;
 
-#[cfg(not(stage0))]
 #[cfg(not(test))]
 #[doc(hidden)]
 #[lang = "oom"]
@@ -43,13 +42,6 @@ pub mod __default_lib_allocator {
         System.alloc(layout) as *mut u8
     }
 
-    #[cfg(stage0)]
-    #[no_mangle]
-    #[rustc_std_internal_symbol]
-    pub unsafe extern fn __rdl_oom() -> ! {
-        super::oom()
-    }
-
     #[no_mangle]
     #[rustc_std_internal_symbol]
     pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
@@ -74,57 +66,4 @@ pub mod __default_lib_allocator {
         let layout = Layout::from_size_align_unchecked(size, align);
         System.alloc_zeroed(layout) as *mut u8
     }
-
-    #[cfg(stage0)]
-    pub mod stage0 {
-        #[no_mangle]
-        #[rustc_std_internal_symbol]
-        pub unsafe extern fn __rdl_usable_size(_layout: *const u8,
-                                               _min: *mut usize,
-                                               _max: *mut usize) {
-            unimplemented!()
-        }
-
-        #[no_mangle]
-        #[rustc_std_internal_symbol]
-        pub unsafe extern fn __rdl_alloc_excess(_size: usize,
-                                                _align: usize,
-                                                _excess: *mut usize,
-                                                _err: *mut u8) -> *mut u8 {
-            unimplemented!()
-        }
-
-        #[no_mangle]
-        #[rustc_std_internal_symbol]
-        pub unsafe extern fn __rdl_realloc_excess(_ptr: *mut u8,
-                                                  _old_size: usize,
-                                                  _old_align: usize,
-                                                  _new_size: usize,
-                                                  _new_align: usize,
-                                                  _excess: *mut usize,
-                                                  _err: *mut u8) -> *mut u8 {
-            unimplemented!()
-        }
-
-        #[no_mangle]
-        #[rustc_std_internal_symbol]
-        pub unsafe extern fn __rdl_grow_in_place(_ptr: *mut u8,
-                                                 _old_size: usize,
-                                                 _old_align: usize,
-                                                 _new_size: usize,
-                                                 _new_align: usize) -> u8 {
-            unimplemented!()
-        }
-
-        #[no_mangle]
-        #[rustc_std_internal_symbol]
-        pub unsafe extern fn __rdl_shrink_in_place(_ptr: *mut u8,
-                                                   _old_size: usize,
-                                                   _old_align: usize,
-                                                   _new_size: usize,
-                                                   _new_align: usize) -> u8 {
-            unimplemented!()
-        }
-
-    }
 }
index 7314d32b0206afaf21f55ca3a4cc925a0bf6bd2a..ae30321f46dfca4ed02c039e88b7ce28028c62d5 100644 (file)
 #![stable(feature = "rust1", since = "1.0.0")]
 #![allow(missing_docs)]
 
-#[cfg(not(test))]
-#[cfg(stage0)]
-use core::num::Float;
 #[cfg(not(test))]
 use intrinsics;
 #[cfg(not(test))]
-#[cfg(stage0)]
-use num::FpCategory;
-#[cfg(not(test))]
 use sys::cmath;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::f32::consts;
 
 #[cfg(not(test))]
-#[cfg_attr(stage0, lang = "f32")]
-#[cfg_attr(not(stage0), lang = "f32_runtime")]
+#[lang = "f32_runtime"]
 impl f32 {
-    #[cfg(stage0)]
-    f32_core_methods!();
-
     /// Returns the largest integer less than or equal to a number.
     ///
     /// # Examples
index 75edba8979f9a1993515bf2c492381e61a5d13e5..7950d434b77e67a5c7302fdafc42c855965e0527 100644 (file)
 #![stable(feature = "rust1", since = "1.0.0")]
 #![allow(missing_docs)]
 
-#[cfg(not(test))]
-#[cfg(stage0)]
-use core::num::Float;
 #[cfg(not(test))]
 use intrinsics;
 #[cfg(not(test))]
-#[cfg(stage0)]
-use num::FpCategory;
-#[cfg(not(test))]
 use sys::cmath;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::f64::consts;
 
 #[cfg(not(test))]
-#[cfg_attr(stage0, lang = "f64")]
-#[cfg_attr(not(stage0), lang = "f64_runtime")]
+#[lang = "f64_runtime"]
 impl f64 {
-    #[cfg(stage0)]
-    f64_core_methods!();
-
     /// Returns the largest integer less than or equal to a number.
     ///
     /// # Examples
index 9cdc6a21622467af00052f3b006b99c20b71e7a9..f7d06852f27937f61ef7e9beea6083f118a1bb87 100644 (file)
 #![feature(collections_range)]
 #![feature(compiler_builtins_lib)]
 #![feature(const_fn)]
-#![cfg_attr(stage0, feature(core_float))]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(exact_size_is_empty)]
 #![feature(fs_read_write)]
 #![feature(fixed_size_array)]
 #![feature(float_from_str_radix)]
-#![cfg_attr(stage0, feature(float_internals))]
 #![feature(fn_traits)]
 #![feature(fnbox)]
-#![cfg_attr(stage0, feature(generic_param_attrs))]
 #![feature(hashmap_internals)]
 #![feature(heap_api)]
 #![feature(int_error_internals)]
 #![cfg_attr(test, feature(update_panic_count))]
 #![cfg_attr(windows, feature(used))]
 #![feature(doc_alias)]
+#![feature(float_internals)]
 
 #![default_lib_allocator]
 
 #[allow(unused_extern_crates)]
 extern crate unwind;
 
-// compiler-rt intrinsics
-#[doc(masked)]
-#[cfg(stage0)]
-extern crate compiler_builtins;
-
 // During testing, this crate is not actually the "real" std library, but rather
 // it links to the real std library, which was compiled from this same source
 // code. So any lang items std defines are conditionally excluded (or else they
index 2b6635ec7831f09da58276e7206a310cce4e2a3a..1817726d6a110bfc5367bd1bbd89e07dcf9cd72d 100644 (file)
@@ -107,8 +107,7 @@ pub fn from_ident(ident: Ident) -> Path {
     // or starts with something like `self`/`super`/`$crate`/etc.
     pub fn make_root(&self) -> Option<PathSegment> {
         if let Some(ident) = self.segments.get(0).map(|seg| seg.ident) {
-            if ::parse::token::is_path_segment_keyword(ident) &&
-               ident.name != keywords::Crate.name() {
+            if ident.is_path_segment_keyword() && ident.name != keywords::Crate.name() {
                 return None;
             }
         }
diff --git a/src/libsyntax/edition.rs b/src/libsyntax/edition.rs
deleted file mode 100644 (file)
index c98b545..0000000
+++ /dev/null
@@ -1,82 +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.
-
-use std::fmt;
-use std::str::FromStr;
-
-/// The edition of the compiler (RFC 2052)
-#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug)]
-#[non_exhaustive]
-pub enum Edition {
-    // editions must be kept in order, newest to oldest
-
-    /// The 2015 edition
-    Edition2015,
-    /// The 2018 edition
-    Edition2018,
-
-    // when adding new editions, be sure to update:
-    //
-    // - Update the `ALL_EDITIONS` const
-    // - Update the EDITION_NAME_LIST const
-    // - add a `rust_####()` function to the session
-    // - update the enum in Cargo's sources as well
-}
-
-// must be in order from oldest to newest
-pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];
-
-pub const EDITION_NAME_LIST: &'static str = "2015|2018";
-
-pub const DEFAULT_EDITION: Edition = Edition::Edition2015;
-
-impl fmt::Display for Edition {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let s = match *self {
-            Edition::Edition2015 => "2015",
-            Edition::Edition2018 => "2018",
-        };
-        write!(f, "{}", s)
-    }
-}
-
-impl Edition {
-    pub fn lint_name(&self) -> &'static str {
-        match *self {
-            Edition::Edition2015 => "rust_2015_compatibility",
-            Edition::Edition2018 => "rust_2018_compatibility",
-        }
-    }
-
-    pub fn feature_name(&self) -> &'static str {
-        match *self {
-            Edition::Edition2015 => "rust_2015_preview",
-            Edition::Edition2018 => "rust_2018_preview",
-        }
-    }
-
-    pub fn is_stable(&self) -> bool {
-        match *self {
-            Edition::Edition2015 => true,
-            Edition::Edition2018 => false,
-        }
-    }
-}
-
-impl FromStr for Edition {
-    type Err = ();
-    fn from_str(s: &str) -> Result<Self, ()> {
-        match s {
-            "2015" => Ok(Edition::Edition2015),
-            "2018" => Ok(Edition::Edition2018),
-            _ => Err(())
-        }
-    }
-}
index 3b76084f2fbe5cd7d8d2e22bafdab9fbcdf8f1eb..f7d4227977c834ebd7defa449137df221d689f01 100644 (file)
 use attr::HasAttrs;
 use codemap::{self, CodeMap, Spanned, respan};
 use syntax_pos::{Span, MultiSpan, DUMMY_SP};
+use edition::Edition;
 use errors::{DiagnosticBuilder, DiagnosticId};
 use ext::expand::{self, Expansion, Invocation};
-use ext::hygiene::{Mark, SyntaxContext};
+use ext::hygiene::{self, Mark, SyntaxContext};
 use fold::{self, Folder};
 use parse::{self, parser, DirectoryOwnership};
 use parse::token;
@@ -586,13 +587,13 @@ pub enum SyntaxExtension {
     MultiModifier(Box<MultiItemModifier + sync::Sync + sync::Send>),
 
     /// A function-like procedural macro. TokenStream -> TokenStream.
-    ProcMacro(Box<ProcMacro + sync::Sync + sync::Send>),
+    ProcMacro(Box<ProcMacro + sync::Sync + sync::Send>, Edition),
 
     /// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream.
     /// The first TokenSteam is the attribute, the second is the annotated item.
     /// Allows modification of the input items and adding new items, similar to
     /// MultiModifier, but uses TokenStreams, rather than AST nodes.
-    AttrProcMacro(Box<AttrProcMacro + sync::Sync + sync::Send>),
+    AttrProcMacro(Box<AttrProcMacro + sync::Sync + sync::Send>, Edition),
 
     /// A normal, function-like syntax extension.
     ///
@@ -608,6 +609,8 @@ pub enum SyntaxExtension {
         allow_internal_unsafe: bool,
         /// The macro's feature name if it is unstable, and the stability feature
         unstable_feature: Option<(Symbol, u32)>,
+        /// Edition of the crate in which the macro is defined
+        edition: Edition,
     },
 
     /// A function-like syntax extension that has an extra ident before
@@ -619,9 +622,8 @@ pub enum SyntaxExtension {
     /// The input is the annotated item.
     /// Allows generating code to implement a Trait for a given struct
     /// or enum item.
-    ProcMacroDerive(Box<MultiItemModifier +
-                        sync::Sync +
-                        sync::Send>, Vec<Symbol> /* inert attribute names */),
+    ProcMacroDerive(Box<MultiItemModifier + sync::Sync + sync::Send>,
+                    Vec<Symbol> /* inert attribute names */, Edition),
 
     /// An attribute-like procedural macro that derives a builtin trait.
     BuiltinDerive(BuiltinDeriveFn),
@@ -629,7 +631,7 @@ pub enum SyntaxExtension {
     /// A declarative macro, e.g. `macro m() {}`.
     ///
     /// The second element is the definition site span.
-    DeclMacro(Box<TTMacroExpander + sync::Sync + sync::Send>, Option<(ast::NodeId, Span)>),
+    DeclMacro(Box<TTMacroExpander + sync::Sync + sync::Send>, Option<(ast::NodeId, Span)>, Edition),
 }
 
 impl SyntaxExtension {
@@ -660,6 +662,21 @@ pub fn is_modern(&self) -> bool {
             _ => false,
         }
     }
+
+    pub fn edition(&self) -> Edition {
+        match *self {
+            SyntaxExtension::NormalTT { edition, .. } |
+            SyntaxExtension::DeclMacro(.., edition) |
+            SyntaxExtension::ProcMacro(.., edition) |
+            SyntaxExtension::AttrProcMacro(.., edition) |
+            SyntaxExtension::ProcMacroDerive(.., edition) => edition,
+            // Unstable legacy stuff
+            SyntaxExtension::IdentTT(..) |
+            SyntaxExtension::MultiDecorator(..) |
+            SyntaxExtension::MultiModifier(..) |
+            SyntaxExtension::BuiltinDerive(..) => hygiene::default_edition(),
+        }
+    }
 }
 
 pub type NamedSyntaxExtension = (Name, SyntaxExtension);
index 6bf166dfe950a84dc3559068d200e132ee4d26e3..0b6a7e1c4f49dc2d6b13f27dab4d601226cf59ab 100644 (file)
@@ -10,7 +10,7 @@
 
 use attr::HasAttrs;
 use ast;
-use codemap::{ExpnInfo, NameAndSpan, ExpnFormat};
+use codemap::{hygiene, ExpnInfo, NameAndSpan, ExpnFormat};
 use ext::base::ExtCtxt;
 use ext::build::AstBuilder;
 use parse::parser::PathStyle;
@@ -65,6 +65,7 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path]
             span: None,
             allow_internal_unstable: true,
             allow_internal_unsafe: false,
+            edition: hygiene::default_edition(),
         },
     });
 
index 584b9455a93ada1e39174e6ed92c7ae2ab2eaf50..ee96963362b6c419f21ef0010ecc5f62e8072d8f 100644 (file)
@@ -16,7 +16,7 @@
 use errors::FatalError;
 use ext::base::*;
 use ext::derive::{add_derived_markers, collect_derives};
-use ext::hygiene::{Mark, SyntaxContext};
+use ext::hygiene::{self, Mark, SyntaxContext};
 use ext::placeholders::{placeholder, PlaceholderExpander};
 use feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
 use fold;
@@ -502,6 +502,7 @@ fn expand_attr_invoc(&mut self,
                 span: None,
                 allow_internal_unstable: false,
                 allow_internal_unsafe: false,
+                edition: ext.edition(),
             }
         });
 
@@ -520,7 +521,7 @@ fn expand_attr_invoc(&mut self,
                 items.push(item);
                 Some(kind.expect_from_annotatables(items))
             }
-            AttrProcMacro(ref mac) => {
+            AttrProcMacro(ref mac, ..) => {
                 self.gate_proc_macro_attr_item(attr.span, &item);
                 let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
                     Annotatable::Item(item) => token::NtItem(item),
@@ -609,7 +610,8 @@ fn expand_bang_invoc(&mut self,
                                           allow_internal_unstable,
                                           allow_internal_unsafe,
                                           // can't infer this type
-                                          unstable_feature: Option<(Symbol, u32)>| {
+                                          unstable_feature: Option<(Symbol, u32)>,
+                                          edition| {
 
             // feature-gate the macro invocation
             if let Some((feature, issue)) = unstable_feature {
@@ -642,15 +644,17 @@ fn expand_bang_invoc(&mut self,
                     span: def_site_span,
                     allow_internal_unstable,
                     allow_internal_unsafe,
+                    edition,
                 },
             });
             Ok(())
         };
 
         let opt_expanded = match *ext {
-            DeclMacro(ref expand, def_span) => {
+            DeclMacro(ref expand, def_span, edition) => {
                 if let Err(dummy_span) = validate_and_set_expn_info(self, def_span.map(|(_, s)| s),
-                                                                    false, false, None) {
+                                                                    false, false, None,
+                                                                    edition) {
                     dummy_span
                 } else {
                     kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
@@ -663,11 +667,13 @@ fn expand_bang_invoc(&mut self,
                 allow_internal_unstable,
                 allow_internal_unsafe,
                 unstable_feature,
+                edition,
             } => {
                 if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
                                                                     allow_internal_unstable,
                                                                     allow_internal_unsafe,
-                                                                    unstable_feature) {
+                                                                    unstable_feature,
+                                                                    edition) {
                     dummy_span
                 } else {
                     kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
@@ -688,6 +694,7 @@ fn expand_bang_invoc(&mut self,
                             span: tt_span,
                             allow_internal_unstable,
                             allow_internal_unsafe: false,
+                            edition: hygiene::default_edition(),
                         }
                     });
 
@@ -709,7 +716,7 @@ fn expand_bang_invoc(&mut self,
                 kind.dummy(span)
             }
 
-            ProcMacro(ref expandfun) => {
+            ProcMacro(ref expandfun, edition) => {
                 if ident.name != keywords::Invalid.name() {
                     let msg =
                         format!("macro {}! expects no ident argument, given '{}'", path, ident);
@@ -728,6 +735,7 @@ fn expand_bang_invoc(&mut self,
                             // FIXME probably want to follow macro_rules macros here.
                             allow_internal_unstable: false,
                             allow_internal_unsafe: false,
+                            edition,
                         },
                     });
 
@@ -802,11 +810,12 @@ fn expand_derive_invoc(&mut self,
                 span: None,
                 allow_internal_unstable: false,
                 allow_internal_unsafe: false,
+                edition: ext.edition(),
             }
         };
 
         match *ext {
-            ProcMacroDerive(ref ext, _) => {
+            ProcMacroDerive(ref ext, ..) => {
                 invoc.expansion_data.mark.set_expn_info(expn_info);
                 let span = span.with_ctxt(self.cx.backtrace());
                 let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
index e96a0e838cfcd50a46429727a3b3180294d1e039..d1a7e7aac266ef8291a2ec7433cabcefe9078939 100644 (file)
@@ -10,6 +10,7 @@
 
 use {ast, attr};
 use syntax_pos::{Span, DUMMY_SP};
+use edition::Edition;
 use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
 use ext::base::{NormalTT, TTMacroExpander};
 use ext::expand::{Expansion, ExpansionKind};
@@ -183,7 +184,8 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
 // Holy self-referential!
 
 /// Converts a `macro_rules!` invocation into a syntax extension.
-pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> SyntaxExtension {
+pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition: Edition)
+               -> SyntaxExtension {
     let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs"));
     let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs"));
 
@@ -298,10 +300,11 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> Syntax
             def_info: Some((def.id, def.span)),
             allow_internal_unstable,
             allow_internal_unsafe,
-            unstable_feature
+            unstable_feature,
+            edition,
         }
     } else {
-        SyntaxExtension::DeclMacro(expander, Some((def.id, def.span)))
+        SyntaxExtension::DeclMacro(expander, Some((def.id, def.span)), edition)
     }
 }
 
index 90af3ba51ecadcff1a3d7fdf58c90099df2c14b4..e98170345696a141a9352d6ae170eec0303edf08 100644 (file)
@@ -22,7 +22,6 @@
 #![feature(unicode_internals)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_sort_by_cached_key)]
-#![feature(non_exhaustive)]
 #![feature(const_atomic_usize_new)]
 #![feature(rustc_attrs)]
 #![feature(str_escape)]
@@ -142,7 +141,6 @@ pub mod syntax {
 #[macro_use]
 pub mod config;
 pub mod entry;
-pub mod edition;
 pub mod feature_gate;
 pub mod fold;
 pub mod parse;
@@ -150,6 +148,7 @@ pub mod syntax {
 pub mod show_span;
 pub mod std_inject;
 pub mod str;
+pub use syntax_pos::edition;
 pub use syntax_pos::symbol;
 pub mod test;
 pub mod tokenstream;
index 63aa5d28ce8dc9a6df04454c397886d85f9262da..672b0b9bbd16da8006ab5ae94f6a6e70fb39725f 100644 (file)
@@ -238,7 +238,19 @@ fn read_block_comment(rdr: &mut StringReader,
     debug!(">>> block comment");
     let p = rdr.pos;
     let mut lines: Vec<String> = Vec::new();
-    let col = rdr.col;
+
+    // Count the number of chars since the start of the line by rescanning.
+    let mut src_index = rdr.src_index(rdr.filemap.line_begin_pos());
+    let end_src_index = rdr.src_index(rdr.pos);
+    assert!(src_index <= end_src_index);
+    let mut n = 0;
+    while src_index < end_src_index {
+        let c = char_at(&rdr.src, src_index);
+        src_index += c.len_utf8();
+        n += 1;
+    }
+    let col = CharPos(n);
+
     rdr.bump();
     rdr.bump();
 
index 3e22598043a3ed1cfef9adf8c5d17626ef778357..bbece1ee5e3d4474e286737cb53d74b5bbb73a6a 100644 (file)
@@ -44,13 +44,11 @@ pub struct StringReader<'a> {
     pub next_pos: BytePos,
     /// The absolute offset within the codemap of the current character
     pub pos: BytePos,
-    /// The column of the next character to read
-    pub col: CharPos,
     /// The current character (which has been read from self.pos)
     pub ch: Option<char>,
     pub filemap: Lrc<syntax_pos::FileMap>,
-    /// If Some, stop reading the source at this position (inclusive).
-    pub terminator: Option<BytePos>,
+    /// Stop reading src at this index.
+    pub end_src_index: usize,
     /// Whether to record new-lines and multibyte chars in filemap.
     /// This is only necessary the first time a filemap is lexed.
     /// If part of a filemap is being re-lexed, this should be set to false.
@@ -61,7 +59,7 @@ pub struct StringReader<'a> {
     pub fatal_errs: Vec<DiagnosticBuilder<'a>>,
     // cache a direct reference to the source text, so that we don't have to
     // retrieve it via `self.filemap.src.as_ref().unwrap()` all the time.
-    source_text: Lrc<String>,
+    src: Lrc<String>,
     /// Stack of open delimiters and their spans. Used for error message.
     token: token::Token,
     span: Span,
@@ -113,14 +111,7 @@ pub fn real_token(&mut self) -> TokenAndSpan {
         self.unwrap_or_abort(res)
     }
     fn is_eof(&self) -> bool {
-        if self.ch.is_none() {
-            return true;
-        }
-
-        match self.terminator {
-            Some(t) => self.next_pos > t,
-            None => false,
-        }
+        self.ch.is_none()
     }
     /// Return the next token. EFFECT: advances the string_reader.
     pub fn try_next_token(&mut self) -> Result<TokenAndSpan, ()> {
@@ -176,21 +167,20 @@ fn new_raw_internal(sess: &'a ParseSess, filemap: Lrc<syntax_pos::FileMap>) -> S
                                               filemap.name));
         }
 
-        let source_text = (*filemap.src.as_ref().unwrap()).clone();
+        let src = (*filemap.src.as_ref().unwrap()).clone();
 
         StringReader {
             sess,
             next_pos: filemap.start_pos,
             pos: filemap.start_pos,
-            col: CharPos(0),
             ch: Some('\n'),
             filemap,
-            terminator: None,
+            end_src_index: src.len(),
             save_new_lines_and_multibyte: true,
             // dummy values; not read
             peek_tok: token::Eof,
             peek_span: syntax_pos::DUMMY_SP,
-            source_text,
+            src,
             fatal_errs: Vec::new(),
             token: token::Eof,
             span: syntax_pos::DUMMY_SP,
@@ -222,7 +212,7 @@ pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
         // Seek the lexer to the right byte range.
         sr.save_new_lines_and_multibyte = false;
         sr.next_pos = span.lo();
-        sr.terminator = Some(span.hi());
+        sr.end_src_index = sr.src_index(span.hi());
 
         sr.bump();
 
@@ -326,9 +316,7 @@ fn struct_err_span_char(&self,
     /// offending string to the error message
     fn fatal_span_verbose(&self, from_pos: BytePos, to_pos: BytePos, mut m: String) -> FatalError {
         m.push_str(": ");
-        let from = self.byte_offset(from_pos).to_usize();
-        let to = self.byte_offset(to_pos).to_usize();
-        m.push_str(&self.source_text[from..to]);
+        m.push_str(&self.src[self.src_index(from_pos)..self.src_index(to_pos)]);
         self.fatal_span_(from_pos, to_pos, &m[..])
     }
 
@@ -354,8 +342,9 @@ fn advance_token(&mut self) -> Result<(), ()> {
         Ok(())
     }
 
-    fn byte_offset(&self, pos: BytePos) -> BytePos {
-        (pos - self.filemap.start_pos)
+    #[inline]
+    fn src_index(&self, pos: BytePos) -> usize {
+        (pos - self.filemap.start_pos).to_usize()
     }
 
     /// Calls `f` with a string slice of the source text spanning from `start`
@@ -386,7 +375,7 @@ pub fn name_from_to(&self, start: BytePos, end: BytePos) -> ast::Name {
     fn with_str_from_to<T, F>(&self, start: BytePos, end: BytePos, f: F) -> T
         where F: FnOnce(&str) -> T
     {
-        f(&self.source_text[self.byte_offset(start).to_usize()..self.byte_offset(end).to_usize()])
+        f(&self.src[self.src_index(start)..self.src_index(end)])
     }
 
     /// Converts CRLF to LF in the given string, raising an error on bare CR.
@@ -438,47 +427,39 @@ fn translate_crlf_(rdr: &StringReader,
         }
     }
 
-
     /// Advance the StringReader by one character. If a newline is
     /// discovered, add it to the FileMap's list of line start offsets.
     pub fn bump(&mut self) {
-        let new_pos = self.next_pos;
-        let new_byte_offset = self.byte_offset(new_pos).to_usize();
-        let end = self.terminator.map_or(self.source_text.len(), |t| {
-            self.byte_offset(t).to_usize()
-        });
-        if new_byte_offset < end {
-            let old_ch_is_newline = self.ch.unwrap() == '\n';
-            let new_ch = char_at(&self.source_text, new_byte_offset);
-            let new_ch_len = new_ch.len_utf8();
-
-            self.ch = Some(new_ch);
-            self.pos = new_pos;
-            self.next_pos = new_pos + Pos::from_usize(new_ch_len);
-            if old_ch_is_newline {
+        let next_src_index = self.src_index(self.next_pos);
+        if next_src_index < self.end_src_index {
+            let next_ch = char_at(&self.src, next_src_index);
+            let next_ch_len = next_ch.len_utf8();
+
+            if self.ch.unwrap() == '\n' {
                 if self.save_new_lines_and_multibyte {
-                    self.filemap.next_line(self.pos);
+                    self.filemap.next_line(self.next_pos);
                 }
-                self.col = CharPos(0);
-            } else {
-                self.col = self.col + CharPos(1);
             }
-            if new_ch_len > 1 {
+            if next_ch_len > 1 {
                 if self.save_new_lines_and_multibyte {
-                    self.filemap.record_multibyte_char(self.pos, new_ch_len);
+                    self.filemap.record_multibyte_char(self.next_pos, next_ch_len);
                 }
             }
-            self.filemap.record_width(self.pos, new_ch);
+            self.filemap.record_width(self.next_pos, next_ch);
+
+            self.ch = Some(next_ch);
+            self.pos = self.next_pos;
+            self.next_pos = self.next_pos + Pos::from_usize(next_ch_len);
         } else {
             self.ch = None;
-            self.pos = new_pos;
+            self.pos = self.next_pos;
         }
     }
 
     pub fn nextch(&self) -> Option<char> {
-        let offset = self.byte_offset(self.next_pos).to_usize();
-        if offset < self.source_text.len() {
-            Some(char_at(&self.source_text, offset))
+        let next_src_index = self.src_index(self.next_pos);
+        if next_src_index < self.end_src_index {
+            Some(char_at(&self.src, next_src_index))
         } else {
             None
         }
@@ -489,17 +470,15 @@ pub fn nextch_is(&self, c: char) -> bool {
     }
 
     pub fn nextnextch(&self) -> Option<char> {
-        let offset = self.byte_offset(self.next_pos).to_usize();
-        let s = &self.source_text[..];
-        if offset >= s.len() {
-            return None;
-        }
-        let next = offset + char_at(s, offset).len_utf8();
-        if next < s.len() {
-            Some(char_at(s, next))
-        } else {
-            None
+        let next_src_index = self.src_index(self.next_pos);
+        if next_src_index < self.end_src_index {
+            let next_next_src_index =
+                next_src_index + char_at(&self.src, next_src_index).len_utf8();
+            if next_next_src_index < self.end_src_index {
+                return Some(char_at(&self.src, next_next_src_index));
+            }
         }
+        None
     }
 
     pub fn nextnextch_is(&self, c: char) -> bool {
@@ -1149,7 +1128,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                 return Ok(self.with_str_from(start, |string| {
                     // FIXME: perform NFKC normalization here. (Issue #2253)
                     let ident = self.mk_ident(string);
-                    if is_raw_ident && (token::is_path_segment_keyword(ident) ||
+                    if is_raw_ident && (ident.is_path_segment_keyword() ||
                                         ident.name == keywords::Underscore.name()) {
                         self.fatal_span_(raw_start, self.pos,
                             &format!("`r#{}` is not currently supported.", ident.name)
@@ -1359,8 +1338,8 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                     loop {
                         self.bump();
                         if self.ch_is('\'') {
-                            let start = self.byte_offset(start).to_usize();
-                            let end = self.byte_offset(self.pos).to_usize();
+                            let start = self.src_index(start);
+                            let end = self.src_index(self.pos);
                             self.bump();
                             let span = self.mk_sp(start_with_quote, self.pos);
                             self.sess.span_diagnostic
@@ -1369,8 +1348,7 @@ fn next_token_inner(&mut self) -> Result<token::Token, ()> {
                                 .span_suggestion(span,
                                                  "if you meant to write a `str` literal, \
                                                   use double quotes",
-                                                 format!("\"{}\"",
-                                                         &self.source_text[start..end]))
+                                                 format!("\"{}\"", &self.src[start..end]))
                                 .emit();
                             return Ok(token::Literal(token::Str_(Symbol::intern("??")), None))
                         }
index a1c056cbb2ccbbb368627aedf17af5dff840ad16..5575614a4d482b8b39d66005cd6a1beb5e06f8d3 100644 (file)
@@ -138,44 +138,6 @@ fn ident_can_begin_type(ident: ast::Ident, is_raw: bool) -> bool {
     ].contains(&ident.name)
 }
 
-pub fn is_path_segment_keyword(id: ast::Ident) -> bool {
-    id.name == keywords::Super.name() ||
-    id.name == keywords::SelfValue.name() ||
-    id.name == keywords::SelfType.name() ||
-    id.name == keywords::Extern.name() ||
-    id.name == keywords::Crate.name() ||
-    id.name == keywords::CrateRoot.name() ||
-    id.name == keywords::DollarCrate.name()
-}
-
-// We see this identifier in a normal identifier position, like variable name or a type.
-// How was it written originally? Did it use the raw form? Let's try to guess.
-pub fn is_raw_guess(ident: ast::Ident) -> bool {
-    ident.name != keywords::Invalid.name() &&
-    is_reserved_ident(ident) && !is_path_segment_keyword(ident)
-}
-
-// Returns true for reserved identifiers used internally for elided lifetimes,
-// unnamed method parameters, crate root module, error recovery etc.
-pub fn is_special_ident(id: ast::Ident) -> bool {
-    id.name <= keywords::Underscore.name()
-}
-
-/// Returns `true` if the token is a keyword used in the language.
-pub fn is_used_keyword(id: ast::Ident) -> bool {
-    id.name >= keywords::As.name() && id.name <= keywords::While.name()
-}
-
-/// Returns `true` if the token is a keyword reserved for possible future use.
-pub fn is_unused_keyword(id: ast::Ident) -> bool {
-    id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name()
-}
-
-/// Returns `true` if the token is either a special identifier or a keyword.
-pub fn is_reserved_ident(id: ast::Ident) -> bool {
-    is_special_ident(id) || is_used_keyword(id) || is_unused_keyword(id)
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)]
 pub enum Token {
     /* Expression-operator symbols. */
@@ -251,7 +213,7 @@ pub fn interpolated(nt: Nonterminal) -> Token {
 
     /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary.
     pub fn from_ast_ident(ident: ast::Ident) -> Token {
-        Ident(ident, is_raw_guess(ident))
+        Ident(ident, ident.is_raw_guess())
     }
 
     /// Returns `true` if the token starts with '>'.
@@ -431,7 +393,7 @@ pub fn is_keyword(&self, kw: keywords::Keyword) -> bool {
 
     pub fn is_path_segment_keyword(&self) -> bool {
         match self.ident() {
-            Some((id, false)) => is_path_segment_keyword(id),
+            Some((id, false)) => id.is_path_segment_keyword(),
             _ => false,
         }
     }
@@ -440,7 +402,7 @@ pub fn is_path_segment_keyword(&self) -> bool {
     // unnamed method parameters, crate root module, error recovery etc.
     pub fn is_special_ident(&self) -> bool {
         match self.ident() {
-            Some((id, false)) => is_special_ident(id),
+            Some((id, false)) => id.is_special(),
             _ => false,
         }
     }
@@ -448,7 +410,7 @@ pub fn is_special_ident(&self) -> bool {
     /// Returns `true` if the token is a keyword used in the language.
     pub fn is_used_keyword(&self) -> bool {
         match self.ident() {
-            Some((id, false)) => is_used_keyword(id),
+            Some((id, false)) => id.is_used_keyword(),
             _ => false,
         }
     }
@@ -456,7 +418,7 @@ pub fn is_used_keyword(&self) -> bool {
     /// Returns `true` if the token is a keyword reserved for possible future use.
     pub fn is_unused_keyword(&self) -> bool {
         match self.ident() {
-            Some((id, false)) => is_unused_keyword(id),
+            Some((id, false)) => id.is_unused_keyword(),
             _ => false,
         }
     }
@@ -464,7 +426,7 @@ pub fn is_unused_keyword(&self) -> bool {
     /// Returns `true` if the token is either a special identifier or a keyword.
     pub fn is_reserved_ident(&self) -> bool {
         match self.ident() {
-            Some((id, false)) => is_reserved_ident(id),
+            Some((id, false)) => id.is_reserved(),
             _ => false,
         }
     }
index a700799cde564c24df903ea45f47967a16b9efa6..17f83a09c77b780cff60c42bf48c9d3cd3e21947 100644 (file)
@@ -2374,7 +2374,7 @@ pub fn print_local_decl(&mut self, loc: &ast::Local) -> io::Result<()> {
     }
 
     pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
-        if token::is_raw_guess(ident) {
+        if ident.is_raw_guess() {
             self.s.word(&format!("r#{}", ident))?;
         } else {
             self.s.word(&ident.name.as_str())?;
index 53dc19ba37d19775a2569023987c3bd7c9c57afd..e9cd7adb9c166fa25f955bdf81ba11c7d3519f70 100644 (file)
@@ -14,7 +14,7 @@
 use ext::hygiene::{Mark, SyntaxContext};
 use symbol::{Symbol, keywords};
 use syntax_pos::{DUMMY_SP, Span};
-use codemap::{ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned, respan};
+use codemap::{ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned, hygiene, respan};
 use ptr::P;
 use tokenstream::TokenStream;
 
@@ -30,6 +30,7 @@ fn ignored_span(sp: Span) -> Span {
             span: None,
             allow_internal_unstable: true,
             allow_internal_unsafe: false,
+            edition: hygiene::default_edition(),
         }
     });
     sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))
index d0f47629b10e5b42fd877c563c6d299e9097b85f..281861918fd8eefaecf88570f6d23ae49e993db2 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#[inline]
 pub fn char_at(s: &str, byte: usize) -> char {
     s[byte..].chars().next().unwrap()
 }
index 1734692f9e7589639024e77643f4278b40e70b97..1dfd48a24c3bfbb4009052492346d2220ec4e73d 100644 (file)
@@ -29,7 +29,7 @@
 use ext::base::{ExtCtxt, Resolver};
 use ext::build::AstBuilder;
 use ext::expand::ExpansionConfig;
-use ext::hygiene::{Mark, SyntaxContext};
+use ext::hygiene::{self, Mark, SyntaxContext};
 use fold::Folder;
 use feature_gate::Features;
 use util::move_map::MoveMap;
@@ -300,6 +300,7 @@ fn generate_test_harness(sess: &ParseSess,
             span: None,
             allow_internal_unstable: true,
             allow_internal_unsafe: false,
+            edition: hygiene::default_edition(),
         }
     });
 
index 369c5b1ff60dbba182d5c272b6b551d98af2b3b7..dd8f79d20abda429638cfc6f2cdce96b7430bdb1 100644 (file)
@@ -45,17 +45,6 @@ fn next(&self) -> State {
     }
 }
 
-macro_rules! span_err_if_not_stage0 {
-    ($cx:expr, $sp:expr, $code:ident, $text:tt) => {
-        #[cfg(not(stage0))] {
-            span_err!($cx, $sp, $code, $text)
-        }
-        #[cfg(stage0)] {
-            $cx.span_err($sp, $text)
-        }
-    }
-}
-
 const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
 
 pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
@@ -100,7 +89,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                 if asm_str_style.is_some() {
                     // If we already have a string with instructions,
                     // ending up in Asm state again is an error.
-                    span_err_if_not_stage0!(cx, sp, E0660, "malformed inline assembly");
+                    span_err!(cx, sp, E0660, "malformed inline assembly");
                     return DummyResult::expr(sp);
                 }
                 // Nested parser, stop before the first colon (see above).
@@ -153,7 +142,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                             Some(Symbol::intern(&format!("={}", ch.as_str())))
                         }
                         _ => {
-                            span_err_if_not_stage0!(cx, span, E0661,
+                            span_err!(cx, span, E0661,
                                                     "output operand constraint lacks '=' or '+'");
                             None
                         }
@@ -179,10 +168,10 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                     let (constraint, _str_style) = panictry!(p.parse_str());
 
                     if constraint.as_str().starts_with("=") {
-                        span_err_if_not_stage0!(cx, p.prev_span, E0662,
+                        span_err!(cx, p.prev_span, E0662,
                                                 "input operand constraint contains '='");
                     } else if constraint.as_str().starts_with("+") {
-                        span_err_if_not_stage0!(cx, p.prev_span, E0663,
+                        span_err!(cx, p.prev_span, E0663,
                                                 "input operand constraint contains '+'");
                     }
 
@@ -205,7 +194,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                     if OPTIONS.iter().any(|&opt| s == opt) {
                         cx.span_warn(p.prev_span, "expected a clobber, found an option");
                     } else if s.as_str().starts_with("{") || s.as_str().ends_with("}") {
-                        span_err_if_not_stage0!(cx, p.prev_span, E0664,
+                        span_err!(cx, p.prev_span, E0664,
                                                 "clobber should not be surrounded by braces");
                     }
 
index f29cc75664da81fb92bc774225a856f7f0c145c4..b22098408a332f06623bc2e29aeede2c28b3fa8e 100644 (file)
@@ -767,9 +767,12 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
     }
 
     if !parser.errors.is_empty() {
-        let (err, note) = parser.errors.remove(0);
-        let mut e = cx.ecx.struct_span_err(cx.fmtsp, &format!("invalid format string: {}", err));
-        if let Some(note) = note {
+        let err = parser.errors.remove(0);
+        let sp = cx.fmtsp.from_inner_byte_pos(err.start, err.end);
+        let mut e = cx.ecx.struct_span_err(sp, &format!("invalid format string: {}",
+                                                        err.description));
+        e.span_label(sp, err.label + " in format string");
+        if let Some(note) = err.note {
             e.note(&note);
         }
         e.emit();
index b6721dd28f3674d008f709112a76222aab38c07e..15fcfac13adf2b02563e781e635d850c3eeda2ac 100644 (file)
@@ -18,7 +18,7 @@
 #![feature(decl_macro)]
 #![feature(str_escape)]
 
-#![cfg_attr(not(stage0), feature(rustc_diagnostic_macros))]
+#![feature(rustc_diagnostic_macros)]
 
 extern crate fmt_macros;
 #[macro_use]
@@ -29,7 +29,6 @@
 extern crate rustc_errors as errors;
 extern crate rustc_target;
 
-#[cfg(not(stage0))]
 mod diagnostics;
 
 mod assert;
@@ -55,6 +54,7 @@
 use rustc_data_structures::sync::Lrc;
 use syntax::ast;
 use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension};
+use syntax::ext::hygiene;
 use syntax::symbol::Symbol;
 
 pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
@@ -75,6 +75,7 @@ macro_rules! register {
                         allow_internal_unstable: false,
                         allow_internal_unsafe: false,
                         unstable_feature: None,
+                        edition: hygiene::default_edition(),
                     });
         )* }
     }
@@ -129,7 +130,8 @@ macro_rules! register {
                 def_info: None,
                 allow_internal_unstable: true,
                 allow_internal_unsafe: false,
-                unstable_feature: None
+                unstable_feature: None,
+                edition: hygiene::default_edition(),
             });
 
     for (name, ext) in user_exts {
index d684e8b4ffea5a4894428fa73f587199863b905e..3593165023a54611cde685e540ce2039e87e267f 100644 (file)
@@ -14,7 +14,7 @@
 
 use syntax::ast::{self, Ident, NodeId};
 use syntax::attr;
-use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute, respan};
+use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute, hygiene, respan};
 use syntax::ext::base::ExtCtxt;
 use syntax::ext::build::AstBuilder;
 use syntax::ext::expand::ExpansionConfig;
@@ -369,6 +369,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
             span: None,
             allow_internal_unstable: true,
             allow_internal_unsafe: false,
+            edition: hygiene::default_edition(),
         }
     });
     let span = DUMMY_SP.apply_mark(mark);
diff --git a/src/libsyntax_pos/edition.rs b/src/libsyntax_pos/edition.rs
new file mode 100644 (file)
index 0000000..18446c1
--- /dev/null
@@ -0,0 +1,82 @@
+// 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.
+
+use std::fmt;
+use std::str::FromStr;
+
+/// The edition of the compiler (RFC 2052)
+#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)]
+#[non_exhaustive]
+pub enum Edition {
+    // editions must be kept in order, newest to oldest
+
+    /// The 2015 edition
+    Edition2015,
+    /// The 2018 edition
+    Edition2018,
+
+    // when adding new editions, be sure to update:
+    //
+    // - Update the `ALL_EDITIONS` const
+    // - Update the EDITION_NAME_LIST const
+    // - add a `rust_####()` function to the session
+    // - update the enum in Cargo's sources as well
+}
+
+// must be in order from oldest to newest
+pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];
+
+pub const EDITION_NAME_LIST: &'static str = "2015|2018";
+
+pub const DEFAULT_EDITION: Edition = Edition::Edition2015;
+
+impl fmt::Display for Edition {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let s = match *self {
+            Edition::Edition2015 => "2015",
+            Edition::Edition2018 => "2018",
+        };
+        write!(f, "{}", s)
+    }
+}
+
+impl Edition {
+    pub fn lint_name(&self) -> &'static str {
+        match *self {
+            Edition::Edition2015 => "rust_2015_compatibility",
+            Edition::Edition2018 => "rust_2018_compatibility",
+        }
+    }
+
+    pub fn feature_name(&self) -> &'static str {
+        match *self {
+            Edition::Edition2015 => "rust_2015_preview",
+            Edition::Edition2018 => "rust_2018_preview",
+        }
+    }
+
+    pub fn is_stable(&self) -> bool {
+        match *self {
+            Edition::Edition2015 => true,
+            Edition::Edition2018 => false,
+        }
+    }
+}
+
+impl FromStr for Edition {
+    type Err = ();
+    fn from_str(s: &str) -> Result<Self, ()> {
+        match s {
+            "2015" => Ok(Edition::Edition2015),
+            "2018" => Ok(Edition::Edition2018),
+            _ => Err(())
+        }
+    }
+}
index be031ea98c9d2ecb4b8deabc1dca001ebca1a5d1..1365ac396ffdf5f4e21bf89e535556ad8a730a52 100644 (file)
@@ -17,6 +17,7 @@
 
 use GLOBALS;
 use Span;
+use edition::Edition;
 use symbol::{Ident, Symbol};
 
 use serialize::{Encodable, Decodable, Encoder, Decoder};
@@ -151,6 +152,7 @@ pub struct HygieneData {
     syntax_contexts: Vec<SyntaxContextData>,
     markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
     gensym_to_ctxt: HashMap<Symbol, Span>,
+    default_edition: Edition,
 }
 
 impl HygieneData {
@@ -168,6 +170,7 @@ pub fn new() -> Self {
             }],
             markings: HashMap::new(),
             gensym_to_ctxt: HashMap::new(),
+            default_edition: Edition::Edition2015,
         }
     }
 
@@ -176,6 +179,14 @@ fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
     }
 }
 
+pub fn default_edition() -> Edition {
+    HygieneData::with(|data| data.default_edition)
+}
+
+pub fn set_default_edition(edition: Edition) {
+    HygieneData::with(|data| data.default_edition = edition);
+}
+
 pub fn clear_markings() {
     HygieneData::with(|data| data.markings = HashMap::new());
 }
@@ -443,6 +454,8 @@ pub struct NameAndSpan {
     /// Whether the macro is allowed to use `unsafe` internally
     /// even if the user crate has `#![forbid(unsafe_code)]`.
     pub allow_internal_unsafe: bool,
+    /// Edition of the crate in which the macro is defined.
+    pub edition: Edition,
     /// The span of the macro definition itself. The macro may not
     /// have a sensible definition span (e.g. something defined
     /// completely inside libsyntax) in which case this is None.
index d30d3d78ca5404dbea9f10b29f81f272b6c5af35..17163576901eb86bd21a8e30a75bd45954a83348 100644 (file)
@@ -20,6 +20,7 @@
 
 #![feature(const_fn)]
 #![feature(custom_attribute)]
+#![feature(non_exhaustive)]
 #![feature(optin_builtin_traits)]
 #![allow(unused_attributes)]
 #![feature(specialization)]
@@ -48,6 +49,7 @@
 
 extern crate unicode_width;
 
+pub mod edition;
 pub mod hygiene;
 pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan, CompilerDesugaringKind};
 
@@ -298,6 +300,12 @@ pub fn parent(self) -> Option<Span> {
         self.ctxt().outer().expn_info().map(|i| i.call_site)
     }
 
+    /// Edition of the crate from which this span came.
+    pub fn edition(self) -> edition::Edition {
+        self.ctxt().outer().expn_info().map_or_else(|| hygiene::default_edition(),
+                                                    |einfo| einfo.callee.edition)
+    }
+
     /// Return the source callee.
     ///
     /// Returns None if the supplied span has no expansion trace,
@@ -428,6 +436,13 @@ pub fn until(self, end: Span) -> Span {
         )
     }
 
+    pub fn from_inner_byte_pos(self, start: usize, end: usize) -> Span {
+        let span = self.data();
+        Span::new(span.lo + BytePos::from_usize(start),
+                  span.lo + BytePos::from_usize(end),
+                  span.ctxt)
+    }
+
     #[inline]
     pub fn apply_mark(self, mark: Mark) -> Span {
         let span = self.data();
@@ -971,6 +986,15 @@ pub fn next_line(&self, pos: BytePos) {
         lines.push(pos);
     }
 
+    /// Return the BytePos of the beginning of the current line.
+    pub fn line_begin_pos(&self) -> BytePos {
+        let lines = self.lines.borrow();
+        match lines.last() {
+            Some(&line_pos) => line_pos,
+            None => self.start_pos,
+        }
+    }
+
     /// Add externally loaded source.
     /// If the hash of the input doesn't match or no input is supplied via None,
     /// it is interpreted as an error and the corresponding enum variant is set.
@@ -1047,6 +1071,7 @@ pub fn record_multibyte_char(&self, pos: BytePos, bytes: usize) {
         self.multibyte_chars.borrow_mut().push(mbc);
     }
 
+    #[inline]
     pub fn record_width(&self, pos: BytePos, ch: char) {
         let width = match ch {
             '\t' =>
index 2258ed12779e4ce7792a195d9cfaa234db812bac..a08f9b2e54a7c63065584879539da96a273cf8fe 100644 (file)
@@ -12,6 +12,7 @@
 //! allows bidirectional lookup; i.e. given a value, one can easily find the
 //! type, and vice versa.
 
+use edition::Edition;
 use hygiene::SyntaxContext;
 use {Span, DUMMY_SP, GLOBALS};
 
@@ -318,7 +319,7 @@ pub fn fresh() -> Self {
 // NB: leaving holes in the ident table is bad! a different ident will get
 // interned with the id from the hole, but it will be between the min and max
 // of the reserved words, and thus tagged as "reserved".
-// After modifying this list adjust `is_special_ident`, `is_used_keyword`/`is_unused_keyword`,
+// After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`,
 // this should be rarely necessary though if the keywords are kept in alphabetic order.
 declare_keywords! {
     // Special reserved identifiers used internally for elided lifetimes,
@@ -383,16 +384,68 @@ pub fn fresh() -> Self {
     (53, Virtual,            "virtual")
     (54, Yield,              "yield")
 
+    // Edition-specific keywords reserved for future use.
+    (55, Async,              "async") // >= 2018 Edition Only
+
     // Special lifetime names
-    (55, UnderscoreLifetime, "'_")
-    (56, StaticLifetime,     "'static")
+    (56, UnderscoreLifetime, "'_")
+    (57, StaticLifetime,     "'static")
 
     // Weak keywords, have special meaning only in specific contexts.
-    (57, Auto,               "auto")
-    (58, Catch,              "catch")
-    (59, Default,            "default")
-    (60, Dyn,                "dyn")
-    (61, Union,              "union")
+    (58, Auto,               "auto")
+    (59, Catch,              "catch")
+    (60, Default,            "default")
+    (61, Dyn,                "dyn")
+    (62, Union,              "union")
+}
+
+impl Symbol {
+    fn is_unused_keyword_2018(self) -> bool {
+        self == keywords::Async.name()
+    }
+}
+
+impl Ident {
+    // Returns true for reserved identifiers used internally for elided lifetimes,
+    // unnamed method parameters, crate root module, error recovery etc.
+    pub fn is_special(self) -> bool {
+        self.name <= keywords::Underscore.name()
+    }
+
+    /// Returns `true` if the token is a keyword used in the language.
+    pub fn is_used_keyword(self) -> bool {
+        self.name >= keywords::As.name() && self.name <= keywords::While.name()
+    }
+
+    /// Returns `true` if the token is a keyword reserved for possible future use.
+    pub fn is_unused_keyword(self) -> bool {
+        // Note: `span.edition()` is relatively expensive, don't call it unless necessary.
+        self.name >= keywords::Abstract.name() && self.name <= keywords::Yield.name() ||
+        self.name.is_unused_keyword_2018() && self.span.edition() == Edition::Edition2018
+    }
+
+    /// Returns `true` if the token is either a special identifier or a keyword.
+    pub fn is_reserved(self) -> bool {
+        self.is_special() || self.is_used_keyword() || self.is_unused_keyword()
+    }
+
+    /// A keyword or reserved identifier that can be used as a path segment.
+    pub fn is_path_segment_keyword(self) -> bool {
+        self.name == keywords::Super.name() ||
+        self.name == keywords::SelfValue.name() ||
+        self.name == keywords::SelfType.name() ||
+        self.name == keywords::Extern.name() ||
+        self.name == keywords::Crate.name() ||
+        self.name == keywords::CrateRoot.name() ||
+        self.name == keywords::DollarCrate.name()
+    }
+
+    // We see this identifier in a normal identifier position, like variable name or a type.
+    // How was it written originally? Did it use the raw form? Let's try to guess.
+    pub fn is_raw_guess(self) -> bool {
+        self.name != keywords::Invalid.name() &&
+        self.is_reserved() && !self.is_path_segment_keyword()
+    }
 }
 
 // If an interner exists, return it. Otherwise, prepare a fresh one.
index 8e5fa00b5f27d6ebdded792cc7d072fe7ec8ea68..f94780682a0c0f33893651b8ad4f7864abfaa271 100644 (file)
@@ -101,7 +101,7 @@ pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         for &(ref f, ref stdout) in &state.not_failures {
             successes.push(f.name.to_string());
             if !stdout.is_empty() {
-                stdouts.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 stdouts.push_str(&output);
                 stdouts.push_str("\n");
@@ -127,7 +127,7 @@ pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         for &(ref f, ref stdout) in &state.failures {
             failures.push(f.name.to_string());
             if !stdout.is_empty() {
-                fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 fail_out.push_str(&output);
                 fail_out.push_str("\n");
index 85286027d69210d49c4c399508d7a0bddb2d6392..22a06b9f605dbdc66f5b70bdfb2fd84b5b079141 100644 (file)
@@ -105,7 +105,7 @@ pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         for &(ref f, ref stdout) in &state.not_failures {
             successes.push(f.name.to_string());
             if !stdout.is_empty() {
-                stdouts.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 stdouts.push_str(&output);
                 stdouts.push_str("\n");
@@ -131,7 +131,7 @@ pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
         for &(ref f, ref stdout) in &state.failures {
             failures.push(f.name.to_string());
             if !stdout.is_empty() {
-                fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name));
+                fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
                 let output = String::from_utf8_lossy(stdout);
                 fail_out.push_str(&output);
                 fail_out.push_str("\n");
index 7d5581bb774b03132b384146479f6004ac46b417..8ff401164c1353e7f4088bd485fefe12b30a06e0 100644 (file)
@@ -23,7 +23,7 @@
 // of other runtime components (registered via yet another special image section).
 
 #![feature(no_core, lang_items, optin_builtin_traits)]
-#![crate_type="rlib"]
+#![crate_type = "rlib"]
 #![no_core]
 #![allow(non_camel_case_types)]
 
@@ -43,7 +43,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     drop_in_place(to_drop);
 }
 
-#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
+#[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))]
 pub mod eh_frames {
     #[no_mangle]
     #[link_section = ".eh_frame"]
@@ -54,6 +54,21 @@ pub mod eh_frames {
     // This is defined as `struct object` in $GCC/libgcc/unwind-dw2-fde.h.
     static mut OBJ: [isize; 6] = [0; 6];
 
+    macro_rules! impl_copy {
+        ($($t:ty)*) => {
+            $(
+                impl ::Copy for $t {}
+            )*
+        }
+    }
+
+    impl_copy! {
+        usize u8 u16 u32 u64 u128
+        isize i8 i16 i32 i64 i128
+        f32 f64
+        bool char
+    }
+
     // Unwind info registration/deregistration routines.
     // See the docs of `unwind` module in libstd.
     extern "C" {
@@ -63,14 +78,18 @@ pub mod eh_frames {
 
     unsafe fn init() {
         // register unwind info on module startup
-        rust_eh_register_frames(&__EH_FRAME_BEGIN__ as *const u8,
-                                &mut OBJ as *mut _ as *mut u8);
+        rust_eh_register_frames(
+            &__EH_FRAME_BEGIN__ as *const u8,
+            &mut OBJ as *mut _ as *mut u8,
+        );
     }
 
     unsafe fn uninit() {
         // unregister on shutdown
-        rust_eh_unregister_frames(&__EH_FRAME_BEGIN__ as *const u8,
-                                  &mut OBJ as *mut _ as *mut u8);
+        rust_eh_unregister_frames(
+            &__EH_FRAME_BEGIN__ as *const u8,
+            &mut OBJ as *mut _ as *mut u8,
+        );
     }
 
     // MSVC-specific init/uninit routine registration
index 9986e0b512a347583c00c783ce090bb3b417a2b0..9ccd37a6a45924fb1e4ecf88795d62e277311e44 100644 (file)
@@ -4,7 +4,7 @@ name = "rustc-main"
 version = "0.0.0"
 
 [[bin]]
-name = "rustc"
+name = "rustc_binary"
 path = "rustc.rs"
 
 [dependencies]
index a5ad2b315a1dd629d4e4000ca2720e8bb5176740..435cfd2f6db4eb4752d593e27c108cf759b1b4d8 100644 (file)
@@ -12,7 +12,7 @@
 # source tarball for a stable release you'll likely see `1.x.0` for rustc and
 # `0.x.0` for Cargo where they were released on `date`.
 
-date: 2018-04-24
+date: 2018-05-10
 rustc: beta
 cargo: beta
 
index 29f1e2e5b781e3d80e7377fce2ef6822dda61854..7dabb1bddea77e1877837d4bdcba726c261bd477 100644 (file)
@@ -140,13 +140,9 @@ check that the test compiles successfully.
 ### Editing and updating the reference files
 
 If you have changed the compiler's output intentionally, or you are
-making a new test, you can use the script `ui/update-references.sh` to
-update the references. When you run the test framework, it will report
-various errors: in those errors is a command you can use to run the
-`ui/update-references.sh` script, which will then copy over the files
-from the build directory and use them as the new reference. You can
-also just run `ui/update-all-references.sh`. In both cases, you can run
-the script with `--help` to get a help message.
+making a new test, you can pass `--bless` to the command you used to
+run the tests. This will then copy over the files
+from the build directory and use them as the new reference.
 
 ### Normalization
 
index 9b9deb4ca8d9d9cbef5304fd34a13d4447a388f0..91007fcd63a28b3d6c0cb0b1585215449bdd0287 100644 (file)
@@ -10,9 +10,8 @@
 
 const A: &'static [i32] = &[];
 const B: i32 = (&A)[1];
-//~^ ERROR constant evaluation error
-//~| index out of bounds: the len is 0 but the index is 1
-//~| WARN this constant cannot be used
+//~^ index out of bounds: the len is 0 but the index is 1
+//~| ERROR this constant cannot be used
 
 fn main() {
     let _ = B;
index 46feb20cf11ddbda624db1055b74db74476b9965..66739d308a70fd99b1c3bbb528f16d0ed9e3aff4 100644 (file)
@@ -10,9 +10,8 @@
 
 const A: [i32; 0] = [];
 const B: i32 = A[1];
-//~^ ERROR constant evaluation error
-//~| index out of bounds: the len is 0 but the index is 1
-//~| WARN this constant cannot be used
+//~^ index out of bounds: the len is 0 but the index is 1
+//~| ERROR this constant cannot be used
 
 fn main() {
     let _ = B;
index 7da5a2f17eaf90960d6339474ec99ddd2a509b47..6d51ff30998096abdc88cbee8f975af62ec8000d 100644 (file)
@@ -12,9 +12,8 @@
 
 const FOO: &'static[u32] = &[1, 2, 3];
 const BAR: u32 = FOO[5];
-//~^ ERROR constant evaluation error [E0080]
-//~| index out of bounds: the len is 3 but the index is 5
-//~| WARN this constant cannot be used
+//~^ index out of bounds: the len is 3 but the index is 5
+//~| ERROR this constant cannot be used
 
 fn main() {
     let _ = BAR;
index 49f76c532df54d328f2605e21e6d4a9f5a330b4f..7315616860293c17389097a4ebbce2e4de8aab85 100644 (file)
@@ -12,11 +12,11 @@ enum Test {
     DivZero = 1/0,
     //~^ attempt to divide by zero
     //~| ERROR constant evaluation error
-    //~| WARN constant evaluation error
+    //~| ERROR constant evaluation error
     RemZero = 1%0,
     //~^ attempt to calculate the remainder with a divisor of zero
     //~| ERROR constant evaluation error
-    //~| WARN constant evaluation error
+    //~| ERROR constant evaluation error
 }
 
 fn main() {}
index d50ffff5c1e14a86f6edbe5900ab653aab18672b..1ea436d8ad19200fb9873f4a99e7522e2a615886 100644 (file)
@@ -13,6 +13,7 @@
 // compile-pass
 
 #![allow(warnings)]
+#![warn(const_err)]
 
 fn main() {
     255u8 + 1; //~ WARNING this expression will panic at run-time
index e189f2e3b34a304a67cd0b810ff427d4ea8601f5..15b104f6c2ff74b9206f5c38872395a3a0883b70 100644 (file)
@@ -130,17 +130,21 @@ fn drop(&mut self) {
 //     let mut _7: &'10s S1;
 //     let mut _8: &'10s S1;
 //     let mut _9: S1;
+//     let mut _10: &'10s S1;
+//     let mut _11: &'12ds S1;
 //
 //     bb0: {
 //         StorageLive(_2);
 //         StorageLive(_3);
 //         StorageLive(_4);
 //         StorageLive(_5);
-//         _5 = promoted[1];
+//         _11 = promoted[1];
+//         _5 = &'12ds (*_11);
 //         _4 = &'12ds (*_5);
 //         StorageLive(_7);
 //         StorageLive(_8);
-//         _8 = promoted[0];
+//         _10 = promoted[0];
+//         _8 = &'10s (*_10);
 //         _7 = &'10s (*_8);
 //         _3 = D1<'12ds, '10s>::{{constructor}}(move _4, move _7);
 //         EndRegion('10s);
index a31298a0f516007fcd8790a10d9539627b5b91af..c2a40399efe3d5718f5e3604a13a04ad56d724fb 100644 (file)
@@ -88,7 +88,8 @@ fn main() {
 //  }
 //  bb9: { // binding1 and guard
 //      StorageLive(_5);
-//      _5 = &((_2 as Some).0: i32);
+//      _11 = promoted[0];
+//      _5 = &(((*_11) as Some).0: i32);
 //      StorageLive(_8);
 //      _8 = const guard() -> [return: bb10, unwind: bb1];
 //  }
index 153739133ac82900258866451e2cdf16a1be753d..62064fa94f2fe9ceaa0968ff28e743d76c9ce3e3 100644 (file)
@@ -13,6 +13,9 @@
 // borrows in `&v[0]` and `&v[1]` each (in theory) have to outlive R3,
 // but only at a particular point, and hence they wind up including
 // distinct regions.
+//
+// FIXME(#43234) -- Well, this used to be true, but we modified NLL
+// for the time being to not take location into account.
 
 // compile-flags:-Zborrowck=mir -Zverbose
 //                              ^^^^^^^^^ force compiler to dump more region information
@@ -36,9 +39,9 @@ fn main() {
 
 // END RUST SOURCE
 // START rustc.main.nll.0.mir
-// | '_#2r    | {bb2[0..=1], bb3[0..=1]}
+// | '_#2r    | {bb2[0..=1], bb3[0..=1], bb8[2..=4]}
 // ...
-// | '_#4r    | {bb8[1..=4]}
+// | '_#4r    | {bb2[1], bb3[0..=1], bb8[1..=4]}
 // | '_#5r    | {bb2[1], bb3[0..=1], bb8[2..=4]}
 // ...
 // let mut _2: &'_#5r usize;
index 250f0726dc9d61d0e83f547e0e40e58e2b94a0f4..584701410ef83a4fff8b623876b80d1807f7bb58 100644 (file)
@@ -11,6 +11,8 @@
 // error-pattern:thread 'main' panicked at 'attempt to add with overflow'
 // compile-flags: -C debug-assertions
 
+#![allow(const_err)]
+
 fn main() {
     let _x = 200u8 + 200u8 + 200u8;
 }
index b47d0fc4136ccaf316f07f26bc0bdc71364c7ef6..5d6f59e02296b3d60a4cf960ce0463de1a24bb38 100644 (file)
@@ -11,6 +11,8 @@
 // error-pattern:thread 'main' panicked at 'attempt to multiply with overflow'
 // compile-flags: -C debug-assertions
 
+#![allow(const_err)]
+
 fn main() {
     let x = 200u8 * 4;
 }
index 836d7e37319e941dcbda0ecbf1a6a7794f8d3cfc..e7c518f1286fb08ed68dec5b3533c46f4448fc7a 100644 (file)
@@ -11,6 +11,8 @@
 // error-pattern:thread 'main' panicked at 'attempt to negate with overflow'
 // compile-flags: -C debug-assertions
 
+#![allow(const_err)]
+
 fn main() {
     let _x = -std::i8::MIN;
 }
index f94cb31b16884cab216e40a23652d47dad572e27..404921a1af5525a2ed58c7c49e12d84381d2ca02 100644 (file)
@@ -11,6 +11,8 @@
 // error-pattern:thread 'main' panicked at 'attempt to subtract with overflow'
 // compile-flags: -C debug-assertions
 
+#![allow(const_err)]
+
 fn main() {
     let _x = 42u8 - (42u8 + 1);
 }
index 231ed2898f1db6af7ebf332911343c57e5284fd3..d7ede763838687f79a620e7f4982329364bce61c 100644 (file)
@@ -20,6 +20,7 @@
 
 use std::borrow::ToOwned;
 use syntax::ast;
+use syntax::ext::hygiene;
 use syntax::ext::build::AstBuilder;
 use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT};
 use syntax::print::pprust;
@@ -54,5 +55,6 @@ pub fn plugin_registrar(reg: &mut Registry) {
             allow_internal_unstable: false,
             allow_internal_unsafe: false,
             unstable_feature: None,
+            edition: hygiene::default_edition(),
         });
 }
diff --git a/src/test/run-pass/align-offset-sign.rs b/src/test/run-pass/align-offset-sign.rs
deleted file mode 100644 (file)
index aaa0419..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2017 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(align_offset)]
-
-fn main() {
-    let x = 1 as *const u8;
-    assert_eq!(x.align_offset(8), 7);
-}
diff --git a/src/test/run-pass/auxiliary/edition-kw-macro-2015.rs b/src/test/run-pass/auxiliary/edition-kw-macro-2015.rs
new file mode 100644 (file)
index 0000000..9127c8e
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2015
+
+#![feature(raw_identifiers)]
+
+#[macro_export]
+macro_rules! produces_async {
+    () => (pub fn async() {})
+}
+
+#[macro_export]
+macro_rules! produces_async_raw {
+    () => (pub fn r#async() {})
+}
+
+#[macro_export]
+macro_rules! consumes_async {
+    (async) => (1)
+}
+
+#[macro_export]
+macro_rules! consumes_async_raw {
+    (r#async) => (1)
+}
+
+#[macro_export]
+macro_rules! passes_ident {
+    ($i: ident) => ($i)
+}
diff --git a/src/test/run-pass/auxiliary/edition-kw-macro-2018.rs b/src/test/run-pass/auxiliary/edition-kw-macro-2018.rs
new file mode 100644 (file)
index 0000000..4fef77d
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2018
+
+#![feature(raw_identifiers)]
+
+#[macro_export]
+macro_rules! produces_async {
+    () => (pub fn async() {})
+}
+
+#[macro_export]
+macro_rules! produces_async_raw {
+    () => (pub fn r#async() {})
+}
+
+#[macro_export]
+macro_rules! consumes_async {
+    (async) => (1)
+}
+
+#[macro_export]
+macro_rules! consumes_async_raw {
+    (r#async) => (1)
+}
+
+#[macro_export]
+macro_rules! passes_ident {
+    ($i: ident) => ($i)
+}
diff --git a/src/test/run-pass/edition-keywords-2015-2015.rs b/src/test/run-pass/edition-keywords-2015-2015.rs
new file mode 100644 (file)
index 0000000..41480bb
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2015
+// aux-build:edition-kw-macro-2015.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+pub fn check_async() {
+    let mut async = 1; // OK
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    // r#async = consumes_async!(r#async); // ERROR, not a match
+    // r#async = consumes_async_raw!(async); // ERROR, not a match
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} // OK
+    if passes_ident!(r#async) == 1 {} // OK
+    one_async::async(); // OK
+    one_async::r#async(); // OK
+    two_async::async(); // OK
+    two_async::r#async(); // OK
+}
+
+mod one_async {
+    produces_async! {} // OK
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/edition-keywords-2015-2018.rs b/src/test/run-pass/edition-keywords-2015-2018.rs
new file mode 100644 (file)
index 0000000..78835d5
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2015
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+pub fn check_async() {
+    let mut async = 1; // OK
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    // r#async = consumes_async!(r#async); // ERROR, not a match
+    // r#async = consumes_async_raw!(async); // ERROR, not a match
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} // OK
+    if passes_ident!(r#async) == 1 {} // OK
+    // one_async::async(); // ERROR, unresolved name
+    // one_async::r#async(); // ERROR, unresolved name
+    two_async::async(); // OK
+    two_async::r#async(); // OK
+}
+
+mod one_async {
+    // produces_async! {} // ERROR, reserved
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/edition-keywords-2018-2015.rs b/src/test/run-pass/edition-keywords-2018-2015.rs
new file mode 100644 (file)
index 0000000..46d5f22
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2018
+// aux-build:edition-kw-macro-2015.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+pub fn check_async() {
+    // let mut async = 1; // ERROR, reserved
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    // r#async = consumes_async!(r#async); // ERROR, not a match
+    // r#async = consumes_async_raw!(async); // ERROR, not a match
+    r#async = consumes_async_raw!(r#async); // OK
+
+    // if passes_ident!(async) == 1 {} // ERROR, reserved
+    if passes_ident!(r#async) == 1 {} // OK
+    // one_async::async(); // ERROR, reserved
+    one_async::r#async(); // OK
+    // two_async::async(); // ERROR, reserved
+    two_async::r#async(); // OK
+}
+
+mod one_async {
+    produces_async! {} // OK
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/edition-keywords-2018-2018.rs b/src/test/run-pass/edition-keywords-2018-2018.rs
new file mode 100644 (file)
index 0000000..0648298
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2018
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+pub fn check_async() {
+    // let mut async = 1; // ERROR, reserved
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    // r#async = consumes_async!(r#async); // ERROR, not a match
+    // r#async = consumes_async_raw!(async); // ERROR, not a match
+    r#async = consumes_async_raw!(r#async); // OK
+
+    // if passes_ident!(async) == 1 {} // ERROR, reserved
+    if passes_ident!(r#async) == 1 {} // OK
+    // one_async::async(); // ERROR, reserved
+    // one_async::r#async(); // ERROR, unresolved name
+    // two_async::async(); // ERROR, reserved
+    two_async::r#async(); // OK
+}
+
+mod one_async {
+    // produces_async! {} // ERROR, reserved
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue-49955-2.rs b/src/test/run-pass/issue-49955-2.rs
new file mode 100644 (file)
index 0000000..17e1de9
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z borrowck=mir
+
+use std::cell::Cell;
+
+#[inline(never)]
+fn tuple_field() -> &'static u32 {
+    // This test is MIR-borrowck-only because the old borrowck
+    // doesn't agree that borrows of "frozen" (i.e. without any
+    // interior mutability) fields of non-frozen temporaries,
+    // should be promoted, while MIR promotion does promote them.
+    &(Cell::new(5), 42).1
+}
+
+fn main() {
+    assert_eq!(tuple_field().to_string(), "42");
+}
diff --git a/src/test/run-pass/issue-49955.rs b/src/test/run-pass/issue-49955.rs
new file mode 100644 (file)
index 0000000..57a1264
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z borrowck=compare
+
+const ALL_THE_NUMS: [u32; 1] = [
+    1
+];
+
+#[inline(never)]
+fn array(i: usize) -> &'static u32 {
+    return &ALL_THE_NUMS[i];
+}
+
+#[inline(never)]
+fn tuple_field() -> &'static u32 {
+    &(42,).0
+}
+
+fn main() {
+    assert_eq!(tuple_field().to_string(), "42");
+    assert_eq!(array(0).to_string(), "1");
+}
diff --git a/src/test/run-pass/nll/get_default.rs b/src/test/run-pass/nll/get_default.rs
deleted file mode 100644 (file)
index 13ef907..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 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(nll)]
-
-use std::collections::HashMap;
-
-fn get_default(map: &mut HashMap<usize, String>, key: usize) -> &mut String {
-    match map.get_mut(&key) {
-        Some(value) => value,
-        None => {
-            map.insert(key, "".to_string());
-            map.get_mut(&key).unwrap()
-        }
-    }
-}
-
-fn main() {
-    let map = &mut HashMap::new();
-    map.insert(22, format!("Hello, world"));
-    map.insert(44, format!("Goodbye, world"));
-    assert_eq!(&*get_default(map, 22), "Hello, world");
-    assert_eq!(&*get_default(map, 66), "");
-}
diff --git a/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs b/src/test/run-pass/nll/issue-50461-used-mut-from-moves.rs
new file mode 100644 (file)
index 0000000..d5cf122
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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(nll)]
+#![deny(unused_mut)]
+
+struct Foo {
+    pub value: i32
+}
+
+fn use_foo_mut(mut foo: Foo) {
+    foo = foo;
+    println!("{}", foo.value);
+}
+
+fn main() {
+    use_foo_mut(Foo { value: 413 });
+}
diff --git a/src/test/rustdoc/auto-impl-primitive.rs b/src/test/rustdoc/auto-impl-primitive.rs
new file mode 100644 (file)
index 0000000..a3887b3
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+#![crate_name = "foo"]
+pub use std::fs::File;
+
+// @has 'foo/primitive.i16.html' '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementation'
+#[doc(primitive = "i16")]
+/// I love poneys!
+mod prim {}
diff --git a/src/test/ui/E0508.ast.nll.stderr b/src/test/ui/E0508.ast.nll.stderr
new file mode 100644 (file)
index 0000000..2840364
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
+  --> $DIR/E0508.rs:18:18
+   |
+LL |     let _value = array[0];  //[ast]~ ERROR [E0508]
+   |                  ^^^^^^^^ cannot move out of here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
diff --git a/src/test/ui/E0508.ast.stderr b/src/test/ui/E0508.ast.stderr
new file mode 100644 (file)
index 0000000..5878b79
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
+  --> $DIR/E0508.rs:18:18
+   |
+LL |     let _value = array[0];  //[ast]~ ERROR [E0508]
+   |                  ^^^^^^^^
+   |                  |
+   |                  cannot move out of here
+   |                  help: consider using a reference instead: `&array[0]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
diff --git a/src/test/ui/E0508.mir.stderr b/src/test/ui/E0508.mir.stderr
new file mode 100644 (file)
index 0000000..2840364
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0508]: cannot move out of type `[NonCopy; 1]`, a non-copy array
+  --> $DIR/E0508.rs:18:18
+   |
+LL |     let _value = array[0];  //[ast]~ ERROR [E0508]
+   |                  ^^^^^^^^ cannot move out of here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0508`.
diff --git a/src/test/ui/E0508.rs b/src/test/ui/E0508.rs
new file mode 100644 (file)
index 0000000..0c3dce6
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2016 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.
+
+// revisions: ast mir
+//[mir]compile-flags: -Z borrowck=mir
+
+struct NonCopy;
+
+fn main() {
+    let array = [NonCopy; 1];
+    let _value = array[0];  //[ast]~ ERROR [E0508]
+                            //[mir]~^ ERROR [E0508]
+}
diff --git a/src/test/ui/auxiliary/edition-kw-macro-2015.rs b/src/test/ui/auxiliary/edition-kw-macro-2015.rs
new file mode 100644 (file)
index 0000000..9127c8e
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2015
+
+#![feature(raw_identifiers)]
+
+#[macro_export]
+macro_rules! produces_async {
+    () => (pub fn async() {})
+}
+
+#[macro_export]
+macro_rules! produces_async_raw {
+    () => (pub fn r#async() {})
+}
+
+#[macro_export]
+macro_rules! consumes_async {
+    (async) => (1)
+}
+
+#[macro_export]
+macro_rules! consumes_async_raw {
+    (r#async) => (1)
+}
+
+#[macro_export]
+macro_rules! passes_ident {
+    ($i: ident) => ($i)
+}
diff --git a/src/test/ui/auxiliary/edition-kw-macro-2018.rs b/src/test/ui/auxiliary/edition-kw-macro-2018.rs
new file mode 100644 (file)
index 0000000..4fef77d
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2018
+
+#![feature(raw_identifiers)]
+
+#[macro_export]
+macro_rules! produces_async {
+    () => (pub fn async() {})
+}
+
+#[macro_export]
+macro_rules! produces_async_raw {
+    () => (pub fn r#async() {})
+}
+
+#[macro_export]
+macro_rules! consumes_async {
+    (async) => (1)
+}
+
+#[macro_export]
+macro_rules! consumes_async_raw {
+    (r#async) => (1)
+}
+
+#[macro_export]
+macro_rules! passes_ident {
+    ($i: ident) => ($i)
+}
index fc288e6b1d6145da8dae576f1217aac1d78c2d00..2284f0784c545d4bbe5223f5837907619a374364 100644 (file)
@@ -2,19 +2,28 @@ error[E0499]: cannot borrow `*arg` as mutable more than once at a time
   --> $DIR/mut-borrow-in-loop.rs:20:25
    |
 LL |             (self.func)(arg) //~ ERROR cannot borrow
-   |                         ^^^ mutable borrow starts here in previous iteration of loop
+   |             ------------^^^-
+   |             |           |
+   |             |           mutable borrow starts here in previous iteration of loop
+   |             borrow later used here
 
 error[E0499]: cannot borrow `*arg` as mutable more than once at a time
   --> $DIR/mut-borrow-in-loop.rs:26:25
    |
 LL |             (self.func)(arg) //~ ERROR cannot borrow
-   |                         ^^^ mutable borrow starts here in previous iteration of loop
+   |             ------------^^^-
+   |             |           |
+   |             |           mutable borrow starts here in previous iteration of loop
+   |             borrow later used here
 
 error[E0499]: cannot borrow `*arg` as mutable more than once at a time
   --> $DIR/mut-borrow-in-loop.rs:33:25
    |
 LL |             (self.func)(arg) //~ ERROR cannot borrow
-   |                         ^^^ mutable borrow starts here in previous iteration of loop
+   |             ------------^^^-
+   |             |           |
+   |             |           mutable borrow starts here in previous iteration of loop
+   |             borrow later used here
 
 error: aborting due to 3 previous errors
 
index 885edb55ed86c9a95ba09cdd68c1eaea1a62463d..63f33cafaf827f9440d3e3411a85dee82a3e678d 100644 (file)
@@ -11,7 +11,7 @@
 // Evaluation of constants in refutable patterns goes through
 // different compiler control-flow paths.
 
-#![allow(unused_imports, warnings)]
+#![allow(unused_imports, warnings, const_err)]
 
 use std::fmt;
 use std::{i8, i16, i32, i64, isize};
index 24e178152eef0cbd7010c09ebde0e942cd5d2f2d..ed14036b0b4cb85d47e6325ae5702bf5d2b4f4b1 100644 (file)
@@ -22,7 +22,7 @@
 const A_I8_T
     : [u32; (i8::MAX as i8 + 1i8) as usize]
     //~^ ERROR E0080
-    //~| WARN attempt to add with overflow
+    //~| ERROR attempt to add with overflow
     = [0; (i8::MAX as usize) + 1];
 
 fn main() {
index db0a6fc820446a2070b5701d16e383997ff0d2b0..fc4762f0554f7828e09c9133e3befac80052f3bb 100644 (file)
@@ -1,10 +1,10 @@
-warning: attempt to add with overflow
+error: attempt to add with overflow
   --> $DIR/const-eval-overflow-4.rs:23:13
    |
 LL |     : [u32; (i8::MAX as i8 + 1i8) as usize]
    |             ^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: #[warn(const_err)] on by default
+   = note: #[deny(const_err)] on by default
 
 error[E0080]: constant evaluation error
   --> $DIR/const-eval-overflow-4.rs:23:13
@@ -12,6 +12,6 @@ error[E0080]: constant evaluation error
 LL |     : [u32; (i8::MAX as i8 + 1i8) as usize]
    |             ^^^^^^^^^^^^^^^^^^^^^ attempt to add with overflow
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index dbddee862e022a87d3521e58ffec761291acf78b..8952a8386d7b8100bbcdb5f4d89796fc8343d214 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-pass
+#![warn(const_err)]
 
 const X: u32 = 5;
 const Y: u32 = 6;
index 713b1b36c08b1b0c55f807d0eee174608f2e45a4..5cf73b9fad66df9e23b5c416a71e728d753cc4d9 100644 (file)
@@ -1,19 +1,23 @@
 warning: attempt to subtract with overflow
-  --> $DIR/conditional_array_execution.rs:15:19
+  --> $DIR/conditional_array_execution.rs:16:19
    |
 LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
    |                   ^^^^^
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/conditional_array_execution.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: this constant cannot be used
-  --> $DIR/conditional_array_execution.rs:15:1
+  --> $DIR/conditional_array_execution.rs:16:1
    |
 LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 warning: constant evaluation error
-  --> $DIR/conditional_array_execution.rs:20:20
+  --> $DIR/conditional_array_execution.rs:21:20
    |
 LL |     println!("{}", FOO);
    |                    ^^^ referenced constant has errors
index 097fba4d3c45094b98152e68372b8878b789539e..7ec100e411b36d6b26222398d6acb0729ff8b626 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-pass
+#![warn(const_err)]
 
 #![feature(const_fn)]
 
index a22e8016296c4f95a3b2fe53907d52bd39a71db4..d0e13d5657e754866e6d497eab91e7137b1fc700 100644 (file)
@@ -1,37 +1,41 @@
 warning: attempt to subtract with overflow
-  --> $DIR/issue-43197.rs:20:20
+  --> $DIR/issue-43197.rs:21:20
    |
 LL |     const X: u32 = 0-1;
    |                    ^^^
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/issue-43197.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: this constant cannot be used
-  --> $DIR/issue-43197.rs:20:5
+  --> $DIR/issue-43197.rs:21:5
    |
 LL |     const X: u32 = 0-1;
    |     ^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 warning: attempt to subtract with overflow
-  --> $DIR/issue-43197.rs:23:24
+  --> $DIR/issue-43197.rs:24:24
    |
 LL |     const Y: u32 = foo(0-1);
    |                        ^^^
 
 warning: this constant cannot be used
-  --> $DIR/issue-43197.rs:23:5
+  --> $DIR/issue-43197.rs:24:5
    |
 LL |     const Y: u32 = foo(0-1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 warning: constant evaluation error
-  --> $DIR/issue-43197.rs:26:23
+  --> $DIR/issue-43197.rs:27:23
    |
 LL |     println!("{} {}", X, Y);
    |                       ^ referenced constant has errors
 
 warning: constant evaluation error
-  --> $DIR/issue-43197.rs:26:26
+  --> $DIR/issue-43197.rs:27:26
    |
 LL |     println!("{} {}", X, Y);
    |                          ^ referenced constant has errors
index 765113cfbb9e2ef8d639a1d63415b272077dc5c6..4133a8864f619b39088ed3ad696be37be27c1787 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-pass
+#![warn(const_err)]
 
 trait Foo {
     const AMT: usize;
index 01c6fa3623f8d95998e7a206978678829ef3dccc..ce6ff86610aa5d4a08f0dcb9aee512bfecd26c74 100644 (file)
@@ -1,13 +1,17 @@
 warning: constant evaluation error
-  --> $DIR/issue-44578.rs:35:20
+  --> $DIR/issue-44578.rs:36:20
    |
 LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/issue-44578.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: constant evaluation error
-  --> $DIR/issue-44578.rs:35:20
+  --> $DIR/issue-44578.rs:36:20
    |
 LL |     println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
index dc30c7f9cce041f0d8c97be8cbff3d2be1952c3b..7385860abae28020fd8921fc92b4aa63166959ed 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![warn(const_err)]
+
 // compile-pass
 // compile-flags: -O
 fn main() {
index 7761f192fdb70aa33edd4e4d1f6557bfb6625151..8e9a0ea43a43b8aae62f7e92984834ae0d33b9cd 100644 (file)
@@ -1,49 +1,53 @@
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:14:20
+  --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 0u32 - 1);
    |                    ^^^^^^^^ attempt to subtract with overflow
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/promoted_errors.rs:11:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:14:20
+  --> $DIR/promoted_errors.rs:16:20
    |
 LL |     println!("{}", 0u32 - 1);
    |                    ^^^^^^^^ attempt to subtract with overflow
 
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:17:14
+  --> $DIR/promoted_errors.rs:19:14
    |
 LL |     let _x = 0u32 - 1;
    |              ^^^^^^^^ attempt to subtract with overflow
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:19:20
+  --> $DIR/promoted_errors.rs:21:20
    |
 LL |     println!("{}", 1/(1-1));
    |                    ^^^^^^^
 
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:19:20
+  --> $DIR/promoted_errors.rs:21:20
    |
 LL |     println!("{}", 1/(1-1));
    |                    ^^^^^^^ attempt to divide by zero
 
 warning: attempt to divide by zero
-  --> $DIR/promoted_errors.rs:22:14
+  --> $DIR/promoted_errors.rs:24:14
    |
 LL |     let _x = 1/(1-1);
    |              ^^^^^^^
 
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:22:14
+  --> $DIR/promoted_errors.rs:24:14
    |
 LL |     let _x = 1/(1-1);
    |              ^^^^^^^ attempt to divide by zero
 
 warning: constant evaluation error
-  --> $DIR/promoted_errors.rs:25:20
+  --> $DIR/promoted_errors.rs:27:20
    |
 LL |     println!("{}", 1/(false as u32));
    |                    ^^^^^^^^^^^^^^^^ attempt to divide by zero
index c6bf07649af38a17dd33964436037a59b06d0493..ef8fdb33d748aa578dc66abfc348905e45716c81 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-pass
+#![warn(const_err)]
 
 #![crate_type = "lib"]
 
index 2981ac20cd981d639a426fd082a0486e2e4ff147..068825f1cd3106871f62c388bf84df8e9927fe37 100644 (file)
@@ -1,25 +1,29 @@
 warning: attempt to subtract with overflow
-  --> $DIR/pub_const_err.rs:15:20
+  --> $DIR/pub_const_err.rs:16:20
    |
 LL | pub const Z: u32 = 0 - 1;
    |                    ^^^^^
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/pub_const_err.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: this constant cannot be used
-  --> $DIR/pub_const_err.rs:15:1
+  --> $DIR/pub_const_err.rs:16:1
    |
 LL | pub const Z: u32 = 0 - 1;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 warning: attempt to subtract with overflow
-  --> $DIR/pub_const_err.rs:19:22
+  --> $DIR/pub_const_err.rs:20:22
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                      ^^^^^
 
 warning: this array length cannot be used
-  --> $DIR/pub_const_err.rs:19:22
+  --> $DIR/pub_const_err.rs:20:22
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                      ^^^^^ attempt to subtract with overflow
index d87cb7ed7707936ab5fb07554edb20f414ef739c..f65da1d8674a29105b1a1d6b0af4d9a6ae9327ac 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // compile-pass
+#![warn(const_err)]
 
 pub const Z: u32 = 0 - 1;
 //~^ WARN attempt to subtract with overflow
index 3e8966d854bf0ff49d9b8c9998c4735d8b6fb990..dcb8125fc55bcf4aee646145d33a44fde4850e09 100644 (file)
@@ -1,25 +1,29 @@
 warning: attempt to subtract with overflow
-  --> $DIR/pub_const_err_bin.rs:13:20
+  --> $DIR/pub_const_err_bin.rs:14:20
    |
 LL | pub const Z: u32 = 0 - 1;
    |                    ^^^^^
    |
-   = note: #[warn(const_err)] on by default
+note: lint level defined here
+  --> $DIR/pub_const_err_bin.rs:12:9
+   |
+LL | #![warn(const_err)]
+   |         ^^^^^^^^^
 
 warning: this constant cannot be used
-  --> $DIR/pub_const_err_bin.rs:13:1
+  --> $DIR/pub_const_err_bin.rs:14:1
    |
 LL | pub const Z: u32 = 0 - 1;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 warning: attempt to subtract with overflow
-  --> $DIR/pub_const_err_bin.rs:17:22
+  --> $DIR/pub_const_err_bin.rs:18:22
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                      ^^^^^
 
 warning: this array length cannot be used
-  --> $DIR/pub_const_err_bin.rs:17:22
+  --> $DIR/pub_const_err_bin.rs:18:22
    |
 LL | pub type Foo = [i32; 0 - 1];
    |                      ^^^^^ attempt to subtract with overflow
index ee07dabab1fc852c06d2f0c7a2bf486798bc4c5c..453e332a903c7bbdffe559e55fc1d553f033702b 100644 (file)
@@ -16,7 +16,7 @@
 const TWO: usize = 2;
 const LEN: usize = ONE - TWO;
 //~^ ERROR E0080
-//~| WARN attempt to subtract with overflow
+//~| ERROR attempt to subtract with overflow
 
 fn main() {
     let a: [i8; LEN] = unimplemented!();
index 8d737dbfc085754f4815e8ae060a95e6e13980e3..48ff7a81c24ee1fe491f94316e51dc2b952b77a3 100644 (file)
@@ -1,10 +1,10 @@
-warning: attempt to subtract with overflow
+error: attempt to subtract with overflow
   --> $DIR/const-len-underflow-separate-spans.rs:17:20
    |
 LL | const LEN: usize = ONE - TWO;
    |                    ^^^^^^^^^
    |
-   = note: #[warn(const_err)] on by default
+   = note: #[deny(const_err)] on by default
 
 error[E0080]: constant evaluation error
   --> $DIR/const-len-underflow-separate-spans.rs:17:20
@@ -18,6 +18,6 @@ error[E0080]: constant evaluation error
 LL |     let a: [i8; LEN] = unimplemented!();
    |                 ^^^ referenced constant has errors
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/edition-keywords-2015-2015-expansion.rs b/src/test/ui/edition-keywords-2015-2015-expansion.rs
new file mode 100644 (file)
index 0000000..b8a1994
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2015
+// aux-build:edition-kw-macro-2015.rs
+// compile-pass
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+mod one_async {
+    produces_async! {} // OK
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/ui/edition-keywords-2015-2015-parsing.rs b/src/test/ui/edition-keywords-2015-2015-parsing.rs
new file mode 100644 (file)
index 0000000..1fb91ca
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2015
+// aux-build:edition-kw-macro-2015.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+pub fn check_async() {
+    let mut async = 1; // OK
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} // OK
+    if passes_ident!(r#async) == 1 {} // OK
+    module::async(); // OK
+    module::r#async(); // OK
+}
diff --git a/src/test/ui/edition-keywords-2015-2015-parsing.stderr b/src/test/ui/edition-keywords-2015-2015-parsing.stderr
new file mode 100644 (file)
index 0000000..5b6fd3e
--- /dev/null
@@ -0,0 +1,14 @@
+error: no rules expected the token `r#async`
+  --> $DIR/edition-keywords-2015-2015-parsing.rs:24:31
+   |
+LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+   |                               ^^^^^^^
+
+error: no rules expected the token `async`
+  --> $DIR/edition-keywords-2015-2015-parsing.rs:25:35
+   |
+LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+   |                                   ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/edition-keywords-2015-2018-expansion.rs b/src/test/ui/edition-keywords-2015-2018-expansion.rs
new file mode 100644 (file)
index 0000000..bc14c10
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2015
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+mod one_async {
+    produces_async! {} // ERROR expected identifier, found reserved keyword
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
diff --git a/src/test/ui/edition-keywords-2015-2018-expansion.stderr b/src/test/ui/edition-keywords-2015-2018-expansion.stderr
new file mode 100644 (file)
index 0000000..13c4ee8
--- /dev/null
@@ -0,0 +1,10 @@
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2015-2018-expansion.rs:20:5
+   |
+LL |     produces_async! {} // ERROR expected identifier, found reserved keyword
+   |     ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/edition-keywords-2015-2018-parsing.rs b/src/test/ui/edition-keywords-2015-2018-parsing.rs
new file mode 100644 (file)
index 0000000..0b680eb
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2015
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+pub fn check_async() {
+    let mut async = 1; // OK
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} // OK
+    if passes_ident!(r#async) == 1 {} // OK
+    module::async(); // OK
+    module::r#async(); // OK
+}
diff --git a/src/test/ui/edition-keywords-2015-2018-parsing.stderr b/src/test/ui/edition-keywords-2015-2018-parsing.stderr
new file mode 100644 (file)
index 0000000..60cfbce
--- /dev/null
@@ -0,0 +1,14 @@
+error: no rules expected the token `r#async`
+  --> $DIR/edition-keywords-2015-2018-parsing.rs:24:31
+   |
+LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+   |                               ^^^^^^^
+
+error: no rules expected the token `async`
+  --> $DIR/edition-keywords-2015-2018-parsing.rs:25:35
+   |
+LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+   |                                   ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/edition-keywords-2018-2015-expansion.rs b/src/test/ui/edition-keywords-2018-2015-expansion.rs
new file mode 100644 (file)
index 0000000..6f85f42
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2018
+// aux-build:edition-kw-macro-2015.rs
+// compile-pass
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+mod one_async {
+    produces_async! {} // OK
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
+
+fn main() {}
diff --git a/src/test/ui/edition-keywords-2018-2015-parsing.rs b/src/test/ui/edition-keywords-2018-2015-parsing.rs
new file mode 100644 (file)
index 0000000..29c5ea4
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2018
+// aux-build:edition-kw-macro-2015.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2015;
+
+pub fn check_async() {
+    let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
+    if passes_ident!(r#async) == 1 {} // OK
+    module::async(); //~ ERROR expected identifier, found reserved keyword `async`
+    module::r#async(); // OK
+}
diff --git a/src/test/ui/edition-keywords-2018-2015-parsing.stderr b/src/test/ui/edition-keywords-2018-2015-parsing.stderr
new file mode 100644 (file)
index 0000000..0b3ca57
--- /dev/null
@@ -0,0 +1,32 @@
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2015-parsing.rs:20:13
+   |
+LL |     let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
+   |             ^^^^^ expected identifier, found reserved keyword
+
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2015-parsing.rs:30:13
+   |
+LL |     module::async(); //~ ERROR expected identifier, found reserved keyword `async`
+   |             ^^^^^ expected identifier, found reserved keyword
+
+error: no rules expected the token `r#async`
+  --> $DIR/edition-keywords-2018-2015-parsing.rs:24:31
+   |
+LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+   |                               ^^^^^^^
+
+error: no rules expected the token `async`
+  --> $DIR/edition-keywords-2018-2015-parsing.rs:25:35
+   |
+LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+   |                                   ^^^^^
+
+error: expected expression, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2015-parsing.rs:28:22
+   |
+LL |     if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
+   |                      ^^^^^ expected expression
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/edition-keywords-2018-2018-expansion.rs b/src/test/ui/edition-keywords-2018-2018-expansion.rs
new file mode 100644 (file)
index 0000000..ef7f63e
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2018
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+mod one_async {
+    produces_async! {} // ERROR expected identifier, found reserved keyword `async`
+}
+mod two_async {
+    produces_async_raw! {} // OK
+}
diff --git a/src/test/ui/edition-keywords-2018-2018-expansion.stderr b/src/test/ui/edition-keywords-2018-2018-expansion.stderr
new file mode 100644 (file)
index 0000000..cd51030
--- /dev/null
@@ -0,0 +1,10 @@
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2018-expansion.rs:20:5
+   |
+LL |     produces_async! {} // ERROR expected identifier, found reserved keyword `async`
+   |     ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword
+   |
+   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/edition-keywords-2018-2018-parsing.rs b/src/test/ui/edition-keywords-2018-2018-parsing.rs
new file mode 100644 (file)
index 0000000..a94808e
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition=2018
+// aux-build:edition-kw-macro-2018.rs
+
+#![feature(raw_identifiers)]
+
+#[macro_use]
+extern crate edition_kw_macro_2018;
+
+pub fn check_async() {
+    let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
+    let mut r#async = 1; // OK
+
+    r#async = consumes_async!(async); // OK
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async_raw!(r#async); // OK
+
+    if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
+    if passes_ident!(r#async) == 1 {} // OK
+    module::async(); //~ ERROR expected identifier, found reserved keyword `async`
+    module::r#async(); // OK
+}
diff --git a/src/test/ui/edition-keywords-2018-2018-parsing.stderr b/src/test/ui/edition-keywords-2018-2018-parsing.stderr
new file mode 100644 (file)
index 0000000..1b18d8a
--- /dev/null
@@ -0,0 +1,32 @@
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:20:13
+   |
+LL |     let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
+   |             ^^^^^ expected identifier, found reserved keyword
+
+error: expected identifier, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:30:13
+   |
+LL |     module::async(); //~ ERROR expected identifier, found reserved keyword `async`
+   |             ^^^^^ expected identifier, found reserved keyword
+
+error: no rules expected the token `r#async`
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:24:31
+   |
+LL |     r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
+   |                               ^^^^^^^
+
+error: no rules expected the token `async`
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:25:35
+   |
+LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+   |                                   ^^^^^
+
+error: expected expression, found reserved keyword `async`
+  --> $DIR/edition-keywords-2018-2018-parsing.rs:28:22
+   |
+LL |     if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
+   |                      ^^^^^ expected expression
+
+error: aborting due to 5 previous errors
+
index 5e401bd6c79da92a3faa90ae0a3630422d832ffe..25ec5c458312d8eb21cce4f1c8d6f56e7568ce54 100644 (file)
@@ -12,15 +12,15 @@ error[E0080]: constant evaluation error
 LL |     X = (1 << 500), //~ ERROR E0080
    |         ^^^^^^^^^^ attempt to shift left with overflow
 
-warning: attempt to divide by zero
+error: attempt to divide by zero
   --> $DIR/E0080.rs:14:9
    |
 LL |     Y = (1 / 0) //~ ERROR E0080
    |         ^^^^^^^
    |
-   = note: #[warn(const_err)] on by default
+   = note: #[deny(const_err)] on by default
 
-warning: constant evaluation error
+error: constant evaluation error
   --> $DIR/E0080.rs:14:9
    |
 LL |     Y = (1 / 0) //~ ERROR E0080
@@ -32,6 +32,6 @@ error[E0080]: constant evaluation error
 LL |     Y = (1 / 0) //~ ERROR E0080
    |         ^^^^^^^ attempt to divide by zero
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
index ec715b3f0ba62f9e618ead0a00b5a00ebdd00e3d..5b13686240e7c0de46e71ec8a31c981b6f55782d 100644 (file)
@@ -12,5 +12,14 @@ fn main() {
     println!("{");
     println!("{{}}");
     println!("}");
+    let _ = format!("{_foo}", _foo = 6usize);
+    //~^ ERROR invalid format string: invalid argument name `_foo`
+    let _ = format!("{_}", _ = 6usize);
+    //~^ ERROR invalid format string: invalid argument name `_`
+    let _ = format!("{");
+    //~^ ERROR invalid format string: expected `'}'` but string was terminated
+    let _ = format!("}");
+    //~^ ERROR invalid format string: unmatched `}` found
+    let _ = format!("{\\}");
+    //~^ ERROR invalid format string: expected `'}'`, found `'\\'`
 }
-
index a7a66722e527f80273e571b0e460c4c88ce58948..ff766ddc8fa67ad132d1d1e137e4fc7ca427760a 100644 (file)
@@ -2,7 +2,7 @@ error: invalid format string: expected `'}'` but string was terminated
   --> $DIR/format-string-error.rs:12:5
    |
 LL |     println!("{");
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ expected `'}'` in format string
    |
    = note: if you intended to print `{`, you can escape it using `{{`
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
@@ -11,10 +11,48 @@ error: invalid format string: unmatched `}` found
   --> $DIR/format-string-error.rs:14:5
    |
 LL |     println!("}");
-   |     ^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^ unmatched `}` in format string
    |
    = note: if you intended to print `}`, you can escape it using `}}`
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
 
-error: aborting due to 2 previous errors
+error: invalid format string: invalid argument name `_foo`
+  --> $DIR/format-string-error.rs:15:23
+   |
+LL |     let _ = format!("{_foo}", _foo = 6usize);
+   |                       ^^^^ invalid argument name in format string
+   |
+   = note: argument names cannot start with an underscore
+
+error: invalid format string: invalid argument name `_`
+  --> $DIR/format-string-error.rs:17:23
+   |
+LL |     let _ = format!("{_}", _ = 6usize);
+   |                       ^ invalid argument name in format string
+   |
+   = note: argument names cannot start with an underscore
+
+error: invalid format string: expected `'}'` but string was terminated
+  --> $DIR/format-string-error.rs:19:23
+   |
+LL |     let _ = format!("{");
+   |                       ^ expected `'}'` in format string
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+
+error: invalid format string: unmatched `}` found
+  --> $DIR/format-string-error.rs:21:22
+   |
+LL |     let _ = format!("}");
+   |                      ^ unmatched `}` in format string
+   |
+   = note: if you intended to print `}`, you can escape it using `}}`
+
+error: invalid format string: expected `'}'`, found `'/'`
+  --> $DIR/format-string-error.rs:23:23
+   |
+LL |     let _ = format!("{/}");
+   |                       ^ expected `}` in format string
+
+error: aborting due to 7 previous errors
 
index c6f021f8c36cbbf21259531db20550abc10e063a..b955a51e38d73433184f516491839ff030d7074c 100644 (file)
@@ -4,14 +4,14 @@ error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as imm
 LL |         match map.get() {
    |               --- immutable borrow occurs here
 ...
-LL |                 map.set(String::new()); // Just AST errors here
+LL |                 map.set(String::new()); // Ideally, this would not error.
    |                 ^^^ mutable borrow occurs here
 ...
 LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:44:17
+  --> $DIR/get_default.rs:45:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
@@ -23,19 +23,40 @@ LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:50:17
+  --> $DIR/get_default.rs:51:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
 ...
-LL |                 map.set(String::new()); // Just AST errors here
+LL |                 map.set(String::new()); // Ideally, just AST would error here
    |                 ^^^ mutable borrow occurs here
 ...
 LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
-  --> $DIR/get_default.rs:44:17
+  --> $DIR/get_default.rs:33:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 map.set(String::new()); // Ideally, this would not error.
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 26:1...
+  --> $DIR/get_default.rs:26:1
+   |
+LL | / fn ok(map: &mut Map) -> &String {
+LL | |     loop {
+LL | |         match map.get() {
+LL | |             Some(v) => {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:45:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
@@ -46,6 +67,27 @@ LL |                 map.set(String::new()); // Both AST and MIR error here
 LL |                 return v;
    |                        - borrow later used here
 
-error: aborting due to 4 previous errors
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:51:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 map.set(String::new()); // Ideally, just AST would error here
+   |                 ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
+  --> $DIR/get_default.rs:41:1
+   |
+LL | / fn err(map: &mut Map) -> &String {
+LL | |     loop {
+LL | |         match map.get() {
+LL | |             Some(v) => {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0502`.
index 728c84695eacf0e3117e8246a75ebb12b18a2c19..1a417b1e28c2e5629b49db7e667cce3bd4e62582 100644 (file)
@@ -30,8 +30,9 @@ fn ok(map: &mut Map) -> &String {
                 return v;
             }
             None => {
-                map.set(String::new()); // Just AST errors here
+                map.set(String::new()); // Ideally, this would not error.
                 //~^ ERROR borrowed as immutable (Ast)
+                //~| ERROR borrowed as immutable (Mir)
             }
         }
     }
@@ -47,8 +48,9 @@ fn err(map: &mut Map) -> &String {
                 return v;
             }
             None => {
-                map.set(String::new()); // Just AST errors here
+                map.set(String::new()); // Ideally, just AST would error here
                 //~^ ERROR borrowed as immutable (Ast)
+                //~| ERROR borrowed as immutable (Mir)
             }
         }
     }
index 064fd38b872513db446308728f0351552cb7ce54..dd69e18652c9afc598ffeb6050598a55b560acaf 100644 (file)
@@ -4,14 +4,14 @@ error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as imm
 LL |         match map.get() {
    |               --- immutable borrow occurs here
 ...
-LL |                 map.set(String::new()); // Just AST errors here
+LL |                 map.set(String::new()); // Ideally, this would not error.
    |                 ^^^ mutable borrow occurs here
 ...
 LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:44:17
+  --> $DIR/get_default.rs:45:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
@@ -23,19 +23,61 @@ LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
-  --> $DIR/get_default.rs:50:17
+  --> $DIR/get_default.rs:51:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
 ...
-LL |                 map.set(String::new()); // Just AST errors here
+LL |                 map.set(String::new()); // Ideally, just AST would error here
    |                 ^^^ mutable borrow occurs here
 ...
 LL | }
    | - immutable borrow ends here
 
 error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
-  --> $DIR/get_default.rs:44:17
+  --> $DIR/get_default.rs:33:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 map.set(String::new()); // Ideally, this would not error.
+   |                 ^^^ mutable borrow occurs here
+   |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 26:1...
+  --> $DIR/get_default.rs:26:1
+   |
+LL | / fn ok(map: &mut Map) -> &String {
+LL | |     loop {
+LL | |         match map.get() {
+LL | |             Some(v) => {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:51:17
+   |
+LL |         match map.get() {
+   |               --- immutable borrow occurs here
+...
+LL |                 map.set(String::new()); // Ideally, just AST would error here
+   |                 ^^^ mutable borrow occurs here
+   |
+note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
+  --> $DIR/get_default.rs:41:1
+   |
+LL | / fn err(map: &mut Map) -> &String {
+LL | |     loop {
+LL | |         match map.get() {
+LL | |             Some(v) => {
+...  |
+LL | |     }
+LL | | }
+   | |_^
+
+error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
+  --> $DIR/get_default.rs:45:17
    |
 LL |         match map.get() {
    |               --- immutable borrow occurs here
@@ -46,6 +88,6 @@ LL |                 map.set(String::new()); // Both AST and MIR error here
 LL |                 return v;
    |                        - borrow later used here
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0502`.
index 812e9c5f39d87f9142eae517dd46ee893c21888c..b2ce5ce52f719ef2c073f83e946e3370150cecba 100644 (file)
@@ -118,6 +118,9 @@ pub fn parse(s: String) -> CompareMode {
 
 #[derive(Clone)]
 pub struct Config {
+    /// Whether to overwrite stderr/stdout files instead of complaining about changes in output
+    pub bless: bool,
+
     /// The library paths required for running the compiler
     pub compile_lib_path: PathBuf,
 
index 42a2cdfa55b5ad9ee78a913d1195402ecd54b7be..2bfc1ece09590687d7df1001a544b861cbccad22 100644 (file)
@@ -166,6 +166,11 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "FLAGS",
         )
         .optflag("", "verbose", "run tests verbosely, showing all output")
+        .optflag(
+            "",
+            "bless",
+            "overwrite stderr/stdout files instead of complaining about a mismatch",
+        )
         .optflag(
             "",
             "quiet",
@@ -290,6 +295,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
     let src_base = opt_path(matches, "src-base");
     let run_ignored = matches.opt_present("ignored");
     Config {
+        bless: matches.opt_present("bless"),
         compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
         run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
         rustc_path: opt_path(matches, "rustc-path"),
index f46713441362b5a75be89309b0eeac011db6ed3b..140c90aaeacc13dca77768aa7e126665c9678fbf 100644 (file)
@@ -2596,15 +2596,13 @@ fn run_ui_test(&self) {
         }
 
         if errors > 0 {
-            println!("To update references, run this command from build directory:");
+            println!("To update references, rerun the tests and pass the `--bless` flag");
             let relative_path_to_file = self.testpaths
                 .relative_dir
                 .join(self.testpaths.file.file_name().unwrap());
             println!(
-                "{}/update-references.sh '{}' '{}'",
-                self.config.src_base.display(),
-                self.config.build_base.display(),
-                relative_path_to_file.display()
+                "To only update this specific test, also pass `--test-args {}`",
+                relative_path_to_file.display(),
             );
             self.fatal_proc_rec(
                 &format!("{} errors occurred comparing output.", errors),
@@ -2926,29 +2924,31 @@ fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
             return 0;
         }
 
-        if expected.is_empty() {
-            println!("normalized {}:\n{}\n", kind, actual);
-        } else {
-            println!("diff of {}:\n", kind);
-            let diff_results = make_diff(expected, actual, 3);
-            for result in diff_results {
-                let mut line_number = result.line_number;
-                for line in result.lines {
-                    match line {
-                        DiffLine::Expected(e) => {
-                            println!("-\t{}", e);
-                            line_number += 1;
-                        }
-                        DiffLine::Context(c) => {
-                            println!("{}\t{}", line_number, c);
-                            line_number += 1;
-                        }
-                        DiffLine::Resulting(r) => {
-                            println!("+\t{}", r);
+        if !self.config.bless {
+            if expected.is_empty() {
+                println!("normalized {}:\n{}\n", kind, actual);
+            } else {
+                println!("diff of {}:\n", kind);
+                let diff_results = make_diff(expected, actual, 3);
+                for result in diff_results {
+                    let mut line_number = result.line_number;
+                    for line in result.lines {
+                        match line {
+                            DiffLine::Expected(e) => {
+                                println!("-\t{}", e);
+                                line_number += 1;
+                            }
+                            DiffLine::Context(c) => {
+                                println!("{}\t{}", line_number, c);
+                                line_number += 1;
+                            }
+                            DiffLine::Resulting(r) => {
+                                println!("+\t{}", r);
+                            }
                         }
                     }
+                    println!("");
                 }
-                println!("");
             }
         }
 
@@ -2958,19 +2958,47 @@ fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize {
             .with_extra_extension(mode)
             .with_extra_extension(kind);
 
-        match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
-            Ok(()) => {}
-            Err(e) => self.fatal(&format!(
-                "failed to write {} to `{}`: {}",
+        let mut files = vec![output_file];
+        if self.config.bless {
+            files.push(expected_output_path(
+                self.testpaths,
+                self.revision,
+                &self.config.compare_mode,
                 kind,
-                output_file.display(),
-                e
-            )),
+            ));
+        }
+
+        for output_file in &files {
+            if actual.is_empty() {
+                if let Err(e) = ::std::fs::remove_file(output_file) {
+                    self.fatal(&format!(
+                        "failed to delete `{}`: {}",
+                        output_file.display(),
+                        e,
+                    ));
+                }
+            } else {
+                match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
+                    Ok(()) => {}
+                    Err(e) => self.fatal(&format!(
+                        "failed to write {} to `{}`: {}",
+                        kind,
+                        output_file.display(),
+                        e
+                    )),
+                }
+            }
         }
 
         println!("\nThe actual {0} differed from the expected {0}.", kind);
-        println!("Actual {} saved to {}", kind, output_file.display());
-        1
+        for output_file in files {
+            println!("Actual {} saved to {}", kind, output_file.display());
+        }
+        if self.config.bless {
+            0
+        } else {
+            1
+        }
     }
 
     fn create_stamp(&self) {
index 3e3df0485004bc1343bc8200b68c67ac7c479b28..cf0609d0af0b734d4b9ee9dce6df66f946fc763f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3e3df0485004bc1343bc8200b68c67ac7c479b28
+Subproject commit cf0609d0af0b734d4b9ee9dce6df66f946fc763f
index 344f617ef95bc069da4e78c66caf95e98d14da91..d38815004418cceb7fd62bd824c25981289003f9 100644 (file)
@@ -7,7 +7,7 @@ authors = ["The Rust Project Developers"]
 # the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
 # rustdoc a different name.
 [[bin]]
-name = "rustdoc-tool-binary"
+name = "rustdoc_tool_binary"
 path = "main.rs"
 
 [dependencies]
index db8cb0b8d6942d42a322b1d36b2504977404f362..bf2581bf7709b91c4431ba7074de910f72283e1f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit db8cb0b8d6942d42a322b1d36b2504977404f362
+Subproject commit bf2581bf7709b91c4431ba7074de910f72283e1f