diff --git a/.gitignore b/.gitignore index ff839c34df1a7..b54bab177d0ae 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ .hg/ .hgignore .idea +*.iml __pycache__/ *.py[cod] *$py.class diff --git a/.gitmodules b/.gitmodules index 1ef3c086a1c23..6244b3c095186 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,9 +2,6 @@ path = src/llvm url = https://github.com/rust-lang/llvm.git branch = master -[submodule "src/compiler-rt"] - path = src/compiler-rt - url = https://github.com/rust-lang/compiler-rt.git [submodule "src/rt/hoedown"] path = src/rt/hoedown url = https://github.com/rust-lang/hoedown.git @@ -33,3 +30,6 @@ [submodule "src/tools/rls"] path = src/tools/rls url = https://github.com/rust-lang-nursery/rls.git +[submodule "src/libcompiler_builtins"] + path = src/libcompiler_builtins + url = https://github.com/rust-lang-nursery/compiler-builtins diff --git a/README.md b/README.md index 0b209fd3e9492..a1f018610753c 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,9 @@ Read ["Installation"] from [The Book]. > ***Note:*** Install locations can be adjusted by copying the config file > from `./src/bootstrap/config.toml.example` to `./config.toml`, and - > adjusting the `prefix` option under `[install]`. Various other options are - > also supported, and are documented in the config file. + > adjusting the `prefix` option under `[install]`. Various other options, such + > as enabling debug information, are also supported, and are documented in + > the config file. When complete, `sudo ./x.py install` will place several programs into `/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the diff --git a/src/Cargo.lock b/src/Cargo.lock index 2d42903ad0a7d..28c4d2e981938 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -43,6 +43,8 @@ dependencies = [ name = "alloc_jemalloc" version = "0.0.0" dependencies = [ + "alloc 0.0.0", + "alloc_system 0.0.0", "build_helper 0.1.0", "core 0.0.0", "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", @@ -53,6 +55,7 @@ dependencies = [ name = "alloc_system" version = "0.0.0" dependencies = [ + "alloc 0.0.0", "core 0.0.0", "libc 0.0.0", ] @@ -273,7 +276,6 @@ dependencies = [ name = "compiler_builtins" version = "0.0.0" dependencies = [ - "build_helper 0.1.0", "core 0.0.0", "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -883,14 +885,6 @@ name = "proc_macro" version = "0.0.0" dependencies = [ "syntax 0.0.0", -] - -[[package]] -name = "proc_macro_plugin" -version = "0.0.0" -dependencies = [ - "rustc_plugin 0.0.0", - "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -1127,10 +1121,21 @@ name = "rustc-serialize" version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc_allocator" +version = "0.0.0" +dependencies = [ + "rustc 0.0.0", + "rustc_errors 0.0.0", + "syntax 0.0.0", + "syntax_pos 0.0.0", +] + [[package]] name = "rustc_asan" version = "0.0.0" dependencies = [ + "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1203,8 +1208,8 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc_macro_plugin 0.0.0", "rustc 0.0.0", + "rustc_allocator 0.0.0", "rustc_back 0.0.0", "rustc_borrowck 0.0.0", "rustc_const_eval 0.0.0", @@ -1273,6 +1278,7 @@ dependencies = [ name = "rustc_lsan" version = "0.0.0" dependencies = [ + "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1317,6 +1323,7 @@ dependencies = [ name = "rustc_msan" version = "0.0.0" dependencies = [ + "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1399,6 +1406,7 @@ dependencies = [ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_allocator 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 8c6eaee24f294..497a5ab6c536c 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -75,16 +75,11 @@ fn main() { Err(_) => 0, }; - // Build scripts always use the snapshot compiler which is guaranteed to be - // able to produce an executable, whereas intermediate compilers may not - // have the standard library built yet and may not be able to produce an - // executable. Otherwise we just use the standard compiler we're - // bootstrapping with. - // - // Also note that cargo will detect the version of the compiler to trigger - // a rebuild when the compiler changes. If this happens, we want to make - // sure to use the actual compiler instead of the snapshot compiler becase - // that's the one that's actually changing. + // Use a different compiler for build scripts, since there may not yet be a + // libstd for the real compiler to use. However, if Cargo is attempting to + // determine the version of the compiler, the real compiler needs to be + // used. Currently, these two states are differentiated based on whether + // --target and -vV is/isn't passed. let (rustc, libdir) = if target.is_none() && version.is_none() { ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR") } else { @@ -142,6 +137,11 @@ fn main() { } } + let crate_name = args.windows(2) + .find(|a| &*a[0] == "--crate-name") + .unwrap(); + let crate_name = &*crate_name[1]; + // If we're compiling specifically the `panic_abort` crate then we pass // the `-C panic=abort` option. Note that we do not do this for any // other crate intentionally as this is the only crate for now that we @@ -150,9 +150,7 @@ fn main() { // This... is a bit of a hack how we detect this. Ideally this // information should be encoded in the crate I guess? Would likely // require an RFC amendment to RFC 1513, however. - let is_panic_abort = args.windows(2) - .any(|a| &*a[0] == "--crate-name" && &*a[1] == "panic_abort"); - if is_panic_abort { + if crate_name == "panic_abort" { cmd.arg("-C").arg("panic=abort"); } @@ -167,7 +165,15 @@ fn main() { Ok(s) => if s == "true" { "y" } else { "n" }, Err(..) => "n", }; - cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); + + // The compiler builtins are pretty sensitive to symbols referenced in + // libcore and such, so we never compile them with debug assertions. + if crate_name == "compiler_builtins" { + cmd.arg("-C").arg("debug-assertions=no"); + } else { + cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); + } + if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") { cmd.arg("-C").arg(format!("codegen-units={}", s)); } diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index eaf2a40f2fad4..ebc4c2fdf7bf2 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -583,7 +583,7 @@ def update_submodules(self): (self.get_toml('jemalloc') or self.get_mk('CFG_JEMALLOC_ROOT'))))] run(["git", "submodule", "update", - "--init"] + submodules, + "--init", "--recursive"] + submodules, cwd=self.rust_root, verbose=self.verbose) run(["git", "submodule", "-q", "foreach", "git", "reset", "-q", "--hard"], diff --git a/src/bootstrap/cc.rs b/src/bootstrap/cc.rs index 54c8194678e61..7c7161916ee2c 100644 --- a/src/bootstrap/cc.rs +++ b/src/bootstrap/cc.rs @@ -42,10 +42,13 @@ use config::Target; pub fn find(build: &mut Build) { // For all targets we're going to need a C compiler for building some shims // and such as well as for being a linker for Rust code. - for target in build.config.target.iter() { + // + // This includes targets that aren't necessarily passed on the commandline + // (FIXME: Perhaps it shouldn't?) + for target in &build.config.target { let mut cfg = gcc::Config::new(); cfg.cargo_metadata(false).opt_level(0).debug(false) - .target(target).host(&build.config.build); + .target(target).host(&build.build); let config = build.config.target_config.get(target); if let Some(cc) = config.and_then(|c| c.cc.as_ref()) { @@ -64,10 +67,13 @@ pub fn find(build: &mut Build) { } // For all host triples we need to find a C++ compiler as well - for host in build.config.host.iter() { + // + // This includes hosts that aren't necessarily passed on the commandline + // (FIXME: Perhaps it shouldn't?) + for host in &build.config.host { let mut cfg = gcc::Config::new(); cfg.cargo_metadata(false).opt_level(0).debug(false).cpp(true) - .target(host).host(&build.config.build); + .target(host).host(&build.build); let config = build.config.target_config.get(host); if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { cfg.compiler(cxx); diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 4664b1f765e63..1153acfa57d39 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -23,12 +23,12 @@ use build_helper::output; use Build; // The version number -pub const CFG_RELEASE_NUM: &'static str = "1.20.0"; +pub const CFG_RELEASE_NUM: &str = "1.20.0"; // An optional number to put after the label, e.g. '.2' -> '-beta.2' // Be sure to make this starts with a dot to conform to semver pre-release // versions (section 9) -pub const CFG_PRERELEASE_VERSION: &'static str = ".1"; +pub const CFG_PRERELEASE_VERSION: &str = ".1"; pub struct GitInfo { inner: Option<Info>, @@ -99,6 +99,10 @@ impl GitInfo { version.push_str(&inner.commit_date); version.push_str(")"); } - return version + version + } + + pub fn is_git(&self) -> bool { + self.inner.is_some() } } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 277728b90b763..b3b5ae8d67d65 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -13,23 +13,22 @@ //! This file implements the various regression test suites that we execute on //! our CI. -extern crate build_helper; - use std::collections::HashSet; use std::env; +use std::iter; use std::fmt; use std::fs::{self, File}; use std::path::{PathBuf, Path}; use std::process::Command; use std::io::Read; -use build_helper::output; +use build_helper::{self, output}; use {Build, Compiler, Mode}; use dist; use util::{self, dylib_path, dylib_path_var, exe}; -const ADB_TEST_DIR: &'static str = "/data/tmp/work"; +const ADB_TEST_DIR: &str = "/data/tmp/work"; /// The two modes of the test runner; tests or benchmarks. #[derive(Copy, Clone)] @@ -60,7 +59,7 @@ impl fmt::Display for TestKind { } fn try_run(build: &Build, cmd: &mut Command) { - if build.flags.cmd.no_fail_fast() { + if !build.fail_fast { if !build.try_run(cmd) { let failures = build.delayed_failures.get(); build.delayed_failures.set(failures + 1); @@ -71,7 +70,7 @@ fn try_run(build: &Build, cmd: &mut Command) { } fn try_run_quiet(build: &Build, cmd: &mut Command) { - if build.flags.cmd.no_fail_fast() { + if !build.fail_fast { if !build.try_run_quiet(cmd) { let failures = build.delayed_failures.get(); build.delayed_failures.set(failures + 1); @@ -99,7 +98,7 @@ pub fn linkcheck(build: &Build, host: &str) { /// This tool in `src/tools` will check out a few Rust projects and run `cargo /// test` to ensure that we don't regress the test suites there. pub fn cargotest(build: &Build, stage: u32, host: &str) { - let ref compiler = Compiler::new(stage, host); + let compiler = Compiler::new(stage, host); // Note that this is a short, cryptic, and not scoped directory name. This // is currently to minimize the length of path on Windows where we otherwise @@ -109,11 +108,11 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) { let _time = util::timeit(); let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest")); - build.prepare_tool_cmd(compiler, &mut cmd); - try_run(build, cmd.arg(&build.cargo) + build.prepare_tool_cmd(&compiler, &mut cmd); + try_run(build, cmd.arg(&build.initial_cargo) .arg(&out_dir) - .env("RUSTC", build.compiler_path(compiler)) - .env("RUSTDOC", build.rustdoc(compiler))); + .env("RUSTC", build.compiler_path(&compiler)) + .env("RUSTDOC", build.rustdoc(&compiler))); } /// Runs `cargo test` for `cargo` packaged with Rust. @@ -124,13 +123,12 @@ pub fn cargo(build: &Build, stage: u32, host: &str) { // and not RUSTC because the Cargo test suite has tests that will // fail if rustc is not spelled `rustc`. let path = build.sysroot(compiler).join("bin"); - let old_path = ::std::env::var("PATH").expect(""); - let sep = if cfg!(windows) { ";" } else {":" }; - let ref newpath = format!("{}{}{}", path.display(), sep, old_path); + let old_path = env::var_os("PATH").unwrap_or_default(); + let newpath = env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect(""); let mut cargo = build.cargo(compiler, Mode::Tool, host, "test"); cargo.arg("--manifest-path").arg(build.src.join("src/tools/cargo/Cargo.toml")); - if build.flags.cmd.no_fail_fast() { + if !build.fail_fast { cargo.arg("--no-fail-fast"); } @@ -198,9 +196,9 @@ pub fn compiletest(build: &Build, cmd.arg("--mode").arg(mode); cmd.arg("--target").arg(target); cmd.arg("--host").arg(compiler.host); - cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build)); + cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.build)); - if let Some(nodejs) = build.config.nodejs.as_ref() { + if let Some(ref nodejs) = build.config.nodejs { cmd.arg("--nodejs").arg(nodejs); } @@ -224,7 +222,7 @@ pub fn compiletest(build: &Build, cmd.arg("--docck-python").arg(build.python()); - if build.config.build.ends_with("apple-darwin") { + if build.build.ends_with("apple-darwin") { // Force /usr/bin/python on macOS for LLDB tests because we're loading the // LLDB plugin's compiled module which only works with the system python // (namely not Homebrew-installed python) @@ -251,7 +249,7 @@ pub fn compiletest(build: &Build, cmd.args(&build.flags.cmd.test_args()); - if build.config.verbose() || build.flags.verbose() { + if build.is_verbose() { cmd.arg("--verbose"); } @@ -279,7 +277,7 @@ pub fn compiletest(build: &Build, if build.remote_tested(target) { cmd.arg("--remote-test-client") - .arg(build.tool(&Compiler::new(0, &build.config.build), + .arg(build.tool(&Compiler::new(0, &build.build), "remote-test-client")); } @@ -368,7 +366,7 @@ pub fn error_index(build: &Build, compiler: &Compiler) { "error_index_generator") .arg("markdown") .arg(&output) - .env("CFG_BUILD", &build.config.build)); + .env("CFG_BUILD", &build.build)); markdown_test(build, compiler, &output); } @@ -450,7 +448,7 @@ pub fn krate(build: &Build, cargo.arg("--manifest-path") .arg(build.src.join(path).join("Cargo.toml")) .arg("--features").arg(features); - if test_kind.subcommand() == "test" && build.flags.cmd.no_fail_fast() { + if test_kind.subcommand() == "test" && !build.fail_fast { cargo.arg("--no-fail-fast"); } @@ -520,16 +518,14 @@ fn krate_emscripten(build: &Build, compiler: &Compiler, target: &str, mode: Mode) { - let mut tests = Vec::new(); let out_dir = build.cargo_out(compiler, mode, target); - find_tests(&out_dir.join("deps"), target, &mut tests); + let tests = find_tests(&out_dir.join("deps"), target); + let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured"); for test in tests { - let test_file_name = test.to_string_lossy().into_owned(); - println!("running {}", test_file_name); - let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured"); + println!("running {}", test.display()); let mut cmd = Command::new(nodejs); - cmd.arg(&test_file_name); + cmd.arg(&test); if build.config.quiet_tests { cmd.arg("--quiet"); } @@ -541,11 +537,10 @@ fn krate_remote(build: &Build, compiler: &Compiler, target: &str, mode: Mode) { - let mut tests = Vec::new(); let out_dir = build.cargo_out(compiler, mode, target); - find_tests(&out_dir.join("deps"), target, &mut tests); + let tests = find_tests(&out_dir.join("deps"), target); - let tool = build.tool(&Compiler::new(0, &build.config.build), + let tool = build.tool(&Compiler::new(0, &build.build), "remote-test-client"); for test in tests { let mut cmd = Command::new(&tool); @@ -559,9 +554,8 @@ fn krate_remote(build: &Build, } } -fn find_tests(dir: &Path, - target: &str, - dst: &mut Vec<PathBuf>) { +fn find_tests(dir: &Path, target: &str) -> Vec<PathBuf> { + let mut dst = Vec::new(); for e in t!(dir.read_dir()).map(|e| t!(e)) { let file_type = t!(e.file_type()); if !file_type.is_file() { @@ -576,6 +570,7 @@ fn find_tests(dir: &Path, dst.push(e.path()); } } + dst } pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) { @@ -590,7 +585,7 @@ pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) { .join(exe("remote-test-server", target)); // Spawn the emulator and wait for it to come online - let tool = build.tool(&Compiler::new(0, &build.config.build), + let tool = build.tool(&Compiler::new(0, &build.build), "remote-test-client"); let mut cmd = Command::new(&tool); cmd.arg("spawn-emulator") @@ -616,7 +611,7 @@ pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) { /// Run "distcheck", a 'make check' from a tarball pub fn distcheck(build: &Build) { - if build.config.build != "x86_64-unknown-linux-gnu" { + if build.build != "x86_64-unknown-linux-gnu" { return } if !build.config.host.iter().any(|s| s == "x86_64-unknown-linux-gnu") { @@ -641,7 +636,7 @@ pub fn distcheck(build: &Build) { .args(&build.config.configure_args) .arg("--enable-vendor") .current_dir(&dir)); - build.run(Command::new(build_helper::make(&build.config.build)) + build.run(Command::new(build_helper::make(&build.build)) .arg("check") .current_dir(&dir)); @@ -659,7 +654,7 @@ pub fn distcheck(build: &Build) { build.run(&mut cmd); let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml"); - build.run(Command::new(&build.cargo) + build.run(Command::new(&build.initial_cargo) .arg("generate-lockfile") .arg("--manifest-path") .arg(&toml) @@ -668,13 +663,13 @@ pub fn distcheck(build: &Build) { /// Test the build system itself pub fn bootstrap(build: &Build) { - let mut cmd = Command::new(&build.cargo); + let mut cmd = Command::new(&build.initial_cargo); cmd.arg("test") .current_dir(build.src.join("src/bootstrap")) .env("CARGO_TARGET_DIR", build.out.join("bootstrap")) .env("RUSTC_BOOTSTRAP", "1") - .env("RUSTC", &build.rustc); - if build.flags.cmd.no_fail_fast() { + .env("RUSTC", &build.initial_rustc); + if !build.fail_fast { cmd.arg("--no-fail-fast"); } cmd.arg("--").args(&build.flags.cmd.test_args()); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index b2bd792e93ba6..5a3106c7d5e64 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -50,7 +50,7 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) { let mut cargo = build.cargo(compiler, Mode::Libstd, target, "build"); let mut features = build.std_features(); - if let Ok(target) = env::var("MACOSX_STD_DEPLOYMENT_TARGET") { + if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") { cargo.env("MACOSX_DEPLOYMENT_TARGET", target); } @@ -158,7 +158,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st return } - let compiler = Compiler::new(0, &build.config.build); + let compiler = Compiler::new(0, &build.build); let compiler_path = build.compiler_path(&compiler); let src_dir = &build.src.join("src/rtstartup"); let dst_dir = &build.native_dir(target).join("rtstartup"); @@ -199,7 +199,7 @@ pub fn test(build: &Build, target: &str, compiler: &Compiler) { let out_dir = build.cargo_out(compiler, Mode::Libtest, target); build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build"); - if let Ok(target) = env::var("MACOSX_STD_DEPLOYMENT_TARGET") { + if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") { cargo.env("MACOSX_DEPLOYMENT_TARGET", target); } cargo.arg("--manifest-path") @@ -247,7 +247,7 @@ pub fn rustc(build: &Build, target: &str, compiler: &Compiler) { cargo.env("CFG_RELEASE", build.rust_release()) .env("CFG_RELEASE_CHANNEL", &build.config.channel) .env("CFG_VERSION", build.rust_version()) - .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(PathBuf::new())); + .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default()); if compiler.stage == 0 { cargo.env("CFG_LIBDIR_RELATIVE", "lib"); @@ -351,7 +351,7 @@ pub fn create_sysroot(build: &Build, compiler: &Compiler) { /// Prepare a new compiler from the artifacts in `stage` /// /// This will assemble a compiler in `build/$host/stage$stage`. The compiler -/// must have been previously produced by the `stage - 1` build.config.build +/// must have been previously produced by the `stage - 1` build.build /// compiler. pub fn assemble_rustc(build: &Build, stage: u32, host: &str) { // nothing to do in stage0 @@ -365,7 +365,7 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) { let target_compiler = Compiler::new(stage, host); // The compiler that compiled the compiler we're assembling - let build_compiler = Compiler::new(stage - 1, &build.config.build); + let build_compiler = Compiler::new(stage - 1, &build.build); // Link in all dylibs to the libdir let sysroot = build.sysroot(&target_compiler); @@ -385,7 +385,7 @@ pub fn assemble_rustc(build: &Build, stage: u32, host: &str) { let rustc = out_dir.join(exe("rustc", host)); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); - let compiler = build.compiler_path(&Compiler::new(stage, host)); + let compiler = build.compiler_path(&target_compiler); let _ = fs::remove_file(&compiler); copy(&rustc, &compiler); @@ -407,6 +407,8 @@ fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) { t!(fs::create_dir_all(&sysroot_dst)); let mut contents = Vec::new(); t!(t!(File::open(stamp)).read_to_end(&mut contents)); + // This is the method we use for extracting paths from the stamp file passed to us. See + // run_cargo for more information (in this file). for part in contents.split(|b| *b == 0) { if part.is_empty() { continue @@ -421,7 +423,7 @@ fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) { /// This will build the specified tool with the specified `host` compiler in /// `stage` into the normal cargo output directory. pub fn maybe_clean_tools(build: &Build, stage: u32, target: &str, mode: Mode) { - let compiler = Compiler::new(stage, &build.config.build); + let compiler = Compiler::new(stage, &build.build); let stamp = match mode { Mode::Libstd => libstd_stamp(build, &compiler, target), @@ -441,7 +443,7 @@ pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) { let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool)); println!("Building stage{} tool {} ({})", stage, tool, target); - let compiler = Compiler::new(stage, &build.config.build); + let compiler = Compiler::new(stage, &build.build); let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build"); let dir = build.src.join("src/tools").join(tool); @@ -557,23 +559,24 @@ fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path) { // If this was an output file in the "host dir" we don't actually // worry about it, it's not relevant for us. if filename.starts_with(&host_root_dir) { - continue + continue; + } // If this was output in the `deps` dir then this is a precise file // name (hash included) so we start tracking it. - } else if filename.starts_with(&target_deps_dir) { + if filename.starts_with(&target_deps_dir) { deps.push(filename.to_path_buf()); + continue; + } // Otherwise this was a "top level artifact" which right now doesn't // have a hash in the name, but there's a version of this file in // the `deps` folder which *does* have a hash in the name. That's // the one we'll want to we'll probe for it later. - } else { - toplevel.push((filename.file_stem().unwrap() - .to_str().unwrap().to_string(), - filename.extension().unwrap().to_owned() - .to_str().unwrap().to_string())); - } + toplevel.push((filename.file_stem().unwrap() + .to_str().unwrap().to_string(), + filename.extension().unwrap().to_owned() + .to_str().unwrap().to_string())); } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 3ada846e38236..34628852ab377 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -81,8 +81,6 @@ pub struct Config { pub build: String, pub host: Vec<String>, pub target: Vec<String>, - pub rustc: Option<PathBuf>, - pub cargo: Option<PathBuf>, pub local_rebuild: bool, // dist misc @@ -114,11 +112,18 @@ pub struct Config { pub python: Option<PathBuf>, pub configure_args: Vec<String>, pub openssl_static: bool, + + + // These are either the stage0 downloaded binaries or the locally installed ones. + pub initial_cargo: PathBuf, + pub initial_rustc: PathBuf, + } /// Per-target configuration stored in the global configuration structure. #[derive(Default)] pub struct Target { + /// Some(path to llvm-config) if using an external LLVM. pub llvm_config: Option<PathBuf>, pub jemalloc: Option<PathBuf>, pub cc: Option<PathBuf>, @@ -307,8 +312,6 @@ impl Config { config.target.push(target.clone()); } } - config.rustc = build.rustc.map(PathBuf::from); - config.cargo = build.cargo.map(PathBuf::from); config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); config.python = build.python.map(PathBuf::from); @@ -410,13 +413,25 @@ impl Config { set(&mut config.rust_dist_src, t.src_tarball); } + let cwd = t!(env::current_dir()); + let out = cwd.join("build"); + + let stage0_root = out.join(&config.build).join("stage0/bin"); + config.initial_rustc = match build.rustc { + Some(s) => PathBuf::from(s), + None => stage0_root.join(exe("rustc", &config.build)), + }; + config.initial_cargo = match build.cargo { + Some(s) => PathBuf::from(s), + None => stage0_root.join(exe("cargo", &config.build)), + }; // compat with `./configure` while we're still using that if fs::metadata("config.mk").is_ok() { config.update_with_config_mk(); } - return config + config } /// "Temporary" routine to parse `config.mk` into this configuration. @@ -609,8 +624,8 @@ impl Config { } "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => { let path = parse_configure_path(value); - self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"])); - self.cargo = Some(push_exe_path(path, &["bin", "cargo"])); + self.initial_rustc = push_exe_path(path.clone(), &["bin", "rustc"]); + self.initial_cargo = push_exe_path(path, &["bin", "cargo"]); } "CFG_PYTHON" if value.len() > 0 => { let path = parse_configure_path(value); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 753bd1df0d83f..637bdbe998496 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -50,7 +50,7 @@ pub fn tmpdir(build: &Build) -> PathBuf { } fn rust_installer(build: &Build) -> Command { - build.tool_cmd(&Compiler::new(0, &build.config.build), "rust-installer") + build.tool_cmd(&Compiler::new(0, &build.build), "rust-installer") } /// Builds the `rust-docs` installer component. @@ -89,7 +89,7 @@ pub fn docs(build: &Build, stage: u32, host: &str) { // As part of this step, *also* copy the docs directory to a directory which // buildbot typically uploads. - if host == build.config.build { + if host == build.build { let dst = distdir(build).join("doc").join(build.rust_package_vers()); t!(fs::create_dir_all(&dst)); cp_r(&src, &dst); @@ -97,7 +97,7 @@ pub fn docs(build: &Build, stage: u32, host: &str) { } fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> { - let mut found = Vec::new(); + let mut found = Vec::with_capacity(files.len()); for file in files { let file_path = @@ -119,17 +119,9 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build: //Ask gcc where it keeps its stuff let mut cmd = Command::new(build.cc(target_triple)); cmd.arg("-print-search-dirs"); - build.run_quiet(&mut cmd); - let gcc_out = - String::from_utf8( - cmd - .output() - .expect("failed to execute gcc") - .stdout).expect("gcc.exe output was not utf8"); - - let mut bin_path: Vec<_> = - env::split_paths(&env::var_os("PATH").unwrap_or_default()) - .collect(); + let gcc_out = output(&mut cmd); + + let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect(); let mut lib_path = Vec::new(); for line in gcc_out.lines() { @@ -140,7 +132,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build: line[(idx + 1)..] .trim_left_matches(trim_chars) .split(';') - .map(|s| PathBuf::from(s)); + .map(PathBuf::from); if key == "programs" { bin_path.extend(value); @@ -149,7 +141,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build: } } - let target_tools = vec!["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "libwinpthread-1.dll"]; + let target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "libwinpthread-1.dll"]; let mut rustc_dlls = vec!["libstdc++-6.dll", "libwinpthread-1.dll"]; if target_triple.starts_with("i686-") { rustc_dlls.push("libgcc_s_dw2-1.dll"); @@ -157,7 +149,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build: rustc_dlls.push("libgcc_s_seh-1.dll"); } - let target_libs = vec![ //MinGW libs + let target_libs = [ //MinGW libs "libgcc.a", "libgcc_eh.a", "libgcc_s.a", @@ -203,7 +195,7 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build: let target_libs = find_files(&target_libs, &lib_path); fn copy_to_folder(src: &Path, dest_folder: &Path) { - let file_name = src.file_name().unwrap().to_os_string(); + let file_name = src.file_name().unwrap(); let dest = dest_folder.join(file_name); copy(src, &dest); } @@ -234,8 +226,6 @@ fn make_win_dist(rust_root: &Path, plat_root: &Path, target_triple: &str, build: /// /// This contains all the bits and pieces to run the MinGW Windows targets /// without any extra installed software (e.g. we bundle gcc, libraries, etc). -/// Currently just shells out to a python script, but that should be rewritten -/// in Rust. pub fn mingw(build: &Build, host: &str) { println!("Dist mingw ({})", host); let name = pkgname(build, "rust-mingw"); @@ -366,9 +356,9 @@ pub fn rustc(build: &Build, stage: u32, host: &str) { pub fn debugger_scripts(build: &Build, sysroot: &Path, host: &str) { + let dst = sysroot.join("lib/rustlib/etc"); + t!(fs::create_dir_all(&dst)); let cp_debugger_script = |file: &str| { - let dst = sysroot.join("lib/rustlib/etc"); - t!(fs::create_dir_all(&dst)); install(&build.src.join("src/etc/").join(file), &dst, 0o644); }; if host.contains("windows-msvc") { @@ -404,7 +394,7 @@ pub fn std(build: &Build, compiler: &Compiler, target: &str) { // The only true set of target libraries came from the build triple, so // let's reduce redundant work by only producing archives from that host. - if compiler.host != build.config.build { + if compiler.host != build.build { println!("\tskipping, not a build host"); return } @@ -450,7 +440,7 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { assert!(build.config.extended); println!("Dist analysis"); - if compiler.host != build.config.build { + if compiler.host != build.build { println!("\tskipping, not a build host"); return; } @@ -498,12 +488,11 @@ fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_di if spath.ends_with("~") || spath.ends_with(".pyc") { return false } - if spath.contains("llvm/test") || spath.contains("llvm\\test") { - if spath.ends_with(".ll") || - spath.ends_with(".td") || - spath.ends_with(".s") { - return false - } + if (spath.contains("llvm/test") || spath.contains("llvm\\test")) && + (spath.ends_with(".ll") || + spath.ends_with(".td") || + spath.ends_with(".s")) { + return false } let full_path = Path::new(dir).join(path); @@ -564,10 +553,10 @@ pub fn rust_src(build: &Build) { "src/libstd", "src/libstd_unicode", "src/libunwind", + "src/rustc/compiler_builtins_shim", "src/rustc/libc_shim", "src/libtest", "src/libterm", - "src/compiler-rt", "src/jemalloc", "src/libprofiler_builtins", ]; @@ -595,7 +584,7 @@ pub fn rust_src(build: &Build) { t!(fs::remove_dir_all(&image)); } -const CARGO_VENDOR_VERSION: &'static str = "0.1.4"; +const CARGO_VENDOR_VERSION: &str = "0.1.4"; /// Creates the plain source tarball pub fn plain_source_tarball(build: &Build) { @@ -634,26 +623,26 @@ pub fn plain_source_tarball(build: &Build) { write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes()); // If we're building from git sources, we need to vendor a complete distribution. - if build.src_is_git { + if build.rust_info.is_git() { // Get cargo-vendor installed, if it isn't already. let mut has_cargo_vendor = false; - let mut cmd = Command::new(&build.cargo); + let mut cmd = Command::new(&build.initial_cargo); for line in output(cmd.arg("install").arg("--list")).lines() { has_cargo_vendor |= line.starts_with("cargo-vendor "); } if !has_cargo_vendor { - let mut cmd = Command::new(&build.cargo); + let mut cmd = Command::new(&build.initial_cargo); cmd.arg("install") .arg("--force") .arg("--debug") .arg("--vers").arg(CARGO_VENDOR_VERSION) .arg("cargo-vendor") - .env("RUSTC", &build.rustc); + .env("RUSTC", &build.initial_rustc); build.run(&mut cmd); } // Vendor all Cargo dependencies - let mut cmd = Command::new(&build.cargo); + let mut cmd = Command::new(&build.initial_cargo); cmd.arg("vendor") .current_dir(&plain_dst_src.join("src")); build.run(&mut cmd); @@ -716,7 +705,7 @@ fn write_file(path: &Path, data: &[u8]) { pub fn cargo(build: &Build, stage: u32, target: &str) { println!("Dist cargo stage{} ({})", stage, target); - let compiler = Compiler::new(stage, &build.config.build); + let compiler = Compiler::new(stage, &build.build); let src = build.src.join("src/tools/cargo"); let etc = src.join("src/etc"); @@ -777,7 +766,7 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { pub fn rls(build: &Build, stage: u32, target: &str) { assert!(build.config.extended); println!("Dist RLS stage{} ({})", stage, target); - let compiler = Compiler::new(stage, &build.config.build); + let compiler = Compiler::new(stage, &build.build); let src = build.src.join("src/tools/rls"); let release_num = build.release_num("rls"); @@ -1209,7 +1198,7 @@ fn add_env(build: &Build, cmd: &mut Command, target: &str) { } pub fn hash_and_sign(build: &Build) { - let compiler = Compiler::new(0, &build.config.build); + let compiler = Compiler::new(0, &build.build); let mut cmd = build.tool_cmd(&compiler, "build-manifest"); let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| { panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n") diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 30f631ca2df64..7dbc3e5553957 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -45,7 +45,7 @@ pub fn rustbook_src(build: &Build, target: &str, name: &str, src: &Path) { t!(fs::create_dir_all(&out)); let out = out.join(name); - let compiler = Compiler::new(0, &build.config.build); + let compiler = Compiler::new(0, &build.build); let src = src.join(name); let index = out.join("index.html"); let rustbook = build.tool(&compiler, "rustbook"); @@ -95,7 +95,7 @@ pub fn book(build: &Build, target: &str, name: &str) { fn invoke_rustdoc(build: &Build, target: &str, markdown: &str) { let out = build.doc_out(target); - let compiler = Compiler::new(0, &build.config.build); + let compiler = Compiler::new(0, &build.build); let path = build.src.join("src/doc").join(markdown); @@ -150,7 +150,7 @@ pub fn standalone(build: &Build, target: &str) { let out = build.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = Compiler::new(0, &build.config.build); + let compiler = Compiler::new(0, &build.build); let favicon = build.src.join("src/doc/favicon.inc"); let footer = build.src.join("src/doc/footer.inc"); @@ -217,7 +217,7 @@ pub fn std(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} std ({})", stage, target); let out = build.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = Compiler::new(stage, &build.config.build); + let compiler = Compiler::new(stage, &build.build); let compiler = if build.force_use_stage1(&compiler, target) { Compiler::new(1, compiler.host) } else { @@ -276,7 +276,7 @@ pub fn test(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} test ({})", stage, target); let out = build.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = Compiler::new(stage, &build.config.build); + let compiler = Compiler::new(stage, &build.build); let compiler = if build.force_use_stage1(&compiler, target) { Compiler::new(1, compiler.host) } else { @@ -306,7 +306,7 @@ pub fn rustc(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} compiler ({})", stage, target); let out = build.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = Compiler::new(stage, &build.config.build); + let compiler = Compiler::new(stage, &build.build); let compiler = if build.force_use_stage1(&compiler, target) { Compiler::new(1, compiler.host) } else { @@ -351,13 +351,13 @@ pub fn error_index(build: &Build, target: &str) { println!("Documenting error index ({})", target); let out = build.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = Compiler::new(0, &build.config.build); + let compiler = Compiler::new(0, &build.build); let mut index = build.tool_cmd(&compiler, "error_index_generator"); index.arg("html"); index.arg(out.join("error-index.html")); // FIXME: shouldn't have to pass this env var - index.env("CFG_BUILD", &build.config.build); + index.env("CFG_BUILD", &build.build); build.run(&mut index); } @@ -367,7 +367,7 @@ pub fn unstable_book_gen(build: &Build, target: &str) { let out = build.md_doc_out(target).join("unstable-book"); t!(fs::create_dir_all(&out)); t!(fs::remove_dir_all(&out)); - let compiler = Compiler::new(0, &build.config.build); + let compiler = Compiler::new(0, &build.build); let mut cmd = build.tool_cmd(&compiler, "unstable-book-gen"); cmd.arg(build.src.join("src")); cmd.arg(out); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index dc9dac7362788..5804df34e8b38 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -35,22 +35,12 @@ pub struct Flags { pub host: Vec<String>, pub target: Vec<String>, pub config: Option<PathBuf>, - pub src: Option<PathBuf>, + pub src: PathBuf, pub jobs: Option<u32>, pub cmd: Subcommand, pub incremental: bool, } -impl Flags { - pub fn verbose(&self) -> bool { - self.verbose > 0 - } - - pub fn very_verbose(&self) -> bool { - self.verbose > 1 - } -} - pub enum Subcommand { Build { paths: Vec<PathBuf>, @@ -61,7 +51,7 @@ pub enum Subcommand { Test { paths: Vec<PathBuf>, test_args: Vec<String>, - no_fail_fast: bool, + fail_fast: bool, }, Bench { paths: Vec<PathBuf>, @@ -122,16 +112,15 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`"); // the subcommand. Therefore we must manually identify the subcommand first, so that we can // complete the definition of the options. Then we can use the getopt::Matches object from // there on out. - let mut possible_subcommands = args.iter().collect::<Vec<_>>(); - possible_subcommands.retain(|&s| - (s == "build") - || (s == "test") - || (s == "bench") - || (s == "doc") - || (s == "clean") - || (s == "dist") - || (s == "install")); - let subcommand = match possible_subcommands.first() { + let subcommand = args.iter().find(|&s| + (s == "build") + || (s == "test") + || (s == "bench") + || (s == "doc") + || (s == "clean") + || (s == "dist") + || (s == "install")); + let subcommand = match subcommand { Some(s) => s, None => { // No subcommand -- show the general usage and subcommand help @@ -164,7 +153,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`"); let mut pass_sanity_check = true; match matches.free.get(0) { Some(check_subcommand) => { - if &check_subcommand != subcommand { + if check_subcommand != subcommand { pass_sanity_check = false; } }, @@ -279,7 +268,7 @@ Arguments: Subcommand::Test { paths: paths, test_args: matches.opt_strs("test-args"), - no_fail_fast: matches.opt_present("no-fail-fast"), + fail_fast: !matches.opt_present("no-fail-fast"), } } "bench" => { @@ -316,12 +305,15 @@ Arguments: let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap()); - if matches.opt_present("incremental") { - if stage.is_none() { - stage = Some(1); - } + if matches.opt_present("incremental") && stage.is_none() { + stage = Some(1); } + let cwd = t!(env::current_dir()); + let src = matches.opt_str("src").map(PathBuf::from) + .or_else(|| env::var_os("SRC").map(PathBuf::from)) + .unwrap_or(cwd); + Flags { verbose: matches.opt_count("verbose"), stage: stage, @@ -333,7 +325,7 @@ Arguments: host: split(matches.opt_strs("host")), target: split(matches.opt_strs("target")), config: cfg_file, - src: matches.opt_str("src").map(PathBuf::from), + src: src, jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd: cmd, incremental: matches.opt_present("incremental"), @@ -352,9 +344,9 @@ impl Subcommand { } } - pub fn no_fail_fast(&self) -> bool { + pub fn fail_fast(&self) -> bool { match *self { - Subcommand::Test { no_fail_fast, .. } => no_fail_fast, + Subcommand::Test { fail_fast, .. } => fail_fast, _ => false, } } diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 21e21628dc947..8e2ef527b1658 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -146,5 +146,5 @@ fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf { _ => {} } } - return ret + ret } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 86180077b82f8..5a3785b1ed634 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -161,25 +161,35 @@ pub struct Build { flags: Flags, // Derived properties from the above two configurations - cargo: PathBuf, - rustc: PathBuf, src: PathBuf, out: PathBuf, rust_info: channel::GitInfo, cargo_info: channel::GitInfo, rls_info: channel::GitInfo, local_rebuild: bool, + fail_fast: bool, + verbosity: usize, + + // Targets for which to build. + build: String, + hosts: Vec<String>, + targets: Vec<String>, + + // Stage 0 (downloaded) compiler and cargo or their local rust equivalents. + initial_rustc: PathBuf, + initial_cargo: PathBuf, // Probed tools at runtime lldb_version: Option<String>, lldb_python_dir: Option<String>, // Runtime state filled in later on + // target -> (cc, ar) cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>, + // host -> (cc, ar) cxx: HashMap<String, gcc::Tool>, crates: HashMap<String, Crate>, is_sudo: bool, - src_is_git: bool, ci_env: CiEnv, delayed_failures: Cell<usize>, } @@ -202,20 +212,16 @@ struct Crate { /// build system, with each mod generating output in a different directory. #[derive(Clone, Copy, PartialEq, Eq)] pub enum Mode { - /// This cargo is going to build the standard library, placing output in the - /// "stageN-std" directory. + /// Build the standard library, placing output in the "stageN-std" directory. Libstd, - /// This cargo is going to build libtest, placing output in the - /// "stageN-test" directory. + /// Build libtest, placing output in the "stageN-test" directory. Libtest, - /// This cargo is going to build librustc and compiler libraries, placing - /// output in the "stageN-rustc" directory. + /// Build librustc and compiler libraries, placing output in the "stageN-rustc" directory. Librustc, - /// This cargo is going to build some tool, placing output in the - /// "stageN-tools" directory. + /// Build some tool, placing output in the "stageN-tools" directory. Tool, } @@ -226,22 +232,9 @@ impl Build { /// By default all build output will be placed in the current directory. pub fn new(flags: Flags, config: Config) -> Build { let cwd = t!(env::current_dir()); - let src = flags.src.clone().or_else(|| { - env::var_os("SRC").map(|x| x.into()) - }).unwrap_or(cwd.clone()); + let src = flags.src.clone(); let out = cwd.join("build"); - let stage0_root = out.join(&config.build).join("stage0/bin"); - let rustc = match config.rustc { - Some(ref s) => PathBuf::from(s), - None => stage0_root.join(exe("rustc", &config.build)), - }; - let cargo = match config.cargo { - Some(ref s) => PathBuf::from(s), - None => stage0_root.join(exe("cargo", &config.build)), - }; - let local_rebuild = config.local_rebuild; - let is_sudo = match env::var_os("SUDO_USER") { Some(sudo_user) => { match env::var_os("USER") { @@ -254,32 +247,64 @@ impl Build { let rust_info = channel::GitInfo::new(&src); let cargo_info = channel::GitInfo::new(&src.join("src/tools/cargo")); let rls_info = channel::GitInfo::new(&src.join("src/tools/rls")); - let src_is_git = src.join(".git").exists(); + + let hosts = if !flags.host.is_empty() { + for host in flags.host.iter() { + if !config.host.contains(host) { + panic!("specified host `{}` is not in configuration", host); + } + } + flags.host.clone() + } else { + config.host.clone() + }; + let targets = if !flags.target.is_empty() { + for target in flags.target.iter() { + if !config.target.contains(target) { + panic!("specified target `{}` is not in configuration", target); + } + } + flags.target.clone() + } else { + config.target.clone() + }; Build { + initial_rustc: config.initial_rustc.clone(), + initial_cargo: config.initial_cargo.clone(), + local_rebuild: config.local_rebuild, + fail_fast: flags.cmd.fail_fast(), + verbosity: cmp::max(flags.verbose, config.verbose), + + build: config.host[0].clone(), + hosts: hosts, + targets: targets, + flags: flags, config: config, - cargo: cargo, - rustc: rustc, src: src, out: out, rust_info: rust_info, cargo_info: cargo_info, rls_info: rls_info, - local_rebuild: local_rebuild, cc: HashMap::new(), cxx: HashMap::new(), crates: HashMap::new(), lldb_version: None, lldb_python_dir: None, is_sudo: is_sudo, - src_is_git: src_is_git, ci_env: CiEnv::current(), delayed_failures: Cell::new(0), } } + fn build_slice(&self) -> &[String] { + unsafe { + std::slice::from_raw_parts(&self.build, 1) + } + } + /// Executes the entire build, as configured by the flags and configuration. pub fn build(&mut self) { unsafe { @@ -296,7 +321,7 @@ impl Build { sanity::check(self); // If local-rust is the same major.minor as the current version, then force a local-rebuild let local_version_verbose = output( - Command::new(&self.rustc).arg("--version").arg("--verbose")); + Command::new(&self.initial_rustc).arg("--version").arg("--verbose")); let local_release = local_version_verbose .lines().filter(|x| x.starts_with("release:")) .next().unwrap().trim_left_matches("release:").trim(); @@ -338,7 +363,7 @@ impl Build { mode: Mode, target: &str, cmd: &str) -> Command { - let mut cargo = Command::new(&self.cargo); + let mut cargo = Command::new(&self.initial_cargo); let out_dir = self.stage_out(compiler, mode); cargo.env("CARGO_TARGET_DIR", out_dir) .arg(cmd) @@ -422,7 +447,7 @@ impl Build { // library up and running, so we can use the normal compiler to compile // build scripts in that situation. if mode == Mode::Libstd { - cargo.env("RUSTC_SNAPSHOT", &self.rustc) + cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc) .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); } else { cargo.env("RUSTC_SNAPSHOT", self.compiler_path(compiler)) @@ -441,8 +466,7 @@ impl Build { cargo.env("RUSTC_ON_FAIL", on_fail); } - let verbose = cmp::max(self.config.verbose, self.flags.verbose); - cargo.env("RUSTC_VERBOSE", format!("{}", verbose)); + cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); // Specify some various options for build scripts used throughout // the build. @@ -458,7 +482,9 @@ impl Build { } } - if self.config.extended && compiler.is_final_stage(self) { + if mode == Mode::Libstd && + self.config.extended && + compiler.is_final_stage(self) { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } @@ -480,7 +506,7 @@ impl Build { // FIXME: should update code to not require this env var cargo.env("CFG_COMPILER_HOST_TRIPLE", target); - if self.config.verbose() || self.flags.verbose() { + if self.is_verbose() { cargo.arg("-v"); } // FIXME: cargo bench does not accept `--release` @@ -496,13 +522,13 @@ impl Build { self.ci_env.force_coloring_in_ci(&mut cargo); - return cargo + cargo } /// Get a path to the compiler specified. fn compiler_path(&self, compiler: &Compiler) -> PathBuf { if compiler.is_snapshot(self) { - self.rustc.clone() + self.initial_rustc.clone() } else { self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host)) } @@ -519,7 +545,7 @@ impl Build { let mut rustdoc = self.compiler_path(compiler); rustdoc.pop(); rustdoc.push(exe("rustdoc", compiler.host)); - return rustdoc + rustdoc } /// Get a `Command` which is ready to run `tool` in `stage` built for @@ -527,7 +553,7 @@ impl Build { fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command { let mut cmd = Command::new(self.tool(&compiler, tool)); self.prepare_tool_cmd(compiler, &mut cmd); - return cmd + cmd } /// Prepares the `cmd` provided to be able to run the `compiler` provided. @@ -578,7 +604,7 @@ impl Build { if self.config.profiler { features.push_str(" profiler"); } - return features + features } /// Get the space-separated set of activated features for the compiler. @@ -587,7 +613,7 @@ impl Build { if self.config.use_jemalloc { features.push_str(" jemalloc"); } - return features + features } /// Component directory that Cargo will produce output into (e.g. @@ -760,7 +786,7 @@ impl Build { /// Returns the libdir of the snapshot compiler. fn rustc_snapshot_libdir(&self) -> PathBuf { - self.rustc.parent().unwrap().parent().unwrap() + self.initial_rustc.parent().unwrap().parent().unwrap() .join(libdir(&self.config.build)) } @@ -792,9 +818,17 @@ impl Build { try_run_suppressed(cmd) } + pub fn is_verbose(&self) -> bool { + self.verbosity > 0 + } + + pub fn is_very_verbose(&self) -> bool { + self.verbosity > 1 + } + /// Prints a message if this build is configured in verbose mode. fn verbose(&self, msg: &str) { - if self.flags.verbose() || self.config.verbose() { + if self.is_verbose() { println!("{}", msg); } } @@ -802,7 +836,7 @@ impl Build { /// Returns the number of parallel jobs that have been configured for this /// build. fn jobs(&self) -> u32 { - self.flags.jobs.unwrap_or(num_cpus::get() as u32) + self.flags.jobs.unwrap_or_else(|| num_cpus::get() as u32) } /// Returns the path to the C compiler for the target specified. @@ -834,7 +868,7 @@ impl Build { if target == "i686-pc-windows-gnu" { base.push("-fno-omit-frame-pointer".into()); } - return base + base } /// Returns the path to the `ar` archive utility for the target specified. @@ -866,7 +900,7 @@ impl Build { !target.contains("emscripten") { base.push(format!("-Clinker={}", self.cc(target).display())); } - return base + base } /// Returns the "musl root" for this `target`, if defined @@ -1047,7 +1081,7 @@ impl<'a> Compiler<'a> { /// Returns whether this is a snapshot compiler for `build`'s configuration fn is_snapshot(&self, build: &Build) -> bool { - self.stage == 0 && self.host == build.config.build + self.stage == 0 && self.host == build.build } /// Returns if this compiler should be treated as a final stage one in the diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 7b6b01655df58..9326bb7129afa 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -56,7 +56,7 @@ fn build_krate(build: &mut Build, krate: &str) { // of packages we're going to have to know what `-p` arguments to pass it // to know what crates to test. Here we run `cargo metadata` to learn about // the dependency graph and what `-p` arguments there are. - let mut cargo = Command::new(&build.cargo); + let mut cargo = Command::new(&build.initial_cargo); cargo.arg("metadata") .arg("--format-version").arg("1") .arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml")); diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index f150df6cdcdb0..20eec97d8e5aa 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -94,7 +94,7 @@ pub fn llvm(build: &Build, target: &str) { let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"}; cfg.target(target) - .host(&build.config.build) + .host(&build.build) .out_dir(&out_dir) .profile(profile) .define("LLVM_ENABLE_ASSERTIONS", assertions) @@ -129,11 +129,11 @@ pub fn llvm(build: &Build, target: &str) { } // http://llvm.org/docs/HowToCrossCompileLLVM.html - if target != build.config.build { + if target != build.build { // FIXME: if the llvm root for the build triple is overridden then we // should use llvm-tblgen from there, also should verify that it // actually exists most of the time in normal installs of LLVM. - let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen"); + let host = build.llvm_out(&build.build).join("bin/llvm-tblgen"); cfg.define("CMAKE_CROSSCOMPILING", "True") .define("LLVM_TABLEGEN", &host); } @@ -243,7 +243,7 @@ pub fn test_helpers(build: &Build, target: &str) { cfg.cargo_metadata(false) .out_dir(&dst) .target(target) - .host(&build.config.build) + .host(&build.build) .opt_level(0) .debug(false) .file(build.src.join("src/rt/rust_test_helpers.c")) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 46d047bb015e5..a9c1b023dd4f5 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -18,9 +18,9 @@ //! In theory if we get past this phase it's a bug if a build fails, but in //! practice that's likely not true! -use std::collections::HashSet; +use std::collections::HashMap; use std::env; -use std::ffi::{OsStr, OsString}; +use std::ffi::{OsString, OsStr}; use std::fs; use std::process::Command; use std::path::PathBuf; @@ -29,45 +29,59 @@ use build_helper::output; use Build; +struct Finder { + cache: HashMap<OsString, Option<PathBuf>>, + path: OsString, +} + +impl Finder { + fn new() -> Self { + Self { + cache: HashMap::new(), + path: env::var_os("PATH").unwrap_or_default() + } + } + + fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> { + let cmd: OsString = cmd.as_ref().into(); + let path = self.path.clone(); + self.cache.entry(cmd.clone()).or_insert_with(|| { + for path in env::split_paths(&path) { + let target = path.join(&cmd); + let mut cmd_alt = cmd.clone(); + cmd_alt.push(".exe"); + if target.is_file() || // some/path/git + target.with_extension("exe").exists() || // some/path/git.exe + target.join(&cmd_alt).exists() { // some/path/git/git.exe + return Some(target); + } + } + None + }).clone() + } + + fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf { + self.maybe_have(&cmd).unwrap_or_else(|| { + panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref()); + }) + } +} + pub fn check(build: &mut Build) { - let mut checked = HashSet::new(); - let path = env::var_os("PATH").unwrap_or(OsString::new()); + let path = env::var_os("PATH").unwrap_or_default(); // On Windows, quotes are invalid characters for filename paths, and if // one is present as part of the PATH then that can lead to the system // being unable to identify the files properly. See // https://github.com/rust-lang/rust/issues/34959 for more details. - if cfg!(windows) { - if path.to_string_lossy().contains("\"") { - panic!("PATH contains invalid character '\"'"); - } + if cfg!(windows) && path.to_string_lossy().contains("\"") { + panic!("PATH contains invalid character '\"'"); } - let have_cmd = |cmd: &OsStr| { - for path in env::split_paths(&path) { - let target = path.join(cmd); - let mut cmd_alt = cmd.to_os_string(); - cmd_alt.push(".exe"); - if target.is_file() || - target.with_extension("exe").exists() || - target.join(cmd_alt).exists() { - return Some(target); - } - } - return None; - }; - - let mut need_cmd = |cmd: &OsStr| { - if !checked.insert(cmd.to_owned()) { - return - } - if have_cmd(cmd).is_none() { - panic!("\n\ncouldn't find required command: {:?}\n\n", cmd); - } - }; + let mut cmd_finder = Finder::new(); // If we've got a git directory we're gona need git to update // submodules and learn about various other aspects. - if build.src_is_git { - need_cmd("git".as_ref()); + if build.rust_info.is_git() { + cmd_finder.must_have("git"); } // We need cmake, but only if we're actually building LLVM or sanitizers. @@ -75,57 +89,32 @@ pub fn check(build: &mut Build) { .filter_map(|host| build.config.target_config.get(host)) .any(|config| config.llvm_config.is_none()); if building_llvm || build.config.sanitizers { - need_cmd("cmake".as_ref()); + cmd_finder.must_have("cmake"); } // Ninja is currently only used for LLVM itself. - if building_llvm && build.config.ninja { - // Some Linux distros rename `ninja` to `ninja-build`. - // CMake can work with either binary name. - if have_cmd("ninja-build".as_ref()).is_none() { - need_cmd("ninja".as_ref()); - } + // Some Linux distros rename `ninja` to `ninja-build`. + // CMake can work with either binary name. + if building_llvm && build.config.ninja && cmd_finder.maybe_have("ninja-build").is_none() { + cmd_finder.must_have("ninja"); } - if build.config.python.is_none() { - // set by bootstrap.py - if let Some(v) = env::var_os("BOOTSTRAP_PYTHON") { - build.config.python = Some(PathBuf::from(v)); - } - } - if build.config.python.is_none() { - build.config.python = have_cmd("python2.7".as_ref()); - } - if build.config.python.is_none() { - build.config.python = have_cmd("python2".as_ref()); - } - if build.config.python.is_none() { - need_cmd("python".as_ref()); - build.config.python = Some("python".into()); - } - need_cmd(build.config.python.as_ref().unwrap().as_ref()); + build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p)) + .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py + .or_else(|| cmd_finder.maybe_have("python2.7")) + .or_else(|| cmd_finder.maybe_have("python2")) + .or_else(|| Some(cmd_finder.must_have("python"))); + build.config.nodejs = build.config.nodejs.take().map(|p| cmd_finder.must_have(p)) + .or_else(|| cmd_finder.maybe_have("node")) + .or_else(|| cmd_finder.maybe_have("nodejs")); - if let Some(ref s) = build.config.nodejs { - need_cmd(s.as_ref()); - } else { - // Look for the nodejs command, needed for emscripten testing - if let Some(node) = have_cmd("node".as_ref()) { - build.config.nodejs = Some(node); - } else if let Some(node) = have_cmd("nodejs".as_ref()) { - build.config.nodejs = Some(node); - } - } - - if let Some(ref gdb) = build.config.gdb { - need_cmd(gdb.as_ref()); - } else { - build.config.gdb = have_cmd("gdb".as_ref()); - } + build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p)) + .or_else(|| cmd_finder.maybe_have("gdb")); // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. - for target in build.config.target.iter() { + for target in &build.config.target { // On emscripten we don't actually need the C compiler to just // build the target artifacts, only for testing. For the sake // of easier bot configuration, just skip detection. @@ -133,33 +122,32 @@ pub fn check(build: &mut Build) { continue; } - need_cmd(build.cc(target).as_ref()); + cmd_finder.must_have(build.cc(target)); if let Some(ar) = build.ar(target) { - need_cmd(ar.as_ref()); + cmd_finder.must_have(ar); } } - for host in build.config.host.iter() { - need_cmd(build.cxx(host).unwrap().as_ref()); - } - // The msvc hosts don't use jemalloc, turn it off globally to - // avoid packaging the dummy liballoc_jemalloc on that platform. for host in build.config.host.iter() { + cmd_finder.must_have(build.cxx(host).unwrap()); + + // The msvc hosts don't use jemalloc, turn it off globally to + // avoid packaging the dummy liballoc_jemalloc on that platform. if host.contains("msvc") { build.config.use_jemalloc = false; } } // Externally configured LLVM requires FileCheck to exist - let filecheck = build.llvm_filecheck(&build.config.build); + let filecheck = build.llvm_filecheck(&build.build); if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests { panic!("FileCheck executable {:?} does not exist", filecheck); } - for target in build.config.target.iter() { + for target in &build.config.target { // Can't compile for iOS unless we're on macOS if target.contains("apple-ios") && - !build.config.build.contains("apple-darwin") { + !build.build.contains("apple-darwin") { panic!("the iOS target is only supported on macOS"); } @@ -206,18 +194,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake } } - for host in build.flags.host.iter() { - if !build.config.host.contains(host) { - panic!("specified host `{}` is not in the ./configure list", host); - } - } - for target in build.flags.target.iter() { - if !build.config.target.contains(target) { - panic!("specified target `{}` is not in the ./configure list", - target); - } - } - let run = |cmd: &mut Command| { cmd.output().map(|output| { String::from_utf8_lossy(&output.stdout) @@ -231,6 +207,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake } if let Some(ref s) = build.config.ccache { - need_cmd(s.as_ref()); + cmd_finder.must_have(s); } } diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 5f0724c657757..c221d7076832f 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -104,10 +104,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.build("llvm", "src/llvm") .host(true) .dep(move |s| { - if s.target == build.config.build { + if s.target == build.build { Step::noop() } else { - s.target(&build.config.build) + s.target(&build.build) } }) .run(move |s| native::llvm(build, s.target)); @@ -124,7 +124,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { Step::noop() } else { s.name("librustc") - .host(&build.config.build) + .host(&build.build) .stage(s.stage - 1) } }) @@ -148,7 +148,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { } } } - return ret + ret }; // ======================================================================== @@ -215,29 +215,29 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { let mut rule = rules.build(&krate, "path/to/nowhere"); rule.dep(move |s| { if build.force_use_stage1(&s.compiler(), s.target) { - s.host(&build.config.build).stage(1) - } else if s.host == build.config.build { + s.host(&build.build).stage(1) + } else if s.host == build.build { s.name(dep) } else { - s.host(&build.config.build) + s.host(&build.build) } }) .run(move |s| { if build.force_use_stage1(&s.compiler(), s.target) { link(build, - &s.stage(1).host(&build.config.build).compiler(), + &s.stage(1).host(&build.build).compiler(), &s.compiler(), s.target) - } else if s.host == build.config.build { + } else if s.host == build.build { link(build, &s.compiler(), &s.compiler(), s.target) } else { link(build, - &s.host(&build.config.build).compiler(), + &s.host(&build.build).compiler(), &s.compiler(), s.target) } }); - return rule + rule } // Similar to the `libstd`, `libtest`, and `librustc` rules above, except @@ -269,7 +269,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { for (krate, path, _default) in krates("std") { rules.build(&krate.build_step, path) .dep(|s| s.name("startup-objects")) - .dep(move |s| s.name("rustc").host(&build.config.build).target(s.host)) + .dep(move |s| s.name("rustc").host(&build.build).target(s.host)) .run(move |s| compile::std(build, s.target, &s.compiler())); } for (krate, path, _default) in krates("test") { @@ -280,7 +280,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { for (krate, path, _default) in krates("rustc-main") { rules.build(&krate.build_step, path) .dep(|s| s.name("libtest-link")) - .dep(move |s| s.name("llvm").host(&build.config.build).stage(0)) + .dep(move |s| s.name("llvm").host(&build.build).stage(0)) .dep(|s| s.name("may-run-build-script")) .run(move |s| compile::rustc(build, s.target, &s.compiler())); } @@ -291,8 +291,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.build("may-run-build-script", "path/to/nowhere") .dep(move |s| { s.name("libstd-link") - .host(&build.config.build) - .target(&build.config.build) + .host(&build.build) + .target(&build.build) }); rules.build("startup-objects", "src/rtstartup") .dep(|s| s.name("create-sysroot").target(s.host)) @@ -332,7 +332,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { "incremental"); } - if build.config.build.contains("msvc") { + if build.build.contains("msvc") { // nothing to do for debuginfo tests } else { rules.test("check-debuginfo-lldb", "src/test/debuginfo-lldb") @@ -352,7 +352,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { "debuginfo-gdb", "debuginfo")); let mut rule = rules.test("check-debuginfo", "src/test/debuginfo"); rule.default(true); - if build.config.build.contains("apple") { + if build.build.contains("apple") { rule.dep(|s| s.name("check-debuginfo-lldb")); } else { rule.dep(|s| s.name("check-debuginfo-gdb")); @@ -594,8 +594,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { // Cargo depends on procedural macros, which requires a full host // compiler to be available, so we need to depend on that. s.name("librustc-link") - .target(&build.config.build) - .host(&build.config.build) + .target(&build.build) + .host(&build.build) }) .run(move |s| compile::tool(build, s.stage, s.target, "cargo")); rules.build("tool-rls", "src/tools/rls") @@ -606,8 +606,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(move |s| { // rls, like cargo, uses procedural macros s.name("librustc-link") - .target(&build.config.build) - .host(&build.config.build) + .target(&build.build) + .host(&build.build) }) .run(move |s| compile::tool(build, s.stage, s.target, "rls")); @@ -635,8 +635,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.doc("doc-book", "src/doc/book") .dep(move |s| { s.name("tool-rustbook") - .host(&build.config.build) - .target(&build.config.build) + .host(&build.build) + .target(&build.build) .stage(0) }) .default(build.config.docs) @@ -644,8 +644,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.doc("doc-nomicon", "src/doc/nomicon") .dep(move |s| { s.name("tool-rustbook") - .host(&build.config.build) - .target(&build.config.build) + .host(&build.build) + .target(&build.build) .stage(0) }) .default(build.config.docs) @@ -653,8 +653,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.doc("doc-reference", "src/doc/reference") .dep(move |s| { s.name("tool-rustbook") - .host(&build.config.build) - .target(&build.config.build) + .host(&build.build) + .target(&build.build) .stage(0) }) .default(build.config.docs) @@ -662,8 +662,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.doc("doc-unstable-book", "src/doc/unstable-book") .dep(move |s| { s.name("tool-rustbook") - .host(&build.config.build) - .target(&build.config.build) + .host(&build.build) + .target(&build.build) .stage(0) }) .dep(move |s| s.name("doc-unstable-book-gen")) @@ -675,14 +675,14 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.doc("doc-standalone", "src/doc") .dep(move |s| { s.name("rustc") - .host(&build.config.build) - .target(&build.config.build) + .host(&build.build) + .target(&build.build) .stage(0) }) .default(build.config.docs) .run(move |s| doc::standalone(build, s.target)); rules.doc("doc-error-index", "src/tools/error_index_generator") - .dep(move |s| s.name("tool-error-index").target(&build.config.build).stage(0)) + .dep(move |s| s.name("tool-error-index").target(&build.build).stage(0)) .dep(move |s| s.name("librustc-link")) .default(build.config.docs) .host(true) @@ -690,8 +690,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.doc("doc-unstable-book-gen", "src/tools/unstable-book-gen") .dep(move |s| { s.name("tool-unstable-book-gen") - .host(&build.config.build) - .target(&build.config.build) + .host(&build.build) + .target(&build.build) .stage(0) }) .dep(move |s| s.name("libstd-link")) @@ -725,7 +725,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { // ======================================================================== // Distribution targets rules.dist("dist-rustc", "src/librustc") - .dep(move |s| s.name("rustc").host(&build.config.build)) + .dep(move |s| s.name("rustc").host(&build.build)) .host(true) .only_host_build(true) .default(true) @@ -811,7 +811,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .host(true) .only_build(true) .only_host_build(true) - .dep(move |s| s.name("tool-build-manifest").target(&build.config.build).stage(0)) + .dep(move |s| s.name("tool-build-manifest").target(&build.build).stage(0)) .run(move |_| dist::hash_and_sign(build)); rules.install("install-docs", "src/doc") @@ -861,8 +861,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { /// Helper to depend on a stage0 build-only rust-installer tool. fn tool_rust_installer<'a>(build: &'a Build, step: &Step<'a>) -> Step<'a> { step.name("tool-rust-installer") - .host(&build.config.build) - .target(&build.config.build) + .host(&build.build) + .target(&build.build) .stage(0) } } @@ -1058,8 +1058,8 @@ impl<'a> Rules<'a> { build: build, sbuild: Step { stage: build.flags.stage.unwrap_or(2), - target: &build.config.build, - host: &build.config.build, + target: &build.build, + host: &build.build, name: "", }, rules: BTreeMap::new(), @@ -1218,16 +1218,9 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? rules.into_iter().flat_map(|(rule, _)| { let hosts = if rule.only_host_build || rule.only_build { - &self.build.config.host[..1] - } else if self.build.flags.host.len() > 0 { - &self.build.flags.host + self.build.build_slice() } else { - &self.build.config.host - }; - let targets = if self.build.flags.target.len() > 0 { - &self.build.flags.target - } else { - &self.build.config.target + &self.build.hosts }; // Determine the actual targets participating in this rule. // NOTE: We should keep the full projection from build triple to @@ -1236,19 +1229,18 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? // the original non-shadowed hosts array is used below. let arr = if rule.host { // If --target was specified but --host wasn't specified, - // don't run any host-only tests. Also, respect any `--host` - // overrides as done for `hosts`. + // don't run any host-only tests. if self.build.flags.host.len() > 0 { - &self.build.flags.host[..] + &self.build.hosts } else if self.build.flags.target.len() > 0 { &[] } else if rule.only_build { - &self.build.config.host[..1] + self.build.build_slice() } else { - &self.build.config.host[..] + &self.build.hosts } } else { - targets + &self.build.targets }; hosts.iter().flat_map(move |host| { @@ -1326,7 +1318,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? for idx in 0..nodes.len() { self.topo_sort(idx, &idx_to_node, &edges, &mut visited, &mut order); } - return order + order } /// Builds the dependency graph rooted at `step`. @@ -1365,7 +1357,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? } edges.entry(idx).or_insert(HashSet::new()).extend(deps); - return idx + idx } /// Given a dependency graph with a finished list of `nodes`, fill out more @@ -1494,8 +1486,8 @@ mod tests { let step = super::Step { name: "", stage: 2, - host: &build.config.build, - target: &build.config.build, + host: &build.build, + target: &build.build, }; assert!(plan.contains(&step.name("dist-docs"))); @@ -1517,8 +1509,8 @@ mod tests { let step = super::Step { name: "", stage: 2, - host: &build.config.build, - target: &build.config.build, + host: &build.build, + target: &build.build, }; assert!(plan.contains(&step.name("dist-docs"))); @@ -1545,8 +1537,8 @@ mod tests { let step = super::Step { name: "", stage: 2, - host: &build.config.build, - target: &build.config.build, + host: &build.build, + target: &build.build, }; assert!(!plan.iter().any(|s| s.host == "B")); @@ -1575,8 +1567,8 @@ mod tests { let step = super::Step { name: "", stage: 2, - host: &build.config.build, - target: &build.config.build, + host: &build.build, + target: &build.build, }; assert!(!plan.iter().any(|s| s.host == "B")); @@ -1612,8 +1604,8 @@ mod tests { let step = super::Step { name: "", stage: 2, - host: &build.config.build, - target: &build.config.build, + host: &build.build, + target: &build.build, }; assert!(!plan.iter().any(|s| s.target == "A")); @@ -1639,8 +1631,8 @@ mod tests { let step = super::Step { name: "", stage: 2, - host: &build.config.build, - target: &build.config.build, + host: &build.build, + target: &build.build, }; assert!(!plan.iter().any(|s| s.target == "A")); @@ -1683,8 +1675,8 @@ mod tests { let step = super::Step { name: "", stage: 2, - host: &build.config.build, - target: &build.config.build, + host: &build.build, + target: &build.build, }; // rustc built for all for of (A, B) x (A, B) diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 61bd85e76c598..092fb04637ba7 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -14,7 +14,6 @@ //! not a lot of interesting happenings here unfortunately. use std::env; -use std::ffi::OsString; use std::fs; use std::io::{self, Write}; use std::path::{Path, PathBuf}; @@ -32,16 +31,9 @@ pub fn staticlib(name: &str, target: &str) -> String { } } -/// Copies a file from `src` to `dst`, attempting to use hard links and then -/// falling back to an actually filesystem copy if necessary. +/// Copies a file from `src` to `dst` pub fn copy(src: &Path, dst: &Path) { - // A call to `hard_link` will fail if `dst` exists, so remove it if it - // already exists so we can try to help `hard_link` succeed. let _ = fs::remove_file(&dst); - - // Attempt to "easy copy" by creating a hard link (symlinks don't work on - // windows), but if that fails just fall back to a slow `copy` operation. - // let res = fs::hard_link(src, dst); let res = fs::copy(src, dst); if let Err(e) = res { panic!("failed to copy `{}` to `{}`: {}", src.display(), @@ -149,8 +141,7 @@ pub fn dylib_path_var() -> &'static str { /// Parses the `dylib_path_var()` environment variable, returning a list of /// paths that are members of this lookup path. pub fn dylib_path() -> Vec<PathBuf> { - env::split_paths(&env::var_os(dylib_path_var()).unwrap_or(OsString::new())) - .collect() + env::split_paths(&env::var_os(dylib_path_var()).unwrap_or_default()).collect() } /// `push` all components to `buf`. On windows, append `.exe` to the last component. @@ -422,4 +413,4 @@ impl CiEnv { cmd.env("TERM", "xterm").args(&["--color", "always"]); } } -} \ No newline at end of file +} diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index ea6a822e360a4..7011261ab6c16 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -239,7 +239,10 @@ pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result<NativeLibBoiler ), _ => return Err(()), }; - native_lib_boilerplate("compiler-rt", sanitizer_name, &link_name, search_path) + native_lib_boilerplate("libcompiler_builtins/compiler-rt", + sanitizer_name, + &link_name, + search_path) } fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool { diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index 817ed8dd55437..f8e86986f82d0 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -67,13 +67,14 @@ for module in $modules; do mv "src/llvm-$commit" src/llvm continue fi - if [ ! -d "$cache_src_dir/$module" ]; then + if [ ! -e "$cache_src_dir/$module/.git" ]; then echo "WARNING: $module not found in pristine repo" - retry sh -c "git submodule deinit -f $module && git submodule update --init $module" + retry sh -c "git submodule deinit -f $module && \ + git submodule update --init --recursive $module" continue fi retry sh -c "git submodule deinit -f $module && \ - git submodule update --init --reference $cache_src_dir/$module $module" + git submodule update --init --recursive --reference $cache_src_dir/$module $module" done travis_fold end update_submodules diff --git a/src/compiler-rt b/src/compiler-rt deleted file mode 160000 index c8a8767c56ad3..0000000000000 --- a/src/compiler-rt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35 diff --git a/src/doc/unstable-book/src/language-features/allocator-internals.md b/src/doc/unstable-book/src/language-features/allocator-internals.md new file mode 100644 index 0000000000000..2023d758fe3de --- /dev/null +++ b/src/doc/unstable-book/src/language-features/allocator-internals.md @@ -0,0 +1,7 @@ +# `allocator_internals` + +This feature does not have a tracking issue, it is an unstable implementation +detail of the `global_allocator` feature not intended for use outside the +compiler. + +------------------------ diff --git a/src/doc/unstable-book/src/language-features/allocator.md b/src/doc/unstable-book/src/language-features/allocator.md deleted file mode 100644 index cfcf8e22d7088..0000000000000 --- a/src/doc/unstable-book/src/language-features/allocator.md +++ /dev/null @@ -1,119 +0,0 @@ -# `allocator` - -The tracking issue for this feature is: [#27389] - -[#27389]: https://github.com/rust-lang/rust/issues/27389 - ------------------------- - -Sometimes even the choices of jemalloc vs the system allocator aren't enough and -an entirely new custom allocator is required. In this you'll write your own -crate which implements the allocator API (e.g. the same as `alloc_system` or -`alloc_jemalloc`). As an example, let's take a look at a simplified and -annotated version of `alloc_system` - -```rust,no_run -# // Only needed for rustdoc --test down below. -# #![feature(lang_items)] -// The compiler needs to be instructed that this crate is an allocator in order -// to realize that when this is linked in another allocator like jemalloc should -// not be linked in. -#![feature(allocator)] -#![allocator] - -// Allocators are not allowed to depend on the standard library which in turn -// requires an allocator in order to avoid circular dependencies. This crate, -// however, can use all of libcore. -#![no_std] - -// Let's give a unique name to our custom allocator: -#![crate_name = "my_allocator"] -#![crate_type = "rlib"] - -// Our system allocator will use the in-tree libc crate for FFI bindings. Note -// that currently the external (crates.io) libc cannot be used because it links -// to the standard library (e.g. `#![no_std]` isn't stable yet), so that's why -// this specifically requires the in-tree version. -#![feature(libc)] -extern crate libc; - -// Listed below are the five allocation functions currently required by custom -// allocators. Their signatures and symbol names are not currently typechecked -// by the compiler, but this is a future extension and are required to match -// what is found below. -// -// Note that the standard `malloc` and `realloc` functions do not provide a way -// to communicate alignment so this implementation would need to be improved -// with respect to alignment in that aspect. - -#[no_mangle] -pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 { - unsafe { libc::malloc(size as libc::size_t) as *mut u8 } -} - -#[no_mangle] -pub extern fn __rust_allocate_zeroed(size: usize, _align: usize) -> *mut u8 { - unsafe { libc::calloc(size as libc::size_t, 1) as *mut u8 } -} - -#[no_mangle] -pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) { - unsafe { libc::free(ptr as *mut libc::c_void) } -} - -#[no_mangle] -pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize, - _align: usize) -> *mut u8 { - unsafe { - libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 - } -} - -#[no_mangle] -pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize, - _size: usize, _align: usize) -> usize { - old_size // This api is not supported by libc. -} - -#[no_mangle] -pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize { - size -} - -# // Only needed to get rustdoc to test this: -# fn main() {} -# #[lang = "panic_fmt"] fn panic_fmt() {} -# #[lang = "eh_personality"] fn eh_personality() {} -# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} -# #[no_mangle] pub extern fn rust_eh_register_frames () {} -# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} -``` - -After we compile this crate, it can be used as follows: - -```rust,ignore -extern crate my_allocator; - -fn main() { - let a = Box::new(8); // Allocates memory via our custom allocator crate. - println!("{}", a); -} -``` - -## Custom allocator limitations - -There are a few restrictions when working with custom allocators which may cause -compiler errors: - -* Any one artifact may only be linked to at most one allocator. Binaries, - dylibs, and staticlibs must link to exactly one allocator, and if none have - been explicitly chosen the compiler will choose one. On the other hand rlibs - do not need to link to an allocator (but still can). - -* A consumer of an allocator is tagged with `#![needs_allocator]` (e.g. the - `liballoc` crate currently) and an `#[allocator]` crate cannot transitively - depend on a crate which needs an allocator (e.g. circular dependencies are not - allowed). This basically means that allocators must restrict themselves to - libcore currently. - - diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md new file mode 100644 index 0000000000000..2eae40aef349e --- /dev/null +++ b/src/doc/unstable-book/src/language-features/global-allocator.md @@ -0,0 +1,71 @@ +# `global_allocator` + +The tracking issue for this feature is: [#27389] + +[#27389]: https://github.com/rust-lang/rust/issues/27389 + +------------------------ + +Rust programs may need to change the allocator that they're running with from +time to time. This use case is distinct from an allocator-per-collection (e.g. a +`Vec` with a custom allocator) and instead is more related to changing the +global default allocator, e.g. what `Vec<T>` uses by default. + +Currently Rust programs don't have a specified global allocator. The compiler +may link to a version of [jemalloc] on some platforms, but this is not +guaranteed. Libraries, however, like cdylibs and staticlibs are guaranteed +to use the "system allocator" which means something like `malloc` on Unixes and +`HeapAlloc` on Windows. + +[jemalloc]: https://github.com/jemalloc/jemalloc + +The `#[global_allocator]` attribute, however, allows configuring this choice. +You can use this to implement a completely custom global allocator to route all +default allocation requests to a custom object. Defined in [RFC 1974] usage +looks like: + +[RFC 1974]: https://github.com/rust-lang/rfcs/pull/1974 + +```rust +#![feature(global_allocator, heap_api)] + +use std::heap::{Alloc, System, Layout, AllocErr}; + +struct MyAllocator; + +unsafe impl<'a> Alloc for &'a MyAllocator { + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + System.alloc(layout) + } + + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + System.dealloc(ptr, layout) + } +} + +#[global_allocator] +static GLOBAL: MyAllocator = MyAllocator; + +fn main() { + // This `Vec` will allocate memory through `GLOBAL` above + let mut v = Vec::new(); + v.push(1); +} +``` + +And that's it! The `#[global_allocator]` attribute is applied to a `static` +which implements the `Alloc` trait in the `std::heap` module. Note, though, +that the implementation is defined for `&MyAllocator`, not just `MyAllocator`. +You may wish, however, to also provide `Alloc for MyAllocator` for other use +cases. + +A crate can only have one instance of `#[global_allocator]` and this instance +may be loaded through a dependency. For example `#[global_allocator]` above +could have been placed in one of the dependencies loaded through `extern crate`. + +Note that `Alloc` itself is an `unsafe` trait, with much documentation on the +trait itself about usage and for implementors. Extra care should be taken when +implementing a global allocator as well as the allocator may be called from many +portions of the standard library, such as the panicking routine. As a result it +is highly recommended to not panic during allocation and work in as many +situations with as few dependencies as possible as well. diff --git a/src/doc/unstable-book/src/library-features/compiler-builtins-lib.md b/src/doc/unstable-book/src/library-features/compiler-builtins-lib.md deleted file mode 100644 index 5da8968fd0ce2..0000000000000 --- a/src/doc/unstable-book/src/library-features/compiler-builtins-lib.md +++ /dev/null @@ -1,35 +0,0 @@ -# `compiler_builtins_lib` - -The tracking issue for this feature is: None. - ------------------------- - -This feature is required to link to the `compiler_builtins` crate which contains -"compiler intrinsics". Compiler intrinsics are software implementations of basic -operations like multiplication of `u64`s. These intrinsics are only required on -platforms where these operations don't directly map to a hardware instruction. - -You should never need to explicitly link to the `compiler_builtins` crate when -building "std" programs as `compiler_builtins` is already in the dependency -graph of `std`. But you may need it when building `no_std` **binary** crates. If -you get a *linker* error like: - -``` text -$PWD/src/main.rs:11: undefined reference to `__aeabi_lmul' -$PWD/src/main.rs:11: undefined reference to `__aeabi_uldivmod' -``` - -That means that you need to link to this crate. - -When you link to this crate, make sure it only appears once in your crate -dependency graph. Also, it doesn't matter where in the dependency graph, you -place the `compiler_builtins` crate. - -<!-- NOTE(ignore) doctests don't support `no_std` binaries --> - -``` rust,ignore -#![feature(compiler_builtins_lib)] -#![no_std] - -extern crate compiler_builtins; -``` diff --git a/src/doc/unstable-book/src/library-features/proc-macro.md b/src/doc/unstable-book/src/library-features/proc-macro.md new file mode 100644 index 0000000000000..19e7f663c7ac3 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/proc-macro.md @@ -0,0 +1,7 @@ +# `proc_macro` + +The tracking issue for this feature is: [#38356] + +[#38356]: https://github.com/rust-lang/rust/issues/38356 + +------------------------ diff --git a/src/liballoc/allocator.rs b/src/liballoc/allocator.rs index bf38629ed38a7..ca5388b470147 100644 --- a/src/liballoc/allocator.rs +++ b/src/liballoc/allocator.rs @@ -13,7 +13,7 @@ slightly, especially to possibly take into account the \ types being stored to make room for a future \ tracing garbage collector", - issue = "27700")] + issue = "32838")] use core::cmp; use core::fmt; @@ -73,6 +73,7 @@ impl Layout { /// * `size`, when rounded up to the nearest multiple of `align`, /// must not overflow (i.e. the rounded value must be less than /// `usize::MAX`). + #[inline] pub fn from_size_align(size: usize, align: usize) -> Option<Layout> { if !align.is_power_of_two() { return None; @@ -96,13 +97,28 @@ impl Layout { return None; } - Some(Layout { size: size, align: align }) + unsafe { + Some(Layout::from_size_align_unchecked(size, align)) + } + } + + /// Creates a layout, bypassing all checks. + /// + /// # Unsafety + /// + /// This function is unsafe as it does not verify that `align` is a power of + /// two nor that `size` aligned to `align` fits within the address space. + #[inline] + pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { + Layout { size: size, align: align } } /// The minimum size in bytes for a memory block of this layout. + #[inline] pub fn size(&self) -> usize { self.size } /// The minimum byte alignment for a memory block of this layout. + #[inline] pub fn align(&self) -> usize { self.align } /// Constructs a `Layout` suitable for holding a value of type `T`. @@ -135,6 +151,7 @@ impl Layout { /// /// Panics if the combination of `self.size` and the given `align` /// violates the conditions listed in `from_size_align`. + #[inline] pub fn align_to(&self, align: usize) -> Self { Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() } @@ -155,6 +172,7 @@ impl Layout { /// to be less than or equal to the alignment of the starting /// address for the whole allocated block of memory. One way to /// satisfy this constraint is to ensure `align <= self.align`. + #[inline] pub fn padding_needed_for(&self, align: usize) -> usize { let len = self.size(); @@ -556,6 +574,7 @@ pub unsafe trait Alloc { /// However, for clients that do not wish to track the capacity /// returned by `alloc_excess` locally, this method is likely to /// produce useful results. + #[inline] fn usable_size(&self, layout: &Layout) -> (usize, usize) { (layout.size(), layout.size()) } diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 7c51c4b161ca8..d9edf50b9c8ec 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -23,7 +23,6 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; use core::borrow; use core::fmt; use core::cmp::Ordering; -use core::mem::{align_of_val, size_of_val}; use core::intrinsics::abort; use core::mem; use core::mem::uninitialized; @@ -34,7 +33,8 @@ use core::marker::Unsize; use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; -use heap::deallocate; + +use heap::{Heap, Alloc, Layout}; /// A soft limit on the amount of references that may be made to an `Arc`. /// @@ -503,7 +503,7 @@ impl<T: ?Sized> Arc<T> { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) + Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) } } @@ -1007,7 +1007,9 @@ impl<T: ?Sized> Drop for Weak<T> { // ref, which can only happen after the lock is released. if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - unsafe { deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) } + unsafe { + Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) + } } } } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 4a43018e973b1..76cf10f0d55ea 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -55,7 +55,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use heap; +use heap::{Heap, Layout, Alloc}; use raw_vec::RawVec; use core::any::Any; @@ -135,8 +135,7 @@ pub struct Box<T: ?Sized>(Unique<T>); #[allow(missing_debug_implementations)] pub struct IntermediateBox<T: ?Sized> { ptr: *mut u8, - size: usize, - align: usize, + layout: Layout, marker: marker::PhantomData<*mut T>, } @@ -156,23 +155,21 @@ unsafe fn finalize<T>(b: IntermediateBox<T>) -> Box<T> { } fn make_place<T>() -> IntermediateBox<T> { - let size = mem::size_of::<T>(); - let align = mem::align_of::<T>(); + let layout = Layout::new::<T>(); - let p = if size == 0 { + let p = if layout.size() == 0 { mem::align_of::<T>() as *mut u8 } else { - let p = unsafe { heap::allocate(size, align) }; - if p.is_null() { - panic!("Box make_place allocation failure."); + unsafe { + Heap.alloc(layout.clone()).unwrap_or_else(|err| { + Heap.oom(err) + }) } - p }; IntermediateBox { ptr: p, - size: size, - align: align, + layout: layout, marker: marker::PhantomData, } } @@ -221,8 +218,10 @@ impl<T> Placer<T> for ExchangeHeapSingleton { issue = "27779")] impl<T: ?Sized> Drop for IntermediateBox<T> { fn drop(&mut self) { - if self.size > 0 { - unsafe { heap::deallocate(self.ptr, self.size, self.align) } + if self.layout.size() > 0 { + unsafe { + Heap.dealloc(self.ptr, self.layout.clone()) + } } } } diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 811174b331e2b..0eaff6f2192c8 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -48,7 +48,7 @@ use core::ptr::{self, Unique}; use core::slice; use boxed::Box; -use heap; +use heap::{Heap, Alloc, Layout}; const B: usize = 6; pub const MIN_LEN: usize = B - 1; @@ -254,11 +254,7 @@ impl<K, V> Root<K, V> { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - heap::deallocate( - top, - mem::size_of::<InternalNode<K, V>>(), - mem::align_of::<InternalNode<K, V>>() - ); + Heap.dealloc(top, Layout::new::<InternalNode<K, V>>()); } } } @@ -445,7 +441,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> { > { let ptr = self.as_leaf() as *const LeafNode<K, V> as *const u8 as *mut u8; let ret = self.ascend().ok(); - heap::deallocate(ptr, mem::size_of::<LeafNode<K, V>>(), mem::align_of::<LeafNode<K, V>>()); + Heap.dealloc(ptr, Layout::new::<LeafNode<K, V>>()); ret } } @@ -466,11 +462,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> { > { let ptr = self.as_internal() as *const InternalNode<K, V> as *const u8 as *mut u8; let ret = self.ascend().ok(); - heap::deallocate( - ptr, - mem::size_of::<InternalNode<K, V>>(), - mem::align_of::<InternalNode<K, V>>() - ); + Heap.dealloc(ptr, Layout::new::<InternalNode<K, V>>()); ret } } @@ -1252,16 +1244,14 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: ).correct_parent_link(); } - heap::deallocate( + Heap.dealloc( right_node.node.get() as *mut u8, - mem::size_of::<InternalNode<K, V>>(), - mem::align_of::<InternalNode<K, V>>() + Layout::new::<InternalNode<K, V>>(), ); } else { - heap::deallocate( + Heap.dealloc( right_node.node.get() as *mut u8, - mem::size_of::<LeafNode<K, V>>(), - mem::align_of::<LeafNode<K, V>>() + Layout::new::<LeafNode<K, V>>(), ); } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index d46c6a83ff32c..1d959ac5bf6dc 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -8,207 +8,212 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![unstable(feature = "heap_api", +#![unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked \ slightly, especially to possibly take into account the \ types being stored to make room for a future \ tracing garbage collector", - issue = "27700")] + issue = "32838")] -use allocator::{Alloc, AllocErr, CannotReallocInPlace, Layout}; -use core::{isize, usize, cmp, ptr}; use core::intrinsics::{min_align_of_val, size_of_val}; +use core::mem::{self, ManuallyDrop}; +use core::usize; -#[allow(improper_ctypes)] -extern "C" { - #[allocator] - fn __rust_allocate(size: usize, align: usize) -> *mut u8; - fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8; - fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize); - fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8; - fn __rust_reallocate_inplace(ptr: *mut u8, - old_size: usize, - size: usize, - align: usize) - -> usize; - fn __rust_usable_size(size: usize, align: usize) -> usize; +pub use allocator::*; +#[doc(hidden)] +pub mod __core { + pub use core::*; } -#[inline(always)] -fn check_size_and_alignment(size: usize, align: usize) { - debug_assert!(size != 0); - debug_assert!(size <= isize::MAX as usize, - "Tried to allocate too much: {} bytes", - size); - debug_assert!(usize::is_power_of_two(align), - "Invalid alignment of allocation: {}", - align); +extern "Rust" { + #[allocator] + fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; + fn __rust_oom(err: *const u8) -> !; + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); + fn __rust_usable_size(layout: *const u8, + min: *mut usize, + max: *mut usize); + fn __rust_realloc(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + err: *mut u8) -> *mut u8; + fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; + fn __rust_alloc_excess(size: usize, + align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8; + fn __rust_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; + fn __rust_grow_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8; + fn __rust_shrink_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8; } #[derive(Copy, Clone, Default, Debug)] -pub struct HeapAlloc; +pub struct Heap; -unsafe impl Alloc for HeapAlloc { +unsafe impl Alloc for Heap { + #[inline] unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let addr = allocate(layout.size(), layout.align()); - if addr.is_null() { - Err(AllocErr::Exhausted { request: layout }) + let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>()); + let ptr = __rust_alloc(layout.size(), + layout.align(), + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) } else { - Ok(addr) + Ok(ptr) } } - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let addr = allocate_zeroed(layout.size(), layout.align()); - if addr.is_null() { - Err(AllocErr::Exhausted { request: layout }) - } else { - Ok(addr) + #[inline] + fn oom(&mut self, err: AllocErr) -> ! { + unsafe { + __rust_oom(&err as *const AllocErr as *const u8) } } + #[inline] unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - deallocate(ptr, layout.size(), layout.align()); + __rust_dealloc(ptr, layout.size(), layout.align()) } + #[inline] fn usable_size(&self, layout: &Layout) -> (usize, usize) { - (layout.size(), usable_size(layout.size(), layout.align())) + let mut min = 0; + let mut max = 0; + unsafe { + __rust_usable_size(layout as *const Layout as *const u8, + &mut min, + &mut max); + } + (min, max) } + #[inline] unsafe fn realloc(&mut self, ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<*mut u8, AllocErr> { - let old_size = layout.size(); - let new_size = new_layout.size(); - if layout.align() == new_layout.align() { - let new_ptr = reallocate(ptr, old_size, new_size, layout.align()); - if new_ptr.is_null() { - // We assume `reallocate` already tried alloc + copy + - // dealloc fallback; thus pointless to repeat effort - Err(AllocErr::Exhausted { request: new_layout }) - } else { - Ok(new_ptr) - } + let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>()); + let ptr = __rust_realloc(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align(), + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) } else { - // if alignments don't match, fall back on alloc + copy + dealloc - let result = self.alloc(new_layout); - if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); - self.dealloc(ptr, layout); - } - result + mem::forget(err); + Ok(ptr) } } + #[inline] + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>()); + let ptr = __rust_alloc_zeroed(layout.size(), + layout.align(), + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(ptr) + } + } + + #[inline] + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> { + let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>()); + let mut size = 0; + let ptr = __rust_alloc_excess(layout.size(), + layout.align(), + &mut size, + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(Excess(ptr, size)) + } + } + + #[inline] + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<Excess, AllocErr> { + let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>()); + let mut size = 0; + let ptr = __rust_realloc_excess(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align(), + &mut size, + &mut *err as *mut AllocErr as *mut u8); + if ptr.is_null() { + Err(ManuallyDrop::into_inner(err)) + } else { + Ok(Excess(ptr, size)) + } + } + + #[inline] unsafe fn grow_in_place(&mut self, ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - // grow_in_place spec requires this, and the spec for reallocate_inplace - // makes it hard to detect failure if it does not hold. debug_assert!(new_layout.size() >= layout.size()); - - if layout.align() != new_layout.align() { // reallocate_inplace requires this. - return Err(CannotReallocInPlace); + debug_assert!(new_layout.align() == layout.align()); + let ret = __rust_grow_in_place(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align()); + if ret != 0 { + Ok(()) + } else { + Err(CannotReallocInPlace) } - let usable = reallocate_inplace(ptr, layout.size(), new_layout.size(), layout.align()); - if usable >= new_layout.size() { Ok(()) } else { Err(CannotReallocInPlace) } } -} - -// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias` -/// Return a pointer to `size` bytes of memory aligned to `align`. -/// -/// On failure, return a null pointer. -/// -/// Behavior is undefined if the requested size is 0 or the alignment is not a -/// power of 2. The alignment must be no larger than the largest supported page -/// size on the platform. -#[inline] -pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { - check_size_and_alignment(size, align); - __rust_allocate(size, align) -} - -/// Return a pointer to `size` bytes of memory aligned to `align` and -/// initialized to zeroes. -/// -/// On failure, return a null pointer. -/// -/// Behavior is undefined if the requested size is 0 or the alignment is not a -/// power of 2. The alignment must be no larger than the largest supported page -/// size on the platform. -#[inline] -pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { - check_size_and_alignment(size, align); - __rust_allocate_zeroed(size, align) -} - -/// Resize the allocation referenced by `ptr` to `size` bytes. -/// -/// On failure, return a null pointer and leave the original allocation intact. -/// -/// If the allocation was relocated, the memory at the passed-in pointer is -/// undefined after the call. -/// -/// Behavior is undefined if the requested size is 0 or the alignment is not a -/// power of 2. The alignment must be no larger than the largest supported page -/// size on the platform. -/// -/// The `old_size` and `align` parameters are the parameters that were used to -/// create the allocation referenced by `ptr`. The `old_size` parameter may be -/// any value in range_inclusive(requested_size, usable_size). -#[inline] -pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { - check_size_and_alignment(size, align); - __rust_reallocate(ptr, old_size, size, align) -} - -/// Resize the allocation referenced by `ptr` to `size` bytes. -/// -/// If the operation succeeds, it returns `usable_size(size, align)` and if it -/// fails (or is a no-op) it returns `usable_size(old_size, align)`. -/// -/// Behavior is undefined if the requested size is 0 or the alignment is not a -/// power of 2. The alignment must be no larger than the largest supported page -/// size on the platform. -/// -/// The `old_size` and `align` parameters are the parameters that were used to -/// create the allocation referenced by `ptr`. The `old_size` parameter may be -/// any value in range_inclusive(requested_size, usable_size). -#[inline] -pub unsafe fn reallocate_inplace(ptr: *mut u8, - old_size: usize, - size: usize, - align: usize) - -> usize { - check_size_and_alignment(size, align); - __rust_reallocate_inplace(ptr, old_size, size, align) -} - -/// Deallocates the memory referenced by `ptr`. -/// -/// The `ptr` parameter must not be null. -/// -/// The `old_size` and `align` parameters are the parameters that were used to -/// create the allocation referenced by `ptr`. The `old_size` parameter may be -/// any value in range_inclusive(requested_size, usable_size). -#[inline] -pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) { - __rust_deallocate(ptr, old_size, align) -} - -/// Returns the usable size of an allocation created with the specified the -/// `size` and `align`. -#[inline] -pub fn usable_size(size: usize, align: usize) -> usize { - unsafe { __rust_usable_size(size, align) } + #[inline] + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + debug_assert!(new_layout.size() <= layout.size()); + debug_assert!(new_layout.align() == layout.align()); + let ret = __rust_shrink_in_place(ptr, + layout.size(), + layout.align(), + new_layout.size(), + new_layout.align()); + if ret != 0 { + Ok(()) + } else { + Err(CannotReallocInPlace) + } + } } /// An arbitrary non-null address to represent zero-size allocations. @@ -228,11 +233,10 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { if size == 0 { align as *mut u8 } else { - let ptr = allocate(size, align); - if ptr.is_null() { - ::oom() - } - ptr + let layout = Layout::from_size_align_unchecked(size, align); + Heap.alloc(layout).unwrap_or_else(|err| { + Heap.oom(err) + }) } } @@ -243,7 +247,8 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) { let align = min_align_of_val(&*ptr); // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary. if size != 0 { - deallocate(ptr as *mut u8, size, align); + let layout = Layout::from_size_align_unchecked(size, align); + Heap.dealloc(ptr as *mut u8, layout); } } @@ -252,38 +257,22 @@ mod tests { extern crate test; use self::test::Bencher; use boxed::Box; - use heap; + use heap::{Heap, Alloc, Layout}; #[test] fn allocate_zeroed() { unsafe { - let size = 1024; - let ptr = heap::allocate_zeroed(size, 1); - if ptr.is_null() { - ::oom() - } + let layout = Layout::from_size_align(1024, 1).unwrap(); + let ptr = Heap.alloc_zeroed(layout.clone()) + .unwrap_or_else(|e| Heap.oom(e)); - let end = ptr.offset(size as isize); + let end = ptr.offset(layout.size() as isize); let mut i = ptr; while i < end { assert_eq!(*i, 0); i = i.offset(1); } - heap::deallocate(ptr, size, 1); - } - } - - #[test] - fn basic_reallocate_inplace_noop() { - unsafe { - let size = 4000; - let ptr = heap::allocate(size, 8); - if ptr.is_null() { - ::oom() - } - let ret = heap::reallocate_inplace(ptr, size, size, 8); - heap::deallocate(ptr, size, 8); - assert_eq!(ret, heap::usable_size(size, 8)); + Heap.dealloc(ptr, layout); } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 23da29131362e..b419aeb5ab593 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -85,7 +85,7 @@ #![cfg_attr(not(test), feature(slice_rotate))] #![cfg_attr(not(test), feature(str_checked_slicing))] #![cfg_attr(test, feature(rand, test))] -#![feature(allocator)] +#![cfg_attr(stage0, feature(allocator))] #![feature(allow_internal_unstable)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -124,6 +124,7 @@ #![feature(unicode)] #![feature(unique)] #![feature(unsize)] +#![cfg_attr(not(stage0), feature(allocator_internals))] #![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))] #![cfg_attr(test, feature(test, box_heap))] @@ -168,7 +169,6 @@ mod boxed_test; pub mod arc; pub mod rc; pub mod raw_vec; -pub mod oom; // collections modules pub mod binary_heap; @@ -260,8 +260,6 @@ trait SpecExtend<I: IntoIterator> { fn spec_extend(&mut self, iter: I); } -pub use oom::oom; - #[doc(no_inline)] pub use binary_heap::BinaryHeap; #[doc(no_inline)] diff --git a/src/liballoc/oom.rs b/src/liballoc/oom.rs deleted file mode 100644 index 3640156fec2ae..0000000000000 --- a/src/liballoc/oom.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[cfg(target_has_atomic = "ptr")] -pub use self::imp::set_oom_handler; -use core::intrinsics; - -fn default_oom_handler() -> ! { - // The default handler can't do much more since we can't assume the presence - // of libc or any way of printing an error message. - unsafe { intrinsics::abort() } -} - -/// Common out-of-memory routine -#[cold] -#[inline(never)] -#[unstable(feature = "oom", reason = "not a scrutinized interface", - issue = "27700")] -pub fn oom() -> ! { - self::imp::oom() -} - -#[cfg(target_has_atomic = "ptr")] -mod imp { - use core::mem; - use core::sync::atomic::{AtomicPtr, Ordering}; - - static OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(super::default_oom_handler as *mut ()); - - #[inline(always)] - pub fn oom() -> ! { - let value = OOM_HANDLER.load(Ordering::SeqCst); - let handler: fn() -> ! = unsafe { mem::transmute(value) }; - handler(); - } - - /// Set a custom handler for out-of-memory conditions - /// - /// To avoid recursive OOM failures, it is critical that the OOM handler does - /// not allocate any memory itself. - #[unstable(feature = "oom", reason = "not a scrutinized interface", - issue = "27700")] - pub fn set_oom_handler(handler: fn() -> !) { - OOM_HANDLER.store(handler as *mut (), Ordering::SeqCst); - } -} - -#[cfg(not(target_has_atomic = "ptr"))] -mod imp { - #[inline(always)] - pub fn oom() -> ! { - super::default_oom_handler() - } -} diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index c56a93c046041..d1aab4c70be4a 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -12,7 +12,7 @@ use allocator::{Alloc, Layout}; use core::ptr::{self, Unique}; use core::mem; use core::slice; -use heap::{HeapAlloc}; +use heap::Heap; use super::boxed::Box; use core::ops::Drop; use core::cmp; @@ -45,7 +45,7 @@ use core::cmp; /// field. This allows zero-sized types to not be special-cased by consumers of /// this type. #[allow(missing_debug_implementations)] -pub struct RawVec<T, A: Alloc = HeapAlloc> { +pub struct RawVec<T, A: Alloc = Heap> { ptr: Unique<T>, cap: usize, a: A, @@ -112,14 +112,14 @@ impl<T, A: Alloc> RawVec<T, A> { } } -impl<T> RawVec<T, HeapAlloc> { +impl<T> RawVec<T, Heap> { /// Creates the biggest possible RawVec (on the system heap) /// without allocating. If T has positive size, then this makes a /// RawVec with capacity 0. If T has 0 size, then it it makes a /// RawVec with capacity `usize::MAX`. Useful for implementing /// delayed allocation. pub fn new() -> Self { - Self::new_in(HeapAlloc) + Self::new_in(Heap) } /// Creates a RawVec (on the system heap) with exactly the @@ -139,13 +139,13 @@ impl<T> RawVec<T, HeapAlloc> { /// Aborts on OOM #[inline] pub fn with_capacity(cap: usize) -> Self { - RawVec::allocate_in(cap, false, HeapAlloc) + RawVec::allocate_in(cap, false, Heap) } /// Like `with_capacity` but guarantees the buffer is zeroed. #[inline] pub fn with_capacity_zeroed(cap: usize) -> Self { - RawVec::allocate_in(cap, true, HeapAlloc) + RawVec::allocate_in(cap, true, Heap) } } @@ -166,7 +166,7 @@ impl<T, A: Alloc> RawVec<T, A> { } } -impl<T> RawVec<T, HeapAlloc> { +impl<T> RawVec<T, Heap> { /// Reconstitutes a RawVec from a pointer, capacity. /// /// # Undefined Behavior @@ -178,7 +178,7 @@ impl<T> RawVec<T, HeapAlloc> { RawVec { ptr: Unique::new(ptr), cap: cap, - a: HeapAlloc, + a: Heap, } } @@ -609,7 +609,7 @@ impl<T, A: Alloc> RawVec<T, A> { } } -impl<T> RawVec<T, HeapAlloc> { +impl<T> RawVec<T, Heap> { /// Converts the entire buffer into `Box<[T]>`. /// /// While it is not *strictly* Undefined Behavior to call @@ -693,13 +693,13 @@ mod tests { if size > self.fuel { return Err(AllocErr::Unsupported { details: "fuel exhausted" }); } - match HeapAlloc.alloc(layout) { + match Heap.alloc(layout) { ok @ Ok(_) => { self.fuel -= size; ok } err @ Err(_) => err, } } unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - HeapAlloc.dealloc(ptr, layout) + Heap.dealloc(ptr, layout) } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 94fe36d01a5a5..306136b21c84b 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -252,13 +252,13 @@ use core::hash::{Hash, Hasher}; use core::intrinsics::abort; use core::marker; use core::marker::Unsize; -use core::mem::{self, align_of_val, forget, size_of, size_of_val, uninitialized}; +use core::mem::{self, forget, size_of, size_of_val, uninitialized}; use core::ops::Deref; use core::ops::CoerceUnsized; use core::ptr::{self, Shared}; use core::convert::From; -use heap::{allocate, deallocate, box_free}; +use heap::{Heap, Alloc, Layout, box_free}; use raw_vec::RawVec; struct RcBox<T: ?Sized> { @@ -461,7 +461,8 @@ impl<T> Rc<[T]> { // FIXME(custom-DST): creating this invalid &[T] is dubiously defined, // we should have a better way of getting the size/align // of a DST from its unsized part. - let ptr = allocate(size_of_val(&*ptr), align_of_val(&*ptr)); + let ptr = Heap.alloc(Layout::for_value(&*ptr)) + .unwrap_or_else(|e| Heap.oom(e)); let ptr: *mut RcBox<[T]> = mem::transmute([ptr as usize, value.len()]); // Initialize the new RcBox. @@ -719,7 +720,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> { self.dec_weak(); if self.weak() == 0 { - deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) + Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); } } } @@ -1097,7 +1098,7 @@ impl<T: ?Sized> Drop for Weak<T> { // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. if self.weak() == 0 { - deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) + Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); } } } diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 79d1ccf637d37..622cc68964bf7 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2008,10 +2008,10 @@ impl From<Box<str>> for String { } } -#[stable(feature = "box_from_str", since = "1.18.0")] -impl Into<Box<str>> for String { - fn into(self) -> Box<str> { - self.into_boxed_str() +#[stable(feature = "box_from_str", since = "1.20.0")] +impl From<String> for Box<str> { + fn from(s: String) -> Box<str> { + s.into_boxed_str() } } diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index fdf453b39cf5d..17f1229c2060e 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -274,6 +274,11 @@ fn test_dedup_by() { vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); assert_eq!(vec, ["foo", "bar", "baz", "bar"]); + + let mut vec = vec![("foo", 1), ("foo", 2), ("bar", 3), ("bar", 4), ("bar", 5)]; + vec.dedup_by(|a, b| a.0 == b.0 && { b.1 += a.1; true }); + + assert_eq!(vec, [("foo", 3), ("bar", 12)]); } #[test] diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index a992351653d7b..f2935c05d4f7a 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -510,8 +510,7 @@ fn test_from_iter() { let u: Vec<_> = deq.iter().cloned().collect(); assert_eq!(u, v); - // FIXME #27741: Remove `.skip(0)` when Range::step_by is fully removed - let seq = (0..).skip(0).step_by(2).take(256); + let seq = (0..).step_by(2).take(256); let deq: VecDeque<_> = seq.collect(); for (i, &x) in deq.iter().enumerate() { assert_eq!(2 * i, x); diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 5d1999a42629a..780a51aec3bab 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -222,7 +222,7 @@ use Bound::{Excluded, Included, Unbounded}; /// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized /// types inside a `Vec`, it will not allocate space for them. *Note that in this case /// the `Vec` may not report a [`capacity`] of 0*. `Vec` will allocate if and only -/// if [`mem::size_of::<T>`]` * capacity() > 0`. In general, `Vec`'s allocation +/// if [`mem::size_of::<T>`]`() * capacity() > 0`. In general, `Vec`'s allocation /// details are subtle enough that it is strongly recommended that you only /// free memory allocated by a `Vec` by creating a new `Vec` and dropping it. /// @@ -823,7 +823,8 @@ impl<T> Vec<T> { } } - /// Removes consecutive elements in the vector that resolve to the same key. + /// Removes all but the first of consecutive elements in the vector that resolve to the same + /// key. /// /// If the vector is sorted, this removes all duplicates. /// @@ -842,11 +843,13 @@ impl<T> Vec<T> { self.dedup_by(|a, b| key(a) == key(b)) } - /// Removes consecutive elements in the vector according to a predicate. + /// Removes all but the first of consecutive elements in the vector satisfying a given equality + /// relation. /// /// The `same_bucket` function is passed references to two elements from the vector, and - /// returns `true` if the elements compare equal, or `false` if they do not. Only the first - /// of adjacent equal items is kept. + /// returns `true` if the elements compare equal, or `false` if they do not. The elements are + /// passed in opposite order from their order in the vector, so if `same_bucket(a, b)` returns + /// `true`, `a` is removed. /// /// If the vector is sorted, this removes all duplicates. /// diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 49e5baad74dda..99c0bf2aaab48 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -15,6 +15,10 @@ doc = false core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } +[target.'cfg(not(stage0))'.dependencies] +alloc = { path = "../liballoc" } +alloc_system = { path = "../liballoc_system" } + [build-dependencies] build_helper = { path = "../build_helper" } gcc = "0.3.50" diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 288531cb5b21f..72686ddcc09ef 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -11,23 +11,36 @@ #![crate_name = "alloc_jemalloc"] #![crate_type = "rlib"] #![no_std] -#![allocator] #![unstable(feature = "alloc_jemalloc", reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] #![deny(warnings)] -#![feature(allocator)] #![feature(libc)] #![feature(staged_api)] - +#![feature(linkage)] +#![cfg_attr(stage0, allocator)] +#![cfg_attr(stage0, feature(allocator))] +#![cfg_attr(not(stage0), feature(global_allocator))] +#![cfg_attr(all(not(stage0), not(dummy_jemalloc)), feature(allocator_api))] +#![cfg_attr(not(stage0), feature(alloc))] +#![cfg_attr(not(stage0), feature(alloc_system))] +#![cfg_attr(dummy_jemalloc, allow(dead_code))] + +#[cfg(not(stage0))] +extern crate alloc; +#[cfg(not(stage0))] +extern crate alloc_system; extern crate libc; -pub use imp::*; +#[cfg(all(not(stage0), not(dummy_jemalloc)))] +pub use contents::*; +#[cfg(all(not(stage0), not(dummy_jemalloc)))] +mod contents { + use core::ptr; -// See comments in build.rs for why we sometimes build a crate that does nothing -#[cfg(not(dummy_jemalloc))] -mod imp { + use alloc::heap::{Alloc, AllocErr, Layout}; + use alloc_system::System; use libc::{c_int, c_void, size_t}; // Note that the symbols here are prefixed by default on macOS and Windows (we @@ -91,96 +104,152 @@ mod imp { } } - #[no_mangle] - pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 { - let flags = align_to_flags(align); - unsafe { mallocx(size as size_t, flags) as *mut u8 } - } + // for symbol names src/librustc/middle/allocator.rs + // for signatures src/librustc_allocator/lib.rs - #[no_mangle] - pub extern "C" fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 { - if align <= MIN_ALIGN { - unsafe { calloc(size as size_t, 1) as *mut u8 } - } else { - let flags = align_to_flags(align) | MALLOCX_ZERO; - unsafe { mallocx(size as size_t, flags) as *mut u8 } - } - } + // linkage directives are provided as part of the current compiler allocator + // ABI #[no_mangle] - pub extern "C" fn __rust_reallocate(ptr: *mut u8, - _old_size: usize, - size: usize, - align: usize) - -> *mut u8 { + #[linkage = "external"] + pub unsafe extern fn __rde_alloc(size: usize, + align: usize, + err: *mut u8) -> *mut u8 { let flags = align_to_flags(align); - unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 } + let ptr = mallocx(size as size_t, flags) as *mut u8; + if ptr.is_null() { + let layout = Layout::from_size_align_unchecked(size, align); + ptr::write(err as *mut AllocErr, + AllocErr::Exhausted { request: layout }); + } + ptr } #[no_mangle] - pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8, - _old_size: usize, - size: usize, - align: usize) - -> usize { - let flags = align_to_flags(align); - unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize } + #[linkage = "external"] + pub unsafe extern fn __rde_oom(err: *const u8) -> ! { + System.oom((*(err as *const AllocErr)).clone()) } #[no_mangle] - pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { + #[linkage = "external"] + pub unsafe extern fn __rde_dealloc(ptr: *mut u8, + size: usize, + align: usize) { let flags = align_to_flags(align); - unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) } + sdallocx(ptr as *mut c_void, size, flags); } #[no_mangle] - pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize { - let flags = align_to_flags(align); - unsafe { nallocx(size as size_t, flags) as usize } - } -} - -#[cfg(dummy_jemalloc)] -mod imp { - fn bogus() -> ! { - panic!("jemalloc is not implemented for this platform"); + #[linkage = "external"] + pub unsafe extern fn __rde_usable_size(layout: *const u8, + min: *mut usize, + max: *mut usize) { + let layout = &*(layout as *const Layout); + let flags = align_to_flags(layout.align()); + let size = nallocx(layout.size(), flags) as usize; + *min = layout.size(); + if size > 0 { + *max = size; + } else { + *max = layout.size(); + } } #[no_mangle] - pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 { - bogus() + #[linkage = "external"] + pub unsafe extern fn __rde_realloc(ptr: *mut u8, + _old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + err: *mut u8) -> *mut u8 { + if new_align != old_align { + ptr::write(err as *mut AllocErr, + AllocErr::Unsupported { details: "can't change alignments" }); + return 0 as *mut u8 + } + + let flags = align_to_flags(new_align); + let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8; + if ptr.is_null() { + let layout = Layout::from_size_align_unchecked(new_size, new_align); + ptr::write(err as *mut AllocErr, + AllocErr::Exhausted { request: layout }); + } + ptr } #[no_mangle] - pub extern "C" fn __rust_allocate_zeroed(_size: usize, _align: usize) -> *mut u8 { - bogus() + #[linkage = "external"] + pub unsafe extern fn __rde_alloc_zeroed(size: usize, + align: usize, + err: *mut u8) -> *mut u8 { + let ptr = if align <= MIN_ALIGN { + calloc(size as size_t, 1) as *mut u8 + } else { + let flags = align_to_flags(align) | MALLOCX_ZERO; + mallocx(size as size_t, flags) as *mut u8 + }; + if ptr.is_null() { + let layout = Layout::from_size_align_unchecked(size, align); + ptr::write(err as *mut AllocErr, + AllocErr::Exhausted { request: layout }); + } + ptr } #[no_mangle] - pub extern "C" fn __rust_reallocate(_ptr: *mut u8, - _old_size: usize, - _size: usize, - _align: usize) - -> *mut u8 { - bogus() + #[linkage = "external"] + pub unsafe extern fn __rde_alloc_excess(size: usize, + align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8 { + let p = __rde_alloc(size, align, err); + if !p.is_null() { + *excess = size; + } + return p } #[no_mangle] - pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8, - _old_size: usize, - _size: usize, - _align: usize) - -> usize { - bogus() + #[linkage = "external"] + pub unsafe extern fn __rde_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 { + let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err); + if !p.is_null() { + *excess = new_size; + } + return p } #[no_mangle] - pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) { - bogus() + #[linkage = "external"] + pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8 { + __rde_shrink_in_place(ptr, old_size, old_align, new_size, new_align) } #[no_mangle] - pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize { - bogus() + #[linkage = "external"] + pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8, + _old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8 { + if old_align == new_align { + let flags = align_to_flags(new_align); + (xallocx(ptr as *mut c_void, new_size, 0, flags) == new_size) as u8 + } else { + 0 + } } } diff --git a/src/liballoc_system/Cargo.toml b/src/liballoc_system/Cargo.toml index 8e3c2c0b9cc66..f20be5fdf5f2b 100644 --- a/src/liballoc_system/Cargo.toml +++ b/src/liballoc_system/Cargo.toml @@ -12,3 +12,6 @@ doc = false [dependencies] core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } + +[target.'cfg(not(stage0))'.dependencies] +alloc = { path = "../liballoc" } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 1f36bc4fbcea7..afecfc16f2c90 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -11,13 +11,18 @@ #![crate_name = "alloc_system"] #![crate_type = "rlib"] #![no_std] -#![allocator] #![deny(warnings)] #![unstable(feature = "alloc_system", reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] -#![feature(allocator)] +#![cfg_attr(stage0, allocator)] +#![cfg_attr(stage0, feature(allocator))] +#![cfg_attr(stage0, feature(core_intrinsics))] +#![cfg_attr(not(stage0), feature(global_allocator))] +#![cfg_attr(not(stage0), feature(allocator_api))] +#![cfg_attr(not(stage0), feature(alloc))] +#![cfg_attr(not(stage0), feature(core_intrinsics))] #![feature(staged_api)] #![cfg_attr(any(unix, target_os = "redox"), feature(libc))] @@ -39,62 +44,201 @@ const MIN_ALIGN: usize = 8; target_arch = "sparc64")))] const MIN_ALIGN: usize = 16; -#[no_mangle] -pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 { - unsafe { imp::allocate(size, align) } -} +#[cfg(stage0)] +pub use old::*; +#[cfg(stage0)] +mod old; -#[no_mangle] -pub extern "C" fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 { - unsafe { imp::allocate_zeroed(size, align) } -} +#[cfg(not(stage0))] +pub use new::System; +#[cfg(not(stage0))] +mod new { + pub extern crate alloc; -#[no_mangle] -pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { - unsafe { imp::deallocate(ptr, old_size, align) } -} + use self::alloc::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}; -#[no_mangle] -pub extern "C" fn __rust_reallocate(ptr: *mut u8, - old_size: usize, - size: usize, - align: usize) - -> *mut u8 { - unsafe { imp::reallocate(ptr, old_size, size, align) } -} + #[unstable(feature = "allocator_api", issue = "32838")] + pub struct System; -#[no_mangle] -pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8, - old_size: usize, - size: usize, - align: usize) - -> usize { - unsafe { imp::reallocate_inplace(ptr, old_size, size, align) } -} + #[unstable(feature = "allocator_api", issue = "32838")] + unsafe impl Alloc for System { + #[inline] + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + (&*self).alloc(layout) + } + + #[inline] + unsafe fn alloc_zeroed(&mut self, layout: Layout) + -> Result<*mut u8, AllocErr> + { + (&*self).alloc_zeroed(layout) + } + + #[inline] + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + (&*self).dealloc(ptr, layout) + } + + #[inline] + unsafe fn realloc(&mut self, + ptr: *mut u8, + old_layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr> { + (&*self).realloc(ptr, old_layout, new_layout) + } -#[no_mangle] -pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize { - imp::usable_size(size, align) + fn oom(&mut self, err: AllocErr) -> ! { + (&*self).oom(err) + } + + #[inline] + fn usable_size(&self, layout: &Layout) -> (usize, usize) { + (&self).usable_size(layout) + } + + #[inline] + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> { + (&*self).alloc_excess(layout) + } + + #[inline] + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<Excess, AllocErr> { + (&*self).realloc_excess(ptr, layout, new_layout) + } + + #[inline] + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + (&*self).grow_in_place(ptr, layout, new_layout) + } + + #[inline] + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + (&*self).shrink_in_place(ptr, layout, new_layout) + } + } } -#[cfg(any(unix, target_os = "redox"))] -mod imp { +#[cfg(all(not(stage0), any(unix, target_os = "redox")))] +mod platform { extern crate libc; use core::cmp; use core::ptr; + use MIN_ALIGN; + use new::System; + use new::alloc::heap::{Alloc, AllocErr, Layout}; + + #[unstable(feature = "allocator_api", issue = "32838")] + unsafe impl<'a> Alloc for &'a System { + #[inline] + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + let ptr = if layout.align() <= MIN_ALIGN { + libc::malloc(layout.size()) as *mut u8 + } else { + aligned_malloc(&layout) + }; + if !ptr.is_null() { + Ok(ptr) + } else { + Err(AllocErr::Exhausted { request: layout }) + } + } - pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { - if align <= MIN_ALIGN { - libc::malloc(size as libc::size_t) as *mut u8 - } else { - aligned_malloc(size, align) + #[inline] + unsafe fn alloc_zeroed(&mut self, layout: Layout) + -> Result<*mut u8, AllocErr> + { + if layout.align() <= MIN_ALIGN { + let ptr = libc::calloc(layout.size(), 1) as *mut u8; + if !ptr.is_null() { + Ok(ptr) + } else { + Err(AllocErr::Exhausted { request: layout }) + } + } else { + let ret = self.alloc(layout.clone()); + if let Ok(ptr) = ret { + ptr::write_bytes(ptr, 0, layout.size()); + } + ret + } + } + + #[inline] + unsafe fn dealloc(&mut self, ptr: *mut u8, _layout: Layout) { + libc::free(ptr as *mut libc::c_void) + } + + #[inline] + unsafe fn realloc(&mut self, + ptr: *mut u8, + old_layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr> { + if old_layout.align() != new_layout.align() { + return Err(AllocErr::Unsupported { + details: "cannot change alignment on `realloc`", + }) + } + + if new_layout.align() <= MIN_ALIGN { + let ptr = libc::realloc(ptr as *mut libc::c_void, new_layout.size()); + if !ptr.is_null() { + Ok(ptr as *mut u8) + } else { + Err(AllocErr::Exhausted { request: new_layout }) + } + } else { + let res = self.alloc(new_layout.clone()); + if let Ok(new_ptr) = res { + let size = cmp::min(old_layout.size(), new_layout.size()); + ptr::copy_nonoverlapping(ptr, new_ptr, size); + self.dealloc(ptr, old_layout); + } + res + } + } + + fn oom(&mut self, err: AllocErr) -> ! { + use core::fmt::{self, Write}; + + // Print a message to stderr before aborting to assist with + // debugging. It is critical that this code does not allocate any + // memory since we are in an OOM situation. Any errors are ignored + // while printing since there's nothing we can do about them and we + // are about to exit anyways. + drop(writeln!(Stderr, "fatal runtime error: {}", err)); + unsafe { + ::core::intrinsics::abort(); + } + + struct Stderr; + + impl Write for Stderr { + fn write_str(&mut self, s: &str) -> fmt::Result { + unsafe { + libc::write(libc::STDERR_FILENO, + s.as_ptr() as *const libc::c_void, + s.len()); + } + Ok(()) + } + } } } #[cfg(any(target_os = "android", target_os = "redox"))] - unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { // On android we currently target API level 9 which unfortunately // doesn't have the `posix_memalign` API used below. Instead we use // `memalign`, but this unfortunately has the property on some systems @@ -112,74 +256,41 @@ mod imp { // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ // /memory/aligned_memory.cc - libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8 + libc::memalign(layout.align(), layout.size()) as *mut u8 } #[cfg(not(any(target_os = "android", target_os = "redox")))] - unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { let mut out = ptr::null_mut(); - let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t); + let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); if ret != 0 { ptr::null_mut() } else { out as *mut u8 } } - - pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { - if align <= MIN_ALIGN { - libc::calloc(size as libc::size_t, 1) as *mut u8 - } else { - let ptr = aligned_malloc(size, align); - if !ptr.is_null() { - ptr::write_bytes(ptr, 0, size); - } - ptr - } - } - - pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { - if align <= MIN_ALIGN { - libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 - } else { - let new_ptr = allocate(size, align); - if !new_ptr.is_null() { - ptr::copy(ptr, new_ptr, cmp::min(size, old_size)); - deallocate(ptr, old_size, align); - } - new_ptr - } - } - - pub unsafe fn reallocate_inplace(_ptr: *mut u8, - old_size: usize, - _size: usize, - _align: usize) - -> usize { - old_size - } - - pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) { - libc::free(ptr as *mut libc::c_void) - } - - pub fn usable_size(size: usize, _align: usize) -> usize { - size - } } -#[cfg(windows)] +#[cfg(all(windows, not(stage0)))] #[allow(bad_style)] -mod imp { - use core::cmp::min; - use core::ptr::copy_nonoverlapping; +mod platform { + use core::cmp; + use core::ptr; + use MIN_ALIGN; + use new::System; + use new::alloc::heap::{Alloc, AllocErr, Layout, CannotReallocInPlace}; type LPVOID = *mut u8; type HANDLE = LPVOID; type SIZE_T = usize; type DWORD = u32; type BOOL = i32; + type LPDWORD = *mut DWORD; + type LPOVERLAPPED = *mut u8; + + const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; extern "system" { fn GetProcessHeap() -> HANDLE; @@ -187,12 +298,18 @@ mod imp { fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; fn GetLastError() -> DWORD; + fn WriteFile(hFile: HANDLE, + lpBuffer: LPVOID, + nNumberOfBytesToWrite: DWORD, + lpNumberOfBytesWritten: LPDWORD, + lpOverlapped: LPOVERLAPPED) + -> BOOL; + fn GetStdHandle(which: DWORD) -> HANDLE; } #[repr(C)] struct Header(*mut u8); - const HEAP_ZERO_MEMORY: DWORD = 0x00000008; const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010; @@ -207,71 +324,149 @@ mod imp { } #[inline] - unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -> *mut u8 { - if align <= MIN_ALIGN { - HeapAlloc(GetProcessHeap(), flags, size as SIZE_T) as *mut u8 + unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) + -> Result<*mut u8, AllocErr> + { + let ptr = if layout.align() <= MIN_ALIGN { + HeapAlloc(GetProcessHeap(), flags, layout.size()) } else { - let ptr = HeapAlloc(GetProcessHeap(), flags, (size + align) as SIZE_T) as *mut u8; + let size = layout.size() + layout.align(); + let ptr = HeapAlloc(GetProcessHeap(), flags, size); if ptr.is_null() { - return ptr; + ptr + } else { + align_ptr(ptr, layout.align()) } - align_ptr(ptr, align) + }; + if ptr.is_null() { + Err(AllocErr::Exhausted { request: layout }) + } else { + Ok(ptr as *mut u8) } } - pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { - allocate_with_flags(size, align, 0) - } + #[unstable(feature = "allocator_api", issue = "32838")] + unsafe impl<'a> Alloc for &'a System { + #[inline] + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + allocate_with_flags(layout, 0) + } - pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { - allocate_with_flags(size, align, HEAP_ZERO_MEMORY) - } + #[inline] + unsafe fn alloc_zeroed(&mut self, layout: Layout) + -> Result<*mut u8, AllocErr> + { + allocate_with_flags(layout, HEAP_ZERO_MEMORY) + } - pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { - if align <= MIN_ALIGN { - HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8 - } else { - let new = allocate(size, align); - if !new.is_null() { - copy_nonoverlapping(ptr, new, min(size, old_size)); - deallocate(ptr, old_size, align); + #[inline] + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + if layout.align() <= MIN_ALIGN { + let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); + debug_assert!(err != 0, "Failed to free heap memory: {}", + GetLastError()); + } else { + let header = get_header(ptr); + let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); + debug_assert!(err != 0, "Failed to free heap memory: {}", + GetLastError()); } - new } - } - pub unsafe fn reallocate_inplace(ptr: *mut u8, - old_size: usize, - size: usize, - align: usize) - -> usize { - let new = if align <= MIN_ALIGN { - HeapReAlloc(GetProcessHeap(), - HEAP_REALLOC_IN_PLACE_ONLY, - ptr as LPVOID, - size as SIZE_T) as *mut u8 - } else { - let header = get_header(ptr); - HeapReAlloc(GetProcessHeap(), - HEAP_REALLOC_IN_PLACE_ONLY, - header.0 as LPVOID, - size + align as SIZE_T) as *mut u8 - }; - if new.is_null() { old_size } else { size } - } + #[inline] + unsafe fn realloc(&mut self, + ptr: *mut u8, + old_layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr> { + if old_layout.align() != new_layout.align() { + return Err(AllocErr::Unsupported { + details: "cannot change alignment on `realloc`", + }) + } - pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) { - if align <= MIN_ALIGN { - let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); - debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); - } else { - let header = get_header(ptr); - let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); - debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); + if new_layout.align() <= MIN_ALIGN { + let ptr = HeapReAlloc(GetProcessHeap(), + 0, + ptr as LPVOID, + new_layout.size()); + if !ptr.is_null() { + Ok(ptr as *mut u8) + } else { + Err(AllocErr::Exhausted { request: new_layout }) + } + } else { + let res = self.alloc(new_layout.clone()); + if let Ok(new_ptr) = res { + let size = cmp::min(old_layout.size(), new_layout.size()); + ptr::copy_nonoverlapping(ptr, new_ptr, size); + self.dealloc(ptr, old_layout); + } + res + } } - } - pub fn usable_size(size: usize, _align: usize) -> usize { - size + #[inline] + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + self.shrink_in_place(ptr, layout, new_layout) + } + + #[inline] + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + old_layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + if old_layout.align() != new_layout.align() { + return Err(CannotReallocInPlace) + } + + let new = if new_layout.align() <= MIN_ALIGN { + HeapReAlloc(GetProcessHeap(), + HEAP_REALLOC_IN_PLACE_ONLY, + ptr as LPVOID, + new_layout.size()) + } else { + let header = get_header(ptr); + HeapReAlloc(GetProcessHeap(), + HEAP_REALLOC_IN_PLACE_ONLY, + header.0 as LPVOID, + new_layout.size() + new_layout.align()) + }; + if new.is_null() { + Err(CannotReallocInPlace) + } else { + Ok(()) + } + } + + fn oom(&mut self, err: AllocErr) -> ! { + use core::fmt::{self, Write}; + + // Same as with unix we ignore all errors here + drop(writeln!(Stderr, "fatal runtime error: {}", err)); + unsafe { + ::core::intrinsics::abort(); + } + + struct Stderr; + + impl Write for Stderr { + fn write_str(&mut self, s: &str) -> fmt::Result { + unsafe { + // WriteFile silently fails if it is passed an invalid + // handle, so there is no need to check the result of + // GetStdHandle. + WriteFile(GetStdHandle(STD_ERROR_HANDLE), + s.as_ptr() as LPVOID, + s.len() as DWORD, + ptr::null_mut(), + ptr::null_mut()); + } + Ok(()) + } + } + } } } diff --git a/src/liballoc_system/old.rs b/src/liballoc_system/old.rs new file mode 100644 index 0000000000000..80aa46075944c --- /dev/null +++ b/src/liballoc_system/old.rs @@ -0,0 +1,268 @@ +// 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. + +#[no_mangle] +pub unsafe extern fn __rust_alloc(size: usize, + align: usize, + err: *mut u8) -> *mut u8 { + let p = imp::allocate(size, align); + if p.is_null() { + __rust_oom(err); + } + p +} + +#[no_mangle] +pub unsafe extern fn __rust_oom(_err: *const u8) -> ! { + ::core::intrinsics::abort() +} + +#[no_mangle] +pub unsafe extern fn __rust_dealloc(ptr: *mut u8, + size: usize, + align: usize) { + imp::deallocate(ptr, size, align) +} + +#[no_mangle] +pub unsafe extern fn __rust_usable_size(size: usize, + _align: usize, + min: *mut usize, + max: *mut usize) { + *min = size; + *max = size; +} + +#[no_mangle] +pub unsafe extern fn __rust_realloc(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + err: *mut u8) -> *mut u8 { + if new_align != old_align { + __rust_oom(err); + } + let p = imp::reallocate(ptr, old_size, new_size, new_align); + if p.is_null() { + __rust_oom(err); + } + p +} + +#[no_mangle] +pub unsafe extern fn __rust_alloc_zeroed(size: usize, + align: usize, + err: *mut u8) -> *mut u8 { + let p = imp::allocate_zeroed(size, align); + if p.is_null() { + __rust_oom(err); + } + p +} + +#[no_mangle] +pub unsafe extern fn __rust_alloc_excess(_size: usize, + _align: usize, + _excess: *mut usize, + err: *mut u8) -> *mut u8 { + __rust_oom(err); +} + +#[no_mangle] +pub unsafe extern fn __rust_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 { + __rust_oom(err); +} + +#[no_mangle] +pub unsafe extern fn __rust_grow_in_place(_ptr: *mut u8, + _old_size: usize, + _old_align: usize, + _new_size: usize, + _new_align: usize) -> u8 { + 0 +} + +#[no_mangle] +pub unsafe extern fn __rust_shrink_in_place(_ptr: *mut u8, + _old_size: usize, + _old_align: usize, + _new_size: usize, + _new_align: usize) -> u8 { + 0 +} + +#[cfg(any(unix, target_os = "redox"))] +mod imp { + extern crate libc; + + use core::cmp; + use core::ptr; + use MIN_ALIGN; + + pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { + if align <= MIN_ALIGN { + libc::malloc(size as libc::size_t) as *mut u8 + } else { + aligned_malloc(size, align) + } + } + + #[cfg(any(target_os = "android", target_os = "redox"))] + unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 { + // On android we currently target API level 9 which unfortunately + // doesn't have the `posix_memalign` API used below. Instead we use + // `memalign`, but this unfortunately has the property on some systems + // where the memory returned cannot be deallocated by `free`! + // + // Upon closer inspection, however, this appears to work just fine with + // Android, so for this platform we should be fine to call `memalign` + // (which is present in API level 9). Some helpful references could + // possibly be chromium using memalign [1], attempts at documenting that + // memalign + free is ok [2] [3], or the current source of chromium + // which still uses memalign on android [4]. + // + // [1]: https://codereview.chromium.org/10796020/ + // [2]: https://code.google.com/p/android/issues/detail?id=35391 + // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 + // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ + // /memory/aligned_memory.cc + libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8 + } + + #[cfg(not(any(target_os = "android", target_os = "redox")))] + unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 { + let mut out = ptr::null_mut(); + let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t); + if ret != 0 { + ptr::null_mut() + } else { + out as *mut u8 + } + } + + pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { + if align <= MIN_ALIGN { + libc::calloc(size as libc::size_t, 1) as *mut u8 + } else { + let ptr = aligned_malloc(size, align); + if !ptr.is_null() { + ptr::write_bytes(ptr, 0, size); + } + ptr + } + } + + pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { + if align <= MIN_ALIGN { + libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 + } else { + let new_ptr = allocate(size, align); + if !new_ptr.is_null() { + ptr::copy(ptr, new_ptr, cmp::min(size, old_size)); + deallocate(ptr, old_size, align); + } + new_ptr + } + } + + pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) { + libc::free(ptr as *mut libc::c_void) + } +} + +#[cfg(windows)] +#[allow(bad_style)] +mod imp { + use core::cmp::min; + use core::ptr::copy_nonoverlapping; + use MIN_ALIGN; + + type LPVOID = *mut u8; + type HANDLE = LPVOID; + type SIZE_T = usize; + type DWORD = u32; + type BOOL = i32; + + extern "system" { + fn GetProcessHeap() -> HANDLE; + fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; + fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; + fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; + fn GetLastError() -> DWORD; + } + + #[repr(C)] + struct Header(*mut u8); + + + const HEAP_ZERO_MEMORY: DWORD = 0x00000008; + + unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header { + &mut *(ptr as *mut Header).offset(-1) + } + + unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 { + let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize); + *get_header(aligned) = Header(ptr); + aligned + } + + #[inline] + unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -> *mut u8 { + if align <= MIN_ALIGN { + HeapAlloc(GetProcessHeap(), flags, size as SIZE_T) as *mut u8 + } else { + let ptr = HeapAlloc(GetProcessHeap(), flags, (size + align) as SIZE_T) as *mut u8; + if ptr.is_null() { + return ptr; + } + align_ptr(ptr, align) + } + } + + pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { + allocate_with_flags(size, align, 0) + } + + pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { + allocate_with_flags(size, align, HEAP_ZERO_MEMORY) + } + + pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { + if align <= MIN_ALIGN { + HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8 + } else { + let new = allocate(size, align); + if !new.is_null() { + copy_nonoverlapping(ptr, new, min(size, old_size)); + deallocate(ptr, old_size, align); + } + new + } + } + + pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) { + if align <= MIN_ALIGN { + let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); + debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); + } else { + let header = get_header(ptr); + let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); + debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); + } + } +} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index de5d6df328cbd..38143593eb12b 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -23,13 +23,11 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![no_std] -#![needs_allocator] #![deny(warnings)] #![feature(alloc)] #![feature(collections_range)] #![feature(macro_reexport)] -#![feature(needs_allocator)] #![feature(staged_api)] //! Collection types diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins new file mode 160000 index 0000000000000..238647af80647 --- /dev/null +++ b/src/libcompiler_builtins @@ -0,0 +1 @@ +Subproject commit 238647af806470dc73e585c03682083931d29cd5 diff --git a/src/libcompiler_builtins/Cargo.toml b/src/libcompiler_builtins/Cargo.toml deleted file mode 100644 index 2c9cee5e7a093..0000000000000 --- a/src/libcompiler_builtins/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -build = "build.rs" -name = "compiler_builtins" -version = "0.0.0" - -[lib] -name = "compiler_builtins" -path = "lib.rs" -test = false -bench = false -doc = false - -[dependencies] -core = { path = "../libcore" } - -[build-dependencies] -build_helper = { path = "../build_helper" } -gcc = "0.3.50" diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs deleted file mode 100644 index 8fe79057bd817..0000000000000 --- a/src/libcompiler_builtins/build.rs +++ /dev/null @@ -1,423 +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. - -//! Compiles the `compiler-rt` library, or at least the builtins part of it. -//! -//! Note that while compiler-rt has a build system associated with it, we -//! specifically don't use it here. The compiler-rt build system, written in -//! CMake, is actually *very* difficult to work with in terms of getting it to -//! compile on all the relevant platforms we want it to compile on. In the end -//! it became so much pain to work with local patches, work around the oddities -//! of the build system, etc, that we're just building everything by hand now. -//! -//! In general compiler-rt is just a bunch of intrinsics that are in practice -//! *very* stable. We just need to make sure that all the relevant functions and -//! such are compiled somewhere and placed in an object file somewhere. -//! Eventually, these should all be written in Rust! -//! -//! So below you'll find a listing of every single file in the compiler-rt repo -//! that we're compiling. We just reach in and compile with the `gcc` crate -//! which should have all the relevant flags and such already configured. -//! -//! The risk here is that if we update compiler-rt we may need to compile some -//! new intrinsics, but to be honest we surely don't use all of the intrinsics -//! listed below today so the likelihood of us actually needing a new intrinsic -//! is quite low. The failure case is also just that someone reports a link -//! error (if any) and then we just add it to the list. Overall, that cost is -//! far far less than working with compiler-rt's build system over time. - -extern crate build_helper; -extern crate gcc; - -use std::collections::BTreeMap; -use std::env; -use std::path::Path; -use build_helper::native_lib_boilerplate; - -struct Sources { - // SYMBOL -> PATH TO SOURCE - map: BTreeMap<&'static str, &'static str>, -} - -impl Sources { - fn new() -> Sources { - Sources { map: BTreeMap::new() } - } - - fn extend(&mut self, sources: &[&'static str]) { - // NOTE Some intrinsics have both a generic implementation (e.g. - // `floatdidf.c`) and an arch optimized implementation - // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized - // implementation and discard the generic implementation. If we don't - // and keep both implementations, the linker will yell at us about - // duplicate symbols! - for &src in sources { - let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); - if src.contains("/") { - // Arch-optimized implementation (preferred) - self.map.insert(symbol, src); - } else { - // Generic implementation - if !self.map.contains_key(symbol) { - self.map.insert(symbol, src); - } - } - } - } -} - -fn main() { - let target = env::var("TARGET").expect("TARGET was not set"); - - // Emscripten's runtime includes all the builtins - if target.contains("emscripten") { - return; - } - - // Can't reuse `sources` list for the freshness check becuse it doesn't contain header files. - let native = match native_lib_boilerplate("compiler-rt", "compiler-rt", "compiler-rt", ".") { - Ok(native) => native, - _ => return, - }; - - let cfg = &mut gcc::Config::new(); - cfg.out_dir(&native.out_dir); - - if target.contains("msvc") { - // Don't pull in extra libraries on MSVC - cfg.flag("/Zl"); - - // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP - cfg.define("__func__", Some("__FUNCTION__")); - } else { - // Turn off various features of gcc and such, mostly copying - // compiler-rt's build system already - cfg.flag("-fno-builtin"); - cfg.flag("-fvisibility=hidden"); - // Accepted practice on Solaris is to never omit frame pointer so that - // system observability tools work as expected. In addition, at least - // on Solaris, -fomit-frame-pointer on sparcv9 appears to generate - // references to data outside of the current stack frame. A search of - // the gcc bug database provides a variety of issues surrounding - // -fomit-frame-pointer on non-x86 platforms. - if !target.contains("solaris") && !target.contains("sparc") { - cfg.flag("-fomit-frame-pointer"); - } - cfg.flag("-ffreestanding"); - cfg.define("VISIBILITY_HIDDEN", None); - } - - let mut sources = Sources::new(); - sources.extend(&["absvdi2.c", - "absvsi2.c", - "adddf3.c", - "addsf3.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "ashldi3.c", - "ashrdi3.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divdf3.c", - "divdi3.c", - "divmoddi4.c", - "divmodsi4.c", - "divsc3.c", - "divsf3.c", - "divsi3.c", - "divxc3.c", - "extendsfdf2.c", - "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", - "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", - "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", - "int_util.c", - "lshrdi3.c", - "moddi3.c", - "modsi3.c", - "muldc3.c", - "muldf3.c", - "muldi3.c", - "mulodi4.c", - "mulosi4.c", - "muloti4.c", - "mulsc3.c", - "mulsf3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powidf2.c", - "powisf2.c", - "powixf2.c", - "subdf3.c", - "subsf3.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c", - "udivdi3.c", - "udivmoddi4.c", - "udivmodsi4.c", - "udivsi3.c", - "umoddi3.c", - "umodsi3.c"]); - - if !target.contains("ios") { - sources.extend(&["absvti2.c", - "addvti3.c", - "ashlti3.c", - "ashrti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "divti3.c", - "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", - "lshrti3.c", - "modti3.c", - "multi3.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "subvti3.c", - "ucmpti2.c", - "udivmodti4.c", - "udivti3.c", - "umodti3.c"]); - } - - if target.contains("apple") { - sources.extend(&["atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c"]); - } - - if target.contains("msvc") { - if target.contains("x86_64") { - sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); - } - } else { - if !target.contains("freebsd") && !target.contains("netbsd") { - sources.extend(&["gcc_personality_v0.c"]); - } - - if target.contains("x86_64") { - sources.extend(&["x86_64/chkstk.S", - "x86_64/chkstk2.S", - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S"]); - } - - if target.contains("i386") || target.contains("i586") || target.contains("i686") { - sources.extend(&["i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S"]); - } - } - - if target.contains("arm") && !target.contains("ios") { - // (At least) udivsi3.S is broken for Thumb 1 which our gcc uses by - // default, we don't want Thumb 2 since it isn't supported on some - // devices, so disable thumb entirely. - // Upstream bug: https://bugs.llvm.org/show_bug.cgi?id=32492 - cfg.define("__ARM_ARCH_ISA_THUMB", Some("0")); - - sources.extend(&["arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - "arm/aeabi_dcmp.S", - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", - "arm/aeabi_frsub.c", - "arm/aeabi_idivmod.S", - "arm/aeabi_ldivmod.S", - "arm/aeabi_memcmp.S", - "arm/aeabi_memcpy.S", - "arm/aeabi_memmove.S", - "arm/aeabi_memset.S", - "arm/aeabi_uidivmod.S", - "arm/aeabi_uldivmod.S", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/comparesf2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S"]); - } - - if target.contains("armv7") { - sources.extend(&["arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S"]); - } - - if target.contains("eabihf") { - sources.extend(&["arm/adddf3vfp.S", - "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", - "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", - "arm/negdf2vfp.S", - "arm/negsf2vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S", - "arm/truncdfsf2vfp.S", - "arm/unorddf2vfp.S", - "arm/unordsf2vfp.S"]); - } - - if target.contains("aarch64") { - sources.extend(&["comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "multc3.c", - "trunctfdf2.c", - "trunctfsf2.c"]); - } - - for src in sources.map.values() { - cfg.file(Path::new("../compiler-rt/lib/builtins").join(src)); - } - - cfg.compile("libcompiler-rt.a"); -} diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs deleted file mode 100644 index 09b3d63950705..0000000000000 --- a/src/libcompiler_builtins/lib.rs +++ /dev/null @@ -1,721 +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(compiler_builtins)] -#![no_std] -#![compiler_builtins] -#![unstable(feature = "compiler_builtins_lib", - reason = "internal implementation detail of rustc right now", - issue = "0")] -#![crate_name = "compiler_builtins"] -#![crate_type = "rlib"] -#![allow(unused_features)] -#![feature(staged_api, core_intrinsics, repr_simd, - i128_type, core_float, abi_unadjusted, associated_consts)] -#![allow(non_camel_case_types, unused_variables, unused_imports)] - -#[cfg(any(target_pointer_width="32", target_pointer_width="16", target_os="windows", - target_arch="mips64"))] -pub mod reimpls { - - #![allow(unused_comparisons)] - - use core::intrinsics::unchecked_div; - use core::intrinsics::unchecked_rem; - use core::ptr; - - macro_rules! ashl { - ($a:expr, $b:expr, $ty:ty) => {{ - let (a, b) = ($a, $b); - let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty; - let half_bits = bits.wrapping_shr(1); - if b & half_bits != 0 { - <$ty>::from_parts(0, a.low().wrapping_shl( - b.wrapping_sub(half_bits) as u32)) - } else if b == 0 { - a - } else { - <$ty>::from_parts(a.low().wrapping_shl(b as u32), - a.high().wrapping_shl(b as u32) - | a.low() - .wrapping_shr(half_bits.wrapping_sub(b) as u32)) - } - }} - } - - #[export_name="__ashlti3"] - pub extern "C" fn shl(a: u128, b: u128) -> u128 { - ashl!(a, b, u128) - } - - macro_rules! ashr { - ($a: expr, $b: expr, $ty:ty) => {{ - let (a, b) = ($a, $b); - let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty; - let half_bits = bits.wrapping_shr(1); - if b & half_bits != 0 { - <$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32) - as <$ty as LargeInt>::LowHalf, - a.high().wrapping_shr(half_bits.wrapping_sub(1) as u32)) - } else if b == 0 { - a - } else { - let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; - <$ty>::from_parts(high_unsigned.wrapping_shl(half_bits.wrapping_sub(b) as u32) - | a.low().wrapping_shr(b as u32), - a.high().wrapping_shr(b as u32)) - } - }} - } - - #[export_name="__ashrti3"] - pub extern "C" fn shr(a: i128, b: i128) -> i128 { - ashr!(a, b, i128) - } - - macro_rules! lshr { - ($a: expr, $b: expr, $ty:ty) => {{ - let (a, b) = ($a, $b); - let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty; - let half_bits = bits.wrapping_shr(1); - if b & half_bits != 0 { - <$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32), 0) - } else if b == 0 { - a - } else { - <$ty>::from_parts(a.high().wrapping_shl(half_bits.wrapping_sub(b) as u32) - | a.low().wrapping_shr(b as u32), - a.high().wrapping_shr(b as u32)) - } - }} - } - - - #[export_name="__lshrti3"] - pub extern "C" fn lshr(a: u128, b: u128) -> u128 { - lshr!(a, b, u128) - } - - pub extern "C" fn u128_div_mod(n: u128, d: u128, rem: *mut u128) -> u128 { - // Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide - unsafe { - // special cases, X is unknown, K != 0 - if n.high() == 0 { - if d.high() == 0 { - // 0 X - // --- - // 0 X - if !rem.is_null() { - *rem = u128::from(unchecked_rem(n.low(), d.low())); - } - return u128::from(unchecked_div(n.low(), d.low())); - } else { - // 0 X - // --- - // K X - if !rem.is_null() { - *rem = n; - } - return 0; - }; - } - - let mut sr; - let mut q; - let mut r; - - if d.low() == 0 { - if d.high() == 0 { - // K X - // --- - // 0 0 - if !rem.is_null() { - *rem = u128::from(unchecked_rem(n.high(), d.low())); - } - return u128::from(unchecked_div(n.high(), d.low())); - } - - if n.low() == 0 { - // K 0 - // --- - // K 0 - if !rem.is_null() { - *rem = u128::from_parts(0, unchecked_rem(n.high(), d.high())); - } - return u128::from(unchecked_div(n.high(), d.high())); - } - - // K K - // --- - // K 0 - - if d.high().is_power_of_two() { - if !rem.is_null() { - *rem = u128::from_parts(n.low(), - n.high() & (d.high().wrapping_sub(1))); - } - return u128::from(n.high().wrapping_shr(d.high().trailing_zeros())); - } - - // K K - // --- - // K 0 - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > 64 - 2 { - if !rem.is_null() { - *rem = n; - } - return 0; - } - - sr = sr.wrapping_add(1); - - // 1 <= sr <= u64::bits() - 1 - q = n.wrapping_shl(128u32.wrapping_sub(sr)); - r = n.wrapping_shr(sr); - } else { - if d.high() == 0 { - // K X - // --- - // 0 K - if d.low().is_power_of_two() { - if !rem.is_null() { - *rem = u128::from(n.low() & (d.low().wrapping_sub(1))); - } - - if d.low() == 1 { - return n; - } else { - let sr = d.low().trailing_zeros(); - return n.wrapping_shr(sr); - }; - } - - sr = (1 + 64u32) - .wrapping_add(d.low().leading_zeros()) - .wrapping_sub(n.high().leading_zeros()); - - // 2 <= sr <= u64::bits() - 1 - q = n.wrapping_shl(128u32.wrapping_sub(sr)); - r = n.wrapping_shr(sr); - // FIXME the C compiler-rt implementation has something here - // that looks like a speed optimisation. - // It would be worth a try to port it to Rust too and - // compare the speed. - } else { - // K X - // --- - // K K - sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); - - // D > N - if sr > 64 - 1 { - if !rem.is_null() { - *rem = n; - } - return 0; - } - - sr = sr.wrapping_add(1); - - // 1 <= sr <= u32::bits() - q = n.wrapping_shl(128u32.wrapping_sub(sr)); - r = n.wrapping_shr(sr); - } - } - - // Not a special case - // q and r are initialized with - // q = n << (u64::bits() - sr) - // r = n >> sr - // 1 <= sr <= u64::bits() - 1 - let mut carry = 0; - - // FIXME: replace this with a for loop - // (atm not doable as this generates call to - // eh_personality when optimisations are turned off, - // which in turn gives a linker error in later - // compilation steps) - while sr > 0 { - // r:q = ((r:q) << 1) | carry - r = r.wrapping_shl(1) | q.wrapping_shr(128 - 1); - q = q.wrapping_shl(1) | carry as u128; - - // carry = 0 - // if r >= d { - // r -= d; - // carry = 1; - // } - let s = ((d.wrapping_sub(r).wrapping_sub(1)) as i128).wrapping_shr(128 - 1); - carry = (s & 1) as u64; - r = r.wrapping_sub(d & s as u128); - sr = sr.wrapping_sub(1); - } - - if !rem.is_null() { - *rem = r; - } - (q.wrapping_shl(1)) | carry as u128 - } - } - - fn i128_mod(a: i128, b: i128) -> i128 { - let b = b.uabs(); - let sa = a.signum(); - let a = a.uabs(); - unsafe { - let mut r = ::core::mem::zeroed(); - u128_div_mod(a, b, &mut r); - if sa == -1 { (r as i128).unchecked_neg() } else { r as i128 } - } - } - - fn i128_div(a: i128, b: i128) -> i128 { - let sa = a.signum(); - let sb = b.signum(); - let a = a.uabs(); - let b = b.uabs(); - let sr = sa.wrapping_mul(sb); // sign of quotient - (if sr == -1 { - (u128_div_mod(a, b, ptr::null_mut()) as i128).unchecked_neg() - } else { - u128_div_mod(a, b, ptr::null_mut()) as i128 - }) - } - - macro_rules! mulo { - ($a:expr, $b:expr, $o: expr, $ty: ty) => {{ - let (a, b, overflow) = ($a, $b, $o); - *overflow = 0; - let result = a.wrapping_mul(b); - if a == <$ty>::min_value() { - if b != 0 && b != 1 { - *overflow = 1; - } - return result; - } - if b == <$ty>::min_value() { - if a != 0 && a != 1 { - *overflow = 1; - } - return result; - } - - let sa = a.signum(); - let abs_a = a.iabs(); - let sb = b.signum(); - let abs_b = b.iabs(); - if abs_a < 2 || abs_b < 2 { - return result; - } - if sa == sb { - if abs_a > unchecked_div(<$ty>::max_value(), abs_b) { - *overflow = 1; - } - } else { - if abs_a > unchecked_div(<$ty>::min_value(), abs_b.unchecked_neg()) { - *overflow = 1; - } - } - result - }} - } - - pub trait LargeInt { - type LowHalf; - type HighHalf; - - fn low(self) -> Self::LowHalf; - fn high(self) -> Self::HighHalf; - fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; - } - impl LargeInt for u128 { - type LowHalf = u64; - type HighHalf = u64; - - fn low(self) -> u64 { - self as u64 - } - fn high(self) -> u64 { - self.wrapping_shr(64) as u64 - } - fn from_parts(low: u64, high: u64) -> u128 { - (high as u128).wrapping_shl(64) | low as u128 - } - } - impl LargeInt for i128 { - type LowHalf = u64; - type HighHalf = i64; - - fn low(self) -> u64 { - self as u64 - } - fn high(self) -> i64 { - self.wrapping_shr(64) as i64 - } - fn from_parts(low: u64, high: i64) -> i128 { - u128::from_parts(low, high as u64) as i128 - } - } - - macro_rules! mul { - ($a:expr, $b:expr, $ty: ty, $tyh: ty) => {{ - let (a, b) = ($a, $b); - let half_bits = ::core::mem::size_of::<$tyh>().wrapping_mul(4) as u32; - let lower_mask = (!0u64).wrapping_shr(half_bits); - let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask); - let mut t = low.wrapping_shr(half_bits); - low &= lower_mask; - t = t.wrapping_add(a.low().wrapping_shr(half_bits) - .wrapping_mul(b.low() & lower_mask)); - low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits)); - let mut high = t.wrapping_shr(half_bits) as $tyh; - t = low.wrapping_shr(half_bits); - low &= lower_mask; - t = t.wrapping_add(b.low().wrapping_shr(half_bits) - .wrapping_mul(a.low() & lower_mask)); - low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits)); - high = high.wrapping_add(t.wrapping_shr(half_bits) as $tyh); - high = high.wrapping_add(a.low().wrapping_shr(half_bits) - .wrapping_mul(b.low().wrapping_shr(half_bits)) as $tyh); - high = high - .wrapping_add(a.high() - .wrapping_mul(b.low() as $tyh)) - .wrapping_add((a.low() as $tyh) - .wrapping_mul(b.high())); - <$ty>::from_parts(low, high) - }} - } - - #[export_name="__multi3"] - pub extern "C" fn u128_mul(a: i128, b: i128) -> i128 { - mul!(a, b, i128, i64) - } - - trait AbsExt: Sized { - fn uabs(self) -> u128; - fn iabs(self) -> i128; - } - - impl AbsExt for i128 { - fn uabs(self) -> u128 { - self.iabs() as u128 - } - fn iabs(self) -> i128 { - let s = self.wrapping_shr(127); - ((self ^ s).wrapping_sub(s)) - } - } - - trait NegExt: Sized { - fn unchecked_neg(self) -> i128; - } - - impl NegExt for i128 { - fn unchecked_neg(self) -> i128 { - (!self).wrapping_add(1) - } - } - - trait FloatStuff: Sized { - type ToBytes; - - const MANTISSA_BITS: u32; - const MAX_EXP: i32; - const EXP_MASK: Self::ToBytes; - const MANTISSA_MASK: Self::ToBytes; - const MANTISSA_LEAD_BIT: Self::ToBytes; - - fn to_bytes(self) -> Self::ToBytes; - fn get_exponent(self) -> i32; - } - - impl FloatStuff for f32 { - type ToBytes = u32; - const MANTISSA_BITS: u32 = 23; - const MAX_EXP: i32 = 127; - const EXP_MASK: u32 = 0x7F80_0000; - const MANTISSA_MASK: u32 = 0x007F_FFFF; - const MANTISSA_LEAD_BIT: u32 = 0x0080_0000; - - fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } } - fn get_exponent(self) -> i32 { - ((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32) - .wrapping_sub(Self::MAX_EXP) - } - } - - impl FloatStuff for f64 { - type ToBytes = u64; - const MANTISSA_BITS: u32 = 52; - const MAX_EXP: i32 = 1023; - const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; - const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; - const MANTISSA_LEAD_BIT: u64 = 0x0010_0000_0000_0000; - - fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } } - fn get_exponent(self) -> i32 { - ((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32) - .wrapping_sub(Self::MAX_EXP) - } - } - - macro_rules! float_as_unsigned { - ($from: expr, $fromty: ty, $outty: ty) => { { - use core::num::Float; - let repr = $from.to_bytes(); - let sign = $from.signum(); - let exponent = $from.get_exponent(); - let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; - let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; - if sign == -1.0 || exponent < 0 { return 0 as u128; } - if exponent > ::core::mem::size_of::<$outty>().wrapping_mul(8) as i32 { - return !(0 as u128); - } - (if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { - (mantissa as $outty) - .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32) - .wrapping_sub(exponent) as u32) - } else { - (mantissa as $outty) - .wrapping_shl(exponent.wrapping_sub( - <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) - }) - } } - } - - macro_rules! float_as_signed { - ($from: expr, $fromty: ty, $outty: ty) => {{ - use core::num::Float; - let repr = $from.to_bytes(); - let sign = $from.signum(); - let exponent = $from.get_exponent(); - let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; - let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; - - if exponent < 0 { return 0 as i128; } - if exponent > ::core::mem::size_of::<$outty>().wrapping_mul(8) as i32 { - let ret = if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }; - return ret - } - let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { - (mantissa as $outty) - .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32) - .wrapping_sub(exponent) as u32) - } else { - (mantissa as $outty) - .wrapping_shl(exponent.wrapping_sub( - <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) - }; - (if sign >= 0.0 { r } else { r.unchecked_neg() }) - }} - } - - - fn i128_as_f64(a: i128) -> f64 { - match a.signum() { - 1 => u128_as_f64(a.uabs()), - 0 => 0.0, - _ => -u128_as_f64(a.uabs()), - } - } - - fn i128_as_f32(a: i128) -> f32 { - match a.signum() { - 1 => u128_as_f32(a.uabs()), - 0 => 0.0, - _ => -u128_as_f32(a.uabs()), - } - } - - fn u128_as_f64(mut a: u128) -> f64 { - use ::core::f64::MANTISSA_DIGITS; - if a == 0 { return 0.0; } - let sd = 128u32.wrapping_sub(a.leading_zeros()); - let mut e = sd.wrapping_sub(1); - const MD1 : u32 = MANTISSA_DIGITS + 1; - const MD2 : u32 = MANTISSA_DIGITS + 2; - - let negn = !0u128; - - if sd > MANTISSA_DIGITS { - a = match sd { - MD1 => a.wrapping_shl(1), - MD2 => a, - _ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) | - (if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2) - .wrapping_sub(sd as u128))) == 0 { 0 } else { 1 }) - }; - a |= if (a & 4) == 0 { 0 } else { 1 }; - a = a.wrapping_add(1); - a = a.wrapping_shr(2); - if a & (1 << MANTISSA_DIGITS) != 0 { - a = a.wrapping_shr(1); - e = e.wrapping_add(1); - } - } else { - a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd)); - } - unsafe { - ::core::mem::transmute((e as u64).wrapping_add(1023).wrapping_shl(52) - | (a as u64 & 0x000f_ffff_ffff_ffff)) - } - } - - fn u128_as_f32(mut a: u128) -> f32 { - use ::core::f32::MANTISSA_DIGITS; - if a == 0 { return 0.0; } - let sd = 128u32.wrapping_sub(a.leading_zeros()); - let mut e = sd.wrapping_sub(1); - const MD1 : u32 = MANTISSA_DIGITS + 1; - const MD2 : u32 = MANTISSA_DIGITS + 2; - - let negn = !0u128; - - if sd > MANTISSA_DIGITS { - a = match sd { - MD1 => a.wrapping_shl(1), - MD2 => a, - _ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) | - (if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2) - .wrapping_sub(sd as u128))) == 0 { 0 } else { 1 }) - }; - a |= if (a & 4) == 0 { 0 } else { 1 }; - a = a.wrapping_add(1); - a = a.wrapping_shr(2); - if a & (1 << MANTISSA_DIGITS) != 0 { - a = a.wrapping_shr(1); - e = e.wrapping_add(1); - } - } else { - a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd)); - } - unsafe { - ::core::mem::transmute((e as u32).wrapping_add(127).wrapping_shl(23) - | (a as u32 & 0x007f_ffff)) - } - } - - - macro_rules! why_are_abi_strings_checked_by_parser { ($cret:ty, $conv:expr, $unadj:tt) => { - mod imp { - use super::{LargeInt, FloatStuff, NegExt, AbsExt}; - use super::{i128_as_f64, i128_as_f32, u128_as_f64, u128_as_f32, - i128_div, i128_mod, u128_div_mod, unchecked_div, ptr}; - // For x64 - // rdx:rcx, r9:r8, stack -> rdx:rax - // aka. - // define i128 @__muloti4(i128, i128, i32*) - #[export_name="__muloti4"] - pub unsafe extern $unadj fn i128_mul_oflow(a: i128, b: i128, o: *mut i32) -> i128 { - mulo!(a, b, o, i128) - } - - // For x64 - // rdx:rax -> xmm0 - // aka. - // define double @__muloti4(i128) - #[export_name="__floattidf"] - pub extern $unadj fn i128_as_f64_(a: i128) -> f64 { - i128_as_f64(a) - } - #[export_name="__floattisf"] - pub extern $unadj fn i128_as_f32_(a: i128) -> f32 { - i128_as_f32(a) - } - #[export_name="__floatuntidf"] - pub extern $unadj fn u128_as_f64_(a: u128) -> f64 { - u128_as_f64(a) - } - #[export_name="__floatuntisf"] - pub extern $unadj fn u128_as_f32_(a: u128) -> f32 { - u128_as_f32(a) - } - - // For x64 - // xmm0 -> rdx:rax - // aka. - // define i128 @stuff(double) - #[export_name="__fixunsdfti"] - pub extern $unadj fn f64_as_u128(a: f64) -> u128 { - float_as_unsigned!(a, f64, u128) - } - - #[export_name="__fixunssfti"] - pub extern $unadj fn f32_as_u128(a: f32) -> u128 { - float_as_unsigned!(a, f32, u128) - } - - #[export_name="__fixdfti"] - pub extern $unadj fn f64_as_i128(a: f64) -> i128 { - float_as_signed!(a, f64, i128) - } - - #[export_name="__fixsfti"] - pub extern $unadj fn f32_as_i128(a: f32) -> i128 { - float_as_signed!(a, f32, i128) - } - - #[repr(simd)] - pub struct u64x2(u64, u64); - - // For x64 - // pointers -> xmm0 - // aka. - // define <2 x u64> @stuff(i128*, i128*, i128*) - // - // That almost matches the C ABI, so we simply use the C ABI - #[export_name="__udivmodti4"] - pub extern "C" fn u128_div_mod_(n: u128, d: u128, rem: *mut u128) -> $cret { - let x = u128_div_mod(n, d, rem); - ($conv)(x) - } - - #[export_name="__udivti3"] - pub extern "C" fn u128_div_(a: u128, b: u128) -> $cret { - let x = u128_div_mod(a, b, ptr::null_mut()); - ($conv)(x) - } - - #[export_name="__umodti3"] - pub extern "C" fn u128_mod_(a: u128, b: u128) -> $cret { - unsafe { - let mut r = ::core::mem::zeroed(); - u128_div_mod(a, b, &mut r); - ($conv)(r) - } - } - - #[export_name="__divti3"] - pub extern "C" fn i128_div_(a: i128, b: i128) -> $cret { - let x = i128_div(a, b); - ($conv)(x as u128) - } - - #[export_name="__modti3"] - pub extern "C" fn i128_mod_(a: i128, b: i128) -> $cret { - let x = i128_mod(a, b); - ($conv)(x as u128) - } - } - } } - - // LLVM expectations for ABI on windows x64 are pure madness. - #[cfg(all(windows, target_pointer_width="64"))] - why_are_abi_strings_checked_by_parser!(u64x2, - |i: u128| u64x2(i.low(), i.high()), - "unadjusted"); - - #[cfg(not(all(windows, target_pointer_width="64")))] - why_are_abi_strings_checked_by_parser!(u128, |i|{ i }, "C"); - pub use self::imp::*; -} diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 7882a8ce5c8ec..f133bd93c9178 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -343,7 +343,7 @@ impl Ordering { /// ``` #[derive(PartialEq, Eq, Debug)] #[stable(feature = "reverse_cmp_key", since = "1.19.0")] -pub struct Reverse<T>(pub T); +pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T); #[stable(feature = "reverse_cmp_key", since = "1.19.0")] impl<T: PartialOrd> PartialOrd for Reverse<T> { diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index 102e3c0bd7b95..322df6e5b47c6 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -49,9 +49,37 @@ impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> { } } -/// A struct to help with `fmt::Debug` implementations. +/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations. /// -/// Constructed by the `Formatter::debug_struct` method. +/// This is useful when you wish to output a formatted struct as a part of your +/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation. +/// +/// This can be constructed by the +/// [`Formatter::debug_struct`](struct.Formatter.html#method.debug_struct) +/// method. +/// +/// # Example +/// +/// ``` +/// use std::fmt; +/// +/// struct Foo { +/// bar: i32, +/// baz: String, +/// } +/// +/// impl fmt::Debug for Foo { +/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { +/// fmt.debug_struct("Foo") +/// .field("bar", &self.bar) +/// .field("baz", &self.baz) +/// .finish() +/// } +/// } +/// +/// // prints "Foo { bar: 10, baz: "Hello World" }" +/// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); +/// ``` #[must_use] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] @@ -116,9 +144,34 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { } } -/// A struct to help with `fmt::Debug` implementations. +/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations. +/// +/// This is useful when you wish to output a formatted tuple as a part of your +/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation. +/// +/// This can be constructed by the +/// [`Formatter::debug_tuple`](struct.Formatter.html#method.debug_tuple) +/// method. /// -/// Constructed by the `Formatter::debug_tuple` method. +/// # Example +/// +/// ``` +/// use std::fmt; +/// +/// struct Foo(i32, String); +/// +/// impl fmt::Debug for Foo { +/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { +/// fmt.debug_tuple("Foo") +/// .field(&self.0) +/// .field(&self.1) +/// .finish() +/// } +/// } +/// +/// // prints "Foo(10, "Hello World")" +/// println!("{:?}", Foo(10, "Hello World".to_string())); +/// ``` #[must_use] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] @@ -228,9 +281,31 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> { } } -/// A struct to help with `fmt::Debug` implementations. +/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations. +/// +/// This is useful when you wish to output a formatted set of items as a part +/// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation. +/// +/// This can be constructed by the +/// [`Formatter::debug_set`](struct.Formatter.html#method.debug_set) +/// method. +/// +/// # Example /// -/// Constructed by the `Formatter::debug_set` method. +/// ``` +/// use std::fmt; +/// +/// struct Foo(Vec<i32>); +/// +/// impl fmt::Debug for Foo { +/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { +/// fmt.debug_set().entries(self.0.iter()).finish() +/// } +/// } +/// +/// // prints "{10, 11}" +/// println!("{:?}", Foo(vec![10, 11])); +/// ``` #[must_use] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] @@ -277,9 +352,31 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { } } -/// A struct to help with `fmt::Debug` implementations. +/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations. +/// +/// This is useful when you wish to output a formatted list of items as a part +/// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation. +/// +/// This can be constructed by the +/// [`Formatter::debug_list`](struct.Formatter.html#method.debug_list) +/// method. +/// +/// # Example +/// +/// ``` +/// use std::fmt; +/// +/// struct Foo(Vec<i32>); /// -/// Constructed by the `Formatter::debug_list` method. +/// impl fmt::Debug for Foo { +/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { +/// fmt.debug_list().entries(self.0.iter()).finish() +/// } +/// } +/// +/// // prints "[10, 11]" +/// println!("{:?}", Foo(vec![10, 11])); +/// ``` #[must_use] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] @@ -326,9 +423,31 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { } } -/// A struct to help with `fmt::Debug` implementations. +/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations. +/// +/// This is useful when you wish to output a formatted map as a part of your +/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation. +/// +/// This can be constructed by the +/// [`Formatter::debug_map`](struct.Formatter.html#method.debug_map) +/// method. +/// +/// # Example +/// +/// ``` +/// use std::fmt; +/// +/// struct Foo(Vec<(String, i32)>); +/// +/// impl fmt::Debug for Foo { +/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { +/// fmt.debug_map().entries(self.0.iter().map(|&(ref k, ref v)| (k, v))).finish() +/// } +/// } /// -/// Constructed by the `Formatter::debug_map` method. +/// // prints "{"A": 10, "B": 11}" +/// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])); +/// ``` #[must_use] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index d6a9be4437d43..decd718d65e15 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -314,12 +314,6 @@ pub use self::iterator::Iterator; reason = "likely to be replaced by finer-grained traits", issue = "42168")] pub use self::range::Step; -#[unstable(feature = "step_by", reason = "recent addition", - issue = "27741")] -#[rustc_deprecated(since = "1.19.0", - reason = "replaced by `iter::StepBy`")] -#[allow(deprecated)] -pub use self::range::StepBy as DeprecatedStepBy; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 9aea4477fb7fc..1dad815794895 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -244,219 +244,6 @@ step_impl_signed!(i64); step_impl_no_between!(u64 i64); step_impl_no_between!(u128 i128); -/// An adapter for stepping range iterators by a custom amount. -/// -/// The resulting iterator handles overflow by stopping. The `A` -/// parameter is the type being iterated over, while `R` is the range -/// type (usually one of `std::ops::{Range, RangeFrom, RangeInclusive}`. -#[derive(Clone, Debug)] -#[unstable(feature = "step_by", reason = "recent addition", - issue = "27741")] -#[rustc_deprecated(since = "1.19.0", - reason = "replaced by `iter::StepBy`")] -#[allow(deprecated)] -pub struct StepBy<A, R> { - step_by: A, - range: R, -} - -impl<A: Step> ops::RangeFrom<A> { - /// Creates an iterator starting at the same point, but stepping by - /// the given amount at each iteration. - /// - /// # Examples - /// - /// ``` - /// #![feature(step_by)] - /// fn main() { - /// let result: Vec<_> = (0..).step_by(2).take(5).collect(); - /// assert_eq!(result, vec![0, 2, 4, 6, 8]); - /// } - /// ``` - #[unstable(feature = "step_by", reason = "recent addition", - issue = "27741")] - #[rustc_deprecated(since = "1.19.0", - reason = "replaced by `Iterator::step_by`")] - #[allow(deprecated)] - pub fn step_by(self, by: A) -> StepBy<A, Self> { - StepBy { - step_by: by, - range: self - } - } -} - -impl<A: Step> ops::Range<A> { - /// Creates an iterator with the same range, but stepping by the - /// given amount at each iteration. - /// - /// The resulting iterator handles overflow by stopping. - /// - /// # Examples - /// - /// ``` - /// #![feature(step_by)] - /// fn main() { - /// let result: Vec<_> = (0..10).step_by(2).collect(); - /// assert_eq!(result, vec![0, 2, 4, 6, 8]); - /// } - /// ``` - #[unstable(feature = "step_by", reason = "recent addition", - issue = "27741")] - #[rustc_deprecated(since = "1.19.0", - reason = "replaced by `Iterator::step_by`")] - #[allow(deprecated)] - pub fn step_by(self, by: A) -> StepBy<A, Self> { - StepBy { - step_by: by, - range: self - } - } -} - -impl<A: Step> ops::RangeInclusive<A> { - /// Creates an iterator with the same range, but stepping by the - /// given amount at each iteration. - /// - /// The resulting iterator handles overflow by stopping. - /// - /// # Examples - /// - /// ``` - /// #![feature(step_by, inclusive_range_syntax)] - /// - /// let result: Vec<_> = (0...10).step_by(2).collect(); - /// assert_eq!(result, vec![0, 2, 4, 6, 8, 10]); - /// ``` - #[unstable(feature = "step_by", reason = "recent addition", - issue = "27741")] - #[rustc_deprecated(since = "1.19.0", - reason = "replaced by `Iterator::step_by`")] - #[allow(deprecated)] - pub fn step_by(self, by: A) -> StepBy<A, Self> { - StepBy { - step_by: by, - range: self - } - } -} - -#[unstable(feature = "step_by", reason = "recent addition", - issue = "27741")] -#[allow(deprecated)] -impl<A> Iterator for StepBy<A, ops::RangeFrom<A>> where - A: Clone, - for<'a> &'a A: Add<&'a A, Output = A> -{ - type Item = A; - - #[inline] - fn next(&mut self) -> Option<A> { - let mut n = &self.range.start + &self.step_by; - mem::swap(&mut n, &mut self.range.start); - Some(n) - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - (usize::MAX, None) // Too bad we can't specify an infinite lower bound - } -} - -#[unstable(feature = "fused", issue = "35602")] -#[allow(deprecated)] -impl<A> FusedIterator for StepBy<A, ops::RangeFrom<A>> - where A: Clone, for<'a> &'a A: Add<&'a A, Output = A> {} - -#[unstable(feature = "step_by", reason = "recent addition", - issue = "27741")] -#[allow(deprecated)] -impl<A: Step + Clone> Iterator for StepBy<A, ops::Range<A>> { - type Item = A; - - #[inline] - fn next(&mut self) -> Option<A> { - let rev = self.step_by.is_negative(); - if (rev && self.range.start > self.range.end) || - (!rev && self.range.start < self.range.end) - { - match self.range.start.step(&self.step_by) { - Some(mut n) => { - mem::swap(&mut self.range.start, &mut n); - Some(n) - }, - None => { - let mut n = self.range.end.clone(); - mem::swap(&mut self.range.start, &mut n); - Some(n) - } - } - } else { - None - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - match Step::steps_between(&self.range.start, - &self.range.end, - &self.step_by) { - Some(hint) => (hint, Some(hint)), - None => (0, None) - } - } -} - -#[unstable(feature = "fused", issue = "35602")] -#[allow(deprecated)] -impl<A: Step + Clone> FusedIterator for StepBy<A, ops::Range<A>> {} - -#[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] -#[allow(deprecated)] -impl<A: Step + Clone> Iterator for StepBy<A, ops::RangeInclusive<A>> { - type Item = A; - - #[inline] - fn next(&mut self) -> Option<A> { - let rev = self.step_by.is_negative(); - - if (rev && self.range.start >= self.range.end) || - (!rev && self.range.start <= self.range.end) - { - match self.range.start.step(&self.step_by) { - Some(n) => { - Some(mem::replace(&mut self.range.start, n)) - }, - None => { - let last = self.range.start.replace_one(); - self.range.end.replace_zero(); - self.step_by.replace_one(); - Some(last) - }, - } - } - else { - None - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - match Step::steps_between(&self.range.start, - &self.range.end, - &self.step_by) { - Some(hint) => (hint.saturating_add(1), hint.checked_add(1)), - None => (0, None) - } - } -} - -#[unstable(feature = "fused", issue = "35602")] -#[allow(deprecated)] -impl<A: Step + Clone> FusedIterator for StepBy<A, ops::RangeInclusive<A>> {} - macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 4f9951cd15399..14f0260f57129 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -12,15 +12,6 @@ use core::iter::*; use core::{i8, i16, isize}; use core::usize; -// FIXME #27741: This is here to simplify calling Iterator::step_by. Remove -// once Range::step_by is completely gone (not just deprecated). -trait IterEx: Sized { - fn iter_step_by(self, n: usize) -> StepBy<Self>; -} -impl<I:Iterator> IterEx for I { - fn iter_step_by(self, n: usize) -> StepBy<Self> { self.step_by(n) } -} - #[test] fn test_lt() { let empty: [isize; 0] = []; @@ -76,7 +67,7 @@ fn test_multi_iter() { #[test] fn test_counter_from_iter() { - let it = (0..).iter_step_by(5).take(10); + let it = (0..).step_by(5).take(10); let xs: Vec<isize> = FromIterator::from_iter(it); assert_eq!(xs, [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]); } @@ -94,7 +85,7 @@ fn test_iterator_chain() { } assert_eq!(i, expected.len()); - let ys = (30..).iter_step_by(10).take(4); + let ys = (30..).step_by(10).take(4); let it = xs.iter().cloned().chain(ys); let mut i = 0; for x in it { @@ -156,13 +147,13 @@ fn test_iterator_chain_find() { #[test] fn test_iterator_step_by() { // Identity - let mut it = (0..).iter_step_by(1).take(3); + let mut it = (0..).step_by(1).take(3); assert_eq!(it.next(), Some(0)); assert_eq!(it.next(), Some(1)); assert_eq!(it.next(), Some(2)); assert_eq!(it.next(), None); - let mut it = (0..).iter_step_by(3).take(4); + let mut it = (0..).step_by(3).take(4); assert_eq!(it.next(), Some(0)); assert_eq!(it.next(), Some(3)); assert_eq!(it.next(), Some(6)); @@ -173,7 +164,7 @@ fn test_iterator_step_by() { #[test] #[should_panic] fn test_iterator_step_by_zero() { - let mut it = (0..).iter_step_by(0); + let mut it = (0..).step_by(0); it.next(); } @@ -252,7 +243,7 @@ fn test_iterator_step_by_size_hint() { #[test] fn test_filter_map() { - let it = (0..).iter_step_by(1).take(10) + let it = (0..).step_by(1).take(10) .filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None }); assert_eq!(it.collect::<Vec<usize>>(), [0*0, 2*2, 4*4, 6*6, 8*8]); } @@ -654,7 +645,7 @@ fn test_iterator_scan() { fn test_iterator_flat_map() { let xs = [0, 3, 6]; let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8]; - let it = xs.iter().flat_map(|&x| (x..).iter_step_by(1).take(3)); + let it = xs.iter().flat_map(|&x| (x..).step_by(1).take(3)); let mut i = 0; for x in it { assert_eq!(x, ys[i]); @@ -680,13 +671,13 @@ fn test_inspect() { #[test] fn test_cycle() { let cycle_len = 3; - let it = (0..).iter_step_by(1).take(cycle_len).cycle(); + let it = (0..).step_by(1).take(cycle_len).cycle(); assert_eq!(it.size_hint(), (usize::MAX, None)); for (i, x) in it.take(100).enumerate() { assert_eq!(i % cycle_len, x); } - let mut it = (0..).iter_step_by(1).take(0).cycle(); + let mut it = (0..).step_by(1).take(0).cycle(); assert_eq!(it.size_hint(), (0, Some(0))); assert_eq!(it.next(), None); } @@ -765,7 +756,7 @@ fn test_iterator_min() { #[test] fn test_iterator_size_hint() { - let c = (0..).iter_step_by(1); + let c = (0..).step_by(1); let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let v2 = &[10, 11, 12]; let vi = v.iter(); @@ -1090,8 +1081,8 @@ fn test_range_step() { #![allow(deprecated)] assert_eq!((0..20).step_by(5).collect::<Vec<isize>>(), [0, 5, 10, 15]); - assert_eq!((20..0).step_by(-5).collect::<Vec<isize>>(), [20, 15, 10, 5]); - assert_eq!((20..0).step_by(-6).collect::<Vec<isize>>(), [20, 14, 8, 2]); + assert_eq!((1..21).rev().step_by(5).collect::<Vec<isize>>(), [20, 15, 10, 5]); + assert_eq!((1..21).rev().step_by(6).collect::<Vec<isize>>(), [20, 14, 8, 2]); assert_eq!((200..255).step_by(50).collect::<Vec<u8>>(), [200, 250]); assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []); assert_eq!((200..200).step_by(1).collect::<Vec<isize>>(), []); @@ -1099,13 +1090,12 @@ fn test_range_step() { assert_eq!((0..20).step_by(1).size_hint(), (20, Some(20))); assert_eq!((0..20).step_by(21).size_hint(), (1, Some(1))); assert_eq!((0..20).step_by(5).size_hint(), (4, Some(4))); - assert_eq!((20..0).step_by(-5).size_hint(), (4, Some(4))); - assert_eq!((20..0).step_by(-6).size_hint(), (4, Some(4))); + assert_eq!((1..21).rev().step_by(5).size_hint(), (4, Some(4))); + assert_eq!((1..21).rev().step_by(6).size_hint(), (4, Some(4))); assert_eq!((20..-5).step_by(1).size_hint(), (0, Some(0))); assert_eq!((20..20).step_by(1).size_hint(), (0, Some(0))); - assert_eq!((0..1).step_by(0).size_hint(), (0, None)); - assert_eq!((i8::MAX..i8::MIN).step_by(i8::MIN).size_hint(), (2, Some(2))); - assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX).size_hint(), (3, Some(3))); + assert_eq!((i8::MIN..i8::MAX).step_by(-(i8::MIN as i32) as usize).size_hint(), (2, Some(2))); + assert_eq!((i16::MIN..i16::MAX).step_by(i16::MAX as usize).size_hint(), (3, Some(3))); assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX))); } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index b0a57d97d5eff..8d3e367d2379a 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -35,7 +35,6 @@ #![feature(slice_rotate)] #![feature(sort_internals)] #![feature(specialization)] -#![feature(step_by)] #![feature(step_trait)] #![feature(test)] #![feature(trusted_len)] diff --git a/src/libproc_macro/Cargo.toml b/src/libproc_macro/Cargo.toml index 7ce65d0fe4dbc..1b5141773a967 100644 --- a/src/libproc_macro/Cargo.toml +++ b/src/libproc_macro/Cargo.toml @@ -9,3 +9,4 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index f3d0521a2af6c..06f9634d70613 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -37,18 +37,26 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] +#![feature(i128_type)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(lang_items)] +#[macro_use] extern crate syntax; +extern crate syntax_pos; -use std::fmt; +use std::{ascii, fmt, iter}; use std::str::FromStr; +use syntax::ast; use syntax::errors::DiagnosticBuilder; -use syntax::parse; -use syntax::tokenstream::TokenStream as TokenStream_; +use syntax::parse::{self, token, parse_stream_from_source_str}; +use syntax::print::pprust; +use syntax::symbol::Symbol; +use syntax::tokenstream; +use syntax_pos::DUMMY_SP; +use syntax_pos::SyntaxContext; /// The main type provided by this crate, representing an abstract stream of /// tokens. @@ -60,17 +68,508 @@ use syntax::tokenstream::TokenStream as TokenStream_; /// The API of this type is intentionally bare-bones, but it'll be expanded over /// time! #[stable(feature = "proc_macro_lib", since = "1.15.0")] -pub struct TokenStream { - inner: TokenStream_, -} +#[derive(Clone, Debug)] +pub struct TokenStream(tokenstream::TokenStream); /// Error returned from `TokenStream::from_str`. -#[derive(Debug)] #[stable(feature = "proc_macro_lib", since = "1.15.0")] +#[derive(Debug)] pub struct LexError { _inner: (), } +#[stable(feature = "proc_macro_lib", since = "1.15.0")] +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result<TokenStream, LexError> { + __internal::with_sess(|(sess, mark)| { + let src = src.to_string(); + let name = "<proc-macro source code>".to_string(); + let call_site = mark.expn_info().unwrap().call_site; + let stream = parse::parse_stream_from_source_str(name, src, sess, Some(call_site)); + Ok(__internal::token_stream_wrap(stream)) + }) + } +} + +#[stable(feature = "proc_macro_lib", since = "1.15.0")] +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +/// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input. +/// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs +/// constructs the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`. +/// +/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. +/// To quote `$` itself, use `$$`. +#[unstable(feature = "proc_macro", issue = "38356")] +#[macro_export] +macro_rules! quote { () => {} } + +#[unstable(feature = "proc_macro_internals", issue = "27812")] +#[doc(hidden)] +mod quote; + +#[unstable(feature = "proc_macro", issue = "38356")] +impl From<TokenTree> for TokenStream { + fn from(tree: TokenTree) -> TokenStream { + TokenStream(tree.to_internal()) + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl From<TokenNode> for TokenStream { + fn from(kind: TokenNode) -> TokenStream { + TokenTree::from(kind).into() + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream { + fn from_iter<I: IntoIterator<Item = T>>(streams: I) -> Self { + let mut builder = tokenstream::TokenStreamBuilder::new(); + for stream in streams { + builder.push(stream.into().0); + } + TokenStream(builder.build()) + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl IntoIterator for TokenStream { + type Item = TokenTree; + type IntoIter = TokenTreeIter; + + fn into_iter(self) -> TokenTreeIter { + TokenTreeIter { cursor: self.0.trees(), next: None } + } +} + +impl TokenStream { + /// Returns an empty `TokenStream`. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn empty() -> TokenStream { + TokenStream(tokenstream::TokenStream::empty()) + } + + /// Checks if this `TokenStream` is empty. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +/// A region of source code, along with macro expansion information. +#[unstable(feature = "proc_macro", issue = "38356")] +#[derive(Copy, Clone, Debug)] +pub struct Span(syntax_pos::Span); + +#[unstable(feature = "proc_macro", issue = "38356")] +impl Default for Span { + fn default() -> Span { + ::__internal::with_sess(|(_, mark)| Span(syntax_pos::Span { + ctxt: SyntaxContext::empty().apply_mark(mark), + ..mark.expn_info().unwrap().call_site + })) + } +} + +/// Quote a `Span` into a `TokenStream`. +/// This is needed to implement a custom quoter. +#[unstable(feature = "proc_macro", issue = "38356")] +pub fn quote_span(span: Span) -> TokenStream { + TokenStream(quote::Quote::quote(&span.0)) +} + +impl Span { + /// The span of the invocation of the current procedural macro. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn call_site() -> Span { + ::__internal::with_sess(|(_, mark)| Span(mark.expn_info().unwrap().call_site)) + } +} + +/// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`). +#[unstable(feature = "proc_macro", issue = "38356")] +#[derive(Clone, Debug)] +pub struct TokenTree { + /// The `TokenTree`'s span + pub span: Span, + /// Description of the `TokenTree` + pub kind: TokenNode, +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl From<TokenNode> for TokenTree { + fn from(kind: TokenNode) -> TokenTree { + TokenTree { span: Span::default(), kind: kind } + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl fmt::Display for TokenTree { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + TokenStream::from(self.clone()).fmt(f) + } +} + +/// Description of a `TokenTree` +#[derive(Clone, Debug)] +#[unstable(feature = "proc_macro", issue = "38356")] +pub enum TokenNode { + /// A delimited tokenstream. + Group(Delimiter, TokenStream), + /// A unicode identifier. + Term(Term), + /// A punctuation character (`+`, `,`, `$`, etc.). + Op(char, Spacing), + /// A literal character (`'a'`), string (`"hello"`), or number (`2.3`). + Literal(Literal), +} + +/// Describes how a sequence of token trees is delimited. +#[derive(Copy, Clone, Debug)] +#[unstable(feature = "proc_macro", issue = "38356")] +pub enum Delimiter { + /// `( ... )` + Parenthesis, + /// `[ ... ]` + Brace, + /// `{ ... }` + Bracket, + /// An implicit delimiter, e.g. `$var`, where $var is `...`. + None, +} + +/// An interned string. +#[derive(Copy, Clone, Debug)] +#[unstable(feature = "proc_macro", issue = "38356")] +pub struct Term(Symbol); + +impl Term { + /// Intern a string into a `Term`. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn intern(string: &str) -> Term { + Term(Symbol::intern(string)) + } + + /// Get a reference to the interned string. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn as_str(&self) -> &str { + unsafe { &*(&*self.0.as_str() as *const str) } + } +} + +/// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace. +#[derive(Copy, Clone, Debug)] +#[unstable(feature = "proc_macro", issue = "38356")] +pub enum Spacing { + /// e.g. `+` is `Alone` in `+ =`. + Alone, + /// e.g. `+` is `Joint` in `+=`. + Joint, +} + +/// A literal character (`'a'`), string (`"hello"`), or number (`2.3`). +#[derive(Clone, Debug)] +#[unstable(feature = "proc_macro", issue = "38356")] +pub struct Literal(token::Token); + +#[unstable(feature = "proc_macro", issue = "38356")] +impl fmt::Display for Literal { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + TokenTree { kind: TokenNode::Literal(self.clone()), span: Span(DUMMY_SP) }.fmt(f) + } +} + +macro_rules! int_literals { + ($($int_kind:ident),*) => {$( + /// Integer literal. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn $int_kind(n: $int_kind) -> Literal { + Literal::typed_integer(n as i128, stringify!($int_kind)) + } + )*} +} + +impl Literal { + /// Integer literal + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn integer(n: i128) -> Literal { + Literal(token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), None)) + } + + int_literals!(u8, i8, u16, i16, u32, i32, u64, i64); + fn typed_integer(n: i128, kind: &'static str) -> Literal { + Literal(token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), + Some(Symbol::intern(kind)))) + } + + /// Floating point literal. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn float(n: f64) -> Literal { + if !n.is_finite() { + panic!("Invalid float literal {}", n); + } + Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())), None)) + } + + /// Floating point literal. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn f32(n: f32) -> Literal { + if !n.is_finite() { + panic!("Invalid f32 literal {}", n); + } + Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())), + Some(Symbol::intern("f32")))) + } + + /// Floating point literal. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn f64(n: f64) -> Literal { + if !n.is_finite() { + panic!("Invalid f64 literal {}", n); + } + Literal(token::Literal(token::Lit::Float(Symbol::intern(&n.to_string())), + Some(Symbol::intern("f64")))) + } + + /// String literal. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn string(string: &str) -> Literal { + let mut escaped = String::new(); + for ch in string.chars() { + escaped.extend(ch.escape_unicode()); + } + Literal(token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None)) + } + + /// Character literal. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn character(ch: char) -> Literal { + let mut escaped = String::new(); + escaped.extend(ch.escape_unicode()); + Literal(token::Literal(token::Lit::Char(Symbol::intern(&escaped)), None)) + } + + /// Byte string literal. + #[unstable(feature = "proc_macro", issue = "38356")] + pub fn byte_string(bytes: &[u8]) -> Literal { + let string = bytes.iter().cloned().flat_map(ascii::escape_default) + .map(Into::<char>::into).collect::<String>(); + Literal(token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None)) + } +} + +/// An iterator over `TokenTree`s. +#[unstable(feature = "proc_macro", issue = "38356")] +pub struct TokenTreeIter { + cursor: tokenstream::Cursor, + next: Option<tokenstream::TokenStream>, +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl Iterator for TokenTreeIter { + type Item = TokenTree; + + fn next(&mut self) -> Option<TokenTree> { + loop { + let next = + unwrap_or!(self.next.take().or_else(|| self.cursor.next_as_stream()), return None); + let tree = TokenTree::from_internal(next, &mut self.next); + if tree.span.0 == DUMMY_SP { + if let TokenNode::Group(Delimiter::None, stream) = tree.kind { + self.cursor.insert(stream.0); + continue + } + } + return Some(tree); + } + } +} + +impl Delimiter { + fn from_internal(delim: token::DelimToken) -> Delimiter { + match delim { + token::Paren => Delimiter::Parenthesis, + token::Brace => Delimiter::Brace, + token::Bracket => Delimiter::Bracket, + token::NoDelim => Delimiter::None, + } + } + + fn to_internal(self) -> token::DelimToken { + match self { + Delimiter::Parenthesis => token::Paren, + Delimiter::Brace => token::Brace, + Delimiter::Bracket => token::Bracket, + Delimiter::None => token::NoDelim, + } + } +} + +impl TokenTree { + fn from_internal(stream: tokenstream::TokenStream, next: &mut Option<tokenstream::TokenStream>) + -> TokenTree { + use syntax::parse::token::*; + + let (tree, is_joint) = stream.as_tree(); + let (mut span, token) = match tree { + tokenstream::TokenTree::Token(span, token) => (span, token), + tokenstream::TokenTree::Delimited(span, delimed) => { + let delimiter = Delimiter::from_internal(delimed.delim); + return TokenTree { + span: Span(span), + kind: TokenNode::Group(delimiter, TokenStream(delimed.tts.into())), + }; + } + }; + + let op_kind = if is_joint { Spacing::Joint } else { Spacing::Alone }; + macro_rules! op { + ($op:expr) => { TokenNode::Op($op, op_kind) } + } + + macro_rules! joint { + ($first:expr, $rest:expr) => { joint($first, $rest, is_joint, &mut span, next) } + } + + fn joint(first: char, rest: Token, is_joint: bool, span: &mut syntax_pos::Span, + next: &mut Option<tokenstream::TokenStream>) + -> TokenNode { + let (first_span, rest_span) = (*span, *span); + *span = first_span; + let tree = tokenstream::TokenTree::Token(rest_span, rest); + *next = Some(if is_joint { tree.joint() } else { tree.into() }); + TokenNode::Op(first, Spacing::Joint) + } + + let kind = match token { + Eq => op!('='), + Lt => op!('<'), + Le => joint!('<', Eq), + EqEq => joint!('=', Eq), + Ne => joint!('!', Eq), + Ge => joint!('>', Eq), + Gt => op!('>'), + AndAnd => joint!('&', BinOp(And)), + OrOr => joint!('|', BinOp(Or)), + Not => op!('!'), + Tilde => op!('~'), + BinOp(Plus) => op!('+'), + BinOp(Minus) => op!('-'), + BinOp(Star) => op!('*'), + BinOp(Slash) => op!('/'), + BinOp(Percent) => op!('%'), + BinOp(Caret) => op!('^'), + BinOp(And) => op!('&'), + BinOp(Or) => op!('|'), + BinOp(Shl) => joint!('<', Lt), + BinOp(Shr) => joint!('>', Gt), + BinOpEq(Plus) => joint!('+', Eq), + BinOpEq(Minus) => joint!('-', Eq), + BinOpEq(Star) => joint!('*', Eq), + BinOpEq(Slash) => joint!('/', Eq), + BinOpEq(Percent) => joint!('%', Eq), + BinOpEq(Caret) => joint!('^', Eq), + BinOpEq(And) => joint!('&', Eq), + BinOpEq(Or) => joint!('|', Eq), + BinOpEq(Shl) => joint!('<', Le), + BinOpEq(Shr) => joint!('>', Ge), + At => op!('@'), + Dot => op!('.'), + DotDot => joint!('.', Dot), + DotDotDot => joint!('.', DotDot), + Comma => op!(','), + Semi => op!(';'), + Colon => op!(':'), + ModSep => joint!(':', Colon), + RArrow => joint!('-', Gt), + LArrow => joint!('<', BinOp(Minus)), + FatArrow => joint!('=', Gt), + Pound => op!('#'), + Dollar => op!('$'), + Question => op!('?'), + Underscore => op!('_'), + + Ident(ident) | Lifetime(ident) => TokenNode::Term(Term(ident.name)), + Literal(..) | DocComment(..) => TokenNode::Literal(self::Literal(token)), + + Interpolated(ref nt) => __internal::with_sess(|(sess, _)| { + TokenNode::Group(Delimiter::None, TokenStream(nt.1.force(|| { + // FIXME(jseyfried): Avoid this pretty-print + reparse hack + let name = "<macro expansion>".to_owned(); + let source = pprust::token_to_string(&token); + parse_stream_from_source_str(name, source, sess, Some(span)) + }))) + }), + + OpenDelim(..) | CloseDelim(..) => unreachable!(), + Whitespace | Comment | Shebang(..) | Eof => unreachable!(), + }; + + TokenTree { span: Span(span), kind: kind } + } + + fn to_internal(self) -> tokenstream::TokenStream { + use syntax::parse::token::*; + use syntax::tokenstream::{TokenTree, Delimited}; + + let (op, kind) = match self.kind { + TokenNode::Op(op, kind) => (op, kind), + TokenNode::Group(delimiter, tokens) => { + return TokenTree::Delimited(self.span.0, Delimited { + delim: delimiter.to_internal(), + tts: tokens.0.into(), + }).into(); + }, + TokenNode::Term(symbol) => { + let ident = ast::Ident { name: symbol.0, ctxt: self.span.0.ctxt }; + let token = + if symbol.0.as_str().starts_with("'") { Lifetime(ident) } else { Ident(ident) }; + return TokenTree::Token(self.span.0, token).into(); + } + TokenNode::Literal(token) => return TokenTree::Token(self.span.0, token.0).into(), + }; + + let token = match op { + '=' => Eq, + '<' => Lt, + '>' => Gt, + '!' => Not, + '~' => Tilde, + '+' => BinOp(Plus), + '-' => BinOp(Minus), + '*' => BinOp(Star), + '/' => BinOp(Slash), + '%' => BinOp(Percent), + '^' => BinOp(Caret), + '&' => BinOp(And), + '|' => BinOp(Or), + '@' => At, + '.' => Dot, + ',' => Comma, + ';' => Semi, + ':' => Colon, + '#' => Pound, + '$' => Dollar, + '?' => Question, + '_' => Underscore, + _ => panic!("unsupported character {}", op), + }; + + let tree = TokenTree::Token(self.span.0, token); + match kind { + Spacing::Alone => tree.into(), + Spacing::Joint => tree.joint(), + } + } +} + /// Permanently unstable internal implementation details of this crate. This /// should not be used. /// @@ -83,32 +582,33 @@ pub struct LexError { #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] pub mod __internal { + pub use quote::{Quoter, __rt}; + use std::cell::Cell; - use std::rc::Rc; use syntax::ast; + use syntax::ext::base::ExtCtxt; + use syntax::ext::hygiene::Mark; use syntax::ptr::P; - use syntax::parse::{self, token, ParseSess}; - use syntax::tokenstream::{TokenTree, TokenStream as TokenStream_}; + use syntax::parse::{self, ParseSess}; + use syntax::parse::token::{self, Token}; + use syntax::tokenstream; + use syntax_pos::DUMMY_SP; use super::{TokenStream, LexError}; pub fn new_token_stream(item: P<ast::Item>) -> TokenStream { - TokenStream { - inner: TokenTree::Token(item.span, token::Interpolated(Rc::new(token::NtItem(item)))) - .into() - } + let token = Token::interpolated(token::NtItem(item)); + TokenStream(tokenstream::TokenTree::Token(DUMMY_SP, token).into()) } - pub fn token_stream_wrap(inner: TokenStream_) -> TokenStream { - TokenStream { - inner: inner - } + pub fn token_stream_wrap(inner: tokenstream::TokenStream) -> TokenStream { + TokenStream(inner) } pub fn token_stream_parse_items(stream: TokenStream) -> Result<Vec<P<ast::Item>>, LexError> { - with_parse_sess(move |sess| { - let mut parser = parse::stream_to_parser(sess, stream.inner); + with_sess(move |(sess, _)| { + let mut parser = parse::stream_to_parser(sess, stream.0); let mut items = Vec::new(); while let Some(item) = try!(parser.parse_item().map_err(super::parse_to_lex_err)) { @@ -119,8 +619,8 @@ pub mod __internal { }) } - pub fn token_stream_inner(stream: TokenStream) -> TokenStream_ { - stream.inner + pub fn token_stream_inner(stream: TokenStream) -> tokenstream::TokenStream { + stream.0 } pub trait Registry { @@ -140,13 +640,14 @@ pub mod __internal { // Emulate scoped_thread_local!() here essentially thread_local! { - static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _); + static CURRENT_SESS: Cell<(*const ParseSess, Mark)> = + Cell::new((0 as *const _, Mark::root())); } - pub fn set_parse_sess<F, R>(sess: &ParseSess, f: F) -> R + pub fn set_sess<F, R>(cx: &ExtCtxt, f: F) -> R where F: FnOnce() -> R { - struct Reset { prev: *const ParseSess } + struct Reset { prev: (*const ParseSess, Mark) } impl Drop for Reset { fn drop(&mut self) { @@ -156,18 +657,18 @@ pub mod __internal { CURRENT_SESS.with(|p| { let _reset = Reset { prev: p.get() }; - p.set(sess); + p.set((cx.parse_sess, cx.current_expansion.mark)); f() }) } - pub fn with_parse_sess<F, R>(f: F) -> R - where F: FnOnce(&ParseSess) -> R + pub fn with_sess<F, R>(f: F) -> R + where F: FnOnce((&ParseSess, Mark)) -> R { let p = CURRENT_SESS.with(|p| p.get()); - assert!(!p.is_null(), "proc_macro::__internal::with_parse_sess() called \ - before set_parse_sess()!"); - f(unsafe { &*p }) + assert!(!p.0.is_null(), "proc_macro::__internal::with_sess() called \ + before set_parse_sess()!"); + f(unsafe { (&*p.0, p.1) }) } } @@ -175,24 +676,3 @@ fn parse_to_lex_err(mut err: DiagnosticBuilder) -> LexError { err.cancel(); LexError { _inner: () } } - -#[stable(feature = "proc_macro_lib", since = "1.15.0")] -impl FromStr for TokenStream { - type Err = LexError; - - fn from_str(src: &str) -> Result<TokenStream, LexError> { - __internal::with_parse_sess(|sess| { - let src = src.to_string(); - let name = "<proc-macro source code>".to_string(); - let stream = parse::parse_stream_from_source_str(name, src, sess); - Ok(__internal::token_stream_wrap(stream)) - }) - } -} - -#[stable(feature = "proc_macro_lib", since = "1.15.0")] -impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.inner.fmt(f) - } -} diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs new file mode 100644 index 0000000000000..bee2c1e0eb6b6 --- /dev/null +++ b/src/libproc_macro/quote.rs @@ -0,0 +1,263 @@ +// 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. + +//! # Quasiquoter +//! This file contains the implementation internals of the quasiquoter provided by `quote!`. + +//! This quasiquoter uses macros 2.0 hygiene to reliably use items from `__rt`, +//! including re-exported API `libsyntax`, to build a `syntax::tokenstream::TokenStream` +//! and wrap it into a `proc_macro::TokenStream`. + +use syntax::ast::Ident; +use syntax::ext::base::{ExtCtxt, ProcMacro}; +use syntax::parse::token::{self, Token, Lit}; +use syntax::symbol::Symbol; +use syntax::tokenstream::{Delimited, TokenTree, TokenStream, TokenStreamBuilder}; +use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::hygiene::SyntaxContext; + +pub struct Quoter; + +pub mod __rt { + pub use syntax::ast::Ident; + pub use syntax::parse::token; + pub use syntax::symbol::Symbol; + pub use syntax::tokenstream::{TokenStream, TokenStreamBuilder, TokenTree, Delimited}; + pub use super::{ctxt, span}; + + pub fn unquote<T: Into<::TokenStream> + Clone>(tokens: &T) -> TokenStream { + T::into(tokens.clone()).0 + } +} + +pub fn ctxt() -> SyntaxContext { + ::__internal::with_sess(|(_, mark)| SyntaxContext::empty().apply_mark(mark)) +} + +pub fn span() -> Span { + ::Span::default().0 +} + +pub trait Quote { + fn quote(&self) -> TokenStream; +} + +macro_rules! quote_tok { + (,) => { Token::Comma }; + (.) => { Token::Dot }; + (:) => { Token::Colon }; + (::) => { Token::ModSep }; + (!) => { Token::Not }; + (<) => { Token::Lt }; + (>) => { Token::Gt }; + (_) => { Token::Underscore }; + (0) => { Token::Literal(token::Lit::Integer(Symbol::intern("0")), None) }; + (&) => { Token::BinOp(token::And) }; + ($i:ident) => { Token::Ident(Ident { name: Symbol::intern(stringify!($i)), ctxt: ctxt() }) }; +} + +macro_rules! quote_tree { + ((unquote $($t:tt)*)) => { TokenStream::from($($t)*) }; + ((quote $($t:tt)*)) => { ($($t)*).quote() }; + (($($t:tt)*)) => { delimit(token::Paren, quote!($($t)*)) }; + ([$($t:tt)*]) => { delimit(token::Bracket, quote!($($t)*)) }; + ({$($t:tt)*}) => { delimit(token::Brace, quote!($($t)*)) }; + (rt) => { quote!(::__internal::__rt) }; + ($t:tt) => { TokenStream::from(TokenTree::Token(span(), quote_tok!($t))) }; +} + +fn delimit(delim: token::DelimToken, stream: TokenStream) -> TokenStream { + TokenTree::Delimited(span(), Delimited { delim: delim, tts: stream.into() }).into() +} + +macro_rules! quote { + () => { TokenStream::empty() }; + ($($t:tt)*) => { [ $( quote_tree!($t), )* ].iter().cloned().collect::<TokenStream>() }; +} + +impl ProcMacro for Quoter { + fn expand<'cx>(&self, cx: &'cx mut ExtCtxt, _: Span, stream: TokenStream) -> TokenStream { + let mut info = cx.current_expansion.mark.expn_info().unwrap(); + info.callee.allow_internal_unstable = true; + cx.current_expansion.mark.set_expn_info(info); + ::__internal::set_sess(cx, || quote!(::TokenStream((quote stream)))) + } +} + +impl<T: Quote> Quote for Option<T> { + fn quote(&self) -> TokenStream { + match *self { + Some(ref t) => quote!(Some((quote t))), + None => quote!(None), + } + } +} + +impl Quote for TokenStream { + fn quote(&self) -> TokenStream { + let mut builder = TokenStreamBuilder::new(); + builder.push(quote!(rt::TokenStreamBuilder::new())); + + let mut trees = self.trees(); + loop { + let (mut tree, mut is_joint) = match trees.next_as_stream() { + Some(next) => next.as_tree(), + None => return builder.add(quote!(.build())).build(), + }; + if let TokenTree::Token(_, Token::Dollar) = tree { + let (next_tree, next_is_joint) = match trees.next_as_stream() { + Some(next) => next.as_tree(), + None => panic!("unexpected trailing `$` in `quote!`"), + }; + match next_tree { + TokenTree::Token(_, Token::Ident(..)) => { + builder.push(quote!(.add(rt::unquote(&(unquote next_tree))))); + continue + } + TokenTree::Token(_, Token::Dollar) => { + tree = next_tree; + is_joint = next_is_joint; + } + _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), + } + } + + builder.push(match is_joint { + true => quote!(.add((quote tree).joint())), + false => quote!(.add(rt::TokenStream::from((quote tree)))), + }); + } + } +} + +impl Quote for TokenTree { + fn quote(&self) -> TokenStream { + match *self { + TokenTree::Token(span, ref token) => quote! { + rt::TokenTree::Token((quote span), (quote token)) + }, + TokenTree::Delimited(span, ref delimited) => quote! { + rt::TokenTree::Delimited((quote span), (quote delimited)) + }, + } + } +} + +impl Quote for Delimited { + fn quote(&self) -> TokenStream { + quote!(rt::Delimited { delim: (quote self.delim), tts: (quote self.stream()).into() }) + } +} + +impl<'a> Quote for &'a str { + fn quote(&self) -> TokenStream { + TokenTree::Token(span(), Token::Literal(token::Lit::Str_(Symbol::intern(self)), None)) + .into() + } +} + +impl Quote for usize { + fn quote(&self) -> TokenStream { + let integer_symbol = Symbol::intern(&self.to_string()); + TokenTree::Token(DUMMY_SP, Token::Literal(token::Lit::Integer(integer_symbol), None)) + .into() + } +} + +impl Quote for Ident { + fn quote(&self) -> TokenStream { + quote!(rt::Ident { name: (quote self.name), ctxt: rt::ctxt() }) + } +} + +impl Quote for Symbol { + fn quote(&self) -> TokenStream { + quote!(rt::Symbol::intern((quote &*self.as_str()))) + } +} + +impl Quote for Span { + fn quote(&self) -> TokenStream { + quote!(rt::span()) + } +} + +impl Quote for Token { + fn quote(&self) -> TokenStream { + macro_rules! gen_match { + ($($i:ident),*; $($t:tt)*) => { + match *self { + $( Token::$i => quote!(rt::token::$i), )* + $( $t )* + } + } + } + + gen_match! { + Eq, Lt, Le, EqEq, Ne, Ge, Gt, AndAnd, OrOr, Not, Tilde, At, Dot, DotDot, DotDotDot, + Comma, Semi, Colon, ModSep, RArrow, LArrow, FatArrow, Pound, Dollar, Question, + Underscore; + + Token::OpenDelim(delim) => quote!(rt::token::OpenDelim((quote delim))), + Token::CloseDelim(delim) => quote!(rt::token::CloseDelim((quote delim))), + Token::BinOp(tok) => quote!(rt::token::BinOp((quote tok))), + Token::BinOpEq(tok) => quote!(rt::token::BinOpEq((quote tok))), + Token::Ident(ident) => quote!(rt::token::Ident((quote ident))), + Token::Lifetime(ident) => quote!(rt::token::Lifetime((quote ident))), + Token::Literal(lit, sfx) => quote!(rt::token::Literal((quote lit), (quote sfx))), + _ => panic!("Unhandled case!"), + } + } +} + +impl Quote for token::BinOpToken { + fn quote(&self) -> TokenStream { + macro_rules! gen_match { + ($($i:ident),*) => { + match *self { + $( token::BinOpToken::$i => quote!(rt::token::BinOpToken::$i), )* + } + } + } + + gen_match!(Plus, Minus, Star, Slash, Percent, Caret, And, Or, Shl, Shr) + } +} + +impl Quote for Lit { + fn quote(&self) -> TokenStream { + macro_rules! gen_match { + ($($i:ident),*; $($raw:ident),*) => { + match *self { + $( Lit::$i(lit) => quote!(rt::token::Lit::$i((quote lit))), )* + $( Lit::$raw(lit, n) => { + quote!(::syntax::parse::token::Lit::$raw((quote lit), (quote n))) + })* + } + } + } + + gen_match!(Byte, Char, Float, Str_, Integer, ByteStr; StrRaw, ByteStrRaw) + } +} + +impl Quote for token::DelimToken { + fn quote(&self) -> TokenStream { + macro_rules! gen_match { + ($($i:ident),*) => { + match *self { + $(token::DelimToken::$i => { quote!(rt::token::DelimToken::$i) })* + } + } + } + + gen_match!(Paren, Bracket, Brace, NoDelim) + } +} diff --git a/src/libproc_macro_plugin/lib.rs b/src/libproc_macro_plugin/lib.rs deleted file mode 100644 index d1bc0966eb567..0000000000000 --- a/src/libproc_macro_plugin/lib.rs +++ /dev/null @@ -1,103 +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. - -//! # Proc_Macro -//! -//! A library for procedural macro writers. -//! -//! ## Usage -//! This crate provides the `quote!` macro for syntax creation. -//! -//! The `quote!` macro uses the crate `syntax`, so users must declare `extern crate syntax;` -//! at the crate root. This is a temporary solution until we have better hygiene. -//! -//! ## Quasiquotation -//! -//! The quasiquoter creates output that, when run, constructs the tokenstream specified as -//! input. For example, `quote!(5 + 5)` will produce a program, that, when run, will -//! construct the TokenStream `5 | + | 5`. -//! -//! ### Unquoting -//! -//! Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. -//! To quote `$` itself, use `$$`. -//! -//! A simple example is: -//! -//!``` -//!fn double(tmp: TokenStream) -> TokenStream { -//! quote!($tmp * 2) -//!} -//!``` -//! -//! ### Large example: Scheme's `cond` -//! -//! Below is an example implementation of Scheme's `cond`. -//! -//! ``` -//! fn cond(input: TokenStream) -> TokenStream { -//! let mut conds = Vec::new(); -//! let mut input = input.trees().peekable(); -//! while let Some(tree) = input.next() { -//! let mut cond = match tree { -//! TokenTree::Delimited(_, ref delimited) => delimited.stream(), -//! _ => panic!("Invalid input"), -//! }; -//! let mut trees = cond.trees(); -//! let test = trees.next(); -//! let rhs = trees.collect::<TokenStream>(); -//! if rhs.is_empty() { -//! panic!("Invalid macro usage in cond: {}", cond); -//! } -//! let is_else = match test { -//! Some(TokenTree::Token(_, Token::Ident(ident))) if ident.name == "else" => true, -//! _ => false, -//! }; -//! conds.push(if is_else || input.peek().is_none() { -//! quote!({ $rhs }) -//! } else { -//! let test = test.unwrap(); -//! quote!(if $test { $rhs } else) -//! }); -//! } -//! -//! conds.into_iter().collect() -//! } -//! ``` -#![crate_name = "proc_macro_plugin"] -#![feature(plugin_registrar)] -#![crate_type = "dylib"] -#![crate_type = "rlib"] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] - -#![feature(rustc_diagnostic_macros)] - -extern crate rustc_plugin; -extern crate syntax; -extern crate syntax_pos; - -mod quote; -use quote::quote; - -use rustc_plugin::Registry; -use syntax::ext::base::SyntaxExtension; -use syntax::symbol::Symbol; - -// ____________________________________________________________________________________________ -// Main macro definition - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension(Symbol::intern("quote"), - SyntaxExtension::ProcMacro(Box::new(quote))); -} diff --git a/src/libproc_macro_plugin/quote.rs b/src/libproc_macro_plugin/quote.rs deleted file mode 100644 index 09675564291a2..0000000000000 --- a/src/libproc_macro_plugin/quote.rs +++ /dev/null @@ -1,230 +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. - -//! # Quasiquoter -//! This file contains the implementation internals of the quasiquoter provided by `qquote!`. - -use syntax::ast::Ident; -use syntax::parse::token::{self, Token, Lit}; -use syntax::symbol::Symbol; -use syntax::tokenstream::{self, Delimited, TokenTree, TokenStream}; -use syntax_pos::DUMMY_SP; - -use std::iter; - -pub fn quote<'cx>(stream: TokenStream) -> TokenStream { - stream.quote() -} - -trait Quote { - fn quote(&self) -> TokenStream; -} - -macro_rules! quote_tok { - (,) => { Token::Comma }; - (.) => { Token::Dot }; - (:) => { Token::Colon }; - (::) => { Token::ModSep }; - (!) => { Token::Not }; - (<) => { Token::Lt }; - (>) => { Token::Gt }; - (_) => { Token::Underscore }; - ($i:ident) => { Token::Ident(Ident::from_str(stringify!($i))) }; -} - -macro_rules! quote_tree { - ((unquote $($t:tt)*)) => { $($t)* }; - ((quote $($t:tt)*)) => { ($($t)*).quote() }; - (($($t:tt)*)) => { delimit(token::Paren, quote!($($t)*)) }; - ([$($t:tt)*]) => { delimit(token::Bracket, quote!($($t)*)) }; - ({$($t:tt)*}) => { delimit(token::Brace, quote!($($t)*)) }; - ($t:tt) => { TokenStream::from(TokenTree::Token(DUMMY_SP, quote_tok!($t))) }; -} - -fn delimit(delim: token::DelimToken, stream: TokenStream) -> TokenStream { - TokenTree::Delimited(DUMMY_SP, Delimited { delim: delim, tts: stream.into() }).into() -} - -macro_rules! quote { - () => { TokenStream::empty() }; - ($($t:tt)*) => { [ $( quote_tree!($t), )* ].iter().cloned().collect::<TokenStream>() }; -} - -impl<T: Quote> Quote for Option<T> { - fn quote(&self) -> TokenStream { - match *self { - Some(ref t) => quote!(::std::option::Option::Some((quote t))), - None => quote!(::std::option::Option::None), - } - } -} - -impl Quote for TokenStream { - fn quote(&self) -> TokenStream { - if self.is_empty() { - return quote!(::syntax::tokenstream::TokenStream::empty()); - } - - struct Quoter(iter::Peekable<tokenstream::Cursor>); - - impl Iterator for Quoter { - type Item = TokenStream; - - fn next(&mut self) -> Option<TokenStream> { - let quoted_tree = if let Some(&TokenTree::Token(_, Token::Dollar)) = self.0.peek() { - self.0.next(); - match self.0.next() { - Some(tree @ TokenTree::Token(_, Token::Ident(..))) => Some(tree.into()), - Some(tree @ TokenTree::Token(_, Token::Dollar)) => Some(tree.quote()), - // FIXME(jseyfried): improve these diagnostics - Some(..) => panic!("`$` must be followed by an ident or `$` in `quote!`"), - None => panic!("unexpected trailing `$` in `quote!`"), - } - } else { - self.0.next().as_ref().map(Quote::quote) - }; - - quoted_tree.map(|quoted_tree| { - quote!(::syntax::tokenstream::TokenStream::from((unquote quoted_tree)),) - }) - } - } - - let quoted = Quoter(self.trees().peekable()).collect::<TokenStream>(); - quote!([(unquote quoted)].iter().cloned().collect::<::syntax::tokenstream::TokenStream>()) - } -} - -impl Quote for TokenTree { - fn quote(&self) -> TokenStream { - match *self { - TokenTree::Token(_, ref token) => quote! { - ::syntax::tokenstream::TokenTree::Token(::syntax::ext::quote::rt::DUMMY_SP, - (quote token)) - }, - TokenTree::Delimited(_, ref delimited) => quote! { - ::syntax::tokenstream::TokenTree::Delimited(::syntax::ext::quote::rt::DUMMY_SP, - (quote delimited)) - }, - } - } -} - -impl Quote for Delimited { - fn quote(&self) -> TokenStream { - quote!(::syntax::tokenstream::Delimited { - delim: (quote self.delim), - tts: (quote self.stream()).into(), - }) - } -} - -impl<'a> Quote for &'a str { - fn quote(&self) -> TokenStream { - TokenTree::Token(DUMMY_SP, Token::Literal(token::Lit::Str_(Symbol::intern(self)), None)) - .into() - } -} - -impl Quote for usize { - fn quote(&self) -> TokenStream { - let integer_symbol = Symbol::intern(&self.to_string()); - TokenTree::Token(DUMMY_SP, Token::Literal(token::Lit::Integer(integer_symbol), None)) - .into() - } -} - -impl Quote for Ident { - fn quote(&self) -> TokenStream { - // FIXME(jseyfried) quote hygiene - quote!(::syntax::ast::Ident::from_str((quote &*self.name.as_str()))) - } -} - -impl Quote for Symbol { - fn quote(&self) -> TokenStream { - quote!(::syntax::symbol::Symbol::intern((quote &*self.as_str()))) - } -} - -impl Quote for Token { - fn quote(&self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident),*; $($t:tt)*) => { - match *self { - $( Token::$i => quote!(::syntax::parse::token::$i), )* - $( $t )* - } - } - } - - gen_match! { - Eq, Lt, Le, EqEq, Ne, Ge, Gt, AndAnd, OrOr, Not, Tilde, At, Dot, DotDot, DotDotDot, - Comma, Semi, Colon, ModSep, RArrow, LArrow, FatArrow, Pound, Dollar, Question, - Underscore; - - Token::OpenDelim(delim) => quote!(::syntax::parse::token::OpenDelim((quote delim))), - Token::CloseDelim(delim) => quote!(::syntax::parse::token::CloseDelim((quote delim))), - Token::BinOp(tok) => quote!(::syntax::parse::token::BinOp((quote tok))), - Token::BinOpEq(tok) => quote!(::syntax::parse::token::BinOpEq((quote tok))), - Token::Ident(ident) => quote!(::syntax::parse::token::Ident((quote ident))), - Token::Lifetime(ident) => quote!(::syntax::parse::token::Lifetime((quote ident))), - Token::Literal(lit, sfx) => quote! { - ::syntax::parse::token::Literal((quote lit), (quote sfx)) - }, - _ => panic!("Unhandled case!"), - } - } -} - -impl Quote for token::BinOpToken { - fn quote(&self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident),*) => { - match *self { - $( token::BinOpToken::$i => quote!(::syntax::parse::token::BinOpToken::$i), )* - } - } - } - - gen_match!(Plus, Minus, Star, Slash, Percent, Caret, And, Or, Shl, Shr) - } -} - -impl Quote for Lit { - fn quote(&self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident),*; $($raw:ident),*) => { - match *self { - $( Lit::$i(lit) => quote!(::syntax::parse::token::Lit::$i((quote lit))), )* - $( Lit::$raw(lit, n) => { - quote!(::syntax::parse::token::Lit::$raw((quote lit), (quote n))) - })* - } - } - } - - gen_match!(Byte, Char, Float, Str_, Integer, ByteStr; StrRaw, ByteStrRaw) - } -} - -impl Quote for token::DelimToken { - fn quote(&self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident),*) => { - match *self { - $(token::DelimToken::$i => { quote!(::syntax::parse::token::DelimToken::$i) })* - } - } - } - - gen_match!(Paren, Bracket, Brace, NoDelim) - } -} diff --git a/src/libprofiler_builtins/build.rs b/src/libprofiler_builtins/build.rs index 1ee284ff4dabf..55df14ea2150a 100644 --- a/src/libprofiler_builtins/build.rs +++ b/src/libprofiler_builtins/build.rs @@ -53,7 +53,7 @@ fn main() { } for src in profile_sources { - cfg.file(Path::new("../compiler-rt/lib/profile").join(src)); + cfg.file(Path::new("../libcompiler_builtins/compiler-rt/lib/profile").join(src)); } cfg.compile("libprofiler-rt.a"); diff --git a/src/librand/lib.rs b/src/librand/lib.rs index ca05db15ffeb9..5e56b0d8ab16c 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -31,7 +31,7 @@ issue = "27703")] #![feature(core_intrinsics)] #![feature(staged_api)] -#![feature(step_by)] +#![feature(iterator_step_by)] #![feature(custom_attribute)] #![feature(specialization)] #![allow(unused_attributes)] diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 85b1858c875bc..fa6b78045ffad 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -58,11 +58,11 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let tables = tcx.typeck_tables_of(owner_def_id); let mut cfg_builder = CFGBuilder { - tcx: tcx, + tcx, owner_def_id, - tables: tables, - graph: graph, - fn_exit: fn_exit, + tables, + graph, + fn_exit, loop_scopes: Vec::new(), breakable_block_scopes: Vec::new(), }; @@ -70,8 +70,8 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cfg_builder.add_contained_edge(body_exit, fn_exit); let CFGBuilder { graph, .. } = cfg_builder; CFG { - graph: graph, - entry: entry, + graph, + entry, exit: fn_exit, } } diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 43f8d6b938dab..ca53fd7a43311 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -36,7 +36,7 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> { pub fn new(graph: DepGraph) -> DepTrackingMap<M> { DepTrackingMap { phantom: PhantomData, - graph: graph, + graph, map: FxHashMap(), } } diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs index 116c527bf46d5..283da1050aedc 100644 --- a/src/librustc/dep_graph/query.rs +++ b/src/librustc/dep_graph/query.rs @@ -36,8 +36,8 @@ impl DepGraphQuery { } DepGraphQuery { - graph: graph, - indices: indices + graph, + indices, } } diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index 8808ea5948da8..e32acbf4756ca 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -59,7 +59,7 @@ impl ShadowGraph { ShadowGraph { stack: RefCell::new(vec![]), - forbidden_edge: forbidden_edge, + forbidden_edge, } } diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs index ad0abfe26f45f..f6635fe16f77d 100644 --- a/src/librustc/dep_graph/thread.rs +++ b/src/librustc/dep_graph/thread.rs @@ -78,7 +78,7 @@ impl DepGraphThreadData { } DepGraphThreadData { - enabled: enabled, + enabled, shadow_graph: ShadowGraph::new(), messages: VecCell::with_capacity(INITIAL_CAPACITY), swap_in: rx2, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 873d39ec9e9fb..a6a294343005c 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -126,9 +126,9 @@ pub fn lower_crate(sess: &Session, LoweringContext { crate_root: std_inject::injected_crate_name(krate), - sess: sess, + sess, parent_def: None, - resolver: resolver, + resolver, name_map: FxHashMap(), items: BTreeMap::new(), trait_items: BTreeMap::new(), @@ -251,15 +251,15 @@ impl<'a> LoweringContext<'a> { .init_node_id_to_hir_id_mapping(self.node_id_to_hir_id); hir::Crate { - module: module, - attrs: attrs, + module, + attrs, span: c.span, exported_macros: hir::HirVec::from(self.exported_macros), items: self.items, trait_items: self.trait_items, impl_items: self.impl_items, bodies: self.bodies, - body_ids: body_ids, + body_ids, trait_impls: self.trait_impls, trait_default_impl: self.trait_default_impl, } @@ -368,7 +368,7 @@ impl<'a> LoweringContext<'a> { arguments: decl.map_or(hir_vec![], |decl| { decl.inputs.iter().map(|x| self.lower_arg(x)).collect() }), - value: value + value, }; let id = body.id(); self.bodies.insert(id, body); @@ -809,7 +809,7 @@ impl<'a> LoweringContext<'a> { self.lower_path_segment(p.span, segment, param_mode, 0) }).chain(name.map(|name| { hir::PathSegment { - name: name, + name, parameters: hir::PathParameters::none() } })).collect(), @@ -857,7 +857,7 @@ impl<'a> LoweringContext<'a> { hir::PathSegment { name: self.lower_ident(segment.identifier), - parameters: parameters, + parameters, } } @@ -881,7 +881,7 @@ impl<'a> LoweringContext<'a> { hir::ParenthesizedParameterData { inputs: inputs.iter().map(|ty| self.lower_ty(ty)).collect(), output: output.as_ref().map(|ty| self.lower_ty(ty)), - span: span, + span, } } @@ -970,8 +970,8 @@ impl<'a> LoweringContext<'a> { hir::TyParam { id: self.lower_node_id(tp.id), - name: name, - bounds: bounds, + name, + bounds, default: tp.default.as_ref().map(|x| self.lower_ty(x)), span: tp.span, pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")), @@ -1081,14 +1081,14 @@ impl<'a> LoweringContext<'a> { TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, _ => Some(self.lower_ty_param_bound(bound)) }).collect(), - span: span, + span, }) } WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime, ref bounds, span}) => { hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { - span: span, + span, lifetime: self.lower_lifetime(lifetime), bounds: bounds.iter().map(|bound| self.lower_lifetime(bound)).collect(), }) @@ -1101,7 +1101,7 @@ impl<'a> LoweringContext<'a> { id: self.lower_node_id(id), lhs_ty: self.lower_ty(lhs_ty), rhs_ty: self.lower_ty(rhs_ty), - span: span, + span, }) } } @@ -1133,7 +1133,7 @@ impl<'a> LoweringContext<'a> { qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath) }; hir::TraitRef { - path: path, + path, ref_id: self.lower_node_id(p.ref_id), } } @@ -1201,10 +1201,10 @@ impl<'a> LoweringContext<'a> { P(hir::Block { id: self.lower_node_id(b.id), stmts: stmts.into(), - expr: expr, + expr, rules: self.lower_block_check_mode(&b.rules), span: b.span, - targeted_by_break: targeted_by_break, + targeted_by_break, }) } @@ -1259,8 +1259,8 @@ impl<'a> LoweringContext<'a> { name: import.rename.unwrap_or(ident).name, attrs: attrs.clone(), node: hir::ItemUse(P(path), hir::UseKind::Single), - vis: vis, - span: span, + vis, + span, }); }); } @@ -1441,7 +1441,7 @@ impl<'a> LoweringContext<'a> { name: self.lower_ident(i.ident), span: i.span, defaultness: self.lower_defaultness(Defaultness::Default, has_default), - kind: kind, + kind, } } @@ -1523,9 +1523,9 @@ impl<'a> LoweringContext<'a> { if let ItemKind::MacroDef(ref def) = i.node { if !def.legacy || i.attrs.iter().any(|attr| attr.path == "macro_export") { self.exported_macros.push(hir::MacroDef { - name: name, - vis: vis, - attrs: attrs, + name, + vis, + attrs, id: i.id, span: i.span, body: def.stream(), @@ -1541,10 +1541,10 @@ impl<'a> LoweringContext<'a> { Some(hir::Item { id: self.lower_node_id(i.id), - name: name, - attrs: attrs, - node: node, - vis: vis, + name, + attrs, + node, + vis, span: i.span, }) } @@ -1650,7 +1650,7 @@ impl<'a> LoweringContext<'a> { Some(def) => { hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path { span: pth1.span, - def: def, + def, segments: hir_vec![ hir::PathSegment::from_name(pth1.node.name) ], @@ -1887,9 +1887,9 @@ impl<'a> LoweringContext<'a> { let blk = P(hir::Block { stmts: hir_vec![], expr: Some(els), - id: id, + id, rules: hir::DefaultBlock, - span: span, + span, targeted_by_break: false, }); P(self.expr_block(blk, ThinVec::new())) @@ -2108,7 +2108,7 @@ impl<'a> LoweringContext<'a> { sub_expr, arms.into(), hir::MatchSource::IfLetDesugar { - contains_else_clause: contains_else_clause, + contains_else_clause, }) } @@ -2536,7 +2536,7 @@ impl<'a> LoweringContext<'a> { fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm { hir::Arm { attrs: hir_vec![], - pats: pats, + pats, guard: None, body: expr, } @@ -2546,10 +2546,10 @@ impl<'a> LoweringContext<'a> { hir::Field { name: Spanned { node: name, - span: span, + span, }, - span: span, - expr: expr, + span, + expr, is_shorthand: false, } } @@ -2578,8 +2578,8 @@ impl<'a> LoweringContext<'a> { }; let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(hir::Path { - span: span, - def: def, + span, + def, segments: hir_vec![hir::PathSegment::from_name(id)], }))); @@ -2619,9 +2619,9 @@ impl<'a> LoweringContext<'a> { fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec<Attribute>) -> hir::Expr { hir::Expr { id: self.next_id(), - node: node, - span: span, - attrs: attrs, + node, + span, + attrs, } } @@ -2632,7 +2632,7 @@ impl<'a> LoweringContext<'a> { source: hir::LocalSource) -> hir::Stmt { let local = P(hir::Local { - pat: pat, + pat, ty: None, init: ex, id: self.next_id(), @@ -2662,11 +2662,11 @@ impl<'a> LoweringContext<'a> { fn block_all(&mut self, span: Span, stmts: hir::HirVec<hir::Stmt>, expr: Option<P<hir::Expr>>) -> hir::Block { hir::Block { - stmts: stmts, - expr: expr, + stmts, + expr, id: self.next_id(), rules: hir::DefaultBlock, - span: span, + span, targeted_by_break: false, } } @@ -2719,15 +2719,15 @@ impl<'a> LoweringContext<'a> { }; P(hir::Pat { - id: id, + id, node: hir::PatKind::Binding(bm, def_id, Spanned { - span: span, + span, node: name, }, None), - span: span, + span, }) } @@ -2739,7 +2739,7 @@ impl<'a> LoweringContext<'a> { P(hir::Pat { id: self.next_id(), node: pat, - span: span, + span, }) } @@ -2748,7 +2748,7 @@ impl<'a> LoweringContext<'a> { /// The path is also resolved according to `is_value`. fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path { let mut path = hir::Path { - span: span, + span, def: Def::Err, segments: iter::once(keywords::CrateRoot.name()).chain({ self.crate_root.into_iter().chain(components.iter().cloned()).map(Symbol::intern) @@ -2769,9 +2769,9 @@ impl<'a> LoweringContext<'a> { let id = self.next_id(); let block = P(hir::Block { rules: rule, - span: span, - id: id, - stmts: stmts, + span, + id, + stmts, expr: Some(expr), targeted_by_break: false, }); @@ -2810,7 +2810,7 @@ impl<'a> LoweringContext<'a> { fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime { hir::Lifetime { id: self.next_id(), - span: span, + span, name: keywords::Invalid.name() } } diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index ff2f1dc1ba28a..661798a825056 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -130,9 +130,9 @@ impl<'a> ClosureParts<'a> { ClosureParts { decl: d, body: b, - id: id, + id, span: s, - attrs: attrs, + attrs, } } } @@ -149,7 +149,7 @@ impl<'a> FnLikeNode<'a> { }; if fn_like { Some(FnLikeNode { - node: node + node, }) } else { None @@ -224,12 +224,12 @@ impl<'a> FnLikeNode<'a> { id: i.id, name: i.name, decl: &decl, - unsafety: unsafety, + unsafety, body: block, - generics: generics, - abi: abi, + generics, + abi, vis: &i.vis, - constness: constness, + constness, span: i.span, attrs: &i.attrs, }), diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 904f74b8787fd..d3ae3e0e8e8ac 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -28,7 +28,7 @@ pub struct NodeCollector<'hir> { impl<'hir> NodeCollector<'hir> { pub fn root(krate: &'hir Crate) -> NodeCollector<'hir> { let mut collector = NodeCollector { - krate: krate, + krate, map: vec![], parent_node: CRATE_NODE_ID, }; diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 7fbefa5788b26..d348a5db05170 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -36,8 +36,8 @@ pub struct MacroInvocationData { impl<'a> DefCollector<'a> { pub fn new(definitions: &'a mut Definitions, expansion: Mark) -> Self { DefCollector { - definitions: definitions, - expansion: expansion, + definitions, + expansion, parent_def: None, visit_macro_invoc: None, } @@ -86,7 +86,7 @@ impl<'a> DefCollector<'a> { if let Some(ref mut visit) = self.visit_macro_invoc { visit(MacroInvocationData { mark: id.placeholder_to_mark(), - const_expr: const_expr, + const_expr, def_index: self.parent_def.unwrap(), }) } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index c969aef675ff9..d89e86ee66a66 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -190,9 +190,9 @@ impl Decodable for DefPathTable { } Ok(DefPathTable { - index_to_key: index_to_key, - key_to_index: key_to_index, - def_path_hashes: def_path_hashes, + index_to_key, + key_to_index, + def_path_hashes, }) } } @@ -578,7 +578,7 @@ impl Definitions { let mut key = DefKey { parent: Some(parent), disambiguated_data: DisambiguatedDefPathData { - data: data, + data, disambiguator: 0 } }; diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs index b3cc0c542ef9d..e6af075a2985f 100644 --- a/src/librustc/hir/map/hir_id_validator.rs +++ b/src/librustc/hir/map/hir_id_validator.rs @@ -16,7 +16,7 @@ use rustc_data_structures::fx::FxHashMap; pub fn check_crate<'hir>(hir_map: &hir::map::Map<'hir>) { let mut outer_visitor = OuterVisitor { - hir_map: hir_map, + hir_map, errors: vec![], }; @@ -49,7 +49,7 @@ impl<'a, 'hir: 'a> OuterVisitor<'a, 'hir> { hir_map: &'a hir::map::Map<'hir>) -> HirIdValidator<'a, 'hir> { HirIdValidator { - hir_map: hir_map, + hir_map, owner_def_index: None, hir_ids_seen: FxHashMap(), errors: Vec::new(), diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 02a36a372d9ef..2044d32ff9b85 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -228,7 +228,7 @@ pub struct Forest { impl Forest { pub fn new(krate: Crate, dep_graph: &DepGraph) -> Forest { Forest { - krate: krate, + krate, dep_graph: dep_graph.clone(), inlined_bodies: TypedArena::new() } @@ -1057,10 +1057,10 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest, } let map = Map { - forest: forest, + forest, dep_graph: forest.dep_graph.clone(), - map: map, - definitions: definitions, + map, + definitions, inlined_bodies: RefCell::new(DefIdMap()), }; diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 3f2977cc503df..3443c6bb2c659 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -218,7 +218,7 @@ impl PathSegment { /// Convert an identifier to the corresponding segment. pub fn from_name(name: Name) -> PathSegment { PathSegment { - name: name, + name, parameters: PathParameters::none() } } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index c6f4cd585d7b5..f32fab7d847d7 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -176,7 +176,7 @@ impl<'a> State<'a> { cur_lit: 0, }, boxes: Vec::new(), - ann: ann, + ann, } } } @@ -196,7 +196,7 @@ pub fn to_string<F>(ann: &PpAnn, f: F) -> String cur_lit: 0, }, boxes: Vec::new(), - ann: ann, + ann, }; f(&mut printer).unwrap(); eof(&mut printer.s).unwrap(); diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs index bf47b9bb9d43d..49e18f100cf26 100644 --- a/src/librustc/ich/caching_codemap_view.rs +++ b/src/librustc/ich/caching_codemap_view.rs @@ -44,7 +44,7 @@ impl<'gcx> CachingCodemapView<'gcx> { }; CachingCodemapView { - codemap: codemap, + codemap, line_cache: [entry.clone(), entry.clone(), entry.clone()], time_stamp: 0, } diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 2784a7bd024f6..8ce1b39d934d1 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -65,13 +65,13 @@ impl<'a, 'gcx, 'tcx> StableHashingContext<'a, 'gcx, 'tcx> { ignored_attr_names.sort(); StableHashingContext { - tcx: tcx, + tcx, codemap: CachingCodemapView::new(tcx), hash_spans: hash_spans_initial, hash_bodies: true, overflow_checks_enabled: check_overflow_initial, node_id_hashing_mode: NodeIdHashingMode::HashDefPath, - ignored_attr_names: ignored_attr_names, + ignored_attr_names, } } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index b9cc3b5fb937f..b827284271ed2 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -283,8 +283,7 @@ fn hash_token<'a, 'gcx, 'tcx, W: StableHasherResult>(token: &token::Token, } token::Token::Ident(ident) | - token::Token::Lifetime(ident) | - token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher), + token::Token::Lifetime(ident) => ident.name.hash_stable(hcx, hasher), token::Token::Interpolated(ref non_terminal) => { // FIXME(mw): This could be implemented properly. It's just a diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 14920b8b668ec..40e933b26a257 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -268,7 +268,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { infcx: self.infcx, span: self.trace.cause.span, for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), - ambient_variance: ambient_variance, + ambient_variance, needs_wf: false, }; diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index a0ef1f65f52ea..41858088f7e70 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -48,7 +48,7 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> TypeFreshener<'a, 'gcx, 'tcx> { TypeFreshener { - infcx: infcx, + infcx, freshen_count: 0, freshen_map: FxHashMap(), } diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index a8bc33f772d55..9cad6ce6f9fad 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -102,7 +102,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { infcx: self, type_variables: &type_variables, region_vars: ®ion_vars, - origin: origin + origin, }; Ok(value.fold_with(&mut fudger)) diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index dbbcc6cfbec6b..541a9978341f6 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -218,7 +218,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { Ok(HrMatchResult { value: a_value, - unconstrained_regions: unconstrained_regions, + unconstrained_regions, }) }); } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 5cb1606da6708..a70a4248cb75b 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -458,9 +458,9 @@ impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> { LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.trans_normalize(infcx, param_env) }, LvalueTy::Downcast { adt_def, substs, variant_index } => { LvalueTy::Downcast { - adt_def: adt_def, + adt_def, substs: substs.trans_normalize(infcx, param_env), - variant_index: variant_index + variant_index, } } } @@ -674,7 +674,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> CombineFields<'a, 'gcx, 'tcx> { CombineFields { infcx: self, - trace: trace, + trace, cause: None, param_env, obligations: PredicateObligations::new(), @@ -1235,7 +1235,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.report_and_explain_type_error( trace, &TypeError::TyParamDefaultMismatch(ExpectedFound { - expected: expected, + expected, found: actual })) .emit(); @@ -1279,7 +1279,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let span = cause.span; let match_trait_ref = match_a.skip_binder().projection_ty.trait_ref; let trace = TypeTrace { - cause: cause, + cause, values: TraitRefs(ExpectedFound::new(true, match_trait_ref, match_b)) }; @@ -1443,10 +1443,10 @@ impl<'tcx> SubregionOrigin<'tcx> { lint_id } => SubregionOrigin::CompareImplMethodObligation { span: cause.span, - item_name: item_name, - impl_item_def_id: impl_item_def_id, - trait_item_def_id: trait_item_def_id, - lint_id: lint_id, + item_name, + impl_item_def_id, + trait_item_def_id, + lint_id, }, _ => default(), diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 6f88b97334cef..4f8168982496e 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -354,7 +354,7 @@ impl<'a, 'gcx, 'tcx> TaintSet<'tcx> { impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> RegionVarBindings<'a, 'gcx, 'tcx> { RegionVarBindings { - tcx: tcx, + tcx, var_origins: RefCell::new(Vec::new()), values: RefCell::new(None), constraints: RefCell::new(FxHashMap()), @@ -378,7 +378,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { debug!("RegionVarBindings: start_snapshot({})", length); self.undo_log.borrow_mut().push(OpenSnapshot); RegionSnapshot { - length: length, + length, region_snapshot: self.unification_table.borrow_mut().snapshot(), skolemization_count: self.skolemization_count.get(), } @@ -733,10 +733,10 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { sub: Region<'tcx>, bound: VerifyBound<'tcx>) { self.add_verify(Verify { - kind: kind, - origin: origin, + kind, + origin, region: sub, - bound: bound + bound, }); } @@ -1459,7 +1459,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { ConstrainRegSubVar(region, _) | ConstrainVarSubReg(_, region) => { state.result.push(RegionAndOrigin { - region: region, + region, origin: this.constraints.borrow().get(&edge.data).unwrap().clone(), }); } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 4ae2a8026409d..cc91a637b8931 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -181,8 +181,8 @@ impl<'tcx> TypeVariableTable<'tcx> { self.sub_relations.new_key(()); let index = self.values.push(TypeVariableData { value: Bounded { default: default }, - origin: origin, - diverging: diverging + origin, + diverging, }); let v = ty::TyVid { index: index as u32 }; debug!("new_var: diverging={:?} index={:?}", diverging, v); @@ -369,7 +369,7 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate<'tcx>) { let Instantiate { vid, default } = action; values[vid.index as usize].value = Bounded { - default: default + default, }; } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index e4cf893375c75..efa6a6cccc2b6 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -84,6 +84,7 @@ pub mod infer; pub mod lint; pub mod middle { + pub mod allocator; pub mod expr_use_visitor; pub mod const_val; pub mod cstore; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 8202c6106d147..d67bca1df3022 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -140,8 +140,8 @@ impl<'a, S: Into<MultiSpan>> IntoEarlyLint for (S, &'a str) { let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg); diagnostic.set_span(span); EarlyLint { - id: id, - diagnostic: diagnostic, + id, + diagnostic, } } } @@ -149,7 +149,7 @@ impl<'a, S: Into<MultiSpan>> IntoEarlyLint for (S, &'a str) { impl IntoEarlyLint for Diagnostic { fn into_early_lint(self, id: LintId) -> EarlyLint { EarlyLint { - id: id, + id, diagnostic: self, } } @@ -805,8 +805,8 @@ impl<'a> EarlyContext<'a> { fn new(sess: &'a Session, krate: &'a ast::Crate) -> EarlyContext<'a> { EarlyContext { - sess: sess, - krate: krate, + sess, + krate, lint_sess: LintSession::new(&sess.lint_store), } } @@ -1350,10 +1350,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let krate = tcx.hir.krate(); let mut cx = LateContext { - tcx: tcx, + tcx, tables: &ty::TypeckTables::empty(), param_env: ty::ParamEnv::empty(Reveal::UserFacing), - access_levels: access_levels, + access_levels, lint_sess: LintSession::new(&tcx.sess.lint_store), }; diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index e81d09773701c..f9222ac9400af 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -294,7 +294,7 @@ impl LintId { /// Get the `LintId` for a `Lint`. pub fn of(lint: &'static Lint) -> LintId { LintId { - lint: lint, + lint, } } diff --git a/src/librustc/middle/allocator.rs b/src/librustc/middle/allocator.rs new file mode 100644 index 0000000000000..79a9ef0e8b577 --- /dev/null +++ b/src/librustc/middle/allocator.rs @@ -0,0 +1,26 @@ +// 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. + +#[derive(Clone, Copy)] +pub enum AllocatorKind { + Global, + DefaultLib, + DefaultExe, +} + +impl AllocatorKind { + pub fn fn_name(&self, base: &str) -> String { + match *self { + AllocatorKind::Global => format!("__rg_{}", base), + AllocatorKind::DefaultLib => format!("__rdl_{}", base), + AllocatorKind::DefaultExe => format!("__rde_{}", base), + } + } +} diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 7d62103e386c4..42f4c5c59d994 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -260,16 +260,16 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let nodeid_to_index = build_nodeid_to_index(body, cfg); DataFlowContext { - tcx: tcx, - analysis_name: analysis_name, - words_per_id: words_per_id, - nodeid_to_index: nodeid_to_index, - bits_per_id: bits_per_id, - oper: oper, - gens: gens, + tcx, + analysis_name, + words_per_id, + nodeid_to_index, + bits_per_id, + oper, + gens, action_kills: kills1, scope_kills: kills2, - on_entry: on_entry + on_entry, } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 6077b7863e2c3..2238e464cbcd5 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -287,6 +287,11 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { return true; } + // Don't lint about global allocators + if attr::contains_name(attrs, "global_allocator") { + return true; + } + let dead_code = lint::builtin::DEAD_CODE.name_lower(); for attr in lint::gather_attrs(attrs) { match attr { @@ -378,8 +383,8 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Seed implemented trait items let mut life_seeder = LifeSeeder { - worklist: worklist, - krate: krate, + worklist, + krate, }; krate.visit_all_item_likes(&mut life_seeder); @@ -392,8 +397,8 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> Box<FxHashSet<ast::NodeId>> { let worklist = create_and_seed_worklist(tcx, access_levels, krate); let mut symbol_visitor = MarkSymbolVisitor { - worklist: worklist, - tcx: tcx, + worklist, + tcx, tables: &ty::TypeckTables::empty(), live_symbols: box FxHashSet(), struct_has_extern_repr: false, diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 4e1f06cca06cc..9af93d0d49424 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -214,10 +214,9 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // // Things like allocators and panic runtimes may not have been activated // quite yet, so do so here. - activate_injected_dep(sess.injected_allocator.get(), &mut ret, - &|cnum| tcx.is_allocator(cnum.as_def_id())); activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret, &|cnum| tcx.is_panic_runtime(cnum.as_def_id())); + activate_injected_allocator(sess, &mut ret); // When dylib B links to dylib A, then when using B we must also link to A. // It could be the case, however, that the rlib for A is present (hence we @@ -295,10 +294,9 @@ fn attempt_static<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<DependencyLis // Our allocator/panic runtime may not have been linked above if it wasn't // explicitly linked, which is the case for any injected dependency. Handle // that here and activate them. - activate_injected_dep(sess.injected_allocator.get(), &mut ret, - &|cnum| tcx.is_allocator(cnum.as_def_id())); activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret, &|cnum| tcx.is_panic_runtime(cnum.as_def_id())); + activate_injected_allocator(sess, &mut ret); Some(ret) } @@ -331,6 +329,18 @@ fn activate_injected_dep(injected: Option<CrateNum>, } } +fn activate_injected_allocator(sess: &session::Session, + list: &mut DependencyList) { + let cnum = match sess.injected_allocator.get() { + Some(cnum) => cnum, + None => return, + }; + let idx = cnum.as_usize() - 1; + if list[idx] == Linkage::NotLinked { + list[idx] = Linkage::Static; + } +} + // After the linkage for a crate has been determined we need to verify that // there's only going to be one allocator in the output. fn verify_ok<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, list: &[Linkage]) { @@ -338,23 +348,12 @@ fn verify_ok<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, list: &[Linkage]) { if list.len() == 0 { return } - let mut allocator = None; let mut panic_runtime = None; for (i, linkage) in list.iter().enumerate() { if let Linkage::NotLinked = *linkage { continue } let cnum = CrateNum::new(i + 1); - if tcx.is_allocator(cnum.as_def_id()) { - if let Some(prev) = allocator { - let prev_name = sess.cstore.crate_name(prev); - let cur_name = sess.cstore.crate_name(cnum); - sess.err(&format!("cannot link together two \ - allocators: {} and {}", - prev_name, cur_name)); - } - allocator = Some(cnum); - } if tcx.is_panic_runtime(cnum.as_def_id()) { if let Some((prev, _)) = panic_runtime { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index eab5a8f910331..abd5cbcb89e33 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -261,7 +261,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut visitor = EffectCheckVisitor { - tcx: tcx, + tcx, tables: &ty::TypeckTables::empty(), body_id: hir::BodyId { node_id: ast::CRATE_NODE_ID }, unsafe_context: UnsafeContext::new(SafeContext), diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index b26cccf5f1617..31e054ec1cb93 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -71,7 +71,7 @@ pub fn find_entry_point(session: &Session, hir_map: &hir_map::Map) { } let mut ctxt = EntryContext { - session: session, + session, map: hir_map, main_fn: None, attr_main_fn: None, diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index fde207e4b2f79..d29622b4a8159 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -20,7 +20,7 @@ use hir; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut visitor = ItemVisitor { - tcx: tcx + tcx, }; tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 3b506d748ef7a..01ed79096b101 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -156,10 +156,10 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { $( item_refs.insert($name, $variant as usize); )* LanguageItemCollector { - session: session, - hir_map: hir_map, + session, + hir_map, items: LanguageItems::new(), - item_refs: item_refs, + item_refs, } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index c6a42be6135cc..551a550442b3d 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -269,7 +269,7 @@ struct IrMaps<'a, 'tcx: 'a> { impl<'a, 'tcx> IrMaps<'a, 'tcx> { fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> IrMaps<'a, 'tcx> { IrMaps { - tcx: tcx, + tcx, num_live_nodes: 0, num_vars: 0, live_node_map: NodeMap(), @@ -385,7 +385,7 @@ fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) { ir.add_live_node_for_node(p_id, VarDefNode(sp)); ir.add_variable(Local(LocalInfo { id: p_id, - name: name + name, })); }); intravisit::walk_local(ir, local); @@ -400,7 +400,7 @@ fn visit_arm<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, arm: &'tcx hir::Arm) { ir.add_live_node_for_node(p_id, VarDefNode(sp)); ir.add_variable(Local(LocalInfo { id: p_id, - name: name + name, })); }) } @@ -534,8 +534,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let num_vars = ir.num_vars; Liveness { - ir: ir, - tables: tables, + ir, + tables, s: specials, successors: vec![invalid_node(); num_live_nodes], users: vec![invalid_users(); num_live_nodes * num_vars], diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 5c741eccf83c7..557d4b24f3032 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -656,8 +656,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Def::Local(def_id) => { let vid = self.tcx.hir.as_local_node_id(def_id).unwrap(); Ok(Rc::new(cmt_ { - id: id, - span: span, + id, + span, cat: Categorization::Local(vid), mutbl: MutabilityCategory::from_local(self.tcx, vid), ty: expr_ty, @@ -706,7 +706,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { None => span_bug!(span, "missing closure kind") }; - let upvar_id = ty::UpvarId { var_id: var_id, + let upvar_id = ty::UpvarId { var_id, closure_expr_id: fn_node_id }; let var_ty = self.node_ty(var_id)?; @@ -717,8 +717,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // from the environment (perhaps we should eventually desugar // this field further, but it will do for now). let cmt_result = cmt_ { - id: id, - span: span, + id, + span, cat: Categorization::Upvar(Upvar {id: upvar_id, kind: kind}), mutbl: var_mutbl, ty: var_ty, @@ -743,7 +743,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // If this is a by-ref capture, then the upvar we loaded is // actually a reference, so we have to add an implicit deref // for that. - let upvar_id = ty::UpvarId { var_id: var_id, + let upvar_id = ty::UpvarId { var_id, closure_expr_id: fn_node_id }; let upvar_capture = self.tables.upvar_capture(upvar_id); let cmt_result = match upvar_capture { @@ -753,8 +753,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ty::UpvarCapture::ByRef(upvar_borrow) => { let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region); cmt_ { - id: id, - span: span, + id, + span, cat: Categorization::Deref(Rc::new(cmt_result), ptr), mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind), ty: var_ty, @@ -813,8 +813,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } let ret = cmt_ { - id: id, - span: span, + id, + span, cat: Categorization::Deref(Rc::new(cmt_result), env_ptr), mutbl: deref_mutbl, ty: var_ty, diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index c2f69147e3a56..df828c8d8e71a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -374,11 +374,11 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> *ty == config::CrateTypeProcMacro }); let mut reachable_context = ReachableContext { - tcx: tcx, + tcx, tables: &ty::TypeckTables::empty(), reachable_symbols: NodeSet(), worklist: Vec::new(), - any_library: any_library, + any_library, }; // Step 1: Seed the worklist with all nodes which were found to be public as @@ -398,8 +398,8 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> } { let mut collect_private_impl_items = CollectPrivateImplItemsVisitor { - tcx: tcx, - access_levels: access_levels, + tcx, + access_levels, worklist: &mut reachable_context.worklist, }; tcx.hir.krate().visit_all_item_likes(&mut collect_private_impl_items); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index b347a93185124..c4f785757cee1 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -266,8 +266,8 @@ pub fn krate(sess: &Session, }; sess.track_errors(|| { let mut visitor = LifetimeContext { - sess: sess, - hir_map: hir_map, + sess, + hir_map, map: &mut map, scope: ROOT_SCOPE, trait_ref_hack: false, @@ -341,7 +341,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { Region::early(&mut index, def) }).collect(); let scope = Scope::Binder { - lifetimes: lifetimes, + lifetimes, s: ROOT_SCOPE }; self.with(scope, |old_scope, this| { @@ -777,13 +777,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let xcrate_object_lifetime_defaults = replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap()); let mut this = LifetimeContext { - sess: sess, - hir_map: hir_map, + sess, + hir_map, map: *map, scope: &wrap_scope, trait_ref_hack: self.trait_ref_hack, - labels_in_fn: labels_in_fn, - xcrate_object_lifetime_defaults: xcrate_object_lifetime_defaults, + labels_in_fn, + xcrate_object_lifetime_defaults, }; debug!("entering scope {:?}", this.scope); f(self.scope, &mut this); @@ -849,7 +849,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }).collect(); let scope = Scope::Binder { - lifetimes: lifetimes, + lifetimes, s: self.scope }; self.with(scope, move |old_scope, this| { @@ -1206,7 +1206,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }; let scope = Scope::Elision { - elide: elide, + elide, s: self.scope }; self.with(scope, |_, this| this.visit_ty(output)); @@ -1620,7 +1620,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, map.issue_32330.insert( lifetime.lifetime.id, ty::Issue32330 { - fn_def_id: fn_def_id, + fn_def_id, region_name: name, }); continue; diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index e27990c29cf9e..668a8693d3a84 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -70,14 +70,14 @@ impl DeprecationEntry { fn local(attr: Deprecation, id: DefId) -> DeprecationEntry { assert!(id.is_local()); DeprecationEntry { - attr: attr, + attr, origin: Some(id.index), } } fn external(attr: Deprecation) -> DeprecationEntry { DeprecationEntry { - attr: attr, + attr, origin: None, } } @@ -384,7 +384,7 @@ impl<'a, 'tcx> Index<'tcx> { let krate = tcx.hir.krate(); let mut annotator = Annotator { - tcx: tcx, + tcx, index: self, parent_stab: None, parent_depr: None, @@ -424,7 +424,7 @@ impl<'a, 'tcx> Index<'tcx> { let mut staged_api = FxHashMap(); staged_api.insert(LOCAL_CRATE, is_staged_api); Index { - staged_api: staged_api, + staged_api, stab_map: DefIdMap(), depr_map: DefIdMap(), active_features: FxHashSet(), @@ -717,8 +717,8 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { if tcx.stability.borrow().staged_api[&LOCAL_CRATE] { let krate = tcx.hir.krate(); let mut missing = MissingStabilityAnnotations { - tcx: tcx, - access_levels: access_levels, + tcx, + access_levels, }; missing.check_missing_stability(ast::CRATE_NODE_ID, krate.span); intravisit::walk_crate(&mut missing, krate); @@ -728,6 +728,7 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let ref declared_lib_features = sess.features.borrow().declared_lib_features; let mut remaining_lib_features: FxHashMap<Symbol, Span> = declared_lib_features.clone().into_iter().collect(); + remaining_lib_features.remove(&Symbol::intern("proc_macro")); fn format_stable_since_msg(version: &str) -> String { format!("this feature has been stable since {}. Attribute no longer needed", version) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index c8d03e7b30588..96ccc3ba50078 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -136,15 +136,15 @@ impl<'tcx> Mir<'tcx> { assert_eq!(local_decls[RETURN_POINTER].ty, return_ty); Mir { - basic_blocks: basic_blocks, - visibility_scopes: visibility_scopes, - promoted: promoted, - return_ty: return_ty, - local_decls: local_decls, - arg_count: arg_count, - upvar_decls: upvar_decls, + basic_blocks, + visibility_scopes, + promoted, + return_ty, + local_decls, + arg_count, + upvar_decls, spread_arg: None, - span: span, + span, cache: cache::Cache::new() } } @@ -395,10 +395,10 @@ impl<'tcx> LocalDecl<'tcx> { pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self { LocalDecl { mutability: Mutability::Mut, - ty: ty, + ty, name: None, source_info: SourceInfo { - span: span, + span, scope: ARGUMENT_VISIBILITY_SCOPE }, is_user_variable: false @@ -414,7 +414,7 @@ impl<'tcx> LocalDecl<'tcx> { mutability: Mutability::Mut, ty: return_ty, source_info: SourceInfo { - span: span, + span, scope: ARGUMENT_VISIBILITY_SCOPE }, name: None, // FIXME maybe we do want some name here? @@ -629,7 +629,7 @@ impl<'tcx> BasicBlockData<'tcx> { pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> { BasicBlockData { statements: vec![], - terminator: terminator, + terminator, is_cleanup: false, } } @@ -941,7 +941,7 @@ impl<'tcx> Lvalue<'tcx> { pub fn elem(self, elem: LvalueElem<'tcx>) -> Lvalue<'tcx> { Lvalue::Projection(Box::new(LvalueProjection { base: self, - elem: elem, + elem, })) } } @@ -1023,7 +1023,7 @@ impl<'tcx> Operand<'tcx> { span: Span, ) -> Self { Operand::Constant(box Constant { - span: span, + span, ty: tcx.type_of(def_id).subst(tcx, substs), literal: Literal::Value { value: ConstVal::Function(def_id, substs) }, }) @@ -1470,7 +1470,7 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { Assign(ref lval, ref rval) => Assign(lval.fold_with(folder), rval.fold_with(folder)), SetDiscriminant { ref lvalue, variant_index } => SetDiscriminant { lvalue: lvalue.fold_with(folder), - variant_index: variant_index + variant_index, }, StorageLive(ref lval) => StorageLive(lval.fold_with(folder)), StorageDead(ref lval) => StorageDead(lval.fold_with(folder)), @@ -1490,7 +1490,7 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { }; Statement { source_info: self.source_info, - kind: kind + kind, } } @@ -1530,14 +1530,14 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { }, Drop { ref location, target, unwind } => Drop { location: location.fold_with(folder), - target: target, - unwind: unwind + target, + unwind, }, DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace { location: location.fold_with(folder), value: value.fold_with(folder), - target: target, - unwind: unwind + target, + unwind, }, Call { ref func, ref args, ref destination, cleanup } => { let dest = destination.as_ref().map(|&(ref loc, dest)| { @@ -1548,7 +1548,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { func: func.fold_with(folder), args: args.fold_with(folder), destination: dest, - cleanup: cleanup + cleanup, } }, Assert { ref cond, expected, ref msg, target, cleanup } => { @@ -1562,10 +1562,10 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { }; Assert { cond: cond.fold_with(folder), - expected: expected, - msg: msg, - target: target, - cleanup: cleanup + expected, + msg, + target, + cleanup, } }, Resume => Resume, @@ -1574,7 +1574,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { }; Terminator { source_info: self.source_info, - kind: kind + kind, } } @@ -1716,8 +1716,8 @@ impl<'tcx, B, V> TypeFoldable<'tcx> for Projection<'tcx, B, V> }; Projection { - base: base, - elem: elem + base, + elem, } } @@ -1750,7 +1750,7 @@ impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { Literal::Item { def_id, substs } => Literal::Item { - def_id: def_id, + def_id, substs: substs.fold_with(folder) }, _ => self.clone() diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 6078778a61d50..71acb36ecf75d 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -58,7 +58,7 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { }) .ty; LvalueTy::Ty { - ty: ty, + ty, } } ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => @@ -85,8 +85,8 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { assert!(adt_def.is_enum()); assert!(index < adt_def.variants.len()); assert_eq!(adt_def, adt_def1); - LvalueTy::Downcast { adt_def: adt_def, - substs: substs, + LvalueTy::Downcast { adt_def, + substs, variant_index: index } } _ => { @@ -104,9 +104,9 @@ impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> { LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.fold_with(folder) }, LvalueTy::Downcast { adt_def, substs, variant_index } => { LvalueTy::Downcast { - adt_def: adt_def, + adt_def, substs: substs.fold_with(folder), - variant_index: variant_index + variant_index, } } } diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index 6057e7ec7e0f5..5aab46b3cefb4 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -44,9 +44,9 @@ impl<'a, 'tcx> Preorder<'a, 'tcx> { let worklist = vec![root]; Preorder { - mir: mir, + mir, visited: BitVector::new(mir.basic_blocks().len()), - worklist: worklist + worklist, } } } @@ -106,7 +106,7 @@ pub struct Postorder<'a, 'tcx: 'a> { impl<'a, 'tcx> Postorder<'a, 'tcx> { pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> { let mut po = Postorder { - mir: mir, + mir, visited: BitVector::new(mir.basic_blocks().len()), visit_stack: Vec::new() }; @@ -251,8 +251,8 @@ impl<'a, 'tcx> ReversePostorder<'a, 'tcx> { let len = blocks.len(); ReversePostorder { - mir: mir, - blocks: blocks, + mir, + blocks, idx: len } } diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs index 215539de6766e..118b84113a0ff 100644 --- a/src/librustc/session/code_stats.rs +++ b/src/librustc/session/code_stats.rs @@ -82,12 +82,12 @@ impl CodeStats { opt_discr_size: Option<Size>, variants: Vec<VariantInfo>) { let info = TypeSizeInfo { - kind: kind, + kind, type_description: type_desc.to_string(), align: align.abi(), overall_size: overall_size.bytes(), opt_discr_size: opt_discr_size.map(|s| s.bytes()), - variants: variants, + variants, }; self.type_sizes.insert(info); } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 4f7ad5ea939f1..240f000a424c0 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1122,9 +1122,9 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config { }; Config { - target: target, - int_type: int_type, - uint_type: uint_type, + target, + int_type, + uint_type, } } @@ -1150,7 +1150,7 @@ impl RustcOptGroup { where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, { RustcOptGroup { - name: name, + name, apply: Box::new(f), stability: OptionStability::Stable, } @@ -1160,7 +1160,7 @@ impl RustcOptGroup { where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static, { RustcOptGroup { - name: name, + name, apply: Box::new(f), stability: OptionStability::Unstable, } @@ -1627,28 +1627,28 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m)); (Options { - crate_types: crate_types, + crate_types, optimize: opt_level, - debuginfo: debuginfo, - lint_opts: lint_opts, - lint_cap: lint_cap, - describe_lints: describe_lints, + debuginfo, + lint_opts, + lint_cap, + describe_lints, output_types: OutputTypes(output_types), - search_paths: search_paths, + search_paths, maybe_sysroot: sysroot_opt, target_triple: target, - test: test, - incremental: incremental, - debugging_opts: debugging_opts, - prints: prints, - cg: cg, - error_format: error_format, + test, + incremental, + debugging_opts, + prints, + cg, + error_format, externs: Externs(externs), - crate_name: crate_name, + crate_name, alt_std_name: None, - libs: libs, + libs, unstable_features: UnstableFeatures::from_environment(), - debug_assertions: debug_assertions, + debug_assertions, actually_rustdoc: false, }, cfg) diff --git a/src/librustc/session/filesearch.rs b/src/librustc/session/filesearch.rs index 47b988a21b4c1..1004b2826022a 100644 --- a/src/librustc/session/filesearch.rs +++ b/src/librustc/session/filesearch.rs @@ -104,10 +104,10 @@ impl<'a> FileSearch<'a> { kind: PathKind) -> FileSearch<'a> { debug!("using sysroot = {}, triple = {}", sysroot.display(), triple); FileSearch { - sysroot: sysroot, - search_paths: search_paths, - triple: triple, - kind: kind, + sysroot, + search_paths, + triple, + kind, } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 8bafdda234a09..fe6b24f3e1f2a 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -16,6 +16,7 @@ use hir::def_id::{CrateNum, DefIndex}; use lint; use middle::cstore::CrateStore; +use middle::allocator::AllocatorKind; use middle::dependency_format; use session::search_paths::PathKind; use session::config::DebugInfoLevel; @@ -106,6 +107,7 @@ pub struct Session { /// dependency if it didn't already find one, and this tracks what was /// injected. pub injected_allocator: Cell<Option<CrateNum>>, + pub allocator_kind: Cell<Option<AllocatorKind>>, pub injected_panic_runtime: Cell<Option<CrateNum>>, /// Map from imported macro spans (which consist of @@ -140,6 +142,9 @@ pub struct Session { /// Loaded up early on in the initialization of this `Session` to avoid /// false positives about a job server in our environment. pub jobserver_from_env: Option<Client>, + + /// Metadata about the allocators for the current crate being compiled + pub has_global_allocator: Cell<bool>, } pub struct PerfStats { @@ -480,7 +485,7 @@ impl Session { *incr_comp_session = IncrCompSession::Active { session_directory: session_dir, - lock_file: lock_file, + lock_file, }; } @@ -510,7 +515,7 @@ impl Session { // Note: This will also drop the lock file, thus unlocking the directory *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { - session_directory: session_directory + session_directory, }; } @@ -690,18 +695,18 @@ pub fn build_session_(sopts: config::Options, let sess = Session { dep_graph: dep_graph.clone(), target: target_cfg, - host: host, + host, opts: sopts, - cstore: cstore, + cstore, parse_sess: p_s, // For a library crate, this is always none entry_fn: RefCell::new(None), entry_type: Cell::new(None), plugin_registrar_fn: Cell::new(None), derive_registrar_fn: Cell::new(None), - default_sysroot: default_sysroot, - local_crate_source_file: local_crate_source_file, - working_dir: working_dir, + default_sysroot, + local_crate_source_file, + working_dir, lint_store: RefCell::new(lint::LintStore::new()), lints: RefCell::new(lint::LintTable::new()), one_time_diagnostics: RefCell::new(FxHashSet()), @@ -715,6 +720,7 @@ pub fn build_session_(sopts: config::Options, type_length_limit: Cell::new(1048576), next_node_id: Cell::new(NodeId::new(1)), injected_allocator: Cell::new(None), + allocator_kind: Cell::new(None), injected_panic_runtime: Cell::new(None), imported_macro_spans: RefCell::new(HashMap::new()), incr_comp_session: RefCell::new(IncrCompSession::NotInitialized), @@ -727,12 +733,11 @@ pub fn build_session_(sopts: config::Options, decode_def_path_tables_time: Cell::new(Duration::from_secs(0)), }, code_stats: RefCell::new(CodeStats::new()), - optimization_fuel_crate: optimization_fuel_crate, - optimization_fuel_limit: optimization_fuel_limit, - print_fuel_crate: print_fuel_crate, - print_fuel: print_fuel, + optimization_fuel_crate, + optimization_fuel_limit, + print_fuel_crate, + print_fuel, out_of_fuel: Cell::new(false), - // Note that this is unsafe because it may misinterpret file descriptors // on Unix as jobserver file descriptors. We hopefully execute this near // the beginning of the process though to ensure we don't get false @@ -750,6 +755,7 @@ pub fn build_session_(sopts: config::Options, }); (*GLOBAL_JOBSERVER).clone() }, + has_global_allocator: Cell::new(false), }; sess diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 54fe3a42b6179..34df447a11e15 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -47,7 +47,7 @@ fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, ' let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id); let header = ty::ImplHeader { - impl_def_id: impl_def_id, + impl_def_id, self_ty: tcx.type_of(impl_def_id), trait_ref: tcx.impl_trait_ref(impl_def_id), predicates: tcx.predicates_of(impl_def_id).predicates @@ -102,7 +102,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, .chain(&b_impl_header.predicates) .map(|p| infcx.resolve_type_vars_if_possible(p)) .map(|p| Obligation { cause: ObligationCause::dummy(), - param_env: param_env, + param_env, recursion_depth: 0, predicate: p }) .chain(obligations) diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 16ecc94b9476a..d0bb1adbabb2d 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -152,11 +152,11 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { cause: ObligationCause<'tcx>) { let trait_ref = ty::TraitRef { - def_id: def_id, + def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]), }; self.register_predicate_obligation(infcx, Obligation { - cause: cause, + cause, recursion_depth: 0, param_env, predicate: trait_ref.to_predicate() @@ -191,7 +191,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { } self.predicates.register_obligation(PendingPredicateObligation { - obligation: obligation, + obligation, stalled_on: vec![] }); } @@ -259,7 +259,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { // Process pending obligations. let outcome = self.predicates.process_obligations(&mut FulfillProcessor { - selcx: selcx, + selcx, region_obligations: &mut self.region_obligations, }); debug!("select: outcome={:?}", outcome); @@ -606,7 +606,7 @@ impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> { pub fn new(dep_graph: DepGraph) -> GlobalFulfilledPredicates<'gcx> { GlobalFulfilledPredicates { set: FxHashSet(), - dep_graph: dep_graph, + dep_graph, } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 16c41c816b4eb..6b243ffa5feb5 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -396,7 +396,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx infcx.tcx.item_path_str(def_id)); let trait_ref = ty::TraitRef { - def_id: def_id, + def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]), }; let obligation = Obligation { diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index c356e53234d9c..14b6d4605e89f 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -245,11 +245,11 @@ impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> { -> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> { AssociatedTypeNormalizer { - selcx: selcx, - param_env: param_env, - cause: cause, + selcx, + param_env, + cause, obligations: vec![], - depth: depth, + depth, } } @@ -371,7 +371,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( let ty_var = selcx.infcx().next_ty_var( TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id))); let projection = ty::Binder(ty::ProjectionPredicate { - projection_ty: projection_ty, + projection_ty, ty: ty_var }); let obligation = Obligation::with_depth( @@ -514,12 +514,12 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( obligations.extend(normalizer.obligations); Normalized { value: normalized_ty, - obligations: obligations, + obligations, } } else { Normalized { value: projected_ty, - obligations: obligations, + obligations, } }; infcx.projection_cache.borrow_mut() @@ -586,7 +586,7 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc -> NormalizedTy<'tcx> { let trait_ref = projection_ty.trait_ref.to_poly_trait_ref(); - let trait_obligation = Obligation { cause: cause, + let trait_obligation = Obligation { cause, recursion_depth: depth, param_env, predicate: trait_ref.to_predicate() }; @@ -1232,7 +1232,7 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( Ok(InferOk { value: ty_match, obligations }) => { Progress { ty: ty_match.value, - obligations: obligations, + obligations, cacheable: ty_match.unconstrained_regions.is_empty(), } } @@ -1306,7 +1306,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name { return specialization_graph::NodeItem { node: specialization_graph::Node::Impl(impl_def_id), - item: item, + item, }; } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 856fea7c2c437..4d4693f1c6468 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -212,7 +212,7 @@ impl<'a, 'tcx> ty::Lift<'tcx> for SelectionCandidate<'a> { Some(match *self { BuiltinCandidate { has_nested } => { BuiltinCandidate { - has_nested: has_nested + has_nested, } } ImplCandidate(def_id) => ImplCandidate(def_id), @@ -290,7 +290,7 @@ pub struct EvaluationCache<'tcx> { impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { pub fn new(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>) -> SelectionContext<'cx, 'gcx, 'tcx> { SelectionContext { - infcx: infcx, + infcx, freshener: infcx.freshener(), intercrate: false, inferred_obligations: SnapshotVec::new(), @@ -299,7 +299,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>) -> SelectionContext<'cx, 'gcx, 'tcx> { SelectionContext { - infcx: infcx, + infcx, freshener: infcx.freshener(), intercrate: true, inferred_obligations: SnapshotVec::new(), @@ -2205,7 +2205,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("vtable_default_impl: obligations={:?}", obligations); VtableDefaultImplData { - trait_def_id: trait_def_id, + trait_def_id, nested: obligations } } @@ -2273,7 +2273,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // e.g. `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V` impl_obligations.append(&mut substs.obligations); - VtableImplData { impl_def_id: impl_def_id, + VtableImplData { impl_def_id, substs: substs.value, nested: impl_obligations } } @@ -2336,7 +2336,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), - vtable_base: vtable_base, + vtable_base, nested: vec![] } } @@ -2405,7 +2405,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::Predicate::ClosureKind(closure_def_id, kind))); Ok(VtableClosureData { - closure_def_id: closure_def_id, + closure_def_id, substs: substs.clone(), nested: obligations }) @@ -2826,8 +2826,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener); TraitObligationStack { - obligation: obligation, - fresh_trait_ref: fresh_trait_ref, + obligation, + fresh_trait_ref, previous: previous_stack, } } @@ -2911,7 +2911,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { predicate.obligations.into_iter().chain( Some(Obligation { cause: cause.clone(), - recursion_depth: recursion_depth, + recursion_depth, param_env, predicate: predicate.value })) diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index c4479e6903267..f1c176561ea48 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -209,15 +209,15 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { trait_item_def_id, lint_id } => { Some(super::CompareImplMethodObligation { - item_name: item_name, - impl_item_def_id: impl_item_def_id, - trait_item_def_id: trait_item_def_id, - lint_id: lint_id, + item_name, + impl_item_def_id, + trait_item_def_id, + lint_id, }) } super::ExprAssignable => Some(super::ExprAssignable), super::MatchExpressionArm { arm_span, source } => { - Some(super::MatchExpressionArm { arm_span: arm_span, + Some(super::MatchExpressionArm { arm_span, source: source }) } super::IfExpression => Some(super::IfExpression), @@ -253,7 +253,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> { traits::ObligationCause { span: self.span, body_id: self.body_id, - code: code, + code, } }) } @@ -271,9 +271,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { }) => { tcx.lift(&substs).map(|substs| { traits::VtableImpl(traits::VtableImplData { - impl_def_id: impl_def_id, - substs: substs, - nested: nested + impl_def_id, + substs, + nested, }) }) } @@ -285,17 +285,17 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { }) => { tcx.lift(&substs).map(|substs| { traits::VtableClosure(traits::VtableClosureData { - closure_def_id: closure_def_id, - substs: substs, - nested: nested + closure_def_id, + substs, + nested, }) }) } traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => { tcx.lift(&fn_ty).map(|fn_ty| { traits::VtableFnPointer(traits::VtableFnPointerData { - fn_ty: fn_ty, - nested: nested, + fn_ty, + nested, }) }) } @@ -309,8 +309,8 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { tcx.lift(&upcast_trait_ref).map(|trait_ref| { traits::VtableObject(traits::VtableObjectData { upcast_trait_ref: trait_ref, - vtable_base: vtable_base, - nested: nested + vtable_base, + nested, }) }) } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index c385927811cf7..dae0c896909c8 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -288,7 +288,7 @@ pub fn supertrait_def_ids<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>, -> SupertraitDefIds<'cx, 'gcx, 'tcx> { SupertraitDefIds { - tcx: tcx, + tcx, stack: vec![trait_def_id], visited: Some(trait_def_id).into_iter().collect(), } @@ -399,8 +399,8 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, generic_bounds.predicates.iter().map(|predicate| { Obligation { cause: cause.clone(), - recursion_depth: recursion_depth, - param_env: param_env, + recursion_depth, + param_env, predicate: predicate.clone() } }).collect() } @@ -413,9 +413,9 @@ pub fn predicate_for_trait_ref<'tcx>( -> PredicateObligation<'tcx> { Obligation { - cause: cause, - param_env: param_env, - recursion_depth: recursion_depth, + cause, + param_env, + recursion_depth, predicate: trait_ref.to_predicate(), } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 5f869fc5567ee..316f871a7a46c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -107,7 +107,7 @@ pub struct CtxtInterners<'tcx> { impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { fn new(arena: &'tcx DroplessArena) -> CtxtInterners<'tcx> { CtxtInterners { - arena: arena, + arena, type_: RefCell::new(FxHashSet()), type_list: RefCell::new(FxHashSet()), substs: RefCell::new(FxHashSet()), @@ -732,12 +732,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { global_interners: interners, dep_graph: dep_graph.clone(), types: common_types, - named_region_map: named_region_map, + named_region_map, trait_map: resolutions.trait_map, export_map: resolutions.export_map, fulfilled_predicates: RefCell::new(fulfilled_predicates), - hir: hir, - def_path_hash_to_def_id: def_path_hash_to_def_id, + hir, + def_path_hash_to_def_id, maps: maps::Maps::new(providers), mir_passes, freevars: RefCell::new(resolutions.freevars), @@ -745,7 +745,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { rcache: RefCell::new(FxHashMap()), normalized_cache: RefCell::new(FxHashMap()), inhabitedness_cache: RefCell::new(FxHashMap()), - lang_items: lang_items, + lang_items, used_unsafe: RefCell::new(NodeSet()), used_mut_nodes: RefCell::new(NodeSet()), stability: RefCell::new(stability), @@ -753,7 +753,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { evaluation_cache: traits::EvaluationCache::new(), rvalue_promotable_to_static: RefCell::new(NodeMap()), crate_name: Symbol::intern(crate_name), - data_layout: data_layout, + data_layout, layout_interner: RefCell::new(FxHashSet()), layout_depth: Cell::new(0), derive_macros: RefCell::new(NodeMap()), @@ -964,8 +964,8 @@ pub mod tls { let prev = tls.get(); tls.set(Some((gcx_ptr, interners_ptr))); let ret = f(TyCtxt { - gcx: gcx, - interners: interners + gcx, + interners, }); tls.set(prev); ret @@ -980,8 +980,8 @@ pub mod tls { let gcx = unsafe { &*(gcx as *const GlobalCtxt) }; let interners = unsafe { &*(interners as *const CtxtInterners) }; f(TyCtxt { - gcx: gcx, - interners: interners + gcx, + interners, }) }) } @@ -1408,7 +1408,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { self.mk_closure_from_closure_substs(closure_id, ClosureSubsts { - substs: substs + substs, }) } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index bb13031a2b7c4..66868040925e1 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -238,10 +238,10 @@ impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> { where F : FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx> { RegionFolder { - tcx: tcx, - skipped_regions: skipped_regions, + tcx, + skipped_regions, current_depth: 1, - fld_r: fld_r, + fld_r, } } } @@ -393,9 +393,9 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx> { RegionReplacer { - tcx: tcx, + tcx, current_depth: 1, - fld_r: fld_r, + fld_r, map: FxHashMap() } } @@ -621,7 +621,7 @@ impl LateBoundRegionsCollector { LateBoundRegionsCollector { current_depth: 1, regions: FxHashSet(), - just_constrained: just_constrained, + just_constrained, } } } diff --git a/src/librustc/ty/inhabitedness/def_id_forest.rs b/src/librustc/ty/inhabitedness/def_id_forest.rs index 6801e82fe7476..231600f95ac60 100644 --- a/src/librustc/ty/inhabitedness/def_id_forest.rs +++ b/src/librustc/ty/inhabitedness/def_id_forest.rs @@ -52,7 +52,7 @@ impl<'a, 'gcx, 'tcx> DefIdForest { let mut root_ids = SmallVec::new(); root_ids.push(id); DefIdForest { - root_ids: root_ids, + root_ids, } } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index b9896e0cecf5d..73b577e2e876b 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -397,7 +397,7 @@ struct LocalPathBuffer { impl LocalPathBuffer { fn new(root_mode: RootMode) -> LocalPathBuffer { LocalPathBuffer { - root_mode: root_mode, + root_mode, str: String::new(), } } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index e1aa89078a33b..3212c6f07d1d6 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -609,7 +609,7 @@ impl<'a, 'tcx> Struct { }; let mut ret = Struct { - align: align, + align, primitive_align: align, packed: repr.packed(), sized: true, @@ -910,10 +910,10 @@ impl<'a, 'tcx> Union { fn new(dl: &TargetDataLayout, packed: bool) -> Union { let align = if packed { dl.i8_align } else { dl.aggregate_align }; Union { - align: align, + align, primitive_align: align, min_size: Size::from_bytes(0), - packed: packed, + packed, } } @@ -1169,8 +1169,8 @@ impl<'a, 'tcx> Layout { sized: true, align: element.align(dl), primitive_align: element.primitive_align(dl), - element_size: element_size, - count: count + element_size, + count, } } ty::TySlice(element) => { @@ -1280,9 +1280,9 @@ impl<'a, 'tcx> Layout { // grok. let (discr, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max); return success(CEnum { - discr: discr, - signed: signed, - non_zero: non_zero, + discr, + signed, + non_zero, // FIXME: should be u128? min: min as u64, max: max as u64 @@ -1364,7 +1364,7 @@ impl<'a, 'tcx> Layout { }; return success(RawNullablePointer { nndiscr: discr as u64, - value: value, + value, }); } @@ -1491,10 +1491,10 @@ impl<'a, 'tcx> Layout { General { discr: ity, - variants: variants, - size: size, - align: align, - primitive_align: primitive_align + variants, + size, + align, + primitive_align, } } @@ -1957,7 +1957,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> { ty::TyParam(_) | ty::TyProjection(_) => { assert!(tail.has_param_types() || tail.has_self_ty()); Ok(SizeSkeleton::Pointer { - non_zero: non_zero, + non_zero, tail: tcx.erase_regions(&tail) }) } @@ -2016,7 +2016,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> { return Ok(SizeSkeleton::Pointer { non_zero: non_zero || Some(def.did) == tcx.lang_items.non_zero(), - tail: tail + tail, }); } else { return Err(err); @@ -2030,7 +2030,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> { (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => { Ok(SizeSkeleton::Pointer { non_zero: false, - tail: tail + tail, }) } _ => Err(err) @@ -2115,7 +2115,7 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for LayoutCx<'a, 'tcx> { let ty = self.normalize_projections(ty); Ok(TyLayout { - ty: ty, + ty, layout: ty.layout(self.tcx, self.param_env)?, variant_index: None }) diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index a6c59d4c22354..f4e333228c94d 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if let Some((i, _)) = stack.iter().enumerate().rev() .find(|&(_, &(_, ref q))| *q == query) { return Err(CycleError { - span: span, + span, cycle: RefMut::map(stack, |stack| &mut stack[i..]) }); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 548ee7bcbe503..88aef53ec9de5 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -964,8 +964,8 @@ impl<'tcx> TraitPredicate<'tcx> { .next() .unwrap_or(trait_def_id); DepNode::new(tcx, DepConstructor::TraitSelect { - trait_def_id: trait_def_id, - input_def_id: input_def_id + trait_def_id, + input_def_id, }) } @@ -1244,12 +1244,12 @@ impl<'tcx> ParamEnv<'tcx> { if value.has_param_types() || value.has_self_ty() { ParamEnvAnd { param_env: self, - value: value, + value, } } else { ParamEnvAnd { param_env: ParamEnv::empty(self.reveal), - value: value, + value, } } } @@ -1487,10 +1487,10 @@ impl<'a, 'gcx, 'tcx> AdtDef { AdtKind::Struct => {} } AdtDef { - did: did, - variants: variants, - flags: flags, - repr: repr, + did, + variants, + flags, + repr, } } @@ -2113,11 +2113,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { AssociatedItem { name: trait_item_ref.name, - kind: kind, + kind, // Visibility of trait items is inherited from their traits. vis: Visibility::from_hir(parent_vis, trait_item_ref.id.node_id, self), defaultness: trait_item_ref.defaultness, - def_id: def_id, + def_id, container: TraitContainer(parent_def_id), method_has_self_argument: has_self } @@ -2138,11 +2138,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::AssociatedItem { name: impl_item_ref.name, - kind: kind, + kind, // Visibility of trait impl items doesn't matter. vis: ty::Visibility::from_hir(&impl_item_ref.vis, impl_item_ref.id.node_id, self), defaultness: impl_item_ref.defaultness, - def_id: def_id, + def_id, container: ImplContainer(parent_def_id), method_has_self_argument: has_self } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 2e9780572c9b4..7710cc965c8f0 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -182,8 +182,8 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { Ok(ty::FnSig { inputs_and_output: relation.tcx().intern_type_list(&inputs_and_output), variadic: a.variadic, - unsafety: unsafety, - abi: abi + unsafety, + abi, }) } } @@ -250,9 +250,9 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { let trait_ref = relation.relate(&a.trait_ref, &b.trait_ref)?; let ty = relation.relate(&a.ty, &b.ty)?; Ok(ty::ExistentialProjection { - trait_ref: trait_ref, + trait_ref, item_name: a.item_name, - ty: ty + ty, }) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index d05262965d7fd..478717eaca097 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -78,7 +78,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { tcx.lift(&self.substs).map(|substs| ty::TraitRef { def_id: self.def_id, - substs: substs + substs, }) } } @@ -88,7 +88,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { tcx.lift(&self.substs).map(|substs| ty::ExistentialTraitRef { def_id: self.def_id, - substs: substs + substs, }) } } @@ -98,7 +98,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<ty::TraitPredicate<'tcx>> { tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate { - trait_ref: trait_ref + trait_ref, }) } } @@ -117,8 +117,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> { -> Option<ty::SubtypePredicate<'tcx>> { tcx.lift(&(self.a, self.b)).map(|(a, b)| ty::SubtypePredicate { a_is_expected: self.a_is_expected, - a: a, - b: b, + a, + b, }) } } @@ -146,8 +146,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> { -> Option<ty::ProjectionPredicate<'tcx>> { tcx.lift(&(self.projection_ty, self.ty)).map(|(projection_ty, ty)| { ty::ProjectionPredicate { - projection_ty: projection_ty, - ty: ty + projection_ty, + ty, } }) } @@ -158,9 +158,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { tcx.lift(&(self.trait_ref, self.ty)).map(|(trait_ref, ty)| { ty::ExistentialProjection { - trait_ref: trait_ref, + trait_ref, item_name: self.item_name, - ty: ty + ty, } }) } @@ -300,8 +300,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound<T> { tcx.lift(&self.expected).and_then(|expected| { tcx.lift(&self.found).map(|found| { ty::error::ExpectedFound { - expected: expected, - found: found + expected, + found, } }) }) @@ -313,7 +313,7 @@ impl<'a, 'tcx> Lift<'tcx> for type_variable::Default<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { tcx.lift(&self.ty).map(|ty| { type_variable::Default { - ty: ty, + ty, origin_span: self.origin_span, def_id: self.def_id } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 452775e9e1337..737e69b658348 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -571,8 +571,8 @@ impl<'a, 'tcx> ProjectionTy<'tcx> { |item| item.name == item_name).unwrap().def_id; ProjectionTy { - trait_ref: trait_ref, - item_def_id: item_def_id, + trait_ref, + item_def_id, } } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index d0d61323392c7..f6112d4887d7d 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -352,9 +352,9 @@ impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T { span: Option<Span>) -> T { - let mut folder = SubstFolder { tcx: tcx, - substs: substs, - span: span, + let mut folder = SubstFolder { tcx, + substs, + span, root_ty: None, ty_stack_depth: 0, region_binders_passed: 0 }; diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 2eb0acac4f7ec..91bc56155969a 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -31,10 +31,10 @@ pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span) -> Option<Vec<traits::PredicateObligation<'tcx>>> { - let mut wf = WfPredicates { infcx: infcx, - param_env: param_env, - body_id: body_id, - span: span, + let mut wf = WfPredicates { infcx, + param_env, + body_id, + span, out: vec![] }; if wf.compute(ty) { debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); diff --git a/src/libproc_macro_plugin/Cargo.toml b/src/librustc_allocator/Cargo.toml similarity index 64% rename from src/libproc_macro_plugin/Cargo.toml rename to src/librustc_allocator/Cargo.toml index 146a66cdf01cb..e3d1d8e32c4b7 100644 --- a/src/libproc_macro_plugin/Cargo.toml +++ b/src/librustc_allocator/Cargo.toml @@ -1,13 +1,15 @@ [package] authors = ["The Rust Project Developers"] -name = "proc_macro_plugin" +name = "rustc_allocator" version = "0.0.0" [lib] path = "lib.rs" crate-type = ["dylib"] +test = false [dependencies] -rustc_plugin = { path = "../librustc_plugin" } +rustc = { path = "../librustc" } +rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs new file mode 100644 index 0000000000000..e942b7264c589 --- /dev/null +++ b/src/librustc_allocator/expand.rs @@ -0,0 +1,498 @@ +// 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. + +use rustc::middle::allocator::AllocatorKind; +use rustc_errors; +use syntax::abi::Abi; +use syntax::ast::{Crate, Attribute, LitKind, StrStyle, ExprKind}; +use syntax::ast::{Unsafety, Constness, Generics, Mutability, Ty, Mac, Arg}; +use syntax::ast::{self, Ident, Item, ItemKind, TyKind, Visibility, Expr}; +use syntax::attr; +use syntax::codemap::dummy_spanned; +use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; +use syntax::ext::base::ExtCtxt; +use syntax::ext::base::Resolver; +use syntax::ext::build::AstBuilder; +use syntax::ext::expand::ExpansionConfig; +use syntax::ext::hygiene::{Mark, SyntaxContext}; +use syntax::fold::{self, Folder}; +use syntax::parse::ParseSess; +use syntax::ptr::P; +use syntax::symbol::Symbol; +use syntax::util::small_vector::SmallVector; +use syntax_pos::{Span, DUMMY_SP}; + +use {AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; + +pub fn modify(sess: &ParseSess, + resolver: &mut Resolver, + krate: Crate, + handler: &rustc_errors::Handler) -> ast::Crate { + ExpandAllocatorDirectives { + handler: handler, + sess: sess, + resolver: resolver, + found: false, + }.fold_crate(krate) +} + +struct ExpandAllocatorDirectives<'a> { + found: bool, + handler: &'a rustc_errors::Handler, + sess: &'a ParseSess, + resolver: &'a mut Resolver, +} + +impl<'a> Folder for ExpandAllocatorDirectives<'a> { + fn fold_item(&mut self, item: P<Item>) -> SmallVector<P<Item>> { + let name = if attr::contains_name(&item.attrs, "global_allocator") { + "global_allocator" + } else { + return fold::noop_fold_item(item, self) + }; + match item.node { + ItemKind::Static(..) => {} + _ => { + self.handler.span_err(item.span, "allocators must be statics"); + return SmallVector::one(item) + } + } + + if self.found { + self.handler.span_err(item.span, "cannot define more than one \ + #[global_allocator]"); + return SmallVector::one(item) + } + self.found = true; + + let mark = Mark::fresh(Mark::root()); + mark.set_expn_info(ExpnInfo { + call_site: DUMMY_SP, + callee: NameAndSpan { + format: MacroAttribute(Symbol::intern(name)), + span: None, + allow_internal_unstable: true, + } + }); + let span = Span { + ctxt: SyntaxContext::empty().apply_mark(mark), + ..item.span + }; + let ecfg = ExpansionConfig::default(name.to_string()); + let mut f = AllocFnFactory { + span: span, + kind: AllocatorKind::Global, + global: item.ident, + alloc: Ident::from_str("alloc"), + cx: ExtCtxt::new(self.sess, ecfg, self.resolver), + }; + let super_path = f.cx.path(f.span, vec![ + Ident::from_str("super"), + f.global, + ]); + let mut items = vec![ + f.cx.item_extern_crate(f.span, f.alloc), + f.cx.item_use_simple(f.span, Visibility::Inherited, super_path), + ]; + for method in ALLOCATOR_METHODS { + items.push(f.allocator_fn(method)); + } + let name = f.kind.fn_name("allocator_abi"); + let allocator_abi = Ident::with_empty_ctxt(Symbol::gensym(&name)); + let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items); + let module = f.cx.monotonic_expander().fold_item(module).pop().unwrap(); + + let mut ret = SmallVector::new(); + ret.push(item); + ret.push(module); + return ret + } + + fn fold_mac(&mut self, mac: Mac) -> Mac { + fold::noop_fold_mac(mac, self) + } +} + +struct AllocFnFactory<'a> { + span: Span, + kind: AllocatorKind, + global: Ident, + alloc: Ident, + cx: ExtCtxt<'a>, +} + +impl<'a> AllocFnFactory<'a> { + fn allocator_fn(&self, method: &AllocatorMethod) -> P<Item> { + let mut abi_args = Vec::new(); + let mut i = 0; + let ref mut mk = || { + let name = Ident::from_str(&format!("arg{}", i)); + i += 1; + name + }; + let args = method.inputs.iter().map(|ty| { + self.arg_ty(ty, &mut abi_args, mk) + }).collect(); + let result = self.call_allocator(method.name, args); + let (output_ty, output_expr) = + self.ret_ty(&method.output, &mut abi_args, mk, result); + let kind = ItemKind::Fn(self.cx.fn_decl(abi_args, output_ty), + Unsafety::Unsafe, + dummy_spanned(Constness::NotConst), + Abi::Rust, + Generics::default(), + self.cx.block_expr(output_expr)); + self.cx.item(self.span, + Ident::from_str(&self.kind.fn_name(method.name)), + self.attrs(), + kind) + } + + fn call_allocator(&self, method: &str, mut args: Vec<P<Expr>>) -> P<Expr> { + let method = self.cx.path(self.span, vec![ + self.alloc, + Ident::from_str("heap"), + Ident::from_str("Alloc"), + Ident::from_str(method), + ]); + let method = self.cx.expr_path(method); + let allocator = self.cx.path_ident(self.span, self.global); + let allocator = self.cx.expr_path(allocator); + let allocator = self.cx.expr_addr_of(self.span, allocator); + let allocator = self.cx.expr_mut_addr_of(self.span, allocator); + args.insert(0, allocator); + + self.cx.expr_call(self.span, method, args) + } + + fn attrs(&self) -> Vec<Attribute> { + let key = Symbol::intern("linkage"); + let value = LitKind::Str(Symbol::intern("external"), StrStyle::Cooked); + let linkage = self.cx.meta_name_value(self.span, key, value); + + let no_mangle = Symbol::intern("no_mangle"); + let no_mangle = self.cx.meta_word(self.span, no_mangle); + vec![ + self.cx.attribute(self.span, linkage), + self.cx.attribute(self.span, no_mangle), + ] + } + + fn arg_ty(&self, + ty: &AllocatorTy, + args: &mut Vec<Arg>, + mut ident: &mut FnMut() -> Ident) -> P<Expr> { + match *ty { + AllocatorTy::Layout => { + let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); + let ty_usize = self.cx.ty_path(usize); + let size = ident(); + let align = ident(); + args.push(self.cx.arg(self.span, size, ty_usize.clone())); + args.push(self.cx.arg(self.span, align, ty_usize)); + + let layout_new = self.cx.path(self.span, vec![ + self.alloc, + Ident::from_str("heap"), + Ident::from_str("Layout"), + Ident::from_str("from_size_align_unchecked"), + ]); + let layout_new = self.cx.expr_path(layout_new); + let size = self.cx.expr_ident(self.span, size); + let align = self.cx.expr_ident(self.span, align); + let layout = self.cx.expr_call(self.span, + layout_new, + vec![size, align]); + layout + } + + AllocatorTy::LayoutRef => { + let ident = ident(); + args.push(self.cx.arg(self.span, ident, self.ptr_u8())); + + // Convert our `arg: *const u8` via: + // + // &*(arg as *const Layout) + let expr = self.cx.expr_ident(self.span, ident); + let expr = self.cx.expr_cast(self.span, expr, self.layout_ptr()); + let expr = self.cx.expr_deref(self.span, expr); + self.cx.expr_addr_of(self.span, expr) + } + + AllocatorTy::AllocErr => { + // We're creating: + // + // (*(arg as *const AllocErr)).clone() + let ident = ident(); + args.push(self.cx.arg(self.span, ident, self.ptr_u8())); + let expr = self.cx.expr_ident(self.span, ident); + let expr = self.cx.expr_cast(self.span, expr, self.alloc_err_ptr()); + let expr = self.cx.expr_deref(self.span, expr); + self.cx.expr_method_call( + self.span, + expr, + Ident::from_str("clone"), + Vec::new() + ) + } + + AllocatorTy::Ptr => { + let ident = ident(); + args.push(self.cx.arg(self.span, ident, self.ptr_u8())); + self.cx.expr_ident(self.span, ident) + } + + AllocatorTy::ResultPtr | + AllocatorTy::ResultExcess | + AllocatorTy::ResultUnit | + AllocatorTy::Bang | + AllocatorTy::UsizePair | + AllocatorTy::Unit => { + panic!("can't convert AllocatorTy to an argument") + } + } + } + + fn ret_ty(&self, + ty: &AllocatorTy, + args: &mut Vec<Arg>, + mut ident: &mut FnMut() -> Ident, + expr: P<Expr>) -> (P<Ty>, P<Expr>) + { + match *ty { + AllocatorTy::UsizePair => { + // We're creating: + // + // let arg = #expr; + // *min = arg.0; + // *max = arg.1; + + let min = ident(); + let max = ident(); + + args.push(self.cx.arg(self.span, min, self.ptr_usize())); + args.push(self.cx.arg(self.span, max, self.ptr_usize())); + + let ident = ident(); + let stmt = self.cx.stmt_let(self.span, false, ident, expr); + let min = self.cx.expr_ident(self.span, min); + let max = self.cx.expr_ident(self.span, max); + let layout = self.cx.expr_ident(self.span, ident); + let assign_min = self.cx.expr(self.span, ExprKind::Assign( + self.cx.expr_deref(self.span, min), + self.cx.expr_tup_field_access(self.span, layout.clone(), 0), + )); + let assign_min = self.cx.stmt_semi(assign_min); + let assign_max = self.cx.expr(self.span, ExprKind::Assign( + self.cx.expr_deref(self.span, max), + self.cx.expr_tup_field_access(self.span, layout.clone(), 1), + )); + let assign_max = self.cx.stmt_semi(assign_max); + + let stmts = vec![stmt, assign_min, assign_max]; + let block = self.cx.block(self.span, stmts); + let ty_unit = self.cx.ty(self.span, TyKind::Tup(Vec::new())); + (ty_unit, self.cx.expr_block(block)) + } + + AllocatorTy::ResultExcess => { + // We're creating: + // + // match #expr { + // Ok(ptr) => { + // *excess = ptr.1; + // ptr.0 + // } + // Err(e) => { + // ptr::write(err_ptr, e); + // 0 as *mut u8 + // } + // } + + let excess_ptr = ident(); + args.push(self.cx.arg(self.span, excess_ptr, self.ptr_usize())); + let excess_ptr = self.cx.expr_ident(self.span, excess_ptr); + + let err_ptr = ident(); + args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8())); + let err_ptr = self.cx.expr_ident(self.span, err_ptr); + let err_ptr = self.cx.expr_cast(self.span, + err_ptr, + self.alloc_err_ptr()); + + let name = ident(); + let ok_expr = { + let ptr = self.cx.expr_ident(self.span, name); + let write = self.cx.expr(self.span, ExprKind::Assign( + self.cx.expr_deref(self.span, excess_ptr), + self.cx.expr_tup_field_access(self.span, ptr.clone(), 1), + )); + let write = self.cx.stmt_semi(write); + let ret = self.cx.expr_tup_field_access(self.span, + ptr.clone(), + 0); + let ret = self.cx.stmt_expr(ret); + let block = self.cx.block(self.span, vec![write, ret]); + self.cx.expr_block(block) + }; + let pat = self.cx.pat_ident(self.span, name); + let ok = self.cx.path_ident(self.span, Ident::from_str("Ok")); + let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]); + let ok = self.cx.arm(self.span, vec![ok], ok_expr); + + let name = ident(); + let err_expr = { + let err = self.cx.expr_ident(self.span, name); + let write = self.cx.path(self.span, vec![ + self.alloc, + Ident::from_str("heap"), + Ident::from_str("__core"), + Ident::from_str("ptr"), + Ident::from_str("write"), + ]); + let write = self.cx.expr_path(write); + let write = self.cx.expr_call(self.span, write, + vec![err_ptr, err]); + let write = self.cx.stmt_semi(write); + let null = self.cx.expr_usize(self.span, 0); + let null = self.cx.expr_cast(self.span, null, self.ptr_u8()); + let null = self.cx.stmt_expr(null); + let block = self.cx.block(self.span, vec![write, null]); + self.cx.expr_block(block) + }; + let pat = self.cx.pat_ident(self.span, name); + let err = self.cx.path_ident(self.span, Ident::from_str("Err")); + let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]); + let err = self.cx.arm(self.span, vec![err], err_expr); + + let expr = self.cx.expr_match(self.span, expr, vec![ok, err]); + (self.ptr_u8(), expr) + } + + AllocatorTy::ResultPtr => { + // We're creating: + // + // match #expr { + // Ok(ptr) => ptr, + // Err(e) => { + // ptr::write(err_ptr, e); + // 0 as *mut u8 + // } + // } + + let err_ptr = ident(); + args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8())); + let err_ptr = self.cx.expr_ident(self.span, err_ptr); + let err_ptr = self.cx.expr_cast(self.span, + err_ptr, + self.alloc_err_ptr()); + + let name = ident(); + let ok_expr = self.cx.expr_ident(self.span, name); + let pat = self.cx.pat_ident(self.span, name); + let ok = self.cx.path_ident(self.span, Ident::from_str("Ok")); + let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]); + let ok = self.cx.arm(self.span, vec![ok], ok_expr); + + let name = ident(); + let err_expr = { + let err = self.cx.expr_ident(self.span, name); + let write = self.cx.path(self.span, vec![ + self.alloc, + Ident::from_str("heap"), + Ident::from_str("__core"), + Ident::from_str("ptr"), + Ident::from_str("write"), + ]); + let write = self.cx.expr_path(write); + let write = self.cx.expr_call(self.span, write, + vec![err_ptr, err]); + let write = self.cx.stmt_semi(write); + let null = self.cx.expr_usize(self.span, 0); + let null = self.cx.expr_cast(self.span, null, self.ptr_u8()); + let null = self.cx.stmt_expr(null); + let block = self.cx.block(self.span, vec![write, null]); + self.cx.expr_block(block) + }; + let pat = self.cx.pat_ident(self.span, name); + let err = self.cx.path_ident(self.span, Ident::from_str("Err")); + let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]); + let err = self.cx.arm(self.span, vec![err], err_expr); + + let expr = self.cx.expr_match(self.span, expr, vec![ok, err]); + (self.ptr_u8(), expr) + } + + AllocatorTy::ResultUnit => { + // We're creating: + // + // #expr.is_ok() as u8 + + let cast = self.cx.expr_method_call( + self.span, + expr, + Ident::from_str("is_ok"), + Vec::new() + ); + let u8 = self.cx.path_ident(self.span, Ident::from_str("u8")); + let u8 = self.cx.ty_path(u8); + let cast = self.cx.expr_cast(self.span, cast, u8.clone()); + (u8, cast) + } + + AllocatorTy::Bang => { + (self.cx.ty(self.span, TyKind::Never), expr) + } + + AllocatorTy::Unit => { + (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr) + } + + AllocatorTy::AllocErr | + AllocatorTy::Layout | + AllocatorTy::LayoutRef | + AllocatorTy::Ptr => { + panic!("can't convert AllocatorTy to an output") + } + } + } + + fn ptr_u8(&self) -> P<Ty> { + let u8 = self.cx.path_ident(self.span, Ident::from_str("u8")); + let ty_u8 = self.cx.ty_path(u8); + self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) + } + + fn ptr_usize(&self) -> P<Ty> { + let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); + let ty_usize = self.cx.ty_path(usize); + self.cx.ty_ptr(self.span, ty_usize, Mutability::Mutable) + } + + fn layout_ptr(&self) -> P<Ty> { + let layout = self.cx.path(self.span, vec![ + self.alloc, + Ident::from_str("heap"), + Ident::from_str("Layout"), + ]); + let layout = self.cx.ty_path(layout); + self.cx.ty_ptr(self.span, layout, Mutability::Mutable) + } + + fn alloc_err_ptr(&self) -> P<Ty> { + let err = self.cx.path(self.span, vec![ + self.alloc, + Ident::from_str("heap"), + Ident::from_str("AllocErr"), + ]); + let err = self.cx.ty_path(err); + self.cx.ty_ptr(self.span, err, Mutability::Mutable) + } +} diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs new file mode 100644 index 0000000000000..d0ea40d1e361d --- /dev/null +++ b/src/librustc_allocator/lib.rs @@ -0,0 +1,101 @@ +// 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(rustc_private)] + +extern crate rustc; +extern crate rustc_errors; +extern crate syntax; +extern crate syntax_pos; + +pub mod expand; + +pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ + AllocatorMethod { + name: "alloc", + inputs: &[AllocatorTy::Layout], + output: AllocatorTy::ResultPtr, + is_unsafe: true, + }, + AllocatorMethod { + name: "oom", + inputs: &[AllocatorTy::AllocErr], + output: AllocatorTy::Bang, + is_unsafe: false, + }, + AllocatorMethod { + name: "dealloc", + inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], + output: AllocatorTy::Unit, + is_unsafe: true, + }, + AllocatorMethod { + name: "usable_size", + inputs: &[AllocatorTy::LayoutRef], + output: AllocatorTy::UsizePair, + is_unsafe: false, + }, + AllocatorMethod { + name: "realloc", + inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], + output: AllocatorTy::ResultPtr, + is_unsafe: true, + }, + AllocatorMethod { + name: "alloc_zeroed", + inputs: &[AllocatorTy::Layout], + output: AllocatorTy::ResultPtr, + is_unsafe: true, + }, + AllocatorMethod { + name: "alloc_excess", + inputs: &[AllocatorTy::Layout], + output: AllocatorTy::ResultExcess, + is_unsafe: true, + }, + AllocatorMethod { + name: "realloc_excess", + inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], + output: AllocatorTy::ResultExcess, + is_unsafe: true, + }, + AllocatorMethod { + name: "grow_in_place", + inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], + output: AllocatorTy::ResultUnit, + is_unsafe: true, + }, + AllocatorMethod { + name: "shrink_in_place", + inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], + output: AllocatorTy::ResultUnit, + is_unsafe: true, + }, +]; + +pub struct AllocatorMethod { + pub name: &'static str, + pub inputs: &'static [AllocatorTy], + pub output: AllocatorTy, + pub is_unsafe: bool, +} + +pub enum AllocatorTy { + AllocErr, + Bang, + Layout, + LayoutRef, + Ptr, + ResultExcess, + ResultPtr, + ResultUnit, + Unit, + UsizePair, +} diff --git a/src/librustc_asan/Cargo.toml b/src/librustc_asan/Cargo.toml index 0fda2805feac8..8f8ef1cc4a011 100644 --- a/src/librustc_asan/Cargo.toml +++ b/src/librustc_asan/Cargo.toml @@ -14,5 +14,6 @@ build_helper = { path = "../build_helper" } cmake = "0.1.18" [dependencies] +alloc = { path = "../liballoc" } alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs index 54941362e8450..e987b1f335e19 100644 --- a/src/librustc_asan/lib.rs +++ b/src/librustc_asan/lib.rs @@ -11,6 +11,8 @@ #![sanitizer_runtime] #![feature(sanitizer_runtime)] #![feature(alloc_system)] +#![cfg_attr(not(stage0), feature(allocator_api))] +#![cfg_attr(not(stage0), feature(global_allocator))] #![feature(staged_api)] #![no_std] #![unstable(feature = "sanitizer_runtime_lib", @@ -18,3 +20,10 @@ issue = "0")] extern crate alloc_system; + +#[cfg(not(stage0))] +use alloc_system::System; + +#[cfg(not(stage0))] +#[global_allocator] +static ALLOC: System = System; diff --git a/src/librustc_back/target/aarch64_unknown_freebsd.rs b/src/librustc_back/target/aarch64_unknown_freebsd.rs index c5cfff0be03ad..c5427a13e4c7d 100644 --- a/src/librustc_back/target/aarch64_unknown_freebsd.rs +++ b/src/librustc_back/target/aarch64_unknown_freebsd.rs @@ -16,7 +16,7 @@ pub fn target() -> TargetResult { base.max_atomic_width = Some(128); // see #36994 - base.exe_allocation_crate = "alloc_system".to_string(); + base.exe_allocation_crate = None; Ok(Target { llvm_target: "aarch64-unknown-freebsd".to_string(), diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index 043bd881c7290..7c2c45a2843a7 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -16,7 +16,7 @@ pub fn target() -> TargetResult { base.max_atomic_width = Some(128); // see #36994 - base.exe_allocation_crate = "alloc_system".to_string(); + base.exe_allocation_crate = None; Ok(Target { llvm_target: "aarch64-unknown-linux-gnu".to_string(), diff --git a/src/librustc_back/target/bitrig_base.rs b/src/librustc_back/target/bitrig_base.rs index 62418e68d4341..5c4e01886a434 100644 --- a/src/librustc_back/target/bitrig_base.rs +++ b/src/librustc_back/target/bitrig_base.rs @@ -19,7 +19,6 @@ pub fn opts() -> TargetOptions { linker_is_gnu: true, has_rpath: true, position_independent_executables: true, - exe_allocation_crate: "alloc_system".to_string(), .. Default::default() } diff --git a/src/librustc_back/target/fuchsia_base.rs b/src/librustc_back/target/fuchsia_base.rs index c6207cdc4d9c1..63ccd21c220f3 100644 --- a/src/librustc_back/target/fuchsia_base.rs +++ b/src/librustc_back/target/fuchsia_base.rs @@ -37,7 +37,6 @@ pub fn opts() -> TargetOptions { has_rpath: true, pre_link_args: args, position_independent_executables: true, - exe_allocation_crate: "alloc_system".to_string(), has_elf_tls: true, .. Default::default() } diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs index 038a70ed6b17e..2d77902046109 100644 --- a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs @@ -29,7 +29,7 @@ pub fn target() -> TargetResult { max_atomic_width: Some(64), // see #36994 - exe_allocation_crate: "alloc_system".to_string(), + exe_allocation_crate: None, ..super::linux_base::opts() }, diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs index aed4c4fbb08de..c26780b9e65ce 100644 --- a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs @@ -29,7 +29,7 @@ pub fn target() -> TargetResult { max_atomic_width: Some(64), // see #36994 - exe_allocation_crate: "alloc_system".to_string(), + exe_allocation_crate: None, ..super::linux_base::opts() }, diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index 9ef61f9caddcd..24649851d76fd 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -28,7 +28,7 @@ pub fn target() -> TargetResult { max_atomic_width: Some(32), // see #36994 - exe_allocation_crate: "alloc_system".to_string(), + exe_allocation_crate: None, ..super::linux_base::opts() }, diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs index f54790bab970b..6303722945c9f 100644 --- a/src/librustc_back/target/mips_unknown_linux_musl.rs +++ b/src/librustc_back/target/mips_unknown_linux_musl.rs @@ -28,7 +28,7 @@ pub fn target() -> TargetResult { max_atomic_width: Some(32), // see #36994 - exe_allocation_crate: "alloc_system".to_string(), + exe_allocation_crate: None, ..super::linux_base::opts() } diff --git a/src/librustc_back/target/mips_unknown_linux_uclibc.rs b/src/librustc_back/target/mips_unknown_linux_uclibc.rs index 59c07efe0fdc1..1a7a56a977921 100644 --- a/src/librustc_back/target/mips_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mips_unknown_linux_uclibc.rs @@ -28,7 +28,7 @@ pub fn target() -> TargetResult { max_atomic_width: Some(32), // see #36994 - exe_allocation_crate: "alloc_system".to_string(), + exe_allocation_crate: None, ..super::linux_base::opts() }, diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index ec19cc1a536ad..cbf8339993c86 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -29,7 +29,7 @@ pub fn target() -> TargetResult { max_atomic_width: Some(32), // see #36994 - exe_allocation_crate: "alloc_system".to_string(), + exe_allocation_crate: None, ..super::linux_base::opts() }, diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs index 00085d18e6d09..b367bce75a1d9 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs @@ -28,7 +28,7 @@ pub fn target() -> TargetResult { max_atomic_width: Some(32), // see #36994 - exe_allocation_crate: "alloc_system".to_string(), + exe_allocation_crate: None, ..super::linux_base::opts() } diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs index b3ca2edec1eda..686dfbe987d10 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs @@ -29,7 +29,7 @@ pub fn target() -> TargetResult { max_atomic_width: Some(32), // see #36994 - exe_allocation_crate: "alloc_system".to_string(), + exe_allocation_crate: None, ..super::linux_base::opts() }, diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 5df227e39acbd..983a98e350c6a 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -378,9 +378,8 @@ pub struct TargetOptions { /// `eh_unwind_resume` lang item. pub custom_unwind_resume: bool, - /// Default crate for allocation symbols to link against - pub lib_allocation_crate: String, - pub exe_allocation_crate: String, + /// If necessary, a different crate to link exe allocators by default + pub exe_allocation_crate: Option<String>, /// Flag indicating whether ELF TLS (e.g. #[thread_local]) is available for /// this target. @@ -457,8 +456,7 @@ impl Default for TargetOptions { link_env: Vec::new(), archive_format: "gnu".to_string(), custom_unwind_resume: false, - lib_allocation_crate: "alloc_system".to_string(), - exe_allocation_crate: "alloc_system".to_string(), + exe_allocation_crate: None, allow_asm: true, has_elf_tls: false, obj_is_bitcode: false, @@ -682,8 +680,7 @@ impl Target { key!(archive_format); key!(allow_asm, bool); key!(custom_unwind_resume, bool); - key!(lib_allocation_crate); - key!(exe_allocation_crate); + key!(exe_allocation_crate, optional); key!(has_elf_tls, bool); key!(obj_is_bitcode, bool); key!(no_integrated_as, bool); @@ -869,7 +866,6 @@ impl ToJson for Target { target_option_val!(archive_format); target_option_val!(allow_asm); target_option_val!(custom_unwind_resume); - target_option_val!(lib_allocation_crate); target_option_val!(exe_allocation_crate); target_option_val!(has_elf_tls); target_option_val!(obj_is_bitcode); @@ -889,10 +885,10 @@ impl ToJson for Target { } } -fn maybe_jemalloc() -> String { +fn maybe_jemalloc() -> Option<String> { if cfg!(feature = "jemalloc") { - "alloc_jemalloc".to_string() + Some("alloc_jemalloc".to_string()) } else { - "alloc_system".to_string() + None } } diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index 2df9b8e03ff53..051028d5c4a77 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -34,7 +34,6 @@ pub fn opts() -> TargetOptions { is_like_openbsd: true, pre_link_args: args, position_independent_executables: true, - exe_allocation_crate: "alloc_system".to_string(), .. Default::default() } } diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs index 55a5bfd1e6746..718a79a685e06 100644 --- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs @@ -18,7 +18,7 @@ pub fn target() -> TargetResult { base.max_atomic_width = Some(64); // see #36994 - base.exe_allocation_crate = "alloc_system".to_string(); + base.exe_allocation_crate = None; Ok(Target { llvm_target: "powerpc64-unknown-linux-gnu".to_string(), diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs index c22bc3b041a4e..5b50b96837fbe 100644 --- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs @@ -18,7 +18,7 @@ pub fn target() -> TargetResult { base.max_atomic_width = Some(64); // see #36994 - base.exe_allocation_crate = "alloc_system".to_string(); + base.exe_allocation_crate = None; Ok(Target { llvm_target: "powerpc64le-unknown-linux-gnu".to_string(), diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs index 677d198b1a379..8d4ad5f0b447f 100644 --- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs @@ -17,7 +17,7 @@ pub fn target() -> TargetResult { base.max_atomic_width = Some(32); // see #36994 - base.exe_allocation_crate = "alloc_system".to_string(); + base.exe_allocation_crate = None; Ok(Target { llvm_target: "powerpc-unknown-linux-gnu".to_string(), diff --git a/src/librustc_back/target/redox_base.rs b/src/librustc_back/target/redox_base.rs index f26a86d4bdc0f..2eae0a1240823 100644 --- a/src/librustc_back/target/redox_base.rs +++ b/src/librustc_back/target/redox_base.rs @@ -36,8 +36,6 @@ pub fn opts() -> TargetOptions { eliminate_frame_pointer: false, target_family: None, linker_is_gnu: true, - lib_allocation_crate: "alloc_system".to_string(), - exe_allocation_crate: "alloc_system".to_string(), has_elf_tls: true, panic_strategy: PanicStrategy::Abort, .. Default::default() diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs index cc8eb7c4e8424..78a6bb7933d95 100644 --- a/src/librustc_back/target/s390x_unknown_linux_gnu.rs +++ b/src/librustc_back/target/s390x_unknown_linux_gnu.rs @@ -21,7 +21,7 @@ pub fn target() -> TargetResult { base.features = "-vector".to_string(); base.max_atomic_width = Some(64); // see #36994 - base.exe_allocation_crate = "alloc_system".to_string(); + base.exe_allocation_crate = None; Ok(Target { llvm_target: "s390x-unknown-linux-gnu".to_string(), diff --git a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs b/src/librustc_back/target/sparc64_unknown_linux_gnu.rs index 1bd51ac62581f..7f710ad402053 100644 --- a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/sparc64_unknown_linux_gnu.rs @@ -15,7 +15,7 @@ pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "v9".to_string(); base.max_atomic_width = Some(64); - base.exe_allocation_crate = "alloc_system".to_string(); + base.exe_allocation_crate = None; Ok(Target { llvm_target: "sparc64-unknown-linux-gnu".to_string(), diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs index 421f59aea93bf..c07321e418e64 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -63,7 +63,6 @@ pub fn opts() -> TargetOptions { is_like_windows: true, is_like_msvc: true, pre_link_args: args, - exe_allocation_crate: "alloc_system".to_string(), .. Default::default() } diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs index eea4389cfd64e..ec5cc197dfc1a 100644 --- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs +++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs @@ -24,7 +24,7 @@ pub fn target() -> TargetResult { base.position_independent_executables = false; base.disable_redzone = true; base.no_default_libraries = false; - base.exe_allocation_crate = "alloc_system".to_string(); + base.exe_allocation_crate = None; Ok(Target { llvm_target: "x86_64-rumprun-netbsd".to_string(), diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 2e949f48c175e..f1bdf0b2c3d37 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -13,8 +13,8 @@ arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } log = { version = "0.3", features = ["release_max_level_info"] } env_logger = { version = "0.4", default-features = false } -proc_macro_plugin = { path = "../libproc_macro_plugin" } rustc = { path = "../librustc" } +rustc_allocator = { path = "../librustc_allocator" } rustc_back = { path = "../librustc_back" } rustc_borrowck = { path = "../librustc_borrowck" } rustc_const_eval = { path = "../librustc_const_eval" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index a3e1cf7c1a8f8..daa5917cf324d 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -27,6 +27,7 @@ use rustc::traits; use rustc::util::common::{ErrorReported, time}; use rustc::util::nodemap::NodeSet; use rustc::util::fs::rename_or_copy_remove; +use rustc_allocator as allocator; use rustc_borrowck as borrowck; use rustc_incremental::{self, IncrementalHashesMap}; use rustc_resolve::{MakeGlobMap, Resolver}; @@ -750,6 +751,13 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session, }); } + krate = time(time_passes, "creating allocators", || { + allocator::expand::modify(&sess.parse_sess, + &mut resolver, + krate, + sess.diagnostic()) + }); + after_expand(&krate)?; if sess.opts.debugging_opts.input_stats { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f2aacbc629fad..1f9f6aad90536 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -34,6 +34,7 @@ extern crate graphviz; extern crate env_logger; extern crate libc; extern crate rustc; +extern crate rustc_allocator; extern crate rustc_back; extern crate rustc_borrowck; extern crate rustc_const_eval; @@ -84,10 +85,11 @@ use std::cmp::max; use std::cmp::Ordering::Equal; use std::default::Default; use std::env; +use std::ffi::OsString; use std::io::{self, Read, Write}; use std::iter::repeat; use std::path::PathBuf; -use std::process; +use std::process::{self, Command, Stdio}; use std::rc::Rc; use std::str; use std::sync::{Arc, Mutex}; @@ -343,6 +345,31 @@ pub trait CompilerCalls<'a> { #[derive(Copy, Clone)] pub struct RustcDefaultCalls; +// FIXME remove these and use winapi 0.3 instead +// Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs +#[cfg(unix)] +fn stdout_isatty() -> bool { + unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 } +} + +#[cfg(windows)] +fn stdout_isatty() -> bool { + type DWORD = u32; + type BOOL = i32; + type HANDLE = *mut u8; + type LPDWORD = *mut u32; + const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD; + extern "system" { + fn GetStdHandle(which: DWORD) -> HANDLE; + fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL; + } + unsafe { + let handle = GetStdHandle(STD_OUTPUT_HANDLE); + let mut out = 0; + GetConsoleMode(handle, &mut out) != 0 + } +} + fn handle_explain(code: &str, descriptions: &errors::registry::Registry, output: ErrorOutputType) { @@ -354,6 +381,8 @@ fn handle_explain(code: &str, match descriptions.find_description(&normalised) { Some(ref description) => { let mut is_in_code_block = false; + let mut text = String::new(); + // Slice off the leading newline and print. for line in description[1..].lines() { let indent_level = line.find(|c: char| !c.is_whitespace()) @@ -361,12 +390,19 @@ fn handle_explain(code: &str, let dedented_line = &line[indent_level..]; if dedented_line.starts_with("```") { is_in_code_block = !is_in_code_block; - println!("{}", &line[..(indent_level+3)]); + text.push_str(&line[..(indent_level+3)]); } else if is_in_code_block && dedented_line.starts_with("# ") { continue; } else { - println!("{}", line); + text.push_str(line); } + text.push('\n'); + } + + if stdout_isatty() { + show_content_with_pager(&text); + } else { + print!("{}", text); } } None => { @@ -375,6 +411,39 @@ fn handle_explain(code: &str, } } +fn show_content_with_pager(content: &String) { + let pager_name = env::var_os("PAGER").unwrap_or_else(|| if cfg!(windows) { + OsString::from("more.com") + } else { + OsString::from("less") + }); + + let mut fallback_to_println = false; + + match Command::new(pager_name).stdin(Stdio::piped()).spawn() { + Ok(mut pager) => { + if let Some(mut pipe) = pager.stdin.as_mut() { + if pipe.write_all(content.as_bytes()).is_err() { + fallback_to_println = true; + } + } + + if pager.wait().is_err() { + fallback_to_println = true; + } + } + Err(_) => { + fallback_to_println = true; + } + } + + // If pager fails for whatever reason, we should still print the content + // to standard output + if fallback_to_println { + print!("{}", content); + } +} + impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn early_callback(&mut self, matches: &getopts::Matches, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2b33150902532..02d68a41b4cc4 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1071,7 +1071,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { hir::ItemFn(.., ref generics, _) => { - if attr::contains_name(&it.attrs, "no_mangle") { + if attr::contains_name(&it.attrs, "no_mangle") && + !attr::contains_name(&it.attrs, "linkage") { if !cx.access_levels.is_reachable(it.id) { let msg = format!("function {} is marked #[no_mangle], but not exported", it.name); diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 770d16e5c029a..9f0ee95b5a60e 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -698,6 +698,7 @@ extern "C" { pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; + pub fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool); // Operations on functions pub fn LLVMAddFunction(M: ModuleRef, Name: *const c_char, FunctionTy: TypeRef) -> ValueRef; diff --git a/src/librustc_lsan/Cargo.toml b/src/librustc_lsan/Cargo.toml index 786883d21350b..087c316211943 100644 --- a/src/librustc_lsan/Cargo.toml +++ b/src/librustc_lsan/Cargo.toml @@ -14,5 +14,6 @@ build_helper = { path = "../build_helper" } cmake = "0.1.18" [dependencies] +alloc = { path = "../liballoc" } alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs index 54941362e8450..e987b1f335e19 100644 --- a/src/librustc_lsan/lib.rs +++ b/src/librustc_lsan/lib.rs @@ -11,6 +11,8 @@ #![sanitizer_runtime] #![feature(sanitizer_runtime)] #![feature(alloc_system)] +#![cfg_attr(not(stage0), feature(allocator_api))] +#![cfg_attr(not(stage0), feature(global_allocator))] #![feature(staged_api)] #![no_std] #![unstable(feature = "sanitizer_runtime_lib", @@ -18,3 +20,10 @@ issue = "0")] extern crate alloc_system; + +#[cfg(not(stage0))] +use alloc_system::System; + +#[cfg(not(stage0))] +#[global_allocator] +static ALLOC: System = System; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 27c2d22168c8b..ac39da48ac1fc 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -16,6 +16,7 @@ use schema::{CrateRoot, Tracked}; use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::svh::Svh; +use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::DepKind; use rustc::session::Session; use rustc::session::config::{Sanitizer, self}; @@ -40,6 +41,7 @@ use syntax::attr; use syntax::ext::base::SyntaxExtension; use syntax::feature_gate::{self, GateIssue}; use syntax::symbol::Symbol; +use syntax::visit; use syntax_pos::{Span, DUMMY_SP}; use log; @@ -920,34 +922,28 @@ impl<'a> CrateLoader<'a> { } } - fn inject_allocator_crate(&mut self) { - // Make sure that we actually need an allocator, if none of our - // dependencies need one then we definitely don't! - // - // Also, if one of our dependencies has an explicit allocator, then we - // also bail out as we don't need to implicitly inject one. - let mut needs_allocator = false; - let mut found_required_allocator = false; + fn inject_allocator_crate(&mut self, krate: &ast::Crate) { + let has_global_allocator = has_global_allocator(krate); + if has_global_allocator { + self.sess.has_global_allocator.set(true); + } + + // Check to see if we actually need an allocator. This desire comes + // about through the `#![needs_allocator]` attribute and is typically + // written down in liballoc. + let mut needs_allocator = attr::contains_name(&krate.attrs, + "needs_allocator"); let dep_graph = &self.sess.dep_graph; - self.cstore.iter_crate_data(|cnum, data| { + self.cstore.iter_crate_data(|_, data| { needs_allocator = needs_allocator || data.needs_allocator(dep_graph); - if data.is_allocator(dep_graph) { - info!("{} required by rlib and is an allocator", data.name()); - self.inject_dependency_if(cnum, "an allocator", - &|data| data.needs_allocator(dep_graph)); - found_required_allocator = found_required_allocator || - data.dep_kind.get() == DepKind::Explicit; - } }); - if !needs_allocator || found_required_allocator { return } + if !needs_allocator { + return + } - // At this point we've determined that we need an allocator and no - // previous allocator has been activated. We look through our outputs of - // crate types to see what kind of allocator types we may need. - // - // The main special output type here is that rlibs do **not** need an - // allocator linked in (they're just object files), only final products - // (exes, dylibs, staticlibs) need allocators. + // At this point we've determined that we need an allocator. Let's see + // if our compilation session actually needs an allocator based on what + // we're emitting. let mut need_lib_alloc = false; let mut need_exe_alloc = false; for ct in self.sess.crate_types.borrow().iter() { @@ -960,44 +956,132 @@ impl<'a> CrateLoader<'a> { config::CrateTypeRlib => {} } } - if !need_lib_alloc && !need_exe_alloc { return } + if !need_lib_alloc && !need_exe_alloc { + return + } - // The default allocator crate comes from the custom target spec, and we - // choose between the standard library allocator or exe allocator. This - // distinction exists because the default allocator for binaries (where - // the world is Rust) is different than library (where the world is - // likely *not* Rust). - // - // If a library is being produced, but we're also flagged with `-C - // prefer-dynamic`, then we interpret this as a *Rust* dynamic library - // is being produced so we use the exe allocator instead. + // Ok, we need an allocator. Not only that but we're actually going to + // create an artifact that needs one linked in. Let's go find the one + // that we're going to link in. // - // What this boils down to is: - // - // * Binaries use jemalloc - // * Staticlibs and Rust dylibs use system malloc - // * Rust dylibs used as dependencies to rust use jemalloc - let name = if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic { - Symbol::intern(&self.sess.target.target.options.lib_allocation_crate) + // First up we check for global allocators. Look at the crate graph here + // and see what's a global allocator, including if we ourselves are a + // global allocator. + let dep_graph = &self.sess.dep_graph; + let mut global_allocator = if has_global_allocator { + Some(None) } else { - Symbol::intern(&self.sess.target.target.options.exe_allocation_crate) + None }; - let dep_kind = DepKind::Implicit; - let (cnum, data) = - self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind); + self.cstore.iter_crate_data(|_, data| { + if !data.has_global_allocator(dep_graph) { + return + } + match global_allocator { + Some(Some(other_crate)) => { + self.sess.err(&format!("the #[global_allocator] in {} \ + conflicts with this global \ + allocator in: {}", + other_crate, + data.name())); + } + Some(None) => { + self.sess.err(&format!("the #[global_allocator] in this \ + crate conflicts with global \ + allocator in: {}", data.name())); + } + None => global_allocator = Some(Some(data.name())), + } + }); + if global_allocator.is_some() { + self.sess.allocator_kind.set(Some(AllocatorKind::Global)); + return + } + + // Ok we haven't found a global allocator but we still need an + // allocator. At this point we'll either fall back to the "library + // allocator" or the "exe allocator" depending on a few variables. Let's + // figure out which one. + // + // Note that here we favor linking to the "library allocator" as much as + // possible. If we're not creating rustc's version of libstd + // (need_lib_alloc and prefer_dynamic) then we select `None`, and if the + // exe allocation crate doesn't exist for this target then we also + // select `None`. + let exe_allocation_crate = + if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic { + None + } else { + self.sess.target.target.options.exe_allocation_crate.as_ref() + }; + + match exe_allocation_crate { + // We've determined that we're injecting an "exe allocator" which + // means that we're going to load up a whole new crate. An example + // of this is that we're producing a normal binary on Linux which + // means we need to load the `alloc_jemalloc` crate to link as an + // allocator. + Some(krate) => { + self.sess.allocator_kind.set(Some(AllocatorKind::DefaultExe)); + let name = Symbol::intern(krate); + let dep_kind = DepKind::Implicit; + let (cnum, _data) = + self.resolve_crate(&None, + name, + name, + None, + DUMMY_SP, + PathKind::Crate, dep_kind); + self.sess.injected_allocator.set(Some(cnum)); + // self.cstore.iter_crate_data(|_, data| { + // if !data.needs_allocator(dep_graph) { + // return + // } + // data.cnum_map.borrow_mut().push(cnum); + // }); + } - // Sanity check the crate we loaded to ensure that it is indeed an - // allocator. - if !data.is_allocator(dep_graph) { - self.sess.err(&format!("the allocator crate `{}` is not tagged \ - with #![allocator]", data.name())); + // We're not actually going to inject an allocator, we're going to + // require that something in our crate graph is the default lib + // allocator. This is typically libstd, so this'll rarely be an + // error. + None => { + self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib)); + let mut found_lib_allocator = + attr::contains_name(&krate.attrs, "default_lib_allocator"); + self.cstore.iter_crate_data(|_, data| { + if !found_lib_allocator { + if data.has_default_lib_allocator(dep_graph) { + found_lib_allocator = true; + } + } + }); + if found_lib_allocator { + return + } + self.sess.err("no #[default_lib_allocator] found but one is \ + required; is libstd not linked?"); + } } - self.sess.injected_allocator.set(Some(cnum)); - self.inject_dependency_if(cnum, "an allocator", - &|data| data.needs_allocator(dep_graph)); + fn has_global_allocator(krate: &ast::Crate) -> bool { + struct Finder(bool); + let mut f = Finder(false); + visit::walk_crate(&mut f, krate); + return f.0; + + impl<'ast> visit::Visitor<'ast> for Finder { + fn visit_item(&mut self, i: &'ast ast::Item) { + if attr::contains_name(&i.attrs, "global_allocator") { + self.0 = true; + } + visit::walk_item(self, i) + } + } + } } + fn inject_dependency_if(&self, krate: CrateNum, what: &str, @@ -1123,7 +1207,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { // sanitizers force the use of the `alloc_system` allocator self.inject_sanitizer_runtime(); self.inject_profiler_runtime(); - self.inject_allocator_crate(); + self.inject_allocator_crate(krate); self.inject_panic_runtime(krate); if log_enabled!(log::LogLevel::Info) { diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 86146fe3947bc..fb43f91c46d7f 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -275,16 +275,27 @@ impl CrateMetadata { self.root.disambiguator } - pub fn is_allocator(&self, dep_graph: &DepGraph) -> bool { - let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph); - attr::contains_name(&attrs, "allocator") - } - pub fn needs_allocator(&self, dep_graph: &DepGraph) -> bool { let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph); attr::contains_name(&attrs, "needs_allocator") } + pub fn has_global_allocator(&self, dep_graph: &DepGraph) -> bool { + let dep_node = self.metadata_dep_node(GlobalMetaDataKind::Krate); + self.root + .has_global_allocator + .get(dep_graph, dep_node) + .clone() + } + + pub fn has_default_lib_allocator(&self, dep_graph: &DepGraph) -> bool { + let dep_node = self.metadata_dep_node(GlobalMetaDataKind::Krate); + self.root + .has_default_lib_allocator + .get(dep_graph, dep_node) + .clone() + } + pub fn is_panic_runtime(&self, dep_graph: &DepGraph) -> bool { let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph); attr::contains_name(&attrs, "panic_runtime") diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 502eab44dac52..86db6fa1f90ce 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -33,6 +33,7 @@ use std::rc::Rc; use syntax::ast; use syntax::attr; +use syntax::ext::base::SyntaxExtension; use syntax::parse::filemap_to_stream; use syntax::symbol::Symbol; use syntax_pos::{Span, NO_EXPANSION}; @@ -134,7 +135,6 @@ provide! { <'tcx> tcx, def_id, cdata, is_mir_available => { cdata.is_item_mir_available(def_id.index) } dylib_dependency_formats => { Rc::new(cdata.get_dylib_dependency_formats(&tcx.dep_graph)) } - is_allocator => { cdata.is_allocator(&tcx.dep_graph) } is_panic_runtime => { cdata.is_panic_runtime(&tcx.dep_graph) } extern_crate => { Rc::new(cdata.extern_crate.get()) } } @@ -365,6 +365,10 @@ impl CrateStore for cstore::CStore { let data = self.get_crate_data(id.krate); if let Some(ref proc_macros) = data.proc_macros { return LoadedMacro::ProcMacro(proc_macros[id.index.as_usize() - 1].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)); + return LoadedMacro::ProcMacro(Rc::new(ext)); } let (name, def) = data.get_macro(id.index); @@ -372,7 +376,7 @@ impl CrateStore for cstore::CStore { let filemap = sess.parse_sess.codemap().new_filemap(source_name, def.body); let local_span = Span { lo: filemap.start_pos, hi: filemap.end_pos, ctxt: NO_EXPANSION }; - let body = filemap_to_stream(&sess.parse_sess, filemap); + let body = filemap_to_stream(&sess.parse_sess, filemap, None); // Mark the attrs as used let attrs = data.get_item_attrs(id.index, &self.dep_graph); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3e6d06ec86ff8..ad3a9dd9fefaf 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -472,7 +472,7 @@ impl<'a, 'tcx> CrateMetadata { } } - fn item_name(&self, item_index: DefIndex) -> ast::Name { + pub fn item_name(&self, item_index: DefIndex) -> ast::Name { self.def_key(item_index) .disambiguated_data .data diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index e9701b95002d4..5d73abc3ee8b8 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -400,12 +400,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tcx = self.tcx; let link_meta = self.link_meta; let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro); + let has_default_lib_allocator = + attr::contains_name(tcx.hir.krate_attrs(), "default_lib_allocator"); + let has_global_allocator = tcx.sess.has_global_allocator.get(); let root = self.lazy(&CrateRoot { name: tcx.crate_name(LOCAL_CRATE), triple: tcx.sess.opts.target_triple.clone(), hash: link_meta.crate_hash, disambiguator: tcx.sess.local_crate_disambiguator(), panic_strategy: Tracked::new(tcx.sess.panic_strategy()), + has_global_allocator: Tracked::new(has_global_allocator), + has_default_lib_allocator: Tracked::new(has_default_lib_allocator), plugin_registrar_fn: tcx.sess .plugin_registrar_fn .get() @@ -1129,6 +1134,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { /// Serialize the text of exported macros fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx> { use syntax::print::pprust; + let def_id = self.tcx.hir.local_def_id(macro_def.id); Entry { kind: EntryKind::MacroDef(self.lazy(&MacroDef { body: pprust::tts_to_string(¯o_def.body.trees().collect::<Vec<_>>()), @@ -1136,11 +1142,11 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { })), visibility: self.lazy(&ty::Visibility::Public), span: self.lazy(¯o_def.span), - attributes: self.encode_attributes(¯o_def.attrs), + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), + children: LazySeq::empty(), - stability: None, - deprecation: None, ty: None, inherent_impls: LazySeq::empty(), variances: LazySeq::empty(), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 9ef5b9408303d..0b670121ba23b 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -243,6 +243,8 @@ pub struct CrateRoot { pub hash: hir::svh::Svh, pub disambiguator: Symbol, pub panic_strategy: Tracked<PanicStrategy>, + pub has_global_allocator: Tracked<bool>, + pub has_default_lib_allocator: Tracked<bool>, pub plugin_registrar_fn: Option<DefIndex>, pub macro_derive_registrar: Option<DefIndex>, diff --git a/src/librustc_msan/Cargo.toml b/src/librustc_msan/Cargo.toml index b3b70bc0a25ef..8d7279b29eb55 100644 --- a/src/librustc_msan/Cargo.toml +++ b/src/librustc_msan/Cargo.toml @@ -14,5 +14,6 @@ build_helper = { path = "../build_helper" } cmake = "0.1.18" [dependencies] +alloc = { path = "../liballoc" } alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs index 54941362e8450..e987b1f335e19 100644 --- a/src/librustc_msan/lib.rs +++ b/src/librustc_msan/lib.rs @@ -11,6 +11,8 @@ #![sanitizer_runtime] #![feature(sanitizer_runtime)] #![feature(alloc_system)] +#![cfg_attr(not(stage0), feature(allocator_api))] +#![cfg_attr(not(stage0), feature(global_allocator))] #![feature(staged_api)] #![no_std] #![unstable(feature = "sanitizer_runtime_lib", @@ -18,3 +20,10 @@ issue = "0")] extern crate alloc_system; + +#[cfg(not(stage0))] +use alloc_system::System; + +#[cfg(not(stage0))] +#[global_allocator] +static ALLOC: System = System; diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index a512cf2f02a5c..c7db2a9a8ae7d 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -17,6 +17,7 @@ log = "0.3" owning_ref = "0.3.3" rustc-demangle = "0.1.4" rustc = { path = "../librustc" } +rustc_allocator = { path = "../librustc_allocator" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs new file mode 100644 index 0000000000000..9abb6d66f9c0f --- /dev/null +++ b/src/librustc_trans/allocator.rs @@ -0,0 +1,117 @@ +// 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. + +use std::ffi::CString; +use std::ptr; + +use libc::c_uint; +use rustc::middle::allocator::AllocatorKind; +use rustc::ty::TyCtxt; +use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy}; + +use ModuleLlvm; +use llvm::{self, False, True}; + +pub unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) { + let llcx = mods.llcx; + let llmod = mods.llmod; + let usize = match &tcx.sess.target.target.target_pointer_width[..] { + "16" => llvm::LLVMInt16TypeInContext(llcx), + "32" => llvm::LLVMInt32TypeInContext(llcx), + "64" => llvm::LLVMInt64TypeInContext(llcx), + tws => bug!("Unsupported target word size for int: {}", tws), + }; + let i8 = llvm::LLVMInt8TypeInContext(llcx); + let i8p = llvm::LLVMPointerType(i8, 0); + let usizep = llvm::LLVMPointerType(usize, 0); + let void = llvm::LLVMVoidTypeInContext(llcx); + + for method in ALLOCATOR_METHODS { + let mut args = Vec::new(); + for ty in method.inputs.iter() { + match *ty { + AllocatorTy::Layout => { + args.push(usize); // size + args.push(usize); // align + } + AllocatorTy::LayoutRef => args.push(i8p), + AllocatorTy::Ptr => args.push(i8p), + AllocatorTy::AllocErr => args.push(i8p), + + AllocatorTy::Bang | + AllocatorTy::ResultExcess | + AllocatorTy::ResultPtr | + AllocatorTy::ResultUnit | + AllocatorTy::UsizePair | + AllocatorTy::Unit => panic!("invalid allocator arg"), + } + } + let output = match method.output { + AllocatorTy::UsizePair => { + args.push(usizep); // min + args.push(usizep); // max + None + } + AllocatorTy::Bang => None, + AllocatorTy::ResultExcess => { + args.push(i8p); // excess_ptr + args.push(i8p); // err_ptr + Some(i8p) + } + AllocatorTy::ResultPtr => { + args.push(i8p); // err_ptr + Some(i8p) + } + AllocatorTy::ResultUnit => Some(i8), + AllocatorTy::Unit => None, + + AllocatorTy::AllocErr | + AllocatorTy::Layout | + AllocatorTy::LayoutRef | + AllocatorTy::Ptr => panic!("invalid allocator output"), + }; + let ty = llvm::LLVMFunctionType(output.unwrap_or(void), + args.as_ptr(), + args.len() as c_uint, + False); + let name = CString::new(format!("__rust_{}", method.name)).unwrap(); + let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, + name.as_ptr(), + ty); + + let callee = CString::new(kind.fn_name(method.name)).unwrap(); + let callee = llvm::LLVMRustGetOrInsertFunction(llmod, + callee.as_ptr(), + ty); + + let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, + llfn, + "entry\0".as_ptr() as *const _); + + let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); + llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); + let args = args.iter().enumerate().map(|(i, _)| { + llvm::LLVMGetParam(llfn, i as c_uint) + }).collect::<Vec<_>>(); + let ret = llvm::LLVMRustBuildCall(llbuilder, + callee, + args.as_ptr(), + args.len() as c_uint, + ptr::null_mut(), + "\0".as_ptr() as *const _); + llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + llvm::LLVMBuildRet(llbuilder, ret); + } else { + llvm::LLVMBuildRetVoid(llbuilder); + } + llvm::LLVMDisposeBuilder(llbuilder); + } +} diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 6bef31ccf64a4..fa93c005dcd8f 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -13,7 +13,7 @@ use std::ffi::{CStr, CString}; use llvm::{self, Attribute, ValueRef}; use llvm::AttributePlace::Function; -pub use syntax::attr::InlineAttr; +pub use syntax::attr::{self, InlineAttr}; use syntax::ast; use context::CrateContext; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index a7f205a18a46c..a4bbdef82f094 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -55,6 +55,10 @@ pub const METADATA_MODULE_NAME: &'static str = "crate.metadata"; /// match up with `METADATA_MODULE_NAME`. pub const METADATA_OBJ_NAME: &'static str = "crate.metadata.o"; +// same as for metadata above, but for allocator shim +pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator"; +pub const ALLOCATOR_OBJ_NAME: &'static str = "crate.allocator.o"; + // RLIB LLVM-BYTECODE OBJECT LAYOUT // Version 1 // Bytes Data @@ -240,6 +244,9 @@ pub fn link_binary(sess: &Session, } } remove(sess, &outputs.with_extension(METADATA_OBJ_NAME)); + if trans.allocator_module.is_some() { + remove(sess, &outputs.with_extension(ALLOCATOR_OBJ_NAME)); + } } out_filenames @@ -363,6 +370,24 @@ pub fn each_linked_rlib(sess: &Session, Ok(()) } +/// Returns a boolean indicating whether the specified crate should be ignored +/// during LTO. +/// +/// Crates ignored during LTO are not lumped together in the "massive object +/// file" that we create and are linked in their normal rlib states. See +/// comments below for what crates do not participate in LTO. +/// +/// It's unusual for a crate to not participate in LTO. Typically only +/// compiler-specific and unstable crates have a reason to not participate in +/// LTO. +pub fn ignored_for_lto(sess: &Session, cnum: CrateNum) -> bool { + // `#![no_builtins]` crates don't participate in LTO because the state + // of builtins gets messed up (our crate isn't tagged with no builtins). + // Similarly `#![compiler_builtins]` doesn't participate because we want + // those builtins! + sess.cstore.is_no_builtins(cnum) || sess.cstore.is_compiler_builtins(cnum) +} + fn out_filename(sess: &Session, crate_type: config::CrateType, outputs: &OutputFilenames, @@ -417,11 +442,21 @@ fn link_binary_output(sess: &Session, let out_filename = out_filename(sess, crate_type, outputs, crate_name); match crate_type { config::CrateTypeRlib => { - link_rlib(sess, Some(trans), &objects, &out_filename, + link_rlib(sess, + trans, + RlibFlavor::Normal, + &objects, + outputs, + &out_filename, tmpdir.path()).build(); } config::CrateTypeStaticlib => { - link_staticlib(sess, &objects, &out_filename, tmpdir.path()); + link_staticlib(sess, + trans, + outputs, + &objects, + &out_filename, + tmpdir.path()); } _ => { link_natively(sess, crate_type, &objects, &out_filename, trans, @@ -477,6 +512,11 @@ fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename: } } +enum RlibFlavor { + Normal, + StaticlibBase, +} + // Create an 'rlib' // // An rlib in its current incarnation is essentially a renamed .a file. The @@ -484,8 +524,10 @@ fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename: // all of the object files from native libraries. This is done by unzipping // native libraries and inserting all of the contents into this archive. fn link_rlib<'a>(sess: &'a Session, - trans: Option<&CrateTranslation>, // None == no metadata/bytecode + trans: &CrateTranslation, + flavor: RlibFlavor, objects: &[PathBuf], + outputs: &OutputFilenames, out_filename: &Path, tmpdir: &Path) -> ArchiveBuilder<'a> { info!("preparing rlib from {:?} to {:?}", objects, out_filename); @@ -546,8 +588,8 @@ fn link_rlib<'a>(sess: &'a Session, // // Basically, all this means is that this code should not move above the // code above. - match trans { - Some(trans) => { + match flavor { + RlibFlavor::Normal => { // Instead of putting the metadata in an object file section, rlibs // contain the metadata in a separate file. We use a temp directory // here so concurrent builds in the same directory don't try to use @@ -620,7 +662,11 @@ fn link_rlib<'a>(sess: &'a Session, } } - None => {} + RlibFlavor::StaticlibBase => { + if trans.allocator_module.is_some() { + ab.add_file(&outputs.with_extension(ALLOCATOR_OBJ_NAME)); + } + } } ab @@ -672,9 +718,19 @@ fn write_rlib_bytecode_object_v1(writer: &mut Write, // There's no need to include metadata in a static archive, so ensure to not // link in the metadata object file (and also don't prepare the archive with a // metadata file). -fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, +fn link_staticlib(sess: &Session, + trans: &CrateTranslation, + outputs: &OutputFilenames, + objects: &[PathBuf], + out_filename: &Path, tempdir: &Path) { - let mut ab = link_rlib(sess, None, objects, out_filename, tempdir); + let mut ab = link_rlib(sess, + trans, + RlibFlavor::StaticlibBase, + objects, + outputs, + out_filename, + tempdir); let mut all_native_libs = vec![]; let res = each_linked_rlib(sess, &mut |cnum, path| { @@ -698,7 +754,10 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, let skip_object_files = native_libs.iter().any(|lib| { lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) }); - ab.add_rlib(path, &name.as_str(), sess.lto(), skip_object_files).unwrap(); + ab.add_rlib(path, + &name.as_str(), + sess.lto() && !ignored_for_lto(sess, cnum), + skip_object_files).unwrap(); all_native_libs.extend(sess.cstore.native_libraries(cnum)); }); @@ -944,6 +1003,10 @@ fn link_args(cmd: &mut Linker, cmd.add_object(&outputs.with_extension(METADATA_OBJ_NAME)); } + if trans.allocator_module.is_some() { + cmd.add_object(&outputs.with_extension(ALLOCATOR_OBJ_NAME)); + } + // Try to strip as much out of the generated object by removing unused // sections if possible. See more comments in linker.rs if !sess.opts.cg.link_dead_code { @@ -1247,7 +1310,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker, lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) }); - if !sess.lto() && crate_type != config::CrateTypeDylib && !skip_native { + if (!sess.lto() || ignored_for_lto(sess, cnum)) && + crate_type != config::CrateTypeDylib && + !skip_native { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); return } diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index b38dc18838923..52fe747858cc4 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -92,7 +92,6 @@ impl ExportedSymbols { // Down below we'll hardwire all of the symbols to the `Rust` export // level instead. let special_runtime_crate = - scx.tcx().is_allocator(cnum.as_def_id()) || scx.tcx().is_panic_runtime(cnum.as_def_id()) || scx.sess().cstore.is_compiler_builtins(cnum); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 562d7171156fe..5e227ec467abb 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -644,6 +644,7 @@ pub fn run_passes(sess: &Session, let mut modules_config = ModuleConfig::new(tm, sess.opts.cg.passes.clone()); let mut metadata_config = ModuleConfig::new(tm, vec![]); + let mut allocator_config = ModuleConfig::new(tm, vec![]); if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer { match *sanitizer { @@ -674,6 +675,7 @@ pub fn run_passes(sess: &Session, modules_config.emit_bc = true; modules_config.emit_lto_bc = true; metadata_config.emit_bc = true; + allocator_config.emit_bc = true; } // Emit bitcode files for the crate if we're emitting an rlib. @@ -699,6 +701,7 @@ pub fn run_passes(sess: &Session, // in this case we still want the metadata object file. if !sess.opts.output_types.contains_key(&OutputType::Assembly) { metadata_config.emit_obj = true; + allocator_config.emit_obj = true; } } OutputType::Object => { modules_config.emit_obj = true; } @@ -706,6 +709,7 @@ pub fn run_passes(sess: &Session, OutputType::Exe => { modules_config.emit_obj = true; metadata_config.emit_obj = true; + allocator_config.emit_obj = true; }, OutputType::Mir => {} OutputType::DepInfo => {} @@ -714,6 +718,7 @@ pub fn run_passes(sess: &Session, modules_config.set_flags(sess, trans); metadata_config.set_flags(sess, trans); + allocator_config.set_flags(sess, trans); // Populate a buffer with a list of codegen threads. Items are processed in @@ -729,6 +734,14 @@ pub fn run_passes(sess: &Session, work_items.push(work); } + if let Some(allocator) = trans.allocator_module.clone() { + let work = build_work_item(sess, + allocator, + allocator_config.clone(), + crate_output.clone()); + work_items.push(work); + } + for mtrans in trans.modules.iter() { let work = build_work_item(sess, mtrans.clone(), @@ -905,6 +918,13 @@ pub fn run_passes(sess: &Session, Some(&trans.metadata_module.name)); remove(sess, &path); } + if allocator_config.emit_bc && !user_wants_bitcode { + if let Some(ref module) = trans.allocator_module { + let path = crate_output.temp_path(OutputType::Bitcode, + Some(&module.name)); + remove(sess, &path); + } + } } // We leave the following files around by default: @@ -1200,8 +1220,7 @@ fn spawn_work<'a>(sess: &'a Session, let crate_types = sess.crate_types.borrow().clone(); let mut each_linked_rlib_for_lto = Vec::new(); drop(link::each_linked_rlib(sess, &mut |cnum, path| { - // `#![no_builtins]` crates don't participate in LTO. - if sess.cstore.is_no_builtins(cnum) { + if link::ignored_for_lto(sess, cnum) { return } each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 2589a3538a940..8298324e99680 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -47,6 +47,7 @@ use rustc::session::config::{self, NoDebugInfo, OutputFilenames}; use rustc::session::Session; use rustc_incremental::IncrementalHashesMap; use abi; +use allocator; use mir::lvalue::LvalueRef; use attributes; use builder::Builder; @@ -1086,8 +1087,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, llmod: metadata_llmod, }), }; + let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); + // Skip crate items and just output metadata in -Z no-trans mode. if tcx.sess.opts.debugging_opts.no_trans || !tcx.sess.opts.output_types.should_trans() { @@ -1097,6 +1100,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_name: tcx.crate_name(LOCAL_CRATE), modules: vec![], metadata_module: metadata_module, + allocator_module: None, link: link_meta, metadata: metadata, exported_symbols: empty_exported_symbols, @@ -1296,6 +1300,41 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, create_imps(sess, &llvm_modules); } + // Translate an allocator shim, if any + // + // If LTO is enabled and we've got some previous LLVM module we translated + // above, then we can just translate directly into that LLVM module. If not, + // however, we need to create a separate module and trans into that. Note + // that the separate translation is critical for the standard library where + // the rlib's object file doesn't have allocator functions but the dylib + // links in an object file that has allocator functions. When we're + // compiling a final LTO artifact, though, there's no need to worry about + // this as we're not working with this dual "rlib/dylib" functionality. + let allocator_module = tcx.sess.allocator_kind.get().and_then(|kind| unsafe { + if sess.lto() && llvm_modules.len() > 0 { + time(tcx.sess.time_passes(), "write allocator module", || { + allocator::trans(tcx, &llvm_modules[0], kind) + }); + None + } else { + let (llcx, llmod) = + context::create_context_and_module(tcx.sess, "allocator"); + let modules = ModuleLlvm { + llmod: llmod, + llcx: llcx, + }; + time(tcx.sess.time_passes(), "write allocator module", || { + allocator::trans(tcx, &modules, kind) + }); + + Some(ModuleTranslation { + name: link::ALLOCATOR_MODULE_NAME.to_string(), + symbol_name_hash: 0, // we always rebuild allocator shims + source: ModuleSource::Translated(modules), + }) + } + }); + let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols); let subsystem = attr::first_attr_value_str_by_name(&krate.attrs, @@ -1313,6 +1352,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_name: tcx.crate_name(LOCAL_CRATE), modules: modules, metadata_module: metadata_module, + allocator_module: allocator_module, link: link_meta, metadata: metadata, exported_symbols: exported_symbols, diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index 2787812f9622c..8f9146283effe 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -30,7 +30,6 @@ use context::CrateContext; use common; use type_::Type; use value::Value; -use syntax::attr; use std::ffi::CString; @@ -88,16 +87,6 @@ fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: } } - // If we're compiling the compiler-builtins crate, e.g. the equivalent of - // compiler-rt, then we want to implicitly compile everything with hidden - // visibility as we're going to link this object all over the place but - // don't want the symbols to get exported. - if attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") { - unsafe { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } - } - match ccx.tcx().sess.opts.cg.opt_level.as_ref().map(String::as_ref) { Some("s") => { llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 6acd10cb887f8..5c76f778f8d63 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -43,6 +43,7 @@ extern crate crossbeam; extern crate libc; extern crate owning_ref; #[macro_use] extern crate rustc; +extern crate rustc_allocator; extern crate rustc_back; extern crate rustc_data_structures; extern crate rustc_incremental; @@ -84,6 +85,7 @@ mod diagnostics; mod abi; mod adt; +mod allocator; mod asm; mod assert_module_sources; mod attributes; @@ -163,6 +165,7 @@ pub struct CrateTranslation { pub crate_name: Symbol, pub modules: Vec<ModuleTranslation>, pub metadata_module: ModuleTranslation, + pub allocator_module: Option<ModuleTranslation>, pub link: rustc::middle::cstore::LinkMeta, pub metadata: rustc::middle::cstore::EncodedMetadata, pub exported_symbols: back::symbol_export::ExportedSymbols, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 2a6e7c5ace6cf..200f6dee334ad 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -162,6 +162,18 @@ impl<'a, 'tcx> TransItem<'tcx> { llvm::SetUniqueComdat(ccx.llmod(), lldecl); } + // If we're compiling the compiler-builtins crate, e.g. the equivalent of + // compiler-rt, then we want to implicitly compile everything with hidden + // visibility as we're going to link this object all over the place but + // don't want the symbols to get exported. + if linkage != llvm::Linkage::InternalLinkage && + linkage != llvm::Linkage::PrivateLinkage && + attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") { + unsafe { + llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); + } + } + debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); if common::is_inline_instance(ccx.tcx(), &instance) { attributes::inline(lldecl, attributes::InlineAttr::Hint); diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index de8749c43d95c..89a40b0db9662 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -319,7 +319,7 @@ impl<'a> Classifier<'a> { token::Lifetime(..) => Class::Lifetime, token::Underscore | token::Eof | token::Interpolated(..) | - token::SubstNt(..) | token::Tilde | token::At => Class::None, + token::Tilde | token::At => Class::None, }; // Anything that didn't return above is the simple case where we the diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 38f83687d1d85..788cd80b075ea 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1233,21 +1233,24 @@ onEach(e.getElementsByClassName('associatedconstant'), func); }); - var span = document.createElement('span'); - span.className = 'toggle-label'; - span.style.display = 'none'; - span.innerHTML = ' Expand description'; - - var mainToggle = toggle.cloneNode(true); - mainToggle.appendChild(span); - - var wrapper = document.createElement('div'); - wrapper.className = 'toggle-wrapper'; - wrapper.appendChild(mainToggle); + function createToggle() { + var span = document.createElement('span'); + span.className = 'toggle-label'; + span.style.display = 'none'; + span.innerHTML = ' Expand description'; + + var mainToggle = toggle.cloneNode(true); + mainToggle.appendChild(span); + + var wrapper = document.createElement('div'); + wrapper.className = 'toggle-wrapper'; + wrapper.appendChild(mainToggle); + return wrapper; + } onEach(document.getElementById('main').getElementsByClassName('docblock'), function(e) { if (e.parentNode.id === "main") { - e.parentNode.insertBefore(wrapper, e); + e.parentNode.insertBefore(createToggle(), e); } }); @@ -1273,18 +1276,22 @@ } }) - var span = document.createElement('span'); - span.className = 'toggle-label'; - span.style.display = 'none'; - span.innerHTML = ' Expand attributes'; - toggle.appendChild(span); + function createToggleWrapper() { + var span = document.createElement('span'); + span.className = 'toggle-label'; + span.style.display = 'none'; + span.innerHTML = ' Expand attributes'; + toggle.appendChild(span); + + var wrapper = document.createElement('div'); + wrapper.className = 'toggle-wrapper toggle-attributes'; + wrapper.appendChild(toggle); + return wrapper; + } - var wrapper = document.createElement('div'); - wrapper.className = 'toggle-wrapper toggle-attributes'; - wrapper.appendChild(toggle); onEach(document.getElementById('main').getElementsByTagName('pre'), function(e) { onEach(e.getElementsByClassName('attributes'), function(i_e) { - i_e.parentNode.insertBefore(wrapper, i_e); + i_e.parentNode.insertBefore(createToggleWrapper(), i_e); collapseDocs(i_e.previousSibling.childNodes[0]); }); }); diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index b516cbd08ca02..09c168169348b 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -19,7 +19,7 @@ collections = { path = "../libcollections" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } rand = { path = "../librand" } -compiler_builtins = { path = "../libcompiler_builtins" } +compiler_builtins = { path = "../rustc/compiler_builtins_shim" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } std_unicode = { path = "../libstd_unicode" } unwind = { path = "../libunwind" } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 50c721db849aa..06f4f7643ec83 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::heap::{allocate, deallocate}; +use alloc::heap::{Heap, Alloc, Layout}; use cmp; use hash::{BuildHasher, Hash, Hasher}; @@ -781,10 +781,8 @@ impl<K, V> RawTable<K, V> { .expect("capacity overflow"), "capacity overflow"); - let buffer = allocate(size, alignment); - if buffer.is_null() { - ::alloc::oom() - } + let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap()) + .unwrap_or_else(|e| Heap.oom(e)); let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; @@ -1193,7 +1191,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> { debug_assert!(!oflo, "should be impossible"); unsafe { - deallocate(self.hashes.ptr() as *mut u8, size, align); + Heap.dealloc(self.hashes.ptr() as *mut u8, + Layout::from_size_align(size, align).unwrap()); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 4b340f70fbc74..d77f817659c56 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -224,7 +224,7 @@ impl Error for ! { #[unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", - issue = "27700")] + issue = "32838")] impl Error for allocator::AllocErr { fn description(&self) -> &str { allocator::AllocErr::description(self) @@ -233,7 +233,7 @@ impl Error for allocator::AllocErr { #[unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", - issue = "27700")] + issue = "32838")] impl Error for allocator::CannotReallocInPlace { fn description(&self) -> &str { allocator::CannotReallocInPlace::description(self) diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 7d79fb078116f..a6eb17c8fa41b 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1131,13 +1131,16 @@ impl f32 { #[inline] pub fn from_bits(mut v: u32) -> Self { const EXP_MASK: u32 = 0x7F800000; - const QNAN_MASK: u32 = 0x00400000; const FRACT_MASK: u32 = 0x007FFFFF; if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 { - // If we have a NaN value, we - // convert signaling NaN values to quiet NaN - // by setting the the highest bit of the fraction - v |= QNAN_MASK; + // While IEEE 754-2008 specifies encodings for quiet NaNs + // and signaling ones, certain MIPS and PA-RISC + // CPUs treat signaling NaNs differently. + // Therefore to be safe, we pass a known quiet NaN + // if v is any kind of NaN. + // The check above only assumes IEEE 754-1985 to be + // valid. + v = unsafe { ::mem::transmute(NAN) }; } unsafe { ::mem::transmute(v) } } @@ -1732,8 +1735,15 @@ mod tests { } #[test] fn test_snan_masking() { + // NOTE: this test assumes that our current platform + // implements IEEE 754-2008 that specifies the difference + // in encoding of quiet and signaling NaNs. + // If you are porting Rust to a platform that does not + // implement IEEE 754-2008 (but e.g. IEEE 754-1985, which + // only says that "Signaling NaNs shall be reserved operands" + // but doesn't specify the actual setup), feel free to + // cfg out this test. let snan: u32 = 0x7F801337; - const PAYLOAD_MASK: u32 = 0x003FFFFF; const QNAN_MASK: u32 = 0x00400000; let nan_masked_fl = f32::from_bits(snan); let nan_masked = nan_masked_fl.to_bits(); @@ -1742,7 +1752,5 @@ mod tests { // Ensure that we have a quiet NaN assert_ne!(nan_masked & QNAN_MASK, 0); assert!(nan_masked_fl.is_nan()); - // Ensure the payload wasn't touched during conversion - assert_eq!(nan_masked & PAYLOAD_MASK, snan & PAYLOAD_MASK); } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index d5b0cd3a1fc79..4d8d8b4ebe6aa 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -1046,13 +1046,16 @@ impl f64 { #[inline] pub fn from_bits(mut v: u64) -> Self { const EXP_MASK: u64 = 0x7FF0000000000000; - const QNAN_MASK: u64 = 0x0001000000000000; const FRACT_MASK: u64 = 0x000FFFFFFFFFFFFF; if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 { - // If we have a NaN value, we - // convert signaling NaN values to quiet NaN - // by setting the the highest bit of the fraction - v |= QNAN_MASK; + // While IEEE 754-2008 specifies encodings for quiet NaNs + // and signaling ones, certain MIPS and PA-RISC + // CPUs treat signaling NaNs differently. + // Therefore to be safe, we pass a known quiet NaN + // if v is any kind of NaN. + // The check above only assumes IEEE 754-1985 to be + // valid. + v = unsafe { ::mem::transmute(NAN) }; } unsafe { ::mem::transmute(v) } } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 1a91417ca0e92..5f0b11a616eb0 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -585,11 +585,11 @@ impl From<Box<CStr>> for CString { } } -#[stable(feature = "box_from_c_string", since = "1.18.0")] -impl Into<Box<CStr>> for CString { +#[stable(feature = "box_from_c_string", since = "1.20.0")] +impl From<CString> for Box<CStr> { #[inline] - fn into(self) -> Box<CStr> { - self.into_boxed_c_str() + fn from(s: CString) -> Box<CStr> { + s.into_boxed_c_str() } } diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 42d641706a894..02a13ed7a5a03 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -540,10 +540,10 @@ impl From<Box<OsStr>> for OsString { } } -#[stable(feature = "box_from_os_string", since = "1.18.0")] -impl Into<Box<OsStr>> for OsString { - fn into(self) -> Box<OsStr> { - self.into_boxed_os_str() +#[stable(feature = "box_from_os_string", since = "1.20.0")] +impl From<OsString> for Box<OsStr> { + fn from(s: OsString) -> Box<OsStr> { + s.into_boxed_os_str() } } diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs new file mode 100644 index 0000000000000..83bd3b04b4de2 --- /dev/null +++ b/src/libstd/heap.rs @@ -0,0 +1,165 @@ +// 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. + +//! dox + +#![unstable(issue = "32838", feature = "allocator_api")] + +pub use alloc::heap::{Heap, Alloc, Layout, Excess, CannotReallocInPlace, AllocErr}; +#[cfg(not(stage0))] +pub use alloc_system::System; + +#[cfg(all(not(stage0), not(test)))] +#[doc(hidden)] +pub mod __default_lib_allocator { + use super::{System, Layout, Alloc, AllocErr}; + use ptr; + + // for symbol names src/librustc/middle/allocator.rs + // for signatures src/librustc_allocator/lib.rs + + // linkage directives are provided as part of the current compiler allocator + // ABI + + #[no_mangle] + pub unsafe extern fn __rdl_alloc(size: usize, + align: usize, + err: *mut u8) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + match System.alloc(layout) { + Ok(p) => p, + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + pub unsafe extern fn __rdl_oom(err: *const u8) -> ! { + System.oom((*(err as *const AllocErr)).clone()) + } + + #[no_mangle] + pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, + size: usize, + align: usize) { + System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) + } + + #[no_mangle] + pub unsafe extern fn __rdl_usable_size(layout: *const u8, + min: *mut usize, + max: *mut usize) { + let pair = System.usable_size(&*(layout as *const Layout)); + *min = pair.0; + *max = pair.1; + } + + #[no_mangle] + pub unsafe extern fn __rdl_realloc(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + err: *mut u8) -> *mut u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.realloc(ptr, old_layout, new_layout) { + Ok(p) => p, + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + pub unsafe extern fn __rdl_alloc_zeroed(size: usize, + align: usize, + err: *mut u8) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + match System.alloc_zeroed(layout) { + Ok(p) => p, + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + pub unsafe extern fn __rdl_alloc_excess(size: usize, + align: usize, + excess: *mut usize, + err: *mut u8) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + match System.alloc_excess(layout) { + Ok(p) => { + *excess = p.1; + p.0 + } + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + 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 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.realloc_excess(ptr, old_layout, new_layout) { + Ok(p) => { + *excess = p.1; + p.0 + } + Err(e) => { + ptr::write(err as *mut AllocErr, e); + 0 as *mut u8 + } + } + } + + #[no_mangle] + pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.grow_in_place(ptr, old_layout, new_layout) { + Ok(()) => 1, + Err(_) => 0, + } + } + + #[no_mangle] + pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize) -> u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, old_align); + let new_layout = Layout::from_size_align_unchecked(new_size, new_align); + match System.shrink_in_place(ptr, old_layout, new_layout) { + Ok(()) => 1, + Err(_) => 0, + } + } +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index bafe23e80a030..c4bdf7c5b822b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -230,11 +230,6 @@ // Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] -// Always use alloc_system during stage0 since we don't know if the alloc_* -// crate the stage0 compiler will pick by default is available (most -// obviously, if the user has disabled jemalloc in `./configure`). -#![cfg_attr(any(stage0, feature = "force_alloc_system"), feature(alloc_system))] - // Turn warnings into errors, but only after stage0, where it can be useful for // code to emit warnings during language transitions #![deny(warnings)] @@ -246,6 +241,8 @@ // compiler details that will never be stable #![feature(alloc)] #![feature(allocator_api)] +#![feature(alloc_system)] +#![feature(allocator_internals)] #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_consts)] @@ -322,6 +319,8 @@ #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(test, feature(float_bits_conv))] +#![cfg_attr(not(stage0), default_lib_allocator)] + // Explicitly import the prelude. The compiler uses this same unstable attribute // to import the prelude implicitly when building crates that depend on std. #[prelude_import] @@ -342,15 +341,13 @@ extern crate core as __core; #[macro_use] #[macro_reexport(vec, format)] extern crate alloc; +extern crate alloc_system; extern crate std_unicode; extern crate libc; // We always need an unwinder currently for backtraces extern crate unwind; -#[cfg(any(stage0, feature = "force_alloc_system"))] -extern crate alloc_system; - // compiler-rt intrinsics extern crate compiler_builtins; @@ -465,6 +462,7 @@ pub mod path; pub mod process; pub mod sync; pub mod time; +pub mod heap; // Platform-abstraction modules #[macro_use] diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 472ce6bc4fe9e..e7c7be981d25f 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1348,10 +1348,10 @@ impl From<Box<Path>> for PathBuf { } } -#[stable(feature = "box_from_path_buf", since = "1.18.0")] -impl Into<Box<Path>> for PathBuf { - fn into(self) -> Box<Path> { - self.into_boxed_path() +#[stable(feature = "box_from_path_buf", since = "1.20.0")] +impl From<PathBuf> for Box<Path> { + fn from(p: PathBuf) -> Box<Path> { + p.into_boxed_path() } } diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 48d9cdcb2c937..c5a19e8debe93 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -420,12 +420,19 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { } pub fn readlink(p: &Path) -> io::Result<PathBuf> { - canonicalize(p) -} - -pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { - ::sys_common::util::dumb_print(format_args!("Symlink\n")); - unimplemented!(); + let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_SYMLINK | syscall::O_RDONLY))?; + let mut buf: [u8; 4096] = [0; 4096]; + let count = cvt(syscall::read(fd, &mut buf))?; + cvt(syscall::close(fd))?; + Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) })) +} + +pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { + let fd = cvt(syscall::open(dst.to_str().unwrap(), + syscall::O_SYMLINK | syscall::O_CREAT | syscall::O_WRONLY | 0o777))?; + cvt(syscall::write(fd, src.to_str().unwrap().as_bytes()))?; + cvt(syscall::close(fd))?; + Ok(()) } pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { diff --git a/src/libstd/sys/redox/syscall/flag.rs b/src/libstd/sys/redox/syscall/flag.rs index 9f0d3e6f77955..bd603cfe6ef9d 100644 --- a/src/libstd/sys/redox/syscall/flag.rs +++ b/src/libstd/sys/redox/syscall/flag.rs @@ -33,6 +33,7 @@ pub const MAP_WRITE_COMBINE: usize = 2; pub const MODE_TYPE: u16 = 0xF000; pub const MODE_DIR: u16 = 0x4000; pub const MODE_FILE: u16 = 0x8000; +pub const MODE_SYMLINK: u16 = 0xA000; pub const MODE_PERM: u16 = 0x0FFF; pub const MODE_SETUID: u16 = 0o4000; @@ -53,6 +54,7 @@ pub const O_TRUNC: usize = 0x0400_0000; pub const O_EXCL: usize = 0x0800_0000; pub const O_DIRECTORY: usize = 0x1000_0000; pub const O_STAT: usize = 0x2000_0000; +pub const O_SYMLINK: usize = 0x4000_0000; pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR; pub const SEEK_SET: usize = 0; diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 854d380d128c9..46e5acdf3d22b 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -59,8 +59,6 @@ pub mod stdio; #[cfg(not(test))] pub fn init() { - use alloc::oom; - // By default, some platforms will send a *signal* when an EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE // handler, causing it to kill the program, which isn't exactly what we @@ -72,24 +70,6 @@ pub fn init() { reset_sigpipe(); } - oom::set_oom_handler(oom_handler); - - // A nicer handler for out-of-memory situations than the default one. This - // one prints a message to stderr before aborting. It is critical that this - // code does not allocate any memory since we are in an OOM situation. Any - // errors are ignored while printing since there's nothing we can do about - // them and we are about to exit anyways. - fn oom_handler() -> ! { - use intrinsics; - let msg = "fatal runtime error: out of memory\n"; - unsafe { - libc::write(libc::STDERR_FILENO, - msg.as_ptr() as *const libc::c_void, - msg.len()); - intrinsics::abort(); - } - } - #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 840e7fdfc9b26..ee58efc5144a8 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -47,24 +47,6 @@ pub mod stdio; #[cfg(not(test))] pub fn init() { - ::alloc::oom::set_oom_handler(oom_handler); - - // See comment in sys/unix/mod.rs - fn oom_handler() -> ! { - use intrinsics; - use ptr; - let msg = "fatal runtime error: out of memory\n"; - unsafe { - // WriteFile silently fails if it is passed an invalid handle, so - // there is no need to check the result of GetStdHandle. - c::WriteFile(c::GetStdHandle(c::STD_ERROR_HANDLE), - msg.as_ptr() as c::LPVOID, - msg.len() as c::DWORD, - ptr::null_mut(), - ptr::null_mut()); - intrinsics::abort(); - } - } } pub fn decode_error_kind(errno: i32) -> ErrorKind { diff --git a/src/libstd_unicode/tables.rs b/src/libstd_unicode/tables.rs index 7173040350ed9..0938738b52cbd 100644 --- a/src/libstd_unicode/tables.rs +++ b/src/libstd_unicode/tables.rs @@ -14,7 +14,7 @@ /// The version of [Unicode](http://www.unicode.org/) /// that the unicode parts of `CharExt` and `UnicodeStrPrelude` traits are based on. -pub const UNICODE_VERSION: (u64, u64, u64) = (9, 0, 0); +pub const UNICODE_VERSION: (u64, u64, u64) = (10, 0, 0); // BoolTrie is a trie for representing a set of Unicode codepoints. It is @@ -167,7 +167,7 @@ pub mod general_category { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 8, 0, 0, 0, 6, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0, 0, 0, 8, 0, 9, 6, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -236,7 +236,7 @@ pub mod derived_property { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 96, 97, 36, 36, 36, 36, 98, 99, 36, 100, 101, 36, 102, - 103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 117, 36, + 103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, @@ -244,23 +244,23 @@ pub mod derived_property { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 118, 119, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 117, 118, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 36, 36, 36, 36, 36, 120, 36, 121, 122, 123, 124, 125, 36, 36, 36, 36, 126, 127, 128, - 129, 31, 130, 36, 131, 132, 133, 113, 134 + 36, 36, 36, 36, 36, 119, 36, 120, 121, 122, 123, 124, 36, 36, 36, 36, 125, 126, 127, + 128, 31, 129, 36, 130, 131, 132, 113, 133 ], r3: &[ - 0x00001ffffcffffff, 0x0000000001ffffff, 0x3fdfffff00000000, 0xffff03f8fff00000, - 0xefffffffffffffff, 0xfffe000fffe1dfff, 0xe3c5fdfffff99fef, 0x0003000fb080599f, - 0xc36dfdfffff987ee, 0x003f00005e021987, 0xe3edfdfffffbbfee, 0x0200000f00011bbf, + 0x00001ffffcffffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0xffff03f8fff00000, + 0xefffffffffffffff, 0xfffe000fffe1dfff, 0xe3c5fdfffff99fef, 0x1003000fb080599f, + 0xc36dfdfffff987ee, 0x003f00005e021987, 0xe3edfdfffffbbfee, 0x1e00000f00011bbf, 0xe3edfdfffff99fee, 0x0002000fb0c0199f, 0xc3ffc718d63dc7ec, 0x0000000000811dc7, 0xe3fffdfffffddfef, 0x0000000f07601ddf, 0xe3effdfffffddfef, 0x0006000f40601ddf, - 0xe7fffffffffddfee, 0xfc00000f80f05ddf, 0x2ffbfffffc7fffec, 0x000c0000ff5f807f, + 0xe7fffffffffddfef, 0xfc00000f80f05ddf, 0x2ffbfffffc7fffec, 0x000c0000ff5f807f, 0x07fffffffffffffe, 0x000000000000207f, 0x3bffecaefef02596, 0x00000000f000205f, 0x0000000000000001, 0xfffe1ffffffffeff, 0x1ffffffffeffff03, 0x0000000000000000, 0xf97fffffffffffff, 0xffffc1e7ffff0000, 0xffffffff3000407f, 0xf7ffffffffff20bf, @@ -278,74 +278,76 @@ pub mod derived_property { 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, 0x0000800000000000, 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, - 0xfffe3fffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x00000000003fffff, + 0xfffe7fffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x8ff07fffffffffff, 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, 0x000000fffffff7bb, 0x000fffffffffffff, 0x28fc00000000002f, 0xffff07fffffffc00, 0x1fffffff0007ffff, 0xfff7ffffffffffff, 0x7c00ffdf00008000, 0x007fffffffffffff, 0xc47fffff00003fff, 0x7fffffffffffffff, 0x003cffff38000005, 0xffff7f7f007e7e7e, - 0xffff003ff7ffffff, 0x000007ffffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, - 0xffff3fffffffffff, 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, - 0x0003ffffffffffff, 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, - 0xfffffffffffcffff, 0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff, - 0x07fffffe00000000, 0xffffffc007fffffe, 0x000000001cfcfcfc + 0xffff003ff7ffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, 0xffff3fffffffffff, + 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0x0003ffffffffffff, + 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, + 0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff, 0x07fffffe00000000, + 0xffffffc007fffffe, 0x000000001cfcfcfc ], r4: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 13, 14, - 15, 5, 5, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 15, 7, 16, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ], r5: &[ 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 33, 34, 35, 32, 36, 2, 37, 38, 4, 39, 40, 41, 42, 4, 4, 2, 43, 2, 44, 4, 4, 45, 46, 47, 48, 28, 4, 49, 4, 4, 4, 4, 4, 50, 51, 4, 4, 4, - 4, 4, 4, 4, 52, 4, 4, 4, 4, 53, 54, 55, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 56, 4, 2, 57, 2, 2, 2, 58, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 52, 53, 54, 55, 4, 4, 4, 4, 56, 57, 58, 4, 59, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 4, 2, 62, 2, 2, 2, 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 57, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 59, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, - 2, 2, 2, 2, 52, 20, 4, 60, 16, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 63, 64, - 65, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 2, 2, 2, 55, 20, 4, 65, 16, 66, 67, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 68, 69, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 66, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 67, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 72, 2, 2, 2, 2, 2, 73, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 2, 68, 69, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 70, 71, 72, 73, 74, 2, 2, 2, 2, 75, 76, 77, 78, 79, 80, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 81, + 4, 4, 4, 4, 4, 4, 4, 2, 74, 75, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 76, 77, 78, 79, 80, 2, 2, 2, 2, 81, 82, 83, 84, 85, 86, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 2, 2, 2, 82, 2, 83, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 84, 85, - 86, 4, 4, 4, 4, 4, 4, 4, 4, 4, 87, 88, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 87, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 88, 2, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 90, 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 72, 93, 94, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 4, 4, 4, + 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4 + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 98, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ], r6: &[ 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, 0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff, - 0xffff0000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, + 0xffffe000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, @@ -356,17 +358,18 @@ pub mod derived_property { 0x000001ffffffffff, 0xe3edfdfffff99fef, 0x0000000fe081199f, 0x00000000000007bb, 0x00000000000000b3, 0x7f3fffffffffffff, 0x000000003f000000, 0x7fffffffffffffff, 0x0000000000000011, 0x000007ffe3ffffff, 0xffffffff00000000, 0x80000000ffffffff, - 0x01ffffffffffffff, 0x7f7ffffffffffdff, 0xfffc000000000001, 0x007ffefffffcffff, - 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, - 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000000ffff, 0x7fffffffffff001f, - 0x00000000fff80000, 0x0000000100000000, 0x00001fffffffffff, 0x0000000000000003, - 0x1fff07ffffffffff, 0x0000000043ff01ff, 0xffffffffffdfffff, 0xebffde64dfffffff, - 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, - 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, - 0x0000000000000ff7, 0x000007dbf9ffff7f, 0x000000000000001f, 0x000000000000008f, - 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0xffff000000000000, - 0xffff03ffffff03ff, 0x00000000000003ff, 0x00000000007fffff, 0x00000003ffffffff, - 0x000000003fffffff + 0x7fe7ffffffffffff, 0xffffffffffff0000, 0x0000000000ffffcf, 0x01ffffffffffffff, + 0x7f7ffffffffffdff, 0xfffc000000000001, 0x007ffefffffcffff, 0xb47ffffffffffb7f, + 0x00000000000000cb, 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, + 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000000ffff, + 0x7fffffffffff001f, 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, + 0xffff000000000000, 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000043ff01ff, + 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, + 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, + 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000007dbf9ffff7f, + 0x000000000000001f, 0x000000000000008f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, + 0x0ffffbee0ffffbff, 0xffff03ffffff03ff, 0x00000000000003ff, 0x00000000007fffff, + 0xffff0003ffffffff, 0x00000001ffffffff, 0x000000003fffffff ], }; @@ -426,9 +429,9 @@ pub mod derived_property { r3: &[ 0x00003fffffc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffffff00000, 0x1400000000000007, 0x0002000c00fe21fe, 0x1000000000000002, 0x0000000c0000201e, - 0x1000000000000006, 0x0023000000023986, 0x0000000c000021be, 0x9000000000000002, + 0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0x9000000000000002, 0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000001, - 0x0000000c00603dc1, 0x0000000c00003040, 0x0000000000000002, 0x00000000005c0400, + 0x0000000c00603dc1, 0x0000000c00003040, 0x1800000000000003, 0x00000000005c0400, 0x07f2000000000000, 0x0000000000007fc0, 0x1bf2000000000000, 0x0000000000003f40, 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x0000000000000040, 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, 0x1000000000000000, @@ -437,7 +440,7 @@ pub mod derived_property { 0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff008000000000, 0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000, 0x00cff00000000000, 0x3f00000000000000, 0x031021fdfff70000, 0xfffff00000000000, - 0x010007ffffffffff, 0xfffffffff8000000, 0xf83fffffffffffff, 0xa000000000000000, + 0x010007ffffffffff, 0xfffffffff8000000, 0xfbffffffffffffff, 0xa000000000000000, 0x6000e000e000e003, 0x00007c900300f800, 0x8002ffdf00000000, 0x000000001fff0000, 0x0001ffffffff0000, 0x3000000000000000, 0x0003800000000000, 0x8000800000000000, 0xffffffff00000000, 0x0000800000000000, 0x083e3c0000000020, 0x000000007e000000, @@ -465,24 +468,24 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 17, 18, 19, 20, - 0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 27, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, + 0, 0, 30, 0, 31, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, - 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 39, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 42, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 45, - 0, 0, 45, 45, 45, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 + 50, 51, 0, 0, 51, 51, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, @@ -491,12 +494,14 @@ pub mod derived_property { 0x0000000000001c00, 0x40d3800000000000, 0x000007f880000000, 0x1000000000000003, 0x001f1fc000000001, 0xff00000000000000, 0x000000000000005c, 0x85f8000000000000, 0x000000000000000d, 0xb03c000000000000, 0x0000000030000001, 0xa7f8000000000000, - 0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0xbf7f000000000000, - 0x006dfcfffffc0000, 0x001f000000000000, 0x007f000000000000, 0x000000000000000f, - 0x00000000ffff8000, 0x0000000f60000000, 0xfff8038000000000, 0x00003c0000000fe7, - 0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, - 0x000007dbf9ffff7f, 0x00000000007f0000, 0x00000000000007f0, 0xf800000000000000, - 0xffffffff00000002, 0xffffffffffffffff, 0x0000ffffffffffff + 0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0x79f800000000067e, + 0x000000000e7e0080, 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, + 0xb47e000000000000, 0x00000000000000bf, 0x001f000000000000, 0x007f000000000000, + 0x000000000000000f, 0x00000000ffff8000, 0x0000000300000000, 0x0000000f60000000, + 0xfff8038000000000, 0x00003c0000000fe7, 0x000000000000001c, 0xf87fffffffffffff, + 0x00201fffffffffff, 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f0000, + 0x00000000000007f0, 0xf800000000000000, 0xffffffff00000002, 0xffffffffffffffff, + 0x0000ffffffffffff ], }; @@ -851,12 +856,12 @@ pub mod derived_property { 127 ], r3: &[ - 0x00003fffffffffff, 0x000000000fffffff, 0x3fdfffff00000000, 0xfffffffbfff00000, - 0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x0003ffcfb080799f, - 0xd36dfdfffff987ee, 0x003fffc05e023987, 0xf3edfdfffffbbfee, 0x0200ffcf00013bbf, + 0x00003fffffffffff, 0x000007ff0fffffff, 0x3fdfffff00000000, 0xfffffffbfff00000, + 0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x1003ffcfb080799f, + 0xd36dfdfffff987ee, 0x003fffc05e023987, 0xf3edfdfffffbbfee, 0xfe00ffcf00013bbf, 0xf3edfdfffff99fee, 0x0002ffcfb0c0399f, 0xc3ffc718d63dc7ec, 0x0000ffc000813dc7, 0xe3fffdfffffddfef, 0x0000ffcf07603ddf, 0xf3effdfffffddfef, 0x0006ffcf40603ddf, - 0xe7fffffffffddfee, 0xfc00ffcf80f07ddf, 0x2ffbfffffc7fffec, 0x000cffc0ff5f847f, + 0xfffffffffffddfef, 0xfc00ffcf80f07ddf, 0x2ffbfffffc7fffec, 0x000cffc0ff5f847f, 0x07fffffffffffffe, 0x0000000003ff7fff, 0x3bffecaefef02596, 0x00000000f3ff3f5f, 0xc2a003ff03000001, 0xfffe1ffffffffeff, 0x1ffffffffeffffdf, 0x0000000000000040, 0xffffffffffff03ff, 0xffffffff3fffffff, 0xf7ffffffffff20bf, 0xffffffff3d7f3dff, @@ -867,13 +872,13 @@ pub mod derived_property { 0x003fffffffffffff, 0x0fff0fff7fffffff, 0x001f3fffffffffc0, 0xffff0fffffffffff, 0x0000000007ff03ff, 0xffffffff0fffffff, 0x9fffffff7fffffff, 0x3fff008003ff03ff, 0x0000000000000000, 0x000ff80003ff0fff, 0x000fffffffffffff, 0x3fffffffffffe3ff, - 0x00000000000001ff, 0x037ffffffff70000, 0xf83fffffffffffff, 0xffffffff3f3fffff, + 0x00000000000001ff, 0x03fffffffff70000, 0xfbffffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8000000000000000, 0x8002000000100001, 0x000000001fff0000, 0x0001ffe21fff0000, 0xf3fffd503f2ffc84, 0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000ff81fffffffff, 0xffff20bfffffffff, 0x800080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, - 0x1f3efffe000000e0, 0xfffffffee67fffff, 0xf7ffffffffffffff, 0xfffe3fffffffffe0, - 0x07ffffff00007fff, 0xffff000000000000, 0x00000000003fffff, 0x0000000000001fff, + 0x1f3efffe000000e0, 0xfffffffee67fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0, + 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, 0x3fffffffffff0000, 0x00000fffffff1fff, 0xbff0ffffffffffff, 0x0003ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, 0x000000ffffffffff, 0x28ffffff03ff003f, 0xffff3fffffffffff, 0x1fffffff000fffff, 0x7fffffff03ff8001, @@ -886,60 +891,62 @@ pub mod derived_property { ], r4: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13, - 14, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 14, 7, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + 5, 5, 5, 5, 5, 5, 5, 17, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ], r5: &[ 0, 1, 2, 3, 4, 5, 4, 6, 4, 4, 7, 8, 9, 10, 11, 12, 2, 2, 13, 14, 15, 16, 4, 4, 2, 2, 2, 2, 17, 18, 4, 4, 19, 20, 21, 22, 23, 4, 24, 4, 25, 26, 27, 28, 29, 30, 31, 4, 2, 32, 33, 33, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 34, 3, 35, 36, 37, 2, 38, 39, 4, 40, 41, 42, 43, 4, 4, 2, 44, 2, 45, 4, 4, 46, 47, 2, 48, 49, 50, 51, 4, 4, 4, 4, 4, 52, 53, 4, 4, 4, - 4, 4, 4, 4, 54, 4, 4, 4, 4, 55, 56, 57, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 58, 4, 2, 59, 2, 2, 2, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 63, 4, 2, 64, 2, 2, 2, 65, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 59, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 61, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, - 2, 2, 2, 2, 54, 62, 4, 63, 17, 64, 65, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 66, 67, - 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 2, 2, 2, 57, 67, 4, 68, 17, 69, 70, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, + 71, 72, 73, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 70, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 21, 75, 2, 2, 2, 2, 2, 76, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 2, 71, 72, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 73, 74, 4, 4, - 75, 4, 4, 4, 4, 4, 4, 2, 76, 77, 78, 79, 80, 2, 2, 2, 2, 81, 82, 83, 84, 85, 86, 4, 4, - 4, 4, 4, 4, 4, 4, 87, 88, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 2, 2, 2, 91, 2, 44, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 92, 93, 94, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 2, 77, 78, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 79, 80, 4, 4, 81, 4, 4, 4, 4, 4, 4, 2, 82, 83, 84, 85, 86, 2, 2, 2, 2, 87, 88, 89, 90, + 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 93, 94, 95, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 97, 2, 44, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 98, 99, 100, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 101, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 102, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 96, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 103, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 97, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 104, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 105, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ], r6: &[ 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, 0x0000000000000000, 0x001fffffffffffff, 0x2000000000000000, 0xffffffff1fffffff, - 0x000000010001ffff, 0xffff0000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, + 0x000000010001ffff, 0xffffe000ffffffff, 0x07ffffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, 0xffff03ff3fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, @@ -950,18 +957,20 @@ pub mod derived_property { 0xffff01ffbfffbd7f, 0x03ff07ffffffffff, 0xf3edfdfffff99fef, 0x001f1fcfe081399f, 0x0000000003ff07ff, 0x0000000003ff00bf, 0xff3fffffffffffff, 0x000000003f000001, 0x0000000003ff0011, 0x00ffffffffffffff, 0x00000000000003ff, 0x03ff0fffe3ffffff, - 0xffffffff00000000, 0x800003ffffffffff, 0x01ffffffffffffff, 0xff7ffffffffffdff, - 0xfffc000003ff0001, 0x007ffefffffcffff, 0x0000000003ffffff, 0x00007fffffffffff, - 0x000000000000000f, 0x000000000000007f, 0x000003ff7fffffff, 0x001f3fffffff0000, - 0xe0fffff803ff000f, 0x000000000000ffff, 0x7fffffffffff001f, 0x00000000ffff8000, - 0x0000000100000000, 0x00001fffffffffff, 0x0000000000000003, 0x1fff07ffffffffff, - 0x0000000063ff01ff, 0xf807e3e000000000, 0x00003c0000000fe7, 0x000000000000001c, - 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, - 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, - 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0xffffffffffffcff7, 0xf87fffffffffffff, - 0x00201fffffffffff, 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f001f, - 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, - 0x00000003ffffffff, 0x000000003fffffff, 0x0000ffffffffffff + 0xffffffff00000000, 0x800003ffffffffff, 0x7fffffffffffffff, 0xffffffffffff0080, + 0x0000000003ffffcf, 0x01ffffffffffffff, 0xff7ffffffffffdff, 0xfffc000003ff0001, + 0x007ffefffffcffff, 0xb47ffffffffffb7f, 0x0000000003ff00ff, 0x0000000003ffffff, + 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, 0x000003ff7fffffff, + 0x001f3fffffff0000, 0xe0fffff803ff000f, 0x000000000000ffff, 0x7fffffffffff001f, + 0x00000000ffff8000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000, + 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000063ff01ff, 0xf807e3e000000000, + 0x00003c0000000fe7, 0x000000000000001c, 0xffffffffffdfffff, 0xebffde64dfffffff, + 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, + 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, + 0xffffffffffffcff7, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, + 0x000007dbf9ffff7f, 0x00000000007f001f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, + 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, 0x00000001ffffffff, + 0x000000003fffffff, 0x0000ffffffffffff ], }; @@ -1027,8 +1036,8 @@ pub mod derived_property { 129, 130, 131, 132 ], r3: &[ - 0x00000110043fffff, 0x0000000001ffffff, 0x3fdfffff00000000, 0x0000000000000000, - 0x23fffffffffffff0, 0xfffe0003ff010000, 0x23c5fdfffff99fe1, 0x00030003b0004000, + 0x00000110043fffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0x0000000000000000, + 0x23fffffffffffff0, 0xfffe0003ff010000, 0x23c5fdfffff99fe1, 0x10030003b0004000, 0x036dfdfffff987e0, 0x001c00005e000000, 0x23edfdfffffbbfe0, 0x0200000300010000, 0x23edfdfffff99fe0, 0x00020003b0000000, 0x03ffc718d63dc7e8, 0x0000000000010000, 0x23fffdfffffddfe0, 0x0000000307000000, 0x23effdfffffddfe1, 0x0006000340000000, @@ -1048,8 +1057,8 @@ pub mod derived_property { 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, 0xf3fffd503f2ffc84, 0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0x000000007f7f7f7f, - 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, 0xfffe3fffffffffe0, - 0x07ffffff00007fff, 0xffff000000000000, 0x00000000003fffff, 0x0000000000001fff, + 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0, + 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x80007fffffffffff, 0xffffffff3fffffff, 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, 0x00000007fffff7bb, 0x000ffffffffffffc, 0x28fc000000000000, 0xffff003ffffffc00, @@ -1064,58 +1073,60 @@ pub mod derived_property { ], r4: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13, - 14, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 14, 7, 15, 16, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 ], r5: &[ 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 33, 4, 34, 35, 36, 37, 38, 39, 40, 4, 41, 20, 42, 43, 4, 4, 5, 44, 45, 46, 4, 4, 47, 48, 45, 49, 50, 4, 51, 4, 4, 4, 4, 4, 52, 53, 4, - 4, 4, 4, 4, 4, 4, 54, 4, 4, 4, 4, 55, 56, 57, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 51, 4, 2, 47, 2, 2, 2, 58, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 51, 4, 2, 47, 2, 2, 2, 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 59, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, - 2, 2, 2, 2, 2, 2, 54, 20, 4, 60, 45, 61, 57, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 62, 63, 64, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 65, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 67, 68, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 69, 70, 71, 72, 73, 2, 2, 2, 2, 74, 75, 76, 77, 78, 79, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 57, 20, 4, 65, 45, 66, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 67, 68, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 71, 2, 2, 2, 2, 2, + 72, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 73, 74, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 75, 76, 77, 78, 79, 2, 2, 2, 2, 80, 81, 82, 83, 84, + 85, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 2, 2, 2, 80, 2, 58, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 81, 82, 83, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 84, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 86, 2, 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 87, 88, 89, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 86, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4 + 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 93, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ], r6: &[ 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, 0x0000000000000000, 0x001fffffffffffff, 0xffffffff1fffffff, 0x000000000001ffff, - 0xffff0000ffffffff, 0x003fffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, + 0xffffe000ffffffff, 0x003fffffffff07ff, 0xffffffff3fffffff, 0x00000000003eff0f, 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, @@ -1126,15 +1137,17 @@ pub mod derived_property { 0x00000ffffffbffff, 0xffff01ffbfffbd7f, 0x23edfdfffff99fe0, 0x00000003e0010000, 0x0000000000000780, 0x0000ffffffffffff, 0x00000000000000b0, 0x00007fffffffffff, 0x000000000f000000, 0x0000000000000010, 0x000007ffffffffff, 0x0000000003ffffff, - 0xffffffff00000000, 0x80000000ffffffff, 0x01ffffffffffffff, 0x00007ffffffffdff, - 0xfffc000000000001, 0x000000000000ffff, 0x000000000000000f, 0x000000000000007f, - 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000001001f, 0x00000000fff80000, - 0x0000000100000000, 0x00001fffffffffff, 0x0000000000000003, 0x1fff07ffffffffff, - 0x0000000003ff01ff, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, - 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, - 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7, - 0x000000000000001f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, - 0x00000000007fffff, 0x00000003ffffffff, 0x000000003fffffff + 0xffffffff00000000, 0x80000000ffffffff, 0x0407fffffffff801, 0xfffffffff0010000, + 0x00000000000003cf, 0x01ffffffffffffff, 0x00007ffffffffdff, 0xfffc000000000001, + 0x000000000000ffff, 0x0001fffffffffb7f, 0x0000000000000040, 0x000000000000000f, + 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000001001f, + 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000, + 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000003ff01ff, 0xffffffffffdfffff, + 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, + 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, + 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000000000000001f, 0x0af7fe96ffffffef, + 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, + 0x00000001ffffffff, 0x000000003fffffff ], }; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ecab801d40853..d00e29d954fc6 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -99,7 +99,7 @@ impl Path { pub fn default_to_global(mut self) -> Path { if !self.is_global() && !::parse::token::Ident(self.segments[0].identifier).is_path_segment_keyword() { - self.segments.insert(0, PathSegment::crate_root()); + self.segments.insert(0, PathSegment::crate_root(self.span)); } self } @@ -133,10 +133,10 @@ impl PathSegment { pub fn from_ident(ident: Ident, span: Span) -> Self { PathSegment { identifier: ident, span: span, parameters: None } } - pub fn crate_root() -> Self { + pub fn crate_root(span: Span) -> Self { PathSegment { - identifier: keywords::CrateRoot.ident(), - span: DUMMY_SP, + identifier: Ident { ctxt: span.ctxt, ..keywords::CrateRoot.ident() }, + span: span, parameters: None, } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 8e63e219c42c1..f0fc849c0c596 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -1057,7 +1057,7 @@ impl MetaItem { { let (mut span, name) = match tokens.next() { Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name), - Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match **nt { + Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match nt.0 { token::Nonterminal::NtIdent(ident) => (ident.span, ident.node.name), token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), _ => return None, @@ -1229,7 +1229,7 @@ impl LitKind { match token { Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)), Token::Ident(ident) if ident.name == "false" => Some(LitKind::Bool(false)), - Token::Interpolated(ref nt) => match **nt { + Token::Interpolated(ref nt) => match nt.0 { token::NtExpr(ref v) => match v.node { ExprKind::Lit(ref lit) => Some(lit.node.clone()), _ => None, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 8089fad5f36d8..4881170c1d13a 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -215,7 +215,7 @@ impl<F> TTMacroExpander for F impl Folder for AvoidInterpolatedIdents { fn fold_tt(&mut self, tt: tokenstream::TokenTree) -> tokenstream::TokenTree { if let tokenstream::TokenTree::Token(_, token::Interpolated(ref nt)) = tt { - if let token::NtIdent(ident) = **nt { + if let token::NtIdent(ident) = nt.0 { return tokenstream::TokenTree::Token(ident.span, token::Ident(ident.node)); } } @@ -578,7 +578,10 @@ impl SyntaxExtension { pub fn is_modern(&self) -> bool { match *self { - SyntaxExtension::DeclMacro(..) => true, + SyntaxExtension::DeclMacro(..) | + SyntaxExtension::ProcMacro(..) | + SyntaxExtension::AttrProcMacro(..) | + SyntaxExtension::ProcMacroDerive(..) => true, _ => false, } } @@ -903,17 +906,3 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt, } Some(es) } - -pub struct ChangeSpan { - pub span: Span -} - -impl Folder for ChangeSpan { - fn new_span(&mut self, _sp: Span) -> Span { - self.span - } - - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - fold::noop_fold_mac(mac, self) - } -} diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 412a34932087d..03e5ea529e210 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -249,6 +249,8 @@ pub trait AstBuilder { name: Ident, attrs: Vec<ast::Attribute>, items: Vec<P<ast::Item>>) -> P<ast::Item>; + fn item_extern_crate(&self, span: Span, name: Ident) -> P<ast::Item>; + fn item_static(&self, span: Span, name: Ident, @@ -320,7 +322,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let last_identifier = idents.pop().unwrap(); let mut segments: Vec<ast::PathSegment> = Vec::new(); if global { - segments.push(ast::PathSegment::crate_root()); + segments.push(ast::PathSegment::crate_root(sp)); } segments.extend(idents.into_iter().map(|i| ast::PathSegment::from_ident(i, sp))); @@ -1095,6 +1097,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ) } + fn item_extern_crate(&self, span: Span, name: Ident) -> P<ast::Item> { + self.item(span, name, Vec::new(), ast::ItemKind::ExternCrate(None)) + } + fn item_static(&self, span: Span, name: Ident, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f8a26287bd47b..d2e51c9cb4868 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -16,20 +16,20 @@ use config::{is_test_or_bench, StripUnconfigured}; use errors::FatalError; use ext::base::*; use ext::derive::{add_derived_markers, collect_derives}; -use ext::hygiene::Mark; +use ext::hygiene::{Mark, SyntaxContext}; use ext::placeholders::{placeholder, PlaceholderExpander}; use feature_gate::{self, Features, is_builtin_attr}; use fold; use fold::*; -use parse::{filemap_to_stream, ParseSess, DirectoryOwnership, PResult, token}; +use parse::{DirectoryOwnership, PResult}; +use parse::token::{self, Token}; use parse::parser::Parser; -use print::pprust; use ptr::P; use std_inject; use symbol::Symbol; use symbol::keywords; use syntax_pos::{Span, DUMMY_SP}; -use tokenstream::TokenStream; +use tokenstream::{TokenStream, TokenTree}; use util::small_vector::SmallVector; use visit::Visitor; @@ -427,11 +427,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind.expect_from_annotatables(items) } SyntaxExtension::AttrProcMacro(ref mac) => { - let item_toks = stream_for_item(&item, self.cx.parse_sess); - - let span = Span { ctxt: self.cx.backtrace(), ..attr.span }; - let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_toks); - self.parse_expansion(tok_result, kind, &attr.path, span) + let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item { + Annotatable::Item(item) => token::NtItem(item), + Annotatable::TraitItem(item) => token::NtTraitItem(item.unwrap()), + Annotatable::ImplItem(item) => token::NtImplItem(item.unwrap()), + })).into(); + let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok); + self.parse_expansion(tok_result, kind, &attr.path, attr.span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path)); @@ -470,7 +472,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Ok(()) }; - let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark)); let opt_expanded = match *ext { SyntaxExtension::DeclMacro(ref expand, def_span) => { if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s), @@ -478,7 +479,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.span_err(path.span, &msg); return kind.dummy(span); } - kind.make_from(expand.expand(self.cx, span, marked_tts)) + kind.make_from(expand.expand(self.cx, span, mac.node.stream())) } NormalTT(ref expandfun, def_info, allow_internal_unstable) => { @@ -487,7 +488,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.span_err(path.span, &msg); return kind.dummy(span); } - kind.make_from(expandfun.expand(self.cx, span, marked_tts)) + kind.make_from(expandfun.expand(self.cx, span, mac.node.stream())) } IdentTT(ref expander, tt_span, allow_internal_unstable) => { @@ -506,7 +507,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } }); - let input: Vec<_> = marked_tts.into_trees().collect(); + let input: Vec<_> = mac.node.stream().into_trees().collect(); kind.make_from(expander.expand(self.cx, span, ident, input)) } @@ -541,21 +542,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }, }); - let tok_result = expandfun.expand(self.cx, span, marked_tts); + let tok_result = expandfun.expand(self.cx, span, mac.node.stream()); Some(self.parse_expansion(tok_result, kind, path, span)) } }; - let expanded = if let Some(expanded) = opt_expanded { - expanded - } else { + unwrap_or!(opt_expanded, { let msg = format!("non-{kind} macro in {kind} position: {name}", name = path.segments[0].identifier.name, kind = kind.name()); self.cx.span_err(path.span, &msg); - return kind.dummy(span); - }; - - expanded.fold_with(&mut Marker(mark)) + kind.dummy(span) + }) } /// Expand a derive invocation. Returns the result of expansion. @@ -621,8 +618,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } }; parser.ensure_complete_parse(path, kind.name(), span); - // FIXME better span info - expansion.fold_with(&mut ChangeSpan { span: span }) + expansion } } @@ -673,7 +669,9 @@ impl<'a> Parser<'a> { if self.token != token::Eof { let msg = format!("macro expansion ignores token `{}` and any following", self.this_token_to_string()); - let mut err = self.diagnostic().struct_span_err(self.span, &msg); + let mut def_site_span = self.span; + def_site_span.ctxt = SyntaxContext::empty(); // Avoid emitting backtrace info twice. + let mut err = self.diagnostic().struct_span_err(def_site_span, &msg); let msg = format!("caused by the macro expansion here; the usage \ of `{}!` is likely invalid in {} context", macro_path, kind_name); @@ -773,28 +771,6 @@ pub fn find_attr_invoc(attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute .map(|i| attrs.remove(i)) } -// These are pretty nasty. Ideally, we would keep the tokens around, linked from -// the AST. However, we don't so we need to create new ones. Since the item might -// have come from a macro expansion (possibly only in part), we can't use the -// existing codemap. -// -// Therefore, we must use the pretty printer (yuck) to turn the AST node into a -// string, which we then re-tokenise (double yuck), but first we have to patch -// the pretty-printed string on to the end of the existing codemap (infinity-yuck). -fn stream_for_item(item: &Annotatable, parse_sess: &ParseSess) -> TokenStream { - let text = match *item { - Annotatable::Item(ref i) => pprust::item_to_string(i), - Annotatable::TraitItem(ref ti) => pprust::trait_item_to_string(ti), - Annotatable::ImplItem(ref ii) => pprust::impl_item_to_string(ii), - }; - string_to_stream(text, parse_sess) -} - -fn string_to_stream(text: String, parse_sess: &ParseSess) -> TokenStream { - let filename = String::from("<macro expansion>"); - filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, text)) -} - impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> { let mut expr = self.cfg.configure_expr(expr).unwrap(); @@ -1070,7 +1046,7 @@ impl<'feat> ExpansionConfig<'feat> { } // A Marker adds the given mark to the syntax context. -struct Marker(Mark); +pub struct Marker(pub Mark); impl Folder for Marker { fn fold_ident(&mut self, mut ident: Ident) -> Ident { diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index f8fac847a053e..9907dfe341e75 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -30,9 +30,9 @@ pub mod rt { use ast; use codemap::Spanned; use ext::base::ExtCtxt; - use parse::{self, token, classify}; + use parse::{self, classify}; + use parse::token::{self, Token}; use ptr::P; - use std::rc::Rc; use symbol::Symbol; use tokenstream::{self, TokenTree, TokenStream}; @@ -82,70 +82,70 @@ pub mod rt { impl ToTokens for ast::Path { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtPath(self.clone()); - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))] } } impl ToTokens for ast::Ty { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtTy(P(self.clone())); - vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(self.span, Token::interpolated(nt))] } } impl ToTokens for ast::Block { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtBlock(P(self.clone())); - vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(self.span, Token::interpolated(nt))] } } impl ToTokens for ast::Generics { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtGenerics(self.clone()); - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))] } } impl ToTokens for ast::WhereClause { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtWhereClause(self.clone()); - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))] } } impl ToTokens for P<ast::Item> { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtItem(self.clone()); - vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(self.span, Token::interpolated(nt))] } } impl ToTokens for ast::ImplItem { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtImplItem(self.clone()); - vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(self.span, Token::interpolated(nt))] } } impl ToTokens for P<ast::ImplItem> { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtImplItem((**self).clone()); - vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(self.span, Token::interpolated(nt))] } } impl ToTokens for ast::TraitItem { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtTraitItem(self.clone()); - vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(self.span, Token::interpolated(nt))] } } impl ToTokens for ast::Stmt { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtStmt(self.clone()); - let mut tts = vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]; + let mut tts = vec![TokenTree::Token(self.span, Token::interpolated(nt))]; // Some statements require a trailing semicolon. if classify::stmt_ends_with_semi(&self.node) { @@ -159,35 +159,35 @@ pub mod rt { impl ToTokens for P<ast::Expr> { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtExpr(self.clone()); - vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(self.span, Token::interpolated(nt))] } } impl ToTokens for P<ast::Pat> { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtPat(self.clone()); - vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(self.span, Token::interpolated(nt))] } } impl ToTokens for ast::Arm { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtArm(self.clone()); - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))] } } impl ToTokens for ast::Arg { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtArg(self.clone()); - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))] } } impl ToTokens for P<ast::Block> { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtBlock(self.clone()); - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))] } } @@ -215,7 +215,7 @@ pub mod rt { impl ToTokens for ast::MetaItem { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let nt = token::NtMeta(self.clone()); - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] + vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))] } } @@ -364,7 +364,7 @@ pub mod rt { fn parse_tts(&self, s: String) -> Vec<TokenTree> { let source_name = "<quote expansion>".to_owned(); - parse::parse_stream_from_source_str(source_name, s, self.parse_sess()) + parse::parse_stream_from_source_str(source_name, s, self.parse_sess(), None) .into_trees().collect() } } @@ -700,7 +700,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> { token::Underscore => "Underscore", token::Eof => "Eof", - token::Whitespace | token::SubstNt(_) | token::Comment | token::Shebang(_) => { + token::Whitespace | token::Comment | token::Shebang(_) => { panic!("unhandled token in quote!"); } }; diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 61d8fc2941afb..e877f1fedd409 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -158,15 +158,10 @@ pub type NamedParseResult = ParseResult<HashMap<Ident, Rc<NamedMatch>>>; pub fn count_names(ms: &[TokenTree]) -> usize { ms.iter().fold(0, |count, elt| { count + match *elt { - TokenTree::Sequence(_, ref seq) => { - seq.num_captures - } - TokenTree::Delimited(_, ref delim) => { - count_names(&delim.tts) - } - TokenTree::MetaVarDecl(..) => { - 1 - } + TokenTree::Sequence(_, ref seq) => seq.num_captures, + TokenTree::Delimited(_, ref delim) => count_names(&delim.tts), + TokenTree::MetaVar(..) => 0, + TokenTree::MetaVarDecl(..) => 1, TokenTree::Token(..) => 0, } }) @@ -244,7 +239,7 @@ fn nameize<I: Iterator<Item=NamedMatch>>(sess: &ParseSess, ms: &[TokenTree], mut } } } - TokenTree::Token(..) => (), + TokenTree::MetaVar(..) | TokenTree::Token(..) => (), } Ok(()) @@ -409,12 +404,11 @@ fn inner_parse_loop(sess: &ParseSess, ei.idx = 0; cur_eis.push(ei); } - TokenTree::Token(_, ref t) => { - if token_name_eq(t, token) { - ei.idx += 1; - next_eis.push(ei); - } + TokenTree::Token(_, ref t) if token_name_eq(t, token) => { + ei.idx += 1; + next_eis.push(ei); } + TokenTree::Token(..) | TokenTree::MetaVar(..) => {} } } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 9c728c9f2ebf0..b732f47ce6a93 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -120,7 +120,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, _ => cx.span_bug(sp, "malformed macro rhs"), }; // rhs has holes ( `$id` and `$(...)` that need filled) - let tts = transcribe(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs); + let tts = transcribe(cx, Some(named_matches), rhs); if cx.trace_macros() { trace_macros_note(cx, sp, format!("to `{}`", tts)); @@ -292,7 +292,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool { use self::quoted::TokenTree; for tt in tts { match *tt { - TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => (), + TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (), TokenTree::Delimited(_, ref del) => if !check_lhs_no_empty_seq(sess, &del.tts) { return false; }, @@ -372,7 +372,7 @@ impl FirstSets { let mut first = TokenSet::empty(); for tt in tts.iter().rev() { match *tt { - TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => { + TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => { first.replace_with(tt.clone()); } TokenTree::Delimited(span, ref delimited) => { @@ -432,7 +432,7 @@ impl FirstSets { for tt in tts.iter() { assert!(first.maybe_empty); match *tt { - TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => { + TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => { first.add_one(tt.clone()); return first; } @@ -602,7 +602,7 @@ fn check_matcher_core(sess: &ParseSess, // First, update `last` so that it corresponds to the set // of NT tokens that might end the sequence `... token`. match *token { - TokenTree::Token(..) | TokenTree::MetaVarDecl(..) => { + TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => { let can_be_followed_by_any; if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, token) { let msg = format!("invalid fragment specifier `{}`", bad_frag); @@ -872,6 +872,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess, fn quoted_tt_to_string(tt: "ed::TokenTree) -> String { match *tt { quoted::TokenTree::Token(_, ref tok) => ::print::pprust::token_to_string(tok), + quoted::TokenTree::MetaVar(_, name) => format!("${}", name), quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind), _ => panic!("unexpected quoted::TokenTree::{{Sequence or Delimited}} \ in follow set checker"), diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index c094a23cefc4a..4e9e30857b1e8 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -78,9 +78,11 @@ pub enum KleeneOp { pub enum TokenTree { Token(Span, token::Token), Delimited(Span, Rc<Delimited>), - /// A kleene-style repetition sequence with a span + /// A kleene-style repetition sequence Sequence(Span, Rc<SequenceRepetition>), - /// Matches a nonterminal. This is only used in the left hand side of MBE macros. + /// E.g. `$var` + MetaVar(Span, ast::Ident), + /// E.g. `$var:expr`. This is only used in the left hand side of MBE macros. MetaVarDecl(Span, ast::Ident /* name to bind */, ast::Ident /* kind of nonterminal */), } @@ -130,6 +132,7 @@ impl TokenTree { pub fn span(&self) -> Span { match *self { TokenTree::Token(sp, _) | + TokenTree::MetaVar(sp, _) | TokenTree::MetaVarDecl(sp, _, _) | TokenTree::Delimited(sp, _) | TokenTree::Sequence(sp, _) => sp, @@ -144,7 +147,7 @@ pub fn parse(input: tokenstream::TokenStream, expect_matchers: bool, sess: &Pars while let Some(tree) = trees.next() { let tree = parse_tree(tree, &mut trees, expect_matchers, sess); match tree { - TokenTree::Token(start_sp, token::SubstNt(ident)) if expect_matchers => { + TokenTree::MetaVar(start_sp, ident) if expect_matchers => { let span = match trees.next() { Some(tokenstream::TokenTree::Token(span, token::Colon)) => match trees.next() { Some(tokenstream::TokenTree::Token(end_sp, ref tok)) => match tok.ident() { @@ -199,13 +202,13 @@ fn parse_tree<I>(tree: tokenstream::TokenTree, let ident = ast::Ident { name: keywords::DollarCrate.name(), ..ident }; TokenTree::Token(span, token::Ident(ident)) } else { - TokenTree::Token(span, token::SubstNt(ident)) + TokenTree::MetaVar(span, ident) } } Some(tokenstream::TokenTree::Token(span, tok)) => { let msg = format!("expected identifier, found `{}`", pprust::token_to_string(&tok)); sess.span_diagnostic.span_err(span, &msg); - TokenTree::Token(span, token::SubstNt(keywords::Invalid.ident())) + TokenTree::MetaVar(span, keywords::Invalid.ident()) } None => TokenTree::Token(span, token::Dollar), }, diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 78e755e73fa30..fe3dd83f9d5c0 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -9,10 +9,12 @@ // except according to those terms. use ast::Ident; -use errors::Handler; +use ext::base::ExtCtxt; +use ext::expand::Marker; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use ext::tt::quoted; -use parse::token::{self, SubstNt, Token, NtTT}; +use fold::noop_fold_tt; +use parse::token::{self, Token, NtTT}; use syntax_pos::{Span, DUMMY_SP}; use tokenstream::{TokenStream, TokenTree, Delimited}; use util::small_vector::SmallVector; @@ -61,9 +63,9 @@ impl Iterator for Frame { } /// This can do Macro-By-Example transcription. On the other hand, if -/// `src` contains no `TokenTree::{Sequence, Match}`s, or `SubstNt`s, `interp` can +/// `src` contains no `TokenTree::{Sequence, MetaVar, MetaVarDecl}`s, `interp` can /// (and should) be None. -pub fn transcribe(sp_diag: &Handler, +pub fn transcribe(cx: &ExtCtxt, interp: Option<HashMap<Ident, Rc<NamedMatch>>>, src: Vec<quoted::TokenTree>) -> TokenStream { @@ -120,22 +122,20 @@ pub fn transcribe(sp_diag: &Handler, &interpolations, &repeats) { LockstepIterSize::Unconstrained => { - panic!(sp_diag.span_fatal( - sp, /* blame macro writer */ + cx.span_fatal(sp, /* blame macro writer */ "attempted to repeat an expression \ containing no syntax \ - variables matched as repeating at this depth")); + variables matched as repeating at this depth"); } LockstepIterSize::Contradiction(ref msg) => { // FIXME #2887 blame macro invoker instead - panic!(sp_diag.span_fatal(sp, &msg[..])); + cx.span_fatal(sp, &msg[..]); } LockstepIterSize::Constraint(len, _) => { if len == 0 { if seq.op == quoted::KleeneOp::OneOrMore { // FIXME #2887 blame invoker - panic!(sp_diag.span_fatal(sp, - "this must repeat at least once")); + cx.span_fatal(sp, "this must repeat at least once"); } } else { repeats.push((0, len)); @@ -149,29 +149,37 @@ pub fn transcribe(sp_diag: &Handler, } } // FIXME #2887: think about span stuff here - quoted::TokenTree::Token(sp, SubstNt(ident)) => { - match lookup_cur_matched(ident, &interpolations, &repeats) { - None => result.push(TokenTree::Token(sp, SubstNt(ident)).into()), - Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched { - match **nt { - NtTT(ref tt) => result.push(tt.clone().into()), - _ => { - let token = TokenTree::Token(sp, token::Interpolated(nt.clone())); - result.push(token.into()); - } + quoted::TokenTree::MetaVar(mut sp, ident) => { + if let Some(cur_matched) = lookup_cur_matched(ident, &interpolations, &repeats) { + if let MatchedNonterminal(ref nt) = *cur_matched { + if let NtTT(ref tt) = **nt { + result.push(tt.clone().into()); + } else { + sp.ctxt = sp.ctxt.apply_mark(cx.current_expansion.mark); + let token = TokenTree::Token(sp, Token::interpolated((**nt).clone())); + result.push(token.into()); } } else { - panic!(sp_diag.span_fatal( - sp, /* blame the macro writer */ - &format!("variable '{}' is still repeating at this depth", ident))); + cx.span_fatal(sp, /* blame the macro writer */ + &format!("variable '{}' is still repeating at this depth", ident)); } + } else { + let ident = + Ident { ctxt: ident.ctxt.apply_mark(cx.current_expansion.mark), ..ident }; + sp.ctxt = sp.ctxt.apply_mark(cx.current_expansion.mark); + result.push(TokenTree::Token(sp, token::Dollar).into()); + result.push(TokenTree::Token(sp, token::Ident(ident)).into()); } } - quoted::TokenTree::Delimited(span, delimited) => { + quoted::TokenTree::Delimited(mut span, delimited) => { + span.ctxt = span.ctxt.apply_mark(cx.current_expansion.mark); stack.push(Frame::Delimited { forest: delimited, idx: 0, span: span }); result_stack.push(mem::replace(&mut result, Vec::new())); } - quoted::TokenTree::Token(span, tok) => result.push(TokenTree::Token(span, tok).into()), + quoted::TokenTree::Token(sp, tok) => { + let mut marker = Marker(cx.current_expansion.mark); + result.push(noop_fold_tt(TokenTree::Token(sp, tok), &mut marker).into()) + } quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"), } } @@ -240,7 +248,7 @@ fn lockstep_iter_size(tree: "ed::TokenTree, size + lockstep_iter_size(tt, interpolations, repeats) }) }, - TokenTree::Token(_, SubstNt(name)) | TokenTree::MetaVarDecl(_, name, _) => + TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => match lookup_cur_matched(name, interpolations, repeats) { Some(matched) => match *matched { MatchedNonterminal(_) => LockstepIterSize::Unconstrained, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index df8ee189d21b3..cb625b1ac066e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -38,12 +38,19 @@ use symbol::Symbol; use std::ascii::AsciiExt; use std::env; -macro_rules! setter { +macro_rules! set { + (proc_macro) => {{ + fn f(features: &mut Features, span: Span) { + features.declared_lib_features.push((Symbol::intern("proc_macro"), span)); + features.proc_macro = true; + } + f as fn(&mut Features, Span) + }}; ($field: ident) => {{ - fn f(features: &mut Features) -> &mut bool { - &mut features.$field + fn f(features: &mut Features, _: Span) { + features.$field = true; } - f as fn(&mut Features) -> &mut bool + f as fn(&mut Features, Span) }} } @@ -51,10 +58,9 @@ macro_rules! declare_features { ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => { /// Represents active features that are currently being implemented or /// currently being considered for addition/removal. - const ACTIVE_FEATURES: &'static [(&'static str, &'static str, - Option<u32>, fn(&mut Features) -> &mut bool)] = &[ - $((stringify!($feature), $ver, $issue, setter!($feature))),+ - ]; + const ACTIVE_FEATURES: + &'static [(&'static str, &'static str, Option<u32>, fn(&mut Features, Span))] = + &[$((stringify!($feature), $ver, $issue, set!($feature))),+]; /// A set of features to be used by later passes. pub struct Features { @@ -137,7 +143,6 @@ declare_features! ( (active, placement_in_syntax, "1.0.0", Some(27779)), (active, unboxed_closures, "1.0.0", Some(29625)), - (active, allocator, "1.0.0", Some(27389)), (active, fundamental, "1.0.0", Some(29635)), (active, main, "1.0.0", Some(29634)), (active, needs_allocator, "1.4.0", Some(27389)), @@ -360,6 +365,10 @@ declare_features! ( // Allows unsized tuple coercion. (active, unsized_tuple_coercion, "1.20.0", Some(42877)), + + // global allocators and their internals + (active, global_allocator, "1.20.0", None), + (active, allocator_internals, "1.20.0", None), ); declare_features! ( @@ -379,6 +388,7 @@ declare_features! ( // rustc internal (removed, unmarked_api, "1.0.0", None), (removed, pushpop_unsafe, "1.2.0", None), + (removed, allocator, "1.0.0", None), ); declare_features! ( @@ -585,16 +595,22 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "the `#[rustc_on_unimplemented]` attribute \ is an experimental feature", cfg_fn!(on_unimplemented))), - ("allocator", Whitelisted, Gated(Stability::Unstable, - "allocator", - "the `#[allocator]` attribute is an experimental feature", - cfg_fn!(allocator))), + ("global_allocator", Normal, Gated(Stability::Unstable, + "global_allocator", + "the `#[global_allocator]` attribute is \ + an experimental feature", + cfg_fn!(global_allocator))), + ("default_lib_allocator", Whitelisted, Gated(Stability::Unstable, + "allocator_internals", + "the `#[default_lib_allocator]` \ + attribute is an experimental feature", + cfg_fn!(allocator_internals))), ("needs_allocator", Normal, Gated(Stability::Unstable, - "needs_allocator", + "allocator_internals", "the `#[needs_allocator]` \ attribute is an experimental \ feature", - cfg_fn!(needs_allocator))), + cfg_fn!(allocator_internals))), ("panic_runtime", Whitelisted, Gated(Stability::Unstable, "panic_runtime", "the `#[panic_runtime]` attribute is \ @@ -1478,9 +1494,9 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F continue }; - if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter() + if let Some(&(_, _, _, set)) = ACTIVE_FEATURES.iter() .find(|& &(n, _, _, _)| name == n) { - *(setter(&mut features)) = true; + set(&mut features, mi.span); feature_checker.collect(&features, mi.span); } else if let Some(&(_, _, _)) = REMOVED_FEATURES.iter() @@ -1514,7 +1530,7 @@ struct MutexFeatureChecker { impl MutexFeatureChecker { // If this method turns out to be a hotspot due to branching, - // the branching can be eliminated by modifying `setter!()` to set these spans + // the branching can be eliminated by modifying `set!()` to set these spans // only for the features that need to be checked for mutual exclusion. fn collect(&mut self, features: &Features, span: Span) { if features.proc_macro { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4c6cf49a8db43..1fc670ec9f7fb 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -22,7 +22,7 @@ use ast::*; use ast; use syntax_pos::Span; use codemap::{Spanned, respan}; -use parse::token; +use parse::token::{self, Token}; use ptr::P; use symbol::keywords; use tokenstream::*; @@ -573,7 +573,7 @@ pub fn noop_fold_tt<T: Folder>(tt: TokenTree, fld: &mut T) -> TokenTree { } pub fn noop_fold_tts<T: Folder>(tts: TokenStream, fld: &mut T) -> TokenStream { - tts.trees().map(|tt| fld.fold_tt(tt)).collect() + tts.map(|tt| fld.fold_tt(tt)) } // apply ident folder if it's an ident, apply other folds to interpolated nodes @@ -586,9 +586,8 @@ pub fn noop_fold_token<T: Folder>(t: token::Token, fld: &mut T) -> token::Token Ok(nt) => nt, Err(nt) => (*nt).clone(), }; - token::Interpolated(Rc::new(fld.fold_interpolated(nt))) + Token::interpolated(fld.fold_interpolated(nt.0)) } - token::SubstNt(ident) => token::SubstNt(fld.fold_ident(ident)), _ => t } } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 082930777e598..c99a09ab24e6b 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -151,7 +151,7 @@ impl<'a> Parser<'a> { pub fn parse_path_and_tokens(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { let meta = match self.token { - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt) => match nt.0 { Nonterminal::NtMeta(ref meta) => Some(meta.clone()), _ => None, }, @@ -223,7 +223,7 @@ impl<'a> Parser<'a> { /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { let nt_meta = match self.token { - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt) => match nt.0 { token::NtMeta(ref e) => Some(e.clone()), _ => None, }, diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index a35b278a4b064..09cdf26bf1fff 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -66,14 +66,15 @@ pub struct StringReader<'a> { token: token::Token, span: Span, open_braces: Vec<(token::DelimToken, Span)>, -} - -fn mk_sp(lo: BytePos, hi: BytePos) -> Span { - Span { lo: lo, hi: hi, ctxt: NO_EXPANSION } + pub override_span: Option<Span>, } impl<'a> StringReader<'a> { - fn next_token(&mut self) -> TokenAndSpan { + fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span { + unwrap_or!(self.override_span, Span { lo: lo, hi: hi, ctxt: NO_EXPANSION}) + } + + fn next_token(&mut self) -> TokenAndSpan where Self: Sized { let res = self.try_next_token(); self.unwrap_or_abort(res) } @@ -175,6 +176,7 @@ impl<'a> StringReader<'a> { token: token::Eof, span: syntax_pos::DUMMY_SP, open_braces: Vec::new(), + override_span: None, } } @@ -229,12 +231,12 @@ impl<'a> StringReader<'a> { /// Report a fatal error spanning [`from_pos`, `to_pos`). fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError { - self.fatal_span(mk_sp(from_pos, to_pos), m) + self.fatal_span(self.mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`). fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) { - self.err_span(mk_sp(from_pos, to_pos), m) + self.err_span(self.mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an @@ -258,7 +260,7 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } - self.sess.span_diagnostic.struct_span_fatal(mk_sp(from_pos, to_pos), &m[..]) + self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..]) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an @@ -282,7 +284,7 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } - self.sess.span_diagnostic.struct_span_err(mk_sp(from_pos, to_pos), &m[..]) + self.sess.span_diagnostic.struct_span_err(self.mk_sp(from_pos, to_pos), &m[..]) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the @@ -306,11 +308,11 @@ impl<'a> StringReader<'a> { None => { if self.is_eof() { self.peek_tok = token::Eof; - self.peek_span = mk_sp(self.filemap.end_pos, self.filemap.end_pos); + self.peek_span = self.mk_sp(self.filemap.end_pos, self.filemap.end_pos); } else { let start_bytepos = self.pos; self.peek_tok = self.next_token_inner()?; - self.peek_span = mk_sp(start_bytepos, self.pos); + self.peek_span = self.mk_sp(start_bytepos, self.pos); }; } } @@ -481,7 +483,7 @@ impl<'a> StringReader<'a> { self.with_str_from(start, |string| { if string == "_" { self.sess.span_diagnostic - .struct_span_warn(mk_sp(start, self.pos), + .struct_span_warn(self.mk_sp(start, self.pos), "underscore literal suffix is not allowed") .warn("this was previously accepted by the compiler but is \ being phased out; it will become a hard error in \ @@ -502,7 +504,7 @@ impl<'a> StringReader<'a> { if let Some(c) = self.ch { if c.is_whitespace() { let msg = "called consume_any_line_comment, but there was whitespace"; - self.sess.span_diagnostic.span_err(mk_sp(self.pos, self.pos), msg); + self.sess.span_diagnostic.span_err(self.mk_sp(self.pos, self.pos), msg); } } @@ -545,13 +547,13 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: mk_sp(start_bpos, self.pos), + sp: self.mk_sp(start_bpos, self.pos), }) }) } else { Some(TokenAndSpan { tok: token::Comment, - sp: mk_sp(start_bpos, self.pos), + sp: self.mk_sp(start_bpos, self.pos), }) } } @@ -584,7 +586,7 @@ impl<'a> StringReader<'a> { } return Some(TokenAndSpan { tok: token::Shebang(self.name_from(start)), - sp: mk_sp(start, self.pos), + sp: self.mk_sp(start, self.pos), }); } } @@ -612,7 +614,7 @@ impl<'a> StringReader<'a> { } let c = Some(TokenAndSpan { tok: token::Whitespace, - sp: mk_sp(start_bpos, self.pos), + sp: self.mk_sp(start_bpos, self.pos), }); debug!("scanning whitespace: {:?}", c); c @@ -674,7 +676,7 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: mk_sp(start_bpos, self.pos), + sp: self.mk_sp(start_bpos, self.pos), }) }) } @@ -869,7 +871,7 @@ impl<'a> StringReader<'a> { let valid = if self.ch_is('{') { self.scan_unicode_escape(delim) && !ascii_only } else { - let span = mk_sp(start, self.pos); + let span = self.mk_sp(start, self.pos); self.sess.span_diagnostic .struct_span_err(span, "incorrect unicode escape sequence") .span_help(span, @@ -907,13 +909,13 @@ impl<'a> StringReader<'a> { }, c); if e == '\r' { - err.span_help(mk_sp(escaped_pos, pos), + err.span_help(self.mk_sp(escaped_pos, pos), "this is an isolated carriage return; consider \ checking your editor and version control \ settings"); } if (e == '{' || e == '}') && !ascii_only { - err.span_help(mk_sp(escaped_pos, pos), + err.span_help(self.mk_sp(escaped_pos, pos), "if used in a formatting string, curly braces \ are escaped with `{{` and `}}`"); } diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 554a1fcfc71a6..63a396c14db85 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -19,7 +19,9 @@ impl<'a> StringReader<'a> { pub fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { let mut tts = Vec::new(); while self.token != token::Eof { - tts.push(self.parse_token_tree()?.into()); + let tree = self.parse_token_tree()?; + let is_joint = tree.span().hi == self.span.lo && token::is_op(&self.token); + tts.push(if is_joint { tree.joint() } else { tree.into() }); } Ok(TokenStream::concat(tts)) } @@ -31,13 +33,15 @@ impl<'a> StringReader<'a> { if let token::CloseDelim(..) = self.token { return TokenStream::concat(tts); } - match self.parse_token_tree() { - Ok(tt) => tts.push(tt.into()), + let tree = match self.parse_token_tree() { + Ok(tree) => tree, Err(mut e) => { e.emit(); return TokenStream::concat(tts); } - } + }; + let is_joint = tree.span().hi == self.span.lo && token::is_op(&self.token); + tts.push(if is_joint { tree.joint() } else { tree.into() }); } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 3a68a6ba7646c..bd9a621c00c00 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -141,9 +141,10 @@ pub fn parse_stmt_from_source_str(name: String, source: String, sess: &ParseSess new_parser_from_source_str(sess, name, source).parse_stmt() } -pub fn parse_stream_from_source_str(name: String, source: String, sess: &ParseSess) - -> TokenStream { - filemap_to_stream(sess, sess.codemap().new_filemap(name, source)) +pub fn parse_stream_from_source_str(name: String, source: String, sess: &ParseSess, + override_span: Option<Span>) + -> TokenStream { + filemap_to_stream(sess, sess.codemap().new_filemap(name, source), override_span) } // Create a new parser from a source string @@ -177,7 +178,7 @@ pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, /// Given a filemap and config, return a parser pub fn filemap_to_parser(sess: & ParseSess, filemap: Rc<FileMap>, ) -> Parser { let end_pos = filemap.end_pos; - let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap)); + let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap, None)); if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP { parser.span = Span { lo: end_pos, hi: end_pos, ctxt: NO_EXPANSION }; @@ -212,8 +213,10 @@ fn file_to_filemap(sess: &ParseSess, path: &Path, spanopt: Option<Span>) } /// Given a filemap, produce a sequence of token-trees -pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc<FileMap>) -> TokenStream { +pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc<FileMap>, override_span: Option<Span>) + -> TokenStream { let mut srdr = lexer::StringReader::new(sess, filemap); + srdr.override_span = override_span; srdr.real_token(); panictry!(srdr.parse_all_token_trees()) } @@ -684,7 +687,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 6), - segments: vec![ast::PathSegment::crate_root(), + segments: vec![ast::PathSegment::crate_root(sp(0, 2)), str2seg("a", 2, 3), str2seg("b", 5, 6)] }), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 64506c4af4691..c248e20b608fc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -107,7 +107,7 @@ pub enum BlockMode { macro_rules! maybe_whole_expr { ($p:expr) => { if let token::Interpolated(nt) = $p.token.clone() { - match *nt { + match nt.0 { token::NtExpr(ref e) => { $p.bump(); return Ok((*e).clone()); @@ -134,7 +134,7 @@ macro_rules! maybe_whole_expr { macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { if let token::Interpolated(nt) = $p.token.clone() { - if let token::$constructor($x) = (*nt).clone() { + if let token::$constructor($x) = nt.0.clone() { $p.bump(); return Ok($e); } @@ -1602,7 +1602,7 @@ impl<'a> Parser<'a> { /// Matches token_lit = LIT_INTEGER | ... pub fn parse_lit_token(&mut self) -> PResult<'a, LitKind> { let out = match self.token { - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt) => match nt.0 { token::NtExpr(ref v) => match v.node { ExprKind::Lit(ref lit) => { lit.node.clone() } _ => { return self.unexpected_last(&self.token); } @@ -1761,7 +1761,7 @@ impl<'a> Parser<'a> { }; if is_global { - segments.insert(0, PathSegment::crate_root()); + segments.insert(0, PathSegment::crate_root(lo)); } // Assemble the result. @@ -1775,7 +1775,7 @@ impl<'a> Parser<'a> { /// This is used when parsing derive macro paths in `#[derive]` attributes. pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { let meta_ident = match self.token { - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt) => match nt.0 { token::NtMeta(ref meta) => match meta.node { ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)), _ => None, @@ -2610,13 +2610,16 @@ impl<'a> Parser<'a> { pub fn process_potential_macro_variable(&mut self) { let ident = match self.token { - token::SubstNt(name) => { + token::Dollar if self.span.ctxt != syntax_pos::hygiene::SyntaxContext::empty() && + self.look_ahead(1, |t| t.is_ident()) => { + self.bump(); + let name = match self.token { token::Ident(ident) => ident, _ => unreachable!() }; self.fatal(&format!("unknown macro variable `{}`", name)).emit(); return } token::Interpolated(ref nt) => { self.meta_var_span = Some(self.span); - match **nt { + match nt.0 { token::NtIdent(ident) => ident, _ => return, } @@ -6168,7 +6171,7 @@ impl<'a> Parser<'a> { // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. self.eat(&token::ModSep); let prefix = ast::Path { - segments: vec![PathSegment::crate_root()], + segments: vec![PathSegment::crate_root(lo)], span: lo.to(self.span), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 75969cf2eb85b..834ac38af9870 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -16,10 +16,12 @@ pub use self::Token::*; use ast::{self}; use ptr::P; +use serialize::{Decodable, Decoder, Encodable, Encoder}; use symbol::keywords; -use tokenstream::TokenTree; +use tokenstream::{TokenStream, TokenTree}; -use std::fmt; +use std::cell::Cell; +use std::{cmp, fmt}; use std::rc::Rc; #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -167,14 +169,12 @@ pub enum Token { Underscore, Lifetime(ast::Ident), - /* For interpolation */ - Interpolated(Rc<Nonterminal>), + // The `LazyTokenStream` is a pure function of the `Nonterminal`, + // and so the `LazyTokenStream` can be ignored by Eq, Hash, etc. + Interpolated(Rc<(Nonterminal, LazyTokenStream)>), // Can be expanded into several tokens. /// Doc comment DocComment(ast::Name), - // In right-hand-sides of MBE macros: - /// A syntactic variable that will be filled in by macro expansion. - SubstNt(ast::Ident), // Junk. These carry no data because we don't really care about the data // they *would* carry, and don't really want to allocate a new ident for @@ -190,6 +190,10 @@ pub enum Token { } impl Token { + pub fn interpolated(nt: Nonterminal) -> Token { + Token::Interpolated(Rc::new((nt, LazyTokenStream::new()))) + } + /// Returns `true` if the token starts with '>'. pub fn is_like_gt(&self) -> bool { match *self { @@ -214,7 +218,7 @@ impl Token { Lt | BinOp(Shl) | // associated path ModSep | // global path Pound => true, // expression attributes - Interpolated(ref nt) => match **nt { + Interpolated(ref nt) => match nt.0 { NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true, _ => false, }, @@ -237,7 +241,7 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | BinOp(Shl) | // associated path ModSep => true, // global path - Interpolated(ref nt) => match **nt { + Interpolated(ref nt) => match nt.0 { NtIdent(..) | NtTy(..) | NtPath(..) => true, _ => false, }, @@ -256,7 +260,7 @@ impl Token { pub fn ident(&self) -> Option<ast::Ident> { match *self { Ident(ident) => Some(ident), - Interpolated(ref nt) => match **nt { + Interpolated(ref nt) => match nt.0 { NtIdent(ident) => Some(ident.node), _ => None, }, @@ -288,7 +292,7 @@ impl Token { /// Returns `true` if the token is an interpolated path. pub fn is_path(&self) -> bool { if let Interpolated(ref nt) = *self { - if let NtPath(..) = **nt { + if let NtPath(..) = nt.0 { return true; } } @@ -358,6 +362,60 @@ impl Token { } } + pub fn glue(self, joint: Token) -> Option<Token> { + Some(match self { + Eq => match joint { + Eq => EqEq, + Gt => FatArrow, + _ => return None, + }, + Lt => match joint { + Eq => Le, + Lt => BinOp(Shl), + Le => BinOpEq(Shl), + BinOp(Minus) => LArrow, + _ => return None, + }, + Gt => match joint { + Eq => Ge, + Gt => BinOp(Shr), + Ge => BinOpEq(Shr), + _ => return None, + }, + Not => match joint { + Eq => Ne, + _ => return None, + }, + BinOp(op) => match joint { + Eq => BinOpEq(op), + BinOp(And) if op == And => AndAnd, + BinOp(Or) if op == Or => OrOr, + Gt if op == Minus => RArrow, + _ => return None, + }, + Dot => match joint { + Dot => DotDot, + DotDot => DotDotDot, + _ => return None, + }, + DotDot => match joint { + Dot => DotDotDot, + _ => return None, + }, + Colon => match joint { + Colon => ModSep, + _ => return None, + }, + + Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | Comma | + Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | + OpenDelim(..) | CloseDelim(..) | Underscore => return None, + + Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) | + Whitespace | Comment | Shebang(..) | Eof => return None, + }) + } + /// Returns `true` if the token is either a special identifier or a keyword. pub fn is_reserved_ident(&self) -> bool { self.is_special_ident() || self.is_used_keyword() || self.is_unused_keyword() @@ -411,3 +469,66 @@ impl fmt::Debug for Nonterminal { } } } + +pub fn is_op(tok: &Token) -> bool { + match *tok { + OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | + Ident(..) | Underscore | Lifetime(..) | Interpolated(..) | + Whitespace | Comment | Shebang(..) | Eof => false, + _ => true, + } +} + +pub struct LazyTokenStream(Cell<Option<TokenStream>>); + +impl Clone for LazyTokenStream { + fn clone(&self) -> Self { + let opt_stream = self.0.take(); + self.0.set(opt_stream.clone()); + LazyTokenStream(Cell::new(opt_stream)) + } +} + +impl cmp::Eq for LazyTokenStream {} +impl PartialEq for LazyTokenStream { + fn eq(&self, _other: &LazyTokenStream) -> bool { + true + } +} + +impl fmt::Debug for LazyTokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.clone().0.into_inner(), f) + } +} + +impl LazyTokenStream { + pub fn new() -> Self { + LazyTokenStream(Cell::new(None)) + } + + pub fn force<F: FnOnce() -> TokenStream>(&self, f: F) -> TokenStream { + let mut opt_stream = self.0.take(); + if opt_stream.is_none() { + opt_stream = Some(f()); + } + self.0.set(opt_stream.clone()); + opt_stream.clone().unwrap() + } +} + +impl Encodable for LazyTokenStream { + fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> { + Ok(()) + } +} + +impl Decodable for LazyTokenStream { + fn decode<D: Decoder>(_: &mut D) -> Result<LazyTokenStream, D::Error> { + Ok(LazyTokenStream::new()) + } +} + +impl ::std::hash::Hash for LazyTokenStream { + fn hash<H: ::std::hash::Hasher>(&self, _hasher: &mut H) {} +} diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6c00e0b9efd7e..d449e412d6cc3 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -270,13 +270,12 @@ pub fn token_to_string(tok: &Token) -> String { /* Other */ token::DocComment(s) => s.to_string(), - token::SubstNt(s) => format!("${}", s), token::Eof => "<eof>".to_string(), token::Whitespace => " ".to_string(), token::Comment => "/* */".to_string(), token::Shebang(s) => format!("/* shebang: {}*/", s), - token::Interpolated(ref nt) => match **nt { + token::Interpolated(ref nt) => match nt.0 { token::NtExpr(ref e) => expr_to_string(e), token::NtMeta(ref e) => meta_item_to_string(e), token::NtTy(ref e) => ty_to_string(e), diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 963482fc223f1..8eee25405df6b 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -138,6 +138,10 @@ impl TokenTree { _ => false, } } + + pub fn joint(self) -> TokenStream { + TokenStream { kind: TokenStreamKind::JointTree(self) } + } } /// # Token Streams @@ -155,6 +159,7 @@ pub struct TokenStream { enum TokenStreamKind { Empty, Tree(TokenTree), + JointTree(TokenTree), Stream(RcSlice<TokenStream>), } @@ -199,7 +204,7 @@ impl TokenStream { pub fn concat(mut streams: Vec<TokenStream>) -> TokenStream { match streams.len() { 0 => TokenStream::empty(), - 1 => TokenStream::from(streams.pop().unwrap()), + 1 => streams.pop().unwrap(), _ => TokenStream::concat_rc_slice(RcSlice::new(streams)), } } @@ -225,6 +230,105 @@ impl TokenStream { } true } + + /// Precondition: `self` consists of a single token tree. + /// Returns true if the token tree is a joint operation w.r.t. `proc_macro::TokenNode`. + pub fn as_tree(self) -> (TokenTree, bool /* joint? */) { + match self.kind { + TokenStreamKind::Tree(tree) => (tree, false), + TokenStreamKind::JointTree(tree) => (tree, true), + _ => unreachable!(), + } + } + + pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream { + let mut trees = self.into_trees(); + let mut result = Vec::new(); + while let Some(stream) = trees.next_as_stream() { + result.push(match stream.kind { + TokenStreamKind::Tree(tree) => f(tree).into(), + TokenStreamKind::JointTree(tree) => f(tree).joint(), + _ => unreachable!() + }); + } + TokenStream::concat(result) + } + + fn first_tree(&self) -> Option<TokenTree> { + match self.kind { + TokenStreamKind::Empty => None, + TokenStreamKind::Tree(ref tree) | + TokenStreamKind::JointTree(ref tree) => Some(tree.clone()), + TokenStreamKind::Stream(ref stream) => stream.first().unwrap().first_tree(), + } + } + + fn last_tree_if_joint(&self) -> Option<TokenTree> { + match self.kind { + TokenStreamKind::Empty | TokenStreamKind::Tree(..) => None, + TokenStreamKind::JointTree(ref tree) => Some(tree.clone()), + TokenStreamKind::Stream(ref stream) => stream.last().unwrap().last_tree_if_joint(), + } + } +} + +pub struct TokenStreamBuilder(Vec<TokenStream>); + +impl TokenStreamBuilder { + pub fn new() -> TokenStreamBuilder { + TokenStreamBuilder(Vec::new()) + } + + pub fn push<T: Into<TokenStream>>(&mut self, stream: T) { + let stream = stream.into(); + let last_tree_if_joint = self.0.last().and_then(TokenStream::last_tree_if_joint); + if let Some(TokenTree::Token(last_span, last_tok)) = last_tree_if_joint { + if let Some(TokenTree::Token(span, tok)) = stream.first_tree() { + if let Some(glued_tok) = last_tok.glue(tok) { + let last_stream = self.0.pop().unwrap(); + self.push_all_but_last_tree(&last_stream); + let glued_span = last_span.to(span); + self.0.push(TokenTree::Token(glued_span, glued_tok).into()); + self.push_all_but_first_tree(&stream); + return + } + } + } + self.0.push(stream); + } + + pub fn add<T: Into<TokenStream>>(mut self, stream: T) -> Self { + self.push(stream); + self + } + + pub fn build(self) -> TokenStream { + TokenStream::concat(self.0) + } + + fn push_all_but_last_tree(&mut self, stream: &TokenStream) { + if let TokenStreamKind::Stream(ref streams) = stream.kind { + let len = streams.len(); + match len { + 1 => {} + 2 => self.0.push(streams[0].clone().into()), + _ => self.0.push(TokenStream::concat_rc_slice(streams.sub_slice(0 .. len - 1))), + } + self.push_all_but_last_tree(&streams[len - 1]) + } + } + + fn push_all_but_first_tree(&mut self, stream: &TokenStream) { + if let TokenStreamKind::Stream(ref streams) = stream.kind { + let len = streams.len(); + match len { + 1 => {} + 2 => self.0.push(streams[1].clone().into()), + _ => self.0.push(TokenStream::concat_rc_slice(streams.sub_slice(1 .. len))), + } + self.push_all_but_first_tree(&streams[0]) + } + } } #[derive(Clone)] @@ -234,6 +338,7 @@ pub struct Cursor(CursorKind); enum CursorKind { Empty, Tree(TokenTree, bool /* consumed? */), + JointTree(TokenTree, bool /* consumed? */), Stream(StreamCursor), } @@ -244,42 +349,45 @@ struct StreamCursor { stack: Vec<(RcSlice<TokenStream>, usize)>, } -impl Iterator for Cursor { - type Item = TokenTree; - - fn next(&mut self) -> Option<TokenTree> { - let cursor = match self.0 { - CursorKind::Stream(ref mut cursor) => cursor, - CursorKind::Tree(ref tree, ref mut consumed @ false) => { - *consumed = true; - return Some(tree.clone()); - } - _ => return None, - }; +impl StreamCursor { + fn new(stream: RcSlice<TokenStream>) -> Self { + StreamCursor { stream: stream, index: 0, stack: Vec::new() } + } + fn next_as_stream(&mut self) -> Option<TokenStream> { loop { - if cursor.index < cursor.stream.len() { - match cursor.stream[cursor.index].kind.clone() { - TokenStreamKind::Tree(tree) => { - cursor.index += 1; - return Some(tree); - } - TokenStreamKind::Stream(stream) => { - cursor.stack.push((mem::replace(&mut cursor.stream, stream), - mem::replace(&mut cursor.index, 0) + 1)); - } - TokenStreamKind::Empty => { - cursor.index += 1; - } + if self.index < self.stream.len() { + self.index += 1; + let next = self.stream[self.index - 1].clone(); + match next.kind { + TokenStreamKind::Tree(..) | TokenStreamKind::JointTree(..) => return Some(next), + TokenStreamKind::Stream(stream) => self.insert(stream), + TokenStreamKind::Empty => {} } - } else if let Some((stream, index)) = cursor.stack.pop() { - cursor.stream = stream; - cursor.index = index; + } else if let Some((stream, index)) = self.stack.pop() { + self.stream = stream; + self.index = index; } else { return None; } } } + + fn insert(&mut self, stream: RcSlice<TokenStream>) { + self.stack.push((mem::replace(&mut self.stream, stream), + mem::replace(&mut self.index, 0))); + } +} + +impl Iterator for Cursor { + type Item = TokenTree; + + fn next(&mut self) -> Option<TokenTree> { + self.next_as_stream().map(|stream| match stream.kind { + TokenStreamKind::Tree(tree) | TokenStreamKind::JointTree(tree) => tree, + _ => unreachable!() + }) + } } impl Cursor { @@ -287,18 +395,49 @@ impl Cursor { Cursor(match stream.kind { TokenStreamKind::Empty => CursorKind::Empty, TokenStreamKind::Tree(tree) => CursorKind::Tree(tree, false), - TokenStreamKind::Stream(stream) => { - CursorKind::Stream(StreamCursor { stream: stream, index: 0, stack: Vec::new() }) - } + TokenStreamKind::JointTree(tree) => CursorKind::JointTree(tree, false), + TokenStreamKind::Stream(stream) => CursorKind::Stream(StreamCursor::new(stream)), }) } - pub fn original_stream(self) -> TokenStream { + pub fn next_as_stream(&mut self) -> Option<TokenStream> { + let (stream, consumed) = match self.0 { + CursorKind::Tree(ref tree, ref mut consumed @ false) => + (tree.clone().into(), consumed), + CursorKind::JointTree(ref tree, ref mut consumed @ false) => + (tree.clone().joint(), consumed), + CursorKind::Stream(ref mut cursor) => return cursor.next_as_stream(), + _ => return None, + }; + + *consumed = true; + Some(stream) + } + + pub fn insert(&mut self, stream: TokenStream) { + match self.0 { + _ if stream.is_empty() => return, + CursorKind::Empty => *self = stream.trees(), + CursorKind::Tree(_, consumed) | CursorKind::JointTree(_, consumed) => { + *self = TokenStream::concat(vec![self.original_stream(), stream]).trees(); + if consumed { + self.next(); + } + } + CursorKind::Stream(ref mut cursor) => { + cursor.insert(ThinTokenStream::from(stream).0.unwrap()); + } + } + } + + pub fn original_stream(&self) -> TokenStream { match self.0 { CursorKind::Empty => TokenStream::empty(), - CursorKind::Tree(tree, _) => tree.into(), - CursorKind::Stream(cursor) => TokenStream::concat_rc_slice({ - cursor.stack.get(0).cloned().map(|(stream, _)| stream).unwrap_or(cursor.stream) + CursorKind::Tree(ref tree, _) => tree.clone().into(), + CursorKind::JointTree(ref tree, _) => tree.clone().joint(), + CursorKind::Stream(ref cursor) => TokenStream::concat_rc_slice({ + cursor.stack.get(0).cloned().map(|(stream, _)| stream) + .unwrap_or(cursor.stream.clone()) }), } } @@ -307,8 +446,9 @@ impl Cursor { fn look_ahead(streams: &[TokenStream], mut n: usize) -> Result<TokenTree, usize> { for stream in streams { n = match stream.kind { - TokenStreamKind::Tree(ref tree) if n == 0 => return Ok(tree.clone()), - TokenStreamKind::Tree(..) => n - 1, + TokenStreamKind::Tree(ref tree) | TokenStreamKind::JointTree(ref tree) + if n == 0 => return Ok(tree.clone()), + TokenStreamKind::Tree(..) | TokenStreamKind::JointTree(..) => n - 1, TokenStreamKind::Stream(ref stream) => match look_ahead(stream, n) { Ok(tree) => return Ok(tree), Err(n) => n, @@ -316,13 +456,15 @@ impl Cursor { _ => n, }; } - Err(n) } match self.0 { - CursorKind::Empty | CursorKind::Tree(_, true) => Err(n), - CursorKind::Tree(ref tree, false) => look_ahead(&[tree.clone().into()], n), + CursorKind::Empty | + CursorKind::Tree(_, true) | + CursorKind::JointTree(_, true) => Err(n), + CursorKind::Tree(ref tree, false) | + CursorKind::JointTree(ref tree, false) => look_ahead(&[tree.clone().into()], n), CursorKind::Stream(ref cursor) => { look_ahead(&cursor.stream[cursor.index ..], n).or_else(|mut n| { for &(ref stream, index) in cursor.stack.iter().rev() { @@ -350,6 +492,7 @@ impl From<TokenStream> for ThinTokenStream { ThinTokenStream(match stream.kind { TokenStreamKind::Empty => None, TokenStreamKind::Tree(tree) => Some(RcSlice::new(vec![tree.into()])), + TokenStreamKind::JointTree(tree) => Some(RcSlice::new(vec![tree.joint()])), TokenStreamKind::Stream(stream) => Some(stream), }) } diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index 2727ab79ebf76..d993ba14a4ab5 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -20,7 +20,7 @@ use std::iter::Peekable; /// Map a string to tts, using a made-up filename: pub fn string_to_stream(source_str: String) -> TokenStream { let ps = ParseSess::new(FilePathMapping::empty()); - filemap_to_stream(&ps, ps.codemap().new_filemap("bogofile".to_string(), source_str)) + filemap_to_stream(&ps, ps.codemap().new_filemap("bogofile".to_string(), source_str), None) } /// Map string to parser (via tts) diff --git a/src/libsyntax/util/rc_slice.rs b/src/libsyntax/util/rc_slice.rs index 2d9fd7aa87553..d6939d71129e4 100644 --- a/src/libsyntax/util/rc_slice.rs +++ b/src/libsyntax/util/rc_slice.rs @@ -9,7 +9,7 @@ // except according to those terms. use std::fmt; -use std::ops::Deref; +use std::ops::{Deref, Range}; use std::rc::Rc; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, @@ -30,6 +30,14 @@ impl<T> RcSlice<T> { data: Rc::new(vec.into_boxed_slice()), } } + + pub fn sub_slice(&self, range: Range<usize>) -> Self { + RcSlice { + data: self.data.clone(), + offset: self.offset + range.start as u32, + len: (range.end - range.start) as u32, + } + } } impl<T> Deref for RcSlice<T> { diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index dc4b8eb24cd0a..6f4c112acb6c6 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -15,6 +15,8 @@ use syntax::feature_gate; use syntax::parse::token; use syntax::ptr::P; use syntax_pos::Span; +use syntax_pos::symbol::Symbol; +use syntax_pos::hygiene::SyntaxContext; use syntax::tokenstream::TokenTree; pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, @@ -50,7 +52,10 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, } } } - let res = ast::Ident::from_str(&res_str); + let res = ast::Ident { + name: Symbol::intern(&res_str), + ctxt: SyntaxContext::empty().apply_mark(cx.current_expansion.mark), + }; struct Result { ident: ast::Ident, diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index b01ef65e5fe5e..fa5537b5d8fe3 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -16,7 +16,6 @@ use syntax::ast::{self, ItemKind, Attribute, Mac}; use syntax::attr::{mark_used, mark_known}; use syntax::codemap::Span; use syntax::ext::base::*; -use syntax::fold::Folder; use syntax::visit::Visitor; struct MarkAttrs<'a>(&'a [ast::Name]); @@ -75,7 +74,7 @@ impl MultiItemModifier for ProcMacroDerive { MarkAttrs(&self.attrs).visit_item(&item); let input = __internal::new_token_stream(ecx.resolver.eliminate_crate_var(item.clone())); - let res = __internal::set_parse_sess(&ecx.parse_sess, || { + let res = __internal::set_sess(ecx, || { let inner = self.inner; panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input))) }); @@ -97,9 +96,9 @@ impl MultiItemModifier for ProcMacroDerive { } }; - let new_items = __internal::set_parse_sess(&ecx.parse_sess, || { + __internal::set_sess(ecx, || { match __internal::token_stream_parse_items(stream) { - Ok(new_items) => new_items, + Ok(new_items) => new_items.into_iter().map(Annotatable::Item).collect(), Err(_) => { // FIXME: handle this better let msg = "proc-macro derive produced unparseable tokens"; @@ -107,12 +106,6 @@ impl MultiItemModifier for ProcMacroDerive { panic!(FatalError); } } - }); - - // Reassign spans of all expanded items to the input `item` - // for better errors here. - new_items.into_iter().map(|item| { - Annotatable::Item(ChangeSpan { span: span }.fold_item(item).expect_one("")) - }).collect() + }) } } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index a6768c07fe13b..144d1930df90b 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -20,7 +20,7 @@ use syntax::ext::build::AstBuilder; use syntax::parse::token; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::Span; use syntax::tokenstream; use std::collections::{HashMap, HashSet}; @@ -558,7 +558,9 @@ impl<'a, 'b> Context<'a, 'b> { // passed to this function. for (i, e) in self.args.into_iter().enumerate() { let name = self.ecx.ident_of(&format!("__arg{}", i)); - pats.push(self.ecx.pat_ident(DUMMY_SP, name)); + let span = + Span { ctxt: e.span.ctxt.apply_mark(self.ecx.current_expansion.mark), ..e.span }; + pats.push(self.ecx.pat_ident(span, name)); for ref arg_ty in self.arg_unique_types[i].iter() { locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name)); } @@ -672,10 +674,10 @@ impl<'a, 'b> Context<'a, 'b> { } pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, - sp: Span, + mut sp: Span, tts: &[tokenstream::TokenTree]) -> Box<base::MacResult + 'cx> { - + sp.ctxt = sp.ctxt.apply_mark(ecx.current_expansion.mark); match parse_args(ecx, sp, tts) { Some((efmt, args, names)) => { MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names)) @@ -696,7 +698,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, // `ArgumentType` does not derive `Clone`. let arg_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); - let macsp = ecx.call_site(); + let mut macsp = ecx.call_site(); + macsp.ctxt = macsp.ctxt.apply_mark(ecx.current_expansion.mark); let msg = "format argument must be a string literal."; let fmt = match expr_to_spanned_string(ecx, efmt, msg) { Some(fmt) => fmt, diff --git a/src/libsyntax_ext/proc_macro_impl.rs b/src/libsyntax_ext/proc_macro_impl.rs index f60e5824db962..5fcedbf50c60f 100644 --- a/src/libsyntax_ext/proc_macro_impl.rs +++ b/src/libsyntax_ext/proc_macro_impl.rs @@ -34,7 +34,7 @@ impl base::AttrProcMacro for AttrProcMacro { let annotation = __internal::token_stream_wrap(annotation); let annotated = __internal::token_stream_wrap(annotated); - let res = __internal::set_parse_sess(&ecx.parse_sess, || { + let res = __internal::set_sess(ecx, || { panic::catch_unwind(panic::AssertUnwindSafe(|| (self.inner)(annotation, annotated))) }); @@ -69,7 +69,7 @@ impl base::ProcMacro for BangProcMacro { -> TokenStream { let input = __internal::token_stream_wrap(input); - let res = __internal::set_parse_sess(&ecx.parse_sess, || { + let res = __internal::set_sess(ecx, || { panic::catch_unwind(panic::AssertUnwindSafe(|| (self.inner)(input))) }); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index f2ccc3f051e92..804b91ab09e3c 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -144,24 +144,18 @@ impl SyntaxContext { pub fn apply_mark(self, mark: Mark) -> SyntaxContext { HygieneData::with(|data| { let syntax_contexts = &mut data.syntax_contexts; - let ctxt_data = syntax_contexts[self.0 as usize]; - if mark == ctxt_data.outer_mark { - return ctxt_data.prev_ctxt; - } - - let modern = if data.marks[mark.0 as usize].modern { - *data.markings.entry((ctxt_data.modern, mark)).or_insert_with(|| { - let modern = SyntaxContext(syntax_contexts.len() as u32); + let mut modern = syntax_contexts[self.0 as usize].modern; + if data.marks[mark.0 as usize].modern { + modern = *data.markings.entry((modern, mark)).or_insert_with(|| { + let len = syntax_contexts.len() as u32; syntax_contexts.push(SyntaxContextData { outer_mark: mark, - prev_ctxt: ctxt_data.modern, - modern: modern, + prev_ctxt: modern, + modern: SyntaxContext(len), }); - modern - }) - } else { - ctxt_data.modern - }; + SyntaxContext(len) + }); + } *data.markings.entry((self, mark)).or_insert_with(|| { syntax_contexts.push(SyntaxContextData { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index bb62efd376a0b..a7c247689cce8 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -186,7 +186,7 @@ impl Span { pub fn to(self, end: Span) -> Span { // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480) - if end.ctxt == SyntaxContext::empty() { + if self.ctxt == SyntaxContext::empty() { Span { lo: self.lo, ..end } } else { Span { hi: end.hi, ..self } diff --git a/src/rustc/compiler_builtins_shim/Cargo.toml b/src/rustc/compiler_builtins_shim/Cargo.toml new file mode 100644 index 0000000000000..e0026078a5d72 --- /dev/null +++ b/src/rustc/compiler_builtins_shim/Cargo.toml @@ -0,0 +1,24 @@ +# See libc_shim/Cargo.toml for why this exists + +[package] +name = "compiler_builtins" +authors = ["The Rust Project Developers"] +version = "0.0.0" +build = "../../libcompiler_builtins/build.rs" + +[lib] +path = "../../libcompiler_builtins/src/lib.rs" +test = false +doctest = false + +[dependencies] +core = { path = "../../libcore" } + +[build-dependencies] +gcc = "0.3" + +[features] +c = [] +default = ["c", "rustbuild", "compiler-builtins"] +rustbuild = [] +compiler-builtins = [] diff --git a/src/test/run-pass/allocator-system.rs b/src/rustc/compiler_builtins_shim/build.rs similarity index 75% rename from src/test/run-pass/allocator-system.rs rename to src/rustc/compiler_builtins_shim/build.rs index 4585003d5793b..546f60482e7bc 100644 --- a/src/test/run-pass/allocator-system.rs +++ b/src/rustc/compiler_builtins_shim/build.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-prefer-dynamic +#![deny(warnings)] -#![feature(alloc_system)] - -extern crate alloc_system; +// See comments in Cargo.toml for why this exists fn main() { - println!("{:?}", Box::new(3)); + println!("cargo:rustc-cfg=stdbuild"); + println!("cargo:rerun-if-changed=build.rs"); } diff --git a/src/rustllvm/.editorconfig b/src/rustllvm/.editorconfig new file mode 100644 index 0000000000000..865cd45f708fb --- /dev/null +++ b/src/rustllvm/.editorconfig @@ -0,0 +1,6 @@ +[*.{h,cpp}] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 2 diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index 37ba326445265..b2d4c11329512 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,8 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. +<<<<<<< 37849a002ed91ac2b80aeb2172364b4e19250e05 2017-06-27 +======= +2017-06-26 +>>>>>>> rustc: Implement the #[global_allocator] attribute diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index bc84ac49da985..d8bbcd9b7328e 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -11,7 +11,7 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] -#![feature(allocator)] +#![feature(custom_attribute)] pub struct S { _field: [i64; 4], diff --git a/src/test/compile-fail/allocator-depends-on-needs-allocators.rs b/src/test/compile-fail/allocator-depends-on-needs-allocators.rs deleted file mode 100644 index 7f420ff735a3e..0000000000000 --- a/src/test/compile-fail/allocator-depends-on-needs-allocators.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: `allocator3` cannot depend on a crate that needs an allocator -// aux-build:needs_allocator.rs -// aux-build:allocator3.rs - -// The needs_allocator crate is a dependency of the allocator crate allocator3, -// which is not allowed - -extern crate allocator3; - -fn main() { -} diff --git a/src/test/compile-fail/allocator-dylib-is-system.rs b/src/test/compile-fail/allocator-dylib-is-system.rs deleted file mode 100644 index 31009554c690d..0000000000000 --- a/src/test/compile-fail/allocator-dylib-is-system.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-musl no dylibs -// aux-build:allocator-dylib.rs -// aux-build:allocator1.rs -// no-prefer-dynamic -// error-pattern: cannot link together two allocators - -// Verify that the allocator for statically linked dynamic libraries is the -// system allocator. Do this by linking in jemalloc and making sure that we get -// an error. - -// ignore-emscripten FIXME: What "other allocator" should we use for emcc? - -#![feature(alloc_jemalloc)] - -extern crate allocator_dylib; - -// The main purpose of this test is to ensure that `alloc_jemalloc` **fails** -// here (specifically the jemalloc allocator), but currently jemalloc is -// disabled on quite a few platforms (bsds, emscripten, msvc, etc). To ensure -// that this just passes on those platforms we link in some other allocator to -// ensure we get the same error. -// -// So long as we CI linux/macOS we should be good. -#[cfg(any(target_os = "linux", target_os = "macos"))] -extern crate alloc_jemalloc; -#[cfg(not(any(target_os = "linux", target_os = "macos")))] -extern crate allocator1; - -fn main() { - allocator_dylib::foo(); -} diff --git a/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs b/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs deleted file mode 100644 index 68e01bad96bb2..0000000000000 --- a/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ignore-musl no dylibs -// aux-build:allocator-dylib2.rs -// aux-build:allocator1.rs -// error-pattern: cannot link together two allocators - -// Ensure that rust dynamic libraries use jemalloc as their allocator, verifying -// by linking in the system allocator here and ensuring that we get a complaint. - -// ignore-emscripten FIXME: What "other allocator" is correct for emscripten? - -#![feature(alloc_system)] - -extern crate allocator_dylib2; - -// The main purpose of this test is to ensure that `alloc_system` **fails** -// here (specifically the system allocator), but currently system is -// disabled on quite a few platforms (bsds, emscripten, msvc, etc). To ensure -// that this just passes on those platforms we link in some other allocator to -// ensure we get the same error. -// -// So long as we CI linux/macOS we should be good. -#[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")), - target_os = "macos"))] -extern crate alloc_system; -#[cfg(not(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")), - target_os = "macos")))] -extern crate allocator1; - -fn main() { - allocator_dylib2::foo(); -} diff --git a/src/test/compile-fail/auxiliary/allocator3.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator.rs similarity index 71% rename from src/test/compile-fail/auxiliary/allocator3.rs rename to src/test/compile-fail/allocator/auxiliary/system-allocator.rs index d3eb1f6f7abac..4761dc421d7f7 100644 --- a/src/test/compile-fail/auxiliary/allocator3.rs +++ b/src/test/compile-fail/allocator/auxiliary/system-allocator.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -10,10 +10,10 @@ // no-prefer-dynamic -#![feature(allocator)] -#![no_std] -#![allocator] +#![feature(global_allocator, allocator_api)] #![crate_type = "rlib"] -extern crate needs_allocator; +use std::heap::System; +#[global_allocator] +static A: System = System; diff --git a/src/test/compile-fail/auxiliary/needs_allocator.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs similarity index 71% rename from src/test/compile-fail/auxiliary/needs_allocator.rs rename to src/test/compile-fail/allocator/auxiliary/system-allocator2.rs index 5100316042732..4761dc421d7f7 100644 --- a/src/test/compile-fail/auxiliary/needs_allocator.rs +++ b/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -10,7 +10,10 @@ // no-prefer-dynamic -#![feature(needs_allocator)] -#![no_std] -#![needs_allocator] +#![feature(global_allocator, allocator_api)] #![crate_type = "rlib"] + +use std::heap::System; + +#[global_allocator] +static A: System = System; diff --git a/src/test/compile-fail/allocator/function-allocator.rs b/src/test/compile-fail/allocator/function-allocator.rs new file mode 100644 index 0000000000000..50f82607b53f6 --- /dev/null +++ b/src/test/compile-fail/allocator/function-allocator.rs @@ -0,0 +1,16 @@ +// 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(global_allocator)] + +#[global_allocator] +fn foo() {} //~ ERROR: allocators must be statics + +fn main() {} diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs new file mode 100644 index 0000000000000..e430143506346 --- /dev/null +++ b/src/test/compile-fail/allocator/not-an-allocator.rs @@ -0,0 +1,26 @@ +// 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(global_allocator, heap_api)] + +#[global_allocator] +static A: usize = 0; +//~^ the trait bound `&usize: +//~| the trait bound `&usize: +//~| the trait bound `&usize: +//~| the trait bound `&usize: +//~| the trait bound `&usize: +//~| the trait bound `&usize: +//~| the trait bound `&usize: +//~| the trait bound `&usize: +//~| the trait bound `&usize: +//~| the trait bound `&usize: + +fn main() {} diff --git a/src/test/compile-fail/two-allocators.rs b/src/test/compile-fail/allocator/two-allocators.rs similarity index 59% rename from src/test/compile-fail/two-allocators.rs rename to src/test/compile-fail/allocator/two-allocators.rs index a34f77de2455b..b46ba6334a2b4 100644 --- a/src/test/compile-fail/two-allocators.rs +++ b/src/test/compile-fail/allocator/two-allocators.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,12 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: cannot link together two allocators +#![feature(global_allocator, allocator_api)] -// aux-build:allocator1.rs -// aux-build:allocator2.rs +use std::heap::System; -extern crate allocator1; -extern crate allocator2; +#[global_allocator] +static A: System = System; +#[global_allocator] +static B: System = System; +//~^ ERROR: cannot define more than one #[global_allocator] fn main() {} + diff --git a/src/test/compile-fail/allocator/two-allocators2.rs b/src/test/compile-fail/allocator/two-allocators2.rs new file mode 100644 index 0000000000000..e342c1f9c44e7 --- /dev/null +++ b/src/test/compile-fail/allocator/two-allocators2.rs @@ -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. + +// aux-build:system-allocator.rs +// no-prefer-dynamic +// error-pattern: the #[global_allocator] in + +#![feature(global_allocator, allocator_api)] + +extern crate system_allocator; + +use std::heap::System; + +#[global_allocator] +static A: System = System; + +fn main() {} + diff --git a/src/test/compile-fail/allocator/two-allocators3.rs b/src/test/compile-fail/allocator/two-allocators3.rs new file mode 100644 index 0000000000000..c310d94f6dfd8 --- /dev/null +++ b/src/test/compile-fail/allocator/two-allocators3.rs @@ -0,0 +1,21 @@ +// 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. + +// aux-build:system-allocator.rs +// aux-build:system-allocator2.rs +// no-prefer-dynamic +// error-pattern: the #[global_allocator] in + +#![feature(global_allocator)] + +extern crate system_allocator; +extern crate system_allocator2; + +fn main() {} diff --git a/src/test/compile-fail/asm-out-assign-imm.rs b/src/test/compile-fail/asm-out-assign-imm.rs index 3c4a5dcb7b038..f95e4410381d9 100644 --- a/src/test/compile-fail/asm-out-assign-imm.rs +++ b/src/test/compile-fail/asm-out-assign-imm.rs @@ -28,7 +28,6 @@ pub fn main() { asm!("mov $1, $0" : "=r"(x) : "r"(5)); //~^ ERROR re-assignment of immutable variable `x` //~| NOTE re-assignment of immutable - //~| NOTE in this expansion of asm! } foo(x); } diff --git a/src/test/run-pass/auxiliary/clibrary.rs b/src/test/compile-fail/feature-gate-allocator_internals.rs similarity index 81% rename from src/test/run-pass/auxiliary/clibrary.rs rename to src/test/compile-fail/feature-gate-allocator_internals.rs index 7438ba21bfc4a..b519a985ec5e7 100644 --- a/src/test/run-pass/auxiliary/clibrary.rs +++ b/src/test/compile-fail/feature-gate-allocator_internals.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-prefer-dynamic -#![crate_type = "staticlib"] +#![default_lib_allocator] //~ ERROR: attribute is an experimental feature + +fn main() {} -#[no_mangle] -pub extern "C" fn foo(x:i32) -> i32 { x } diff --git a/src/test/compile-fail/auxiliary/allocator-dylib.rs b/src/test/compile-fail/feature-gate-global_allocator.rs similarity index 70% rename from src/test/compile-fail/auxiliary/allocator-dylib.rs rename to src/test/compile-fail/feature-gate-global_allocator.rs index 568b247ecdbf3..ff3c342f9e003 100644 --- a/src/test/compile-fail/auxiliary/allocator-dylib.rs +++ b/src/test/compile-fail/feature-gate-global_allocator.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// no-prefer-dynamic +#[global_allocator] //~ ERROR: attribute is an experimental feature +static A: usize = 0; -#![crate_type = "dylib"] - -pub fn foo() {} +fn main() {} diff --git a/src/test/compile-fail/macro-context.rs b/src/test/compile-fail/macro-context.rs index 80802e19f8401..cc714a6e43141 100644 --- a/src/test/compile-fail/macro-context.rs +++ b/src/test/compile-fail/macro-context.rs @@ -23,5 +23,5 @@ fn main() { m!() => {} //~ NOTE the usage of `m!` is likely invalid in pattern context } - m!(); + m!(); //~ NOTE in this expansion } diff --git a/src/test/compile-fail/two-allocators-2.rs b/src/test/compile-fail/two-allocators-2.rs deleted file mode 100644 index d6fcbcb513ae3..0000000000000 --- a/src/test/compile-fail/two-allocators-2.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: cannot link together two allocators: allocator1 and allocator2 -// aux-build:allocator1.rs -// aux-build:allocator2.rs - -// Make sure we can't link together two explicit allocators. - -extern crate allocator1; -extern crate allocator2; - -fn main() {} - diff --git a/src/test/compile-fail/two-allocators-3.rs b/src/test/compile-fail/two-allocators-3.rs deleted file mode 100644 index 965e4e0e2eabe..0000000000000 --- a/src/test/compile-fail/two-allocators-3.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:allocator1.rs -// error-pattern: cannot link together two allocators -// ignore-musl no dylibs on musl yet -// ignore-emscripten - -// We're linking std dynamically (via -C prefer-dynamic for this test) which -// has an allocator and then we're also linking in a new allocator (allocator1) -// and this should be an error - -extern crate allocator1; - -fn main() { -} diff --git a/src/test/run-make/no-duplicate-libs/Makefile b/src/test/run-make/no-duplicate-libs/Makefile index 3f6a28c251a2f..13d8366c60ab9 100644 --- a/src/test/run-make/no-duplicate-libs/Makefile +++ b/src/test/run-make/no-duplicate-libs/Makefile @@ -4,9 +4,7 @@ ifdef IS_MSVC # FIXME(#27979) all: else -all: - $(RUSTC) foo.rs - $(RUSTC) bar.rs +all: $(call STATICLIB,foo) $(call STATICLIB,bar) $(RUSTC) main.rs $(call RUN,main) endif diff --git a/src/test/compile-fail/feature-gate-allocator.rs b/src/test/run-make/no-duplicate-libs/bar.c similarity index 76% rename from src/test/compile-fail/feature-gate-allocator.rs rename to src/test/run-make/no-duplicate-libs/bar.c index 6490216d0126f..b9dcd0f5e5eeb 100644 --- a/src/test/compile-fail/feature-gate-allocator.rs +++ b/src/test/run-make/no-duplicate-libs/bar.c @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allocator] //~ ERROR: experimental feature +extern void foo(); -fn main() {} +void bar() { + foo(); +} diff --git a/src/test/run-make/no-duplicate-libs/bar.rs b/src/test/run-make/no-duplicate-libs/bar.rs deleted file mode 100644 index cb1c88689a89d..0000000000000 --- a/src/test/run-make/no-duplicate-libs/bar.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2014 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(lang_items, alloc_system, compiler_builtins_lib)] -#![crate_type = "dylib"] -#![no_std] - -extern crate alloc_system; -extern crate compiler_builtins; - -#[no_mangle] -pub extern fn bar() {} - -#[lang = "eh_personality"] fn eh_personality() {} -#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -#[no_mangle] pub extern fn rust_eh_register_frames () {} -#[no_mangle] pub extern fn rust_eh_unregister_frames () {} diff --git a/src/test/compile-fail/auxiliary/allocator-dylib2.rs b/src/test/run-make/no-duplicate-libs/foo.c similarity index 83% rename from src/test/compile-fail/auxiliary/allocator-dylib2.rs rename to src/test/run-make/no-duplicate-libs/foo.c index 0d76c0e5eb8d1..906cd5682b82d 100644 --- a/src/test/compile-fail/auxiliary/allocator-dylib2.rs +++ b/src/test/run-make/no-duplicate-libs/foo.c @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,5 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub fn foo() {} - +void foo() {} diff --git a/src/test/run-make/no-duplicate-libs/foo.rs b/src/test/run-make/no-duplicate-libs/foo.rs deleted file mode 100644 index 214fb156c2d63..0000000000000 --- a/src/test/run-make/no-duplicate-libs/foo.rs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2014 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(lang_items, alloc_system, compiler_builtins_lib)] -#![no_std] -#![crate_type = "dylib"] - -extern crate alloc_system; -extern crate compiler_builtins; - -#[no_mangle] -pub extern fn foo() {} - -#[lang = "eh_personality"] fn eh_personality() {} -#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {} -#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -#[no_mangle] pub extern fn rust_eh_register_frames () {} -#[no_mangle] pub extern fn rust_eh_unregister_frames () {} diff --git a/src/test/run-make/no-duplicate-libs/main.rs b/src/test/run-make/no-duplicate-libs/main.rs index 12ddce345820b..824946fe9c2bd 100644 --- a/src/test/run-make/no-duplicate-libs/main.rs +++ b/src/test/run-make/no-duplicate-libs/main.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[link(name = "foo")] -#[link(name = "bar")] -#[link(name = "foo")] +#[link(name = "foo")] // linker should drop this library, no symbols used +#[link(name = "bar")] // symbol comes from this library +#[link(name = "foo")] // now linker picks up `foo` b/c `bar` library needs it extern { fn bar(); } diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs index 0433b95865ef8..e2c68a626f91e 100644 --- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs @@ -8,50 +8,37 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused_parens)] -#![feature(plugin)] -#![feature(plugin_registrar)] -#![feature(rustc_private)] -#![plugin(proc_macro_plugin)] +// no-prefer-dynamic -extern crate rustc_plugin; -extern crate syntax; +#![crate_type = "proc-macro"] +#![feature(proc_macro)] -use rustc_plugin::Registry; +extern crate proc_macro; -use syntax::ext::base::SyntaxExtension; -use syntax::parse::token::Token; -use syntax::symbol::Symbol; -use syntax::tokenstream::{TokenTree, TokenStream}; +use proc_macro::{TokenStream, TokenNode, quote}; -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension(Symbol::intern("cond"), - SyntaxExtension::ProcMacro(Box::new(cond))); -} - -fn cond(input: TokenStream) -> TokenStream { +#[proc_macro] +pub fn cond(input: TokenStream) -> TokenStream { let mut conds = Vec::new(); - let mut input = input.trees().peekable(); + let mut input = input.into_iter().peekable(); while let Some(tree) = input.next() { - let mut cond = match tree { - TokenTree::Delimited(_, ref delimited) => delimited.stream(), + let cond = match tree.kind { + TokenNode::Group(_, cond) => cond, _ => panic!("Invalid input"), }; - let mut trees = cond.trees(); - let test = trees.next(); - let rhs = trees.collect::<TokenStream>(); + let mut cond_trees = cond.clone().into_iter(); + let test = cond_trees.next().expect("Unexpected empty condition in `cond!`"); + let rhs = cond_trees.collect::<TokenStream>(); if rhs.is_empty() { panic!("Invalid macro usage in cond: {}", cond); } - let is_else = match test { - Some(TokenTree::Token(_, Token::Ident(ident))) if ident.name == "else" => true, + let is_else = match test.kind { + TokenNode::Term(word) => word.as_str() == "else", _ => false, }; conds.push(if is_else || input.peek().is_none() { quote!({ $rhs }) } else { - let test = test.unwrap(); quote!(if $test { $rhs } else) }); } diff --git a/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs b/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs index 9522592a5e9e6..cf6584e961a67 100644 --- a/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs +++ b/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs @@ -8,29 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(plugin)] -#![feature(plugin_registrar)] -#![feature(rustc_private)] -#![plugin(proc_macro_plugin)] +// no-prefer-dynamic -extern crate rustc_plugin; -extern crate syntax; +#![crate_type = "proc-macro"] +#![feature(proc_macro, proc_macro_lib)] -use rustc_plugin::Registry; -use syntax::ext::base::SyntaxExtension; -use syntax::symbol::Symbol; -use syntax::tokenstream::TokenStream; +extern crate proc_macro; -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension(Symbol::intern("hello"), - SyntaxExtension::ProcMacro(Box::new(hello))); -} +use proc_macro::{TokenStream, quote}; // This macro is not very interesting, but it does contain delimited tokens with // no content - `()` and `{}` - which has caused problems in the past. // Also, it tests that we can escape `$` via `$$`. -fn hello(_: TokenStream) -> TokenStream { +#[proc_macro] +pub fn hello(_: TokenStream) -> TokenStream { quote!({ fn hello() {} macro_rules! m { ($$($$t:tt)*) => { $$($$t)* } } diff --git a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs index 0e37a7a5dcce2..1b47043884844 100644 --- a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs +++ b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs @@ -8,47 +8,37 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(plugin, plugin_registrar, rustc_private)] -#![plugin(proc_macro_plugin)] - -extern crate rustc_plugin; -extern crate syntax; - -use rustc_plugin::Registry; -use syntax::ext::base::SyntaxExtension; -use syntax::tokenstream::TokenStream; -use syntax::symbol::Symbol; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension(Symbol::intern("attr_tru"), - SyntaxExtension::AttrProcMacro(Box::new(attr_tru))); - reg.register_syntax_extension(Symbol::intern("attr_identity"), - SyntaxExtension::AttrProcMacro(Box::new(attr_identity))); - reg.register_syntax_extension(Symbol::intern("tru"), - SyntaxExtension::ProcMacro(Box::new(tru))); - reg.register_syntax_extension(Symbol::intern("ret_tru"), - SyntaxExtension::ProcMacro(Box::new(ret_tru))); - reg.register_syntax_extension(Symbol::intern("identity"), - SyntaxExtension::ProcMacro(Box::new(identity))); -} +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro, proc_macro_lib)] + +extern crate proc_macro; + +use proc_macro::{TokenStream, quote}; -fn attr_tru(_attr: TokenStream, _item: TokenStream) -> TokenStream { - quote!(fn f1() -> bool { true }) +#[proc_macro_attribute] +pub fn attr_tru(_attr: TokenStream, item: TokenStream) -> TokenStream { + let name = item.into_iter().skip(1).next().unwrap(); + quote!(fn $name() -> bool { true }) } -fn attr_identity(_attr: TokenStream, item: TokenStream) -> TokenStream { +#[proc_macro_attribute] +pub fn attr_identity(_attr: TokenStream, item: TokenStream) -> TokenStream { quote!($item) } -fn tru(_ts: TokenStream) -> TokenStream { +#[proc_macro] +pub fn tru(_ts: TokenStream) -> TokenStream { quote!(true) } -fn ret_tru(_ts: TokenStream) -> TokenStream { +#[proc_macro] +pub fn ret_tru(_ts: TokenStream) -> TokenStream { quote!(return true;) } -fn identity(ts: TokenStream) -> TokenStream { +#[proc_macro] +pub fn identity(ts: TokenStream) -> TokenStream { quote!($ts) } diff --git a/src/test/run-pass-fulldeps/macro-quote-1.rs b/src/test/run-pass-fulldeps/macro-quote-1.rs deleted file mode 100644 index e7d0a83017be0..0000000000000 --- a/src/test/run-pass-fulldeps/macro-quote-1.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2012-2014 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. - -// ignore-stage1 - -#![feature(plugin)] -#![feature(rustc_private)] -#![plugin(proc_macro_plugin)] - -extern crate syntax; -extern crate syntax_pos; - -use syntax::ast::{Ident, Name}; -use syntax::parse::token::{self, Token, Lit}; -use syntax::tokenstream::TokenTree; - -fn main() { - let true_tok = token::Ident(Ident::from_str("true")); - assert!(quote!(true).eq_unspanned(&true_tok.into())); - - // issue #35829, extended check to proc_macro. - let triple_dot_tok = Token::DotDotDot; - assert!(quote!(...).eq_unspanned(&triple_dot_tok.into())); - - let byte_str_tok = Token::Literal(Lit::ByteStr(Name::intern("one")), None); - assert!(quote!(b"one").eq_unspanned(&byte_str_tok.into())); - - let byte_str_raw_tok = Token::Literal(Lit::ByteStrRaw(Name::intern("#\"two\"#"), 3), None); - assert!(quote!(br###"#"two"#"###).eq_unspanned(&byte_str_raw_tok.into())); - - let str_raw_tok = Token::Literal(Lit::StrRaw(Name::intern("#\"three\"#"), 2), None); - assert!(quote!(r##"#"three"#"##).eq_unspanned(&str_raw_tok.into())); -} diff --git a/src/test/run-pass-fulldeps/macro-quote-cond.rs b/src/test/run-pass-fulldeps/macro-quote-cond.rs index fa969b6a087cf..cff743bdae6cd 100644 --- a/src/test/run-pass-fulldeps/macro-quote-cond.rs +++ b/src/test/run-pass-fulldeps/macro-quote-cond.rs @@ -11,9 +11,11 @@ // aux-build:cond_plugin.rs // ignore-stage1 -#![feature(plugin)] -#![feature(rustc_private)] -#![plugin(cond_plugin)] +#![feature(proc_macro)] + +extern crate cond_plugin; + +use cond_plugin::cond; fn fact(n : i64) -> i64 { if n == 0 { diff --git a/src/test/run-pass-fulldeps/macro-quote-test.rs b/src/test/run-pass-fulldeps/macro-quote-test.rs index bdbea8a419416..eb77895e2d7ad 100644 --- a/src/test/run-pass-fulldeps/macro-quote-test.rs +++ b/src/test/run-pass-fulldeps/macro-quote-test.rs @@ -13,10 +13,10 @@ // aux-build:hello_macro.rs // ignore-stage1 -#![feature(plugin)] -#![feature(rustc_private)] -#![plugin(hello_macro)] +#![feature(proc_macro)] + +extern crate hello_macro; fn main() { - hello!(); + hello_macro::hello!(); } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs index 989c77f1089cf..93815d16837d3 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs @@ -24,7 +24,7 @@ pub fn attr_with_args(args: TokenStream, input: TokenStream) -> TokenStream { let input = input.to_string(); - assert_eq!(input, "fn foo ( ) { }"); + assert_eq!(input, "fn foo() { }"); r#" fn foo() -> &'static str { "Hello, world!" } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs new file mode 100644 index 0000000000000..ec2ff0d1e2b8c --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs @@ -0,0 +1,36 @@ +// 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. + +// no-prefer-dynamic + +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::{TokenStream, TokenNode, Spacing, Literal, quote}; + +#[proc_macro] +pub fn count_compound_ops(input: TokenStream) -> TokenStream { + assert_eq!(count_compound_ops_helper(quote!(++ (&&) 4@a)), 3); + TokenNode::Literal(Literal::u32(count_compound_ops_helper(input))).into() +} + +fn count_compound_ops_helper(input: TokenStream) -> u32 { + let mut count = 0; + for token in input { + match token.kind { + TokenNode::Op(c, Spacing::Alone) => count += 1, + TokenNode::Group(_, tokens) => count += count_compound_ops_helper(tokens), + _ => {} + } + } + count +} diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example.rs new file mode 100644 index 0000000000000..8ffa7abe6f7f9 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example.rs @@ -0,0 +1,19 @@ +// 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(proc_macro)] + +extern crate hygiene_example_codegen; + +pub use hygiene_example_codegen::hello; + +pub fn print(string: &str) { + println!("{}", string); +} diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs new file mode 100644 index 0000000000000..055e4e2fad7af --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs @@ -0,0 +1,36 @@ +// 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. + +// no-prefer-dynamic + +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro as proc_macro_renamed; // This does not break `quote!` + +use proc_macro_renamed::{TokenStream, quote}; + +#[proc_macro] +pub fn hello(input: TokenStream) -> TokenStream { + quote!(hello_helper!($input)) + //^ `hello_helper!` always resolves to the following proc macro, + //| no matter where `hello!` is used. +} + +#[proc_macro] +pub fn hello_helper(input: TokenStream) -> TokenStream { + quote! { + extern crate hygiene_example; // This is never a conflict error + let string = format!("hello {}", $input); + //^ `format!` always resolves to the prelude macro, + //| even if a different `format!` is in scope where `hello!` is used. + hygiene_example::print(&string) + } +} diff --git a/src/test/run-pass/allocator-default.rs b/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs similarity index 60% rename from src/test/run-pass/allocator-default.rs rename to src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs index 0a02e8072b9b3..1a2b144e4717b 100644 --- a/src/test/run-pass/allocator-default.rs +++ b/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(alloc_jemalloc)] +// aux-build:count_compound_ops.rs -#[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")), - target_os = "macos"))] -extern crate alloc_jemalloc; +#![feature(proc_macro)] + +extern crate count_compound_ops; +use count_compound_ops::count_compound_ops; fn main() { - println!("{:?}", Box::new(3)); + assert_eq!(count_compound_ops!(foo<=>bar <<<! -baz ++), 4); } diff --git a/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs b/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs new file mode 100644 index 0000000000000..51198db5aa76d --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs @@ -0,0 +1,27 @@ +// 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. + +// aux-build:hygiene_example_codegen.rs +// aux-build:hygiene_example.rs + +#![feature(proc_macro)] + +extern crate hygiene_example; +use hygiene_example::hello; + +fn main() { + mod hygiene_example {} // no conflict with `extern crate hygiene_example;` from the proc macro + macro_rules! format { () => {} } // does not interfere with `format!` from the proc macro + macro_rules! hello_helper { () => {} } // similarly does not intefere with the proc macro + + let string = "world"; // no conflict with `string` from the proc macro + hello!(string); + hello!(string); +} diff --git a/src/test/run-pass-fulldeps/proc_macro.rs b/src/test/run-pass-fulldeps/proc_macro.rs index 22cc9f0f8d40e..cdda723585b7a 100644 --- a/src/test/run-pass-fulldeps/proc_macro.rs +++ b/src/test/run-pass-fulldeps/proc_macro.rs @@ -12,10 +12,11 @@ // ignore-stage1 // ignore-cross-compile -#![feature(plugin, custom_attribute)] -#![feature(type_macros)] +#![feature(proc_macro)] -#![plugin(proc_macro_def)] +extern crate proc_macro_def; + +use proc_macro_def::{attr_tru, attr_identity, identity, ret_tru, tru}; #[attr_tru] fn f1() -> bool { diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index 7cc547dcc04e2..712fa2d600177 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -8,20 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(alloc, allocator_api, heap_api, unique)] +#![feature(allocator_api, unique)] -extern crate alloc; - -use alloc::heap::HeapAlloc; -use alloc::allocator::Alloc; +use std::heap::{Heap, Alloc}; fn main() { unsafe { - let ptr = HeapAlloc.alloc_one::<i32>().unwrap_or_else(|e| { - HeapAlloc.oom(e) + let ptr = Heap.alloc_one::<i32>().unwrap_or_else(|e| { + Heap.oom(e) }); *ptr.as_ptr() = 4; assert_eq!(*ptr.as_ptr(), 4); - HeapAlloc.dealloc_one(ptr); + Heap.dealloc_one(ptr); } } diff --git a/src/test/run-pass/allocator-override.rs b/src/test/run-pass/allocator-override.rs deleted file mode 100644 index ca2dbdf2b3de3..0000000000000 --- a/src/test/run-pass/allocator-override.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// no-prefer-dynamic -// aux-build:allocator-dummy.rs -// ignore-emscripten - -#![feature(test)] - -extern crate allocator_dummy; -extern crate test; - -fn main() { - unsafe { - let before = allocator_dummy::HITS; - let mut b = Box::new(3); - test::black_box(&mut b); // Make sure the allocation is not optimized away - assert_eq!(allocator_dummy::HITS - before, 1); - drop(b); - assert_eq!(allocator_dummy::HITS - before, 2); - } -} diff --git a/src/test/compile-fail/auxiliary/allocator2.rs b/src/test/run-pass/allocator/auxiliary/custom-as-global.rs similarity index 58% rename from src/test/compile-fail/auxiliary/allocator2.rs rename to src/test/run-pass/allocator/auxiliary/custom-as-global.rs index b24784838d00b..538f36faadf2c 100644 --- a/src/test/compile-fail/auxiliary/allocator2.rs +++ b/src/test/run-pass/allocator/auxiliary/custom-as-global.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -10,7 +10,18 @@ // no-prefer-dynamic -#![feature(allocator)] -#![allocator] +#![feature(global_allocator)] #![crate_type = "rlib"] -#![no_std] + +extern crate custom; + +use std::sync::atomic::{ATOMIC_USIZE_INIT, Ordering}; + +use custom::A; + +#[global_allocator] +static ALLOCATOR: A = A(ATOMIC_USIZE_INIT); + +pub fn get() -> usize { + ALLOCATOR.0.load(Ordering::SeqCst) +} diff --git a/src/test/run-pass/allocator/auxiliary/custom.rs b/src/test/run-pass/allocator/auxiliary/custom.rs new file mode 100644 index 0000000000000..8f4fbcd5ab1c1 --- /dev/null +++ b/src/test/run-pass/allocator/auxiliary/custom.rs @@ -0,0 +1,31 @@ +// 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. + +// no-prefer-dynamic + +#![feature(heap_api, allocator_api)] +#![crate_type = "rlib"] + +use std::heap::{Alloc, System, AllocErr, Layout}; +use std::sync::atomic::{AtomicUsize, Ordering}; + +pub struct A(pub AtomicUsize); + +unsafe impl<'a> Alloc for &'a A { + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + self.0.fetch_add(1, Ordering::SeqCst); + System.alloc(layout) + } + + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + self.0.fetch_add(1, Ordering::SeqCst); + System.dealloc(ptr, layout) + } +} diff --git a/src/test/compile-fail/auxiliary/allocator1.rs b/src/test/run-pass/allocator/auxiliary/helper.rs similarity index 77% rename from src/test/compile-fail/auxiliary/allocator1.rs rename to src/test/run-pass/allocator/auxiliary/helper.rs index b24784838d00b..e75a432710df2 100644 --- a/src/test/compile-fail/auxiliary/allocator1.rs +++ b/src/test/run-pass/allocator/auxiliary/helper.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -10,7 +10,10 @@ // no-prefer-dynamic -#![feature(allocator)] -#![allocator] #![crate_type = "rlib"] -#![no_std] + +use std::fmt; + +pub fn work_with(p: &fmt::Debug) { + drop(p); +} diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs new file mode 100644 index 0000000000000..b46f024b5bff3 --- /dev/null +++ b/src/test/run-pass/allocator/custom.rs @@ -0,0 +1,68 @@ +// 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. + +// aux-build:helper.rs +// no-prefer-dynamic + +#![feature(global_allocator, heap_api, allocator_api)] + +extern crate helper; + +use std::env; +use std::heap::{Heap, Alloc, System, Layout, AllocErr}; +use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; + +static HITS: AtomicUsize = ATOMIC_USIZE_INIT; + +struct A; + +unsafe impl<'a> Alloc for &'a A { + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + HITS.fetch_add(1, Ordering::SeqCst); + System.alloc(layout) + } + + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + HITS.fetch_add(1, Ordering::SeqCst); + System.dealloc(ptr, layout) + } +} + +#[global_allocator] +static GLOBAL: A = A; + +fn main() { + env::set_var("FOO", "bar"); + drop(env::var("FOO")); + + let n = HITS.load(Ordering::SeqCst); + assert!(n > 0); + unsafe { + let layout = Layout::from_size_align(4, 2).unwrap(); + + let ptr = Heap.alloc(layout.clone()).unwrap(); + helper::work_with(&ptr); + assert_eq!(HITS.load(Ordering::SeqCst), n + 1); + Heap.dealloc(ptr, layout.clone()); + assert_eq!(HITS.load(Ordering::SeqCst), n + 2); + + let s = String::with_capacity(10); + helper::work_with(&s); + assert_eq!(HITS.load(Ordering::SeqCst), n + 3); + drop(s); + assert_eq!(HITS.load(Ordering::SeqCst), n + 4); + + let ptr = System.alloc(layout.clone()).unwrap(); + assert_eq!(HITS.load(Ordering::SeqCst), n + 4); + helper::work_with(&ptr); + System.dealloc(ptr, layout); + assert_eq!(HITS.load(Ordering::SeqCst), n + 4); + } +} diff --git a/src/test/run-pass/allocator/xcrate-use.rs b/src/test/run-pass/allocator/xcrate-use.rs new file mode 100644 index 0000000000000..4b987b9223d6d --- /dev/null +++ b/src/test/run-pass/allocator/xcrate-use.rs @@ -0,0 +1,44 @@ +// 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. + +// aux-build:custom.rs +// aux-build:helper.rs +// no-prefer-dynamic + +#![feature(global_allocator, heap_api, allocator_api)] + +extern crate custom; +extern crate helper; + +use std::env; +use std::heap::{Heap, Alloc, System, Layout}; +use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT}; + +#[global_allocator] +static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT); + +fn main() { + unsafe { + let n = GLOBAL.0.load(Ordering::SeqCst); + let layout = Layout::from_size_align(4, 2).unwrap(); + + let ptr = Heap.alloc(layout.clone()).unwrap(); + helper::work_with(&ptr); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1); + Heap.dealloc(ptr, layout.clone()); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); + + let ptr = System.alloc(layout.clone()).unwrap(); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); + helper::work_with(&ptr); + System.dealloc(ptr, layout); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); + } +} diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs new file mode 100644 index 0000000000000..7e6cd9fdf4950 --- /dev/null +++ b/src/test/run-pass/allocator/xcrate-use2.rs @@ -0,0 +1,57 @@ +// 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. + +// aux-build:custom.rs +// aux-build:custom-as-global.rs +// aux-build:helper.rs +// no-prefer-dynamic + +#![feature(heap_api, allocator_api)] + +extern crate custom; +extern crate custom_as_global; +extern crate helper; + +use std::env; +use std::heap::{Heap, Alloc, System, Layout}; +use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT}; + +static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT); + +fn main() { + unsafe { + let n = custom_as_global::get(); + let layout = Layout::from_size_align(4, 2).unwrap(); + + // Global allocator routes to the `custom_as_global` global + let ptr = Heap.alloc(layout.clone()).unwrap(); + helper::work_with(&ptr); + assert_eq!(custom_as_global::get(), n + 1); + Heap.dealloc(ptr, layout.clone()); + assert_eq!(custom_as_global::get(), n + 2); + + // Usage of the system allocator avoids all globals + let ptr = System.alloc(layout.clone()).unwrap(); + helper::work_with(&ptr); + assert_eq!(custom_as_global::get(), n + 2); + System.dealloc(ptr, layout.clone()); + assert_eq!(custom_as_global::get(), n + 2); + + // Usage of our personal allocator doesn't affect other instances + let ptr = (&GLOBAL).alloc(layout.clone()).unwrap(); + helper::work_with(&ptr); + assert_eq!(custom_as_global::get(), n + 2); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 1); + (&GLOBAL).dealloc(ptr, layout); + assert_eq!(custom_as_global::get(), n + 2); + assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 2); + } +} + diff --git a/src/test/run-pass/lib-defaults.rs b/src/test/run-pass/lib-defaults.rs index a38080f8cfe75..6e5dccae0a07d 100644 --- a/src/test/run-pass/lib-defaults.rs +++ b/src/test/run-pass/lib-defaults.rs @@ -8,16 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:clibrary.rs -// compile-flags: -lclibrary +// compile-flags: -lrust_test_helpers -#[link(name = "clibrary", kind = "static")] +#[link(name = "rust_test_helpers", kind = "static")] extern "C" { - pub fn foo(x:i32) -> i32; + pub fn rust_dbg_extern_identity_u32(x: u32) -> u32; } fn main() { unsafe { - foo(42); + rust_dbg_extern_identity_u32(42); } } diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs index 372d4a8b732ac..f6119e709990a 100644 --- a/src/test/run-pass/range_inclusive.rs +++ b/src/test/run-pass/range_inclusive.rs @@ -10,7 +10,7 @@ // Test inclusive range syntax. -#![feature(inclusive_range_syntax, inclusive_range, step_by)] +#![feature(inclusive_range_syntax, inclusive_range, iterator_step_by)] use std::ops::{RangeInclusive, RangeToInclusive}; diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index b32d42df6b129..eddcd5a584a5d 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -13,11 +13,9 @@ // Ideally this would be revised to use no_std, but for now it serves // well enough to reproduce (and illustrate) the bug from #16687. -#![feature(heap_api, alloc, oom)] +#![feature(heap_api, allocator_api)] -extern crate alloc; - -use alloc::heap; +use std::heap::{Heap, Alloc, Layout}; use std::ptr; fn main() { @@ -47,38 +45,39 @@ unsafe fn test_triangle() -> bool { static PRINT : bool = false; - unsafe fn allocate(size: usize, align: usize) -> *mut u8 { - if PRINT { println!("allocate(size={} align={})", size, align); } + unsafe fn allocate(layout: Layout) -> *mut u8 { + if PRINT { + println!("allocate({:?})", layout); + } - let ret = heap::allocate(size, align); - if ret.is_null() { alloc::oom() } + let ret = Heap.alloc(layout.clone()).unwrap_or_else(|e| Heap.oom(e)); - if PRINT { println!("allocate(size={} align={}) ret: 0x{:010x}", - size, align, ret as usize); + if PRINT { + println!("allocate({:?}) = {:?}", layout, ret); } ret } - unsafe fn deallocate(ptr: *mut u8, size: usize, align: usize) { - if PRINT { println!("deallocate(ptr=0x{:010x} size={} align={})", - ptr as usize, size, align); + + unsafe fn deallocate(ptr: *mut u8, layout: Layout) { + if PRINT { + println!("deallocate({:?}, {:?}", ptr, layout); } - heap::deallocate(ptr, size, align); + Heap.dealloc(ptr, layout); } - unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { + + unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { if PRINT { - println!("reallocate(ptr=0x{:010x} old_size={} size={} align={})", - ptr as usize, old_size, size, align); + println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); } - let ret = heap::reallocate(ptr, old_size, size, align); - if ret.is_null() { alloc::oom() } + let ret = Heap.realloc(ptr, old.clone(), new.clone()) + .unwrap_or_else(|e| Heap.oom(e)); if PRINT { - println!("reallocate(ptr=0x{:010x} old_size={} size={} align={}) \ - ret: 0x{:010x}", - ptr as usize, old_size, size, align, ret as usize); + println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", + ptr, old, new, ret); } ret } @@ -91,8 +90,8 @@ unsafe fn test_triangle() -> bool { // way.) for i in 0..COUNT / 2 { let size = idx_to_size(i); - ascend[2*i] = allocate(size, ALIGN); - ascend[2*i+1] = allocate(size, ALIGN); + ascend[2*i] = allocate(Layout::from_size_align(size, ALIGN).unwrap()); + ascend[2*i+1] = allocate(Layout::from_size_align(size, ALIGN).unwrap()); } // Initialize each pair of rows to distinct value. @@ -112,8 +111,8 @@ unsafe fn test_triangle() -> bool { for i in 0..COUNT / 2 { let size = idx_to_size(i); - deallocate(ascend[2*i], size, ALIGN); - deallocate(ascend[2*i+1], size, ALIGN); + deallocate(ascend[2*i], Layout::from_size_align(size, ALIGN).unwrap()); + deallocate(ascend[2*i+1], Layout::from_size_align(size, ALIGN).unwrap()); } return true; @@ -124,14 +123,16 @@ unsafe fn test_triangle() -> bool { // rows as we go. unsafe fn test_1(ascend: &mut [*mut u8]) { let new_size = idx_to_size(COUNT-1); + let new = Layout::from_size_align(new_size, ALIGN).unwrap(); for i in 0..COUNT / 2 { let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i)); assert!(old_size < new_size); + let old = Layout::from_size_align(old_size, ALIGN).unwrap(); - ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN); + ascend[2*i] = reallocate(p0, old.clone(), new.clone()); sanity_check(&*ascend); - ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN); + ascend[2*i+1] = reallocate(p1, old.clone(), new.clone()); sanity_check(&*ascend); } } @@ -139,14 +140,16 @@ unsafe fn test_triangle() -> bool { // Test 2: turn the square back into a triangle, top to bottom. unsafe fn test_2(ascend: &mut [*mut u8]) { let old_size = idx_to_size(COUNT-1); + let old = Layout::from_size_align(old_size, ALIGN).unwrap(); for i in 0..COUNT / 2 { let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i)); assert!(new_size < old_size); + let new = Layout::from_size_align(new_size, ALIGN).unwrap(); - ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN); + ascend[2*i] = reallocate(p0, old.clone(), new.clone()); sanity_check(&*ascend); - ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN); + ascend[2*i+1] = reallocate(p1, old.clone(), new.clone()); sanity_check(&*ascend); } } @@ -154,14 +157,16 @@ unsafe fn test_triangle() -> bool { // Test 3: turn triangle into a square, bottom to top. unsafe fn test_3(ascend: &mut [*mut u8]) { let new_size = idx_to_size(COUNT-1); + let new = Layout::from_size_align(new_size, ALIGN).unwrap(); for i in (0..COUNT / 2).rev() { let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i)); assert!(old_size < new_size); + let old = Layout::from_size_align(old_size, ALIGN).unwrap(); - ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN); + ascend[2*i+1] = reallocate(p1, old.clone(), new.clone()); sanity_check(&*ascend); - ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN); + ascend[2*i] = reallocate(p0, old.clone(), new.clone()); sanity_check(&*ascend); } } @@ -169,14 +174,16 @@ unsafe fn test_triangle() -> bool { // Test 4: turn the square back into a triangle, bottom to top. unsafe fn test_4(ascend: &mut [*mut u8]) { let old_size = idx_to_size(COUNT-1); + let old = Layout::from_size_align(old_size, ALIGN).unwrap(); for i in (0..COUNT / 2).rev() { let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i)); assert!(new_size < old_size); + let new = Layout::from_size_align(new_size, ALIGN).unwrap(); - ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN); + ascend[2*i+1] = reallocate(p1, old.clone(), new.clone()); sanity_check(&*ascend); - ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN); + ascend[2*i] = reallocate(p0, old.clone(), new.clone()); sanity_check(&*ascend); } } diff --git a/src/test/run-pass/rfc1717/library-override.rs b/src/test/run-pass/rfc1717/library-override.rs index d6ef96c5add01..26713a2554377 100644 --- a/src/test/run-pass/rfc1717/library-override.rs +++ b/src/test/run-pass/rfc1717/library-override.rs @@ -8,16 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:clibrary.rs -// compile-flags: -lstatic=wronglibrary:clibrary +// compile-flags: -lstatic=wronglibrary:rust_test_helpers #[link(name = "wronglibrary", kind = "dylib")] extern "C" { - pub fn foo(x:i32) -> i32; + pub fn rust_dbg_extern_identity_u32(x: u32) -> u32; } fn main() { unsafe { - foo(42); + rust_dbg_extern_identity_u32(42); } } diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs index 053ee8ee42ed6..bcbd3fd3786ab 100644 --- a/src/test/run-pass/smallest-hello-world.rs +++ b/src/test/run-pass/smallest-hello-world.rs @@ -10,32 +10,32 @@ // Smallest "hello world" with a libc runtime -// pretty-expanded FIXME #23616 // ignore-windows +// ignore-android #![feature(intrinsics, lang_items, start, no_core, alloc_system)] -#![no_core] +#![feature(global_allocator, allocator_api)] +#![no_std] extern crate alloc_system; -extern { fn puts(s: *const u8); } -extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; } +use alloc_system::System; -#[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} +#[global_allocator] +static A: System = System; + +extern { + fn puts(s: *const u8); +} + +#[no_mangle] +#[lang = "eh_personality"] pub extern fn rust_eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } -#[no_mangle] pub extern fn rust_eh_register_frames () {} -#[no_mangle] pub extern fn rust_eh_unregister_frames () {} #[start] fn main(_: isize, _: *const *const u8) -> isize { unsafe { - let (ptr, _): (*const u8, usize) = transmute("Hello!\0"); - puts(ptr); + puts("Hello!\0".as_ptr() as *const u8); } - return 0; + return 0 } - -#[cfg(target_os = "android")] -#[link(name="gcc")] -extern { } diff --git a/src/test/run-pass/sync-send-iterators-in-libcore.rs b/src/test/run-pass/sync-send-iterators-in-libcore.rs index d12bdf182fa4d..c11a0d391a469 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcore.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcore.rs @@ -14,7 +14,7 @@ #![feature(iter_empty)] #![feature(iter_once)] #![feature(iter_unfold)] -#![feature(step_by)] +#![feature(iterator_step_by)] #![feature(str_escape)] use std::iter::{empty, once, repeat}; diff --git a/src/test/ui/token/macro-incomplete-parse.rs b/src/test/ui/token/macro-incomplete-parse.rs index 47374fc3c6085..08749373432f5 100644 --- a/src/test/ui/token/macro-incomplete-parse.rs +++ b/src/test/ui/token/macro-incomplete-parse.rs @@ -32,7 +32,7 @@ macro_rules! ignored_pat { ignored_item!(); //~ NOTE caused by the macro expansion here fn main() { - ignored_expr!(); + ignored_expr!(); //~ NOTE in this expansion match 1 { ignored_pat!() => (), //~ NOTE caused by the macro expansion here _ => (), diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr index f23d97586b843..6bce09af05250 100644 --- a/src/test/ui/token/macro-incomplete-parse.stderr +++ b/src/test/ui/token/macro-incomplete-parse.stderr @@ -15,6 +15,9 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` | 22 | () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` | ^ expected one of `.`, `;`, `?`, `}`, or an operator here +... +35 | ignored_expr!(); //~ NOTE in this expansion + | ---------------- in this macro invocation error: macro expansion ignores token `,` and any following --> $DIR/macro-incomplete-parse.rs:29:14 diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs index c8c6cb0ee6b41..f40fea60f40a8 100644 --- a/src/tools/tidy/src/cargo.rs +++ b/src/tools/tidy/src/cargo.rs @@ -91,14 +91,6 @@ fn verify(tomlfile: &Path, libfile: &Path, bad: &mut bool) { continue } - // We want the compiler to depend on the proc_macro_plugin crate so - // that it is built and included in the end, but we don't want to - // actually use it in the compiler. - if toml.contains("name = \"rustc_driver\"") && - krate == "proc_macro_plugin" { - continue - } - if !librs.contains(&format!("extern crate {}", krate)) { tidy_error!(bad, "{} doesn't have `extern crate {}`, but Cargo.toml \ depends on it", libfile.display(), krate); diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 722fc2b317eb4..4c94ade98d965 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -245,7 +245,7 @@ fn get_and_check_lib_features(base_src_path: &Path, let mut err = |msg: &str| { tidy_error!(bad, "{}:{}: {}", file.display(), line, msg); }; - if lang_features.contains_key(name) { + if lang_features.contains_key(name) && name != "proc_macro" { err("duplicating a lang feature"); } if let Some(ref s) = lib_features.get(name) { diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index bcf86e4489be3..020570e61dc63 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -54,6 +54,7 @@ fn filter_dirs(path: &Path) -> bool { "src/jemalloc", "src/llvm", "src/libbacktrace", + "src/libcompiler_builtins", "src/compiler-rt", "src/rustllvm", "src/liblibc",