From: bors Date: Thu, 27 Apr 2017 10:47:56 +0000 (+0000) Subject: Auto merge of #41433 - estebank:constructor, r=michaelwoerister X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=79b05fee0fd1423a49e9655d554eec7bfebb0e87;hp=cd60307acb110ae268556e41a6abdc8d59d7e72b;p=rust.git Auto merge of #41433 - estebank:constructor, r=michaelwoerister Do not show `::{{constructor}}` on tuple struct diagnostics Fix #41313. --- diff --git a/.travis.yml b/.travis.yml index 5d56379dcce..c5372609e9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,7 +54,7 @@ matrix: # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. - env: > RUST_CHECK_TARGET=check - RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin + RUST_CONFIGURE_ARGS="--build=x86_64-apple-darwin --enable-sanitizers" SRC=. RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log @@ -98,7 +98,7 @@ matrix: install: *osx_install_sccache - env: > RUST_CHECK_TARGET=dist - RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended" + RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended --enable-sanitizers" SRC=. DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 diff --git a/appveyor.yml b/appveyor.yml index 5de5f3bd26c..c662ba03602 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,39 +20,28 @@ environment: # 32/64-bit MinGW builds. # - # The MinGW builds unfortunately have to both download a custom toolchain and - # avoid the one installed by AppVeyor by default. Interestingly, though, for - # different reasons! + # We are using MinGW with posix threads since LLVM does not compile with + # the win32 threads version due to missing support for C++'s std::thread. # - # For 32-bit the installed gcc toolchain on AppVeyor uses the pthread - # threading model. This is unfortunately not what we want, and if we compile - # with it then there's lots of link errors in the standard library (undefined - # references to pthread symbols). - # - # For 64-bit the installed gcc toolchain is currently 5.3.0 which - # unfortunately segfaults on Windows with --enable-llvm-assertions (segfaults - # in LLVM). See rust-lang/rust#28445 for more information, but to work around - # this we go back in time to 4.9.2 specifically. + # Instead of relying on the MinGW version installed on appveryor we download + # and install one ourselves so we won't be surprised by changes to appveyor's + # build image. # # Finally, note that the downloads below are all in the `rust-lang-ci` S3 # bucket, but they cleraly didn't originate there! The downloads originally # came from the mingw-w64 SourceForge download site. Unfortunately # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. - # - # And as a final point of note, the 32-bit MinGW build using the makefiles do - # *not* use debug assertions and llvm assertions. This is because they take - # too long on appveyor and this is tested by rustbuild below. - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-ninja SCRIPT: python x.py test MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: i686-6.2.0-release-win32-dwarf-rt_v5-rev1.7z + MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 - MSYS_BITS: 64 SCRIPT: python x.py test RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-ninja MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.2.0-release-win32-seh-rt_v5-rev1.7z + MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 # 32/64 bit MSVC and GNU deployment @@ -71,14 +60,14 @@ environment: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-ninja SCRIPT: python x.py dist MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: i686-6.2.0-release-win32-dwarf-rt_v5-rev1.7z + MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 DEPLOY: 1 - MSYS_BITS: 64 SCRIPT: python x.py dist RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-ninja MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.2.0-release-win32-seh-rt_v5-rev1.7z + MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 DEPLOY: 1 @@ -107,6 +96,26 @@ install: - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul - if defined MINGW_URL set PATH=%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH% + # Here we do a pretty heinous thing which is to mangle the MinGW installation + # we just had above. Currently, as of this writing, we're using MinGW-w64 + # builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it appears to + # be the first version which contains a fix for #40546, builds randomly + # failing during LLVM due to ar.exe/ranlib.exe failures. + # + # Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds + # to contain a regression in gdb (#40184). As a result if we were to use the + # gdb provided (7.11.1) then we would fail all debuginfo tests. + # + # In order to fix spurious failures (pretty high priority) we use 6.3.0. To + # avoid disabling gdb tests we download an *old* version of gdb, specifically + # that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb + # with the 6.2.0 gdb to get tests passing. + # + # Note that we don't literally overwrite the gdb.exe binary because it appears + # to just use gdborig.exe, so that's the binary we deal with instead. + - if defined MINGW_URL appveyor-retry appveyor DownloadFile %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe + - if defined MINGW_URL mv 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_DIR%\bin\gdborig.exe + # Otherwise pull in the MinGW installed on appveyor - if NOT defined MINGW_URL set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% diff --git a/cargo b/cargo index c416fb60b11..03efb7fc8b0 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 +Subproject commit 03efb7fc8b0dbb54973ee1b6188f3faf14fffe36 diff --git a/configure b/configure index 35b376d5f27..c5ecc223689 100755 --- a/configure +++ b/configure @@ -479,6 +479,7 @@ valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path" valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path" valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path" valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path" +valopt x86_64-linux-android-ndk "" "x86_64-linux-android NDK standalone path" valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!" valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)" valopt musl-root-x86_64 "" "x86_64-unknown-linux-musl install directory" @@ -746,6 +747,7 @@ putvar CFG_AARCH64_LINUX_ANDROID_NDK putvar CFG_ARM_LINUX_ANDROIDEABI_NDK putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK putvar CFG_I686_LINUX_ANDROID_NDK +putvar CFG_X86_64_LINUX_ANDROID_NDK putvar CFG_NACL_CROSS_PATH putvar CFG_MANDIR putvar CFG_DOCDIR diff --git a/rls b/rls index 016cbc514cf..6ecff95fdc3 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 +Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce diff --git a/src/Cargo.lock b/src/Cargo.lock index f4c35719f36..0a584ac6b01 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -78,7 +78,7 @@ dependencies = [ "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -299,7 +299,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "0.2.13" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1004,7 +1004,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum mdbook 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "2598843aeda0c5bb2e8e4d714564f1c3fc40f7844157e34563bf96ae3866b56e" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" -"checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" +"checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" "checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 1eda1608c47..ecfddec328c 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -27,7 +27,7 @@ test = false build_helper = { path = "../build_helper" } cmake = "0.1.17" filetime = "0.1" -num_cpus = "0.2" +num_cpus = "1.0" toml = "0.1" getopts = "0.2" rustc-serialize = "0.3" diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 3233a73b007..e5f8143b418 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -367,6 +367,9 @@ class RustBuild(object): env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ (os.pathsep + env["DYLD_LIBRARY_PATH"]) \ if "DYLD_LIBRARY_PATH" in env else "" + env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ + (os.pathsep + env["LIBRARY_PATH"]) \ + if "LIBRARY_PATH" in env else "" env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] if not os.path.isfile(self.cargo()): @@ -407,7 +410,11 @@ class RustBuild(object): # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. if ostype == 'Linux': - ostype = 'unknown-linux-gnu' + os = subprocess.check_output(['uname', '-o']).strip().decode(default_encoding) + if os == 'Android': + ostype = 'linux-android' + else: + ostype = 'unknown-linux-gnu' elif ostype == 'FreeBSD': ostype = 'unknown-freebsd' elif ostype == 'DragonFly': @@ -464,15 +471,21 @@ class RustBuild(object): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' + if ostype == 'linux-android': + ostype = 'linux-androideabi' elif cputype == 'armv6l': cputype = 'arm' - ostype += 'eabihf' + if ostype == 'linux-android': + ostype = 'linux-androideabi' + else: + ostype += 'eabihf' elif cputype in {'armv7l', 'armv8l'}: cputype = 'armv7' - ostype += 'eabihf' - elif cputype == 'aarch64': - cputype = 'aarch64' - elif cputype == 'arm64': + if ostype == 'linux-android': + ostype = 'linux-androideabi' + else: + ostype += 'eabihf' + elif cputype in {'aarch64', 'arm64'}: cputype = 'aarch64' elif cputype == 'mips': if sys.byteorder == 'big': diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index f8f641060c4..8ab07e9e5b5 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -78,14 +78,6 @@ pub fn linkcheck(build: &Build, host: &str) { pub fn cargotest(build: &Build, stage: u32, host: &str) { let ref compiler = Compiler::new(stage, host); - // Configure PATH to find the right rustc. NB. we have to use PATH - // 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); - // 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 // quickly run into path name limit constraints. @@ -95,9 +87,35 @@ 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); - build.run(cmd.env("PATH", newpath) - .arg(&build.cargo) - .arg(&out_dir)); + build.run(cmd.arg(&build.cargo) + .arg(&out_dir) + .env("RUSTC", build.compiler_path(compiler)) + .env("RUSTDOC", build.rustdoc(compiler))) +} + +/// Runs `cargo test` for `cargo` packaged with Rust. +pub fn cargo(build: &Build, stage: u32, host: &str) { + let ref compiler = Compiler::new(stage, host); + + // Configure PATH to find the right rustc. NB. we have to use PATH + // 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 mut cargo = build.cargo(compiler, Mode::Tool, host, "test"); + cargo.arg("--manifest-path").arg(build.src.join("cargo/Cargo.toml")); + + // Don't build tests dynamically, just a pain to work with + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + + // Don't run cross-compile tests, we may not have cross-compiled libstd libs + // available. + cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); + + build.run(cargo.env("PATH", newpath)); } /// Runs the `tidy` tool as compiled in `stage` by the `host` compiler. diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index bddd570a13d..6f1de62d07e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -115,6 +115,13 @@ pub fn std_link(build: &Build, if target.contains("musl") && !target.contains("mips") { copy_musl_third_party_objects(build, target, &libdir); } + + if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" { + // The sanitizers are only built in stage1 or above, so the dylibs will + // be missing in stage0 and causes panic. See the `std()` function above + // for reason why the sanitizers are not built in stage0. + copy_apple_sanitizer_dylibs(&build.native_dir(target), "osx", &libdir); + } } /// Copies the crt(1,i,n).o startup objects @@ -126,6 +133,18 @@ fn copy_musl_third_party_objects(build: &Build, target: &str, into: &Path) { } } +fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) { + for &sanitizer in &["asan", "tsan"] { + let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform); + let mut src_path = native_dir.join(sanitizer); + src_path.push("build"); + src_path.push("lib"); + src_path.push("darwin"); + src_path.push(&filename); + copy(&src_path, &into.join(filename)); + } +} + /// Build and prepare startup objects like rsbegin.o and rsend.o /// /// These are primarily used on Windows right now for linking executables/dlls. @@ -151,6 +170,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st if !up_to_date(src_file, dst_file) { let mut cmd = Command::new(&compiler_path); build.run(cmd.env("RUSTC_BOOTSTRAP", "1") + .arg("--cfg").arg(format!("stage{}", compiler.stage)) .arg("--target").arg(target) .arg("--emit=obj") .arg("--out-dir").arg(dst_dir) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 693114d01ad..34fbc33d981 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -570,6 +570,12 @@ macro_rules! check { .or_insert(Target::default()); target.ndk = Some(parse_configure_path(value)); } + "CFG_X86_64_LINUX_ANDROID_NDK" if value.len() > 0 => { + let target = "x86_64-linux-android".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.ndk = Some(parse_configure_path(value)); + } "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => { let path = parse_configure_path(value); self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"])); diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index fad79022043..0309eca0e5d 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -51,7 +51,7 @@ # support. You'll need to write a target specification at least, and most # likely, teach rustc about the C ABI of the target. Get in touch with the # Rust team and file an issue if you need assistance in porting! -#targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX" +#targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX;Hexagon" # Cap the number of parallel linker invocations when compiling LLVM. # This can be useful when building LLVM with debug info, which significantly diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 4328c4e3f1d..639ba5d5b0c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -254,7 +254,12 @@ pub fn debugger_scripts(build: &Build, install(&build.src.join("src/etc/").join(file), &dst, 0o644); }; if host.contains("windows-msvc") { - // no debugger scripts + // windbg debugger scripts + install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"), + 0o755); + + cp_debugger_script("natvis/libcore.natvis"); + cp_debugger_script("natvis/libcollections.natvis"); } else { cp_debugger_script("debugger_pretty_printers_common.py"); @@ -369,13 +374,11 @@ pub fn rust_src(build: &Build) { println!("Dist src"); - let name = pkgname(build, "rust-src"); - let image = tmpdir(build).join(format!("{}-image", name)); - let _ = fs::remove_dir_all(&image); - - let dst = image.join("lib/rustlib/src"); - let dst_src = dst.join("rust"); - t!(fs::create_dir_all(&dst_src)); + // Make sure that the root folder of tarball has the correct name + let plain_name = format!("rustc-{}-src", build.rust_package_vers()); + let plain_dst_src = tmpdir(build).join(&plain_name); + let _ = fs::remove_dir_all(&plain_dst_src); + t!(fs::create_dir_all(&plain_dst_src)); // This is the set of root paths which will become part of the source package let src_files = [ @@ -424,13 +427,13 @@ pub fn rust_src(build: &Build) { // Copy the directories using our filter for item in &src_dirs { - let dst = &dst_src.join(item); + let dst = &plain_dst_src.join(item); t!(fs::create_dir(dst)); cp_filtered(&build.src.join(item), dst, &filter_fn); } // Copy the files normally for item in &src_files { - copy(&build.src.join(item), &dst_src.join(item)); + copy(&build.src.join(item), &plain_dst_src.join(item)); } // If we're building from git sources, we need to vendor a complete distribution. @@ -455,10 +458,63 @@ pub fn rust_src(build: &Build) { // Vendor all Cargo dependencies let mut cmd = Command::new(&build.cargo); cmd.arg("vendor") - .current_dir(&dst_src.join("src")); + .current_dir(&plain_dst_src.join("src")); build.run(&mut cmd); } + // Create the version file + write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes()); + + // Create plain source tarball + let tarball = rust_src_location(build); + if let Some(dir) = tarball.parent() { + t!(fs::create_dir_all(dir)); + } + let mut cmd = Command::new("tar"); + cmd.arg("-czf").arg(sanitize_sh(&tarball)) + .arg(&plain_name) + .current_dir(tmpdir(build)); + build.run(&mut cmd); + + + let name = pkgname(build, "rust-src"); + let image = tmpdir(build).join(format!("{}-image", name)); + let _ = fs::remove_dir_all(&image); + + let dst = image.join("lib/rustlib/src"); + let dst_src = dst.join("rust"); + t!(fs::create_dir_all(&dst_src)); + + // This is the reduced set of paths which will become the rust-src component + // (essentially libstd and all of its path dependencies) + let std_src_dirs = [ + "src/build_helper", + "src/liballoc", + "src/liballoc_jemalloc", + "src/liballoc_system", + "src/libcollections", + "src/libcompiler_builtins", + "src/libcore", + "src/liblibc", + "src/libpanic_abort", + "src/libpanic_unwind", + "src/librand", + "src/librustc_asan", + "src/librustc_lsan", + "src/librustc_msan", + "src/librustc_tsan", + "src/libstd", + "src/libstd_unicode", + "src/libunwind", + "src/rustc/libc_shim", + ]; + + for item in &std_src_dirs { + let dst = &dst_src.join(item); + t!(fs::create_dir_all(dst)); + cp_r(&plain_dst_src.join(item), dst); + } + // Create source tarball in rust-installer format let mut cmd = Command::new(SH_CMD); cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) @@ -473,23 +529,6 @@ pub fn rust_src(build: &Build) { .arg("--legacy-manifest-dirs=rustlib,cargo"); build.run(&mut cmd); - // Rename directory, so that root folder of tarball has the correct name - let plain_name = format!("rustc-{}-src", build.rust_package_vers()); - let plain_dst_src = tmpdir(build).join(&plain_name); - let _ = fs::remove_dir_all(&plain_dst_src); - t!(fs::create_dir_all(&plain_dst_src)); - cp_r(&dst_src, &plain_dst_src); - - // Create the version file - write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes()); - - // Create plain source tarball - let mut cmd = Command::new("tar"); - cmd.arg("-czf").arg(sanitize_sh(&rust_src_location(build))) - .arg(&plain_name) - .current_dir(tmpdir(build)); - build.run(&mut cmd); - t!(fs::remove_dir_all(&image)); t!(fs::remove_dir_all(&plain_dst_src)); } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 5e046f41673..bbfab388950 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -557,6 +557,19 @@ fn cargo(&self, cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } + // When being built Cargo will at some point call `nmake.exe` on Windows + // MSVC. Unfortunately `nmake` will read these two environment variables + // below and try to intepret them. We're likely being run, however, from + // MSYS `make` which uses the same variables. + // + // As a result, to prevent confusion and errors, we remove these + // variables from our environment to prevent passing MSYS make flags to + // nmake, causing it to blow up. + if cfg!(target_env = "msvc") { + cargo.env_remove("MAKE"); + cargo.env_remove("MAKEFLAGS"); + } + // Environment variables *required* needed throughout the build // // FIXME: should update code to not require this env var @@ -882,6 +895,13 @@ fn cflags(&self, target: &str) -> Vec { if target.contains("apple-darwin") { base.push("-stdlib=libc++".into()); } + + // Work around an apparently bad MinGW / GCC optimization, + // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html + // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78936 + if target == "i686-pc-windows-gnu" { + base.push("-fno-omit-frame-pointer".into()); + } return base } diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 5918fe41e7c..7b6b01655df 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -58,6 +58,7 @@ fn build_krate(build: &mut Build, krate: &str) { // the dependency graph and what `-p` arguments there are. let mut cargo = Command::new(&build.cargo); cargo.arg("metadata") + .arg("--format-version").arg("1") .arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml")); let output = output(&mut cargo); let output: Output = json::decode(&output).unwrap(); diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 457ac825832..a5df741e2bf 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -55,6 +55,7 @@ check: check-aux: $(Q)$(BOOTSTRAP) test \ src/tools/cargotest \ + cargo \ src/test/pretty \ src/test/run-pass/pretty \ src/test/run-fail/pretty \ diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 726e94e49a1..c0b8a9f1ef6 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -81,7 +81,7 @@ pub fn llvm(build: &Build, target: &str) { // NOTE: remember to also update `config.toml.example` when changing the defaults! let llvm_targets = match build.config.llvm_targets { Some(ref s) => s, - None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX", + None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX;Hexagon", }; let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"}; @@ -306,7 +306,7 @@ pub fn openssl(build: &Build, target: &str) { println!("Configuring openssl for {}", target); build.run_quiet(&mut configure); println!("Building openssl for {}", target); - build.run_quiet(Command::new("make").current_dir(&obj)); + build.run_quiet(Command::new("make").arg("-j1").current_dir(&obj)); println!("Installing openssl for {}", target); build.run_quiet(Command::new("make").arg("install").current_dir(&obj)); diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 17902a39df1..d811e1122c4 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -470,6 +470,10 @@ fn crate_rule<'a, 'b>(build: &'a Build, .dep(|s| s.name("librustc")) .host(true) .run(move |s| check::cargotest(build, s.stage, s.target)); + rules.test("check-cargo", "cargo") + .dep(|s| s.name("tool-cargo")) + .host(true) + .run(move |s| check::cargo(build, s.stage, s.target)); rules.test("check-tidy", "src/tools/tidy") .dep(|s| s.name("tool-tidy").stage(0)) .default(true) diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index dab20f44bc3..e01c06b10fc 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -139,6 +139,8 @@ pub fn dylib_path_var() -> &'static str { "PATH" } else if cfg!(target_os = "macos") { "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" } else { "LD_LIBRARY_PATH" } diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index cb58a916fb7..da00b970da9 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -198,7 +198,11 @@ pub fn native_lib_boilerplate(src_name: &str, let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap()); let out_dir = PathBuf::from(out_dir).join(out_name); t!(create_dir_racy(&out_dir)); - println!("cargo:rustc-link-lib=static={}", link_name); + if link_name.contains('=') { + println!("cargo:rustc-link-lib={}", link_name); + } else { + println!("cargo:rustc-link-lib=static={}", link_name); + } println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display()); let timestamp = out_dir.join("rustbuild.timestamp"); @@ -209,6 +213,21 @@ pub fn native_lib_boilerplate(src_name: &str, } } +pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result { + let (link_name, search_path) = match &*env::var("TARGET").unwrap() { + "x86_64-unknown-linux-gnu" => ( + format!("clang_rt.{}-x86_64", sanitizer_name), + "build/lib/linux", + ), + "x86_64-apple-darwin" => ( + format!("dylib=clang_rt.{}_osx_dynamic", sanitizer_name), + "build/lib/darwin", + ), + _ => return Err(()), + }; + native_lib_boilerplate("compiler-rt", sanitizer_name, &link_name, search_path) +} + fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool { t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| { let meta = t!(e.metadata()); diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 99c176aa820..28cc885ed30 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -36,9 +36,10 @@ RUN curl -o /usr/local/bin/sccache \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi +ENV TARGETS=$TARGETS,armv7-linux-androideabi ENV TARGETS=$TARGETS,i686-linux-android ENV TARGETS=$TARGETS,aarch64-linux-android -ENV TARGETS=$TARGETS,armv7-linux-androideabi +ENV TARGETS=$TARGETS,x86_64-linux-android ENV RUST_CONFIGURE_ARGS \ --target=$TARGETS \ @@ -46,6 +47,7 @@ ENV RUST_CONFIGURE_ARGS \ --arm-linux-androideabi-ndk=/android/ndk-arm-9 \ --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \ --i686-linux-android-ndk=/android/ndk-x86-9 \ - --aarch64-linux-android-ndk=/android/ndk-aarch64 + --aarch64-linux-android-ndk=/android/ndk-arm64-21 \ + --x86_64-linux-android-ndk=/android/ndk-x86_64-21 ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-android/install-ndk.sh b/src/ci/docker/dist-android/install-ndk.sh index 19c1b94e784..d3a2d317545 100644 --- a/src/ci/docker/dist-android/install-ndk.sh +++ b/src/ci/docker/dist-android/install-ndk.sh @@ -25,7 +25,7 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ --platform=android-21 \ --toolchain=aarch64-linux-android-4.9 \ - --install-dir=/android/ndk-aarch64 \ + --install-dir=/android/ndk-arm64-21 \ --ndk-dir=/android/android-ndk-r11c \ --arch=arm64 bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ @@ -34,5 +34,11 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ --install-dir=/android/ndk-x86-9 \ --ndk-dir=/android/android-ndk-r11c \ --arch=x86 +bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ + --platform=android-21 \ + --toolchain=x86_64-4.9 \ + --install-dir=/android/ndk-x86_64-21 \ + --ndk-dir=/android/android-ndk-r11c \ + --arch=x86_64 rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile index ffdb1d18a94..cbbca23f6e3 100644 --- a/src/ci/docker/emscripten/Dockerfile +++ b/src/ci/docker/emscripten/Dockerfile @@ -27,10 +27,10 @@ WORKDIR /tmp COPY build-emscripten.sh /tmp/ RUN ./build-emscripten.sh ENV PATH=$PATH:/tmp/emsdk_portable -ENV PATH=$PATH:/tmp/emsdk_portable/clang/tag-e1.37.1/build_tag-e1.37.1_32/bin +ENV PATH=$PATH:/tmp/emsdk_portable/clang/tag-e1.37.10/build_tag-e1.37.10_32/bin ENV PATH=$PATH:/tmp/emsdk_portable/node/4.1.1_32bit/bin -ENV PATH=$PATH:/tmp/emsdk_portable/emscripten/tag-1.37.1 -ENV EMSCRIPTEN=/tmp/emsdk_portable/emscripten/tag-1.37.1 +ENV PATH=$PATH:/tmp/emsdk_portable/emscripten/tag-1.37.10 +ENV EMSCRIPTEN=/tmp/emsdk_portable/emscripten/tag-1.37.10 ENV RUST_CONFIGURE_ARGS --target=asmjs-unknown-emscripten diff --git a/src/ci/docker/emscripten/build-emscripten.sh b/src/ci/docker/emscripten/build-emscripten.sh index e39767357ad..8d6a28f418b 100755 --- a/src/ci/docker/emscripten/build-emscripten.sh +++ b/src/ci/docker/emscripten/build-emscripten.sh @@ -49,5 +49,5 @@ chmod 755 emsdk_portable source emsdk_portable/emsdk_env.sh hide_output emsdk update -hide_output emsdk install --build=Release sdk-tag-1.37.1-32bit -hide_output emsdk activate --build=Release sdk-tag-1.37.1-32bit +hide_output emsdk install --build=Release sdk-tag-1.37.10-32bit +hide_output emsdk activate --build=Release sdk-tag-1.37.10-32bit diff --git a/src/compiler-rt b/src/compiler-rt index d30da544a8a..c8a8767c56a 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 +Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35 diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 3fbf9f06d99..12daa24e857 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -781,10 +781,11 @@ never_type : "!" ; ### Type parameter bounds ```antlr +bound-list := bound | bound '+' bound-list '+' ? bound := ty_bound | lt_bound lt_bound := lifetime -ty_bound := [?] [ for ] simple_path -bound-list := bound | bound '+' bound-list '+' ? +ty_bound := ty_bound_noparen | (ty_bound_noparen) +ty_bound_noparen := [?] [ for ] simple_path ``` ### Self types diff --git a/src/doc/index.md b/src/doc/index.md index 1294c1a8c59..fd5b120e81f 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -32,16 +32,21 @@ nicknamed 'The Rust Bookshelf.' * [The Rustonomicon][nomicon] is your guidebook to the dark arts of unsafe Rust. * [The Reference][ref] is not a formal spec, but is more detailed and comprehensive than the book. +Initially, documentation lands in the Unstable Book, and then, as part of the +stabilization process, is moved into the Book, Nomicon, or Reference. + Another few words about the reference: it is guaranteed to be accurate, but not -complete. We now have a policy that all new features must be included in the -reference before stabilization; however, we are still back-filling things that -landed before then. That work is being tracked [here][38643]. +complete. We have a policy that features must have documentation to be stabilized, +but we did not always have this policy, and so there are some stable things that +are not yet in the reference. We're working on back-filling things that landed +before this policy was put into place. That work is being tracked +[here][refchecklist]. [Rust Learning]: https://github.com/ctjhoa/rust-learning [Docs.rs]: https://docs.rs/ [api]: std/index.html [ref]: reference/index.html -[38643]: https://github.com/rust-lang/rust/issues/38643 +[refchecklist]: https://github.com/rust-lang-nursery/reference/issues/9 [err]: error-index.html [book]: book/index.html [nomicon]: nomicon/index.html diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 3e041543977..2cb37630112 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -72,6 +72,7 @@ - [proc_macro](language-features/proc-macro.md) - [quote](language-features/quote.md) - [relaxed_adts](language-features/relaxed-adts.md) + - [repr_align](language-features/repr-align.md) - [repr_simd](language-features/repr-simd.md) - [rustc_attrs](language-features/rustc-attrs.md) - [rustc_diagnostic_macros](language-features/rustc-diagnostic-macros.md) @@ -101,11 +102,8 @@ - [alloc_system](library-features/alloc-system.md) - [alloc](library-features/alloc.md) - [as_c_str](library-features/as-c-str.md) - - [as_unsafe_cell](library-features/as-unsafe-cell.md) - [ascii_ctype](library-features/ascii-ctype.md) - - [binary_heap_extras](library-features/binary-heap-extras.md) - [binary_heap_peek_mut_pop](library-features/binary-heap-peek-mut-pop.md) - - [borrow_state](library-features/borrow-state.md) - [box_heap](library-features/box-heap.md) - [c_void_variant](library-features/c-void-variant.md) - [char_escape_debug](library-features/char-escape-debug.md) @@ -130,14 +128,12 @@ - [derive_clone_copy](library-features/derive-clone-copy.md) - [derive_eq](library-features/derive-eq.md) - [discriminant_value](library-features/discriminant-value.md) - - [enumset](library-features/enumset.md) - [error_type_id](library-features/error-type-id.md) - [exact_size_is_empty](library-features/exact-size-is-empty.md) - [fd](library-features/fd.md) - [fd_read](library-features/fd-read.md) - [fixed_size_array](library-features/fixed-size-array.md) - [float_bits_conv](library-features/float-bits-conv.md) - - [float_extras](library-features/float-extras.md) - [flt2dec](library-features/flt2dec.md) - [fmt_flags_align](library-features/fmt-flags-align.md) - [fmt_internals](library-features/fmt-internals.md) @@ -157,7 +153,6 @@ - [io_error_internals](library-features/io-error-internals.md) - [io](library-features/io.md) - [ip](library-features/ip.md) - - [is_unique](library-features/is-unique.md) - [iter_rfind](library-features/iter-rfind.md) - [libstd_io_internals](library-features/libstd-io-internals.md) - [libstd_sys_internals](library-features/libstd-sys-internals.md) @@ -165,7 +160,7 @@ - [linked_list_extras](library-features/linked-list-extras.md) - [lookup_host](library-features/lookup-host.md) - [manually_drop](library-features/manually-drop.md) - - [map_entry_recover_keys](library-features/map-entry-recover-keys.md) + - [more_io_inner_methods](library-features/more-io-inner-methods.md) - [mpsc_select](library-features/mpsc-select.md) - [n16](library-features/n16.md) - [never_type_impls](library-features/never-type-impls.md) @@ -188,7 +183,6 @@ - [rand](library-features/rand.md) - [range_contains](library-features/range-contains.md) - [raw](library-features/raw.md) - - [rc_would_unwrap](library-features/rc-would-unwrap.md) - [retain_hash_collection](library-features/retain-hash-collection.md) - [reverse_cmp_key](library-features/reverse-cmp-key.md) - [rt](library-features/rt.md) @@ -202,11 +196,13 @@ - [slice_rsplit](library-features/slice-rsplit.md) - [sort_internals](library-features/sort-internals.md) - [sort_unstable](library-features/sort-unstable.md) + - [splice](library-features/splice.md) - [step_by](library-features/step-by.md) - [step_trait](library-features/step-trait.md) - [str_checked_slicing](library-features/str-checked-slicing.md) - [str_escape](library-features/str-escape.md) - [str_internals](library-features/str-internals.md) + - [str_box_extras](library-features/str-box-extras.md) - [str_mut_extras](library-features/str-mut-extras.md) - [test](library-features/test.md) - [thread_id](library-features/thread-id.md) @@ -224,5 +220,3 @@ - [windows_handle](library-features/windows-handle.md) - [windows_net](library-features/windows-net.md) - [windows_stdio](library-features/windows-stdio.md) - - [zero_one](library-features/zero-one.md) ->>>>>> Add top level sections to the Unstable Book. diff --git a/src/doc/unstable-book/src/language-features/repr-align.md b/src/doc/unstable-book/src/language-features/repr-align.md new file mode 100644 index 00000000000..deea04f4c51 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/repr-align.md @@ -0,0 +1,11 @@ +# `repr_align` + +The tracking issue for this feature is: [#33626] + +[#33626]: https://github.com/rust-lang/rust/issues/33626 + +------------------------ + + + + diff --git a/src/doc/unstable-book/src/library-features/as-unsafe-cell.md b/src/doc/unstable-book/src/library-features/as-unsafe-cell.md deleted file mode 100644 index 79d7a7cad0b..00000000000 --- a/src/doc/unstable-book/src/library-features/as-unsafe-cell.md +++ /dev/null @@ -1,7 +0,0 @@ -# `as_unsafe_cell` - -The tracking issue for this feature is: [#27708] - -[#27708]: https://github.com/rust-lang/rust/issues/27708 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/binary-heap-extras.md b/src/doc/unstable-book/src/library-features/binary-heap-extras.md deleted file mode 100644 index aa535f3b678..00000000000 --- a/src/doc/unstable-book/src/library-features/binary-heap-extras.md +++ /dev/null @@ -1,7 +0,0 @@ -# `binary_heap_extras` - -The tracking issue for this feature is: [#28147] - -[#28147]: https://github.com/rust-lang/rust/issues/28147 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/borrow-state.md b/src/doc/unstable-book/src/library-features/borrow-state.md deleted file mode 100644 index 304b8dffe98..00000000000 --- a/src/doc/unstable-book/src/library-features/borrow-state.md +++ /dev/null @@ -1,7 +0,0 @@ -# `borrow_state` - -The tracking issue for this feature is: [#27733] - -[#27733]: https://github.com/rust-lang/rust/issues/27733 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/enumset.md b/src/doc/unstable-book/src/library-features/enumset.md deleted file mode 100644 index 24c8d8fa7db..00000000000 --- a/src/doc/unstable-book/src/library-features/enumset.md +++ /dev/null @@ -1,7 +0,0 @@ -# `enumset` - -The tracking issue for this feature is: [#37966] - -[#37966]: https://github.com/rust-lang/rust/issues/37966 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/float-extras.md b/src/doc/unstable-book/src/library-features/float-extras.md deleted file mode 100644 index ff2d20a545f..00000000000 --- a/src/doc/unstable-book/src/library-features/float-extras.md +++ /dev/null @@ -1,7 +0,0 @@ -# `float_extras` - -The tracking issue for this feature is: [#27752] - -[#27752]: https://github.com/rust-lang/rust/issues/27752 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/is-unique.md b/src/doc/unstable-book/src/library-features/is-unique.md deleted file mode 100644 index 6070006758b..00000000000 --- a/src/doc/unstable-book/src/library-features/is-unique.md +++ /dev/null @@ -1,7 +0,0 @@ -# `is_unique` - -The tracking issue for this feature is: [#28356] - -[#28356]: https://github.com/rust-lang/rust/issues/28356 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md b/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md deleted file mode 100644 index 2d15aa0e90d..00000000000 --- a/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md +++ /dev/null @@ -1,5 +0,0 @@ -# `map_entry_recover_keys` - -The tracking issue for this feature is: [#34285] - -[#34285]: https://github.com/rust-lang/rust/issues/34285 diff --git a/src/doc/unstable-book/src/library-features/more-io-inner-methods.md b/src/doc/unstable-book/src/library-features/more-io-inner-methods.md new file mode 100644 index 00000000000..c84f40e7ee5 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/more-io-inner-methods.md @@ -0,0 +1,11 @@ +# `more_io_inner_methods` + +The tracking issue for this feature is: [#41519] + +[#41519]: https://github.com/rust-lang/rust/issues/41519 + +------------------------ + +This feature enables several internal accessor methods on structures in +`std::io` including `Take::{get_ref, get_mut}` and `Chain::{into_inner, get_ref, +get_mut}`. diff --git a/src/doc/unstable-book/src/library-features/rc-would-unwrap.md b/src/doc/unstable-book/src/library-features/rc-would-unwrap.md deleted file mode 100644 index 462387dfdcc..00000000000 --- a/src/doc/unstable-book/src/library-features/rc-would-unwrap.md +++ /dev/null @@ -1,5 +0,0 @@ -# `rc_would_unwrap` - -The tracking issue for this feature is: [#28356] - -[#28356]: https://github.com/rust-lang/rust/issues/28356 diff --git a/src/doc/unstable-book/src/library-features/splice.md b/src/doc/unstable-book/src/library-features/splice.md new file mode 100644 index 00000000000..ca7f78a8f79 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/splice.md @@ -0,0 +1,24 @@ +# `splice` + +The tracking issue for this feature is: [#32310] + +[#32310]: https://github.com/rust-lang/rust/issues/32310 + +------------------------ + +The `splice()` method on `Vec` and `String` allows you to replace a range +of values in a vector or string with another range of values, and returns +the replaced values. + +A simple example: + +```rust +#![feature(splice)] +let mut s = String::from("α is alpha, β is beta"); +let beta_offset = s.find('β').unwrap_or(s.len()); + +// Replace the range up until the β from the string +let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect(); +assert_eq!(t, "α is alpha, "); +assert_eq!(s, "Α is capital alpha; β is beta"); +``` \ No newline at end of file diff --git a/src/doc/unstable-book/src/library-features/str-box-extras.md b/src/doc/unstable-book/src/library-features/str-box-extras.md new file mode 100644 index 00000000000..d05dcafa84d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/str-box-extras.md @@ -0,0 +1,9 @@ +# `str_box_extras` + +The tracking issue for this feature is: [#str_box_extras] + +[#str_box_extras]: https://github.com/rust-lang/rust/issues/41119 + +------------------------ + + diff --git a/src/doc/unstable-book/src/library-features/zero-one.md b/src/doc/unstable-book/src/library-features/zero-one.md deleted file mode 100644 index 4d1cf38c3c2..00000000000 --- a/src/doc/unstable-book/src/library-features/zero-one.md +++ /dev/null @@ -1,7 +0,0 @@ -# `zero_one` - -The tracking issue for this feature is: [#27739] - -[#27739]: https://github.com/rust-lang/rust/issues/27739 - ------------------------- diff --git a/src/etc/rust-gdb b/src/etc/rust-gdb index 520a108da91..52601cd96f8 100755 --- a/src/etc/rust-gdb +++ b/src/etc/rust-gdb @@ -17,7 +17,10 @@ RUSTC_SYSROOT=`rustc --print=sysroot` GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" # Run GDB with the additional arguments that load the pretty printers -PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" gdb \ +# Set the environment variable `RUST_GDB` to overwrite the call to a +# different/specific command (defaults to `gdb`). +RUST_GDB="${RUST_GDB:-gdb}" +PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" ${RUST_GDB} \ -d "$GDB_PYTHON_MODULE_DIRECTORY" \ -iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \ "$@" diff --git a/src/etc/rust-windbg.cmd b/src/etc/rust-windbg.cmd new file mode 100644 index 00000000000..4cdd6b98609 --- /dev/null +++ b/src/etc/rust-windbg.cmd @@ -0,0 +1,18 @@ +@echo off +setlocal + +REM Copyright 2014 The Rust Project Developers. See the COPYRIGHT +REM file at the top-level directory of this distribution and at +REM http://rust-lang.org/COPYRIGHT. +REM +REM Licensed under the Apache License, Version 2.0 or the MIT license +REM , at your +REM option. This file may not be copied, modified, or distributed +REM except according to those terms. + +for /f "delims=" %%i in ('rustc --print=sysroot') do set rustc_sysroot=%%i + +set rust_etc=%rustc_sysroot%\lib\rustlib\etc + +windbg -c ".nvload %rust_etc%\libcore.natvis;.nvload %rust_etc%\libcollections.natvis;" %* \ No newline at end of file diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index 3aa76d168df..c9fcdf7647b 100644 --- a/src/grammar/parser-lalr.y +++ b/src/grammar/parser-lalr.y @@ -89,6 +89,7 @@ extern char *yytext; %token TRAIT %token TYPE %token UNSAFE +%token DEFAULT %token USE %token WHILE %token CONTINUE @@ -534,6 +535,12 @@ maybe_unsafe | %empty { $$ = mk_none(); } ; +maybe_default_maybe_unsafe +: DEFAULT UNSAFE { $$ = mk_atom("DefaultUnsafe"); } +| DEFAULT { $$ = mk_atom("Default"); } +| UNSAFE { $$ = mk_atom("Unsafe"); } +| %empty { $$ = mk_none(); } + trait_method : type_method { $$ = mk_node("Required", 1, $1); } | method { $$ = mk_node("Provided", 1, $1); } @@ -588,27 +595,27 @@ impl_method // they are ambiguous with traits. We do the same here, regrettably, // by splitting ty into ty and ty_prim. item_impl -: maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +: maybe_default_maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8); } -| maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_default_maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10); } -| maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10); } -| maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11); } -| maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' +| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' { $$ = mk_node("ItemImplDefault", 3, $1, $3, $4); } -| maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' +| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' { $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4); } @@ -1935,4 +1942,4 @@ brackets_delimited_token_trees $2, mk_node("TTTok", 1, mk_atom("]"))); } -; +; \ No newline at end of file diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 43b0d72186a..b03e3bb7a4b 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -68,6 +68,7 @@ use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer}; use core::ptr::{self, Unique}; use core::convert::From; +use str::from_boxed_utf8_unchecked; /// A value that represents the heap. This is the default place that the `box` /// keyword allocates into when no place is supplied. @@ -320,8 +321,7 @@ fn default() -> Box<[T]> { #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { - let default: Box<[u8]> = Default::default(); - unsafe { mem::transmute(default) } + unsafe { from_boxed_utf8_unchecked(Default::default()) } } } @@ -366,7 +366,7 @@ fn clone(&self) -> Self { let buf = RawVec::with_capacity(len); unsafe { ptr::copy_nonoverlapping(self.as_ptr(), buf.ptr(), len); - mem::transmute(buf.into_box()) // bytes to str ~magic + from_boxed_utf8_unchecked(buf.into_box()) } } } @@ -441,8 +441,16 @@ fn from(slice: &'a [T]) -> Box<[T]> { #[stable(feature = "box_from_slice", since = "1.17.0")] impl<'a> From<&'a str> for Box { fn from(s: &'a str) -> Box { - let boxed: Box<[u8]> = Box::from(s.as_bytes()); - unsafe { mem::transmute(boxed) } + unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) } + } +} + +#[stable(feature = "boxed_str_conv", since = "1.18.0")] +impl From> for Box<[u8]> { + fn from(s: Box) -> Self { + unsafe { + mem::transmute(s) + } } } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 08a0b2a6d00..056af13016c 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -16,7 +16,6 @@ issue = "27700")] use core::{isize, usize}; -#[cfg(not(test))] use core::intrinsics::{min_align_of_val, size_of_val}; #[allow(improper_ctypes)] @@ -158,10 +157,9 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg(not(test))] -#[lang = "box_free"] +#[cfg_attr(not(test), lang = "box_free")] #[inline] -unsafe fn box_free(ptr: *mut T) { +pub(crate) unsafe fn box_free(ptr: *mut T) { let size = size_of_val(&*ptr); let align = min_align_of_val(&*ptr); // We do not allocate for Box when T is ZST, so deallocation is also not necessary. diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0c01eabd593..fee0e1eb260 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -87,6 +87,7 @@ #![feature(needs_allocator)] #![feature(optin_builtin_traits)] #![feature(placement_in_syntax)] +#![cfg_attr(stage0, feature(pub_restricted))] #![feature(shared)] #![feature(staged_api)] #![feature(unboxed_closures)] @@ -128,6 +129,8 @@ mod boxed { pub mod arc; pub mod rc; pub mod raw_vec; +#[unstable(feature = "str_box_extras", issue = "41119")] +pub mod str; pub mod oom; pub use oom::oom; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index fed718e9be4..38dc9145835 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -239,7 +239,7 @@ use core::ptr::{self, Shared}; use core::convert::From; -use heap::deallocate; +use heap::{allocate, deallocate, box_free}; use raw_vec::RawVec; struct RcBox { @@ -248,7 +248,6 @@ struct RcBox { value: T, } - /// A single-threaded reference-counting pointer. /// /// See the [module-level documentation](./index.html) for more details. @@ -341,19 +340,6 @@ pub fn try_unwrap(this: Self) -> Result { } } - /// Checks whether [`Rc::try_unwrap`][try_unwrap] would return - /// [`Ok`]. - /// - /// [try_unwrap]: struct.Rc.html#method.try_unwrap - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - #[unstable(feature = "rc_would_unwrap", - reason = "just added for niche usecase", - issue = "28356")] - #[rustc_deprecated(since = "1.15.0", reason = "too niche; use `strong_count` instead")] - pub fn would_unwrap(this: &Self) -> bool { - Rc::strong_count(&this) == 1 - } - /// Consumes the `Rc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using @@ -438,6 +424,38 @@ pub fn __from_str(value: &str) -> Rc { } } +impl Rc<[T]> { + /// Constructs a new `Rc<[T]>` from a `Box<[T]>`. + #[doc(hidden)] + #[unstable(feature = "rustc_private", + reason = "for internal use in rustc", + issue = "0")] + pub fn __from_array(value: Box<[T]>) -> Rc<[T]> { + unsafe { + let ptr: *mut RcBox<[T]> = + mem::transmute([mem::align_of::>(), value.len()]); + // 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: *mut RcBox<[T]> = mem::transmute([ptr as usize, value.len()]); + + // Initialize the new RcBox. + ptr::write(&mut (*ptr).strong, Cell::new(1)); + ptr::write(&mut (*ptr).weak, Cell::new(1)); + ptr::copy_nonoverlapping( + value.as_ptr(), + &mut (*ptr).value as *mut [T] as *mut T, + value.len()); + + // Free the original allocation without freeing its (moved) contents. + box_free(Box::into_raw(value)); + + Rc { ptr: Shared::new(ptr as *const _) } + } + } +} + impl Rc { /// Creates a new [`Weak`][weak] pointer to this value. /// @@ -501,11 +519,7 @@ pub fn strong_count(this: &Self) -> usize { /// /// [weak]: struct.Weak.html #[inline] - #[unstable(feature = "is_unique", reason = "uniqueness has unclear meaning", - issue = "28356")] - #[rustc_deprecated(since = "1.15.0", - reason = "too niche; use `strong_count` and `weak_count` instead")] - pub fn is_unique(this: &Self) -> bool { + fn is_unique(this: &Self) -> bool { Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 } diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs new file mode 100644 index 00000000000..c87db16a0f4 --- /dev/null +++ b/src/liballoc/str.rs @@ -0,0 +1,21 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Methods for dealing with boxed strings. +use core::mem; + +use boxed::Box; + +/// Converts a boxed slice of bytes to a boxed string slice without checking +/// that the string contains valid UTF-8. +#[unstable(feature = "str_box_extras", issue = "41119")] +pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { + mem::transmute(v) +} diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 149c285a72a..7d972403f65 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -555,82 +555,6 @@ pub fn push(&mut self, item: T) { self.sift_up(0, old_len); } - /// Pushes an item onto the binary heap, then pops the greatest item off the queue in - /// an optimized fashion. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(binary_heap_extras)] - /// #![allow(deprecated)] - /// - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// heap.push(1); - /// heap.push(5); - /// - /// assert_eq!(heap.push_pop(3), 5); - /// assert_eq!(heap.push_pop(9), 9); - /// assert_eq!(heap.len(), 2); - /// assert_eq!(heap.peek(), Some(&3)); - /// ``` - #[unstable(feature = "binary_heap_extras", - reason = "needs to be audited", - issue = "28147")] - #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")] - pub fn push_pop(&mut self, mut item: T) -> T { - match self.data.get_mut(0) { - None => return item, - Some(top) => { - if *top > item { - swap(&mut item, top); - } else { - return item; - } - } - } - - self.sift_down(0); - item - } - - /// Pops the greatest item off the binary heap, then pushes an item onto the queue in - /// an optimized fashion. The push is done regardless of whether the binary heap - /// was empty. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(binary_heap_extras)] - /// #![allow(deprecated)] - /// - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// - /// assert_eq!(heap.replace(1), None); - /// assert_eq!(heap.replace(3), Some(1)); - /// assert_eq!(heap.len(), 1); - /// assert_eq!(heap.peek(), Some(&3)); - /// ``` - #[unstable(feature = "binary_heap_extras", - reason = "needs to be audited", - issue = "28147")] - #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")] - pub fn replace(&mut self, mut item: T) -> Option { - if !self.is_empty() { - swap(&mut item, &mut self.data[0]); - self.sift_down(0); - Some(item) - } else { - self.push(item); - None - } - } - /// Consumes the `BinaryHeap` and returns the underlying vector /// in arbitrary order. /// @@ -1042,7 +966,7 @@ impl<'a, T> FusedIterator for Iter<'a, T> {} /// An owning iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`] +/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`][`BinaryHeap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.BinaryHeap.html#method.into_iter diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index fb0b852d102..d73c0254a74 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -298,7 +298,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { /// An owning iterator over the entries of a `BTreeMap`. /// -/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`] +/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`][`BTreeMap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.BTreeMap.html#method.into_iter @@ -2217,13 +2217,6 @@ pub fn key(&self) -> &K { self.handle.reborrow().into_kv().0 } - /// Deprecated, renamed to `remove_entry` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] - pub fn remove_pair(self) -> (K, V) { - self.remove_entry() - } - /// Take ownership of the key and value from the map. /// /// # Examples diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index dfff44e30c5..d32460da939 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -97,7 +97,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { /// An owning iterator over the items of a `BTreeSet`. /// -/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`] +/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`][`BTreeSet`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html @@ -138,7 +138,8 @@ pub struct Difference<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Difference<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Difference") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } @@ -160,7 +161,8 @@ pub struct SymmetricDifference<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for SymmetricDifference<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("SymmetricDifference") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } @@ -182,7 +184,8 @@ pub struct Intersection<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Intersection<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Intersection") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } @@ -204,7 +207,8 @@ pub struct Union<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Union<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Union") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs deleted file mode 100644 index ebee75d1a1a..00000000000 --- a/src/libcollections/enum_set.rs +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A structure for holding a set of enum variants. -//! -//! This module defines a container which uses an efficient bit mask -//! representation to hold C-like enum variants. - -#![unstable(feature = "enumset", - reason = "matches collection reform specification, \ - waiting for dust to settle", - issue = "37966")] -#![rustc_deprecated(since = "1.16.0", reason = "long since replaced")] -#![allow(deprecated)] - -use core::marker; -use core::fmt; -use core::iter::{FromIterator, FusedIterator}; -use core::ops::{Sub, BitOr, BitAnd, BitXor}; - -// FIXME(contentions): implement union family of methods? (general design may be -// wrong here) - -/// A specialized set implementation to use enum types. -/// -/// It is a logic error for an item to be modified in such a way that the -/// transformation of the item to or from a `usize`, as determined by the -/// `CLike` trait, changes while the item is in the set. This is normally only -/// possible through `Cell`, `RefCell`, global state, I/O, or unsafe code. -#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct EnumSet { - // We must maintain the invariant that no bits are set - // for which no variant exists - bits: usize, - marker: marker::PhantomData, -} - -impl Copy for EnumSet {} - -impl Clone for EnumSet { - fn clone(&self) -> EnumSet { - *self - } -} - -impl fmt::Debug for EnumSet { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_set().entries(self).finish() - } -} - -/// An interface for casting C-like enum to usize and back. -/// A typically implementation is as below. -/// -/// ```{rust,ignore} -/// #[repr(usize)] -/// enum Foo { -/// A, B, C -/// } -/// -/// impl CLike for Foo { -/// fn to_usize(&self) -> usize { -/// *self as usize -/// } -/// -/// fn from_usize(v: usize) -> Foo { -/// unsafe { mem::transmute(v) } -/// } -/// } -/// ``` -pub trait CLike { - /// Converts a C-like enum to a `usize`. - fn to_usize(&self) -> usize; - /// Converts a `usize` to a C-like enum. - fn from_usize(usize) -> Self; -} - -fn bit(e: &E) -> usize { - use core::mem; - let value = e.to_usize(); - let bits = mem::size_of::() * 8; - assert!(value < bits, - "EnumSet only supports up to {} variants.", - bits - 1); - 1 << value -} - -impl EnumSet { - /// Returns an empty `EnumSet`. - pub fn new() -> EnumSet { - EnumSet { - bits: 0, - marker: marker::PhantomData, - } - } - - /// Returns the number of elements in the given `EnumSet`. - pub fn len(&self) -> usize { - self.bits.count_ones() as usize - } - - /// Returns `true` if the `EnumSet` is empty. - pub fn is_empty(&self) -> bool { - self.bits == 0 - } - - pub fn clear(&mut self) { - self.bits = 0; - } - - /// Returns `false` if the `EnumSet` contains any enum of the given `EnumSet`. - pub fn is_disjoint(&self, other: &EnumSet) -> bool { - (self.bits & other.bits) == 0 - } - - /// Returns `true` if a given `EnumSet` is included in this `EnumSet`. - pub fn is_superset(&self, other: &EnumSet) -> bool { - (self.bits & other.bits) == other.bits - } - - /// Returns `true` if this `EnumSet` is included in the given `EnumSet`. - pub fn is_subset(&self, other: &EnumSet) -> bool { - other.is_superset(self) - } - - /// Returns the union of both `EnumSets`. - pub fn union(&self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits | e.bits, - marker: marker::PhantomData, - } - } - - /// Returns the intersection of both `EnumSets`. - pub fn intersection(&self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & e.bits, - marker: marker::PhantomData, - } - } - - /// Adds an enum to the `EnumSet`, and returns `true` if it wasn't there before - pub fn insert(&mut self, e: E) -> bool { - let result = !self.contains(&e); - self.bits |= bit(&e); - result - } - - /// Removes an enum from the EnumSet - pub fn remove(&mut self, e: &E) -> bool { - let result = self.contains(e); - self.bits &= !bit(e); - result - } - - /// Returns `true` if an `EnumSet` contains a given enum. - pub fn contains(&self, e: &E) -> bool { - (self.bits & bit(e)) != 0 - } - - /// Returns an iterator over an `EnumSet`. - pub fn iter(&self) -> Iter { - Iter::new(self.bits) - } -} - -impl Sub for EnumSet { - type Output = EnumSet; - - fn sub(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & !e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitOr for EnumSet { - type Output = EnumSet; - - fn bitor(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits | e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitAnd for EnumSet { - type Output = EnumSet; - - fn bitand(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitXor for EnumSet { - type Output = EnumSet; - - fn bitxor(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits ^ e.bits, - marker: marker::PhantomData, - } - } -} - -/// An iterator over an `EnumSet` -pub struct Iter { - index: usize, - bits: usize, - marker: marker::PhantomData, -} - -impl fmt::Debug for Iter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Iter") - .field(&self.clone()) - .finish() - } -} - -// FIXME(#19839) Remove in favor of `#[derive(Clone)]` -impl Clone for Iter { - fn clone(&self) -> Iter { - Iter { - index: self.index, - bits: self.bits, - marker: marker::PhantomData, - } - } -} - -impl Iter { - fn new(bits: usize) -> Iter { - Iter { - index: 0, - bits: bits, - marker: marker::PhantomData, - } - } -} - -impl Iterator for Iter { - type Item = E; - - fn next(&mut self) -> Option { - if self.bits == 0 { - return None; - } - - while (self.bits & 1) == 0 { - self.index += 1; - self.bits >>= 1; - } - let elem = CLike::from_usize(self.index); - self.index += 1; - self.bits >>= 1; - Some(elem) - } - - fn size_hint(&self) -> (usize, Option) { - let exact = self.bits.count_ones() as usize; - (exact, Some(exact)) - } -} - -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for Iter {} - -impl FromIterator for EnumSet { - fn from_iter>(iter: I) -> EnumSet { - let mut ret = EnumSet::new(); - ret.extend(iter); - ret - } -} - -impl<'a, E> IntoIterator for &'a EnumSet - where E: CLike -{ - type Item = E; - type IntoIter = Iter; - - fn into_iter(self) -> Iter { - self.iter() - } -} - -impl Extend for EnumSet { - fn extend>(&mut self, iter: I) { - for element in iter { - self.insert(element); - } - } -} - -impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet { - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } -} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 3bea61f6220..842f2f44fff 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -60,6 +60,7 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)] +#![feature(str_box_extras)] #![feature(str_mut_extras)] #![feature(trusted_len)] #![feature(unicode)] @@ -89,9 +90,6 @@ #[doc(no_inline)] pub use linked_list::LinkedList; #[doc(no_inline)] -#[allow(deprecated)] -pub use enum_set::EnumSet; -#[doc(no_inline)] pub use vec_deque::VecDeque; #[doc(no_inline)] pub use string::String; @@ -107,7 +105,6 @@ pub mod binary_heap; mod btree; pub mod borrow; -pub mod enum_set; pub mod fmt; pub mod linked_list; pub mod range; diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index bfb03a5b23f..adfd91bec48 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -75,7 +75,7 @@ pub struct Iter<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Iter") - .field(&self.clone()) + .field(&self.len) .finish() } } @@ -107,14 +107,15 @@ pub struct IterMut<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IterMut") - .field(self.clone()) + .field(&self.list) + .field(&self.len) .finish() } } /// An owning iterator over the elements of a `LinkedList`. /// -/// This `struct` is created by the [`into_iter`] method on [`LinkedList`] +/// This `struct` is created by the [`into_iter`] method on [`LinkedList`][`LinkedList`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.LinkedList.html#method.into_iter @@ -129,7 +130,7 @@ pub struct IntoIter { impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IntoIter") - .field(self.clone()) + .field(&self.list) .finish() } } @@ -1128,7 +1129,7 @@ pub struct FrontPlace<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for FrontPlace<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("FrontPlace") - .field(self.clone()) + .field(&self.list) .finish() } } @@ -1183,7 +1184,7 @@ pub struct BackPlace<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for BackPlace<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("BackPlace") - .field(self.clone()) + .field(&self.list) .finish() } } diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 7c3c825cfd1..2eef132374e 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1519,13 +1519,9 @@ fn to_owned(&self) -> Vec { self.to_vec() } - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec`, which is required for this method - // definition, is not available. Since we don't require this method for testing purposes, I'll - // just stub it - // NB see the slice::hack module in slice.rs for more information #[cfg(test)] fn to_owned(&self) -> Vec { - panic!("not available with cfg(test)") + hack::to_vec(self) } fn clone_into(&self, target: &mut Vec) { diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 8168e02bf82..964660183e7 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -70,14 +70,17 @@ #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{MatchIndices, RMatchIndices}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{from_utf8, Chars, CharIndices, Bytes}; +pub use core::str::{from_utf8, from_utf8_mut, Chars, CharIndices, Bytes}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError}; +#[unstable(feature = "str_box_extras", issue = "41119")] +pub use alloc::str::from_boxed_utf8_unchecked; #[stable(feature = "rust1", since = "1.0.0")] pub use std_unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; + #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", issue = "27747")] @@ -1715,6 +1718,12 @@ pub fn parse(&self) -> Result { core_str::StrExt::parse(self) } + /// Converts a `Box` into a `Box<[u8]>` without copying or allocating. + #[unstable(feature = "str_box_extras", issue = "41119")] + pub fn into_boxed_bytes(self: Box) -> Box<[u8]> { + self.into() + } + /// Replaces all matches of a pattern with another string. /// /// `replace` creates a new [`String`], and copies the data from this string slice into it. diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 8d6cf305112..aa9628c535a 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -56,10 +56,11 @@ #![stable(feature = "rust1", since = "1.0.0")] +use alloc::str as alloc_str; + use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; -use core::mem; use core::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; use core::str as core_str; @@ -1316,7 +1317,7 @@ pub fn clear(&mut self) { self.vec.clear() } - /// Create a draining iterator that removes the specified range in the string + /// Creates a draining iterator that removes the specified range in the string /// and yields the removed chars. /// /// Note: The element range is removed even if the iterator is not @@ -1382,6 +1383,71 @@ pub fn drain(&mut self, range: R) -> Drain } } + /// Creates a splicing iterator that removes the specified range in the string, + /// replaces with the given string, and yields the removed chars. + /// The given string doesn’t need to be the same length as the range. + /// + /// Note: The element range is removed when the `Splice` is dropped, + /// even if the iterator is not consumed until the end. + /// + /// # Panics + /// + /// Panics if the starting point or end point do not lie on a [`char`] + /// boundary, or if they're out of bounds. + /// + /// [`char`]: ../../std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(splice)] + /// let mut s = String::from("α is alpha, β is beta"); + /// let beta_offset = s.find('β').unwrap_or(s.len()); + /// + /// // Replace the range up until the β from the string + /// let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect(); + /// assert_eq!(t, "α is alpha, "); + /// assert_eq!(s, "Α is capital alpha; β is beta"); + /// ``` + #[unstable(feature = "splice", reason = "recently added", issue = "32310")] + pub fn splice<'a, 'b, R>(&'a mut self, range: R, replace_with: &'b str) -> Splice<'a, 'b> + where R: RangeArgument + { + // Memory safety + // + // The String version of Splice does not have the memory safety issues + // of the vector version. The data is just plain bytes. + // Because the range removal happens in Drop, if the Splice iterator is leaked, + // the removal will not happen. + let len = self.len(); + let start = match range.start() { + Included(&n) => n, + Excluded(&n) => n + 1, + Unbounded => 0, + }; + let end = match range.end() { + Included(&n) => n + 1, + Excluded(&n) => n, + Unbounded => len, + }; + + // Take out two simultaneous borrows. The &mut String won't be accessed + // until iteration is over, in Drop. + let self_ptr = self as *mut _; + // slicing does the appropriate bounds checks + let chars_iter = self[start..end].chars(); + + Splice { + start: start, + end: end, + iter: chars_iter, + string: self_ptr, + replace_with: replace_with + } + } + /// Converts this `String` into a `Box`. /// /// This will drop any excess capacity. @@ -1398,7 +1464,7 @@ pub fn drain(&mut self, range: R) -> Drain #[stable(feature = "box_str", since = "1.4.0")] pub fn into_boxed_str(self) -> Box { let slice = self.vec.into_boxed_slice(); - unsafe { mem::transmute::, Box>(slice) } + unsafe { alloc_str::from_boxed_utf8_unchecked(slice) } } } @@ -2145,3 +2211,61 @@ fn next_back(&mut self) -> Option { #[unstable(feature = "fused", issue = "35602")] impl<'a> FusedIterator for Drain<'a> {} + +/// A splicing iterator for `String`. +/// +/// This struct is created by the [`splice()`] method on [`String`]. See its +/// documentation for more. +/// +/// [`splice()`]: struct.String.html#method.splice +/// [`String`]: struct.String.html +#[derive(Debug)] +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +pub struct Splice<'a, 'b> { + /// Will be used as &'a mut String in the destructor + string: *mut String, + /// Start of part to remove + start: usize, + /// End of part to remove + end: usize, + /// Current remaining range to remove + iter: Chars<'a>, + replace_with: &'b str, +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +unsafe impl<'a, 'b> Sync for Splice<'a, 'b> {} +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +unsafe impl<'a, 'b> Send for Splice<'a, 'b> {} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, 'b> Drop for Splice<'a, 'b> { + fn drop(&mut self) { + unsafe { + let vec = (*self.string).as_mut_vec(); + vec.splice(self.start..self.end, self.replace_with.bytes()); + } + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, 'b> Iterator for Splice<'a, 'b> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, 'b> DoubleEndedIterator for Splice<'a, 'b> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} diff --git a/src/libcollections/tests/binary_heap.rs b/src/libcollections/tests/binary_heap.rs index d284937a9e6..af18cddaddb 100644 --- a/src/libcollections/tests/binary_heap.rs +++ b/src/libcollections/tests/binary_heap.rs @@ -152,36 +152,6 @@ fn test_push_unique() { assert!(*heap.peek().unwrap() == box 103); } -#[test] -#[allow(deprecated)] -fn test_push_pop() { - let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(6), 6); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(0), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(4), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(1), 4); - assert_eq!(heap.len(), 5); -} - -#[test] -#[allow(deprecated)] -fn test_replace() { - let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(6).unwrap(), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(0).unwrap(), 6); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(4).unwrap(), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(1).unwrap(), 4); - assert_eq!(heap.len(), 5); -} - fn check_to_vec(mut data: Vec) { let heap = BinaryHeap::from(data.clone()); let mut v = heap.clone().into_vec(); @@ -227,13 +197,6 @@ fn test_empty_peek_mut() { assert!(empty.peek_mut().is_none()); } -#[test] -#[allow(deprecated)] -fn test_empty_replace() { - let mut heap = BinaryHeap::new(); - assert!(heap.replace(5).is_none()); -} - #[test] fn test_from_iter() { let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1]; diff --git a/src/libcollections/tests/lib.rs b/src/libcollections/tests/lib.rs index 618eb386c0f..eae3bf3915f 100644 --- a/src/libcollections/tests/lib.rs +++ b/src/libcollections/tests/lib.rs @@ -10,7 +10,6 @@ #![deny(warnings)] -#![feature(binary_heap_extras)] #![feature(binary_heap_peek_mut_pop)] #![feature(box_syntax)] #![feature(inclusive_range_syntax)] @@ -21,6 +20,7 @@ #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(rand)] +#![feature(splice)] #![feature(step_by)] #![feature(str_escape)] #![feature(test)] diff --git a/src/libcollections/tests/string.rs b/src/libcollections/tests/string.rs index 2f021b9935d..b1731b2a5dc 100644 --- a/src/libcollections/tests/string.rs +++ b/src/libcollections/tests/string.rs @@ -419,6 +419,69 @@ fn test_drain() { assert_eq!(t, ""); } +#[test] +fn test_splice() { + let mut s = "Hello, world!".to_owned(); + let t: String = s.splice(7..12, "世界").collect(); + assert_eq!(s, "Hello, 世界!"); + assert_eq!(t, "world"); +} + +#[test] +#[should_panic] +fn test_splice_char_boundary() { + let mut s = "Hello, 世界!".to_owned(); + s.splice(..8, ""); +} + +#[test] +fn test_splice_inclusive_range() { + let mut v = String::from("12345"); + let t: String = v.splice(2...3, "789").collect(); + assert_eq!(v, "127895"); + assert_eq!(t, "34"); + let t2: String = v.splice(1...2, "A").collect(); + assert_eq!(v, "1A895"); + assert_eq!(t2, "27"); +} + +#[test] +#[should_panic] +fn test_splice_out_of_bounds() { + let mut s = String::from("12345"); + s.splice(5..6, "789"); +} + +#[test] +#[should_panic] +fn test_splice_inclusive_out_of_bounds() { + let mut s = String::from("12345"); + s.splice(5...5, "789"); +} + +#[test] +fn test_splice_empty() { + let mut s = String::from("12345"); + let t: String = s.splice(1..2, "").collect(); + assert_eq!(s, "1345"); + assert_eq!(t, "2"); +} + +#[test] +fn test_splice_unbounded() { + let mut s = String::from("12345"); + let t: String = s.splice(.., "").collect(); + assert_eq!(s, ""); + assert_eq!(t, "12345"); +} + +#[test] +fn test_splice_forget() { + let mut s = String::from("12345"); + ::std::mem::forget(s.splice(2..4, "789")); + assert_eq!(s, "12345"); +} + #[test] fn test_extend_ref() { let mut a = "foo".to_string(); diff --git a/src/libcollections/tests/vec.rs b/src/libcollections/tests/vec.rs index 64c76142b59..29f18274962 100644 --- a/src/libcollections/tests/vec.rs +++ b/src/libcollections/tests/vec.rs @@ -579,6 +579,69 @@ fn test_drain_inclusive_out_of_bounds() { v.drain(5...5); } +#[test] +fn test_splice() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(2..4, a.iter().cloned()); + assert_eq!(v, &[1, 2, 10, 11, 12, 5]); + v.splice(1..3, Some(20)); + assert_eq!(v, &[1, 20, 11, 12, 5]); +} + +#[test] +fn test_splice_inclusive_range() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + let t1: Vec<_> = v.splice(2...3, a.iter().cloned()).collect(); + assert_eq!(v, &[1, 2, 10, 11, 12, 5]); + assert_eq!(t1, &[3, 4]); + let t2: Vec<_> = v.splice(1...2, Some(20)).collect(); + assert_eq!(v, &[1, 20, 11, 12, 5]); + assert_eq!(t2, &[2, 10]); +} + +#[test] +#[should_panic] +fn test_splice_out_of_bounds() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(5..6, a.iter().cloned()); +} + +#[test] +#[should_panic] +fn test_splice_inclusive_out_of_bounds() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(5...5, a.iter().cloned()); +} + +#[test] +fn test_splice_items_zero_sized() { + let mut vec = vec![(), (), ()]; + let vec2 = vec![]; + let t: Vec<_> = vec.splice(1..2, vec2.iter().cloned()).collect(); + assert_eq!(vec, &[(), ()]); + assert_eq!(t, &[()]); +} + +#[test] +fn test_splice_unbounded() { + let mut vec = vec![1, 2, 3, 4, 5]; + let t: Vec<_> = vec.splice(.., None).collect(); + assert_eq!(vec, &[]); + assert_eq!(t, &[1, 2, 3, 4, 5]); +} + +#[test] +fn test_splice_forget() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + ::std::mem::forget(v.splice(2..4, a.iter().cloned())); + assert_eq!(v, &[1, 2]); +} + #[test] fn test_into_boxed_slice() { let xs = vec![1, 2, 3]; diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 6deb87ae772..fc5de70e983 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -275,7 +275,9 @@ /// removed data to be erased for security purposes. Even if you drop a `Vec`, its /// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory /// first, that may not actually happen because the optimizer does not consider -/// this a side-effect that must be preserved. +/// this a side-effect that must be preserved. There is one case which we will +/// not break, however: using `unsafe` code to write to the excess capacity, +/// and then increasing the length to match, is always valid. /// /// `Vec` does not currently guarantee the order in which elements are dropped /// (the order has changed in the past, and may change again). @@ -1057,13 +1059,13 @@ unsafe fn append_elements(&mut self, other: *const [T]) { self.len += count; } - /// Create a draining iterator that removes the specified range in the vector + /// Creates a draining iterator that removes the specified range in the vector /// and yields the removed items. /// /// Note 1: The element range is removed even if the iterator is only /// partially consumed or not consumed at all. /// - /// Note 2: It is unspecified how many elements are removed from the vector, + /// Note 2: It is unspecified how many elements are removed from the vector /// if the `Drain` value is leaked. /// /// # Panics @@ -1147,7 +1149,8 @@ pub fn clear(&mut self) { self.truncate(0) } - /// Returns the number of elements in the vector. + /// Returns the number of elements in the vector, also referred to + /// as its 'length'. /// /// # Examples /// @@ -1845,6 +1848,54 @@ fn extend_desugared>(&mut self, mut iterator: I) { } } } + + /// Creates a splicing iterator that replaces the specified range in the vector + /// with the given `replace_with` iterator and yields the removed items. + /// `replace_with` does not need to be the same length as `range`. + /// + /// Note 1: The element range is removed even if the iterator is not + /// consumed until the end. + /// + /// Note 2: It is unspecified how many elements are removed from the vector, + /// if the `Splice` value is leaked. + /// + /// Note 3: The input iterator `replace_with` is only consumed + /// when the `Splice` value is dropped. + /// + /// Note 4: This is optimal if: + /// + /// * The tail (elements in the vector after `range`) is empty, + /// * or `replace_with` yields fewer elements than `range`’s length + /// * or the lower bound of its `size_hint()` is exact. + /// + /// Otherwise, a temporary vector is allocated and the tail is moved twice. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// #![feature(splice)] + /// let mut v = vec![1, 2, 3]; + /// let new = [7, 8]; + /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect(); + /// assert_eq!(v, &[7, 8, 3]); + /// assert_eq!(u, &[1, 2]); + /// ``` + #[inline] + #[unstable(feature = "splice", reason = "recently added", issue = "32310")] + pub fn splice(&mut self, range: R, replace_with: I) -> Splice + where R: RangeArgument, I: IntoIterator + { + Splice { + drain: self.drain(range), + replace_with: replace_with.into_iter(), + } + } + } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -1984,6 +2035,18 @@ fn from(s: &'a [T]) -> Vec { } } +#[stable(feature = "vec_from_mut", since = "1.21.0")] +impl<'a, T: Clone> From<&'a mut [T]> for Vec { + #[cfg(not(test))] + fn from(s: &'a mut [T]) -> Vec { + s.to_vec() + } + #[cfg(test)] + fn from(s: &'a mut [T]) -> Vec { + ::slice::to_vec(s) + } +} + #[stable(feature = "vec_from_cow_slice", since = "1.14.0")] impl<'a, T> From> for Vec where [T]: ToOwned> { fn from(s: Cow<'a, [T]>) -> Vec { @@ -2344,3 +2407,125 @@ unsafe fn finalize(mut self) -> &'a mut T { &mut *ptr } } + + +/// A splicing iterator for `Vec`. +/// +/// This struct is created by the [`splice()`] method on [`Vec`]. See its +/// documentation for more. +/// +/// [`splice()`]: struct.Vec.html#method.splice +/// [`Vec`]: struct.Vec.html +#[derive(Debug)] +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +pub struct Splice<'a, I: Iterator + 'a> { + drain: Drain<'a, I::Item>, + replace_with: I, +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> Iterator for Splice<'a, I> { + type Item = I::Item; + + fn next(&mut self) -> Option { + self.drain.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.drain.size_hint() + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> DoubleEndedIterator for Splice<'a, I> { + fn next_back(&mut self) -> Option { + self.drain.next_back() + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> ExactSizeIterator for Splice<'a, I> {} + + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> Drop for Splice<'a, I> { + fn drop(&mut self) { + // exhaust drain first + while let Some(_) = self.drain.next() {} + + + unsafe { + if self.drain.tail_len == 0 { + let vec = &mut *self.drain.vec.as_mut_ptr(); + vec.extend(self.replace_with.by_ref()); + return + } + + // First fill the range left by drain(). + if !self.drain.fill(&mut self.replace_with) { + return + } + + // There may be more elements. Use the lower bound as an estimate. + // FIXME: Is the upper bound a better guess? Or something else? + let (lower_bound, _upper_bound) = self.replace_with.size_hint(); + if lower_bound > 0 { + self.drain.move_tail(lower_bound); + if !self.drain.fill(&mut self.replace_with) { + return + } + } + + // Collect any remaining elements. + // This is a zero-length vector which does not allocate if `lower_bound` was exact. + let mut collected = self.replace_with.by_ref().collect::>().into_iter(); + // Now we have an exact count. + if collected.len() > 0 { + self.drain.move_tail(collected.len()); + let filled = self.drain.fill(&mut collected); + debug_assert!(filled); + debug_assert_eq!(collected.len(), 0); + } + } + // Let `Drain::drop` move the tail back if necessary and restore `vec.len`. + } +} + +/// Private helper methods for `Splice::drop` +impl<'a, T> Drain<'a, T> { + /// The range from `self.vec.len` to `self.tail_start` contains elements + /// that have been moved out. + /// Fill that range as much as possible with new elements from the `replace_with` iterator. + /// Return whether we filled the entire range. (`replace_with.next()` didn’t return `None`.) + unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { + let vec = &mut *self.vec.as_mut_ptr(); + let range_start = vec.len; + let range_end = self.tail_start; + let range_slice = slice::from_raw_parts_mut( + vec.as_mut_ptr().offset(range_start as isize), + range_end - range_start); + + for place in range_slice { + if let Some(new_item) = replace_with.next() { + ptr::write(place, new_item); + vec.len += 1; + } else { + return false + } + } + true + } + + /// Make room for inserting more elements before the tail. + unsafe fn move_tail(&mut self, extra_capacity: usize) { + let vec = &mut *self.vec.as_mut_ptr(); + let used_capacity = self.tail_start + self.tail_len; + vec.buf.reserve(used_capacity, extra_capacity); + + let new_tail_start = self.tail_start + extra_capacity; + let src = vec.as_ptr().offset(self.tail_start as isize); + let dst = vec.as_mut_ptr().offset(new_tail_start as isize); + ptr::copy(src, dst, self.tail_len); + self.tail_start = new_tail_start; + } +} diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 2a73a78adbe..079d3acf376 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -1913,7 +1913,9 @@ pub struct Iter<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Iter") - .field(&self.clone()) + .field(&self.ring) + .field(&self.tail) + .field(&self.head) .finish() } } @@ -2000,7 +2002,9 @@ pub struct IterMut<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IterMut") - .field(&self.clone()) + .field(&self.ring) + .field(&self.tail) + .field(&self.head) .finish() } } @@ -2066,7 +2070,7 @@ impl<'a, T> FusedIterator for IterMut<'a, T> {} /// An owning iterator over the elements of a `VecDeque`. /// -/// This `struct` is created by the [`into_iter`] method on [`VecDeque`] +/// This `struct` is created by the [`into_iter`] method on [`VecDeque`][`VecDeque`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.VecDeque.html#method.into_iter @@ -2081,7 +2085,7 @@ pub struct IntoIter { impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IntoIter") - .field(&self.clone()) + .field(&self.inner) .finish() } } @@ -2139,7 +2143,9 @@ pub struct Drain<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Drain") - .field(&self.clone()) + .field(&self.after_tail) + .field(&self.after_head) + .field(&self.iter) .finish() } } diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs index bcd3a92dd43..8fe79057bd8 100644 --- a/src/libcompiler_builtins/build.rs +++ b/src/libcompiler_builtins/build.rs @@ -293,6 +293,12 @@ fn main() { } 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", diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 0186d972782..f62057b3a52 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -310,26 +310,6 @@ pub const fn new(value: T) -> Cell { } } - /// Returns a reference to the underlying `UnsafeCell`. - /// - /// # Examples - /// - /// ``` - /// #![feature(as_unsafe_cell)] - /// - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// let uc = c.as_unsafe_cell(); - /// ``` - #[inline] - #[unstable(feature = "as_unsafe_cell", issue = "27708")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] - pub fn as_unsafe_cell(&self) -> &UnsafeCell { - &self.value - } - /// Returns a raw pointer to the underlying data in this cell. /// /// # Examples @@ -480,20 +460,6 @@ pub struct RefCell { value: UnsafeCell, } -/// An enumeration of values returned from the `state` method on a `RefCell`. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "borrow_state", issue = "27733")] -#[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")] -#[allow(deprecated)] -pub enum BorrowState { - /// The cell is currently being read, there is at least one active `borrow`. - Reading, - /// The cell is currently being written to, there is an active `borrow_mut`. - Writing, - /// There are no outstanding borrows on this cell. - Unused, -} - /// An error returned by [`RefCell::try_borrow`](struct.RefCell.html#method.try_borrow). #[stable(feature = "try_borrow", since = "1.13.0")] pub struct BorrowError { @@ -582,38 +548,6 @@ pub fn into_inner(self) -> T { } impl RefCell { - /// Query the current state of this `RefCell` - /// - /// The returned value can be dispatched on to determine if a call to - /// `borrow` or `borrow_mut` would succeed. - /// - /// # Examples - /// - /// ``` - /// #![feature(borrow_state)] - /// - /// use std::cell::{BorrowState, RefCell}; - /// - /// let c = RefCell::new(5); - /// - /// match c.borrow_state() { - /// BorrowState::Writing => println!("Cannot be borrowed"), - /// BorrowState::Reading => println!("Cannot be borrowed mutably"), - /// BorrowState::Unused => println!("Can be borrowed (mutably as well)"), - /// } - /// ``` - #[unstable(feature = "borrow_state", issue = "27733")] - #[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")] - #[allow(deprecated)] - #[inline] - pub fn borrow_state(&self) -> BorrowState { - match self.borrow.get() { - WRITING => BorrowState::Writing, - UNUSED => BorrowState::Unused, - _ => BorrowState::Reading, - } - } - /// Immutably borrows the wrapped value. /// /// The borrow lasts until the returned `Ref` exits scope. Multiple @@ -769,29 +703,6 @@ pub fn try_borrow_mut(&self) -> Result, BorrowMutError> { } } - /// Returns a reference to the underlying `UnsafeCell`. - /// - /// This can be used to circumvent `RefCell`'s safety checks. - /// - /// This function is `unsafe` because `UnsafeCell`'s field is public. - /// - /// # Examples - /// - /// ``` - /// #![feature(as_unsafe_cell)] - /// - /// use std::cell::RefCell; - /// - /// let c = RefCell::new(5); - /// let c = unsafe { c.as_unsafe_cell() }; - /// ``` - #[inline] - #[unstable(feature = "as_unsafe_cell", issue = "27708")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] - pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell { - &self.value - } - /// Returns a raw pointer to the underlying data in this cell. /// /// # Examples @@ -814,6 +725,15 @@ pub fn as_ptr(&self) -> *mut T { /// This call borrows `RefCell` mutably (at compile-time) so there is no /// need for dynamic checks. /// + /// However be cautious: this method expects `self` to be mutable, which is + /// generally not the case when using a `RefCell`. Take a look at the + /// [`borrow_mut`] method instead if `self` isn't mutable. + /// + /// Also, please be aware that this method is only for special circumstances and is usually + /// not you want. In case of doubt, use [`borrow_mut`] instead. + /// + /// [`borrow_mut`]: #method.borrow_mut + /// /// # Examples /// /// ``` diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 0b0f831f093..084736685e3 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -17,8 +17,8 @@ //! Like many traits, these are often used as bounds for generic functions, to //! support arguments of multiple types. //! -//! - Impl the `As*` traits for reference-to-reference conversions -//! - Impl the [`Into`] trait when you want to consume the value in the conversion +//! - Implement the `As*` traits for reference-to-reference conversions +//! - Implement the [`Into`] trait when you want to consume the value in the conversion //! - The [`From`] trait is the most flexible, useful for value _and_ reference conversions //! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], but allow for the //! conversion to fail @@ -26,16 +26,16 @@ //! As a library author, you should prefer implementing [`From`][`From`] or //! [`TryFrom`][`TryFrom`] rather than [`Into`][`Into`] or [`TryInto`][`TryInto`], //! as [`From`] and [`TryFrom`] provide greater flexibility and offer -//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a blanket implementation -//! in the standard library. +//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a +//! blanket implementation in the standard library. //! -//! # Generic impl +//! # Generic Implementations //! //! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference //! - [`From`]` for T` implies [`Into`]` for U` //! - [`TryFrom`]` for T` implies [`TryInto`]` for U` -//! - [`From`] and [`Into`] are reflexive, which means that all types can `into()` -//! themselves and `from()` themselves +//! - [`From`] and [`Into`] are reflexive, which means that all types can +//! `into` themselves and `from` themselves //! //! See each trait for usage examples. //! @@ -50,20 +50,42 @@ use str::FromStr; -/// A cheap, reference-to-reference conversion. +/// A cheap reference-to-reference conversion. Used to convert a value to a +/// reference value within generic code. /// -/// `AsRef` is very similar to, but different than, [`Borrow`]. See -/// [the book][book] for more. +/// `AsRef` is very similar to, but serves a slightly different purpose than, +/// [`Borrow`]. +/// +/// `AsRef` is to be used when wishing to convert to a reference of another +/// type. +/// `Borrow` is more related to the notion of taking the reference. It is +/// useful when wishing to abstract over the type of reference +/// (`&T`, `&mut T`) or allow both the referenced and owned type to be treated +/// in the same manner. +/// +/// The key difference between the two traits is the intention: +/// +/// - Use `AsRef` when goal is to simply convert into a reference +/// - Use `Borrow` when goal is related to writing code that is agnostic to the +/// type of borrow and if is reference or value +/// +/// See [the book][book] for a more detailed comparison. /// /// [book]: ../../book/borrow-and-asref.html /// [`Borrow`]: ../../std/borrow/trait.Borrow.html /// -/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an [`Option`] or a [`Result`]. +/// **Note: this trait must not fail**. If the conversion can fail, use a +/// dedicated method which returns an [`Option`] or a [`Result`]. /// /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// +/// # Generic Implementations +/// +/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable +/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type +/// `&mut Foo` or `&&mut Foo`) +/// /// # Examples /// /// Both [`String`] and `&str` implement `AsRef`: @@ -82,11 +104,6 @@ /// is_hello(s); /// ``` /// -/// # Generic Impls -/// -/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable -/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`) -/// #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRef { /// Performs the conversion. @@ -96,12 +113,21 @@ pub trait AsRef { /// A cheap, mutable reference-to-mutable reference conversion. /// -/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an [`Option`] or a [`Result`]. +/// This trait is similar to `AsRef` but used for converting between mutable +/// references. +/// +/// **Note: this trait must not fail**. If the conversion can fail, use a +/// dedicated method which returns an [`Option`] or a [`Result`]. /// /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// +/// # Generic Implementations +/// +/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable +/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type +/// `&mut Foo` or `&&mut Foo`) +/// /// # Examples /// /// [`Box`] implements `AsMut`: @@ -118,10 +144,6 @@ pub trait AsRef { /// assert_eq!(*boxed_num, 1); /// ``` /// -/// # Generic Impls -/// -/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable -/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`) /// #[stable(feature = "rust1", since = "1.0.0")] pub trait AsMut { @@ -130,14 +152,22 @@ pub trait AsMut { fn as_mut(&mut self) -> &mut T; } -/// A conversion that consumes `self`, which may or may not be expensive. +/// A conversion that consumes `self`, which may or may not be expensive. The +/// reciprocal of [`From`][From]. +/// +/// **Note: this trait must not fail**. If the conversion can fail, use +/// [`TryInto`] or a dedicated method which returns an [`Option`] or a +/// [`Result`]. /// -/// **Note: this trait must not fail**. If the conversion can fail, use [`TryInto`] or a dedicated -/// method which returns an [`Option`] or a [`Result`]. +/// Library authors should not directly implement this trait, but should prefer +/// implementing the [`From`][From] trait, which offers greater flexibility and +/// provides an equivalent `Into` implementation for free, thanks to a blanket +/// implementation in the standard library. /// -/// Library authors should not directly implement this trait, but should prefer implementing -/// the [`From`][From] trait, which offers greater flexibility and provides an equivalent `Into` -/// implementation for free, thanks to a blanket implementation in the standard library. +/// # Generic Implementations +/// +/// - [`From`][From]` for U` implies `Into for T` +/// - [`into`] is reflexive, which means that `Into for T` is implemented /// /// # Examples /// @@ -153,11 +183,6 @@ pub trait AsMut { /// is_hello(s); /// ``` /// -/// # Generic Impls -/// -/// - [`From`][From]` for U` implies `Into for T` -/// - [`into`] is reflexive, which means that `Into for T` is implemented -/// /// [`TryInto`]: trait.TryInto.html /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html @@ -171,10 +196,31 @@ pub trait Into: Sized { fn into(self) -> T; } -/// Construct `Self` via a conversion. +/// Simple and safe type conversions in to `Self`. It is the reciprocal of +/// `Into`. +/// +/// This trait is useful when performing error handling as described by +/// [the book][book] and is closely related to the `?` operator. +/// +/// When constructing a function that is capable of failing the return type +/// will generally be of the form `Result`. +/// +/// The `From` trait allows for simplification of error handling by providing a +/// means of returning a single error type that encapsulates numerous possible +/// erroneous situations. +/// +/// This trait is not limited to error handling, rather the general case for +/// this trait would be in any type conversions to have an explicit definition +/// of how they are performed. +/// +/// **Note: this trait must not fail**. If the conversion can fail, use +/// [`TryFrom`] or a dedicated method which returns an [`Option`] or a +/// [`Result`]. /// -/// **Note: this trait must not fail**. If the conversion can fail, use [`TryFrom`] or a dedicated -/// method which returns an [`Option`] or a [`Result`]. +/// # Generic Implementations +/// +/// - `From for U` implies [`Into`]` for T` +/// - [`from`] is reflexive, which means that `From for T` is implemented /// /// # Examples /// @@ -186,10 +232,38 @@ pub trait Into: Sized { /// /// assert_eq!(string, other_string); /// ``` -/// # Generic impls /// -/// - `From for U` implies [`Into`]` for T` -/// - [`from`] is reflexive, which means that `From for T` is implemented +/// An example usage for error handling: +/// +/// ``` +/// use std::io::{self, Read}; +/// use std::num; +/// +/// enum CliError { +/// IoError(io::Error), +/// ParseError(num::ParseIntError), +/// } +/// +/// impl From for CliError { +/// fn from(error: io::Error) -> Self { +/// CliError::IoError(error) +/// } +/// } +/// +/// impl From for CliError { +/// fn from(error: num::ParseIntError) -> Self { +/// CliError::ParseError(error) +/// } +/// } +/// +/// fn open_and_parse_file(file_name: &str) -> Result { +/// let mut file = std::fs::File::open("test")?; +/// let mut contents = String::new(); +/// file.read_to_string(&mut contents)?; +/// let num: i32 = contents.trim().parse()?; +/// Ok(num) +/// } +/// ``` /// /// [`TryFrom`]: trait.TryFrom.html /// [`Option`]: ../../std/option/enum.Option.html @@ -197,6 +271,7 @@ pub trait Into: Sized { /// [`String`]: ../../std/string/struct.String.html /// [`Into`]: trait.Into.html /// [`from`]: trait.From.html#tymethod.from +/// [book]: ../../book/error-handling.html #[stable(feature = "rust1", since = "1.0.0")] pub trait From: Sized { /// Performs the conversion. @@ -204,11 +279,13 @@ pub trait From: Sized { fn from(T) -> Self; } -/// An attempted conversion that consumes `self`, which may or may not be expensive. +/// An attempted conversion that consumes `self`, which may or may not be +/// expensive. /// -/// Library authors should not directly implement this trait, but should prefer implementing -/// the [`TryFrom`] trait, which offers greater flexibility and provides an equivalent `TryInto` -/// implementation for free, thanks to a blanket implementation in the standard library. +/// Library authors should not directly implement this trait, but should prefer +/// implementing the [`TryFrom`] trait, which offers greater flexibility and +/// provides an equivalent `TryInto` implementation for free, thanks to a +/// blanket implementation in the standard library. /// /// [`TryFrom`]: trait.TryFrom.html #[unstable(feature = "try_from", issue = "33417")] @@ -236,7 +313,8 @@ pub trait TryFrom: Sized { // As lifts over & #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T where T: AsRef { +impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T where T: AsRef +{ fn as_ref(&self) -> &U { >::as_ref(*self) } @@ -244,7 +322,8 @@ fn as_ref(&self) -> &U { // As lifts over &mut #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef { +impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef +{ fn as_ref(&self) -> &U { >::as_ref(*self) } @@ -260,7 +339,8 @@ fn as_ref(&self) -> &U { // AsMut lifts over &mut #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut { +impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut +{ fn as_mut(&mut self) -> &mut U { (*self).as_mut() } @@ -276,7 +356,8 @@ fn as_mut(&mut self) -> &mut U { // From implies Into #[stable(feature = "rust1", since = "1.0.0")] -impl Into for T where U: From { +impl Into for T where U: From +{ fn into(self) -> U { U::from(self) } @@ -291,7 +372,8 @@ fn from(t: T) -> T { t } // TryFrom implies TryInto #[unstable(feature = "try_from", issue = "33417")] -impl TryInto for T where U: TryFrom { +impl TryInto for T where U: TryFrom +{ type Error = U::Error; fn try_into(self) -> Result { @@ -327,7 +409,8 @@ fn as_ref(&self) -> &str { // FromStr implies TryFrom<&str> #[unstable(feature = "try_from", issue = "33417")] -impl<'a, T> TryFrom<&'a str> for T where T: FromStr { +impl<'a, T> TryFrom<&'a str> for T where T: FromStr +{ type Error = ::Err; fn try_from(s: &'a str) -> Result { diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index a324a4aed25..4ca303dee43 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -15,7 +15,6 @@ // FIXME: #6220 Implement floating point formatting use fmt; -use num::Zero; use ops::{Div, Rem, Sub}; use str; use slice; @@ -23,8 +22,9 @@ use mem; #[doc(hidden)] -trait Int: Zero + PartialEq + PartialOrd + Div + Rem + +trait Int: PartialEq + PartialOrd + Div + Rem + Sub + Copy { + fn zero() -> Self; fn from_u8(u: u8) -> Self; fn to_u8(&self) -> u8; fn to_u16(&self) -> u16; @@ -35,6 +35,7 @@ trait Int: Zero + PartialEq + PartialOrd + Div + Rem + macro_rules! doit { ($($t:ident)*) => ($(impl Int for $t { + fn zero() -> $t { 0 } fn from_u8(u: u8) -> $t { u as $t } fn to_u8(&self) -> u8 { *self as u8 } fn to_u16(&self) -> u16 { *self as u16 } diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 3ad91ef15ea..b3f4d75c4da 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -629,8 +629,9 @@ fn enumerate(self) -> Enumerate where Self: Sized { /// /// Note that the underlying iterator is still advanced when [`peek`] is /// called for the first time: In order to retrieve the next element, - /// [`next`] is called on the underlying iterator, hence any side effects of - /// the [`next`] method will occur. + /// [`next`] is called on the underlying iterator, hence any side effects (i.e. + /// anything other than fetching the next value) of the [`next`] method + /// will occur. /// /// [`peek`]: struct.Peekable.html#method.peek /// [`next`]: ../../std/iter/trait.Iterator.html#tymethod.next diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 687c477f19e..bd831d638c0 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -86,12 +86,12 @@ fn is_negative(&self) -> bool { #[inline] fn replace_one(&mut self) -> Self { - mem::replace(self, 0) + mem::replace(self, 1) } #[inline] fn replace_zero(&mut self) -> Self { - mem::replace(self, 1) + mem::replace(self, 0) } #[inline] @@ -157,12 +157,12 @@ fn is_negative(&self) -> bool { #[inline] fn replace_one(&mut self) -> Self { - mem::replace(self, 0) + mem::replace(self, 1) } #[inline] fn replace_zero(&mut self) -> Self { - mem::replace(self, 1) + mem::replace(self, 0) } #[inline] @@ -206,12 +206,12 @@ fn is_negative(&self) -> bool { #[inline] fn replace_one(&mut self) -> Self { - mem::replace(self, 0) + mem::replace(self, 1) } #[inline] fn replace_zero(&mut self) -> Self { - mem::replace(self, 1) + mem::replace(self, 0) } #[inline] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 393c01b0105..c0aa650a1e8 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -16,6 +16,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use cell::UnsafeCell; use cmp; use hash::Hash; use hash::Hasher; @@ -553,3 +554,19 @@ unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {} } + +/// Compiler-internal trait used to determine whether a type contains +/// any `UnsafeCell` internally, but not through an indirection. +/// This affects, for example, whether a `static` of that type is +/// placed in read-only static memory or writable static memory. +#[cfg_attr(not(stage0), lang = "freeze")] +unsafe trait Freeze {} + +unsafe impl Freeze for .. {} + +impl !Freeze for UnsafeCell {} +unsafe impl Freeze for PhantomData {} +unsafe impl Freeze for *const T {} +unsafe impl Freeze for *mut T {} +unsafe impl<'a, T: ?Sized> Freeze for &'a T {} +unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 1485c79ead2..2a60292d023 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -63,11 +63,8 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp const NAN: Self; const ZERO: Self; - // suffix of "2" because Float::integer_decode is deprecated - #[allow(deprecated)] - fn integer_decode2(self) -> (u64, i16, i8) { - Float::integer_decode(self) - } + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8); /// Get the raw binary representation of the float. fn transmute(self) -> u64; @@ -160,6 +157,21 @@ impl RawFloat for f32 { const ZERO_CUTOFF: i64 = -48; other_constants!(f32); + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8) { + let bits: u32 = unsafe { transmute(self) }; + let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; + let mantissa = if exponent == 0 { + (bits & 0x7fffff) << 1 + } else { + (bits & 0x7fffff) | 0x800000 + }; + // Exponent bias + mantissa shift + exponent -= 127 + 23; + (mantissa as u64, exponent, sign) + } + fn transmute(self) -> u64 { let bits: u32 = unsafe { transmute(self) }; bits as u64 @@ -171,7 +183,7 @@ fn from_bits(bits: u64) -> f32 { } fn unpack(self) -> Unpacked { - let (sig, exp, _sig) = self.integer_decode2(); + let (sig, exp, _sig) = self.integer_decode(); Unpacked::new(sig, exp) } @@ -196,6 +208,21 @@ impl RawFloat for f64 { const ZERO_CUTOFF: i64 = -326; other_constants!(f64); + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8) { + let bits: u64 = unsafe { transmute(self) }; + let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; + let mantissa = if exponent == 0 { + (bits & 0xfffffffffffff) << 1 + } else { + (bits & 0xfffffffffffff) | 0x10000000000000 + }; + // Exponent bias + mantissa shift + exponent -= 1023 + 52; + (mantissa, exponent, sign) + } + fn transmute(self) -> u64 { let bits: u64 = unsafe { transmute(self) }; bits @@ -206,7 +233,7 @@ fn from_bits(bits: u64) -> f64 { } fn unpack(self) -> Unpacked { - let (sig, exp, _sig) = self.integer_decode2(); + let (sig, exp, _sig) = self.integer_decode(); Unpacked::new(sig, exp) } diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 4527d46a27d..91ca213e96e 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -143,36 +143,6 @@ pub mod consts { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] impl Float for f32 { - #[inline] - fn nan() -> f32 { - NAN - } - - #[inline] - fn infinity() -> f32 { - INFINITY - } - - #[inline] - fn neg_infinity() -> f32 { - NEG_INFINITY - } - - #[inline] - fn zero() -> f32 { - 0.0 - } - - #[inline] - fn neg_zero() -> f32 { - -0.0 - } - - #[inline] - fn one() -> f32 { - 1.0 - } - /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { @@ -214,21 +184,6 @@ fn classify(self) -> Fp { } } - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits: u32 = unsafe { mem::transmute(self) }; - let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; - let mantissa = if exponent == 0 { - (bits & 0x7fffff) << 1 - } else { - (bits & 0x7fffff) | 0x800000 - }; - // Exponent bias + mantissa shift - exponent -= 127 + 23; - (mantissa as u64, exponent, sign) - } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[inline] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 991a8568349..7d6d6cef049 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -143,36 +143,6 @@ pub mod consts { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] impl Float for f64 { - #[inline] - fn nan() -> f64 { - NAN - } - - #[inline] - fn infinity() -> f64 { - INFINITY - } - - #[inline] - fn neg_infinity() -> f64 { - NEG_INFINITY - } - - #[inline] - fn zero() -> f64 { - 0.0 - } - - #[inline] - fn neg_zero() -> f64 { - -0.0 - } - - #[inline] - fn one() -> f64 { - 1.0 - } - /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { @@ -214,21 +184,6 @@ fn classify(self) -> Fp { } } - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits: u64 = unsafe { mem::transmute(self) }; - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) - } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[inline] diff --git a/src/libcore/num/flt2dec/decoder.rs b/src/libcore/num/flt2dec/decoder.rs index 72529d3da01..b779eefce57 100644 --- a/src/libcore/num/flt2dec/decoder.rs +++ b/src/libcore/num/flt2dec/decoder.rs @@ -67,7 +67,7 @@ fn min_pos_norm_value() -> Self { f64::MIN_POSITIVE } /// Returns a sign (true when negative) and `FullDecoded` value /// from given floating point number. pub fn decode(v: T) -> (/*negative?*/ bool, FullDecoded) { - let (mant, exp, sign) = v.integer_decode2(); + let (mant, exp, sign) = v.integer_decode(); let even = (mant & 1) == 0; let decoded = match v.classify() { FpCategory::Nan => FullDecoded::Nan, @@ -81,7 +81,7 @@ pub fn decode(v: T) -> (/*negative?*/ bool, FullDecoded) { exp: exp, inclusive: even }) } FpCategory::Normal => { - let minnorm = ::min_pos_norm_value().integer_decode2(); + let minnorm = ::min_pos_norm_value().integer_decode(); if mant == minnorm.0 { // neighbors: (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp) // where maxmant = minnormmant * 2 - 1 diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f665cfdee77..5c4a43fbd11 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -96,78 +96,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { pub mod bignum; pub mod diy_float; -/// Types that have a "zero" value. -/// -/// This trait is intended for use in conjunction with `Add`, as an identity: -/// `x + T::zero() == x`. -#[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] -#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \ - Iterator::sum")] -pub trait Zero: Sized { - /// The "zero" (usually, additive identity) for this type. - fn zero() -> Self; -} - -/// Types that have a "one" value. -/// -/// This trait is intended for use in conjunction with `Mul`, as an identity: -/// `x * T::one() == x`. -#[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] -#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \ - Iterator::product")] -pub trait One: Sized { - /// The "one" (usually, multiplicative identity) for this type. - fn one() -> Self; -} - -macro_rules! zero_one_impl { - ($($t:ty)*) => ($( - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl Zero for $t { - #[inline] - fn zero() -> Self { 0 } - } - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl One for $t { - #[inline] - fn one() -> Self { 1 } - } - )*) -} -zero_one_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } - -macro_rules! zero_one_impl_float { - ($($t:ty)*) => ($( - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl Zero for $t { - #[inline] - fn zero() -> Self { 0.0 } - } - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl One for $t { - #[inline] - fn one() -> Self { 1.0 } - } - )*) -} -zero_one_impl_float! { f32 f64 } - macro_rules! checked_op { ($U:ty, $op:path, $x:expr, $y:expr) => {{ let (result, overflowed) = unsafe { $op($x as $U, $y as $U) }; @@ -2525,49 +2453,6 @@ pub enum FpCategory { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] pub trait Float: Sized { - /// Returns the NaN value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn nan() -> Self; - /// Returns the infinite value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn infinity() -> Self; - /// Returns the negative infinite value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn neg_infinity() -> Self; - /// Returns -0.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn neg_zero() -> Self; - /// Returns 0.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn zero() -> Self; - /// Returns 1.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn one() -> Self; - /// Returns `true` if this value is NaN and false otherwise. #[stable(feature = "core", since = "1.6.0")] fn is_nan(self) -> bool; @@ -2585,14 +2470,6 @@ pub trait Float: Sized { #[stable(feature = "core", since = "1.6.0")] fn classify(self) -> FpCategory; - /// Returns the mantissa, exponent and sign as integers, respectively. - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn integer_decode(self) -> (u64, i16, i8); - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[stable(feature = "core", since = "1.6.0")] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 08442f9bcbf..001fa304cd0 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1082,3 +1082,41 @@ fn test_chain_fold() { assert_eq!(&[2, 3, 1, 2, 0], &result[..]); } +#[test] +fn test_step_replace_unsigned() { + let mut x = 4u32; + let y = x.replace_zero(); + assert_eq!(x, 0); + assert_eq!(y, 4); + + x = 5; + let y = x.replace_one(); + assert_eq!(x, 1); + assert_eq!(y, 5); +} + +#[test] +fn test_step_replace_signed() { + let mut x = 4i32; + let y = x.replace_zero(); + assert_eq!(x, 0); + assert_eq!(y, 4); + + x = 5; + let y = x.replace_one(); + assert_eq!(x, 1); + assert_eq!(y, 5); +} + +#[test] +fn test_step_replace_no_between() { + let mut x = 4u128; + let y = x.replace_zero(); + assert_eq!(x, 0); + assert_eq!(y, 4); + + x = 5; + let y = x.replace_one(); + assert_eq!(x, 1); + assert_eq!(y, 5); +} \ No newline at end of file diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 528ab3bc845..f0c46a6f194 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(fixed_size_array)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(i128_type)] #![feature(iter_rfind)] #![feature(libc)] #![feature(nonzero)] @@ -30,6 +31,7 @@ #![feature(sort_internals)] #![feature(sort_unstable)] #![feature(step_by)] +#![feature(step_trait)] #![feature(test)] #![feature(try_from)] #![feature(unicode)] diff --git a/src/libcore/tests/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs index 1a3533317da..2b0afc40202 100644 --- a/src/libcore/tests/num/dec2flt/rawfp.rs +++ b/src/libcore/tests/num/dec2flt/rawfp.rs @@ -8,23 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::f32; use std::f64; -use std::mem; use core::num::diy_float::Fp; use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal}; +use core::num::dec2flt::rawfp::RawFloat; fn integer_decode(f: f64) -> (u64, i16, i8) { - let bits: u64 = unsafe { mem::transmute(f) }; - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) + RawFloat::integer_decode(f) } #[test] @@ -152,3 +143,35 @@ fn next_float_monotonic() { } assert!(x > 0.5); } + +#[test] +fn test_f32_integer_decode() { + assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); + assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); + assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); + assert_eq!(0f32.integer_decode(), (0, -150, 1)); + assert_eq!((-0f32).integer_decode(), (0, -150, -1)); + assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1)); + assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (12582912, 105)); +} + +#[test] +fn test_f64_integer_decode() { + assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); + assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); + assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); + assert_eq!(0f64.integer_decode(), (0, -1075, 1)); + assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); + assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1)); + assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (6755399441055744, 972)); +} diff --git a/src/liblibc b/src/liblibc index 05a2d197356..c34a802d1eb 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f +Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65 diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 20b322ec189..d234e408a22 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -52,7 +52,7 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Find the tables for this body. let owner_def_id = tcx.hir.local_def_id(tcx.hir.body_owner(body.id())); - let tables = tcx.item_tables(owner_def_id); + let tables = tcx.typeck_tables_of(owner_def_id); let mut cfg_builder = CFGBuilder { tcx: tcx, diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index fd9750dbfe3..33133f6834b 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -88,15 +88,17 @@ pub enum DepNode { // predicates for an item wind up in `ItemSignature`). AssociatedItems(D), ItemSignature(D), + IsForeignItem(D), TypeParamPredicates((D, D)), SizedConstraint(D), + DtorckConstraint(D), AdtDestructor(D), AssociatedItemDefIds(D), InherentImpls(D), TypeckBodiesKrate, TypeckTables(D), UsedTraitImports(D), - MonomorphicConstEval(D), + ConstEval(D), // The set of impls for a given trait. Ultimately, it would be // nice to get more fine-grained here (e.g., to include a @@ -171,6 +173,7 @@ macro_rules! check { TransCrateItem, AssociatedItems, ItemSignature, + IsForeignItem, AssociatedItemDefIds, InherentImpls, TypeckTables, @@ -221,16 +224,18 @@ pub fn map_def(&self, mut op: OP) -> Option> TransInlinedItem(ref d) => op(d).map(TransInlinedItem), AssociatedItems(ref d) => op(d).map(AssociatedItems), ItemSignature(ref d) => op(d).map(ItemSignature), + IsForeignItem(ref d) => op(d).map(IsForeignItem), TypeParamPredicates((ref item, ref param)) => { Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param))))) } SizedConstraint(ref d) => op(d).map(SizedConstraint), + DtorckConstraint(ref d) => op(d).map(DtorckConstraint), AdtDestructor(ref d) => op(d).map(AdtDestructor), AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds), InherentImpls(ref d) => op(d).map(InherentImpls), TypeckTables(ref d) => op(d).map(TypeckTables), UsedTraitImports(ref d) => op(d).map(UsedTraitImports), - MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval), + ConstEval(ref d) => op(d).map(ConstEval), TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), ReprHints(ref d) => op(d).map(ReprHints), diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 618561f3b02..30e9f502abc 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1829,6 +1829,7 @@ extern "C" fn foo(userdata: Box) { E0314, // closure outlives stack frame E0315, // cannot invoke closure outside of its lifetime E0316, // nested quantification of lifetimes + E0320, // recursive overflow during dropck E0473, // dereference of reference outside its lifetime E0474, // captured variable `..` does not outlive the enclosing closure E0475, // index of slice outside its lifetime @@ -1847,5 +1848,6 @@ extern "C" fn foo(userdata: Box) { E0489, // type/lifetime parameter not in scope here E0490, // a value of type `..` is borrowed for too long E0495, // cannot infer an appropriate lifetime due to conflicting requirements - E0566 // conflicting representation hints + E0566, // conflicting representation hints + E0587, // conflicting packed and align representation hints } diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 54ae9472140..bf292ccb8d8 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -57,6 +57,9 @@ fn check_repr(&self, attr: &ast::Attribute, target: Target) { }; let mut conflicting_reprs = 0; + let mut found_packed = false; + let mut found_align = false; + for word in words { let name = match word.name() { @@ -84,6 +87,7 @@ fn check_repr(&self, attr: &ast::Attribute, target: Target) { ("attribute should be applied to struct or union", "a struct or union") } else { + found_packed = true; continue } } @@ -96,6 +100,15 @@ fn check_repr(&self, attr: &ast::Attribute, target: Target) { continue } } + "align" => { + found_align = true; + if target != Target::Struct { + ("attribute should be applied to struct", + "a struct") + } else { + continue + } + } "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "isize" | "usize" => { @@ -117,6 +130,10 @@ fn check_repr(&self, attr: &ast::Attribute, target: Target) { span_warn!(self.sess, attr.span, E0566, "conflicting representation hints"); } + if found_align && found_packed { + struct_span_err!(self.sess, attr.span, E0587, + "conflicting packed and align representation hints").emit(); + } } fn check_attribute(&self, attr: &ast::Attribute, target: Target) { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b7aafa0a9ab..8f4dce5a783 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1326,7 +1326,13 @@ fn lower_item_kind(&mut self, hir::ItemDefaultImpl(self.lower_unsafety(unsafety), trait_ref) } - ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { + ItemKind::Impl(unsafety, + polarity, + defaultness, + ref generics, + ref ifce, + ref ty, + ref impl_items) => { let new_impl_items = impl_items.iter() .map(|item| self.lower_impl_item_ref(item)) .collect(); @@ -1340,6 +1346,7 @@ fn lower_item_kind(&mut self, hir::ItemImpl(self.lower_unsafety(unsafety), self.lower_impl_polarity(polarity), + self.lower_defaultness(defaultness, true /* [1] */), self.lower_generics(generics), ifce, self.lower_ty(ty), @@ -1355,6 +1362,9 @@ fn lower_item_kind(&mut self, } ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } + + // [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to + // not cause an assertion failure inside the `lower_defaultness` function } fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 562b5884440..cb7f530b995 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1712,6 +1712,7 @@ pub enum Item_ { /// An implementation, eg `impl Trait for Foo { .. }` ItemImpl(Unsafety, ImplPolarity, + Defaultness, Generics, Option, // (optional) trait this impl implements P, // self diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 5144f75b1a3..a78d5ce1c16 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -678,12 +678,14 @@ pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> { } hir::ItemImpl(unsafety, polarity, + defaultness, ref generics, ref opt_trait, ref ty, ref impl_items) => { self.head("")?; self.print_visibility(&item.vis)?; + self.print_defaultness(defaultness)?; self.print_unsafety(unsafety)?; self.word_nbsp("impl")?; @@ -820,6 +822,14 @@ pub fn print_visibility(&mut self, vis: &hir::Visibility) -> io::Result<()> { } } + pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> { + match defaultness { + hir::Defaultness::Default { .. } => self.word_nbsp("default")?, + hir::Defaultness::Final => (), + } + Ok(()) + } + pub fn print_struct(&mut self, struct_def: &hir::VariantData, generics: &hir::Generics, @@ -931,11 +941,7 @@ pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> { self.hardbreak_if_not_bol()?; self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - - match ii.defaultness { - hir::Defaultness::Default { .. } => self.word_nbsp("default")?, - hir::Defaultness::Final => (), - } + self.print_defaultness(ii.defaultness)?; match ii.node { hir::ImplItemKind::Const(ref ty, expr) => { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 82e03a9fddc..3aeee1c1b98 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -933,7 +933,7 @@ fn hash_stable(&self, ItemUnion(variant_data, generics), ItemTrait(unsafety, generics, bounds, item_refs), ItemDefaultImpl(unsafety, trait_ref), - ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs) + ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs) }); impl_stable_hash_for!(struct hir::TraitItemRef { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f55462fb5de..16af98c2035 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -273,6 +273,12 @@ fn hash_stable(&self, ConstVal::Bool(value) => { value.hash_stable(hcx, hasher); } + ConstVal::Char(value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Variant(def_id) => { + def_id.hash_stable(hcx, hasher); + } ConstVal::Function(def_id, substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); @@ -296,9 +302,6 @@ fn hash_stable(&self, value.hash_stable(hcx, hasher); times.hash_stable(hcx, hasher); } - ConstVal::Char(value) => { - value.hash_stable(hcx, hasher); - } } } } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 697a1ecadc4..922842136dc 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -99,7 +99,7 @@ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { ty::ReEmpty | ty::ReErased => { // replace all free regions with 'erased - self.tcx().mk_region(ty::ReErased) + self.tcx().types.re_erased } } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 4d8b31a33cd..e75513e924e 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -450,7 +450,7 @@ fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) Option>, Option>) { let item_id = tcx.hir.body_owner(self); - (Some(tcx.item_tables(tcx.hir.local_def_id(item_id))), + (Some(tcx.typeck_tables_of(tcx.hir.local_def_id(item_id))), None, Some(ty::ParameterEnvironment::for_item(tcx, item_id))) } @@ -1237,7 +1237,7 @@ pub fn type_var_for_def(&self, substs: &[Kind<'tcx>]) -> Ty<'tcx> { let default = if def.has_default { - let default = self.tcx.item_type(def.def_id); + let default = self.tcx.type_of(def.def_id); Some(type_variable::Default { ty: default.subst_spanned(self.tcx, substs, Some(span)), origin_span: span, diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 0bb9e2c7fa1..fa6775737b5 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -948,7 +948,7 @@ fn lub_concrete_regions(&self, } else { // otherwise, we don't know what the free region is, // so we must conservatively say the LUB is static: - self.tcx.mk_region(ReStatic) + self.tcx.types.re_static } } @@ -971,7 +971,7 @@ fn lub_concrete_regions(&self, if a == b { a } else { - self.tcx.mk_region(ReStatic) + self.tcx.types.re_static } } } @@ -1018,7 +1018,7 @@ fn infer_variable_values(&self, fn construct_var_data(&self) -> Vec> { (0..self.num_vars() as usize) - .map(|_| Value(self.tcx.mk_region(ty::ReEmpty))) + .map(|_| Value(self.tcx.types.re_empty)) .collect() } @@ -1493,7 +1493,7 @@ fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, -> &'tcx ty::Region { match values[rid.index as usize] { Value(r) => r, - ErrorValue => tcx.mk_region(ReStatic), // Previously reported error. + ErrorValue => tcx.types.re_static, // Previously reported error. } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 20bf241a999..6947e7c3f40 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -43,7 +43,7 @@ use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; -use syntax_pos::{DUMMY_SP, MultiSpan, Span}; +use syntax_pos::{MultiSpan, Span}; use errors::{self, Diagnostic, DiagnosticBuilder}; use hir; use hir::def_id::LOCAL_CRATE; @@ -1234,7 +1234,7 @@ fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore, pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck); - let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let krate = tcx.hir.krate(); diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index b4c5af94019..74026abe64d 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -14,7 +14,7 @@ use hir; use hir::def::Def; use hir::def_id::DefId; -use ty::{self, TyCtxt}; +use ty::TyCtxt; use ty::subst::Substs; use util::common::ErrorReported; use rustc_const_math::*; @@ -38,12 +38,13 @@ pub enum ConstVal<'tcx> { Str(InternedString), ByteStr(Rc>), Bool(bool), + Char(char), + Variant(DefId), Function(DefId, &'tcx Substs<'tcx>), Struct(BTreeMap>), Tuple(Vec>), Array(Vec>), Repeat(Box>, u64), - Char(char), } impl<'tcx> ConstVal<'tcx> { @@ -54,12 +55,13 @@ pub fn description(&self) -> &'static str { Str(_) => "string literal", ByteStr(_) => "byte string literal", Bool(_) => "boolean", + Char(..) => "char", + Variant(_) => "enum variant", Struct(_) => "struct", Tuple(_) => "tuple", Function(..) => "function definition", Array(..) => "array", Repeat(..) => "repeat", - Char(..) => "char", } } @@ -85,7 +87,6 @@ pub enum ErrKind<'tcx> { MissingStructField, NegateOn(ConstVal<'tcx>), NotOn(ConstVal<'tcx>), - CallOn(ConstVal<'tcx>), NonConstPath, UnimplementedConstVal(&'static str), @@ -145,7 +146,6 @@ macro_rules! simple { CannotCast => simple!("can't cast this type"), NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), NotOn(ref const_val) => simple!("not on {}", const_val.description()), - CallOn(ref const_val) => simple!("call on {}", const_val.description()), MissingStructField => simple!("nonexistent struct field"), NonConstPath => simple!("non-constant path in constant expression"), @@ -227,7 +227,8 @@ pub fn eval_length(tcx: TyCtxt, { let count_expr = &tcx.hir.body(count).value; let count_def_id = tcx.hir.body_owner_def_id(count); - match ty::queries::monomorphic_const_eval::get(tcx, count_expr.span, count_def_id) { + let substs = Substs::empty(); + match tcx.at(count_expr.span).const_eval((count_def_id, substs)) { Ok(Integral(Usize(count))) => { let val = count.as_u64(tcx.sess.target.uint_type); assert_eq!(val as usize as u64, val); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index cbbfeacadb4..60171f1a428 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -188,14 +188,14 @@ pub trait CrateStore { fn visibility(&self, def: DefId) -> ty::Visibility; fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap>; fn item_generics_cloned(&self, def: DefId) -> ty::Generics; - fn item_attrs(&self, def_id: DefId) -> Vec; + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>; fn fn_arg_names(&self, did: DefId) -> Vec; // trait info fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity; + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness; fn impl_parent(&self, impl_def_id: DefId) -> Option; // trait/impl-item info @@ -250,8 +250,8 @@ fn retrace_path(&self, fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro; // misc. metadata - fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option<&'tcx hir::Body>; + fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx hir::Body; fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap; fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool; @@ -323,14 +323,14 @@ fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap> { } fn item_generics_cloned(&self, def: DefId) -> ty::Generics { bug!("item_generics_cloned") } - fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { bug!("item_attrs") } fn fn_arg_names(&self, did: DefId) -> Vec { bug!("fn_arg_names") } // trait info fn implementations_of_trait(&self, filter: Option) -> Vec { vec![] } // impl info - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") } + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness { bug!("impl_defaultness") } fn impl_parent(&self, def: DefId) -> Option { bug!("impl_parent") } // trait/impl-item info @@ -401,9 +401,9 @@ fn item_children(&self, did: DefId) -> Vec { bug!("item_children") fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") } // misc. metadata - fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option<&'tcx hir::Body> { - bug!("maybe_get_item_body") + fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx hir::Body { + bug!("item_body") } fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap { bug!("item_body_nested_bodies") diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 63d90d93bb5..0840495ff77 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -26,7 +26,6 @@ use syntax::{ast, codemap}; use syntax::attr; -use syntax::codemap::DUMMY_SP; use syntax_pos; // Any local node that may call something in its body block should be @@ -160,7 +159,7 @@ fn visit_node(&mut self, node: &hir_map::Node<'tcx>) { match item.node { hir::ItemStruct(..) | hir::ItemUnion(..) => { let def_id = self.tcx.hir.local_def_id(item.id); - let def = self.tcx.lookup_adt_def(def_id); + let def = self.tcx.adt_def(def_id); self.struct_has_extern_repr = def.repr.c(); intravisit::walk_item(self, &item); @@ -433,7 +432,7 @@ fn should_warn_about_item(&mut self, item: &hir::Item) -> bool { } fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool { - let field_type = self.tcx.item_type(self.tcx.hir.local_def_id(field.id)); + let field_type = self.tcx.type_of(self.tcx.hir.local_def_id(field.id)); let is_marker_field = match field_type.ty_to_def_id() { Some(def_id) => self.tcx.lang_items.items().iter().any(|item| *item == Some(def_id)), _ => false @@ -593,7 +592,7 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let krate = tcx.hir.krate(); let live_symbols = find_live(tcx, access_levels, krate); let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols }; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a10f52e2d4c..82e7d972c57 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -426,7 +426,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) { hir::ExprMatch(ref discr, ref arms, _) => { let discr_cmt = return_if_err!(self.mc.cat_expr(&discr)); - let r = self.tcx().mk_region(ty::ReEmpty); + let r = self.tcx().types.re_empty; self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant); // treatment of the discriminant is handled while walking the arms. @@ -998,7 +998,7 @@ fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: Mat Def::Variant(variant_did) | Def::VariantCtor(variant_did, ..) => { let enum_did = tcx.parent_def_id(variant_did).unwrap(); - let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() { + let downcast_cmt = if tcx.adt_def(enum_did).is_univariant() { cmt_pat } else { let cmt_pat_ty = cmt_pat.ty; diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index ecc0bb9fe49..435dd05358d 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -66,7 +66,7 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { - let intrinsic = match self.infcx.tcx.item_type(def_id).sty { + let intrinsic = match self.infcx.tcx.type_of(def_id).sty { ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic, _ => return false }; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 5989fa9007c..3b506d748ef 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -223,9 +223,10 @@ pub fn collect(&mut self, krate: &hir::Crate) { pub fn extract(attrs: &[ast::Attribute]) -> Option { for attribute in attrs { - match attribute.value_str() { - Some(value) if attribute.check_name("lang") => return Some(value), - _ => {} + if attribute.check_name("lang") { + if let Some(value) = attribute.value_str() { + return Some(value) + } } } @@ -274,6 +275,7 @@ pub fn collect_language_items(session: &Session, UnsizeTraitLangItem, "unsize", unsize_trait; CopyTraitLangItem, "copy", copy_trait; SyncTraitLangItem, "sync", sync_trait; + FreezeTraitLangItem, "freeze", freeze_trait; DropTraitLangItem, "drop", drop_trait; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index b7da8480c1c..63104678862 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1426,7 +1426,7 @@ fn check_ret(&self, entry_ln: LiveNode, body: &hir::Body) { - let fn_ty = self.ir.tcx.item_type(self.ir.tcx.hir.local_def_id(id)); + let fn_ty = self.ir.tcx.type_of(self.ir.tcx.hir.local_def_id(id)); let fn_sig = match fn_ty.sty { ty::TyClosure(closure_def_id, substs) => { self.ir.tcx.closure_type(closure_def_id) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7d3c17a0489..677eca10d7b 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -871,8 +871,8 @@ pub fn cat_rvalue_node(&self, // we can promote to a constant, otherwise equal to enclosing temp // lifetime. let (re, old_re) = if promotable { - (self.tcx().mk_region(ty::ReStatic), - self.tcx().mk_region(ty::ReStatic)) + (self.tcx().types.re_static, + self.tcx().types.re_static) } else { self.temporary_scope(id) }; @@ -1159,7 +1159,7 @@ fn cat_pattern_(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResul Def::VariantCtor(variant_did, ..) => { // univariant enums do not need downcasts let enum_did = self.tcx().parent_def_id(variant_did).unwrap(); - if !self.tcx().lookup_adt_def(enum_did).is_univariant() { + if !self.tcx().adt_def(enum_did).is_univariant() { self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) } else { cmt @@ -1177,7 +1177,7 @@ fn cat_pattern_(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResul let expected_len = match def { Def::VariantCtor(def_id, CtorKind::Fn) => { let enum_def = self.tcx().parent_def_id(def_id).unwrap(); - self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len() + self.tcx().adt_def(enum_def).variant_with_id(def_id).fields.len() } Def::StructCtor(_, CtorKind::Fn) => { match self.pat_ty(&pat)?.sty { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 63455f94ced..939d7364d9e 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -18,6 +18,7 @@ use hir::map as hir_map; use hir::def::Def; use hir::def_id::{DefId, CrateNum}; +use std::rc::Rc; use ty::{self, TyCtxt}; use ty::maps::Providers; use middle::privacy; @@ -27,7 +28,6 @@ use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::codemap::DUMMY_SP; use hir; use hir::def_id::LOCAL_CRATE; use hir::intravisit::{Visitor, NestedVisitorMap}; @@ -49,7 +49,7 @@ fn item_might_be_inlined(item: &hir::Item) -> bool { } match item.node { - hir::ItemImpl(_, _, ref generics, ..) | + hir::ItemImpl(_, _, _, ref generics, ..) | hir::ItemFn(.., ref generics, _) => { generics_require_inlining(generics) } @@ -185,7 +185,7 @@ fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool { // does too. let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap(); match self.tcx.hir.expect_item(impl_node_id).node { - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { generics_require_inlining(generics) } _ => false @@ -362,14 +362,14 @@ fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { } } -pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { - ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE) +pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { + tcx.reachable_set(LOCAL_CRATE) } -fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet { +fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> Rc { debug_assert!(crate_num == LOCAL_CRATE); - let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || @@ -411,7 +411,7 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> reachable_context.propagate(); // Return the set of reachable symbols. - reachable_context.reachable_symbols + Rc::new(reachable_context.reachable_symbols) } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index a1aabc775a3..a8ba708cc2c 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -331,7 +331,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) | hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { // These kinds of items have only early bound lifetime parameters. let mut index = if let hir::ItemTrait(..) = item.node { 1 // Self comes before lifetimes @@ -834,7 +834,7 @@ fn visit_early_late(&mut self, } match parent.node { hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { index += (generics.lifetimes.len() + generics.ty_params.len()) as u32; } _ => {} diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 1e856f6716e..7431eb3fe96 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -656,7 +656,7 @@ fn lookup_deprecation_uncached(self, id: DefId) -> Option { pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let sess = &tcx.sess; - let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); if tcx.stability.borrow().staged_api[&LOCAL_CRATE] && tcx.sess.features.borrow().staged_api { let krate = tcx.hir.krate(); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9ff64b295b7..724d4f457de 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1015,7 +1015,7 @@ pub fn function_handle<'a>( ) -> Self { Operand::Constant(Constant { span: span, - ty: tcx.item_type(def_id).subst(tcx, substs), + ty: tcx.type_of(def_id).subst(tcx, substs), literal: Literal::Value { value: ConstVal::Function(def_id, substs) }, }) } @@ -1307,10 +1307,11 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { write!(fmt, "b\"{}\"", escaped) } Bool(b) => write!(fmt, "{:?}", b), + Char(c) => write!(fmt, "{:?}", c), + Variant(def_id) | Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Struct(_) | Tuple(_) | Array(_) | Repeat(..) => bug!("ConstVal `{:?}` should not be in MIR", const_val), - Char(c) => write!(fmt, "{:?}", c), } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index f40b9c60537..b6020df0728 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -194,7 +194,7 @@ pub fn ty<'a, 'gcx>(&self, mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<' ) } AggregateKind::Adt(def, _, substs, _) => { - tcx.item_type(def.did).subst(tcx, substs) + tcx.type_of(def.did).subst(tcx, substs) } AggregateKind::Closure(did, substs) => { tcx.mk_closure_from_closure_substs(did, substs) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index fadb1844008..462fd57cbf1 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -51,7 +51,7 @@ pub struct Config { pub uint_type: UintTy, } -#[derive(Clone, Hash)] +#[derive(Clone, Hash, Debug)] pub enum Sanitizer { Address, Leak, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ba340a40692..353677f4f2b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -258,7 +258,7 @@ fn impl_similar_to(&self, let mut self_match_impls = vec![]; let mut fuzzy_match_impls = vec![]; - self.tcx.lookup_trait_def(trait_ref.def_id) + self.tcx.trait_def(trait_ref.def_id) .for_each_relevant_impl(self.tcx, trait_self_ty, |def_id| { let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id); let impl_trait_ref = tcx @@ -314,7 +314,7 @@ fn on_unimplemented_note(&self, let trait_str = self.tcx.item_path_str(trait_ref.def_id); if let Some(istring) = item.value_str() { let istring = &*istring.as_str(); - let generics = self.tcx.item_generics(trait_ref.def_id); + let generics = self.tcx.generics_of(trait_ref.def_id); let generic_map = generics.types.iter().map(|param| { (param.name.as_str().to_string(), trait_ref.substs.type_for_def(param).to_string()) @@ -372,7 +372,7 @@ fn find_similar_impl_candidates(&self, trait_ref.skip_binder().self_ty(), true); let mut impl_candidates = Vec::new(); - let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id()); + let trait_def = self.tcx.trait_def(trait_ref.def_id()); match simp { Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| { diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index d49affa3e87..908bb337fa1 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -443,7 +443,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( // Otherwise, we have something of the form // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`. Some(t_a) => { - let r_static = selcx.tcx().mk_region(ty::ReStatic); + let r_static = selcx.tcx().types.re_static; register_region_obligation(t_a, r_static, obligation.cause.clone(), region_obligations); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 0ff379b30ff..a7f9cc74c4f 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -55,6 +55,7 @@ mod select; mod specialize; mod structural_impls; +pub mod trans; mod util; /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for @@ -628,7 +629,7 @@ pub fn get_vtable_methods<'a, 'tcx>( // the method may have some early-bound lifetimes, add // regions for those let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.mk_region(ty::ReErased), + |_, _| tcx.types.re_erased, |def, _| trait_ref.substs().type_for_def(def)); // the trait type may have higher-ranked lifetimes in it; @@ -640,7 +641,7 @@ pub fn get_vtable_methods<'a, 'tcx>( // do not hold for this particular set of type parameters. // Note that this method could then never be called, so we // do not want to try and trans it, in that case (see #23435). - let predicates = tcx.item_predicates(def_id).instantiate_own(tcx, substs); + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); if !normalize_and_test_predicates(tcx, predicates.predicates) { debug!("get_vtable_methods: predicates do not hold"); return None; diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index d190635bec3..351bde2177c 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -37,6 +37,9 @@ pub enum ObjectSafetyViolation { /// Method has something illegal Method(ast::Name, MethodViolationCode), + + /// Associated const + AssociatedConst(ast::Name), } impl ObjectSafetyViolation { @@ -54,6 +57,8 @@ pub fn error_msg(&self) -> Cow<'static, str> { in its arguments or return type", name).into(), ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => format!("method `{}` has generic type parameters", name).into(), + ObjectSafetyViolation::AssociatedConst(name) => + format!("the trait cannot contain associated consts like `{}`", name).into(), } } } @@ -74,7 +79,7 @@ pub enum MethodViolationCode { impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn is_object_safe(self, trait_def_id: DefId) -> bool { // Because we query yes/no results frequently, we keep a cache: - let def = self.lookup_trait_def(trait_def_id); + let def = self.trait_def(trait_def_id); let result = def.object_safety().unwrap_or_else(|| { let result = self.object_safety_violations(trait_def_id).is_empty(); @@ -141,6 +146,10 @@ fn object_safety_violations_for_trait(self, trait_def_id: DefId) violations.push(ObjectSafetyViolation::SupertraitSelf); } + violations.extend(self.associated_items(trait_def_id) + .filter(|item| item.kind == ty::AssociatedKind::Const) + .map(|item| ObjectSafetyViolation::AssociatedConst(item.name))); + debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", trait_def_id, violations); @@ -158,9 +167,9 @@ fn predicates_reference_self( substs: Substs::identity_for_item(self, trait_def_id) }); let predicates = if supertraits_only { - self.item_super_predicates(trait_def_id) + self.super_predicates_of(trait_def_id) } else { - self.item_predicates(trait_def_id) + self.predicates_of(trait_def_id) }; predicates .predicates @@ -199,7 +208,7 @@ fn generics_require_sized_self(self, def_id: DefId) -> bool { // Search for a predicate like `Self : Sized` amongst the trait bounds. let free_substs = self.construct_free_substs(def_id, self.region_maps.node_extent(ast::DUMMY_NODE_ID)); - let predicates = self.item_predicates(def_id); + let predicates = self.predicates_of(def_id); let predicates = predicates.instantiate(self, free_substs).predicates; elaborate_predicates(self, predicates) .any(|predicate| { @@ -272,7 +281,7 @@ fn virtual_call_violation_for_method(self, // The `Self` type is erased, so it should not appear in list of // arguments or return type apart from the receiver. - let ref sig = self.item_type(method.def_id).fn_sig(); + let ref sig = self.type_of(method.def_id).fn_sig(); for input_ty in &sig.skip_binder().inputs()[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); @@ -283,7 +292,7 @@ fn virtual_call_violation_for_method(self, } // We can't monomorphize things like `fn foo(...)`. - if !self.item_generics(method.def_id).types.is_empty() { + if !self.generics_of(method.def_id).types.is_empty() { return Some(MethodViolationCode::Generic); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 3d8f9e41c67..e01f97eb1f3 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -279,7 +279,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*) // Only normalize `impl Trait` after type-checking, usually in trans. if self.selcx.projection_mode() == Reveal::All { - let generic_ty = self.tcx().item_type(def_id); + let generic_ty = self.tcx().type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.fold_ty(concrete_ty) } else { @@ -787,7 +787,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( }; // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = selcx.tcx().item_predicates(def_id); + let trait_predicates = selcx.tcx().predicates_of(def_id); let bounds = trait_predicates.instantiate(selcx.tcx(), substs); let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates); assemble_candidates_from_predicates(selcx, @@ -923,7 +923,8 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // being invoked). node_item.item.defaultness.has_value() } else { - node_item.item.defaultness.is_default() + node_item.item.defaultness.is_default() || + selcx.tcx().impl_is_default(node_item.node.def_id()) }; // Only reveal a specializable default if we're past type-checking @@ -1288,7 +1289,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( obligation.predicate.trait_ref); tcx.types.err } else { - tcx.item_type(node_item.item.def_id) + tcx.type_of(node_item.item.def_id) }; let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); Progress { @@ -1317,7 +1318,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( -> Option> { let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id; - let trait_def = selcx.tcx().lookup_trait_def(trait_def_id); + let trait_def = selcx.tcx().trait_def(trait_def_id); if !trait_def.is_complete(selcx.tcx()) { let impl_node = specialization_graph::Node::Impl(impl_def_id); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 70ddcff5181..cccc20e5b29 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -842,7 +842,7 @@ fn candidate_from_obligation<'o>(&mut self, fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if let ImplCandidate(def_id) = candidate { - if self.tcx().trait_impl_polarity(def_id) == hir::ImplPolarity::Negative { + if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative { return Err(Unimplemented) } } @@ -943,17 +943,17 @@ fn candidate_from_obligation_no_cache<'o>(&mut self, debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); i += 1; + + // If there are *STILL* multiple candidates, give up + // and report ambiguity. + if i > 1 { + debug!("multiple matches, ambig"); + return Ok(None); + } } } } - // If there are *STILL* multiple candidates, give up and - // report ambiguity. - if candidates.len() > 1 { - debug!("multiple matches, ambig"); - return Ok(None); - } - // If there are *NO* candidates, then there are no impls -- // that we know of, anyway. Note that in the case where there // are unbound type variables within the obligation, it might @@ -1222,8 +1222,8 @@ fn match_projection_obligation_against_definition_bounds( def_id={:?}, substs={:?}", def_id, substs); - let item_predicates = self.tcx().item_predicates(def_id); - let bounds = item_predicates.instantiate(self.tcx(), substs); + let predicates_of = self.tcx().predicates_of(def_id); + let bounds = predicates_of.instantiate(self.tcx(), substs); debug!("match_projection_obligation_against_definition_bounds: \ bounds={:?}", bounds); @@ -1300,8 +1300,13 @@ fn assemble_candidates_from_caller_bounds<'o>(&mut self, .iter() .filter_map(|o| o.to_opt_poly_trait_ref()); + // micro-optimization: filter out predicates relating to different + // traits. + let matching_bounds = + all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); + let matching_bounds = - all_bounds.filter( + matching_bounds.filter( |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply()); let param_candidates = @@ -1427,7 +1432,7 @@ fn assemble_candidates_from_impls(&mut self, { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - let def = self.tcx().lookup_trait_def(obligation.predicate.def_id()); + let def = self.tcx().trait_def(obligation.predicate.def_id()); def.for_each_relevant_impl( self.tcx(), @@ -1790,11 +1795,9 @@ fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>) ty::TyAdt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here - Where(ty::Binder(match sized_crit.sty { - ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs), - ty::TyBool => vec![], - _ => vec![sized_crit.subst(self.tcx(), substs)] - })) + Where(ty::Binder( + sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect() + )) } ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None, @@ -1944,7 +1947,7 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - vec![self.tcx().item_type(def_id).subst(self.tcx(), substs)] + vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)] } } } @@ -2523,7 +2526,7 @@ fn confirm_builtin_unsize_candidate(&mut self, (&ty::TyAdt(def, substs_a), &ty::TyAdt(_, substs_b)) => { let fields = def .all_fields() - .map(|f| tcx.item_type(f.did)) + .map(|f| tcx.type_of(f.did)) .collect::>(); // The last field of the structure has to exist and contain type parameters. @@ -2841,7 +2844,7 @@ fn impl_or_trait_obligations(&mut self, // obligation will normalize to `<$0 as Iterator>::Item = $1` and // `$1: Copy`, so we must ensure the obligations are emitted in // that order. - let predicates = tcx.item_predicates(def_id); + let predicates = tcx.predicates_of(def_id); assert_eq!(predicates.parent, None); let predicates = predicates.predicates.iter().flat_map(|predicate| { let predicate = normalize_with_depth(self, cause.clone(), recursion_depth, diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 5f02688be34..6c685851e25 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -117,7 +117,7 @@ pub fn find_associated_item<'a, 'tcx>( assert!(!substs.needs_infer()); let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); - let trait_def = tcx.lookup_trait_def(trait_def_id); + let trait_def = tcx.trait_def(trait_def_id); let ancestors = trait_def.ancestors(impl_data.impl_def_id); match ancestors.defs(tcx, item.name, item.kind).next() { @@ -175,7 +175,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // See RFC 1210 for more details and justification. // Currently we do not allow e.g. a negative impl to specialize a positive one - if tcx.trait_impl_polarity(impl1_def_id) != tcx.trait_impl_polarity(impl2_def_id) { + if tcx.impl_polarity(impl1_def_id) != tcx.impl_polarity(impl2_def_id) { return false; } diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs new file mode 100644 index 00000000000..e38306aed2a --- /dev/null +++ b/src/librustc/traits/trans/mod.rs @@ -0,0 +1,212 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This file contains various trait resolution methods used by trans. +// They all assume regions can be erased and monomorphic types. It +// seems likely that they should eventually be merged into more +// general routines. + +use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; +use hir::def_id::DefId; +use infer::TransNormalize; +use std::cell::RefCell; +use std::marker::PhantomData; +use syntax::ast; +use syntax_pos::Span; +use traits::{FulfillmentContext, Obligation, ObligationCause, Reveal, SelectionContext, Vtable}; +use ty::{self, Ty, TyCtxt}; +use ty::subst::{Subst, Substs}; +use ty::fold::{TypeFoldable, TypeFolder}; +use util::common::MemoizationMap; + +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Attempts to resolve an obligation to a vtable.. The result is + /// a shallow vtable resolution -- meaning that we do not + /// (necessarily) resolve all nested obligations on the impl. Note + /// that type check should guarantee to us that all nested + /// obligations *could be* resolved if we wanted to. + pub fn trans_fulfill_obligation(self, + span: Span, + trait_ref: ty::PolyTraitRef<'tcx>) + -> Vtable<'tcx, ()> + { + // Remove any references to regions; this helps improve caching. + let trait_ref = self.erase_regions(&trait_ref); + + self.trans_trait_caches.trait_cache.memoize(trait_ref, || { + debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", + trait_ref, trait_ref.def_id()); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + self.infer_ctxt((), Reveal::All).enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::misc(span, + ast::DUMMY_NODE_ID); + let obligation = Obligation::new(obligation_cause, + trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + // Ambiguity can happen when monomorphizing during trans + // expands to some humongo type that never occurred + // statically -- this humongo type can then overflow, + // leading to an ambiguous result. So report this as an + // overflow bug, since I believe this is the only case + // where ambiguity can result. + debug!("Encountered ambiguity selecting `{:?}` during trans, \ + presuming due to overflow", + trait_ref); + self.sess.span_fatal(span, + "reached the recursion limit during monomorphization \ + (selection ambiguity)"); + } + Err(e) => { + span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", + e, trait_ref) + } + }; + + debug!("fulfill_obligation: selection={:?}", selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = FulfillmentContext::new(); + let vtable = selection.map(|predicate| { + debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + vtable + }) + }) + } + + /// Monomorphizes a type from the AST by first applying the in-scope + /// substitutions and then normalizing any associated types. + pub fn trans_apply_param_substs(self, + param_substs: &Substs<'tcx>, + value: &T) + -> T + where T: TransNormalize<'tcx> + { + debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); + let substituted = value.subst(self, param_substs); + let substituted = self.erase_regions(&substituted); + AssociatedTypeNormalizer::new(self).fold(&substituted) + } +} + +struct AssociatedTypeNormalizer<'a, 'gcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'gcx>, +} + +impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> { + fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self { + AssociatedTypeNormalizer { tcx } + } + + fn fold>(&mut self, value: &T) -> T { + if !value.has_projection_types() { + value.clone() + } else { + value.fold_with(self) + } + } +} + +impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { + fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projection_types() { + ty + } else { + self.tcx.trans_trait_caches.project_cache.memoize(ty, || { + debug!("AssociatedTypeNormalizer: ty={:?}", ty); + self.tcx.normalize_associated_type(&ty) + }) + } + } +} + +/// Specializes caches used in trans -- in particular, they assume all +/// types are fully monomorphized and that free regions can be erased. +pub struct TransTraitCaches<'tcx> { + trait_cache: RefCell>>, + project_cache: RefCell>>, +} + +impl<'tcx> TransTraitCaches<'tcx> { + pub fn new(graph: DepGraph) -> Self { + TransTraitCaches { + trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())), + project_cache: RefCell::new(DepTrackingMap::new(graph)), + } + } +} + +// Implement DepTrackingMapConfig for `trait_cache` +pub struct TraitSelectionCache<'tcx> { + data: PhantomData<&'tcx ()> +} + +impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { + type Key = ty::PolyTraitRef<'tcx>; + type Value = Vtable<'tcx, ()>; + fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode { + key.to_poly_trait_predicate().dep_node() + } +} + +// # Global Cache + +pub struct ProjectionCache<'gcx> { + data: PhantomData<&'gcx ()> +} + +impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { + type Key = Ty<'gcx>; + type Value = Ty<'gcx>; + fn to_dep_node(key: &Self::Key) -> DepNode { + // Ideally, we'd just put `key` into the dep-node, but we + // can't put full types in there. So just collect up all the + // def-ids of structs/enums as well as any traits that we + // project out of. It doesn't matter so much what we do here, + // except that if we are too coarse, we'll create overly + // coarse edges between impls and the trans. For example, if + // we just used the def-id of things we are projecting out of, + // then the key for `::T` and `::T` would both share a dep-node + // (`TraitSelect(SomeTrait)`), and hence the impls for both + // `Foo` and `Bar` would be considered inputs. So a change to + // `Bar` would affect things that just normalized `Foo`. + // Anyway, this heuristic is not ideal, but better than + // nothing. + let def_ids: Vec = + key.walk() + .filter_map(|t| match t.sty { + ty::TyAdt(adt_def, _) => Some(adt_def.did), + ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), + _ => None, + }) + .collect(); + + DepNode::ProjectionCache { def_ids: def_ids } + } +} + diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index d4245ec9b24..1d10c3a9695 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -13,6 +13,8 @@ use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; use ty::outlives::Component; use util::nodemap::FxHashSet; +use hir::{self}; +use traits::specialize::specialization_graph::NodeItem; use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; @@ -130,7 +132,7 @@ fn push(&mut self, predicate: &ty::Predicate<'tcx>) { match *predicate { ty::Predicate::Trait(ref data) => { // Predicates declared on the trait. - let predicates = tcx.item_super_predicates(data.def_id()); + let predicates = tcx.super_predicates_of(data.def_id()); let mut predicates: Vec<_> = predicates.predicates @@ -301,7 +303,7 @@ fn next(&mut self) -> Option { None => { return None; } }; - let predicates = self.tcx.item_super_predicates(def_id); + let predicates = self.tcx.super_predicates_of(def_id); let visited = &mut self.visited; self.stack.extend( predicates.predicates @@ -368,7 +370,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); - let predicates = selcx.tcx().item_predicates(impl_def_id); + let predicates = selcx.tcx().predicates_of(impl_def_id); let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let Normalized { value: predicates, obligations: normalization_obligations2 } = super::normalize(selcx, ObligationCause::dummy(), &predicates); @@ -504,6 +506,30 @@ pub fn closure_trait_ref_and_return_type(self, }; ty::Binder((trait_ref, sig.skip_binder().output())) } + + pub fn impl_is_default(self, node_item_def_id: DefId) -> bool { + match self.hir.as_local_node_id(node_item_def_id) { + Some(node_id) => { + let item = self.hir.expect_item(node_id); + if let hir::ItemImpl(_, _, defaultness, ..) = item.node { + defaultness.is_default() + } else { + false + } + } + None => { + self.global_tcx() + .sess + .cstore + .impl_defaultness(node_item_def_id) + .is_default() + } + } + } + + pub fn impl_item_is_final(self, node_item: &NodeItem) -> bool { + node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id()) + } } pub enum TupleArgumentsFlag { Yes, No } diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs deleted file mode 100644 index e1429598291..00000000000 --- a/src/librustc/ty/contents.rs +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use hir::def_id::{DefId}; -use ty::{self, Ty, TyCtxt}; -use util::common::MemoizationMap; -use util::nodemap::FxHashMap; - -use std::fmt; -use std::ops; - -use syntax::ast; - -/// Type contents is how the type checker reasons about kinds. -/// They track what kinds of things are found within a type. You can -/// think of them as kind of an "anti-kind". They track the kinds of values -/// and thinks that are contained in types. Having a larger contents for -/// a type tends to rule that type *out* from various kinds. For example, -/// a type that contains a reference is not sendable. -/// -/// The reason we compute type contents and not kinds is that it is -/// easier for me (nmatsakis) to think about what is contained within -/// a type than to think about what is *not* contained within a type. -#[derive(Clone, Copy)] -pub struct TypeContents { - pub bits: u64 -} - -macro_rules! def_type_content_sets { - (mod $mname:ident { $($name:ident = $bits:expr),+ }) => { - #[allow(non_snake_case)] - mod $mname { - use super::TypeContents; - $( - #[allow(non_upper_case_globals)] - pub const $name: TypeContents = TypeContents { bits: $bits }; - )+ - } - } -} - -def_type_content_sets! { - mod TC { - None = 0b0000_0000__0000_0000__0000, - - // Things that are interior to the value (first nibble): - InteriorUnsafe = 0b0000_0000__0000_0000__0010, - InteriorParam = 0b0000_0000__0000_0000__0100, - // InteriorAll = 0b00000000__00000000__1111, - - // Things that are owned by the value (second and third nibbles): - OwnsDtor = 0b0000_0000__0000_0010__0000, - // OwnsAll = 0b0000_0000__1111_1111__0000, - - // All bits - All = 0b1111_1111__1111_1111__1111 - } -} - -impl TypeContents { - pub fn when(&self, cond: bool) -> TypeContents { - if cond {*self} else {TC::None} - } - - pub fn intersects(&self, tc: TypeContents) -> bool { - (self.bits & tc.bits) != 0 - } - - pub fn interior_param(&self) -> bool { - self.intersects(TC::InteriorParam) - } - - pub fn interior_unsafe(&self) -> bool { - self.intersects(TC::InteriorUnsafe) - } - - pub fn needs_drop(&self, _: TyCtxt) -> bool { - self.intersects(TC::OwnsDtor) - } - - pub fn union(v: I, mut f: F) -> TypeContents where - I: IntoIterator, - F: FnMut(T) -> TypeContents, - { - v.into_iter().fold(TC::None, |tc, ty| tc | f(ty)) - } -} - -impl ops::BitOr for TypeContents { - type Output = TypeContents; - - fn bitor(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits | other.bits} - } -} - -impl ops::BitAnd for TypeContents { - type Output = TypeContents; - - fn bitand(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits & other.bits} - } -} - -impl ops::Sub for TypeContents { - type Output = TypeContents; - - fn sub(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits & !other.bits} - } -} - -impl fmt::Debug for TypeContents { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TypeContents({:b})", self.bits) - } -} - -impl<'a, 'tcx> ty::TyS<'tcx> { - pub fn type_contents(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> TypeContents { - return tcx.tc_cache.memoize(self, || tc_ty(tcx, self, &mut FxHashMap())); - - fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - cache: &mut FxHashMap, TypeContents>) -> TypeContents - { - // Subtle: Note that we are *not* using tcx.tc_cache here but rather a - // private cache for this walk. This is needed in the case of cyclic - // types like: - // - // struct List { next: Box>, ... } - // - // When computing the type contents of such a type, we wind up deeply - // recursing as we go. So when we encounter the recursive reference - // to List, we temporarily use TC::None as its contents. Later we'll - // patch up the cache with the correct value, once we've computed it - // (this is basically a co-inductive process, if that helps). So in - // the end we'll compute TC::OwnsOwned, in this case. - // - // The problem is, as we are doing the computation, we will also - // compute an *intermediate* contents for, e.g., Option of - // TC::None. This is ok during the computation of List itself, but if - // we stored this intermediate value into tcx.tc_cache, then later - // requests for the contents of Option would also yield TC::None - // which is incorrect. This value was computed based on the crutch - // value for the type contents of list. The correct value is - // TC::OwnsOwned. This manifested as issue #4821. - if let Some(tc) = cache.get(&ty) { - return *tc; - } - // Must check both caches! - if let Some(tc) = tcx.tc_cache.borrow().get(&ty) { - return *tc; - } - cache.insert(ty, TC::None); - - let result = match ty.sty { - // usize and isize are ffi-unsafe - ty::TyUint(ast::UintTy::Us) | ty::TyInt(ast::IntTy::Is) => { - TC::None - } - - // Scalar and unique types are sendable, and durable - ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | - ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | - ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => { - TC::None - } - - ty::TyDynamic(..) => { - TC::All - TC::InteriorParam - } - - ty::TyRawPtr(_) => { - TC::None - } - - ty::TyRef(..) => { - TC::None - } - - ty::TyArray(ty, _) => { - tc_ty(tcx, ty, cache) - } - - ty::TySlice(ty) => { - tc_ty(tcx, ty, cache) - } - ty::TyStr => TC::None, - - ty::TyClosure(def_id, ref substs) => { - TypeContents::union( - substs.upvar_tys(def_id, tcx), - |ty| tc_ty(tcx, &ty, cache)) - } - - ty::TyTuple(ref tys, _) => { - TypeContents::union(&tys[..], - |ty| tc_ty(tcx, *ty, cache)) - } - - ty::TyAdt(def, substs) => { - let mut res = - TypeContents::union(&def.variants, |v| { - TypeContents::union(&v.fields, |f| { - tc_ty(tcx, f.ty(tcx, substs), cache) - }) - }); - - if def.is_union() { - // unions don't have destructors regardless of the child types - res = res - TC::OwnsDtor; - } - - if def.has_dtor(tcx) { - res = res | TC::OwnsDtor; - } - - apply_lang_items(tcx, def.did, res) - } - - ty::TyProjection(..) | - ty::TyParam(_) | - ty::TyAnon(..) => { - TC::All - } - - ty::TyInfer(_) | - ty::TyError => { - bug!("asked to compute contents of error type"); - } - }; - - cache.insert(ty, result); - result - } - - fn apply_lang_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId, tc: TypeContents) - -> TypeContents { - if Some(did) == tcx.lang_items.unsafe_cell_type() { - tc | TC::InteriorUnsafe - } else { - tc - } - } - } -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 8b7438c0bfa..ac7a72e6665 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -190,6 +190,10 @@ pub struct CommonTypes<'tcx> { pub f64: Ty<'tcx>, pub never: Ty<'tcx>, pub err: Ty<'tcx>, + + pub re_empty: &'tcx Region, + pub re_static: &'tcx Region, + pub re_erased: &'tcx Region, } #[derive(RustcEncodable, RustcDecodable)] @@ -360,6 +364,14 @@ pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { let mk = |sty| interners.intern_ty(sty, None); + let mk_region = |r| { + if let Some(r) = interners.region.borrow().get(&r) { + return r.0; + } + let r = interners.arena.alloc(r); + interners.region.borrow_mut().insert(Interned(r)); + &*r + }; CommonTypes { bool: mk(TyBool), char: mk(TyChar), @@ -379,6 +391,10 @@ fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { u128: mk(TyUint(ast::UintTy::U128)), f32: mk(TyFloat(ast::FloatTy::F32)), f64: mk(TyFloat(ast::FloatTy::F64)), + + re_empty: mk_region(Region::ReEmpty), + re_static: mk_region(Region::ReStatic), + re_erased: mk_region(Region::ReErased), } } } @@ -407,6 +423,8 @@ pub struct GlobalCtxt<'tcx> { pub specializes_cache: RefCell, + pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>, + pub dep_graph: DepGraph, /// Common types, pre-interned for your convenience. @@ -436,9 +454,6 @@ pub struct GlobalCtxt<'tcx> { // Internal cache for metadata decoding. No need to track deps on this. pub rcache: RefCell>>, - // Cache for the type-contents routine. FIXME -- track deps? - pub tc_cache: RefCell, ty::contents::TypeContents>>, - // FIXME dep tracking -- should be harmless enough pub normalized_cache: RefCell, Ty<'tcx>>>, @@ -692,6 +707,7 @@ pub fn create_and_enter(s: &'tcx Session, providers[LOCAL_CRATE] = local_providers; tls::enter_global(GlobalCtxt { sess: s, + trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()), specializes_cache: RefCell::new(traits::SpecializesCache::new()), global_arenas: arenas, global_interners: interners, @@ -708,7 +724,6 @@ pub fn create_and_enter(s: &'tcx Session, freevars: RefCell::new(resolutions.freevars), maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports, rcache: RefCell::new(FxHashMap()), - tc_cache: RefCell::new(FxHashMap()), normalized_cache: RefCell::new(FxHashMap()), inhabitedness_cache: RefCell::new(FxHashMap()), lang_items: lang_items, @@ -1233,7 +1248,7 @@ pub fn mk_str(self) -> Ty<'tcx> { } pub fn mk_static_str(self) -> Ty<'tcx> { - self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) + self.mk_imm_ref(self.types.re_static, self.mk_str()) } pub fn mk_adt(self, def: &'tcx AdtDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { @@ -1243,7 +1258,7 @@ pub fn mk_adt(self, def: &'tcx AdtDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); - let adt_def = self.lookup_adt_def(def_id); + let adt_def = self.adt_def(def_id); let substs = self.mk_substs(iter::once(Kind::from(ty))); self.mk_ty(TyAdt(adt_def, substs)) } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index e29653c9e88..969d040e7a6 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -410,7 +410,7 @@ fn collect_late_bound_regions(&self, value: &Binder, just_constraint: bool pub fn erase_late_bound_regions(self, value: &Binder) -> T where T : TypeFoldable<'tcx> { - self.replace_late_bound_regions(value, |_| self.mk_region(ty::ReErased)).0 + self.replace_late_bound_regions(value, |_| self.types.re_erased).0 } /// Rewrite any late-bound regions so that they are anonymous. Region numbers are @@ -538,7 +538,7 @@ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { // whenever a substitution occurs. match *r { ty::ReLateBound(..) => r, - _ => self.tcx().mk_region(ty::ReErased) + _ => self.tcx().types.re_erased } } } @@ -565,6 +565,22 @@ pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region { } } +pub fn shift_region_ref<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + region: &'tcx ty::Region, + amount: u32) + -> &'tcx ty::Region +{ + match region { + &ty::ReLateBound(debruijn, br) if amount > 0 => { + tcx.mk_region(ty::ReLateBound(debruijn.shifted(amount), br)) + } + _ => { + region + } + } +} + pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, amount: u32, value: &T) -> T where T: TypeFoldable<'tcx> @@ -573,7 +589,7 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, value, amount); value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { - tcx.mk_region(shift_region(*region, amount)) + shift_region_ref(tcx, region, amount) })) } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 67287f1b4ff..7dca28df9da 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -13,10 +13,7 @@ use ty::{self, Ty, TypeFoldable, Substs}; use util::ppaux; -use std::borrow::Cow; use std::fmt; -use syntax::ast; - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Instance<'tcx> { @@ -55,11 +52,11 @@ pub fn def_id(&self) -> DefId { #[inline] pub fn def_ty<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { - tcx.item_type(self.def_id()) + tcx.type_of(self.def_id()) } #[inline] - pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Cow<'tcx, [ast::Attribute]> { + pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> { tcx.get_attrs(self.def_id()) } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 64dfd2b71b4..eb31dfba4a4 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -206,7 +206,7 @@ fn push_impl_path(self, // for local crates, check whether type info is // available; typeck might not have completed yet self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) && - self.maps.ty.borrow().contains_key(&impl_def_id) + self.maps.type_of.borrow().contains_key(&impl_def_id) }; if !use_types { @@ -218,7 +218,7 @@ fn push_impl_path(self, // users may find it useful. Currently, we omit the parent if // the impl is either in the same module as the self-type or // as the trait. - let self_ty = self.item_type(impl_def_id); + let self_ty = self.type_of(impl_def_id); let in_self_mod = match characteristic_def_id_of_type(self_ty) { None => false, Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index df60eee8c02..49cc4e7c993 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -548,8 +548,12 @@ pub fn align(self, cx: C) -> Align { /// A structure, a product type in ADT terms. #[derive(PartialEq, Eq, Hash, Debug)] pub struct Struct { + /// Maximum alignment of fields and repr alignment. pub align: Align, + /// Primitive alignment of fields without repr alignment. + pub primitive_align: Align, + /// If true, no alignment padding is used. pub packed: bool, @@ -583,10 +587,20 @@ impl<'a, 'gcx, 'tcx> Struct { fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, repr: &ReprOptions, kind: StructKind, scapegoat: Ty<'gcx>) -> Result> { - let packed = repr.packed(); + if repr.packed() && repr.align > 0 { + bug!("Struct cannot be packed and aligned"); + } + + let align = if repr.packed() { + dl.i8_align + } else { + dl.aggregate_align + }; + let mut ret = Struct { - align: if packed { dl.i8_align } else { dl.aggregate_align }, - packed: packed, + align: align, + primitive_align: align, + packed: repr.packed(), sized: true, offsets: vec![], memory_index: vec![], @@ -660,7 +674,9 @@ fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, // Invariant: offset < dl.obj_size_bound() <= 1<<61 if !ret.packed { let align = field.align(dl); + let primitive_align = field.primitive_align(dl); ret.align = ret.align.max(align); + ret.primitive_align = ret.primitive_align.max(primitive_align); offset = offset.abi_align(align); } @@ -671,6 +687,11 @@ fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?; } + if repr.align > 0 { + let repr_align = repr.align as u64; + ret.align = ret.align.max(Align::from_bytes(repr_align, repr_align).unwrap()); + debug!("Struct::new repr_align: {:?}", repr_align); + } debug!("Struct::new min_size: {:?}", offset); ret.min_size = offset; @@ -801,7 +822,7 @@ fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { return Ok(None); } @@ -836,12 +857,23 @@ fn non_zero_field_paths(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } Ok(None) } + + pub fn over_align(&self) -> Option { + let align = self.align.abi(); + let primitive_align = self.primitive_align.abi(); + if align > primitive_align { + Some(align as u32) + } else { + None + } + } } /// An untagged union. #[derive(PartialEq, Eq, Hash, Debug)] pub struct Union { pub align: Align, + pub primitive_align: Align, pub min_size: Size, @@ -851,8 +883,10 @@ pub struct Union { impl<'a, 'gcx, 'tcx> Union { fn new(dl: &TargetDataLayout, packed: bool) -> Union { + let align = if packed { dl.i8_align } else { dl.aggregate_align }; Union { - align: if packed { dl.i8_align } else { dl.aggregate_align }, + align: align, + primitive_align: align, min_size: Size::from_bytes(0), packed: packed, } @@ -875,6 +909,7 @@ fn extend(&mut self, dl: &TargetDataLayout, if !self.packed { self.align = self.align.max(field.align(dl)); + self.primitive_align = self.primitive_align.max(field.primitive_align(dl)); } self.min_size = cmp::max(self.min_size, field.size(dl)); } @@ -888,6 +923,16 @@ fn extend(&mut self, dl: &TargetDataLayout, pub fn stride(&self) -> Size { self.min_size.abi_align(self.align) } + + pub fn over_align(&self) -> Option { + let align = self.align.abi(); + let primitive_align = self.primitive_align.abi(); + if align > primitive_align { + Some(align as u32) + } else { + None + } + } } /// The first half of a fat pointer. @@ -924,6 +969,7 @@ pub enum Layout { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, align: Align, + primitive_align: Align, element_size: Size, count: u64 }, @@ -970,7 +1016,8 @@ pub enum Layout { discr: Integer, variants: Vec, size: Size, - align: Align + align: Align, + primitive_align: Align, }, /// Two cases distinguished by a nullable pointer: the case with discriminant @@ -1020,28 +1067,6 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { } } -/// Helper function for normalizing associated types in an inference context. -fn normalize_associated_type<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'gcx>) - -> Ty<'gcx> { - if !ty.has_projection_types() { - return ty; - } - - let mut selcx = traits::SelectionContext::new(infcx); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { value: result, obligations } = - traits::normalize(&mut selcx, cause, &ty); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(infcx, obligation); - } - - infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) -} - impl<'a, 'gcx, 'tcx> Layout { pub fn compute_uncached(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>) @@ -1053,7 +1078,7 @@ pub fn compute_uncached(ty: Ty<'gcx>, let ptr_layout = |pointee: Ty<'gcx>| { let non_zero = !ty.is_unsafe_ptr(); - let pointee = normalize_associated_type(infcx, pointee); + let pointee = infcx.normalize_projections(pointee); if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) { Ok(Scalar { value: Pointer, non_zero: non_zero }) } else { @@ -1118,6 +1143,7 @@ pub fn compute_uncached(ty: Ty<'gcx>, Array { sized: true, align: element.align(dl), + primitive_align: element.primitive_align(dl), element_size: element_size, count: count } @@ -1127,6 +1153,7 @@ pub fn compute_uncached(ty: Ty<'gcx>, Array { sized: false, align: element.align(dl), + primitive_align: element.primitive_align(dl), element_size: element.size(dl), count: 0 } @@ -1135,6 +1162,7 @@ pub fn compute_uncached(ty: Ty<'gcx>, Array { sized: false, align: dl.i8_align, + primitive_align: dl.i8_align, element_size: Size::from_bytes(1), count: 0 } @@ -1340,6 +1368,7 @@ pub fn compute_uncached(ty: Ty<'gcx>, assert!(discr_max >= 0); let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max); let mut align = dl.aggregate_align; + let mut primitive_align = dl.aggregate_align; let mut size = Size::from_bytes(0); // We're interested in the smallest alignment, so start large. @@ -1369,6 +1398,7 @@ pub fn compute_uncached(ty: Ty<'gcx>, } size = cmp::max(size, st.min_size); align = align.max(st.align); + primitive_align = primitive_align.max(st.primitive_align); Ok(st) }).collect::, _>>()?; @@ -1435,13 +1465,14 @@ pub fn compute_uncached(ty: Ty<'gcx>, discr: ity, variants: variants, size: size, - align: align + align: align, + primitive_align: primitive_align } } // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { return Err(LayoutError::Unknown(ty)); } @@ -1557,6 +1588,30 @@ pub fn align(&self, cx: C) -> Align { } } + /// Returns alignment before repr alignment is applied + pub fn primitive_align(&self, dl: &TargetDataLayout) -> Align { + match *self { + Array { primitive_align, .. } | General { primitive_align, .. } => primitive_align, + Univariant { ref variant, .. } | + StructWrappedNullablePointer { nonnull: ref variant, .. } => { + variant.primitive_align + }, + + _ => self.align(dl) + } + } + + /// Returns repr alignment if it is greater than the primitive alignment. + pub fn over_align(&self, dl: &TargetDataLayout) -> Option { + let align = self.align(dl); + let primitive_align = self.primitive_align(dl); + if align.abi() > primitive_align.abi() { + Some(align.abi() as u32) + } else { + None + } + } + pub fn field_offset(&self, cx: C, i: usize, @@ -1735,7 +1790,7 @@ pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>) } ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { Err(err) } else { @@ -1805,13 +1860,14 @@ pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> { type TyLayout; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout; + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>; } impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { type TyLayout = Result, LayoutError<'gcx>>; fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout { - let ty = normalize_associated_type(self, ty); + let ty = self.normalize_projections(ty); Ok(TyLayout { ty: ty, @@ -1819,6 +1875,25 @@ fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout { variant_index: None }) } + + fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projection_types() { + return ty; + } + + let mut selcx = traits::SelectionContext::new(self); + let cause = traits::ObligationCause::dummy(); + let traits::Normalized { value: result, obligations } = + traits::normalize(&mut selcx, cause, &ty); + + let mut fulfill_cx = traits::FulfillmentContext::new(); + + for obligation in obligations { + fulfill_cx.register_predicate_obligation(self, obligation); + } + + self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) + } } impl<'a, 'tcx> TyLayout<'tcx> { @@ -1942,6 +2017,6 @@ pub fn field_type>(&self, cx: C, i: usize) -> Ty<'tcx> { } pub fn field>(&self, cx: C, i: usize) -> C::TyLayout { - cx.layout_of(self.field_type(cx, i)) + cx.layout_of(cx.normalize_projections(self.field_type(cx, i))) } } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index e9eb5e97582..1407e57dc2a 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -10,15 +10,18 @@ use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use hir; use middle::const_val; use middle::privacy::AccessLevels; use mir; use session::CompileResult; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use ty::subst::Substs; use util::nodemap::NodeSet; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; +use std::ops::Deref; use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; @@ -73,6 +76,15 @@ fn default_span(&self, tcx: TyCtxt) -> Span { } } +impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) { + fn map_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.0.default_span(tcx) + } +} + trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; } @@ -96,6 +108,13 @@ fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { } } + +impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> { + fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + Self::empty() + } +} + pub struct CycleError<'a, 'tcx: 'a> { span: Span, cycle: RefMut<'a, [(Span, Query<'tcx>)]>, @@ -157,7 +176,7 @@ impl> QueryDescription for M { } } -impl<'tcx> QueryDescription for queries::super_predicates<'tcx> { +impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> { fn describe(tcx: TyCtxt, def_id: DefId) -> String { format!("computing the supertraits of `{}`", tcx.item_path_str(def_id)) @@ -216,6 +235,13 @@ fn describe(_: TyCtxt, _: CrateNum) -> String { } } +impl<'tcx> QueryDescription for queries::const_eval<'tcx> { + fn describe(tcx: TyCtxt, (def_id, _): (DefId, &'tcx Substs<'tcx>)) -> String { + format!("const-evaluating `{}`", + tcx.item_path_str(def_id)) + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -304,14 +330,6 @@ pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) Self::try_get_with(tcx, span, key, Clone::clone) } - $(#[$attr])* - pub fn get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) -> $V { - Self::try_get(tcx, span, key).unwrap_or_else(|e| { - tcx.report_cycle(e); - Value::from_cycle_error(tcx.global_tcx()) - }) - } - pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) { // FIXME(eddyb) Move away from using `DepTrackingMap` // so we don't have to explicitly ignore a false edge: @@ -326,6 +344,45 @@ pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) { } })* + #[derive(Copy, Clone)] + pub struct TyCtxtAt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'gcx, 'tcx>, + pub span: Span, + } + + impl<'a, 'gcx, 'tcx> Deref for TyCtxtAt<'a, 'gcx, 'tcx> { + type Target = TyCtxt<'a, 'gcx, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.tcx + } + } + + impl<'a, $tcx, 'lcx> TyCtxt<'a, $tcx, 'lcx> { + /// Return a transparent wrapper for `TyCtxt` which uses + /// `span` as the location of queries performed through it. + pub fn at(self, span: Span) -> TyCtxtAt<'a, $tcx, 'lcx> { + TyCtxtAt { + tcx: self, + span + } + } + + $($(#[$attr])* + pub fn $name(self, key: $K) -> $V { + self.at(DUMMY_SP).$name(key) + })* + } + + impl<'a, $tcx, 'lcx> TyCtxtAt<'a, $tcx, 'lcx> { + $($(#[$attr])* + pub fn $name(self, key: $K) -> $V { + queries::$name::try_get(self.tcx, self.span, key).unwrap_or_else(|e| { + self.report_cycle(e); + Value::from_cycle_error(self.global_tcx()) + }) + })* + } + pub struct Providers<$tcx> { $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $V),* } @@ -355,12 +412,12 @@ fn default() -> Self { // the driver creates (using several `rustc_*` crates). define_maps! { <'tcx> /// Records the type of every item. - pub ty: ItemSignature(DefId) -> Ty<'tcx>, + pub type_of: ItemSignature(DefId) -> Ty<'tcx>, /// Maps from the def-id of an item (trait/struct/enum/fn) to its /// associated generics and predicates. - pub generics: ItemSignature(DefId) -> &'tcx ty::Generics, - pub predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, + pub generics_of: ItemSignature(DefId) -> &'tcx ty::Generics, + pub predicates_of: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, /// Maps from the def-id of a trait to the list of /// super-predicates. This is a subset of the full list of @@ -368,7 +425,7 @@ fn default() -> Self { /// evaluate them even during type conversion, often before the /// full predicates are available (note that supertraits have /// additional acyclicity requirements). - pub super_predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, + pub super_predicates_of: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. @@ -378,11 +435,15 @@ fn default() -> Self { pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef, pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef, pub adt_destructor: AdtDestructor(DefId) -> Option, - pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>, + pub adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], + pub adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>, + + /// True if this is a foreign item (i.e., linked via `extern { ... }`). + pub is_foreign_item: IsForeignItem(DefId) -> bool, /// Maps from def-id of a type or region parameter to its /// (inferred) variance. - pub variances: ItemSignature(DefId) -> Rc>, + pub variances_of: ItemSignature(DefId) -> Rc>, /// Maps from an impl/trait def-id to a list of the def-ids of its items pub associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc>, @@ -391,6 +452,7 @@ fn default() -> Self { pub associated_item: AssociatedItems(DefId) -> ty::AssociatedItem, pub impl_trait_ref: ItemSignature(DefId) -> Option>, + pub impl_polarity: ItemSignature(DefId) -> hir::ImplPolarity, /// Maps a DefId of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. @@ -425,7 +487,7 @@ fn default() -> Self { pub typeck_item_bodies: typeck_item_bodies_dep_node(CrateNum) -> CompileResult, - pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, + pub typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (), @@ -441,16 +503,17 @@ fn default() -> Self { /// (Defined only for LOCAL_CRATE) pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (), - /// Results of evaluating monomorphic constants embedded in - /// other items, such as enum variant explicit discriminants. - pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> const_val::EvalResult<'tcx>, + /// Results of evaluating const items or constants embedded in + /// other items (such as enum variant explicit discriminants). + pub const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>)) + -> const_val::EvalResult<'tcx>, /// Performs the privacy check and computes "access levels". pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, - pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet, + pub reachable_set: reachability_dep_node(CrateNum) -> Rc, - pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> + pub mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell> } fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { @@ -465,10 +528,14 @@ fn reachability_dep_node(_: CrateNum) -> DepNode { DepNode::Reachability } -fn mir_shim(instance: ty::InstanceDef) -> DepNode { +fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode { instance.dep_node() } fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode { DepNode::TypeckBodiesKrate } + +fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode { + DepNode::ConstEval(def_id) +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ab1a06aeacd..9a8c91f5820 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -31,13 +31,15 @@ use ty::subst::{Subst, Substs}; use ty::util::IntTypeExt; use ty::walk::TypeWalker; -use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; +use util::common::ErrorReported; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; use serialize::{self, Encodable, Encoder}; -use std::borrow::Cow; use std::cell::{Cell, RefCell, Ref}; use std::collections::BTreeMap; +use std::cmp; use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; use std::ops::Deref; use std::rc::Rc; use std::slice; @@ -71,7 +73,6 @@ pub use self::sty::Region::*; pub use self::sty::TypeVariants::*; -pub use self::contents::TypeContents; pub use self::context::{TyCtxt, GlobalArenas, tls}; pub use self::context::{Lift, TypeckTables}; @@ -99,7 +100,6 @@ pub mod wf; pub mod util; -mod contents; mod context; mod flags; mod instance; @@ -116,7 +116,7 @@ #[derive(Clone)] pub struct CrateAnalysis { pub access_levels: Rc, - pub reachable: NodeSet, + pub reachable: Rc, pub name: String, pub glob_map: Option, } @@ -165,9 +165,9 @@ pub fn with_fresh_ty_vars(selcx: &mut traits::SelectionContext<'a, 'gcx, 'tcx>, let header = ImplHeader { impl_def_id: impl_def_id, - self_ty: tcx.item_type(impl_def_id), + self_ty: tcx.type_of(impl_def_id), trait_ref: tcx.impl_trait_ref(impl_def_id), - predicates: tcx.item_predicates(impl_def_id).predicates + predicates: tcx.predicates_of(impl_def_id).predicates }.subst(tcx, impl_substs); let traits::Normalized { value: mut header, obligations } = @@ -425,6 +425,10 @@ pub enum FragmentInfo { const IS_SIZED = 1 << 17, const MOVENESS_CACHED = 1 << 18, const MOVES_BY_DEFAULT = 1 << 19, + const FREEZENESS_CACHED = 1 << 20, + const IS_FREEZE = 1 << 21, + const NEEDS_DROP_CACHED = 1 << 22, + const NEEDS_DROP = 1 << 23, } } @@ -723,7 +727,7 @@ fn instantiate_into(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, instantiated: &mut InstantiatedPredicates<'tcx>, substs: &Substs<'tcx>) { if let Some(def_id) = self.parent { - tcx.item_predicates(def_id).instantiate_into(tcx, instantiated, substs); + tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, substs); } instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs))) } @@ -1181,6 +1185,9 @@ pub struct ParameterEnvironment<'tcx> { /// A cache for `type_is_sized` pub is_sized_cache: RefCell, bool>>, + + /// A cache for `type_is_freeze` + pub is_freeze_cache: RefCell, bool>>, } impl<'a, 'tcx> ParameterEnvironment<'tcx> { @@ -1195,6 +1202,7 @@ pub fn with_caller_bounds(&self, free_id_outlive: self.free_id_outlive, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), + is_freeze_cache: RefCell::new(FxHashMap()), } } @@ -1326,17 +1334,6 @@ pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId) pub struct Destructor { /// The def-id of the destructor method pub did: DefId, - /// Invoking the destructor of a dtorck type during usual cleanup - /// (e.g. the glue emitted for stack unwinding) requires all - /// lifetimes in the type-structure of `adt` to strictly outlive - /// the adt value itself. - /// - /// If `adt` is not dtorck, then the adt's destructor can be - /// invoked even when there are lifetimes in the type-structure of - /// `adt` that do not strictly outlive the adt value itself. - /// (This allows programs to make cyclic structures without - /// resorting to unsafe means; see RFCs 769 and 1238). - pub is_dtorck: bool, } bitflags! { @@ -1464,10 +1461,12 @@ pub enum AdtKind { Struct, Union, Enum } #[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] pub struct ReprOptions { pub int: Option, + pub align: u16, pub flags: ReprFlags, } impl_stable_hash_for!(struct ReprOptions { + align, int, flags }); @@ -1476,7 +1475,7 @@ impl ReprOptions { pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { let mut flags = ReprFlags::empty(); let mut size = None; - + let mut max_align = 0; for attr in tcx.get_attrs(did).iter() { for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) { flags.insert(match r { @@ -1487,6 +1486,10 @@ pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { size = Some(i); ReprFlags::empty() }, + attr::ReprAlign(align) => { + max_align = cmp::max(align, max_align); + ReprFlags::empty() + }, }); } } @@ -1500,7 +1503,7 @@ pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) { flags.insert(ReprFlags::IS_LINEAR); } - ReprOptions { int: size, flags: flags } + ReprOptions { int: size, align: max_align, flags: flags } } #[inline] @@ -1597,14 +1600,6 @@ pub fn variant_descr(&self) -> &'static str { } } - /// Returns whether this is a dtorck type. If this returns - /// true, this type being safe for destruction requires it to be - /// alive; Otherwise, only the contents are required to be. - #[inline] - pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool { - self.destructor(tcx).map_or(false, |d| d.is_dtorck) - } - /// Returns whether this type is #[fundamental] for the purposes /// of coherence checking. #[inline] @@ -1638,7 +1633,7 @@ pub fn struct_variant(&self) -> &VariantDef { #[inline] pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> GenericPredicates<'gcx> { - tcx.item_predicates(self.did) + tcx.predicates_of(self.did) } /// Returns an iterator over all fields contained @@ -1681,6 +1676,7 @@ pub fn variant_of_def(&self, def: Def) -> &VariantDef { } } + #[inline] pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator + 'a { let repr_type = self.repr.discr_type(); @@ -1689,11 +1685,18 @@ pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) self.variants.iter().map(move |v| { let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr()); if let VariantDiscr::Explicit(expr_did) = v.discr { - match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) { + let substs = Substs::empty(); + match tcx.const_eval((expr_did, substs)) { Ok(ConstVal::Integral(v)) => { discr = v; } - _ => {} + err => { + if !expr_did.is_local() { + span_bug!(tcx.def_span(expr_did), + "variant discriminant evaluation succeeded \ + in its crate but failed locally: {:?}", err); + } + } } } prev_discr = Some(discr); @@ -1721,12 +1724,21 @@ pub fn discriminant_for_variant(&self, explicit_index -= distance; } ty::VariantDiscr::Explicit(expr_did) => { - match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) { + let substs = Substs::empty(); + match tcx.const_eval((expr_did, substs)) { Ok(ConstVal::Integral(v)) => { explicit_value = v; break; } - _ => { + err => { + if !expr_did.is_local() { + span_bug!(tcx.def_span(expr_did), + "variant discriminant evaluation succeeded \ + in its crate but failed locally: {:?}", err); + } + if explicit_index == 0 { + break; + } explicit_index -= 1; } } @@ -1748,19 +1760,12 @@ pub fn discriminant_for_variant(&self, } pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { - queries::adt_destructor::get(tcx, DUMMY_SP, self.did) + tcx.adt_destructor(self.did) } - /// Returns a simpler type such that `Self: Sized` if and only + /// Returns a list of types such that `Self: Sized` if and only /// if that type is Sized, or `TyErr` if this type is recursive. /// - /// HACK: instead of returning a list of types, this function can - /// return a tuple. In that case, the result is Sized only if - /// all elements of the tuple are Sized. - /// - /// This is generally the `struct_tail` if this is a struct, or a - /// tuple of them if this is an enum. - /// /// Oddly enough, checking that the sized-constraint is Sized is /// actually more expressive than checking all members: /// the Sized trait is inductive, so an associated type that references @@ -1768,16 +1773,16 @@ pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { /// /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer, e.g. issue #31299. - pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) { - Ok(ty) => ty, + Ok(tys) => tys, Err(_) => { debug!("adt_sized_constraint: {:?} is recursive", self); // This should be reported as an error by `check_representable`. // // Consider the type as Sized in the meanwhile to avoid // further errors. - tcx.types.err + tcx.intern_type_list(&[tcx.types.err]) } } } @@ -1807,18 +1812,13 @@ fn sized_constraint_for_ty(&self, TyAdt(adt, substs) => { // recursive case - let adt_ty = - adt.sized_constraint(tcx) - .subst(tcx, substs); + let adt_tys = adt.sized_constraint(tcx); debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", - ty, adt_ty); - if let ty::TyTuple(ref tys, _) = adt_ty.sty { - tys.iter().flat_map(|ty| { - self.sized_constraint_for_ty(tcx, ty) - }).collect() - } else { - self.sized_constraint_for_ty(tcx, adt_ty) - } + ty, adt_tys); + adt_tys.iter() + .map(|ty| ty.subst(tcx, substs)) + .flat_map(|ty| self.sized_constraint_for_ty(tcx, ty)) + .collect() } TyProjection(..) | TyAnon(..) => { @@ -1840,7 +1840,7 @@ fn sized_constraint_for_ty(&self, def_id: sized_trait, substs: tcx.mk_substs_trait(ty, &[]) }).to_predicate(); - let predicates = tcx.item_predicates(self.did).predicates; + let predicates = tcx.predicates_of(self.did).predicates; if predicates.into_iter().any(|p| p == sized_predicate) { vec![] } else { @@ -1881,7 +1881,7 @@ pub fn field_named(&self, name: ast::Name) -> &FieldDef { impl<'a, 'gcx, 'tcx> FieldDef { pub fn ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { - tcx.item_type(self.did).subst(tcx, subst) + tcx.type_of(self.did).subst(tcx, subst) } } @@ -2023,13 +2023,26 @@ pub fn to_user_str(&self) -> &'static str { } } -impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> { - self.item_tables(self.hir.body_owner_def_id(body)) +#[derive(Debug, Clone)] +pub enum Attributes<'gcx> { + Owned(Rc<[ast::Attribute]>), + Borrowed(&'gcx [ast::Attribute]) +} + +impl<'gcx> ::std::ops::Deref for Attributes<'gcx> { + type Target = [ast::Attribute]; + + fn deref(&self) -> &[ast::Attribute] { + match self { + &Attributes::Owned(ref data) => &data, + &Attributes::Borrowed(data) => data + } } +} - pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> { - queries::typeck_tables::get(self, DUMMY_SP, def_id) +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { + pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> { + self.typeck_tables_of(self.hir.body_owner_def_id(body)) } pub fn expr_span(self, id: NodeId) -> Span { @@ -2119,33 +2132,15 @@ pub fn provided_trait_methods(self, id: DefId) -> Vec { .collect() } - pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity { - if let Some(id) = self.hir.as_local_node_id(id) { - match self.hir.expect_item(id).node { - hir::ItemImpl(_, polarity, ..) => polarity, - ref item => bug!("trait_impl_polarity: {:?} not an impl", item) - } - } else { - self.sess.cstore.impl_polarity(id) - } - } - pub fn trait_relevant_for_never(self, did: DefId) -> bool { self.associated_items(did).any(|item| { item.relevant_for_never() }) } - pub fn coerce_unsized_info(self, did: DefId) -> adjustment::CoerceUnsizedInfo { - queries::coerce_unsized_info::get(self, DUMMY_SP, did) - } - - pub fn associated_item(self, def_id: DefId) -> AssociatedItem { - queries::associated_item::get(self, DUMMY_SP, def_id) - } - fn associated_item_from_trait_item_ref(self, parent_def_id: DefId, + parent_vis: &hir::Visibility, trait_item_ref: &hir::TraitItemRef) -> AssociatedItem { let def_id = self.hir.local_def_id(trait_item_ref.id.node_id); @@ -2160,7 +2155,8 @@ fn associated_item_from_trait_item_ref(self, AssociatedItem { name: trait_item_ref.name, kind: kind, - vis: Visibility::from_hir(&hir::Inherited, trait_item_ref.id.node_id, self), + // 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, container: TraitContainer(parent_def_id), @@ -2170,7 +2166,6 @@ fn associated_item_from_trait_item_ref(self, fn associated_item_from_impl_item_ref(self, parent_def_id: DefId, - from_trait_impl: bool, impl_item_ref: &hir::ImplItemRef) -> AssociatedItem { let def_id = self.hir.local_def_id(impl_item_ref.id.node_id); @@ -2182,14 +2177,11 @@ fn associated_item_from_impl_item_ref(self, hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false), }; - // Trait impl items are always public. - let public = hir::Public; - let vis = if from_trait_impl { &public } else { &impl_item_ref.vis }; - ty::AssociatedItem { name: impl_item_ref.name, kind: kind, - vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self), + // 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, container: ImplContainer(parent_def_id), @@ -2197,10 +2189,6 @@ fn associated_item_from_impl_item_ref(self, } } - pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { - queries::associated_item_def_ids::get(self, DUMMY_SP, def_id) - } - #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. pub fn associated_items(self, def_id: DefId) -> impl Iterator + 'a { @@ -2208,12 +2196,6 @@ pub fn associated_items(self, def_id: DefId) (0..def_ids.len()).map(move |i| self.associated_item(def_ids[i])) } - /// Returns the trait-ref corresponding to a given impl, or None if it is - /// an inherent impl. - pub fn impl_trait_ref(self, id: DefId) -> Option> { - queries::impl_trait_ref::get(self, DUMMY_SP, id) - } - /// Returns true if the impls are the same polarity and are implementing /// a trait which contains no items pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { @@ -2228,7 +2210,7 @@ pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> boo .map_or(false, |trait_ref| { self.associated_item_def_ids(trait_ref.def_id).is_empty() }); - self.trait_impl_polarity(def_id1) == self.trait_impl_polarity(def_id2) + self.impl_polarity(def_id1) == self.impl_polarity(def_id2) && trait1_is_empty && trait2_is_empty } @@ -2239,14 +2221,14 @@ pub fn expect_variant_def(self, def: Def) -> &'tcx VariantDef { match def { Def::Variant(did) | Def::VariantCtor(did, ..) => { let enum_did = self.parent_def_id(did).unwrap(); - self.lookup_adt_def(enum_did).variant_with_id(did) + self.adt_def(enum_did).variant_with_id(did) } Def::Struct(did) | Def::Union(did) => { - self.lookup_adt_def(did).struct_variant() + self.adt_def(did).struct_variant() } Def::StructCtor(ctor_did, ..) => { let did = self.parent_def_id(ctor_did).expect("struct ctor has no parent"); - self.lookup_adt_def(did).struct_variant() + self.adt_def(did).struct_variant() } _ => bug!("expect_variant_def used with unexpected def {:?}", def) } @@ -2315,40 +2297,9 @@ pub fn item_name(self, id: DefId) -> ast::Name { } } - // If the given item is in an external crate, looks up its type and adds it to - // the type cache. Returns the type parameters and type. - pub fn item_type(self, did: DefId) -> Ty<'gcx> { - queries::ty::get(self, DUMMY_SP, did) - } - - /// Given the did of a trait, returns its canonical trait ref. - pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef { - queries::trait_def::get(self, DUMMY_SP, did) - } - - /// Given the did of an ADT, return a reference to its definition. - pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef { - queries::adt_def::get(self, DUMMY_SP, did) - } - - /// Given the did of an item, returns its generics. - pub fn item_generics(self, did: DefId) -> &'gcx Generics { - queries::generics::get(self, DUMMY_SP, did) - } - - /// Given the did of an item, returns its full set of predicates. - pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> { - queries::predicates::get(self, DUMMY_SP, did) - } - - /// Given the did of a trait, returns its superpredicates. - pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> { - queries::super_predicates::get(self, DUMMY_SP, did) - } - /// Given the did of an item, returns its MIR, borrowed immutably. pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> { - queries::mir::get(self, DUMMY_SP, did).borrow() + self.mir(did).borrow() } /// Return the possibly-auto-generated MIR of a (DefId, Subst) pair. @@ -2357,7 +2308,7 @@ pub fn instance_mir(self, instance: ty::InstanceDef<'gcx>) { match instance { ty::InstanceDef::Item(did) if true => self.item_mir(did), - _ => queries::mir_shims::get(self, DUMMY_SP, instance).borrow(), + _ => self.mir_shims(instance).borrow(), } } @@ -2375,46 +2326,12 @@ pub fn maybe_item_mir(self, did: DefId) -> Option>> { Some(self.item_mir(did)) } - /// If `type_needs_drop` returns true, then `ty` is definitely - /// non-copy and *might* have a destructor attached; if it returns - /// false, then `ty` definitely has no destructor (i.e. no drop glue). - /// - /// (Note that this implies that if `ty` has a destructor attached, - /// then `type_needs_drop` will definitely return `true` for `ty`.) - pub fn type_needs_drop_given_env(self, - ty: Ty<'gcx>, - param_env: &ty::ParameterEnvironment<'gcx>) -> bool { - // Issue #22536: We first query type_moves_by_default. It sees a - // normalized version of the type, and therefore will definitely - // know whether the type implements Copy (and thus needs no - // cleanup/drop/zeroing) ... - let tcx = self.global_tcx(); - let implements_copy = !ty.moves_by_default(tcx, param_env, DUMMY_SP); - - if implements_copy { return false; } - - // ... (issue #22536 continued) but as an optimization, still use - // prior logic of asking if the `needs_drop` bit is set; we need - // not zero non-Copy types if they have no destructor. - - // FIXME(#22815): Note that calling `ty::type_contents` is a - // conservative heuristic; it may report that `needs_drop` is set - // when actual type does not actually have a destructor associated - // with it. But since `ty` absolutely did not have the `Copy` - // bound attached (see above), it is sound to treat it as having a - // destructor (e.g. zero its memory on move). - - let contents = ty.type_contents(tcx); - debug!("type_needs_drop ty={:?} contents={:?}", ty, contents); - contents.needs_drop(tcx) - } - /// Get the attributes of a definition. - pub fn get_attrs(self, did: DefId) -> Cow<'gcx, [ast::Attribute]> { + pub fn get_attrs(self, did: DefId) -> Attributes<'gcx> { if let Some(id) = self.hir.as_local_node_id(did) { - Cow::Borrowed(self.hir.attrs(id)) + Attributes::Borrowed(self.hir.attrs(id)) } else { - Cow::Owned(self.sess.cstore.item_attrs(did)) + Attributes::Owned(self.sess.cstore.item_attrs(did)) } } @@ -2423,12 +2340,8 @@ pub fn has_attr(self, did: DefId, attr: &str) -> bool { self.get_attrs(did).iter().any(|item| item.check_name(attr)) } - pub fn item_variances(self, item_id: DefId) -> Rc> { - queries::variances::get(self, DUMMY_SP, item_id) - } - pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool { - let def = self.lookup_trait_def(trait_def_id); + let def = self.trait_def(trait_def_id); def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) } @@ -2443,7 +2356,7 @@ pub fn populate_implementations_for_trait_if_necessary(self, trait_id: DefId) { // metadata and don't need to track edges. let _ignore = self.dep_graph.in_ignore(); - let def = self.lookup_trait_def(trait_id); + let def = self.trait_def(trait_id); if def.flags.get().intersects(TraitFlags::HAS_REMOTE_IMPLS) { return; } @@ -2461,14 +2374,6 @@ pub fn populate_implementations_for_trait_if_necessary(self, trait_id: DefId) { def.flags.set(def.flags.get() | TraitFlags::HAS_REMOTE_IMPLS); } - pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind { - queries::closure_kind::get(self, DUMMY_SP, def_id) - } - - pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> { - queries::closure_type::get(self, DUMMY_SP, def_id) - } - /// Given the def_id of an impl, return the def_id of the trait it implements. /// If it implements no trait, return `None`. pub fn trait_id_of_impl(self, def_id: DefId) -> Option { @@ -2520,17 +2425,16 @@ pub fn trait_of_item(self, def_id: DefId) -> Option { /// Construct a parameter environment suitable for static contexts or other contexts where there /// are no free type/lifetime parameters in scope. pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> { - - // for an empty parameter environment, there ARE no free - // regions, so it shouldn't matter what we use for the free id - let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID); ty::ParameterEnvironment { free_substs: self.intern_substs(&[]), caller_bounds: Vec::new(), - implicit_region_bound: self.mk_region(ty::ReEmpty), - free_id_outlive: free_id_outlive, + implicit_region_bound: self.types.re_empty, + // for an empty parameter environment, there ARE no free + // regions, so it shouldn't matter what we use for the free id + free_id_outlive: ROOT_CODE_EXTENT, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), + is_freeze_cache: RefCell::new(FxHashMap()), } } @@ -2578,7 +2482,7 @@ pub fn construct_parameter_environment(self, // let tcx = self.global_tcx(); - let generic_predicates = tcx.item_predicates(def_id); + let generic_predicates = tcx.predicates_of(def_id); let bounds = generic_predicates.instantiate(tcx, free_substs); let bounds = tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); let predicates = bounds.predicates; @@ -2603,6 +2507,7 @@ pub fn construct_parameter_environment(self, free_id_outlive: free_id_outlive, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), + is_freeze_cache: RefCell::new(FxHashMap()), }; let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps)); @@ -2663,12 +2568,10 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) let parent_def_id = tcx.hir.local_def_id(parent_id); let parent_item = tcx.hir.expect_item(parent_id); match parent_item.node { - hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => { + hir::ItemImpl(.., ref impl_item_refs) => { if let Some(impl_item_ref) = impl_item_refs.iter().find(|i| i.id.node_id == id) { - let assoc_item = - tcx.associated_item_from_impl_item_ref(parent_def_id, - impl_trait_ref.is_some(), - impl_item_ref); + let assoc_item = tcx.associated_item_from_impl_item_ref(parent_def_id, + impl_item_ref); debug_assert_eq!(assoc_item.def_id, def_id); return assoc_item; } @@ -2676,8 +2579,9 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) hir::ItemTrait(.., ref trait_item_refs) => { if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.node_id == id) { - let assoc_item = - tcx.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref); + let assoc_item = tcx.associated_item_from_trait_item_ref(parent_def_id, + &parent_item.vis, + trait_item_ref); debug_assert_eq!(assoc_item.def_id, def_id); return assoc_item; } @@ -2692,13 +2596,7 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) /// Calculates the Sized-constraint. /// -/// As the Sized-constraint of enums can be a *set* of types, -/// the Sized-constraint may need to be a set also. Because introducing -/// a new type of IVar is currently a complex affair, the Sized-constraint -/// may be a tuple. -/// -/// In fact, there are only a few options for the constraint: -/// - `bool`, if the type is always Sized +/// In fact, there are only a few options for the types in the constraint: /// - an obviously-unsized type /// - a type parameter or projection whose Sizedness can't be known /// - a tuple of type parameters or projections, if there are multiple @@ -2707,26 +2605,50 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) /// check should catch this case. fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Ty<'tcx> { - let def = tcx.lookup_adt_def(def_id); + -> &'tcx [Ty<'tcx>] { + let def = tcx.adt_def(def_id); - let tys: Vec<_> = def.variants.iter().flat_map(|v| { + let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| { v.fields.last() }).flat_map(|f| { - let ty = tcx.item_type(f.did); - def.sized_constraint_for_ty(tcx, ty) - }).collect(); - - let ty = match tys.len() { - _ if tys.references_error() => tcx.types.err, - 0 => tcx.types.bool, - 1 => tys[0], - _ => tcx.intern_tup(&tys[..], false) - }; + def.sized_constraint_for_ty(tcx, tcx.type_of(f.did)) + }).collect::>()); + + debug!("adt_sized_constraint: {:?} => {:?}", def, result); + + result +} + +/// Calculates the dtorck constraint for a type. +fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> DtorckConstraint<'tcx> { + let def = tcx.adt_def(def_id); + let span = tcx.def_span(def_id); + debug!("dtorck_constraint: {:?}", def); + + if def.is_phantom_data() { + let result = DtorckConstraint { + outlives: vec![], + dtorck_types: vec![ + tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0]) + ] + }; + debug!("dtorck_constraint: {:?} => {:?}", def, result); + return result; + } + + let mut result = def.all_fields() + .map(|field| tcx.type_of(field.did)) + .map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty)) + .collect::>() + .unwrap_or(DtorckConstraint::empty()); + result.outlives.extend(tcx.destructor_constraints(def)); + result.dedup(); - debug!("adt_sized_constraint: {:?} => {:?}", def, ty); + debug!("dtorck_constraint: {:?} => {:?}", def, result); - ty + result } fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -2757,6 +2679,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { associated_item, associated_item_def_ids, adt_sized_constraint, + adt_dtorck_constraint, ..*providers }; } @@ -2764,6 +2687,7 @@ pub fn provide(providers: &mut ty::maps::Providers) { pub fn provide_extern(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { adt_sized_constraint, + adt_dtorck_constraint, ..*providers }; } @@ -2772,11 +2696,52 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) { /// A map for the local crate mapping each type to a vector of its /// inherent impls. This is not meant to be used outside of coherence; /// rather, you should request the vector for a specific type via -/// `ty::queries::inherent_impls::get(def_id)` so as to minimize your -/// dependencies (constructing this map requires touching the entire -/// crate). +/// `tcx.inherent_impls(def_id)` so as to minimize your dependencies +/// (constructing this map requires touching the entire crate). #[derive(Clone, Debug)] pub struct CrateInherentImpls { pub inherent_impls: DefIdMap>>, } +/// A set of constraints that need to be satisfied in order for +/// a type to be valid for destruction. +#[derive(Clone, Debug)] +pub struct DtorckConstraint<'tcx> { + /// Types that are required to be alive in order for this + /// type to be valid for destruction. + pub outlives: Vec>, + /// Types that could not be resolved: projections and params. + pub dtorck_types: Vec>, +} + +impl<'tcx> FromIterator> for DtorckConstraint<'tcx> +{ + fn from_iter>>(iter: I) -> Self { + let mut result = Self::empty(); + + for constraint in iter { + result.outlives.extend(constraint.outlives); + result.dtorck_types.extend(constraint.dtorck_types); + } + + result + } +} + + +impl<'tcx> DtorckConstraint<'tcx> { + fn empty() -> DtorckConstraint<'tcx> { + DtorckConstraint { + outlives: vec![], + dtorck_types: vec![] + } + } + + fn dedup<'a>(&mut self) { + let mut outlives = FxHashSet(); + let mut dtorck_types = FxHashSet(); + + self.outlives.retain(|&val| outlives.replace(val).is_none()); + self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none()); + } +} diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index cef24d44d68..58ebc843da1 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -126,7 +126,7 @@ fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, let variances; let opt_variances = if relation.tcx().variance_computed.get() { - variances = relation.tcx().item_variances(item_def_id); + variances = relation.tcx().variances_of(item_def_id); Some(&*variances) } else { None diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d5924817034..7857d07ed09 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -262,7 +262,7 @@ impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) -> impl Iterator> + 'tcx { - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); self.substs[self.substs.len()-generics.own_count()..].iter().map( |t| t.as_type().expect("unexpected region in upvars")) } @@ -285,7 +285,7 @@ pub fn cmp(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, other: &Self) -> Ordering { (Trait(_), Trait(_)) => Ordering::Equal, (Projection(ref a), Projection(ref b)) => a.sort_key(tcx).cmp(&b.sort_key(tcx)), (AutoTrait(ref a), AutoTrait(ref b)) => - tcx.lookup_trait_def(*a).def_path_hash.cmp(&tcx.lookup_trait_def(*b).def_path_hash), + tcx.trait_def(*a).def_path_hash.cmp(&tcx.trait_def(*b).def_path_hash), (Trait(_), _) => Ordering::Less, (Projection(_), Trait(_)) => Ordering::Greater, (Projection(_), _) => Ordering::Less, @@ -841,7 +841,7 @@ pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (u64, InternedString) { // We want something here that is stable across crate boundaries. // The DefId isn't but the `deterministic_hash` of the corresponding // DefPath is. - let trait_def = tcx.lookup_trait_def(self.trait_ref.def_id); + let trait_def = tcx.trait_def(self.trait_ref.def_id); let def_path_hash = trait_def.def_path_hash; // An `ast::Name` is also not stable (it's just an index into an diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 0a2cc1c30f4..961140d5eac 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -185,7 +185,7 @@ pub fn for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, -> &'tcx Substs<'tcx> where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { - let defs = tcx.item_generics(def_id); + let defs = tcx.generics_of(def_id); let mut substs = Vec::with_capacity(defs.count()); Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type); tcx.intern_substs(&substs) @@ -200,7 +200,7 @@ pub fn extend_to(&self, where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { - let defs = tcx.item_generics(def_id); + let defs = tcx.generics_of(def_id); let mut result = Vec::with_capacity(defs.count()); result.extend(self[..].iter().cloned()); Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type); @@ -216,7 +216,7 @@ fn fill_item(substs: &mut Vec>, FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { if let Some(def_id) = defs.parent { - let parent_defs = tcx.item_generics(def_id); + let parent_defs = tcx.generics_of(def_id); Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type); } Substs::fill_single(substs, defs, mk_region, mk_type) @@ -297,7 +297,7 @@ pub fn rebase_onto(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, source_ancestor: DefId, target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { - let defs = tcx.item_generics(source_ancestor); + let defs = tcx.generics_of(source_ancestor); tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) } @@ -539,6 +539,9 @@ fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> { } fn shift_region_through_binders(&self, region: &'tcx ty::Region) -> &'tcx ty::Region { + if self.region_binders_passed == 0 || !region.has_escaping_regions() { + return region; + } self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed)) } } @@ -550,7 +553,7 @@ pub fn from_method(tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_id: DefId, substs: &Substs<'tcx>) -> ty::TraitRef<'tcx> { - let defs = tcx.item_generics(trait_id); + let defs = tcx.generics_of(trait_id); ty::TraitRef { def_id: trait_id, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 5334ee2835d..87921c80502 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -19,9 +19,10 @@ use ty::ParameterEnvironment; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; +use ty::subst::{Subst, Kind}; use ty::TypeVariants::*; use util::common::ErrorReported; -use util::nodemap::FxHashMap; +use util::nodemap::{FxHashMap, FxHashSet}; use middle::lang_items; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; @@ -368,11 +369,11 @@ pub fn calculate_dtor( return None; }; - ty::queries::coherent_trait::get(self, DUMMY_SP, (LOCAL_CRATE, drop_trait)); + self.coherent_trait((LOCAL_CRATE, drop_trait)); let mut dtor_did = None; - let ty = self.item_type(adt_did); - self.lookup_trait_def(drop_trait).for_each_relevant_impl(self, ty, |impl_did| { + let ty = self.type_of(adt_did); + self.trait_def(drop_trait).for_each_relevant_impl(self, ty, |impl_did| { if let Some(item) = self.associated_items(impl_did).next() { if let Ok(()) = validate(self, impl_did) { dtor_did = Some(item.def_id); @@ -385,6 +386,27 @@ pub fn calculate_dtor( None => return None, }; + Some(ty::Destructor { did: dtor_did }) + } + + /// Return the set of types that are required to be alive in + /// order to run the destructor of `def` (see RFCs 769 and + /// 1238). + /// + /// Note that this returns only the constraints for the + /// destructor of `def` itself. For the destructors of the + /// contents, you need `adt_dtorck_constraint`. + pub fn destructor_constraints(self, def: &'tcx ty::AdtDef) + -> Vec> + { + let dtor = match def.destructor(self) { + None => { + debug!("destructor_constraints({:?}) - no dtor", def.did); + return vec![] + } + Some(dtor) => dtor.did + }; + // RFC 1238: if the destructor method is tagged with the // attribute `unsafe_destructor_blind_to_params`, then the // compiler is being instructed to *assume* that the @@ -394,11 +416,147 @@ pub fn calculate_dtor( // Such access can be in plain sight (e.g. dereferencing // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden // (e.g. calling `foo.0.clone()` of `Foo`). - let is_dtorck = !self.has_attr(dtor_did, "unsafe_destructor_blind_to_params"); - Some(ty::Destructor { did: dtor_did, is_dtorck: is_dtorck }) + if self.has_attr(dtor, "unsafe_destructor_blind_to_params") { + debug!("destructor_constraint({:?}) - blind", def.did); + return vec![]; + } + + let impl_def_id = self.associated_item(dtor).container.id(); + let impl_generics = self.generics_of(impl_def_id); + + // We have a destructor - all the parameters that are not + // pure_wrt_drop (i.e, don't have a #[may_dangle] attribute) + // must be live. + + // We need to return the list of parameters from the ADTs + // generics/substs that correspond to impure parameters on the + // impl's generics. This is a bit ugly, but conceptually simple: + // + // Suppose our ADT looks like the following + // + // struct S(X, Y, Z); + // + // and the impl is + // + // impl<#[may_dangle] P0, P1, P2> Drop for S + // + // We want to return the parameters (X, Y). For that, we match + // up the item-substs with the substs on the impl ADT, + // , and then look up which of the impl substs refer to + // parameters marked as pure. + + let impl_substs = match self.type_of(impl_def_id).sty { + ty::TyAdt(def_, substs) if def_ == def => substs, + _ => bug!() + }; + + let item_substs = match self.type_of(def.did).sty { + ty::TyAdt(def_, substs) if def_ == def => substs, + _ => bug!() + }; + + let result = item_substs.iter().zip(impl_substs.iter()) + .filter(|&(_, &k)| { + if let Some(&ty::Region::ReEarlyBound(ref ebr)) = k.as_region() { + !impl_generics.region_param(ebr).pure_wrt_drop + } else if let Some(&ty::TyS { + sty: ty::TypeVariants::TyParam(ref pt), .. + }) = k.as_type() { + !impl_generics.type_param(pt).pure_wrt_drop + } else { + // not a type or region param - this should be reported + // as an error. + false + } + }).map(|(&item_param, _)| item_param).collect(); + debug!("destructor_constraint({:?}) = {:?}", def.did, result); + result + } + + /// Return a set of constraints that needs to be satisfied in + /// order for `ty` to be valid for destruction. + pub fn dtorck_constraint_for_ty(self, + span: Span, + for_ty: Ty<'tcx>, + depth: usize, + ty: Ty<'tcx>) + -> Result, ErrorReported> + { + debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", + span, for_ty, depth, ty); + + if depth >= self.sess.recursion_limit.get() { + let mut err = struct_span_err!( + self.sess, span, E0320, + "overflow while adding drop-check rules for {}", for_ty); + err.note(&format!("overflowed on {}", ty)); + err.emit(); + return Err(ErrorReported); + } + + let result = match ty.sty { + ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | + ty::TyFloat(_) | ty::TyStr | ty::TyNever | + ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => { + // these types never have a destructor + Ok(ty::DtorckConstraint::empty()) + } + + ty::TyArray(ety, _) | ty::TySlice(ety) => { + // single-element containers, behave like their element + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ety) + } + + ty::TyTuple(tys, _) => { + tys.iter().map(|ty| { + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) + }).collect() + } + + ty::TyClosure(def_id, substs) => { + substs.upvar_tys(def_id, self).map(|ty| { + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) + }).collect() + } + + ty::TyAdt(def, substs) => { + let ty::DtorckConstraint { + dtorck_types, outlives + } = self.at(span).adt_dtorck_constraint(def.did); + Ok(ty::DtorckConstraint { + // FIXME: we can try to recursively `dtorck_constraint_on_ty` + // there, but that needs some way to handle cycles. + dtorck_types: dtorck_types.subst(self, substs), + outlives: outlives.subst(self, substs) + }) + } + + // Objects must be alive in order for their destructor + // to be called. + ty::TyDynamic(..) => Ok(ty::DtorckConstraint { + outlives: vec![Kind::from(ty)], + dtorck_types: vec![], + }), + + // Types that can't be resolved. Pass them forward. + ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => { + Ok(ty::DtorckConstraint { + outlives: vec![], + dtorck_types: vec![ty], + }) + } + + ty::TyInfer(..) | ty::TyError => { + self.sess.delay_span_bug(span, "unresolved type in dtorck"); + Err(ErrorReported) + } + }; + + debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result); + result } - pub fn closure_base_def_id(&self, def_id: DefId) -> DefId { + pub fn closure_base_def_id(self, def_id: DefId) -> DefId { let mut def_id = def_id; while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr { def_id = self.parent_def_id(def_id).unwrap_or_else(|| { @@ -412,7 +570,7 @@ pub fn closure_base_def_id(&self, def_id: DefId) -> DefId { /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> { ty::Substs::for_item(self, item_def_id, - |_, _| self.mk_region(ty::ReErased), + |_, _| self.types.re_erased, |_, _| { bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) }) @@ -655,6 +813,165 @@ fn is_sized_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, result } + /// Returns `true` if and only if there are no `UnsafeCell`s + /// nested within the type (ignoring `PhantomData` or pointers). + #[inline] + pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ParameterEnvironment<'tcx>, + span: Span) -> bool + { + if self.flags.get().intersects(TypeFlags::FREEZENESS_CACHED) { + return self.flags.get().intersects(TypeFlags::IS_FREEZE); + } + + self.is_freeze_uncached(tcx, param_env, span) + } + + fn is_freeze_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ParameterEnvironment<'tcx>, + span: Span) -> bool { + assert!(!self.needs_infer()); + + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyStr | TyNever => Some(true), + + TyArray(..) | TySlice(_) | + TyTuple(..) | TyClosure(..) | TyAdt(..) | + TyDynamic(..) | TyProjection(..) | TyParam(..) | + TyInfer(..) | TyAnon(..) | TyError => None + }.unwrap_or_else(|| { + self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::FreezeTraitLangItem), + ¶m_env.is_freeze_cache, span) }); + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::FREEZENESS_CACHED | TypeFlags::IS_FREEZE + } else { + TypeFlags::FREEZENESS_CACHED + }); + } + + result + } + + /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely + /// non-copy and *might* have a destructor attached; if it returns + /// `false`, then `ty` definitely has no destructor (i.e. no drop glue). + /// + /// (Note that this implies that if `ty` has a destructor attached, + /// then `needs_drop` will definitely return `true` for `ty`.) + #[inline] + pub fn needs_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>) -> bool { + if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) { + return self.flags.get().intersects(TypeFlags::NEEDS_DROP); + } + + self.needs_drop_uncached(tcx, param_env, &mut FxHashSet()) + } + + fn needs_drop_inner(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>, + stack: &mut FxHashSet>) + -> bool { + if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) { + return self.flags.get().intersects(TypeFlags::NEEDS_DROP); + } + + // This should be reported as an error by `check_representable`. + // + // Consider the type as not needing drop in the meanwhile to avoid + // further errors. + if let Some(_) = stack.replace(self) { + return false; + } + + let needs_drop = self.needs_drop_uncached(tcx, param_env, stack); + + // "Pop" the cycle detection "stack". + stack.remove(self); + + needs_drop + } + + fn needs_drop_uncached(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>, + stack: &mut FxHashSet>) + -> bool { + assert!(!self.needs_infer()); + + let result = match self.sty { + // Fast-path for primitive types + ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | + ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | + ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false, + + // Issue #22536: We first query type_moves_by_default. It sees a + // normalized version of the type, and therefore will definitely + // know whether the type implements Copy (and thus needs no + // cleanup/drop/zeroing) ... + _ if !self.moves_by_default(tcx, param_env, DUMMY_SP) => false, + + // ... (issue #22536 continued) but as an optimization, still use + // prior logic of asking for the structural "may drop". + + // FIXME(#22815): Note that this is a conservative heuristic; + // it may report that the type "may drop" when actual type does + // not actually have a destructor associated with it. But since + // the type absolutely did not have the `Copy` bound attached + // (see above), it is sound to treat it as having a destructor. + + // User destructors are the only way to have concrete drop types. + ty::TyAdt(def, _) if def.has_dtor(tcx) => true, + + // Can refer to a type which may drop. + // FIXME(eddyb) check this against a ParameterEnvironment. + ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) | + ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true, + + // Structural recursion. + ty::TyArray(ty, _) | ty::TySlice(ty) => { + ty.needs_drop_inner(tcx, param_env, stack) + } + + ty::TyClosure(def_id, ref substs) => { + substs.upvar_tys(def_id, tcx) + .any(|ty| ty.needs_drop_inner(tcx, param_env, stack)) + } + + ty::TyTuple(ref tys, _) => { + tys.iter().any(|ty| ty.needs_drop_inner(tcx, param_env, stack)) + } + + // unions don't have destructors regardless of the child types + ty::TyAdt(def, _) if def.is_union() => false, + + ty::TyAdt(def, substs) => { + def.variants.iter().any(|v| { + v.fields.iter().any(|f| { + f.ty(tcx, substs).needs_drop_inner(tcx, param_env, stack) + }) + }) + } + }; + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::NEEDS_DROP_CACHED | TypeFlags::NEEDS_DROP + } else { + TypeFlags::NEEDS_DROP_CACHED + }); + } + + result + } + #[inline] pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 0b0e8a180cc..6c7073de70b 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -443,7 +443,7 @@ fn nominal_obligations(&mut self, -> Vec> { let predicates = - self.infcx.tcx.item_predicates(def_id) + self.infcx.tcx.predicates_of(def_id) .instantiate(self.infcx.tcx, substs); let cause = self.cause(traits::ItemObligation(def_id)); predicates.predicates diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 2daf71d95ad..df5a2731c89 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -104,7 +104,7 @@ pub fn parameterized(f: &mut fmt::Formatter, } } } - let mut generics = tcx.item_generics(item_def_id); + let mut generics = tcx.generics_of(item_def_id); let mut path_def_id = did; verbose = tcx.sess.verbose(); has_self = generics.has_self; @@ -114,7 +114,7 @@ pub fn parameterized(f: &mut fmt::Formatter, // Methods. assert!(is_value_path); child_types = generics.types.len(); - generics = tcx.item_generics(def_id); + generics = tcx.generics_of(def_id); num_regions = generics.regions.len(); num_types = generics.types.len(); @@ -144,7 +144,7 @@ pub fn parameterized(f: &mut fmt::Formatter, if !def.has_default { break; } - if tcx.item_type(def.def_id).subst(tcx, substs) != actual { + if tcx.type_of(def.def_id).subst(tcx, substs) != actual { break; } num_supplied_defaults += 1; @@ -772,11 +772,11 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let item_predicates = tcx.item_predicates(def_id); + let predicates_of = tcx.predicates_of(def_id); let substs = tcx.lift(&substs).unwrap_or_else(|| { tcx.intern_substs(&[]) }); - let bounds = item_predicates.instantiate(tcx, substs); + let bounds = predicates_of.instantiate(tcx, substs); let mut first = true; let mut is_sized = false; diff --git a/src/librustc_asan/build.rs b/src/librustc_asan/build.rs index 2df2e001e6f..3a80baa0485 100644 --- a/src/librustc_asan/build.rs +++ b/src/librustc_asan/build.rs @@ -12,14 +12,13 @@ extern crate cmake; use std::env; -use build_helper::native_lib_boilerplate; +use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { - let native = match native_lib_boilerplate("compiler-rt", "asan", "clang_rt.asan-x86_64", - "build/lib/linux") { + let native = match sanitizer_lib_boilerplate("asan") { Ok(native) => native, _ => return, }; diff --git a/src/librustc_back/dynamic_lib.rs b/src/librustc_back/dynamic_lib.rs index 38e60060925..e6f305c22b2 100644 --- a/src/librustc_back/dynamic_lib.rs +++ b/src/librustc_back/dynamic_lib.rs @@ -68,6 +68,8 @@ pub fn envvar() -> &'static str { "PATH" } else if cfg!(target_os = "macos") { "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" } else { "LD_LIBRARY_PATH" } diff --git a/src/librustc_back/target/haiku_base.rs b/src/librustc_back/target/haiku_base.rs index bfdc9faaa8a..8e7f463563c 100644 --- a/src/librustc_back/target/haiku_base.rs +++ b/src/librustc_back/target/haiku_base.rs @@ -16,9 +16,10 @@ pub fn opts() -> TargetOptions { linker: "cc".to_string(), dynamic_linking: true, executables: true, - has_rpath: true, + has_rpath: false, target_family: Some("unix".to_string()), linker_is_gnu: true, + no_integrated_as: true, .. Default::default() } } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index ca6894a7b70..e60fdc386ce 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -162,6 +162,7 @@ fn $module() { ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), ("i686-linux-android", i686_linux_android), + ("x86_64-linux-android", x86_64_linux_android), ("arm-linux-androideabi", arm_linux_androideabi), ("armv7-linux-androideabi", armv7_linux_androideabi), ("aarch64-linux-android", aarch64_linux_android), diff --git a/src/librustc_back/target/x86_64_linux_android.rs b/src/librustc_back/target/x86_64_linux_android.rs new file mode 100644 index 00000000000..75cf3e12438 --- /dev/null +++ b/src/librustc_back/target/x86_64_linux_android.rs @@ -0,0 +1,34 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use LinkerFlavor; +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::android_base::opts(); + base.cpu = "x86-64".to_string(); + // https://developer.android.com/ndk/guides/abis.html#86-64 + base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string(); + base.max_atomic_width = Some(64); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + + Ok(Target { + llvm_target: "x86_64-linux-android".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(), + arch: "x86_64".to_string(), + target_os: "android".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: base, + }) +} diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index bbfb7e5874e..b921678b495 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -120,7 +120,7 @@ fn scope(&self, cmt: &mc::cmt<'tcx>) -> &'tcx ty::Region { } Categorization::StaticItem | Categorization::Deref(.., mc::UnsafePtr(..)) => { - self.bccx.tcx.mk_region(ty::ReStatic) + self.bccx.tcx.types.re_static } Categorization::Deref(.., mc::BorrowedPtr(_, r)) | Categorization::Deref(.., mc::Implicit(_, r)) => { diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index dc01cbe5e76..de5613dbfaa 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -322,7 +322,7 @@ fn on_all_drop_children_bits<'a, 'tcx, F>( let ty = lvalue.ty(mir, tcx).to_ty(tcx); debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, lvalue, ty); - if tcx.type_needs_drop_given_env(ty, &ctxt.param_env) { + if ty.needs_drop(tcx, &ctxt.param_env) { each_child(child); } else { debug!("on_all_drop_children_bits - skipping") diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 142286bd834..401c878cd40 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -42,7 +42,7 @@ use std::rc::Rc; use std::hash::{Hash, Hasher}; use syntax::ast; -use syntax_pos::{DUMMY_SP, MultiSpan, Span}; +use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use rustc::hir; @@ -63,7 +63,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { - ty::queries::borrowck::get(tcx, DUMMY_SP, body_owner_def_id); + tcx.borrowck(body_owner_def_id); }); } @@ -87,7 +87,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap(); let body_id = tcx.hir.body_owned_by(owner_id); let attributes = tcx.get_attrs(owner_def_id); - let tables = tcx.item_tables(owner_def_id); + let tables = tcx.typeck_tables_of(owner_def_id); let mut bccx = &mut BorrowckCtxt { tcx: tcx, @@ -169,7 +169,7 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( { let owner_id = tcx.hir.body_owner(body_id); let owner_def_id = tcx.hir.local_def_id(owner_id); - let tables = tcx.item_tables(owner_def_id); + let tables = tcx.typeck_tables_of(owner_def_id); let mut bccx = BorrowckCtxt { tcx: tcx, diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 9c5a669bef0..9470316c7e7 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -15,7 +15,7 @@ use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; use rustc::traits; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; @@ -27,7 +27,7 @@ use syntax::ast; use rustc::hir::{self, Expr}; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::Span; use std::cmp::Ordering; @@ -48,110 +48,39 @@ macro_rules! math { } } -fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - variant_def: DefId) - -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> { - if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) { - let enum_node_id = tcx.hir.get_parent(variant_node_id); - if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) { - if let hir::ItemEnum(ref edef, _) = it.node { - for variant in &edef.variants { - if variant.node.data.id() == variant_node_id { - return variant.node.disr_expr.map(|e| { - let def_id = tcx.hir.body_owner_def_id(e); - (&tcx.hir.body(e).value, - tcx.item_tables(def_id)) - }); - } - } - } - } - } - None -} - /// * `def_id` is the id of the constant. /// * `substs` is the monomorphized substitutions for the expression. /// /// `substs` is optional and is used for associated constants. /// This generally happens in late/trans const evaluation. -pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>) - -> Option<(&'tcx Expr, - &'a ty::TypeckTables<'tcx>)> { +pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> Option<(DefId, &'tcx Substs<'tcx>)> { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { match tcx.hir.find(node_id) { - None => None, - Some(hir_map::NodeItem(&hir::Item { - node: hir::ItemConst(_, body), .. - })) | - Some(hir_map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Const(_, body), .. - })) => { - Some((&tcx.hir.body(body).value, - tcx.item_tables(def_id))) + Some(hir_map::NodeTraitItem(_)) => { + // If we have a trait item and the substitutions for it, + // `resolve_trait_associated_const` will select an impl + // or the default. + resolve_trait_associated_const(tcx, def_id, substs) } - Some(hir_map::NodeTraitItem(ti)) => match ti.node { - hir::TraitItemKind::Const(_, default) => { - // If we have a trait item and the substitutions for it, - // `resolve_trait_associated_const` will select an impl - // or the default. - let trait_id = tcx.hir.get_parent(node_id); - let trait_id = tcx.hir.local_def_id(trait_id); - let default_value = default.map(|body| { - (&tcx.hir.body(body).value, - tcx.item_tables(def_id)) - }); - resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs) - } - _ => None - }, - Some(_) => None + _ => Some((def_id, substs)) } } else { - let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { - (&body.value, tcx.item_tables(def_id)) - }); match tcx.sess.cstore.describe_def(def_id) { Some(Def::AssociatedConst(_)) => { - let trait_id = tcx.sess.cstore.trait_of_item(def_id); // As mentioned in the comments above for in-crate // constants, we only try to find the expression for a // trait-associated const if the caller gives us the // substitutions for the reference to it. - if let Some(trait_id) = trait_id { - resolve_trait_associated_const(tcx, def_id, expr_and_tables, - trait_id, substs) + if tcx.sess.cstore.trait_of_item(def_id).is_some() { + resolve_trait_associated_const(tcx, def_id, substs) } else { - expr_and_tables + Some((def_id, substs)) } - }, - Some(Def::Const(..)) => expr_and_tables, - _ => None - } - } -} - -fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)> -{ - if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { - FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| { - if fn_like.constness() == hir::Constness::Const { - Some((tcx.hir.body(fn_like.body()), - tcx.item_tables(def_id))) - } else { - None } - }) - } else { - if tcx.sess.cstore.is_const_fn(def_id) { - tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { - (body, tcx.item_tables(def_id)) - }) - } else { - None + _ => Some((def_id, substs)) } } } @@ -338,9 +267,22 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprCast(ref base, _) => { - match cast_const(tcx, cx.eval(base)?, ety) { - Ok(val) => val, - Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }), + let base_val = cx.eval(base)?; + let base_ty = cx.tables.expr_ty(base); + + // Avoid applying substitutions if they're empty, that'd ICE. + let base_ty = if cx.substs.is_empty() { + base_ty + } else { + base_ty.subst(tcx, cx.substs) + }; + if ety == base_ty { + base_val + } else { + match cast_const(tcx, base_val, ety) { + Ok(val) => val, + Err(kind) => signal!(e, kind), + } } } hir::ExprPath(ref qpath) => { @@ -357,42 +299,29 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, match cx.tables.qpath_def(qpath, e.id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { - if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) { - let cx = ConstContext::with_tables(tcx, tables); - match cx.eval(expr) { - Ok(val) => val, - Err(ConstEvalErr { kind: TypeckError, .. }) => { - signal!(e, TypeckError); - } - Err(err) => { - debug!("bad reference: {:?}, {:?}", err.description(), err.span); - signal!(e, ErroneousReferencedConstant(box err)) - }, - } - } else { - signal!(e, TypeckError); - } + match tcx.at(e.span).const_eval((def_id, substs)) { + Ok(val) => val, + Err(ConstEvalErr { kind: TypeckError, .. }) => { + signal!(e, TypeckError); + } + Err(err) => { + debug!("bad reference: {:?}, {:?}", err.description(), err.span); + signal!(e, ErroneousReferencedConstant(box err)) + }, + } }, - Def::VariantCtor(variant_def, ..) => { - if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) { - let cx = ConstContext::with_tables(tcx, tables); - match cx.eval(expr) { - Ok(val) => val, - Err(ConstEvalErr { kind: TypeckError, .. }) => { - signal!(e, TypeckError); - } - Err(err) => { - debug!("bad reference: {:?}, {:?}", err.description(), err.span); - signal!(e, ErroneousReferencedConstant(box err)) - }, - } - } else { - signal!(e, UnimplementedConstVal("enum variants")); - } + Def::VariantCtor(variant_def, CtorKind::Const) => { + Variant(variant_def) + } + Def::VariantCtor(_, CtorKind::Fn) => { + signal!(e, UnimplementedConstVal("enum variants")); } - Def::StructCtor(..) => { + Def::StructCtor(_, CtorKind::Const) => { ConstVal::Struct(Default::default()) } + Def::StructCtor(_, CtorKind::Fn) => { + signal!(e, UnimplementedConstVal("tuple struct constructors")) + } Def::Local(def_id) => { debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args); if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) { @@ -407,14 +336,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprCall(ref callee, ref args) => { - let (did, substs) = match cx.eval(callee)? { - Function(did, substs) => (did, substs), - Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")), - callee => signal!(e, CallOn(callee)), + let (def_id, substs) = match cx.eval(callee)? { + Function(def_id, substs) => (def_id, substs), + _ => signal!(e, TypeckError), }; - let (body, tables) = match lookup_const_fn_by_id(tcx, did) { - Some(x) => x, - None => signal!(e, NonConstPath), + + let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) { + if fn_like.constness() == hir::Constness::Const { + tcx.hir.body(fn_like.body()) + } else { + signal!(e, TypeckError) + } + } else { + signal!(e, TypeckError) + } + } else { + if tcx.sess.cstore.is_const_fn(def_id) { + tcx.sess.cstore.item_body(tcx, def_id) + } else { + signal!(e, TypeckError) + } }; let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node { @@ -434,7 +376,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, debug!("const call({:?})", call_args); let callee_cx = ConstContext { tcx: tcx, - tables: tables, + tables: tcx.typeck_tables_of(def_id), substs: substs, fn_args: Some(call_args) }; @@ -532,19 +474,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, Ok(result) } -fn resolve_trait_associated_const<'a, 'tcx: 'a>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_item_id: DefId, - default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>, - trait_id: DefId, - rcvr_substs: &'tcx Substs<'tcx> -) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> -{ - let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs)); +fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> Option<(DefId, &'tcx Substs<'tcx>)> { + let trait_item = tcx.associated_item(def_id); + let trait_id = trait_item.container.id(); + let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs)); debug!("resolve_trait_associated_const: trait_ref={:?}", trait_ref); - tcx.populate_implementations_for_trait_if_necessary(trait_id); tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), @@ -569,12 +508,20 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>( // when constructing the inference context above. match selection { traits::VtableImpl(ref impl_data) => { - let name = tcx.associated_item(trait_item_id).name; + let name = trait_item.name; let ac = tcx.associated_items(impl_data.impl_def_id) .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); match ac { - Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()), - None => default_value, + // FIXME(eddyb) Use proper Instance resolution to + // get the correct Substs returned from here. + Some(ic) => Some((ic.def_id, Substs::empty())), + None => { + if trait_item.defaultness.has_value() { + Some((def_id, substs)) + } else { + None + } + } } } _ => { @@ -615,7 +562,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, U8(u) => Ok(Char(u as char)), _ => bug!(), }, - _ => bug!(), + _ => Err(CannotCast), } } @@ -659,6 +606,11 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Bool(b) => cast_const_int(tcx, U8(b as u8), ty), Float(f) => cast_const_float(tcx, f, ty), Char(c) => cast_const_int(tcx, U32(c as u32), ty), + Variant(v) => { + let adt = tcx.adt_def(tcx.parent_def_id(v).unwrap()); + let idx = adt.variant_index_with_id(v); + cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty) + } Function(..) => Err(UnimplementedConstVal("casting fn pointers")), ByteStr(b) => match ty.sty { ty::TyRawPtr(_) => { @@ -796,21 +748,35 @@ pub fn compare_lit_exprs(&self, pub fn provide(providers: &mut Providers) { *providers = Providers { - monomorphic_const_eval, + const_eval, ..*providers }; } -fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> EvalResult<'tcx> { - let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id)); +fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + (def_id, substs): (DefId, &'tcx Substs<'tcx>)) + -> EvalResult<'tcx> { + let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, def_id, substs) { + resolved + } else { + return Err(ConstEvalErr { + span: tcx.def_span(def_id), + kind: TypeckError + }); + }; + + let cx = ConstContext { + tcx, + tables: tcx.typeck_tables_of(def_id), + substs: substs, + fn_args: None + }; let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { - ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); + tcx.mir_const_qualif(def_id); tcx.hir.body(tcx.hir.body_owned_by(id)) } else { - tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap() + tcx.sess.cstore.item_body(tcx, def_id) }; cx.eval(&body.value) } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index f20fa27dc22..aea40b85535 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -116,6 +116,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]), ConstVal::Bool(b) => write!(f, "{:?}", b), ConstVal::Char(c) => write!(f, "{:?}", c), + ConstVal::Variant(_) | ConstVal::Struct(_) | ConstVal::Tuple(_) | ConstVal::Function(..) | @@ -546,7 +547,7 @@ fn lower_variant_or_leaf( match def { Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { let enum_id = self.tcx.parent_def_id(variant_id).unwrap(); - let adt_def = self.tcx.lookup_adt_def(enum_id); + let adt_def = self.tcx.adt_def(enum_id); if adt_def.variants.len() > 1 { let substs = match ty.sty { TypeVariants::TyAdt(_, substs) => substs, @@ -587,11 +588,16 @@ fn lower_path(&mut self, let substs = self.tables.node_id_item_substs(id) .unwrap_or_else(|| tcx.intern_substs(&[])); match eval::lookup_const_by_id(tcx, def_id, substs) { - Some((const_expr, const_tables)) => { + Some((def_id, _substs)) => { // Enter the inlined constant's tables temporarily. let old_tables = self.tables; - self.tables = const_tables; - let pat = self.lower_const_expr(const_expr, pat_id, span); + self.tables = tcx.typeck_tables_of(def_id); + let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { + tcx.hir.body(tcx.hir.body_owned_by(id)) + } else { + tcx.sess.cstore.item_body(tcx, def_id) + }; + let pat = self.lower_const_expr(&body.value, pat_id, span); self.tables = old_tables; return pat; } @@ -615,7 +621,12 @@ fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> { let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables); match const_cx.eval(expr) { Ok(value) => { - PatternKind::Constant { value: value } + if let ConstVal::Variant(def_id) = value { + let ty = self.tables.expr_ty(expr); + self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![]) + } else { + PatternKind::Constant { value: value } + } } Err(e) => { self.errors.push(PatternError::ConstEval(e)); diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 26417e3ba7c..32f0fd41997 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -113,6 +113,7 @@ pub struct flock { pub l_sysid: libc::c_int, } + pub const F_RDLCK: libc::c_short = 0x0040; pub const F_UNLCK: libc::c_short = 0x0200; pub const F_WRLCK: libc::c_short = 0x0400; pub const F_SETLK: libc::c_int = 0x0080; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 7632b40ab4f..438f482fa55 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -225,6 +225,8 @@ macro_rules! controller_entry_point { sess.code_stats.borrow().print_type_sizes(); } + if ::std::env::var("SKIP_LLVM").is_ok() { ::std::process::exit(0); } + let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs); controller_entry_point!(after_llvm, @@ -810,7 +812,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, defs: resolver.definitions, analysis: ty::CrateAnalysis { access_levels: Rc::new(AccessLevels::default()), - reachable: NodeSet(), + reachable: Rc::new(NodeSet()), name: crate_name.to_string(), glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, }, @@ -889,9 +891,10 @@ macro_rules! try_with_f { let index = stability::Index::new(&hir_map); let mut local_providers = ty::maps::Providers::default(); + borrowck::provide(&mut local_providers); mir::provide(&mut local_providers); + reachable::provide(&mut local_providers); rustc_privacy::provide(&mut local_providers); - borrowck::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); reachable::provide(&mut local_providers); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 7447fba3038..147d6558e19 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -343,12 +343,12 @@ pub fn t_rptr_free(&self, nid: u32, id: u32) -> Ty<'tcx> { } pub fn t_rptr_static(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReStatic), + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_static, self.tcx().types.isize) } pub fn t_rptr_empty(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReEmpty), + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_empty, self.tcx().types.isize) } diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index a52628ceb47..64652bb308b 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -263,6 +263,41 @@ fn render_source_line(&self, draw_col_separator(buffer, line_offset, width_offset - 2); + // Special case when there's only one annotation involved, it is the start of a multiline + // span and there's no text at the beginning of the code line. Instead of doing the whole + // graph: + // + // 2 | fn foo() { + // | _^ + // 3 | | + // 4 | | } + // | |_^ test + // + // we simplify the output to: + // + // 2 | / fn foo() { + // 3 | | + // 4 | | } + // | |_^ test + if line.annotations.len() == 1 { + if let Some(ref ann) = line.annotations.get(0) { + if let AnnotationType::MultilineStart(depth) = ann.annotation_type { + if source_string[0..ann.start_col].trim() == "" { + let style = if ann.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }; + buffer.putc(line_offset, + width_offset + depth - 1, + '/', + style); + return vec![(depth, style)]; + } + } + } + } + // We want to display like this: // // vec.push(vec.pop().unwrap()); @@ -355,10 +390,8 @@ fn render_source_line(&self, for (i, annotation) in annotations.iter().enumerate() { for (j, next) in annotations.iter().enumerate() { if overlaps(next, annotation, 0) // This label overlaps with another one and both - && !annotation.is_line() // take space (they have text and are not - && !next.is_line() // multiline lines). - && annotation.has_label() - && j > i + && annotation.has_label() // take space (they have text and are not + && j > i // multiline lines). && p == 0 // We're currently on the first line, move the label one line down { // This annotation needs a new line in the output. @@ -374,7 +407,7 @@ fn render_source_line(&self, } else { 0 }; - if overlaps(next, annotation, l) // Do not allow two labels to be in the same + if (overlaps(next, annotation, l) // Do not allow two labels to be in the same // line if they overlap including padding, to // avoid situations like: // @@ -383,11 +416,18 @@ fn render_source_line(&self, // | | // fn_spanx_span // - && !annotation.is_line() // Do not add a new line if this annotation - && !next.is_line() // or the next are vertical line placeholders. && annotation.has_label() // Both labels must have some text, otherwise - && next.has_label() // they are not overlapping. + && next.has_label()) // they are not overlapping. + // Do not add a new line if this annotation + // or the next are vertical line placeholders. + || (annotation.takes_space() // If either this or the next annotation is + && next.has_label()) // multiline start/end, move it to a new line + || (annotation.has_label() // so as not to overlap the orizontal lines. + && next.takes_space()) + || (annotation.takes_space() + && next.takes_space()) { + // This annotation needs a new line in the output. p += 1; break; } @@ -397,6 +437,7 @@ fn render_source_line(&self, line_len = p; } } + if line_len != 0 { line_len += 1; } @@ -480,7 +521,7 @@ fn render_source_line(&self, }; let pos = pos + 1; - if pos > 1 && annotation.has_label() { + if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..line_offset + pos + 1 { buffer.putc(p, code_offset + annotation.start_col, @@ -514,12 +555,12 @@ fn render_source_line(&self, // After this we will have: // // 2 | fn foo() { - // | __________ starting here... + // | __________ // | | // | something about `foo` // 3 | // 4 | } - // | _ ...ending here: test + // | _ test for &(pos, annotation) in &annotations_position { let style = if annotation.is_primary { Style::LabelPrimary @@ -557,12 +598,12 @@ fn render_source_line(&self, // After this we will have: // // 2 | fn foo() { - // | ____-_____^ starting here... + // | ____-_____^ // | | // | something about `foo` // 3 | // 4 | } - // | _^ ...ending here: test + // | _^ test for &(_, annotation) in &annotations_position { let (underline, style) = if annotation.is_primary { ('^', Style::UnderlinePrimary) diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 9aa4682e1af..7401ead2208 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -63,7 +63,7 @@ pub fn as_start(&self) -> Annotation { start_col: self.start_col, end_col: self.start_col + 1, is_primary: self.is_primary, - label: Some("starting here...".to_owned()), + label: None, annotation_type: AnnotationType::MultilineStart(self.depth) } } @@ -73,10 +73,7 @@ pub fn as_end(&self) -> Annotation { start_col: self.end_col - 1, end_col: self.end_col, is_primary: self.is_primary, - label: match self.label { - Some(ref label) => Some(format!("...ending here: {}", label)), - None => Some("...ending here".to_owned()), - }, + label: self.label.clone(), annotation_type: AnnotationType::MultilineEnd(self.depth) } } @@ -106,9 +103,9 @@ pub enum AnnotationType { // Each of these corresponds to one part of the following diagram: // // x | foo(1 + bar(x, - // | _________^ starting here... < MultilineStart - // x | | y), < MultilineLine - // | |______________^ ...ending here: label < MultilineEnd + // | _________^ < MultilineStart + // x | | y), < MultilineLine + // | |______________^ label < MultilineEnd // x | z); /// Annotation marking the first character of a fully shown multiline span MultilineStart(usize), @@ -189,6 +186,15 @@ pub fn has_label(&self) -> bool { false } } + + pub fn takes_space(&self) -> bool { + // Multiline annotations always have to keep vertical space. + match self.annotation_type { + AnnotationType::MultilineStart(_) | + AnnotationType::MultilineEnd(_) => true, + _ => false, + } + } } #[derive(Debug)] diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 0ee9d4a42c7..c8644820ac0 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -118,7 +118,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { hir::ItemStruct(..) | hir::ItemUnion(..) => { let def_id = cx.tcx.hir.local_def_id(it.id); - self.check_heap_type(cx, it.span, cx.tcx.item_type(def_id)) + self.check_heap_type(cx, it.span, cx.tcx.type_of(def_id)) } _ => () } @@ -130,7 +130,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { for struct_field in struct_def.fields() { let def_id = cx.tcx.hir.local_def_id(struct_field.id); self.check_heap_type(cx, struct_field.span, - cx.tcx.item_type(def_id)); + cx.tcx.type_of(def_id)); } } _ => (), @@ -504,21 +504,21 @@ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { if ast_generics.is_parameterized() { return; } - let def = cx.tcx.lookup_adt_def(cx.tcx.hir.local_def_id(item.id)); + let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id)); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } hir::ItemUnion(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } - let def = cx.tcx.lookup_adt_def(cx.tcx.hir.local_def_id(item.id)); + let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id)); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } hir::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } - let def = cx.tcx.lookup_adt_def(cx.tcx.hir.local_def_id(item.id)); + let def = cx.tcx.adt_def(cx.tcx.hir.local_def_id(item.id)); (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[]))) } _ => return, @@ -582,10 +582,10 @@ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { }; if self.impling_types.is_none() { - let debug_def = cx.tcx.lookup_trait_def(debug); + let debug_def = cx.tcx.trait_def(debug); let mut impls = NodeSet(); debug_def.for_each_impl(cx.tcx, |d| { - if let Some(ty_def) = cx.tcx.item_type(d).ty_to_def_id() { + if let Some(ty_def) = cx.tcx.type_of(d).ty_to_def_id() { if let Some(node_id) = cx.tcx.hir.as_local_node_id(ty_def) { impls.insert(node_id); } @@ -1094,7 +1094,7 @@ fn get_transmute_from_to<'a, 'tcx> } fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { - match cx.tcx.item_type(def_id).sty { + match cx.tcx.type_of(def_id).sty { ty::TyFnDef(.., bfty) if bfty.abi() == RustIntrinsic => (), _ => return false, } @@ -1151,8 +1151,8 @@ fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) { if let hir::ItemUnion(ref vdata, _) = item.node { let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); for field in vdata.fields() { - let field_ty = ctx.tcx.item_type(ctx.tcx.hir.local_def_id(field.id)); - if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) { + let field_ty = ctx.tcx.type_of(ctx.tcx.hir.local_def_id(field.id)); + if field_ty.needs_drop(ctx.tcx, param_env) { ctx.span_lint(UNIONS_WITH_DROP_FIELDS, field.span, "union contains a field with possibly non-trivial drop code, \ diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 3e60d8a5ada..c2181c9764c 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -660,7 +660,7 @@ fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) { fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) { let def_id = self.cx.tcx.hir.local_def_id(id); - let sig = self.cx.tcx.item_type(def_id).fn_sig(); + let sig = self.cx.tcx.type_of(def_id).fn_sig(); let sig = self.cx.tcx.erase_late_bound_regions(&sig); for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) { @@ -677,7 +677,7 @@ fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) { fn check_foreign_static(&mut self, id: ast::NodeId, span: Span) { let def_id = self.cx.tcx.hir.local_def_id(id); - let ty = self.cx.tcx.item_type(def_id); + let ty = self.cx.tcx.type_of(def_id); self.check_type_for_ffi_and_report_errors(span, ty); } } @@ -724,7 +724,7 @@ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types - let t = cx.tcx.item_type(cx.tcx.hir.local_def_id(it.id)); + let t = cx.tcx.type_of(cx.tcx.hir.local_def_id(it.id)); let layout = cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx| { let ty = cx.tcx.erase_regions(&t); ty.layout(&infcx).unwrap_or_else(|e| { diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index a8def4bafd8..3fd75146193 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -17,30 +17,24 @@ use build_helper::output; -fn detect_llvm_link(llvm_config: &Path) -> (&'static str, Option<&'static str>) { - let mut version_cmd = Command::new(llvm_config); - version_cmd.arg("--version"); - let version_output = output(&mut version_cmd); - let mut parts = version_output.split('.').take(2) - .filter_map(|s| s.parse::().ok()); - if let (Some(major), Some(minor)) = (parts.next(), parts.next()) { - if major > 3 || (major == 3 && minor >= 9) { - // Force the link mode we want, preferring static by default, but - // possibly overridden by `configure --enable-llvm-link-shared`. - if env::var_os("LLVM_LINK_SHARED").is_some() { - return ("dylib", Some("--link-shared")); - } else { - return ("static", Some("--link-static")); - } - } else if major == 3 && minor == 8 { - // Find out LLVM's default linking mode. - let mut mode_cmd = Command::new(llvm_config); - mode_cmd.arg("--shared-mode"); - if output(&mut mode_cmd).trim() == "shared" { - return ("dylib", None); - } else { - return ("static", None); - } +fn detect_llvm_link(major: u32, minor: u32, llvm_config: &Path) + -> (&'static str, Option<&'static str>) { + if major > 3 || (major == 3 && minor >= 9) { + // Force the link mode we want, preferring static by default, but + // possibly overridden by `configure --enable-llvm-link-shared`. + if env::var_os("LLVM_LINK_SHARED").is_some() { + return ("dylib", Some("--link-shared")); + } else { + return ("static", Some("--link-static")); + } + } else if major == 3 && minor == 8 { + // Find out LLVM's default linking mode. + let mut mode_cmd = Command::new(llvm_config); + mode_cmd.arg("--shared-mode"); + if output(&mut mode_cmd).trim() == "shared" { + return ("dylib", None); + } else { + return ("static", None); } } ("static", None) @@ -92,9 +86,25 @@ fn main() { let host = env::var("HOST").expect("HOST was not set"); let is_crossed = target != host; - let optional_components = - ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430", - "sparc", "nvptx"]; + let mut optional_components = + vec!["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", + "systemz", "jsbackend", "msp430", "sparc", "nvptx"]; + + let mut version_cmd = Command::new(&llvm_config); + version_cmd.arg("--version"); + let version_output = output(&mut version_cmd); + let mut parts = version_output.split('.').take(2) + .filter_map(|s| s.parse::().ok()); + let (major, minor) = + if let (Some(major), Some(minor)) = (parts.next(), parts.next()) { + (major, minor) + } else { + (3, 7) + }; + + if major > 3 { + optional_components.push("hexagon"); + } // FIXME: surely we don't need all these components, right? Stuff like mcjit // or interpreter the compiler itself never uses. @@ -158,7 +168,7 @@ fn main() { .cpp_link_stdlib(None) // we handle this below .compile("librustllvm.a"); - let (llvm_kind, llvm_link_arg) = detect_llvm_link(&llvm_config); + let (llvm_kind, llvm_link_arg) = detect_llvm_link(major, minor, &llvm_config); // Link in all LLVM libraries, if we're uwring the "wrong" llvm-config then // we don't pick up system libs because unfortunately they're for the host @@ -268,4 +278,8 @@ fn main() { if target.contains("windows") { println!("cargo:rustc-link-lib=ole32"); } + if target.contains("windows-gnu") { + println!("cargo:rustc-link-lib=static-nobundle=gcc_s"); + println!("cargo:rustc-link-lib=static-nobundle=pthread"); + } } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index f300bf16145..c9b3a7ff3f3 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -29,6 +29,7 @@ #![feature(link_args)] #![feature(staged_api)] #![feature(rustc_private)] +#![feature(static_nobundle)] extern crate libc; #[macro_use] @@ -381,6 +382,12 @@ fn init() { } LLVMInitializeNVPTXTarget, LLVMInitializeNVPTXTargetMC, LLVMInitializeNVPTXAsmPrinter); + init_target!(llvm_component = "hexagon", + LLVMInitializeHexagonTargetInfo, + LLVMInitializeHexagonTarget, + LLVMInitializeHexagonTargetMC, + LLVMInitializeHexagonAsmPrinter, + LLVMInitializeHexagonAsmParser); } pub fn last_error() -> Option { diff --git a/src/librustc_lsan/build.rs b/src/librustc_lsan/build.rs index 005163f4102..da53571a243 100644 --- a/src/librustc_lsan/build.rs +++ b/src/librustc_lsan/build.rs @@ -12,14 +12,13 @@ extern crate cmake; use std::env; -use build_helper::native_lib_boilerplate; +use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { - let native = match native_lib_boilerplate("compiler-rt", "lsan", "clang_rt.lsan-x86_64", - "build/lib/linux") { + let native = match sanitizer_lib_boilerplate("lsan") { Ok(native) => native, _ => return, }; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index a8ee999505e..966e814e337 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -326,6 +326,7 @@ fn register_crate(&mut self, cnum_map: RefCell::new(cnum_map), cnum: cnum, codemap_import_info: RefCell::new(vec![]), + attribute_cache: RefCell::new([Vec::new(), Vec::new()]), dep_kind: Cell::new(dep_kind), source: cstore::CrateSource { dylib: dylib, @@ -798,11 +799,26 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) { fn inject_sanitizer_runtime(&mut self) { if let Some(ref sanitizer) = self.sess.opts.debugging_opts.sanitizer { - // Sanitizers can only be used with x86_64 Linux executables linked - // to `std` - if self.sess.target.target.llvm_target != "x86_64-unknown-linux-gnu" { - self.sess.err(&format!("Sanitizers only work with the \ - `x86_64-unknown-linux-gnu` target.")); + // Sanitizers can only be used on some tested platforms with + // executables linked to `std` + const ASAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu", + "x86_64-apple-darwin"]; + const TSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu", + "x86_64-apple-darwin"]; + const LSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"]; + const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"]; + + let supported_targets = match *sanitizer { + Sanitizer::Address => ASAN_SUPPORTED_TARGETS, + Sanitizer::Thread => TSAN_SUPPORTED_TARGETS, + Sanitizer::Leak => LSAN_SUPPORTED_TARGETS, + Sanitizer::Memory => MSAN_SUPPORTED_TARGETS, + }; + if !supported_targets.contains(&&*self.sess.target.target.llvm_target) { + self.sess.err(&format!("{:?}Sanitizer only works with the `{}` target", + sanitizer, + supported_targets.join("` or `") + )); return } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 17a6a706e0a..72ad1d75a56 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -72,6 +72,7 @@ pub struct CrateMetadata { pub cnum_map: RefCell, pub cnum: CrateNum, pub codemap_import_info: RefCell>, + pub attribute_cache: RefCell<[Vec>>; 2]>, pub root: schema::CrateRoot, @@ -269,7 +270,7 @@ pub fn disambiguator(&self) -> Symbol { } pub fn is_staged_api(&self) -> bool { - for attr in self.get_item_attrs(CRATE_DEF_INDEX) { + for attr in self.get_item_attrs(CRATE_DEF_INDEX).iter() { if attr.path == "stable" || attr.path == "unstable" { return true; } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 3239dfb937b..ddb3332be37 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -69,10 +69,10 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) { } provide! { <'tcx> tcx, def_id, cdata - ty => { cdata.get_type(def_id.index, tcx) } - generics => { tcx.alloc_generics(cdata.get_generics(def_id.index)) } - predicates => { cdata.get_predicates(def_id.index, tcx) } - super_predicates => { cdata.get_super_predicates(def_id.index, tcx) } + type_of => { cdata.get_type(def_id.index, tcx) } + generics_of => { tcx.alloc_generics(cdata.get_generics(def_id.index)) } + predicates_of => { cdata.get_predicates(def_id.index, tcx) } + super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) } trait_def => { tcx.alloc_trait_def(cdata.get_trait_def(def_id.index)) } @@ -81,7 +81,7 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) { let _ = cdata; tcx.calculate_dtor(def_id, &mut |_,_| Ok(())) } - variances => { Rc::new(cdata.get_item_variances(def_id.index)) } + variances_of => { Rc::new(cdata.get_item_variances(def_id.index)) } associated_item_def_ids => { let mut result = vec![]; cdata.each_child_of_item(def_id.index, |child| result.push(child.def.def_id())); @@ -89,6 +89,7 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) { } associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } + impl_polarity => { cdata.get_impl_polarity(def_id.index) } coerce_unsized_info => { cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); @@ -107,10 +108,11 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) { mir } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } - typeck_tables => { cdata.item_body_tables(def_id.index, tcx) } + typeck_tables_of => { cdata.item_body_tables(def_id.index, tcx) } closure_kind => { cdata.closure_kind(def_id.index) } closure_type => { cdata.closure_ty(def_id.index, tcx) } inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } + is_foreign_item => { cdata.is_foreign_item(def_id.index) } } impl CrateStore for cstore::CStore { @@ -148,7 +150,7 @@ fn item_generics_cloned(&self, def: DefId) -> ty::Generics { self.get_crate_data(def.krate).get_generics(def.index) } - fn item_attrs(&self, def_id: DefId) -> Vec + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { self.dep_graph.read(DepNode::MetaData(def_id)); self.get_crate_data(def_id.krate).get_item_attrs(def_id.index) @@ -176,10 +178,10 @@ fn implementations_of_trait(&self, filter: Option) -> Vec result } - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness { self.dep_graph.read(DepNode::MetaData(def)); - self.get_crate_data(def.krate).get_impl_polarity(def.index) + self.get_crate_data(def.krate).get_impl_defaultness(def.index) } fn impl_parent(&self, impl_def: DefId) -> Option { @@ -405,7 +407,7 @@ fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro { // Mark the attrs as used let attrs = data.get_item_attrs(id.index); - for attr in &attrs { + for attr in attrs.iter() { attr::mark_used(attr); } @@ -418,25 +420,24 @@ fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro { ident: ast::Ident::with_empty_ctxt(name), id: ast::DUMMY_NODE_ID, span: local_span, - attrs: attrs, + attrs: attrs.iter().cloned().collect(), node: ast::ItemKind::MacroDef(body.into()), vis: ast::Visibility::Inherited, }) } - fn maybe_get_item_body<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Option<&'tcx hir::Body> - { + fn item_body<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> &'tcx hir::Body { if let Some(cached) = tcx.hir.get_inlined_body(def_id) { - return Some(cached); + return cached; } self.dep_graph.read(DepNode::MetaData(def_id)); - debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id)); + debug!("item_body({}): inlining item", tcx.item_path_str(def_id)); - self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index) + self.get_crate_data(def_id.krate).item_body(tcx, def_id.index) } fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index fac6079529e..37913dad7ee 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -31,6 +31,7 @@ use std::collections::BTreeMap; use std::io; use std::mem; +use std::rc::Rc; use std::str; use std::u32; @@ -366,7 +367,7 @@ fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice>, Self::Erro impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::AdtDef> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx ty::AdtDef, Self::Error> { let def_id = DefId::decode(self)?; - Ok(self.tcx().lookup_adt_def(def_id)) + Ok(self.tcx().adt_def(def_id)) } } @@ -628,6 +629,10 @@ pub fn get_impl_polarity(&self, id: DefIndex) -> hir::ImplPolarity { self.get_impl_data(id).polarity } + pub fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness { + self.get_impl_data(id).defaultness + } + pub fn get_coerce_unsized_info(&self, id: DefIndex) -> Option { @@ -749,16 +754,15 @@ pub fn each_child_of_item(&self, id: DefIndex, mut callback: F) } } - pub fn maybe_get_item_body(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: DefIndex) - -> Option<&'tcx hir::Body> { - if self.is_proc_macro(id) { return None; } - self.entry(id).ast.map(|ast| { - let def_id = self.local_def_id(id); - let body = ast.decode(self).body.decode(self); - tcx.hir.intern_inlined_body(def_id, body) - }) + pub fn item_body(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: DefIndex) + -> &'tcx hir::Body { + assert!(!self.is_proc_macro(id)); + let ast = self.entry(id).ast.unwrap(); + let def_id = self.local_def_id(id); + let body = ast.decode(self).body.decode(self); + tcx.hir.intern_inlined_body(def_id, body) } pub fn item_body_tables(&self, @@ -859,10 +863,18 @@ pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option { } } - pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec { + pub fn get_item_attrs(&self, node_id: DefIndex) -> Rc<[ast::Attribute]> { + let (node_as, node_index) = + (node_id.address_space().index(), node_id.as_array_index()); if self.is_proc_macro(node_id) { - return Vec::new(); + return Rc::new([]); } + + if let Some(&Some(ref val)) = + self.attribute_cache.borrow()[node_as].get(node_index) { + return val.clone(); + } + // The attributes for a tuple struct are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition @@ -871,7 +883,13 @@ pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec { if def_key.disambiguated_data.data == DefPathData::StructCtor { item = self.entry(def_key.parent.unwrap()); } - self.get_attributes(&item) + let result = Rc::__from_array(self.get_attributes(&item).into_boxed_slice()); + let vec_ = &mut self.attribute_cache.borrow_mut()[node_as]; + if vec_.len() < node_index + 1 { + vec_.resize(node_index + 1, None); + } + vec_[node_index] = Some(result.clone()); + result } pub fn get_struct_field_names(&self, id: DefIndex) -> Vec { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ce9f0a73fe2..3676e5a7f0f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -36,7 +36,7 @@ use syntax::codemap::Spanned; use syntax::attr; use syntax::symbol::Symbol; -use syntax_pos::{self, DUMMY_SP}; +use syntax_pos; use rustc::hir::{self, PatKind}; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -242,12 +242,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq { debug!("EntryBuilder::encode_item_variances({:?})", def_id); let tcx = self.tcx; - self.lazy_seq_from_slice(&tcx.item_variances(def_id)) + self.lazy_seq_from_slice(&tcx.variances_of(def_id)) } fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - let ty = tcx.item_type(def_id); + let ty = tcx.type_of(def_id); debug!("EntryBuilder::encode_item_type({:?}) => {:?}", def_id, ty); self.lazy(&ty) } @@ -261,7 +261,7 @@ fn encode_enum_variant_info(&mut self, (enum_did, Untracked(index)): (DefId, Untracked)) -> Entry<'tcx> { let tcx = self.tcx; - let def = tcx.lookup_adt_def(enum_did); + let def = tcx.adt_def(enum_did); let variant = &def.variants[index]; let def_id = variant.did; debug!("EntryBuilder::encode_enum_variant_info({:?})", def_id); @@ -341,7 +341,7 @@ fn encode_info_for_mod(&mut self, impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { fn encode_fields(&mut self, adt_def_id: DefId) { - let def = self.tcx.lookup_adt_def(adt_def_id); + let def = self.tcx.adt_def(adt_def_id); for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, @@ -365,7 +365,7 @@ fn encode_field(&mut self, usize)>)) -> Entry<'tcx> { let tcx = self.tcx; - let variant = &tcx.lookup_adt_def(adt_def_id).variants[variant_index]; + let variant = &tcx.adt_def(adt_def_id).variants[variant_index]; let field = &variant.fields[field_index]; let def_id = field.did; @@ -397,7 +397,7 @@ fn encode_field(&mut self, fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<'tcx> { debug!("EntryBuilder::encode_struct_ctor({:?})", def_id); let tcx = self.tcx; - let variant = tcx.lookup_adt_def(adt_def_id).struct_variant(); + let variant = tcx.adt_def(adt_def_id).struct_variant(); let data = VariantData { ctor_kind: variant.ctor_kind, @@ -439,13 +439,13 @@ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry< fn encode_generics(&mut self, def_id: DefId) -> Lazy { debug!("EntryBuilder::encode_generics({:?})", def_id); let tcx = self.tcx; - self.lazy(tcx.item_generics(def_id)) + self.lazy(tcx.generics_of(def_id)) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { debug!("EntryBuilder::encode_predicates({:?})", def_id); let tcx = self.tcx; - self.lazy(&tcx.item_predicates(def_id)) + self.lazy(&tcx.predicates_of(def_id)) } fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { @@ -547,7 +547,7 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { let kind = match impl_item.kind { ty::AssociatedKind::Const => { EntryKind::AssociatedConst(container, - ty::queries::mir_const_qualif::get(self.tcx, ast_item.span, def_id)) + self.tcx.at(ast_item.span).mir_const_qualif(def_id)) } ty::AssociatedKind::Method => { let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { @@ -570,7 +570,7 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { let (ast, mir) = if let hir::ImplItemKind::Const(_, body) = ast_item.node { (Some(body), true) } else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { - let generics = self.tcx.item_generics(def_id); + let generics = self.tcx.generics_of(def_id); let types = generics.parent_types as usize + generics.types.len(); let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs); let is_const_fn = sig.constness == hir::Constness::Const; @@ -656,7 +656,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic, hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic, hir::ItemConst(..) => { - EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, item.span, def_id)) + EntryKind::Const(tcx.at(item.span).mir_const_qualif(def_id)) } hir::ItemFn(_, _, constness, .., body) => { let data = FnData { @@ -674,7 +674,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> hir::ItemTy(..) => EntryKind::Type, hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)), hir::ItemStruct(ref struct_def, _) => { - let variant = tcx.lookup_adt_def(def_id).struct_variant(); + let variant = tcx.adt_def(def_id).struct_variant(); // Encode def_ids for each field and method // for methods, write all the stuff get_trait_method @@ -694,7 +694,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> }), repr_options) } hir::ItemUnion(..) => { - let variant = tcx.lookup_adt_def(def_id).struct_variant(); + let variant = tcx.adt_def(def_id).struct_variant(); let repr_options = get_repr_options(&tcx, def_id); EntryKind::Union(self.lazy(&VariantData { @@ -706,6 +706,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> hir::ItemDefaultImpl(..) => { let data = ImplData { polarity: hir::ImplPolarity::Positive, + defaultness: hir::Defaultness::Final, parent_impl: None, coerce_unsized_info: None, trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)), @@ -713,10 +714,10 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> EntryKind::DefaultImpl(self.lazy(&data)) } - hir::ItemImpl(_, polarity, ..) => { + hir::ItemImpl(_, polarity, defaultness, ..) => { let trait_ref = tcx.impl_trait_ref(def_id); let parent = if let Some(trait_ref) = trait_ref { - let trait_def = tcx.lookup_trait_def(trait_ref.def_id); + let trait_def = tcx.trait_def(trait_ref.def_id); trait_def.ancestors(def_id).skip(1).next().and_then(|node| { match node { specialization_graph::Node::Impl(parent) => Some(parent), @@ -732,7 +733,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> let coerce_unsized_info = trait_ref.and_then(|t| { if Some(t.def_id) == tcx.lang_items.coerce_unsized_trait() { - Some(ty::queries::coerce_unsized_info::get(tcx, item.span, def_id)) + Some(tcx.at(item.span).coerce_unsized_info(def_id)) } else { None } @@ -740,6 +741,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> let data = ImplData { polarity: polarity, + defaultness: defaultness, parent_impl: parent, coerce_unsized_info: coerce_unsized_info, trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)), @@ -748,12 +750,12 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> EntryKind::Impl(self.lazy(&data)) } hir::ItemTrait(..) => { - let trait_def = tcx.lookup_trait_def(def_id); + let trait_def = tcx.trait_def(def_id); let data = TraitData { unsafety: trait_def.unsafety, paren_sugar: trait_def.paren_sugar, has_default_impl: tcx.trait_has_default_impl(def_id), - super_predicates: self.lazy(&tcx.item_super_predicates(def_id)), + super_predicates: self.lazy(&tcx.super_predicates_of(def_id)), }; EntryKind::Trait(self.lazy(&data)) @@ -774,7 +776,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> .map(|foreign_item| tcx.hir.local_def_id(foreign_item.id).index)) } hir::ItemEnum(..) => { - let def = self.tcx.lookup_adt_def(def_id); + let def = self.tcx.adt_def(def_id); self.lazy_seq(def.variants.iter().map(|v| { assert!(v.did.is_local()); v.did.index @@ -782,7 +784,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> } hir::ItemStruct(..) | hir::ItemUnion(..) => { - let def = self.tcx.lookup_adt_def(def_id); + let def = self.tcx.adt_def(def_id); self.lazy_seq(def.struct_variant().fields.iter().map(|f| { assert!(f.did.is_local()); f.did.index @@ -919,7 +921,7 @@ fn encode_addl_info_for_item(&mut self, item: &hir::Item) { hir::ItemEnum(..) => { self.encode_fields(def_id); - let def = self.tcx.lookup_adt_def(def_id); + let def = self.tcx.adt_def(def_id); for (i, variant) in def.variants.iter().enumerate() { self.record(variant.did, EntryBuilder::encode_enum_variant_info, @@ -1169,7 +1171,7 @@ fn encode_info_for_embedded_const(&mut self, def_id: DefId) -> Entry<'tcx> { let body = tcx.hir.body_owned_by(id); Entry { - kind: EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id)), + kind: EntryKind::Const(tcx.mir_const_qualif(def_id)), visibility: self.lazy(&ty::Visibility::Public), span: self.lazy(&tcx.def_span(def_id)), attributes: LazySeq::empty(), @@ -1539,7 +1541,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } pub fn get_repr_options<'a, 'tcx, 'gcx>(tcx: &TyCtxt<'a, 'tcx, 'gcx>, did: DefId) -> ReprOptions { - let ty = tcx.item_type(did); + let ty = tcx.type_of(did); match ty.sty { ty::TyAdt(ref def, _) => return def.repr, _ => bug!("{} is not an ADT", ty), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 2f2e0e125ae..5870903e771 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -406,6 +406,7 @@ pub struct TraitData<'tcx> { #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, + pub defaultness: hir::Defaultness, pub parent_impl: Option, /// This is `Some` only for impls of `CoerceUnsized`. @@ -415,6 +416,7 @@ pub struct ImplData<'tcx> { impl_stable_hash_for!(struct ImplData<'tcx> { polarity, + defaultness, parent_impl, coerce_unsized_info, trait_ref diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 5fece4d6a5d..0833342927f 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -280,7 +280,7 @@ pub fn perform_test(&mut self, assert!(ty.is_slice()); let array_ty = tcx.mk_array(tcx.types.u8, bytes.len()); - let array_ref = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), array_ty); + let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty); let array = self.literal_operand(test.span, array_ref, Literal::Value { value: value.clone() }); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index dd4190a412d..95b20560c62 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -784,7 +784,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, TerminatorKind::Call { func: Operand::Constant(Constant { span: data.span, - ty: tcx.item_type(free_func).subst(tcx, substs), + ty: tcx.type_of(free_func).subst(tcx, substs), literal: Literal::Value { value: ConstVal::Function(free_func, substs), } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index b7de50efe34..7b267fa276b 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -593,7 +593,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprRepeat(ref v, count) => { let c = &cx.tcx.hir.body(count).value; let def_id = cx.tcx.hir.body_owner_def_id(count); - let count = match ty::queries::monomorphic_const_eval::get(cx.tcx, c.span, def_id) { + let substs = Substs::empty(); + let count = match cx.tcx.at(c.span).const_eval((def_id, substs)) { Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 5f9fb8e1b12..e73eaafc4b9 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -140,7 +140,7 @@ pub fn trait_method(&mut self, let substs = self.tcx.mk_substs_trait(self_ty, params); for item in self.tcx.associated_items(trait_def_id) { if item.kind == ty::AssociatedKind::Method && item.name == method_name { - let method_ty = self.tcx.item_type(item.def_id); + let method_ty = self.tcx.type_of(item.def_id); let method_ty = method_ty.subst(self.tcx, substs); return (method_ty, Literal::Value { @@ -168,7 +168,7 @@ pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool { type with inference types/regions", ty); }); - self.tcx.type_needs_drop_given_env(ty, &self.infcx.parameter_environment) + ty.needs_drop(self.tcx.global_tcx(), &self.infcx.parameter_environment) } pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 9dfe1a34c9c..77f5c8ff124 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -139,7 +139,7 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) // types/lifetimes replaced) let fn_sig = cx.tables().liberated_fn_sigs[&id].clone(); - let ty = tcx.item_type(tcx.hir.local_def_id(id)); + let ty = tcx.type_of(tcx.hir.local_def_id(id)); let mut abi = fn_sig.abi; let implicit_argument = if let ty::TyClosure(..) = ty.sty { // HACK(eddyb) Avoid having RustCall on closures, diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 4d70540a7c6..9e57472c236 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -167,7 +167,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, } else { param_env.free_substs }; - let fn_ty = tcx.item_type(def_id).subst(tcx, substs); + let fn_ty = tcx.type_of(def_id).subst(tcx, substs); let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); let span = tcx.def_span(def_id); @@ -290,7 +290,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, call_kind={:?}, untuple_args={:?})", def_id, rcvr_adjustment, call_kind, untuple_args); - let fn_ty = tcx.item_type(def_id).subst(tcx, param_env.free_substs); + let fn_ty = tcx.type_of(def_id).subst(tcx, param_env.free_substs); let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig()); let span = tcx.def_span(def_id); @@ -308,10 +308,9 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, Adjustment::Deref => Operand::Consume(rcvr_l.deref()), Adjustment::RefMut => { // let rcvr = &mut rcvr; - let re_erased = tcx.mk_region(ty::ReErased); let ref_rcvr = local_decls.push(temp_decl( Mutability::Not, - tcx.mk_ref(re_erased, ty::TypeAndMut { + tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::MutMutable }), @@ -321,7 +320,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, source_info: source_info, kind: StatementKind::Assign( Lvalue::Local(ref_rcvr), - Rvalue::Ref(re_erased, BorrowKind::Mut, rcvr_l) + Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, rcvr_l) ) }); Operand::Consume(Lvalue::Local(ref_rcvr)) @@ -333,7 +332,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, CallKind::Direct(def_id) => ( Operand::Constant(Constant { span: span, - ty: tcx.item_type(def_id).subst(tcx, param_env.free_substs), + ty: tcx.type_of(def_id).subst(tcx, param_env.free_substs), literal: Literal::Value { value: ConstVal::Function(def_id, param_env.free_substs), }, @@ -423,7 +422,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, { let tcx = infcx.tcx; let def_id = tcx.hir.local_def_id(ctor_id); - let sig = match tcx.item_type(def_id).sty { + let sig = match tcx.type_of(def_id).sty { ty::TyFnDef(_, _, fty) => tcx.no_late_bound_regions(&fty) .expect("LBR in ADT constructor signature"), _ => bug!("unexpected type for ctor {:?}", def_id) diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 0f869e7ed02..5cc5cf29793 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -13,7 +13,7 @@ //! care erasing regions all over the place. use rustc::ty::subst::Substs; -use rustc::ty::{Ty, TyCtxt, ReErased, ClosureSubsts}; +use rustc::ty::{Ty, TyCtxt, ClosureSubsts}; use rustc::mir::*; use rustc::mir::visit::MutVisitor; use rustc::mir::transform::{MirPass, MirSource, Pass}; @@ -43,7 +43,7 @@ fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>) { fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { match *rvalue { Rvalue::Ref(ref mut r, _, _) => { - *r = self.tcx.mk_region(ReErased); + *r = self.tcx.types.re_erased; } Rvalue::Use(..) | Rvalue::Repeat(..) | diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index ac2bdaad24f..45bdff9195c 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -357,7 +357,7 @@ fn should_inline(&self, callsite: CallSite<'tcx>, // a regular goto. let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs); let ty = ty.to_ty(tcx); - if tcx.type_needs_drop_given_env(ty, ¶m_env) { + if ty.needs_drop(tcx, ¶m_env) { cost += CALL_PENALTY; if let Some(unwind) = unwind { work_list.push(unwind); @@ -497,7 +497,7 @@ fn dest_needs_borrow(lval: &Lvalue) -> bool { let dest = if dest_needs_borrow(&destination.0) { debug!("Creating temp for return destination"); let dest = Rvalue::Ref( - self.tcx.mk_region(ty::ReErased), + self.tcx.types.re_erased, BorrowKind::Mut, destination.0); @@ -582,7 +582,7 @@ fn dest_needs_borrow(lval: &Lvalue) -> bool { fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>, callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> { let arg = Rvalue::Ref( - self.tcx.mk_region(ty::ReErased), + self.tcx.types.re_erased, BorrowKind::Mut, arg.deref()); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 1313b24fa74..afb775aa01e 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -80,10 +80,10 @@ impl<'a, 'tcx> Qualif { fn restrict(&mut self, ty: Ty<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: &ty::ParameterEnvironment<'tcx>) { - if !ty.type_contents(tcx).interior_unsafe() { + if ty.is_freeze(tcx, param_env, DUMMY_SP) { *self = *self - Qualif::MUTABLE_INTERIOR; } - if !tcx.type_needs_drop_given_env(ty, param_env) { + if !ty.needs_drop(tcx, param_env) { *self = *self - Qualif::NEEDS_DROP; } } @@ -258,7 +258,7 @@ fn find_drop_implementation_method_span(&self) -> Option { let mut span = None; self.tcx - .lookup_trait_def(drop_trait_id) + .trait_def(drop_trait_id) .for_each_relevant_impl(self.tcx, self.mir.return_ty, |impl_did| { self.tcx.hir .as_local_node_id(impl_did) @@ -573,9 +573,7 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { if substs.types().next().is_some() { self.add_type(constant.ty); } else { - let bits = ty::queries::mir_const_qualif::get(self.tcx, - constant.span, - def_id); + let bits = self.tcx.at(constant.span).mir_const_qualif(def_id); let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif"); self.add(qualif); @@ -959,7 +957,7 @@ fn run_pass<'a>(&mut self, let src = MirSource::from_node(tcx, id); if let MirSource::Const(_) = src { - ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); + tcx.mir_const_qualif(def_id); continue; } diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 0a8f147b214..ef7990653ba 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -124,6 +124,8 @@ pub fn simplify(mut self) { self.collapse_goto_chain(successor, &mut changed); } + changed |= self.simplify_unwind(&mut terminator); + let mut new_stmts = vec![]; let mut inner_changed = true; while inner_changed { @@ -238,6 +240,38 @@ fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool { true } + // turn an unwind branch to a resume block into a None + fn simplify_unwind(&mut self, terminator: &mut Terminator<'tcx>) -> bool { + let unwind = match terminator.kind { + TerminatorKind::Drop { ref mut unwind, .. } | + TerminatorKind::DropAndReplace { ref mut unwind, .. } | + TerminatorKind::Call { cleanup: ref mut unwind, .. } | + TerminatorKind::Assert { cleanup: ref mut unwind, .. } => + unwind, + _ => return false + }; + + if let &mut Some(unwind_block) = unwind { + let is_resume_block = match self.basic_blocks[unwind_block] { + BasicBlockData { + ref statements, + terminator: Some(Terminator { + kind: TerminatorKind::Resume, .. + }), .. + } if statements.is_empty() => true, + _ => false + }; + if is_resume_block { + debug!("simplifying unwind to {:?} from {:?}", + unwind_block, terminator.source_info); + *unwind = None; + } + return is_resume_block; + } + + false + } + fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index bfb08de56d8..d2e4c1a9649 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -133,7 +133,7 @@ fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> Lval Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty }, Lvalue::Static(box Static { def_id, ty: sty }) => { let sty = self.sanitize_type(lvalue, sty); - let ty = self.tcx().item_type(def_id); + let ty = self.tcx().type_of(def_id); let ty = self.cx.normalize(&ty); if let Err(terr) = self.cx.eq_types(self.last_span, ty, sty) { span_mirbug!( diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 04a1fc891cf..9d7c7ec63cf 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -277,8 +277,7 @@ fn drop_ladder<'a>(&mut self, let mut fields = fields; fields.retain(|&(ref lvalue, _)| { - self.tcx().type_needs_drop_given_env( - self.lvalue_ty(lvalue), self.elaborator.param_env()) + self.lvalue_ty(lvalue).needs_drop(self.tcx(), self.elaborator.param_env()) }); debug!("drop_ladder - fields needing drop: {:?}", fields); @@ -507,8 +506,7 @@ fn destructor_call_block<'a>(&mut self, (succ, unwind): (BasicBlock, Option(&mut self, (succ, unwind): (BasicBlock, Option native, _ => return, }; diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 2c4439f80a2..f275b4cafaf 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -46,7 +46,7 @@ use rustc::hir::{self, PatKind, RangeEnd}; use syntax::ast; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use std::collections::hash_map::Entry; @@ -85,11 +85,11 @@ fn check_const_eval(&self, expr: &'gcx hir::Expr) { // Adds the worst effect out of all the values of one type. fn add_type(&mut self, ty: Ty<'gcx>) { - if ty.type_contents(self.tcx).interior_unsafe() { + if !ty.is_freeze(self.tcx, &self.param_env, DUMMY_SP) { self.promotable = false; } - if self.tcx.type_needs_drop_given_env(ty, &self.param_env) { + if ty.needs_drop(self.tcx, &self.param_env) { self.promotable = false; } } @@ -130,7 +130,7 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) { }; let outer_tables = self.tables; - self.tables = self.tcx.item_tables(self.tcx.hir.local_def_id(item_id)); + self.tables = self.tcx.typeck_tables_of(self.tcx.hir.local_def_id(item_id)); let body = self.tcx.hir.body(body_id); if !self.in_fn { diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 92f7e48b6be..82c91727293 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -13,8 +13,8 @@ #![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/")] + 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)] @@ -30,7 +30,6 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::DeepVisitor; -use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::lint; use rustc::middle::privacy::{AccessLevel, AccessLevels}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; @@ -38,7 +37,7 @@ use rustc::ty::maps::Providers; use rustc::util::nodemap::NodeSet; use syntax::ast; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::Span; use std::cmp; use std::mem::replace; @@ -88,7 +87,7 @@ struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> { impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { fn item_ty_level(&self, item_def_id: DefId) -> Option { - let ty_def_id = match self.tcx.item_type(item_def_id).sty { + let ty_def_id = match self.tcx.type_of(item_def_id).sty { ty::TyAdt(adt, _) => adt.did, ty::TyDynamic(ref obj, ..) if obj.principal().is_some() => obj.principal().unwrap().def_id(), @@ -236,7 +235,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { if item_level.is_some() { - self.reach(item.id).generics().predicates().item_type(); + self.reach(item.id).generics().predicates().ty(); } } hir::ItemTrait(.., ref trait_item_refs) => { @@ -251,7 +250,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { !trait_item_ref.defaultness.has_value() { // No type to visit. } else { - reach.item_type(); + reach.ty(); } } } @@ -264,7 +263,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { for impl_item_ref in impl_item_refs { let id = impl_item_ref.id.node_id; if trait_ref.is_some() || self.get(id).is_some() { - self.reach(id).generics().predicates().item_type(); + self.reach(id).generics().predicates().ty(); } } } @@ -278,7 +277,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { for variant in &def.variants { if self.get(variant.node.data.id()).is_some() { for field in variant.node.data.fields() { - self.reach(field.id).item_type(); + self.reach(field.id).ty(); } // Corner case: if the variant is reachable, but its // enum is not, make the enum reachable as well. @@ -290,7 +289,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { hir::ItemForeignMod(ref foreign_mod) => { for foreign_item in &foreign_mod.items { if self.get(foreign_item.id).is_some() { - self.reach(foreign_item.id).generics().predicates().item_type(); + self.reach(foreign_item.id).generics().predicates().ty(); } } } @@ -301,7 +300,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { self.reach(item.id).generics().predicates(); for field in struct_def.fields() { if self.get(field.id).is_some() { - self.reach(field.id).item_type(); + self.reach(field.id).ty(); } } } @@ -351,7 +350,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) { if let hir::TyImplTrait(..) = ty.node { if self.get(ty.id).is_some() { // Reach the (potentially private) type and the API being exposed. - self.reach(ty.id).item_type().predicates(); + self.reach(ty.id).ty().predicates(); } } @@ -361,21 +360,21 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) { impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { fn generics(&mut self) -> &mut Self { - for def in &self.ev.tcx.item_generics(self.item_def_id).types { + for def in &self.ev.tcx.generics_of(self.item_def_id).types { if def.has_default { - self.ev.tcx.item_type(def.def_id).visit_with(self); + self.ev.tcx.type_of(def.def_id).visit_with(self); } } self } fn predicates(&mut self) -> &mut Self { - self.ev.tcx.item_predicates(self.item_def_id).visit_with(self); + self.ev.tcx.predicates_of(self.item_def_id).visit_with(self); self } - fn item_type(&mut self) -> &mut Self { - self.ev.tcx.item_type(self.item_def_id).visit_with(self); + fn ty(&mut self) -> &mut Self { + self.ev.tcx.type_of(self.item_def_id).visit_with(self); self } @@ -415,52 +414,32 @@ fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool { } } -//////////////////////////////////////////////////////////////////////////////// -/// The privacy visitor, where privacy checks take place (violations reported) -//////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////// +/// Name privacy visitor, checks privacy and reports violations. +/// Most of name privacy checks are performed during the main resolution phase, +/// or later in type checking when field accesses and associated items are resolved. +/// This pass performs remaining checks for fields in struct expressions and patterns. +////////////////////////////////////////////////////////////////////////////////////// -struct PrivacyVisitor<'a, 'tcx: 'a> { +struct NamePrivacyVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - curitem: DefId, - in_foreign: bool, tables: &'a ty::TypeckTables<'tcx>, + current_item: DefId, } -impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { - fn item_is_accessible(&self, did: DefId) -> bool { - match self.tcx.hir.as_local_node_id(did) { - Some(node_id) => - ty::Visibility::from_hir(&self.tcx.hir.expect_item(node_id).vis, node_id, self.tcx), - None => self.tcx.sess.cstore.visibility(did), - }.is_accessible_from(self.curitem, self.tcx) - } - - // Checks that a field is in scope. +impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> { + // Checks that a field is accessible. fn check_field(&mut self, span: Span, def: &'tcx ty::AdtDef, field: &'tcx ty::FieldDef) { - if !def.is_enum() && !field.vis.is_accessible_from(self.curitem, self.tcx) { + if !def.is_enum() && !field.vis.is_accessible_from(self.current_item, self.tcx) { struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private", - field.name, def.variant_descr(), self.tcx.item_path_str(def.did)) + field.name, def.variant_descr(), self.tcx.item_path_str(def.did)) .span_label(span, &format!("field `{}` is private", field.name)) .emit(); } } - - // Checks that a method is in scope. - fn check_method(&mut self, span: Span, method_def_id: DefId) { - match self.tcx.associated_item(method_def_id).container { - // Trait methods are always all public. The only controlling factor - // is whether the trait itself is accessible or not. - ty::TraitContainer(trait_def_id) if !self.item_is_accessible(trait_def_id) => { - let msg = format!("source trait `{}` is private", - self.tcx.item_path_str(trait_def_id)); - self.tcx.sess.span_err(span, &msg); - } - _ => {} - } - } } -impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> { +impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { /// We want to visit items in the context of their containing /// module and so forth, so supply a crate for doing a deep walk. fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { @@ -468,44 +447,36 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { } fn visit_nested_body(&mut self, body: hir::BodyId) { - let old_tables = self.tables; - self.tables = self.tcx.body_tables(body); + let orig_tables = replace(&mut self.tables, self.tcx.body_tables(body)); let body = self.tcx.hir.body(body); self.visit_body(body); - self.tables = old_tables; + self.tables = orig_tables; } fn visit_item(&mut self, item: &'tcx hir::Item) { - let orig_curitem = replace(&mut self.curitem, self.tcx.hir.local_def_id(item.id)); + let orig_current_item = replace(&mut self.current_item, self.tcx.hir.local_def_id(item.id)); intravisit::walk_item(self, item); - self.curitem = orig_curitem; + self.current_item = orig_current_item; } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { - hir::ExprMethodCall(..) => { - let method_call = ty::MethodCall::expr(expr.id); - let method = self.tables.method_map[&method_call]; - self.check_method(expr.span, method.def_id); - } - hir::ExprStruct(ref qpath, ref expr_fields, _) => { + hir::ExprStruct(ref qpath, ref fields, ref base) => { let def = self.tables.qpath_def(qpath, expr.id); let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap(); let variant = adt.variant_of_def(def); - // RFC 736: ensure all unmentioned fields are visible. - // Rather than computing the set of unmentioned fields - // (i.e. `all_fields - fields`), just check them all, - // unless the ADT is a union, then unmentioned fields - // are not checked. - if adt.is_union() { - for expr_field in expr_fields { - self.check_field(expr.span, adt, variant.field_named(expr_field.name.node)); + if let Some(ref base) = *base { + // If the expression uses FRU we need to make sure all the unmentioned fields + // are checked for privacy (RFC 736). Rather than computing the set of + // unmentioned fields, just check them all. + for variant_field in &variant.fields { + let field = fields.iter().find(|f| f.name.node == variant_field.name); + let span = if let Some(f) = field { f.span } else { base.span }; + self.check_field(span, adt, variant_field); } } else { - for field in &variant.fields { - let expr_field = expr_fields.iter().find(|f| f.name.node == field.name); - let span = if let Some(f) = expr_field { f.span } else { expr.span }; - self.check_field(span, adt, field); + for field in fields { + self.check_field(field.span, adt, variant.field_named(field.name.node)); } } } @@ -515,47 +486,20 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) { intravisit::walk_expr(self, expr); } - fn visit_pat(&mut self, pattern: &'tcx hir::Pat) { - // Foreign functions do not have their patterns mapped in the def_map, - // and there's nothing really relevant there anyway, so don't bother - // checking privacy. If you can name the type then you can pass it to an - // external C function anyway. - if self.in_foreign { return } - - match pattern.node { + fn visit_pat(&mut self, pat: &'tcx hir::Pat) { + match pat.node { PatKind::Struct(ref qpath, ref fields, _) => { - let def = self.tables.qpath_def(qpath, pattern.id); - let adt = self.tables.pat_ty(pattern).ty_adt_def().unwrap(); + let def = self.tables.qpath_def(qpath, pat.id); + let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap(); let variant = adt.variant_of_def(def); for field in fields { self.check_field(field.span, adt, variant.field_named(field.node.name)); } } - PatKind::TupleStruct(_, ref fields, ddpos) => { - match self.tables.pat_ty(pattern).sty { - // enum fields have no privacy at this time - ty::TyAdt(def, _) if !def.is_enum() => { - let expected_len = def.struct_variant().fields.len(); - for (i, field) in fields.iter().enumerate_and_adjust(expected_len, ddpos) { - if let PatKind::Wild = field.node { - continue - } - self.check_field(field.span, def, &def.struct_variant().fields[i]); - } - } - _ => {} - } - } _ => {} } - intravisit::walk_pat(self, pattern); - } - - fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem) { - self.in_foreign = true; - intravisit::walk_foreign_item(self, fi); - self.in_foreign = false; + intravisit::walk_pat(self, pat); } } @@ -924,21 +868,21 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { fn generics(&mut self) -> &mut Self { - for def in &self.tcx.item_generics(self.item_def_id).types { + for def in &self.tcx.generics_of(self.item_def_id).types { if def.has_default { - self.tcx.item_type(def.def_id).visit_with(self); + self.tcx.type_of(def.def_id).visit_with(self); } } self } fn predicates(&mut self) -> &mut Self { - self.tcx.item_predicates(self.item_def_id).visit_with(self); + self.tcx.predicates_of(self.item_def_id).visit_with(self); self } - fn item_type(&mut self) -> &mut Self { - self.tcx.item_type(self.item_def_id).visit_with(self); + fn ty(&mut self) -> &mut Self { + self.tcx.type_of(self.item_def_id).visit_with(self); self } @@ -1104,7 +1048,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { // Subitems of these items have inherited publicity hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { - self.check(item.id, item_visibility).generics().predicates().item_type(); + self.check(item.id, item_visibility).generics().predicates().ty(); // Recurse for e.g. `impl Trait` (see `visit_ty`). self.inner_visibility = item_visibility; @@ -1121,7 +1065,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { !trait_item_ref.defaultness.has_value() { // No type to visit. } else { - check.item_type(); + check.ty(); } } } @@ -1130,7 +1074,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { for variant in &def.variants { for field in variant.node.data.fields() { - self.check(field.id, item_visibility).item_type(); + self.check(field.id, item_visibility).ty(); } } } @@ -1138,7 +1082,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { hir::ItemForeignMod(ref foreign_mod) => { for foreign_item in &foreign_mod.items { let vis = ty::Visibility::from_hir(&foreign_item.vis, item.id, tcx); - self.check(foreign_item.id, vis).generics().predicates().item_type(); + self.check(foreign_item.id, vis).generics().predicates().ty(); } } // Subitems of structs and unions have their own publicity @@ -1148,7 +1092,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { for field in struct_def.fields() { let field_visibility = ty::Visibility::from_hir(&field.vis, item.id, tcx); - self.check(field.id, min(item_visibility, field_visibility)).item_type(); + self.check(field.id, min(item_visibility, field_visibility)).ty(); } } // The interface is empty @@ -1157,7 +1101,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { // Subitems of inherent impls have their own publicity hir::ItemImpl(.., None, _, ref impl_item_refs) => { let ty_vis = - self.check(item.id, ty::Visibility::Invisible).item_type().min_visibility; + self.check(item.id, ty::Visibility::Invisible).ty().min_visibility; self.check(item.id, ty_vis).generics().predicates(); for impl_item_ref in impl_item_refs { @@ -1165,7 +1109,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { let impl_item_vis = ty::Visibility::from_hir(&impl_item.vis, item.id, tcx); self.check(impl_item.id, min(impl_item_vis, ty_vis)) - .generics().predicates().item_type(); + .generics().predicates().ty(); // Recurse for e.g. `impl Trait` (see `visit_ty`). self.inner_visibility = impl_item_vis; @@ -1176,11 +1120,11 @@ fn visit_item(&mut self, item: &'tcx hir::Item) { // Subitems of trait impls have inherited publicity hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => { let vis = self.check(item.id, ty::Visibility::Invisible) - .item_type().impl_trait_ref().min_visibility; + .ty().impl_trait_ref().min_visibility; self.check(item.id, vis).generics().predicates(); for impl_item_ref in impl_item_refs { let impl_item = self.tcx.hir.impl_item(impl_item_ref.id); - self.check(impl_item.id, vis).generics().predicates().item_type(); + self.check(impl_item.id, vis).generics().predicates().ty(); // Recurse for e.g. `impl Trait` (see `visit_ty`). self.inner_visibility = vis; @@ -1200,7 +1144,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty) { // e.g. `impl Iterator` has two predicates, // `X: Iterator` and `::Item == T`, // where `X` is the `impl Iterator` itself, - // stored in `item_predicates`, not in the `Ty` itself. + // stored in `predicates_of`, not in the `Ty` itself. self.check(ty.id, self.inner_visibility).predicates(); } @@ -1222,7 +1166,7 @@ pub fn provide(providers: &mut Providers) { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { tcx.dep_graph.with_ignore(|| { // FIXME - ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE) + tcx.privacy_access_levels(LOCAL_CRATE) }) } @@ -1233,17 +1177,14 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let krate = tcx.hir.krate(); - // Use the parent map to check the privacy of everything - let mut visitor = PrivacyVisitor { - curitem: DefId::local(CRATE_DEF_INDEX), - in_foreign: false, + // Check privacy of names not checked in previous compilation stages. + let mut visitor = NamePrivacyVisitor { tcx: tcx, tables: &ty::TypeckTables::empty(), + current_item: DefId::local(CRATE_DEF_INDEX), }; intravisit::walk_crate(&mut visitor, krate); - tcx.sess.abort_if_errors(); - // Build up a set of all exported items in the AST. This is a set of all // items which are reachable from external crates based on visibility. let mut visitor = EmbargoVisitor { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3e8f7e11b6b..4639847651c 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -114,7 +114,7 @@ fn nest_tables(&mut self, item_id: NodeId, f: F) where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>) { let item_def_id = self.tcx.hir.local_def_id(item_id); - match self.tcx.maps.typeck_tables.borrow().get(&item_def_id) { + match self.tcx.maps.typeck_tables_of.borrow().get(&item_def_id) { Some(tables) => { let old_tables = self.save_ctxt.tables; self.save_ctxt.tables = tables; @@ -430,7 +430,7 @@ fn process_method(&mut self, } None => { if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) { - if let hir::ItemImpl(_, _, _, _, ref ty, _) = item.node { + if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node { trait_id = self.lookup_def_id(ty.id); } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index d822f7bea3a..e2c399e85cd 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -341,7 +341,7 @@ pub fn get_field_data(&self, let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon); filter!(self.span_utils, sub_span, field.span, None); let def_id = self.tcx.hir.local_def_id(field.id); - let typ = self.tcx.item_type(def_id).to_string(); + let typ = self.tcx.type_of(def_id).to_string(); let span = field.span; let text = self.span_utils.snippet(field.span); diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index c4fdc46d030..a6b0eb473eb 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -29,6 +29,7 @@ use cabi_sparc64; use cabi_nvptx; use cabi_nvptx64; +use cabi_hexagon; use machine::llalign_of_min; use type_::Type; use type_of; @@ -553,7 +554,7 @@ pub fn store(&self, bcx: &Builder<'a, 'tcx>, mut val: ValueRef, dst: ValueRef) { // bitcasting to the struct type yields invalid cast errors. // We instead thus allocate some scratch space... - let llscratch = bcx.alloca(ty, "abi_cast"); + let llscratch = bcx.alloca(ty, "abi_cast", None); base::Lifetime::Start.call(bcx, llscratch); // ...where we first store the value... @@ -746,13 +747,13 @@ pub fn unadjusted(ccx: &CrateContext<'a, 'tcx>, // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as // both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely // on memory dependencies rather than pointer equality - let interior_unsafe = mt.ty.type_contents(ccx.tcx()).interior_unsafe(); + let is_freeze = ccx.shared().type_is_freeze(mt.ty); - if mt.mutbl != hir::MutMutable && !interior_unsafe { + if mt.mutbl != hir::MutMutable && is_freeze { arg.attrs.set(ArgAttribute::NoAlias); } - if mt.mutbl == hir::MutImmutable && !interior_unsafe { + if mt.mutbl == hir::MutImmutable && is_freeze { arg.attrs.set(ArgAttribute::ReadOnly); } @@ -896,6 +897,7 @@ fn adjust_for_abi(&mut self, "sparc64" => cabi_sparc64::compute_abi_info(ccx, self), "nvptx" => cabi_nvptx::compute_abi_info(ccx, self), "nvptx64" => cabi_nvptx64::compute_abi_info(ccx, self), + "hexagon" => cabi_hexagon::compute_abi_info(ccx, self), a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 87ca410dece..d1c1dd7436a 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -90,12 +90,12 @@ pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, /// and fill in the actual contents in a second pass to prevent /// unbounded recursion; see also the comments in `trans::type_of`. pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { - generic_type_of(cx, t, None, false, false) + generic_type_of(cx, t, None) } pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, name: &str) -> Type { - generic_type_of(cx, t, Some(name), false, false) + generic_type_of(cx, t, Some(name)) } pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, @@ -114,7 +114,7 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, _ => unreachable!() }; let fields = compute_fields(cx, t, nonnull_variant_index as usize, true); - llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant, false, false), + llty.set_struct_body(&struct_llfields(cx, &fields, nonnull_variant), packed) }, _ => bug!("This function cannot handle {} with layout {:#?}", t, l) @@ -123,12 +123,9 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, - name: Option<&str>, - sizing: bool, - dst: bool) -> Type { + name: Option<&str>) -> Type { let l = cx.layout_of(t); - debug!("adt::generic_type_of t: {:?} name: {:?} sizing: {} dst: {}", - t, name, sizing, dst); + debug!("adt::generic_type_of t: {:?} name: {:?}", t, name); match *l { layout::CEnum { discr, .. } => Type::from_integer(cx, discr), layout::RawNullablePointer { nndiscr, .. } => { @@ -148,11 +145,10 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fields = compute_fields(cx, t, nndiscr as usize, false); match name { None => { - Type::struct_(cx, &struct_llfields(cx, &fields, nonnull, sizing, dst), + Type::struct_(cx, &struct_llfields(cx, &fields, nonnull), nonnull.packed) } Some(name) => { - assert_eq!(sizing, false); Type::named_struct(cx, name) } } @@ -163,13 +159,12 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fields = compute_fields(cx, t, 0, true); match name { None => { - let fields = struct_llfields(cx, &fields, &variant, sizing, dst); + let fields = struct_llfields(cx, &fields, &variant); Type::struct_(cx, &fields, variant.packed) } Some(name) => { // Hypothesis: named_struct's can never need a // drop flag. (... needs validation.) - assert_eq!(sizing, false); Type::named_struct(cx, name) } } @@ -190,7 +185,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } } - layout::General { discr, size, align, .. } => { + layout::General { discr, size, align, primitive_align, .. } => { // We need a representation that has: // * The alignment of the most-aligned field // * The size of the largest variant (rounded up to that alignment) @@ -203,14 +198,15 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // of the size. let size = size.bytes(); let align = align.abi(); + let primitive_align = primitive_align.abi(); assert!(align <= std::u32::MAX as u64); let discr_ty = Type::from_integer(cx, discr); let discr_size = discr.size().bytes(); let padded_discr_size = roundup(discr_size, align as u32); let variant_part_size = size-padded_discr_size; - let variant_fill = union_fill(cx, variant_part_size, align); + let variant_fill = union_fill(cx, variant_part_size, primitive_align); - assert_eq!(machine::llalign_of_min(cx, variant_fill), align as u32); + assert_eq!(machine::llalign_of_min(cx, variant_fill), primitive_align as u32); assert_eq!(padded_discr_size % discr_size, 0); // Ensure discr_ty can fill pad evenly let fields: Vec = [discr_ty, @@ -245,15 +241,60 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type { } -fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fields: &Vec>, - variant: &layout::Struct, - sizing: bool, _dst: bool) -> Vec { - let fields = variant.field_index_by_increasing_offset().map(|i| fields[i as usize]); - if sizing { - bug!() +// Double index to account for padding (FieldPath already uses `Struct::memory_index`) +fn struct_llfields_path(discrfield: &layout::FieldPath) -> Vec { + discrfield.iter().map(|&i| (i as usize) << 1).collect::>() +} + + +// Lookup `Struct::memory_index` and double it to account for padding +pub fn struct_llfields_index(variant: &layout::Struct, index: usize) -> usize { + (variant.memory_index[index] as usize) << 1 +} + + +pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, field_tys: &Vec>, + variant: &layout::Struct) -> Vec { + debug!("struct_llfields: variant: {:?}", variant); + let mut first_field = true; + let mut min_offset = 0; + let mut result: Vec = Vec::with_capacity(field_tys.len() * 2); + let field_iter = variant.field_index_by_increasing_offset().map(|i| { + (i, field_tys[i as usize], variant.offsets[i as usize].bytes()) }); + for (index, ty, target_offset) in field_iter { + if first_field { + debug!("struct_llfields: {} ty: {} min_offset: {} target_offset: {}", + index, ty, min_offset, target_offset); + first_field = false; + } else { + assert!(target_offset >= min_offset); + let padding_bytes = if variant.packed { 0 } else { target_offset - min_offset }; + result.push(Type::array(&Type::i8(cx), padding_bytes)); + debug!("struct_llfields: {} ty: {} pad_bytes: {} min_offset: {} target_offset: {}", + index, ty, padding_bytes, min_offset, target_offset); + } + let llty = type_of::in_memory_type_of(cx, ty); + result.push(llty); + let layout = cx.layout_of(ty); + let target_size = layout.size(&cx.tcx().data_layout).bytes(); + min_offset = target_offset + target_size; + } + if variant.sized && !field_tys.is_empty() { + if variant.stride().bytes() < min_offset { + bug!("variant: {:?} stride: {} min_offset: {}", variant, variant.stride().bytes(), + min_offset); + } + let padding_bytes = variant.stride().bytes() - min_offset; + debug!("struct_llfields: pad_bytes: {} min_offset: {} min_size: {} stride: {}\n", + padding_bytes, min_offset, variant.min_size.bytes(), variant.stride().bytes()); + result.push(Type::array(&Type::i8(cx), padding_bytes)); + assert!(result.len() == (field_tys.len() * 2)); } else { - fields.map(|ty| type_of::in_memory_type_of(cx, ty)).collect() + debug!("struct_llfields: min_offset: {} min_size: {} stride: {}\n", + min_offset, variant.min_size.bytes(), variant.stride().bytes()); } + + result } pub fn is_discr_signed<'tcx>(l: &layout::Layout) -> bool { @@ -309,8 +350,8 @@ fn struct_wrapped_nullable_bitdiscr( scrutinee: ValueRef, alignment: Alignment, ) -> ValueRef { - let llptrptr = bcx.gepi(scrutinee, - &discrfield.iter().map(|f| *f as usize).collect::>()); + let path = struct_llfields_path(discrfield); + let llptrptr = bcx.gepi(scrutinee, &path); let llptr = bcx.load(llptrptr, alignment.to_align()); let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; bcx.icmp(cmp, llptr, C_null(val_ty(llptr))) @@ -380,7 +421,7 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu let align = C_i32(bcx.ccx, nonnull.align.abi() as i32); base::call_memset(bcx, llptr, fill_byte, size, align, false); } else { - let path = discrfield.iter().map(|&i| i as usize).collect::>(); + let path = struct_llfields_path(discrfield); let llptrptr = bcx.gepi(val, &path); let llptrty = val_ty(llptrptr).element_type(); bcx.store(C_null(llptrty), llptrptr, None); diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 7c0522a9c8c..e42e69d2a76 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -1122,6 +1122,19 @@ fn link_sanitizer_runtime(cmd: &mut Linker, cnum: CrateNum) { let src = sess.cstore.used_crate_source(cnum); let cratepath = &src.rlib.unwrap().0; + + if sess.target.target.options.is_like_osx { + // On Apple platforms, the sanitizer is always built as a dylib, and + // LLVM will link to `@rpath/*.dylib`, so we need to specify an + // rpath to the library as well (the rpath should be absolute, see + // PR #41352 for details). + // + // FIXME: Remove this logic into librustc_*san once Cargo supports it + let rpath = cratepath.parent().unwrap(); + let rpath = rpath.to_str().expect("non-utf8 component in path"); + cmd.args(&["-Wl,-rpath".into(), "-Xlinker".into(), rpath.into()]); + } + let dst = tmpdir.join(cratepath.file_name().unwrap()); let cfg = archive_config(sess, &dst, Some(cratepath)); let mut archive = ArchiveBuilder::new(cfg); diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 5d6717272fd..221c52141a8 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -53,7 +53,7 @@ pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, scx.tcx().hir.local_def_id(node_id) }) .map(|def_id| { - let name = symbol_for_def_id(scx, def_id, symbol_map); + let name = symbol_for_def_id(scx.tcx(), def_id, symbol_map); let export_level = export_level(scx, def_id); debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level); (name, export_level) @@ -108,7 +108,7 @@ pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, .exported_symbols(cnum) .iter() .map(|&def_id| { - let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx); + let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx.tcx()); let export_level = if special_runtime_crate { // We can probably do better here by just ensuring that // it has hidden visibility rather than public @@ -214,21 +214,21 @@ pub fn is_below_threshold(level: SymbolExportLevel, } } -fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn symbol_for_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, symbol_map: &SymbolMap<'tcx>) -> String { // Just try to look things up in the symbol map. If nothing's there, we // recompute. - if let Some(node_id) = scx.tcx().hir.as_local_node_id(def_id) { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) { return sym.to_owned(); } } - let instance = Instance::mono(scx.tcx(), def_id); + let instance = Instance::mono(tcx, def_id); symbol_map.get(TransItem::Fn(instance)) .map(str::to_owned) - .unwrap_or_else(|| symbol_name(instance, scx)) + .unwrap_or_else(|| symbol_name(instance, tcx)) } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 8facbd6cc27..a96128fcf2f 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -97,13 +97,12 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -use common::SharedCrateContext; use monomorphize::Instance; use rustc::middle::weak_lang_items; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; -use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::fold::TypeVisitor; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::ty::subst::Substs; @@ -111,9 +110,10 @@ use rustc::util::common::record_time; use syntax::attr; -use syntax::symbol::{Symbol, InternedString}; -fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +use std::fmt::Write; + +fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the DefId of the item this name is for def_id: Option, @@ -130,8 +130,6 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, -> String { debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); - let tcx = scx.tcx(); - let mut hasher = ty::util::TypeIdHasher::::new(tcx); record_time(&tcx.sess.perf_stats.symbol_hash_time, || { @@ -157,8 +155,8 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // in case the same instances is emitted in two crates of the same // project. if substs.types().next().is_some() { - hasher.hash(scx.tcx().crate_name.as_str()); - hasher.hash(scx.sess().local_crate_disambiguator().as_str()); + hasher.hash(tcx.crate_name.as_str()); + hasher.hash(tcx.sess.local_crate_disambiguator().as_str()); } } }); @@ -168,37 +166,37 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, - scx: &SharedCrateContext<'a, 'tcx>) -> String { + tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { let def_id = instance.def_id(); let substs = instance.substs; debug!("symbol_name(def_id={:?}, substs={:?})", def_id, substs); - let node_id = scx.tcx().hir.as_local_node_id(def_id); + let node_id = tcx.hir.as_local_node_id(def_id); if let Some(id) = node_id { - if scx.sess().plugin_registrar_fn.get() == Some(id) { + if tcx.sess.plugin_registrar_fn.get() == Some(id) { let idx = def_id.index; - let disambiguator = scx.sess().local_crate_disambiguator(); - return scx.sess().generate_plugin_registrar_symbol(disambiguator, idx); + let disambiguator = tcx.sess.local_crate_disambiguator(); + return tcx.sess.generate_plugin_registrar_symbol(disambiguator, idx); } - if scx.sess().derive_registrar_fn.get() == Some(id) { + if tcx.sess.derive_registrar_fn.get() == Some(id) { let idx = def_id.index; - let disambiguator = scx.sess().local_crate_disambiguator(); - return scx.sess().generate_derive_registrar_symbol(disambiguator, idx); + let disambiguator = tcx.sess.local_crate_disambiguator(); + return tcx.sess.generate_derive_registrar_symbol(disambiguator, idx); } } // FIXME(eddyb) Precompute a custom symbol name based on attributes. - let attrs = scx.tcx().get_attrs(def_id); + let attrs = tcx.get_attrs(def_id); let is_foreign = if let Some(id) = node_id { - match scx.tcx().hir.get(id) { + match tcx.hir.get(id) { hir_map::NodeForeignItem(_) => true, _ => false } } else { - scx.sess().cstore.is_foreign_item(def_id) + tcx.sess.cstore.is_foreign_item(def_id) }; if let Some(name) = weak_lang_items::link_name(&attrs) { @@ -210,17 +208,17 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, return name.to_string(); } // Don't mangle foreign items. - return scx.tcx().item_name(def_id).as_str().to_string(); + return tcx.item_name(def_id).as_str().to_string(); } - if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), &attrs) { + if let Some(name) = attr::find_export_name_attr(tcx.sess.diagnostic(), &attrs) { // Use provided name return name.to_string(); } if attr::contains_name(&attrs, "no_mangle") { // Don't mangle - return scx.tcx().item_name(def_id).as_str().to_string(); + return tcx.item_name(def_id).as_str().to_string(); } // We want to compute the "type" of this item. Unfortunately, some @@ -230,11 +228,11 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, let mut ty_def_id = def_id; let instance_ty; loop { - let key = scx.tcx().def_key(ty_def_id); + let key = tcx.def_key(ty_def_id); match key.disambiguated_data.data { DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { - instance_ty = scx.tcx().item_type(ty_def_id); + instance_ty = tcx.type_of(ty_def_id); break; } _ => { @@ -251,23 +249,51 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>, // Erase regions because they may not be deterministic when hashed // and should not matter anyhow. - let instance_ty = scx.tcx().erase_regions(&instance_ty); - - let hash = get_symbol_hash(scx, Some(def_id), instance_ty, Some(substs)); + let instance_ty = tcx.erase_regions(&instance_ty); - let mut buffer = SymbolPathBuffer { - names: Vec::new() - }; + let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs)); + let mut buffer = SymbolPathBuffer::new(); item_path::with_forced_absolute_paths(|| { - scx.tcx().push_item_path(&mut buffer, def_id); + tcx.push_item_path(&mut buffer, def_id); }); - - mangle(buffer.names.into_iter(), &hash) + buffer.finish(&hash) } +// Follow C++ namespace-mangling style, see +// http://en.wikipedia.org/wiki/Name_mangling for more info. +// +// It turns out that on macOS you can actually have arbitrary symbols in +// function names (at least when given to LLVM), but this is not possible +// when using unix's linker. Perhaps one day when we just use a linker from LLVM +// we won't need to do this name mangling. The problem with name mangling is +// that it seriously limits the available characters. For example we can't +// have things like &T in symbol names when one would theoretically +// want them for things like impls of traits on that type. +// +// To be able to work on all platforms and get *some* reasonable output, we +// use C++ name-mangling. struct SymbolPathBuffer { - names: Vec, + result: String, + temp_buf: String +} + +impl SymbolPathBuffer { + fn new() -> Self { + let mut result = SymbolPathBuffer { + result: String::with_capacity(64), + temp_buf: String::with_capacity(16) + }; + result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested + result + } + + fn finish(mut self, hash: &str) -> String { + // end name-sequence + self.push(hash); + self.result.push('E'); + self.result + } } impl ItemPathBuffer for SymbolPathBuffer { @@ -277,24 +303,32 @@ fn root_mode(&self) -> &RootMode { } fn push(&mut self, text: &str) { - self.names.push(Symbol::intern(text).as_str()); + self.temp_buf.clear(); + let need_underscore = sanitize(&mut self.temp_buf, text); + let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize)); + if need_underscore { + self.result.push('_'); + } + self.result.push_str(&self.temp_buf); } } -pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +pub fn exported_name_from_type_and_prefix<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, t: Ty<'tcx>, prefix: &str) -> String { - let hash = get_symbol_hash(scx, None, t, None); - let path = [Symbol::intern(prefix).as_str()]; - mangle(path.iter().cloned(), &hash) + let hash = get_symbol_hash(tcx, None, t, None); + let mut buffer = SymbolPathBuffer::new(); + buffer.push(prefix); + buffer.finish(&hash) } // Name sanitation. LLVM will happily accept identifiers with weird names, but // gas doesn't! // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $ -pub fn sanitize(s: &str) -> String { - let mut result = String::new(); +// +// returns true if an underscore must be added at the start +pub fn sanitize(result: &mut String, s: &str) -> bool { for c in s.chars() { match c { // Escape these with $ sequences @@ -331,44 +365,7 @@ pub fn sanitize(s: &str) -> String { } // Underscore-qualify anything that didn't start as an ident. - if !result.is_empty() && + !result.is_empty() && result.as_bytes()[0] != '_' as u8 && - ! (result.as_bytes()[0] as char).is_xid_start() { - return format!("_{}", result); - } - - return result; -} - -fn mangle>(path: PI, hash: &str) -> String { - // Follow C++ namespace-mangling style, see - // http://en.wikipedia.org/wiki/Name_mangling for more info. - // - // It turns out that on macOS you can actually have arbitrary symbols in - // function names (at least when given to LLVM), but this is not possible - // when using unix's linker. Perhaps one day when we just use a linker from LLVM - // we won't need to do this name mangling. The problem with name mangling is - // that it seriously limits the available characters. For example we can't - // have things like &T in symbol names when one would theoretically - // want them for things like impls of traits on that type. - // - // To be able to work on all platforms and get *some* reasonable output, we - // use C++ name-mangling. - - let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested - - fn push(n: &mut String, s: &str) { - let sani = sanitize(s); - n.push_str(&format!("{}{}", sani.len(), sani)); - } - - // First, connect each component with pairs. - for data in path { - push(&mut n, &data); - } - - push(&mut n, hash); - - n.push('E'); // End name-sequence. - n + ! (result.as_bytes()[0] as char).is_xid_start() } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index cb8022efedb..e8cca7bc74f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -65,6 +65,7 @@ use mir; use monomorphize::{self, Instance}; use partitioning::{self, PartitioningStrategy, CodegenUnit}; +use symbol_cache::SymbolCache; use symbol_map::SymbolMap; use symbol_names_test; use trans_item::{TransItem, DefPathBasedNames}; @@ -75,7 +76,6 @@ use libc::c_uint; use std::ffi::{CStr, CString}; -use std::rc::Rc; use std::str; use std::i32; use syntax_pos::Span; @@ -802,6 +802,7 @@ enum MetadataKind { /// in any other compilation unit. Give these symbols internal linkage. fn internalize_symbols<'a, 'tcx>(sess: &Session, scx: &SharedCrateContext<'a, 'tcx>, + translation_items: &FxHashSet>, llvm_modules: &[ModuleLlvm], symbol_map: &SymbolMap<'tcx>, exported_symbols: &ExportedSymbols) { @@ -854,7 +855,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let mut locally_defined_symbols = FxHashSet(); let mut linkage_fixed_explicitly = FxHashSet(); - for trans_item in scx.translation_items().borrow().iter() { + for trans_item in translation_items { let symbol_name = symbol_map.get_or_compute(scx, *trans_item); if trans_item.explicit_linkage(tcx).is_some() { linkage_fixed_explicitly.insert(symbol_name.clone()); @@ -1011,8 +1012,8 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { /// /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. -pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { - reachable.into_iter().filter(|&id| { +pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { + reachable.iter().cloned().filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two // categories: @@ -1040,7 +1041,7 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { hir_map::NodeImplItem(&hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => { let def_id = tcx.hir.local_def_id(id); - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); let attributes = tcx.get_attrs(def_id); (generics.parent_types == 0 && generics.types.is_empty()) && // Functions marked with #[inline] are only ever translated @@ -1064,7 +1065,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let krate = tcx.hir.krate(); let ty::CrateAnalysis { reachable, .. } = analysis; - let exported_symbols = find_exported_symbols(tcx, reachable); + let exported_symbols = find_exported_symbols(tcx, &reachable); let check_overflow = tcx.sess.overflow_checks(); @@ -1109,9 +1110,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Run the translation item collector and partition the collected items into // codegen units. - let (codegen_units, symbol_map) = collect_and_partition_translation_items(&shared_ccx); - - let symbol_map = Rc::new(symbol_map); + let (translation_items, codegen_units, symbol_map) = + collect_and_partition_translation_items(&shared_ccx); let mut all_stats = Stats::default(); let modules: Vec = codegen_units @@ -1121,7 +1121,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (stats, module) = tcx.dep_graph.with_task(dep_node, AssertDepGraphSafe(&shared_ccx), - AssertDepGraphSafe((cgu, symbol_map.clone())), + AssertDepGraphSafe(cgu), module_translation); all_stats.extend(stats); module @@ -1130,16 +1130,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn module_translation<'a, 'tcx>( scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>, - args: AssertDepGraphSafe<(CodegenUnit<'tcx>, Rc>)>) + args: AssertDepGraphSafe>) -> (Stats, ModuleTranslation) { // FIXME(#40304): We ought to be using the id as a key and some queries, I think. let AssertDepGraphSafe(scx) = scx; - let AssertDepGraphSafe((cgu, symbol_map)) = args; + let AssertDepGraphSafe(cgu) = args; let cgu_name = String::from(cgu.name()); let cgu_id = cgu.work_product_id(); - let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_map); + let symbol_cache = SymbolCache::new(scx.tcx()); + let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_cache); // Check whether there is a previous work-product we can // re-use. Not only must the file exist, and the inputs not @@ -1174,11 +1175,11 @@ fn module_translation<'a, 'tcx>( } // Instantiate translation items without filling out definitions yet... - let lcx = LocalCrateContext::new(scx, cgu, symbol_map.clone()); + let lcx = LocalCrateContext::new(scx, cgu, &symbol_cache); let module = { let ccx = CrateContext::new(scx, &lcx); let trans_items = ccx.codegen_unit() - .items_in_deterministic_order(ccx.tcx(), &symbol_map); + .items_in_deterministic_order(ccx.tcx(), &symbol_cache); for &(trans_item, linkage) in &trans_items { trans_item.predefine(&ccx, linkage); } @@ -1238,7 +1239,7 @@ fn module_translation<'a, 'tcx>( assert_module_sources::assert_module_sources(tcx, &modules); - symbol_names_test::report_symbol_names(&shared_ccx); + symbol_names_test::report_symbol_names(tcx); if shared_ccx.sess().trans_stats() { println!("--- trans stats ---"); @@ -1289,6 +1290,7 @@ fn module_translation<'a, 'tcx>( time(shared_ccx.sess().time_passes(), "internalize symbols", || { internalize_symbols(sess, &shared_ccx, + &translation_items, &llvm_modules, &symbol_map, &exported_symbols); @@ -1517,7 +1519,9 @@ enum Fields<'a> { } fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) - -> (Vec>, SymbolMap<'tcx>) { + -> (FxHashSet>, + Vec>, + SymbolMap<'tcx>) { let time_passes = scx.sess().time_passes(); let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items { @@ -1563,13 +1567,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() || scx.tcx().sess.opts.debugging_opts.incremental.is_some()); - { - let mut ccx_map = scx.translation_items().borrow_mut(); - - for trans_item in items.iter().cloned() { - ccx_map.insert(trans_item); - } - } + let translation_items: FxHashSet> = items.iter().cloned().collect(); if scx.sess().opts.debugging_opts.print_trans_items.is_some() { let mut item_to_cgus = FxHashMap(); @@ -1624,5 +1622,5 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a } } - (codegen_units, symbol_map) + (translation_items, codegen_units, symbol_map) } diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 8b1010d89fd..5103ca5c5e1 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -477,24 +477,28 @@ pub fn not(&self, v: ValueRef) -> ValueRef { } } - pub fn alloca(&self, ty: Type, name: &str) -> ValueRef { + pub fn alloca(&self, ty: Type, name: &str, align: Option) -> ValueRef { let builder = Builder::with_ccx(self.ccx); builder.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) }); - builder.dynamic_alloca(ty, name) + builder.dynamic_alloca(ty, name, align) } - pub fn dynamic_alloca(&self, ty: Type, name: &str) -> ValueRef { + pub fn dynamic_alloca(&self, ty: Type, name: &str, align: Option) -> ValueRef { self.count_insn("alloca"); unsafe { - if name.is_empty() { + let alloca = if name.is_empty() { llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), noname()) } else { let name = CString::new(name).unwrap(); llvm::LLVMBuildAlloca(self.llbuilder, ty.to_ref(), name.as_ptr()) + }; + if let Some(align) = align { + llvm::LLVMSetAlignment(alloca, align as c_uint); } + alloca } } diff --git a/src/librustc_trans/cabi_hexagon.rs b/src/librustc_trans/cabi_hexagon.rs new file mode 100644 index 00000000000..1acda72675c --- /dev/null +++ b/src/librustc_trans/cabi_hexagon.rs @@ -0,0 +1,43 @@ +// Copyright 2012-2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +use abi::{FnType, ArgType, LayoutExt}; +use context::CrateContext; + +fn classify_ret_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ret: &mut ArgType<'tcx>) { + if ret.layout.is_aggregate() && ret.layout.size(ccx).bits() > 64 { + ret.make_indirect(ccx); + } else { + ret.extend_integer_width_to(32); + } +} + +fn classify_arg_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &mut ArgType<'tcx>) { + if arg.layout.is_aggregate() && arg.layout.size(ccx).bits() > 64 { + arg.make_indirect(ccx); + } else { + arg.extend_integer_width_to(32); + } +} + +pub fn compute_abi_info<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fty: &mut FnType<'tcx>) { + if !fty.ret.is_ignore() { + classify_ret_ty(ccx, &mut fty.ret); + } + + for arg in &mut fty.args { + if arg.is_ignore() { + continue; + } + classify_arg_ty(ccx, arg); + } +} diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index aefee51191a..78e0a524ef2 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -14,18 +14,17 @@ //! and methods are represented as just a fn ptr and not a full //! closure. -use llvm::{self, ValueRef}; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; use attributes; use common::{self, CrateContext}; -use monomorphize; use consts; use declare; -use monomorphize::Instance; +use llvm::{self, ValueRef}; +use monomorphize::{self, Instance}; +use rustc::hir::def_id::DefId; +use rustc::ty::TypeFoldable; +use rustc::ty::subst::Substs; use trans_item::TransItem; use type_of; -use rustc::ty::TypeFoldable; /// Translates a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -51,8 +50,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; } - let sym = ccx.symbol_map().get_or_compute(ccx.shared(), - TransItem::Fn(instance)); + let sym = ccx.symbol_cache().get(TransItem::Fn(instance)); debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym); // This is subtle and surprising, but sometimes we have to bitcast @@ -102,15 +100,17 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let attrs = instance.def.attrs(ccx.tcx()); attributes::from_fn_attrs(ccx, &attrs, llfn); - let is_local_def = ccx.shared().translation_items().borrow() - .contains(&TransItem::Fn(instance)); - if is_local_def { - // FIXME(eddyb) Doubt all extern fn should allow unwinding. + // Perhaps questionable, but we assume that anything defined + // *in Rust code* may unwind. Foreign items like `extern "C" { + // fn foo(); }` are assumed not to unwind **unless** they have + // a `#[unwind]` attribute. + if !tcx.is_foreign_item(instance.def_id()) { attributes::unwind(llfn, true); unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); } } + if ccx.use_dll_storage_attrs() && ccx.sess().cstore.is_dllimport_foreign_item(instance.def_id()) { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index ba2b807d5a0..77155a474ae 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -467,13 +467,11 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { - let target_ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &target_ty); + let target_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &target_ty); let source_ty = operand.ty(self.mir, self.scx.tcx()); - let source_ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &source_ty); + let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &source_ty); let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx, source_ty, target_ty); @@ -489,10 +487,8 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { } mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => { let fn_ty = operand.ty(self.mir, self.scx.tcx()); - let fn_ty = monomorphize::apply_param_substs( - self.scx, - self.param_substs, - &fn_ty); + let fn_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &fn_ty); visit_fn_use(self.scx, fn_ty, false, &mut self.output); } mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => { @@ -534,9 +530,8 @@ fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) } if let mir::Literal::Item { def_id, substs } = constant.literal { - let substs = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &substs); + let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &substs); let instance = monomorphize::resolve(self.scx, def_id, substs); collect_neighbours(self.scx, instance, self.output); } @@ -552,17 +547,14 @@ fn visit_terminator_kind(&mut self, match *kind { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.mir, tcx); - let callee_ty = monomorphize::apply_param_substs( - self.scx, self.param_substs, &callee_ty); + let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty); visit_fn_use(self.scx, callee_ty, true, &mut self.output); } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { let ty = location.ty(self.mir, self.scx.tcx()) .to_ty(self.scx.tcx()); - let ty = monomorphize::apply_param_substs(self.scx, - self.param_substs, - &ty); + let ty = tcx.trans_apply_param_substs(self.param_substs, &ty); visit_drop_use(self.scx, ty, true, self.output); } mir::TerminatorKind::Goto { .. } | @@ -888,7 +880,7 @@ fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { let parent_node_id = hir_map.get_parent_node(ii.id); let is_impl_generic = match hir_map.expect_item(parent_node_id) { &hir::Item { - node: hir::ItemImpl(_, _, ref generics, ..), + node: hir::ItemImpl(_, _, _, ref generics, ..), .. } => { generics.is_type_parameterized() @@ -919,6 +911,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' let tcx = scx.tcx(); match item.node { hir::ItemImpl(_, + _, _, ref generics, .., @@ -943,14 +936,14 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' continue; } - if !tcx.item_generics(method.def_id).types.is_empty() { + if !tcx.generics_of(method.def_id).types.is_empty() { continue; } let instance = monomorphize::resolve(scx, method.def_id, callee_substs); - let predicates = tcx.item_predicates(instance.def_id()).predicates + let predicates = tcx.predicates_of(instance.def_id()).predicates .subst(tcx, instance.substs); if !traits::normalize_and_test_predicates(tcx, predicates) { continue; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 5d58c935389..025062f7dde 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -563,8 +563,8 @@ pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - let ty = shared.tcx().item_type(def_id); - monomorphize::apply_param_substs(shared, substs, &ty) + let ty = shared.tcx().type_of(def_id); + shared.tcx().trans_apply_param_substs(substs, &ty) } /// Return the substituted type of an instance. @@ -573,5 +573,5 @@ pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, -> Ty<'tcx> { let ty = instance.def.def_ty(shared.tcx()); - monomorphize::apply_param_substs(shared, instance.substs, &ty) + shared.tcx().trans_apply_param_substs(instance.substs, &ty) } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 7a53a03344f..3d614cfbcbf 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -93,20 +93,19 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { hir_map::NodeItem(&hir::Item { ref attrs, span, node: hir::ItemStatic(..), .. }) => { - let sym = ccx.symbol_map() - .get(TransItem::Static(id)) - .expect("Local statics should always be in the SymbolMap"); + let sym = ccx.symbol_cache() + .get(TransItem::Static(id)); let defined_in_current_codegen_unit = ccx.codegen_unit() .items() .contains_key(&TransItem::Static(id)); assert!(!defined_in_current_codegen_unit); - if declare::get_declared_value(ccx, sym).is_some() { + if declare::get_declared_value(ccx, &sym[..]).is_some() { span_bug!(span, "trans: Conflicting symbol names for static?"); } - let g = declare::define_global(ccx, sym, llty).unwrap(); + let g = declare::define_global(ccx, &sym[..], llty).unwrap(); (g, attrs) } @@ -114,7 +113,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { hir_map::NodeForeignItem(&hir::ForeignItem { ref attrs, span, node: hir::ForeignItemStatic(..), .. }) => { - let sym = symbol_names::symbol_name(instance, ccx.shared()); + let sym = symbol_names::symbol_name(instance, ccx.tcx()); let g = if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "linkage") { // If this is a static with a linkage specified, then we need to handle @@ -174,7 +173,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { g } else { - let sym = symbol_names::symbol_name(instance, ccx.shared()); + let sym = symbol_names::symbol_name(instance, ccx.tcx()); // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global @@ -261,8 +260,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. if m != hir::MutMutable { - let tcontents = ty.type_contents(ccx.tcx()); - if !tcontents.interior_unsafe() { + if ccx.shared().type_is_freeze(ty) { llvm::LLVMSetGlobalConstant(g, llvm::True); } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index c3770470bfd..bef22cf304d 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,7 +10,7 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; -use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig}; +use rustc::dep_graph::{DepGraph, DepGraphSafe}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::traits; @@ -21,7 +21,6 @@ use monomorphize::Instance; use partitioning::CodegenUnit; -use trans_item::TransItem; use type_::Type; use rustc_data_structures::base_n; use rustc::ty::subst::Substs; @@ -30,15 +29,13 @@ use session::config::NoDebugInfo; use session::Session; use session::config; -use symbol_map::SymbolMap; -use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; +use symbol_cache::SymbolCache; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; -use std::marker::PhantomData; use std::ptr; use std::iter; -use std::rc::Rc; use std::str; use syntax::ast; use syntax::symbol::InternedString; @@ -86,17 +83,13 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { check_overflow: bool, use_dll_storage_attrs: bool, - - translation_items: RefCell>>, - trait_cache: RefCell>>, - project_cache: RefCell>>, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` /// per compilation unit. Each one has its own LLVM `ContextRef` so that /// several compilation units may be optimized in parallel. All other LLVM /// data structures in the `LocalCrateContext` are tied to that `ContextRef`. -pub struct LocalCrateContext<'tcx> { +pub struct LocalCrateContext<'a, 'tcx: 'a> { llmod: ModuleRef, llcx: ContextRef, stats: Stats, @@ -168,60 +161,10 @@ pub struct LocalCrateContext<'tcx> { /// Depth of the current type-of computation - used to bail out type_of_depth: Cell, - symbol_map: Rc>, - /// A counter that is used for generating local symbol names local_gen_sym_counter: Cell, -} - -// Implement DepTrackingMapConfig for `trait_cache` -pub struct TraitSelectionCache<'tcx> { - data: PhantomData<&'tcx ()> -} - -impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { - type Key = ty::PolyTraitRef<'tcx>; - type Value = traits::Vtable<'tcx, ()>; - fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode { - key.to_poly_trait_predicate().dep_node() - } -} - -// # Global Cache -pub struct ProjectionCache<'gcx> { - data: PhantomData<&'gcx ()> -} - -impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { - type Key = Ty<'gcx>; - type Value = Ty<'gcx>; - fn to_dep_node(key: &Self::Key) -> DepNode { - // Ideally, we'd just put `key` into the dep-node, but we - // can't put full types in there. So just collect up all the - // def-ids of structs/enums as well as any traits that we - // project out of. It doesn't matter so much what we do here, - // except that if we are too coarse, we'll create overly - // coarse edges between impls and the trans. For example, if - // we just used the def-id of things we are projecting out of, - // then the key for `::T` and `::T` would both share a dep-node - // (`TraitSelect(SomeTrait)`), and hence the impls for both - // `Foo` and `Bar` would be considered inputs. So a change to - // `Bar` would affect things that just normalized `Foo`. - // Anyway, this heuristic is not ideal, but better than - // nothing. - let def_ids: Vec = - key.walk() - .filter_map(|t| match t.sty { - ty::TyAdt(adt_def, _) => Some(adt_def.did), - ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), - _ => None, - }) - .collect(); - - DepNode::ProjectionCache { def_ids: def_ids } - } + symbol_cache: &'a SymbolCache<'a, 'tcx>, } /// A CrateContext value binds together one LocalCrateContext with the @@ -229,12 +172,12 @@ fn to_dep_node(key: &Self::Key) -> DepNode { /// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans. pub struct CrateContext<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccx: &'a LocalCrateContext<'tcx>, + local_ccx: &'a LocalCrateContext<'a, 'tcx>, } impl<'a, 'tcx> CrateContext<'a, 'tcx> { pub fn new(shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccx: &'a LocalCrateContext<'tcx>) + local_ccx: &'a LocalCrateContext<'a, 'tcx>) -> Self { CrateContext { shared, local_ccx } } @@ -385,30 +328,23 @@ pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, tcx: tcx, check_overflow: check_overflow, use_dll_storage_attrs: use_dll_storage_attrs, - translation_items: RefCell::new(FxHashSet()), - trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), - project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), } } pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - self.tcx.type_needs_drop_given_env(ty, &self.empty_param_env) + ty.needs_drop(self.tcx, &self.empty_param_env) } pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { ty.is_sized(self.tcx, &self.empty_param_env, DUMMY_SP) } - pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { - &self.exported_symbols - } - - pub fn trait_cache(&self) -> &RefCell>> { - &self.trait_cache + pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { + ty.is_freeze(self.tcx, &self.empty_param_env, DUMMY_SP) } - pub fn project_cache(&self) -> &RefCell>> { - &self.project_cache + pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet { + &self.exported_symbols } pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { @@ -426,17 +362,13 @@ pub fn dep_graph<'a>(&'a self) -> &'a DepGraph { pub fn use_dll_storage_attrs(&self) -> bool { self.use_dll_storage_attrs } - - pub fn translation_items(&self) -> &RefCell>> { - &self.translation_items - } } -impl<'tcx> LocalCrateContext<'tcx> { - pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, - codegen_unit: CodegenUnit<'tcx>, - symbol_map: Rc>) - -> LocalCrateContext<'tcx> { +impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { + pub fn new(shared: &SharedCrateContext<'a, 'tcx>, + codegen_unit: CodegenUnit<'tcx>, + symbol_cache: &'a SymbolCache<'a, 'tcx>) + -> LocalCrateContext<'a, 'tcx> { unsafe { // Append ".rs" to LLVM module identifier. // @@ -490,8 +422,8 @@ pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, rust_try_fn: Cell::new(None), intrinsics: RefCell::new(FxHashMap()), type_of_depth: Cell::new(0), - symbol_map: symbol_map, local_gen_sym_counter: Cell::new(0), + symbol_cache: symbol_cache, }; let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = { @@ -525,9 +457,9 @@ pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, /// This is used in the `LocalCrateContext` constructor to allow calling /// functions that expect a complete `CrateContext`, even before the local /// portion is fully initialized and attached to the `SharedCrateContext`. - fn dummy_ccx<'a>(shared: &'a SharedCrateContext<'a, 'tcx>, - local_ccxs: &'a [LocalCrateContext<'tcx>]) - -> CrateContext<'a, 'tcx> { + fn dummy_ccx(shared: &'a SharedCrateContext<'a, 'tcx>, + local_ccxs: &'a [LocalCrateContext<'a, 'tcx>]) + -> CrateContext<'a, 'tcx> { assert!(local_ccxs.len() == 1); CrateContext { shared: shared, @@ -545,7 +477,7 @@ pub fn shared(&self) -> &'b SharedCrateContext<'b, 'tcx> { self.shared } - fn local(&self) -> &'b LocalCrateContext<'tcx> { + fn local(&self) -> &'b LocalCrateContext<'b, 'tcx> { self.local_ccx } @@ -712,12 +644,8 @@ pub fn use_dll_storage_attrs(&self) -> bool { self.shared.use_dll_storage_attrs() } - pub fn symbol_map(&self) -> &SymbolMap<'tcx> { - &*self.local().symbol_map - } - - pub fn translation_items(&self) -> &RefCell>> { - &self.shared.translation_items + pub fn symbol_cache(&self) -> &'b SymbolCache<'b, 'tcx> { + self.local().symbol_cache } /// Given the def-id of some item that has no type parameters, make @@ -843,6 +771,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { type TyLayout = TyLayout<'tcx>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) { + return TyLayout { ty: ty, layout: layout, variant_index: None }; + } + self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { infcx.layout_of(ty).unwrap_or_else(|e| { match e { @@ -853,6 +785,10 @@ fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { }) }) } + + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.tcx().normalize_associated_type(&ty) + } } impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { @@ -861,9 +797,13 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { self.shared.layout_of(ty) } + + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.shared.normalize_projections(ty) + } } -pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>); +pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'a, 'tcx>); impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> { fn drop(&mut self) { diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 1b7cf26853b..982ea5ffeb7 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -237,7 +237,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. - let generics = cx.tcx().item_generics(fn_def_id); + let generics = cx.tcx().generics_of(fn_def_id); let substs = instance.substs.truncate_to(cx.tcx(), generics); let template_parameters = get_template_parameters(cx, &generics, @@ -382,7 +382,7 @@ fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn get_type_parameter_names(cx: &CrateContext, generics: &ty::Generics) -> Vec { let mut names = generics.parent.map_or(vec![], |def_id| { - get_type_parameter_names(cx, cx.tcx().item_generics(def_id)) + get_type_parameter_names(cx, cx.tcx().generics_of(def_id)) }); names.extend(generics.types.iter().map(|param| param.name)); names diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 7077eade611..54e20f590c6 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -778,7 +778,7 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, // // More information can be found in libstd's seh.rs implementation. let i64p = Type::i64(ccx).ptr_to(); - let slot = bcx.alloca(i64p, "slot"); + let slot = bcx.alloca(i64p, "slot", None); bcx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index be214a0f614..d5fc2ee5e25 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -97,6 +97,7 @@ pub mod back { mod cabi_aarch64; mod cabi_arm; mod cabi_asmjs; +mod cabi_hexagon; mod cabi_mips; mod cabi_mips64; mod cabi_msp430; @@ -124,6 +125,7 @@ pub mod back { mod mir; mod monomorphize; mod partitioning; +mod symbol_cache; mod symbol_map; mod symbol_names_test; mod trans_item; diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 0f5a38ac7f6..d94d7f4430b 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -15,6 +15,7 @@ use rustc::ty::layout::{self, LayoutTyper}; use rustc::mir; use abi::{Abi, FnType, ArgType}; +use adt; use base::{self, Lifetime}; use callee; use builder::Builder; @@ -177,7 +178,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock, }; let llslot = match op.val { Immediate(_) | Pair(..) => { - let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret"); + let llscratch = bcx.alloca(ret.memory_ty(bcx.ccx), "ret", None); self.store_operand(&bcx, llscratch, None, op); llscratch } @@ -630,7 +631,7 @@ fn trans_argument(&mut self, let (mut llval, align, by_ref) = match op.val { Immediate(_) | Pair(..) => { if arg.is_indirect() || arg.cast.is_some() { - let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg"); + let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg", None); self.store_operand(bcx, llscratch, None, op); (llscratch, Alignment::AbiAligned, true) } else { @@ -642,7 +643,7 @@ fn trans_argument(&mut self, // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't // have scary latent bugs around. - let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg"); + let llscratch = bcx.alloca(arg.memory_ty(bcx.ccx), "arg", None); base::memcpy_ty(bcx, llscratch, llval, op.ty, Some(1)); (llscratch, Alignment::AbiAligned, true) } @@ -711,7 +712,8 @@ fn trans_arguments_untupled(&mut self, bug!("Not a tuple."); }; for (n, &ty) in arg_types.iter().enumerate() { - let mut elem = bcx.extract_value(llval, v.memory_index[n] as usize); + let mut elem = bcx.extract_value( + llval, adt::struct_llfields_index(v, n)); // Truncate bools to i1, if needed if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx) { elem = bcx.trunc(elem, Type::i1(bcx.ccx)); @@ -750,7 +752,7 @@ fn get_personality_slot(&mut self, bcx: &Builder<'a, 'tcx>) -> ValueRef { slot } else { let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); - let slot = bcx.alloca(llretty, "personalityslot"); + let slot = bcx.alloca(llretty, "personalityslot", None); self.llpersonalityslot = Some(slot); slot } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 8bce0cf85c0..040194e63d0 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -100,15 +100,13 @@ pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>, ConstVal::Integral(ref i) => return Const::from_constint(ccx, i), ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()), ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"), + ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false), + ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)), + ConstVal::Variant(_) | ConstVal::Struct(_) | ConstVal::Tuple(_) | ConstVal::Array(..) | ConstVal::Repeat(..) => { bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv) } - ConstVal::Function(..) => { - let llty = type_of::type_of(ccx, ty); - return Const::new(C_null(llty), ty); - } - ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false), }; assert!(!ty.has_erasable_regions()); @@ -260,9 +258,7 @@ fn trans_def(ccx: &'a CrateContext<'a, 'tcx>, fn monomorphize(&self, value: &T) -> T where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.ccx.shared(), - self.substs, - value) + self.ccx.tcx().trans_apply_param_substs(self.substs, value) } fn trans(&mut self) -> Result, ConstEvalErr<'tcx>> { @@ -710,7 +706,7 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>, let tr_lvalue = self.const_lvalue(lvalue, span)?; let ty = tr_lvalue.ty; - let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased), + let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() }); let base = match tr_lvalue.base { diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index fc889604ab8..88e46b5c99a 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -97,7 +97,8 @@ pub fn new_sized_ty(llval: ValueRef, ty: Ty<'tcx>, alignment: Alignment) -> Lval pub fn alloca(bcx: &Builder<'a, 'tcx>, ty: Ty<'tcx>, name: &str) -> LvalueRef<'tcx> { debug!("alloca({:?}: {:?})", name, ty); - let tmp = bcx.alloca(type_of::type_of(bcx.ccx, ty), name); + let tmp = bcx.alloca( + type_of::type_of(bcx.ccx, ty), name, bcx.ccx.over_align_of(ty)); assert!(!ty.has_param_types()); Self::new_sized_ty(tmp, ty, Alignment::AbiAligned) } @@ -131,11 +132,9 @@ fn struct_field_ptr( let alignment = self.alignment | Alignment::from_packed(st.packed); + let llfields = adt::struct_llfields(ccx, fields, st); let ptr_val = if needs_cast { - let fields = st.field_index_by_increasing_offset().map(|i| { - type_of::in_memory_type_of(ccx, fields[i]) - }).collect::>(); - let real_ty = Type::struct_(ccx, &fields[..], st.packed); + let real_ty = Type::struct_(ccx, &llfields[..], st.packed); bcx.pointercast(self.llval, real_ty.ptr_to()) } else { self.llval @@ -147,14 +146,16 @@ fn struct_field_ptr( // * Field is sized - pointer is properly aligned already if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed || bcx.ccx.shared().type_is_sized(fty) { - return (bcx.struct_gep(ptr_val, st.memory_index[ix] as usize), alignment); + return (bcx.struct_gep( + ptr_val, adt::struct_llfields_index(st, ix)), alignment); } // If the type of the last field is [T] or str, then we don't need to do // any adjusments match fty.sty { ty::TySlice(..) | ty::TyStr => { - return (bcx.struct_gep(ptr_val, st.memory_index[ix] as usize), alignment); + return (bcx.struct_gep( + ptr_val, adt::struct_llfields_index(st, ix)), alignment); } _ => () } @@ -163,7 +164,7 @@ fn struct_field_ptr( if !self.has_extra() { debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment", ix, Value(ptr_val)); - return (bcx.struct_gep(ptr_val, ix), alignment); + return (bcx.struct_gep(ptr_val, adt::struct_llfields_index(st, ix)), alignment); } // We need to get the pointer manually now. diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 3d8c5085462..af0e27c8ca3 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -22,7 +22,7 @@ use builder::Builder; use common::{self, CrateContext, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; -use monomorphize::{self, Instance}; +use monomorphize::Instance; use abi::FnType; use type_of; @@ -102,8 +102,9 @@ pub struct MirContext<'a, 'tcx:'a> { impl<'a, 'tcx> MirContext<'a, 'tcx> { pub fn monomorphize(&self, value: &T) -> T - where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.ccx.shared(), self.param_substs, value) + where T: TransNormalize<'tcx> + { + self.ccx.tcx().trans_apply_param_substs(self.param_substs, value) } pub fn set_debug_loc(&mut self, bcx: &Builder, source_info: mir::SourceInfo) { @@ -524,7 +525,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, // doesn't actually strip the offset when splitting the closure // environment into its components so it ends up out of bounds. let env_ptr = if !env_ref { - let alloc = bcx.alloca(common::val_ty(llval), "__debuginfo_env_ptr"); + let alloc = bcx.alloca(common::val_ty(llval), "__debuginfo_env_ptr", None); bcx.store(llval, alloc, None); alloc } else { diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index c31142323c8..6889b5064b6 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -15,6 +15,7 @@ use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; +use adt; use base; use common::{self, CrateContext, C_null}; use builder::Builder; @@ -134,6 +135,12 @@ pub fn pack_if_pair(mut self, bcx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> { if common::val_ty(elem) == Type::i1(bcx.ccx) { elem = bcx.zext(elem, Type::i8(bcx.ccx)); } + let layout = bcx.ccx.layout_of(self.ty); + let i = if let Layout::Univariant { ref variant, .. } = *layout { + adt::struct_llfields_index(variant, i) + } else { + i + }; llpair = bcx.insert_value(llpair, elem, i); } self.val = OperandValue::Immediate(llpair); @@ -183,14 +190,17 @@ pub fn trans_load(&mut self, let (lldata, llextra) = base::load_fat_ptr(bcx, llval, align, ty); OperandValue::Pair(lldata, llextra) } else if common::type_is_imm_pair(bcx.ccx, ty) { - let f_align = match *bcx.ccx.layout_of(ty) { - Layout::Univariant { ref variant, .. } => - Alignment::from_packed(variant.packed) | align, - _ => align + let (ix0, ix1, f_align) = match *bcx.ccx.layout_of(ty) { + Layout::Univariant { ref variant, .. } => { + (adt::struct_llfields_index(variant, 0), + adt::struct_llfields_index(variant, 1), + Alignment::from_packed(variant.packed) | align) + }, + _ => (0, 1, align) }; let [a_ty, b_ty] = common::type_pair_fields(bcx.ccx, ty).unwrap(); - let a_ptr = bcx.struct_gep(llval, 0); - let b_ptr = bcx.struct_gep(llval, 1); + let a_ptr = bcx.struct_gep(llval, ix0); + let b_ptr = bcx.struct_gep(llval, ix1); OperandValue::Pair( base::load_ty(bcx, a_ptr, f_align, a_ty), @@ -302,17 +312,19 @@ pub fn store_operand(&mut self, bcx.store(base::from_immediate(bcx, s), lldest, align); } OperandValue::Pair(a, b) => { - let f_align = match *bcx.ccx.layout_of(operand.ty) { - Layout::Univariant { ref variant, .. } if variant.packed => { - Some(1) + let (ix0, ix1, f_align) = match *bcx.ccx.layout_of(operand.ty) { + Layout::Univariant { ref variant, .. } => { + (adt::struct_llfields_index(variant, 0), + adt::struct_llfields_index(variant, 1), + if variant.packed { Some(1) } else { None }) } - _ => align + _ => (0, 1, align) }; let a = base::from_immediate(bcx, a); let b = base::from_immediate(bcx, b); - bcx.store(a, bcx.struct_gep(lldest, 0), f_align); - bcx.store(b, bcx.struct_gep(lldest, 1), f_align); + bcx.store(a, bcx.struct_gep(lldest, ix0), f_align); + bcx.store(b, bcx.struct_gep(lldest, ix1), f_align); } } } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 98e9008f829..b8e9a490b0e 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -130,10 +130,12 @@ pub fn trans_rvalue(&mut self, _ => { // If this is a tuple or closure, we need to translate GEP indices. let layout = bcx.ccx.layout_of(dest.ty.to_ty(bcx.tcx())); - let translation = if let Layout::Univariant { ref variant, .. } = *layout { - Some(&variant.memory_index) - } else { - None + let get_memory_index = |i| { + if let Layout::Univariant { ref variant, .. } = *layout { + adt::struct_llfields_index(variant, i) + } else { + i + } }; let alignment = dest.alignment; for (i, operand) in operands.iter().enumerate() { @@ -143,11 +145,7 @@ pub fn trans_rvalue(&mut self, // Note: perhaps this should be StructGep, but // note that in some cases the values here will // not be structs but arrays. - let i = if let Some(ref t) = translation { - t[i] as usize - } else { - i - }; + let i = get_memory_index(i); let dest = bcx.gepi(dest.llval, &[0, i]); self.store_operand(&bcx, dest, alignment.to_align(), op); } @@ -331,7 +329,7 @@ pub fn trans_rvalue_operand(&mut self, let ty = tr_lvalue.ty.to_ty(bcx.tcx()); let ref_ty = bcx.tcx().mk_ref( - bcx.tcx().mk_region(ty::ReErased), + bcx.tcx().types.re_erased, ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() } ); diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 382ca8ef010..d27eeb2b646 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -13,17 +13,13 @@ use glue; use rustc::hir::def_id::DefId; -use rustc::infer::TransNormalize; use rustc::middle::lang_items::DropInPlaceFnLangItem; -use rustc::traits::{self, SelectionContext, Reveal}; +use rustc::traits; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::ty::fold::{TypeFolder, TypeFoldable}; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::util::common::MemoizationMap; -use syntax::ast; -use syntax::codemap::{Span, DUMMY_SP}; +use syntax::codemap::DUMMY_SP; pub use rustc::ty::Instance; @@ -104,73 +100,6 @@ pub fn resolve_closure<'a, 'tcx> ( } } -/// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we -/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should -/// guarantee to us that all nested obligations *could be* resolved if we wanted to. -fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - span: Span, - trait_ref: ty::PolyTraitRef<'tcx>) - -> traits::Vtable<'tcx, ()> -{ - let tcx = scx.tcx(); - - // Remove any references to regions; this helps improve caching. - let trait_ref = tcx.erase_regions(&trait_ref); - - scx.trait_cache().memoize(trait_ref, || { - debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", - trait_ref, trait_ref.def_id()); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - tcx.infer_ctxt((), Reveal::All).enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = traits::ObligationCause::misc(span, - ast::DUMMY_NODE_ID); - let obligation = traits::Obligation::new(obligation_cause, - trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - debug!("Encountered ambiguity selecting `{:?}` during trans, \ - presuming due to overflow", - trait_ref); - tcx.sess.span_fatal(span, - "reached the recursion limit during monomorphization \ - (selection ambiguity)"); - } - Err(e) => { - span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", - e, trait_ref) - } - }; - - debug!("fulfill_obligation: selection={:?}", selection); - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = traits::FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) - }) -} - fn resolve_associated_item<'a, 'tcx>( scx: &SharedCrateContext<'a, 'tcx>, trait_item: &ty::AssociatedItem, @@ -185,7 +114,7 @@ fn resolve_associated_item<'a, 'tcx>( def_id, trait_id, rcvr_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref)); + let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::Binder(trait_ref)); // Now that we know which impl is being used, we can dispatch to // the actual function: @@ -285,7 +214,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty]) }); - match fulfill_obligation(scx, DUMMY_SP, trait_ref) { + match scx.tcx().trans_fulfill_obligation(DUMMY_SP, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap() } @@ -295,21 +224,6 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx } } -/// Monomorphizes a type from the AST by first applying the in-scope -/// substitutions and then normalizing any associated types. -pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>, - param_substs: &Substs<'tcx>, - value: &T) - -> T - where T: TransNormalize<'tcx> -{ - let tcx = scx.tcx(); - debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); - let substituted = value.subst(tcx, param_substs); - let substituted = scx.tcx().erase_regions(&substituted); - AssociatedTypeNormalizer::new(scx).fold(&substituted) -} - /// Returns the normalized type of a struct field pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_substs: &Substs<'tcx>, @@ -319,39 +233,3 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.normalize_associated_type(&f.ty(tcx, param_substs)) } -struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b> { - shared: &'a SharedCrateContext<'b, 'gcx>, -} - -impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> { - fn new(shared: &'a SharedCrateContext<'b, 'gcx>) -> Self { - AssociatedTypeNormalizer { - shared: shared, - } - } - - fn fold>(&mut self, value: &T) -> T { - if !value.has_projection_types() { - value.clone() - } else { - value.fold_with(self) - } - } -} - -impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { - self.shared.tcx() - } - - fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { - if !ty.has_projection_types() { - ty - } else { - self.shared.project_cache().memoize(ty, || { - debug!("AssociatedTypeNormalizer: ty={:?}", ty); - self.shared.tcx().normalize_associated_type(&ty) - }) - } - } -} diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 4973181202e..6b89d11cfb6 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -116,7 +116,7 @@ use std::cmp::Ordering; use std::hash::Hash; use std::sync::Arc; -use symbol_map::SymbolMap; +use symbol_cache::SymbolCache; use syntax::ast::NodeId; use syntax::symbol::{Symbol, InternedString}; use trans_item::{TransItem, InstantiationMode}; @@ -174,14 +174,15 @@ pub fn work_product_dep_node(&self) -> DepNode { DepNode::WorkProduct(self.work_product_id()) } - pub fn compute_symbol_name_hash(&self, - scx: &SharedCrateContext, - symbol_map: &SymbolMap) -> u64 { + pub fn compute_symbol_name_hash<'a>(&self, + scx: &SharedCrateContext<'a, 'tcx>, + symbol_cache: &SymbolCache<'a, 'tcx>) + -> u64 { let mut state = IchHasher::new(); let exported_symbols = scx.exported_symbols(); - let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_map); + let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_cache); for (item, _) in all_items { - let symbol_name = symbol_map.get(item).unwrap(); + let symbol_name = symbol_cache.get(item); symbol_name.len().hash(&mut state); symbol_name.hash(&mut state); let exported = match item { @@ -201,10 +202,10 @@ pub fn compute_symbol_name_hash(&self, state.finish().to_smaller_hash() } - pub fn items_in_deterministic_order(&self, - tcx: TyCtxt, - symbol_map: &SymbolMap) - -> Vec<(TransItem<'tcx>, llvm::Linkage)> { + pub fn items_in_deterministic_order<'a>(&self, + tcx: TyCtxt, + symbol_cache: &SymbolCache<'a, 'tcx>) + -> Vec<(TransItem<'tcx>, llvm::Linkage)> { let mut items: Vec<(TransItem<'tcx>, llvm::Linkage)> = self.items.iter().map(|(item, linkage)| (*item, *linkage)).collect(); @@ -216,9 +217,9 @@ pub fn items_in_deterministic_order(&self, match (node_id1, node_id2) { (None, None) => { - let symbol_name1 = symbol_map.get(trans_item1).unwrap(); - let symbol_name2 = symbol_map.get(trans_item2).unwrap(); - symbol_name1.cmp(symbol_name2) + let symbol_name1 = symbol_cache.get(trans_item1); + let symbol_name2 = symbol_cache.get(trans_item2); + symbol_name1.cmp(&symbol_name2) } // In the following two cases we can avoid looking up the symbol (None, Some(_)) => Ordering::Less, @@ -230,9 +231,9 @@ pub fn items_in_deterministic_order(&self, return ordering; } - let symbol_name1 = symbol_map.get(trans_item1).unwrap(); - let symbol_name2 = symbol_map.get(trans_item2).unwrap(); - symbol_name1.cmp(symbol_name2) + let symbol_name1 = symbol_cache.get(trans_item1); + let symbol_name2 = symbol_cache.get(trans_item2); + symbol_name1.cmp(&symbol_name2) } } }); @@ -271,14 +272,14 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let mut initial_partitioning = place_root_translation_items(scx, trans_items); - debug_dump(scx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter()); // If the partitioning should produce a fixed count of codegen units, merge // until that count is reached. if let PartitioningStrategy::FixedUnitCount(count) = strategy { merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name.as_str()); - debug_dump(scx, "POST MERGING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); } // In the next step, we use the inlining map to determine which addtional @@ -288,7 +289,7 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let post_inlining = place_inlined_translation_items(initial_partitioning, inlining_map); - debug_dump(scx, "POST INLINING:", post_inlining.0.iter()); + debug_dump(tcx, "POST INLINING:", post_inlining.0.iter()); // Finally, sort by codegen unit name, so that we get deterministic results let mut result = post_inlining.0; @@ -528,7 +529,7 @@ fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString Symbol::intern(&format!("{}{}{}", crate_name, NUMBERED_CODEGEN_UNIT_MARKER, index)).as_str() } -fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, +fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, label: &str, cgus: I) where I: Iterator>, @@ -536,20 +537,18 @@ fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, { if cfg!(debug_assertions) { debug!("{}", label); + let symbol_cache = SymbolCache::new(tcx); for cgu in cgus { - let symbol_map = SymbolMap::build(scx, cgu.items - .iter() - .map(|(&trans_item, _)| trans_item)); debug!("CodegenUnit {}:", cgu.name); for (trans_item, linkage) in &cgu.items { - let symbol_name = symbol_map.get_or_compute(scx, *trans_item); + let symbol_name = symbol_cache.get(*trans_item); let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..]) .unwrap_or(""); debug!(" - {} [{:?}] [{}]", - trans_item.to_string(scx.tcx()), + trans_item.to_string(tcx), linkage, symbol_hash); } diff --git a/src/librustc_trans/symbol_cache.rs b/src/librustc_trans/symbol_cache.rs new file mode 100644 index 00000000000..ddc1ef537a5 --- /dev/null +++ b/src/librustc_trans/symbol_cache.rs @@ -0,0 +1,42 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::ty::TyCtxt; +use std::cell::RefCell; +use syntax_pos::symbol::{InternedString, Symbol}; +use trans_item::TransItem; +use util::nodemap::FxHashMap; + +// In the SymbolCache we collect the symbol names of translation items +// and cache them for later reference. This is just a performance +// optimization and the cache is populated lazilly; symbol names of +// translation items are deterministic and fully defined by the item. +// Thus they can always be recomputed if needed. + +pub struct SymbolCache<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + index: RefCell, Symbol>>, +} + +impl<'a, 'tcx> SymbolCache<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + SymbolCache { + tcx: tcx, + index: RefCell::new(FxHashMap()) + } + } + + pub fn get(&self, trans_item: TransItem<'tcx>) -> InternedString { + let mut index = self.index.borrow_mut(); + index.entry(trans_item) + .or_insert_with(|| Symbol::intern(&trans_item.compute_symbol_name(self.tcx))) + .as_str() + } +} diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs index 36c3981e3a6..9d3e62888a2 100644 --- a/src/librustc_trans/symbol_map.rs +++ b/src/librustc_trans/symbol_map.rs @@ -34,8 +34,9 @@ pub fn build<'a, I>(scx: &SharedCrateContext<'a, 'tcx>, where I: Iterator> { // Check for duplicate symbol names + let tcx = scx.tcx(); let mut symbols: Vec<_> = trans_items.map(|trans_item| { - (trans_item, trans_item.compute_symbol_name(scx)) + (trans_item, trans_item.compute_symbol_name(tcx)) }).collect(); (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{ @@ -124,7 +125,7 @@ pub fn get_or_compute<'map, 'scx>(&'map self, if let Some(sym) = self.get(trans_item) { Cow::from(sym) } else { - Cow::from(trans_item.compute_symbol_name(scx)) + Cow::from(trans_item.compute_symbol_name(scx.tcx())) } } } diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index fe551b06b3d..fd817cb94c1 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -17,43 +17,42 @@ use back::symbol_names; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::ty::TyCtxt; use syntax::ast; -use common::SharedCrateContext; use monomorphize::Instance; const SYMBOL_NAME: &'static str = "rustc_symbol_name"; const ITEM_PATH: &'static str = "rustc_item_path"; -pub fn report_symbol_names(scx: &SharedCrateContext) { +pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // if the `rustc_attrs` feature is not enabled, then the // attributes we are interested in cannot be present anyway, so // skip the walk. - let tcx = scx.tcx(); if !tcx.sess.features.borrow().rustc_attrs { return; } let _ignore = tcx.dep_graph.in_ignore(); - let mut visitor = SymbolNamesTest { scx: scx }; + let mut visitor = SymbolNamesTest { tcx: tcx }; // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } struct SymbolNamesTest<'a, 'tcx:'a> { - scx: &'a SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, } impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { fn process_attrs(&mut self, node_id: ast::NodeId) { - let tcx = self.scx.tcx(); + let tcx = self.tcx; let def_id = tcx.hir.local_def_id(node_id); for attr in tcx.get_attrs(def_id).iter() { if attr.check_name(SYMBOL_NAME) { // for now, can only use on monomorphic names let instance = Instance::mono(tcx, def_id); - let name = symbol_names::symbol_name(instance, self.scx); + let name = symbol_names::symbol_name(instance, self.tcx); tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); } else if attr.check_name(ITEM_PATH) { let path = tcx.item_path_str(def_id); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 4d908f3c94f..d8e139dc505 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -18,7 +18,7 @@ use attributes; use base; use consts; -use context::{CrateContext, SharedCrateContext}; +use context::CrateContext; use common; use declare; use llvm; @@ -118,8 +118,7 @@ pub fn predefine(&self, self.to_raw_string(), ccx.codegen_unit().name()); - let symbol_name = ccx.symbol_map() - .get_or_compute(ccx.shared(), *self); + let symbol_name = ccx.symbol_cache().get(*self); debug!("symbol {}", &symbol_name); @@ -185,16 +184,15 @@ fn predefine_fn(ccx: &CrateContext<'a, 'tcx>, ccx.instances().borrow_mut().insert(instance, lldecl); } - pub fn compute_symbol_name(&self, - scx: &SharedCrateContext<'a, 'tcx>) -> String { + pub fn compute_symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { match *self { - TransItem::Fn(instance) => symbol_names::symbol_name(instance, scx), + TransItem::Fn(instance) => symbol_names::symbol_name(instance, tcx), TransItem::Static(node_id) => { - let def_id = scx.tcx().hir.local_def_id(node_id); - symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx) + let def_id = tcx.hir.local_def_id(node_id); + symbol_names::symbol_name(Instance::mono(tcx, def_id), tcx) } TransItem::GlobalAsm(node_id) => { - let def_id = scx.tcx().hir.local_def_id(node_id); + let def_id = tcx.hir.local_def_id(node_id); format!("global_asm_{:?}", def_id) } } @@ -446,7 +444,7 @@ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) { }, ty::TyClosure(def_id, ref closure_substs) => { self.push_def_path(def_id, output); - let generics = self.tcx.item_generics(self.tcx.closure_base_def_id(def_id)); + let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id)); let substs = closure_substs.substs.truncate_to(self.tcx, generics); self.push_type_params(substs, iter::empty(), output); } diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index d4ab6b07828..9f9126ba83a 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -214,6 +214,16 @@ pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign { pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize { self.layout_of(ty).size(self).bytes() as machine::llsize } + + pub fn over_align_of(&self, t: Ty<'tcx>) + -> Option { + let layout = self.layout_of(t); + if let Some(align) = layout.over_align(&self.tcx().data_layout) { + Some(align as machine::llalign) + } else { + None + } + } } fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String { diff --git a/src/librustc_tsan/build.rs b/src/librustc_tsan/build.rs index 055b344d2e9..5ea52f17a0f 100644 --- a/src/librustc_tsan/build.rs +++ b/src/librustc_tsan/build.rs @@ -12,14 +12,13 @@ extern crate cmake; use std::env; -use build_helper::native_lib_boilerplate; +use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { - let native = match native_lib_boilerplate("compiler-rt", "tsan", "clang_rt.tsan-x86_64", - "build/lib/linux") { + let native = match sanitizer_lib_boilerplate("tsan") { Ok(native) => native, _ => return, }; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9426d601dfc..92f80a3607b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -109,7 +109,7 @@ pub fn ast_region_to_region(&self, let tcx = self.tcx(); let r = match tcx.named_region_map.defs.get(&lifetime.id) { Some(&rl::Region::Static) => { - tcx.mk_region(ty::ReStatic) + tcx.types.re_static } Some(&rl::Region::LateBound(debruijn, id)) => { @@ -171,7 +171,7 @@ pub fn ast_path_substs_for_ty(&self, .emit(); return Substs::for_item(tcx, def_id, |_, _| { - tcx.mk_region(ty::ReStatic) + tcx.types.re_static }, |_, _| { tcx.types.err }); @@ -217,7 +217,7 @@ fn create_substs_for_ast_path(&self, // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). - let decl_generics = tcx.item_generics(def_id); + let decl_generics = tcx.generics_of(def_id); let expected_num_region_params = decl_generics.regions.len(); let supplied_num_region_params = lifetimes.len(); if expected_num_region_params != supplied_num_region_params { @@ -238,7 +238,7 @@ fn create_substs_for_ast_path(&self, let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); let default_needs_object_self = |p: &ty::TypeParameterDef| { if is_object && p.has_default { - if ty::queries::ty::get(tcx, span, p.def_id).has_self_ty() { + if tcx.at(span).type_of(p.def_id).has_self_ty() { // There is no suitable inference default for a type parameter // that references self, in an object type. return true; @@ -254,7 +254,7 @@ fn create_substs_for_ast_path(&self, if let Some(lifetime) = lifetimes.get(i) { self.ast_region_to_region(lifetime, Some(def)) } else { - tcx.mk_region(ty::ReStatic) + tcx.types.re_static } }, |def, substs| { let i = def.index as usize; @@ -307,7 +307,7 @@ fn create_substs_for_ast_path(&self, // This is a default type parameter. self.normalize_ty( span, - ty::queries::ty::get(tcx, span, def.def_id) + tcx.at(span).type_of(def.def_id) .subst_spanned(tcx, substs, Some(span)) ) } @@ -458,7 +458,7 @@ fn create_substs_for_ast_trait_ref(&self, debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); - let trait_def = self.tcx().lookup_trait_def(trait_def_id); + let trait_def = self.tcx().trait_def(trait_def_id); match trait_segment.parameters { hir::AngleBracketedParameters(_) => { @@ -600,7 +600,7 @@ fn ast_path_to_ty(&self, let substs = self.ast_path_substs_for_ty(span, did, item_segment); self.normalize_ty( span, - ty::queries::ty::get(self.tcx(), span, did).subst(self.tcx(), substs) + self.tcx().at(span).type_of(did).subst(self.tcx(), substs) ) } @@ -715,7 +715,7 @@ fn conv_object_ty_poly_trait_ref(&self, span_err!(tcx.sess, span, E0228, "the lifetime bound for this object type cannot be deduced \ from context; please supply an explicit bound"); - tcx.mk_region(ty::ReStatic) + tcx.types.re_static }) } }) @@ -903,10 +903,16 @@ pub fn associated_path_def_to_ty(&self, let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name); let ty = self.normalize_ty(span, ty); - let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name); - let def_id = item.expect("missing associated type").def_id; - tcx.check_stability(def_id, ref_id, span); - (ty, Def::AssociatedTy(def_id)) + let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name) + .expect("missing associated type"); + let def = Def::AssociatedTy(item.def_id); + if !tcx.vis_is_accessible_from(item.vis, ref_id) { + let msg = format!("{} `{}` is private", def.kind_name(), assoc_name); + tcx.sess.span_err(span, &msg); + } + tcx.check_stability(item.def_id, ref_id, span); + + (ty, def) } fn qpath_to_ty(&self, @@ -1008,7 +1014,7 @@ pub fn def_to_ty(&self, let node_id = tcx.hir.as_local_node_id(did).unwrap(); let item_id = tcx.hir.get_parent_node(node_id); let item_def_id = tcx.hir.local_def_id(item_id); - let generics = tcx.item_generics(item_def_id); + let generics = tcx.generics_of(item_def_id); let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id).index]; tcx.mk_param(index, tcx.hir.name(node_id)) } @@ -1018,7 +1024,7 @@ pub fn def_to_ty(&self, assert_eq!(opt_self_ty, None); self.prohibit_type_params(&path.segments); - let ty = ty::queries::ty::get(tcx, span, def_id); + let ty = tcx.at(span).type_of(def_id); if let Some(free_substs) = self.get_free_substs() { ty.subst(tcx, free_substs) } else { @@ -1357,7 +1363,7 @@ fn compute_object_lifetime_bound(&self, // If any of the derived region bounds are 'static, that is always // the best choice. if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) { - return Some(tcx.mk_region(ty::ReStatic)); + return Some(tcx.types.re_static); } // Determine whether there is exactly one unique region in the set diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 4a044642444..1086773041c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -55,7 +55,7 @@ pub fn check_pat_arg(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>, is_arg: boo let expected_ty = self.structurally_resolved_type(pat.span, expected); if let ty::TyRef(_, mt) = expected_ty.sty { if let ty::TySlice(_) = mt.ty.sty { - pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), + pat_ty = tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_slice(tcx.types.u8)) } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index c6a1f6cfc0d..d21b5f739bd 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -78,6 +78,7 @@ use syntax::abi; use syntax::feature_gate; use syntax::ptr::P; +use syntax_pos; use std::collections::VecDeque; use std::ops::Deref; @@ -722,6 +723,16 @@ pub fn try_coerce(&self, Ok(target) } + /// Same as `try_coerce()`, but without side-effects. + pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool { + let source = self.resolve_type_vars_with_obligations(expr_ty); + debug!("coercion::can({:?} -> {:?})", source, target); + + let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable); + let coerce = Coerce::new(self, cause); + self.probe(|_| coerce.coerce::(&[], source, target)).is_ok() + } + /// Given some expressions, their known unified type and another expression, /// tries to unify the types, potentially inserting coercions on any of the /// provided expressions and returns their LUB (aka "common supertype"). diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index ae70049cc5b..a38840552c2 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -180,10 +180,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs); - let impl_m_generics = tcx.item_generics(impl_m.def_id); - let trait_m_generics = tcx.item_generics(trait_m.def_id); - let impl_m_predicates = tcx.item_predicates(impl_m.def_id); - let trait_m_predicates = tcx.item_predicates(trait_m.def_id); + let impl_m_generics = tcx.generics_of(impl_m.def_id); + let trait_m_generics = tcx.generics_of(trait_m.def_id); + let impl_m_predicates = tcx.predicates_of(impl_m.def_id); + let trait_m_predicates = tcx.predicates_of(trait_m.def_id); // Check region bounds. check_region_bounds_on_impl_method(tcx, @@ -199,7 +199,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // environment. We can't just use `impl_env.caller_bounds`, // however, because we want to replace all late-bound regions with // region variables. - let impl_predicates = tcx.item_predicates(impl_m_predicates.parent.unwrap()); + let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap()); let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); @@ -261,7 +261,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let tcx = infcx.tcx; let m_sig = |method: &ty::AssociatedItem| { - match tcx.item_type(method.def_id).sty { + match tcx.type_of(method.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => bug!() } @@ -509,7 +509,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::ImplContainer(_) => impl_trait_ref.self_ty(), ty::TraitContainer(_) => tcx.mk_self_type() }; - let method_ty = tcx.item_type(method.def_id); + let method_ty = tcx.type_of(method.def_id); let self_arg_ty = *method_ty.fn_sig().input(0).skip_binder(); match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) { ExplicitSelf::ByValue => "self".to_string(), @@ -567,8 +567,8 @@ fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_m: &ty::AssociatedItem, trait_item_span: Option) -> Result<(), ErrorReported> { - let impl_m_generics = tcx.item_generics(impl_m.def_id); - let trait_m_generics = tcx.item_generics(trait_m.def_id); + let impl_m_generics = tcx.generics_of(impl_m.def_id); + let trait_m_generics = tcx.generics_of(trait_m.def_id); let num_impl_m_type_params = impl_m_generics.types.len(); let num_trait_m_type_params = trait_m_generics.types.len(); if num_impl_m_type_params != num_trait_m_type_params { @@ -637,7 +637,7 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_span: Option) -> Result<(), ErrorReported> { let m_fty = |method: &ty::AssociatedItem| { - match tcx.item_type(method.def_id).sty { + match tcx.type_of(method.def_id).sty { ty::TyFnDef(_, _, f) => f, _ => bug!() } @@ -750,8 +750,8 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_to_skol_substs); // Compute skolemized form of impl and trait const tys. - let impl_ty = tcx.item_type(impl_c.def_id).subst(tcx, impl_to_skol_substs); - let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs); + let impl_ty = tcx.type_of(impl_c.def_id).subst(tcx, impl_to_skol_substs); + let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_skol_substs); let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id); // There is no "body" here, so just pass dummy id. diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index e922c7447ff..d92dafe6904 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -10,15 +10,14 @@ use check::FnCtxt; -use rustc::ty::Ty; -use rustc::infer::{InferOk}; +use rustc::infer::InferOk; use rustc::traits::ObligationCause; use syntax::ast; use syntax_pos::{self, Span}; use rustc::hir; use rustc::hir::def::Def; -use rustc::ty::{self, AssociatedItem}; +use rustc::ty::{self, Ty, AssociatedItem}; use errors::DiagnosticBuilder; use super::method::probe; @@ -80,18 +79,24 @@ pub fn demand_coerce(&self, if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) { let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); - let mode = probe::Mode::MethodCall; - let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP, - mode, - expected, - checked_ty, - ast::DUMMY_NODE_ID); let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); - if suggestions.len() > 0 { - err.help(&format!("here are some functions which \ - might fulfill your needs:\n{}", - self.get_best_match(&suggestions).join("\n"))); - }; + if let Some(suggestion) = self.check_ref(expr, + checked_ty, + expected) { + err.help(&suggestion); + } else { + let mode = probe::Mode::MethodCall; + let suggestions = self.probe_for_return_type(syntax_pos::DUMMY_SP, + mode, + expected, + checked_ty, + ast::DUMMY_NODE_ID); + if suggestions.len() > 0 { + err.help(&format!("here are some functions which \ + might fulfill your needs:\n{}", + self.get_best_match(&suggestions).join("\n"))); + } + } err.emit(); } } @@ -130,7 +135,7 @@ fn get_best_match(&self, methods: &[AssociatedItem]) -> Vec { fn has_no_input_arg(&self, method: &AssociatedItem) -> bool { match method.def() { Def::Method(def_id) => { - match self.tcx.item_type(def_id).sty { + match self.tcx.type_of(def_id).sty { ty::TypeVariants::TyFnDef(_, _, sig) => { sig.inputs().skip_binder().len() == 1 } @@ -140,4 +145,60 @@ fn has_no_input_arg(&self, method: &AssociatedItem) -> bool { _ => false, } } + + /// This function is used to determine potential "simple" improvements or users' errors and + /// provide them useful help. For example: + /// + /// ``` + /// fn some_fn(s: &str) {} + /// + /// let x = "hey!".to_owned(); + /// some_fn(x); // error + /// ``` + /// + /// No need to find every potential function which could make a coercion to transform a + /// `String` into a `&str` since a `&` would do the trick! + /// + /// In addition of this check, it also checks between references mutability state. If the + /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with + /// `&mut`!". + fn check_ref(&self, + expr: &hir::Expr, + checked_ty: Ty<'tcx>, + expected: Ty<'tcx>) + -> Option { + match (&expected.sty, &checked_ty.sty) { + (&ty::TyRef(_, _), &ty::TyRef(_, _)) => None, + (&ty::TyRef(_, mutability), _) => { + // Check if it can work when put into a ref. For example: + // + // ``` + // fn bar(x: &mut i32) {} + // + // let x = 0u32; + // bar(&x); // error, expected &mut + // ``` + let ref_ty = match mutability.mutbl { + hir::Mutability::MutMutable => self.tcx.mk_mut_ref( + self.tcx.mk_region(ty::ReStatic), + checked_ty), + hir::Mutability::MutImmutable => self.tcx.mk_imm_ref( + self.tcx.mk_region(ty::ReStatic), + checked_ty), + }; + if self.can_coerce(ref_ty, expected) { + if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) { + return Some(format!("try with `{}{}`", + match mutability.mutbl { + hir::Mutability::MutMutable => "&mut ", + hir::Mutability::MutImmutable => "&", + }, + &src)); + } + } + None + } + _ => None, + } + } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index b71ff58ccec..8d26f007429 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -15,12 +15,11 @@ use rustc::infer::{self, InferOk}; use middle::region; use rustc::ty::subst::{Subst, Substs}; -use rustc::ty::{self, AdtKind, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::traits::{self, ObligationCause, Reveal}; use util::common::ErrorReported; use util::nodemap::FxHashSet; -use syntax::ast; use syntax_pos::Span; /// check_drop_impl confirms that the Drop implementation identfied by @@ -43,8 +42,8 @@ pub fn check_drop_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, drop_impl_did: DefId) -> Result<(), ErrorReported> { - let dtor_self_type = tcx.item_type(drop_impl_did); - let dtor_predicates = tcx.item_predicates(drop_impl_did); + let dtor_self_type = tcx.type_of(drop_impl_did); + let dtor_predicates = tcx.predicates_of(drop_impl_did); match dtor_self_type.sty { ty::TyAdt(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond(tcx, @@ -86,7 +85,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); - let named_type = tcx.item_type(self_type_did); + let named_type = tcx.type_of(self_type_did); let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs); let drop_impl_span = tcx.def_span(drop_impl_did); @@ -176,7 +175,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( // We can assume the predicates attached to struct/enum definition // hold. - let generic_assumptions = tcx.item_predicates(self_type_did); + let generic_assumptions = tcx.predicates_of(self_type_did); let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); let assumptions_in_impl_context = assumptions_in_impl_context.predicates; @@ -270,389 +269,64 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>( /// pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>, - typ: ty::Ty<'tcx>, + ty: ty::Ty<'tcx>, span: Span, scope: region::CodeExtent) + -> Result<(), ErrorReported> { debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}", - typ, scope); + ty, scope); let parent_scope = match rcx.tcx.region_maps.opt_encl_scope(scope) { - Some(parent_scope) => parent_scope, - // If no enclosing scope, then it must be the root scope which cannot be outlived. - None => return + Some(parent_scope) => parent_scope, + // If no enclosing scope, then it must be the root scope + // which cannot be outlived. + None => return Ok(()) }; - - let result = iterate_over_potentially_unsafe_regions_in_type( - &mut DropckContext { - rcx: rcx, - span: span, - parent_scope: parent_scope, - breadcrumbs: FxHashSet() - }, - TypeContext::Root, - typ, - 0); - match result { - Ok(()) => {} - Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => { - let tcx = rcx.tcx; - let mut err = struct_span_err!(tcx.sess, span, E0320, - "overflow while adding drop-check rules for {}", typ); - match *ctxt { - TypeContext::Root => { - // no need for an additional note if the overflow - // was somehow on the root. - } - TypeContext::ADT { def_id, variant, field } => { - let adt = tcx.lookup_adt_def(def_id); - let variant_name = match adt.adt_kind() { - AdtKind::Enum => format!("enum {} variant {}", - tcx.item_path_str(def_id), - variant), - AdtKind::Struct => format!("struct {}", - tcx.item_path_str(def_id)), - AdtKind::Union => format!("union {}", - tcx.item_path_str(def_id)), - }; - span_note!( - &mut err, - span, - "overflowed on {} field {} type: {}", - variant_name, - field, - detected_on_typ); + let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope)); + let origin = || infer::SubregionOrigin::SafeDestructor(span); + + let ty = rcx.fcx.resolve_type_vars_if_possible(&ty); + let for_ty = ty; + let mut types = vec![(ty, 0)]; + let mut known = FxHashSet(); + while let Some((ty, depth)) = types.pop() { + let ty::DtorckConstraint { + dtorck_types, outlives + } = rcx.tcx.dtorck_constraint_for_ty(span, for_ty, depth, ty)?; + + for ty in dtorck_types { + let ty = rcx.fcx.normalize_associated_types_in(span, &ty); + let ty = rcx.fcx.resolve_type_vars_with_obligations(ty); + let ty = rcx.fcx.resolve_type_and_region_vars_if_possible(&ty); + match ty.sty { + // All parameters live for the duration of the + // function. + ty::TyParam(..) => {} + + // A projection that we couldn't resolve - it + // might have a destructor. + ty::TyProjection(..) | ty::TyAnon(..) => { + rcx.type_must_outlive(origin(), ty, parent_scope); } - } - err.emit(); - } - } -} - -enum Error<'tcx> { - Overflow(TypeContext, ty::Ty<'tcx>), -} - -#[derive(Copy, Clone)] -enum TypeContext { - Root, - ADT { - def_id: DefId, - variant: ast::Name, - field: ast::Name, - } -} - -struct DropckContext<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> { - rcx: &'a mut RegionCtxt<'b, 'gcx, 'tcx>, - /// types that have already been traversed - breadcrumbs: FxHashSet>, - /// span for error reporting - span: Span, - /// the scope reachable dtorck types must outlive - parent_scope: region::CodeExtent -} - -// `context` is used for reporting overflow errors -fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( - cx: &mut DropckContext<'a, 'b, 'gcx, 'tcx>, - context: TypeContext, - ty: Ty<'tcx>, - depth: usize) - -> Result<(), Error<'tcx>> -{ - let tcx = cx.rcx.tcx; - // Issue #22443: Watch out for overflow. While we are careful to - // handle regular types properly, non-regular ones cause problems. - let recursion_limit = tcx.sess.recursion_limit.get(); - if depth / 4 >= recursion_limit { - // This can get into rather deep recursion, especially in the - // presence of things like Vec -> Unique -> PhantomData -> T. - // use a higher recursion limit to avoid errors. - return Err(Error::Overflow(context, ty)) - } - // canoncialize the regions in `ty` before inserting - infinitely many - // region variables can refer to the same region. - let ty = cx.rcx.resolve_type_and_region_vars_if_possible(&ty); - - if !cx.breadcrumbs.insert(ty) { - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?} - cached", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - return Ok(()); // we already visited this type - } - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?}", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - - // If `typ` has a destructor, then we must ensure that all - // borrowed data reachable via `typ` must outlive the parent - // of `scope`. This is handled below. - // - // However, there is an important special case: for any Drop - // impl that is tagged as "blind" to their parameters, - // we assume that data borrowed via such type parameters - // remains unreachable via that Drop impl. - // - // For example, consider: - // - // ```rust - // #[unsafe_destructor_blind_to_params] - // impl Drop for Vec { ... } - // ``` - // - // which does have to be able to drop instances of `T`, but - // otherwise cannot read data from `T`. - // - // Of course, for the type expression passed in for any such - // unbounded type parameter `T`, we must resume the recursive - // analysis on `T` (since it would be ignored by - // type_must_outlive). - let dropck_kind = has_dtor_of_interest(tcx, ty); - debug!("iterate_over_potentially_unsafe_regions_in_type \ - ty: {:?} dropck_kind: {:?}", ty, dropck_kind); - match dropck_kind { - DropckKind::NoBorrowedDataAccessedInMyDtor => { - // The maximally blind attribute. - } - DropckKind::BorrowedDataMustStrictlyOutliveSelf => { - cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), - ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); - return Ok(()); - } - DropckKind::RevisedSelf(revised_ty) => { - cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span), - revised_ty, tcx.mk_region(ty::ReScope(cx.parent_scope))); - // Do not return early from this case; we want - // to recursively process the internal structure of Self - // (because even though the Drop for Self has been asserted - // safe, the types instantiated for the generics of Self - // may themselves carry dropck constraints.) - } - } - - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}ty: {} scope: {:?} - checking interior", - (0..depth).map(|_| ' ').collect::(), - ty, cx.parent_scope); - - // We still need to ensure all referenced data is safe. - match ty.sty { - ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | - ty::TyFloat(_) | ty::TyStr | ty::TyNever => { - // primitive - definitely safe - Ok(()) - } - - ty::TyArray(ity, _) | ty::TySlice(ity) => { - // single-element containers, behave like their element - iterate_over_potentially_unsafe_regions_in_type( - cx, context, ity, depth+1) - } - - ty::TyAdt(def, substs) if def.is_phantom_data() => { - // PhantomData - behaves identically to T - let ity = substs.type_at(0); - iterate_over_potentially_unsafe_regions_in_type( - cx, context, ity, depth+1) - } - - ty::TyAdt(def, substs) => { - let did = def.did; - for variant in &def.variants { - for field in variant.fields.iter() { - let fty = field.ty(tcx, substs); - let fty = cx.rcx.fcx.resolve_type_vars_with_obligations( - cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty)); - iterate_over_potentially_unsafe_regions_in_type( - cx, - TypeContext::ADT { - def_id: did, - field: field.name, - variant: variant.name, - }, - fty, - depth+1)? + _ => { + if let None = known.replace(ty) { + types.push((ty, depth+1)); + } } } - Ok(()) - } - - ty::TyClosure(def_id, substs) => { - for ty in substs.upvar_tys(def_id, tcx) { - iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? - } - Ok(()) - } - - ty::TyTuple(tys, _) => { - for ty in tys { - iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)? - } - Ok(()) - } - - ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyParam(..) => { - // these always come with a witness of liveness (references - // explicitly, pointers implicitly, parameters by the - // caller). - Ok(()) } - ty::TyFnDef(..) | ty::TyFnPtr(_) => { - // FIXME(#26656): this type is always destruction-safe, but - // it implicitly witnesses Self: Fn, which can be false. - Ok(()) - } - - ty::TyInfer(..) | ty::TyError => { - tcx.sess.delay_span_bug(cx.span, "unresolved type in regionck"); - Ok(()) - } - - // these are always dtorck - ty::TyDynamic(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(), - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum DropckKind<'tcx> { - /// The "safe" kind; i.e. conservatively assume any borrow - /// accessed by dtor, and therefore such data must strictly - /// outlive self. - /// - /// Equivalent to RevisedTy with no change to the self type. - BorrowedDataMustStrictlyOutliveSelf, - - /// The nearly completely-unsafe kind. - /// - /// Equivalent to RevisedSelf with *all* parameters remapped to () - /// (maybe...?) - NoBorrowedDataAccessedInMyDtor, - - /// Assume all borrowed data access by dtor occurs as if Self has the - /// type carried by this variant. In practice this means that some - /// of the type parameters are remapped to `()` (and some lifetime - /// parameters remapped to `'static`), because the developer has asserted - /// that the destructor will not access their contents. - RevisedSelf(Ty<'tcx>), -} - -/// Returns the classification of what kind of check should be applied -/// to `ty`, which may include a revised type where some of the type -/// parameters are re-mapped to `()` to reflect the destructor's -/// "purity" with respect to their actual contents. -fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'tcx>) - -> DropckKind<'tcx> { - match ty.sty { - ty::TyAdt(adt_def, substs) => { - if !adt_def.is_dtorck(tcx) { - return DropckKind::NoBorrowedDataAccessedInMyDtor; + for outlive in outlives { + if let Some(r) = outlive.as_region() { + rcx.sub_regions(origin(), parent_scope, r); + } else if let Some(ty) = outlive.as_type() { + rcx.type_must_outlive(origin(), ty, parent_scope); } - - // Find the `impl<..> Drop for _` to inspect any - // attributes attached to the impl's generics. - let dtor_method = adt_def.destructor(tcx) - .expect("dtorck type without destructor impossible"); - let method = tcx.associated_item(dtor_method.did); - let impl_def_id = method.container.id(); - let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs); - return DropckKind::RevisedSelf(revised_ty); - } - ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyAnon(..) => { - debug!("ty: {:?} isn't known, and therefore is a dropck type", ty); - return DropckKind::BorrowedDataMustStrictlyOutliveSelf; - }, - _ => { - return DropckKind::NoBorrowedDataAccessedInMyDtor; } } -} -// Constructs new Ty just like the type defined by `adt_def` coupled -// with `substs`, except each type and lifetime parameter marked as -// `#[may_dangle]` in the Drop impl (identified by `impl_def_id`) is -// respectively mapped to `()` or `'static`. -// -// For example: If the `adt_def` maps to: -// -// enum Foo<'a, X, Y> { ... } -// -// and the `impl_def_id` maps to: -// -// impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... } -// -// then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>` -fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - adt_def: &'tcx ty::AdtDef, - impl_def_id: DefId, - substs: &Substs<'tcx>) - -> Ty<'tcx> { - // Get generics for `impl Drop` to query for `#[may_dangle]` attr. - let impl_bindings = tcx.item_generics(impl_def_id); - - // Get Substs attached to Self on `impl Drop`; process in parallel - // with `substs`, replacing dangling entries as appropriate. - let self_substs = { - let impl_self_ty: Ty<'tcx> = tcx.item_type(impl_def_id); - if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty { - assert_eq!(adt_def, self_adt_def); - self_substs - } else { - bug!("Self in `impl Drop for _` must be an Adt."); - } - }; - - // Walk `substs` + `self_substs`, build new substs appropriate for - // `adt_def`; each non-dangling param reuses entry from `substs`. - // - // Note: The manner we map from a right-hand side (i.e. Region or - // Ty) for a given `def` to generic parameter associated with that - // right-hand side is tightly coupled to `Drop` impl constraints. - // - // E.g. we know such a Ty must be `TyParam`, because a destructor - // for `struct Foo` is defined via `impl Drop for Foo`, - // and never by (for example) `impl Drop for Foo>`. - let substs = Substs::for_item( - tcx, - adt_def.did, - |def, _| { - let r_orig = substs.region_for_def(def); - let impl_self_orig = self_substs.region_for_def(def); - let r = if let ty::Region::ReEarlyBound(ref ebr) = *impl_self_orig { - if impl_bindings.region_param(ebr).pure_wrt_drop { - tcx.mk_region(ty::ReStatic) - } else { - r_orig - } - } else { - bug!("substs for an impl must map regions to ReEarlyBound"); - }; - debug!("has_dtor_of_interest mapping def {:?} orig {:?} to {:?}", - def, r_orig, r); - r - }, - |def, _| { - let t_orig = substs.type_for_def(def); - let impl_self_orig = self_substs.type_for_def(def); - let t = if let ty::TypeVariants::TyParam(ref pt) = impl_self_orig.sty { - if impl_bindings.type_param(pt).pure_wrt_drop { - tcx.mk_nil() - } else { - t_orig - } - } else { - bug!("substs for an impl must map types to TyParam"); - }; - debug!("has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}", - def, t_orig, t_orig.sty, t, t.sty); - t - }); - - tcx.mk_adt(adt_def, &substs) + Ok(()) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index cd58fcd4806..2a97bc1d98f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -36,7 +36,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let def_id = tcx.hir.local_def_id(it.id); let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.mk_region(ty::ReErased), + |_, _| tcx.types.re_erased, |def, _| tcx.mk_param_from_def(def)); let fty = tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig( @@ -46,7 +46,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir::Unsafety::Unsafe, abi ))); - let i_n_tps = tcx.item_generics(def_id).types.len(); + let i_n_tps = tcx.generics_of(def_id).types.len(); if i_n_tps != n_tps { let span = match it.node { hir::ForeignItemFn(_, _, ref generics) => generics.span, @@ -64,7 +64,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &ObligationCause::new(it.span, it.id, ObligationCauseCode::IntrinsicType), - tcx.item_type(def_id), + tcx.type_of(def_id), fty); } } @@ -324,7 +324,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let def_id = tcx.hir.local_def_id(it.id); - let i_n_tps = tcx.item_generics(def_id).types.len(); + let i_n_tps = tcx.generics_of(def_id).types.len(); let name = it.name.as_str(); let (n_tps, inputs, output) = match &*name { @@ -367,7 +367,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut structural_to_nomimal = FxHashMap(); - let sig = tcx.item_type(def_id).fn_sig(); + let sig = tcx.type_of(def_id).fn_sig(); let sig = tcx.no_late_bound_regions(&sig).unwrap(); if intr.inputs.len() != sig.inputs().len() { span_err!(tcx.sess, it.span, E0444, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 26ba965fe5c..f0a74ea4be9 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -276,7 +276,7 @@ fn instantiate_method_substs(&mut self, // If they were not explicitly supplied, just construct fresh // variables. let num_supplied_types = supplied_method_types.len(); - let method_generics = self.tcx.item_generics(pick.item.def_id); + let method_generics = self.tcx.generics_of(pick.item.def_id); let num_method_types = method_generics.types.len(); if num_supplied_types > 0 && num_supplied_types != num_method_types { @@ -358,14 +358,14 @@ fn instantiate_method_sig(&mut self, // type/early-bound-regions substitutions performed. There can // be no late-bound regions appearing here. let def_id = pick.item.def_id; - let method_predicates = self.tcx.item_predicates(def_id) + let method_predicates = self.tcx.predicates_of(def_id) .instantiate(self.tcx, all_substs); let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates); debug!("method_predicates after subst = {:?}", method_predicates); - let sig = self.tcx.item_type(def_id).fn_sig(); + let sig = self.tcx.type_of(def_id).fn_sig(); // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 7dd2699a6ea..57a9a08a966 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -232,7 +232,7 @@ pub fn lookup_method_in_trait_adjusted(&self, let tcx = self.tcx; let method_item = self.associated_item(trait_def_id, m_name).unwrap(); let def_id = method_item.def_id; - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); assert_eq!(generics.types.len(), 0); assert_eq!(generics.regions.len(), 0); @@ -245,7 +245,7 @@ pub fn lookup_method_in_trait_adjusted(&self, // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let original_method_ty = tcx.item_type(def_id); + let original_method_ty = tcx.type_of(def_id); let fn_sig = original_method_ty.fn_sig(); let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, @@ -272,7 +272,7 @@ pub fn lookup_method_in_trait_adjusted(&self, // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let bounds = self.tcx.item_predicates(def_id).instantiate(self.tcx, substs); + let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs); let bounds = match self.normalize_associated_types_in_as_infer_ok(span, &bounds) { InferOk { value, obligations: o } => { obligations.extend(o); @@ -349,15 +349,8 @@ pub fn resolve_ufcs(&self, } let def = pick.item.def(); - self.tcx.check_stability(def.def_id(), expr_id, span); - if let probe::InherentImplPick = pick.kind { - if !self.tcx.vis_is_accessible_from(pick.item.vis, self.body_id) { - let msg = format!("{} `{}` is private", def.kind_name(), method_name); - self.tcx.sess.span_err(span, &msg); - } - } Ok(def) } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 59dbbfe49f0..3cd53c378dd 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -369,6 +369,24 @@ fn reset(&mut self) { /////////////////////////////////////////////////////////////////////////// // CANDIDATE ASSEMBLY + fn push_inherent_candidate(&mut self, xform_self_ty: Ty<'tcx>, item: ty::AssociatedItem, + kind: CandidateKind<'tcx>, import_id: Option) { + if self.tcx.vis_is_accessible_from(item.vis, self.body_id) { + self.inherent_candidates.push(Candidate { xform_self_ty, item, kind, import_id }); + } else if self.private_candidate.is_none() { + self.private_candidate = Some(item.def()); + } + } + + fn push_extension_candidate(&mut self, xform_self_ty: Ty<'tcx>, item: ty::AssociatedItem, + kind: CandidateKind<'tcx>, import_id: Option) { + if self.tcx.vis_is_accessible_from(item.vis, self.body_id) { + self.extension_candidates.push(Candidate { xform_self_ty, item, kind, import_id }); + } else if self.private_candidate.is_none() { + self.private_candidate = Some(item.def()); + } + } + fn assemble_inherent_candidates(&mut self) { let steps = self.steps.clone(); for step in steps.iter() { @@ -479,7 +497,7 @@ fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option) { } fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) { - let impl_def_ids = ty::queries::inherent_impls::get(self.tcx, self.span, def_id); + let impl_def_ids = self.tcx.at(self.span).inherent_impls(def_id); for &impl_def_id in impl_def_ids.iter() { self.assemble_inherent_impl_probe(impl_def_id); } @@ -499,11 +517,6 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) { continue } - if !self.tcx.vis_is_accessible_from(item.vis, self.body_id) { - self.private_candidate = Some(item.def()); - continue - } - let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); let impl_ty = impl_ty.subst(self.tcx, impl_substs); @@ -519,12 +532,8 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: DefId) { debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}", xform_self_ty); - self.inherent_candidates.push(Candidate { - xform_self_ty: xform_self_ty, - item: item, - kind: InherentImplCandidate(impl_substs, obligations), - import_id: None, - }); + self.push_inherent_candidate(xform_self_ty, item, + InherentImplCandidate(impl_substs, obligations), None); } } @@ -548,12 +557,7 @@ fn assemble_inherent_candidates_from_object(&mut self, let xform_self_ty = this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); - this.inherent_candidates.push(Candidate { - xform_self_ty: xform_self_ty, - item: item, - kind: ObjectCandidate, - import_id: None, - }); + this.push_inherent_candidate(xform_self_ty, item, ObjectCandidate, None); }); } @@ -599,12 +603,8 @@ fn assemble_inherent_candidates_from_param(&mut self, // `WhereClausePick`. assert!(!trait_ref.substs.needs_infer()); - this.inherent_candidates.push(Candidate { - xform_self_ty: xform_self_ty, - item: item, - kind: WhereClauseCandidate(poly_trait_ref), - import_id: None, - }); + this.push_inherent_candidate(xform_self_ty, item, + WhereClauseCandidate(poly_trait_ref), None); }); } @@ -661,7 +661,7 @@ pub fn matches_return_type(&self, method: &ty::AssociatedItem, expected: ty::Ty<'tcx>) -> bool { match method.def() { Def::Method(def_id) => { - let fty = self.tcx.item_type(def_id).fn_sig(); + let fty = self.tcx.type_of(def_id).fn_sig(); self.probe(|_| { let substs = self.fresh_substs_for_item(self.span, method.def_id); let output = fty.output().subst(self.tcx, substs); @@ -706,7 +706,7 @@ fn assemble_extension_candidates_for_trait_impls(&mut self, import_id: Option, trait_def_id: DefId, item: ty::AssociatedItem) { - let trait_def = self.tcx.lookup_trait_def(trait_def_id); + let trait_def = self.tcx.trait_def(trait_def_id); // FIXME(arielb1): can we use for_each_relevant_impl here? trait_def.for_each_impl(self.tcx, |impl_def_id| { @@ -743,12 +743,8 @@ fn assemble_extension_candidates_for_trait_impls(&mut self, debug!("xform_self_ty={:?}", xform_self_ty); - self.extension_candidates.push(Candidate { - xform_self_ty: xform_self_ty, - item: item.clone(), - kind: ExtensionImplCandidate(impl_def_id, impl_substs, obligations), - import_id: import_id, - }); + self.push_extension_candidate(xform_self_ty, item, + ExtensionImplCandidate(impl_def_id, impl_substs, obligations), import_id); }); } @@ -760,7 +756,7 @@ fn impl_can_possibly_match(&self, impl_def_id: DefId) -> bool { } }; - let impl_type = self.tcx.item_type(impl_def_id); + let impl_type = self.tcx.type_of(impl_def_id); let impl_simplified_type = match ty::fast_reject::simplify_type(self.tcx, impl_type, false) { Some(simplified_type) => simplified_type, @@ -833,12 +829,7 @@ fn assemble_closure_candidates(&mut self, }); let xform_self_ty = self.xform_self_ty(&item, step.self_ty, substs); - self.inherent_candidates.push(Candidate { - xform_self_ty: xform_self_ty, - item: item.clone(), - kind: TraitCandidate, - import_id: import_id, - }); + self.push_inherent_candidate(xform_self_ty, item, TraitCandidate, import_id); } Ok(()) @@ -854,7 +845,7 @@ fn assemble_projection_candidates(&mut self, trait_def_id, item); - for step in self.steps.iter() { + for step in Rc::clone(&self.steps).iter() { debug!("assemble_projection_candidates: step={:?}", step); let (def_id, substs) = match step.self_ty.sty { @@ -867,7 +858,7 @@ fn assemble_projection_candidates(&mut self, def_id, substs); - let trait_predicates = self.tcx.item_predicates(def_id); + let trait_predicates = self.tcx.predicates_of(def_id); let bounds = trait_predicates.instantiate(self.tcx, substs); let predicates = bounds.predicates; debug!("assemble_projection_candidates: predicates={:?}", @@ -889,12 +880,7 @@ fn assemble_projection_candidates(&mut self, bound, xform_self_ty); - self.extension_candidates.push(Candidate { - xform_self_ty: xform_self_ty, - item: item.clone(), - kind: TraitCandidate, - import_id: import_id, - }); + self.push_extension_candidate(xform_self_ty, item, TraitCandidate, import_id); } } } @@ -918,12 +904,8 @@ fn assemble_where_clause_candidates(&mut self, bound, xform_self_ty); - self.extension_candidates.push(Candidate { - xform_self_ty: xform_self_ty, - item: item.clone(), - kind: WhereClauseCandidate(poly_bound), - import_id: import_id, - }); + self.push_extension_candidate(xform_self_ty, item, + WhereClauseCandidate(poly_bound), import_id); } } @@ -1063,7 +1045,7 @@ fn pick_autorefd_method(&mut self, step: &CandidateStep<'tcx>) -> Option, substs: &Substs<'tcx>) -> Ty<'tcx> { - let self_ty = self.tcx.item_type(method).fn_sig().input(0); + let self_ty = self.tcx.type_of(method).fn_sig().input(0); debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", impl_ty, self_ty, @@ -1307,7 +1289,7 @@ fn xform_method_self_ty(&self, // are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - let generics = self.tcx.item_generics(method); + let generics = self.tcx.generics_of(method); assert_eq!(substs.types().count(), generics.parent_types as usize); assert_eq!(substs.regions().count(), generics.parent_regions as usize); @@ -1325,7 +1307,7 @@ fn xform_method_self_ty(&self, } else { // In general, during probe we erase regions. See // `impl_self_ty()` for an explanation. - self.tcx.mk_region(ty::ReErased) + self.tcx.types.re_erased } }, |def, cur_substs| { let i = def.index as usize; @@ -1341,11 +1323,11 @@ fn xform_method_self_ty(&self, /// Get the type of an impl and generate substitutions with placeholders. fn impl_ty_and_substs(&self, impl_def_id: DefId) -> (Ty<'tcx>, &'tcx Substs<'tcx>) { - let impl_ty = self.tcx.item_type(impl_def_id); + let impl_ty = self.tcx.type_of(impl_def_id); let substs = Substs::for_item(self.tcx, impl_def_id, - |_, _| self.tcx.mk_region(ty::ReErased), + |_, _| self.tcx.types.re_erased, |_, _| self.next_ty_var( TypeVariableOrigin::SubstitutionPlaceholder( self.tcx.def_span(impl_def_id)))); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 902cfb889f8..fe003f3f242 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -621,14 +621,14 @@ pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult } pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { - ty::queries::typeck_item_bodies::get(tcx, DUMMY_SP, LOCAL_CRATE) + tcx.typeck_item_bodies(LOCAL_CRATE) } fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> CompileResult { debug_assert!(crate_num == LOCAL_CRATE); tcx.sess.track_errors(|| { tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { - tcx.item_tables(body_owner_def_id); + tcx.typeck_tables_of(body_owner_def_id); }); }) } @@ -636,7 +636,7 @@ fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum pub fn provide(providers: &mut Providers) { *providers = Providers { typeck_item_bodies, - typeck_tables, + typeck_tables_of, closure_type, closure_kind, adt_destructor, @@ -648,14 +648,14 @@ fn closure_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::PolyFnSig<'tcx> { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); - tcx.item_tables(def_id).closure_tys[&node_id] + tcx.typeck_tables_of(def_id).closure_tys[&node_id] } fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureKind { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); - tcx.item_tables(def_id).closure_kinds[&node_id] + tcx.typeck_tables_of(def_id).closure_kinds[&node_id] } fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -664,14 +664,14 @@ fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl) } -fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::TypeckTables<'tcx> { // Closures' tables come from their outermost function, // as they are part of the same "inference environment". let outer_def_id = tcx.closure_base_def_id(def_id); if outer_def_id != def_id { - return tcx.item_tables(outer_def_id); + return tcx.typeck_tables_of(outer_def_id); } let id = tcx.hir.as_local_node_id(def_id).unwrap(); @@ -736,7 +736,7 @@ fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Inherited::build(tcx, id).enter(|inh| { let fcx = if let Some(decl) = fn_decl { - let fn_sig = tcx.item_type(def_id).fn_sig(); + let fn_sig = tcx.type_of(def_id).fn_sig(); check_abi(tcx, span, fn_sig.abi()); @@ -752,7 +752,7 @@ fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_fn(&inh, fn_sig, decl, id, body) } else { let fcx = FnCtxt::new(&inh, body.value.id); - let expected_type = tcx.item_type(def_id); + let expected_type = tcx.type_of(def_id); let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); @@ -946,20 +946,26 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: ast::NodeId, span: Span) { let def_id = tcx.hir.local_def_id(id); - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); if def.repr.simd() { check_simd(tcx, span, def_id); } + + // if struct is packed and not aligned, check fields for alignment. + // Checks for combining packed and align attrs on single struct are done elsewhere. + if tcx.adt_def(def_id).repr.packed() && tcx.adt_def(def_id).repr.align == 0 { + check_packed(tcx, span, def_id); + } } fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: ast::NodeId, span: Span) { let def_id = tcx.hir.local_def_id(id); - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated check_representable(tcx, span, def_id); } @@ -973,7 +979,7 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item // Consts can play a role in type-checking, so they are included here. hir::ItemStatic(..) | hir::ItemConst(..) => { - tcx.item_tables(tcx.hir.local_def_id(it.id)); + tcx.typeck_tables_of(tcx.hir.local_def_id(it.id)); } hir::ItemEnum(ref enum_definition, _) => { check_enum(tcx, @@ -1007,7 +1013,7 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item } hir::ItemTy(_, ref generics) => { let def_id = tcx.hir.local_def_id(it.id); - let pty_ty = tcx.item_type(def_id); + let pty_ty = tcx.type_of(def_id); check_bounds_are_used(tcx, generics, pty_ty); } hir::ItemForeignMod(ref m) => { @@ -1023,7 +1029,7 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item } } else { for item in &m.items { - let generics = tcx.item_generics(tcx.hir.local_def_id(item.id)); + let generics = tcx.generics_of(tcx.hir.local_def_id(item.id)); if !generics.types.is_empty() { let mut err = struct_span_err!(tcx.sess, item.span, E0044, "foreign items may not have type parameters"); @@ -1046,7 +1052,7 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item fn check_on_unimplemented<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, item: &hir::Item) { - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); if let Some(ref attr) = item.attrs.iter().find(|a| { a.check_name("rustc_on_unimplemented") }) { @@ -1135,7 +1141,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .map(|node_item| node_item.map(|parent| parent.defaultness)); if let Some(parent) = parent { - if parent.item.is_final() { + if tcx.impl_item_is_final(&parent) { report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); } } @@ -1153,7 +1159,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if impl_trait_ref.references_error() { return; } // Locate trait definition and items - let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id); + let trait_def = tcx.trait_def(impl_trait_ref.def_id); let mut overridden_associated_type = None; let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir.impl_item(iiref.id)); @@ -1274,11 +1280,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let signature = |item: &ty::AssociatedItem| { match item.kind { ty::AssociatedKind::Method => { - format!("{}", tcx.item_type(item.def_id).fn_sig().0) + format!("{}", tcx.type_of(item.def_id).fn_sig().0) } ty::AssociatedKind::Type => format!("type {};", item.name.to_string()), ty::AssociatedKind::Const => { - format!("const {}: {:?};", item.name.to_string(), tcx.item_type(item.def_id)) + format!("const {}: {:?};", item.name.to_string(), tcx.type_of(item.def_id)) } } }; @@ -1324,7 +1330,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, item_def_id: DefId) -> bool { - let rty = tcx.item_type(item_def_id); + let rty = tcx.type_of(item_def_id); // Check that it is possible to represent this type. This call identifies // (1) types that contain themselves and (2) types that contain a different @@ -1342,7 +1348,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { - let t = tcx.item_type(def_id); + let t = tcx.type_of(def_id); match t.sty { ty::TyAdt(def, substs) if def.is_struct() => { let fields = &def.struct_variant().fields; @@ -1371,13 +1377,54 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId } } +fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { + if check_packed_inner(tcx, def_id, &mut Vec::new()) { + struct_span_err!(tcx.sess, sp, E0588, + "packed struct cannot transitively contain a `[repr(align)]` struct").emit(); + } +} + +fn check_packed_inner<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + stack: &mut Vec) -> bool { + let t = tcx.type_of(def_id); + if stack.contains(&def_id) { + debug!("check_packed_inner: {:?} is recursive", t); + return false; + } + match t.sty { + ty::TyAdt(def, substs) if def.is_struct() => { + if tcx.adt_def(def.did).repr.align > 0 { + return true; + } + // push struct def_id before checking fields + stack.push(def_id); + for field in &def.struct_variant().fields { + let f = field.ty(tcx, substs); + match f.sty { + ty::TyAdt(def, _) => { + if check_packed_inner(tcx, def.did, stack) { + return true; + } + } + _ => () + } + } + // only need to pop if not early out + stack.pop(); + } + _ => () + } + false +} + #[allow(trivial_numeric_casts)] pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, vs: &'tcx [hir::Variant], id: ast::NodeId) { let def_id = tcx.hir.local_def_id(id); - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated if vs.is_empty() && tcx.has_attr(def_id, "repr") { @@ -1398,7 +1445,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for v in vs { if let Some(e) = v.node.disr_expr { - tcx.item_tables(tcx.hir.local_def_id(e.node_id)); + tcx.typeck_tables_of(tcx.hir.local_def_id(e.node_id)); } } @@ -1446,7 +1493,7 @@ fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let item_id = tcx.hir.ty_param_owner(node_id); let item_def_id = tcx.hir.local_def_id(item_id); - let generics = tcx.item_generics(item_def_id); + let generics = tcx.generics_of(item_def_id); let index = generics.type_param_to_index[&def_id.index]; ty::GenericPredicates { parent: None, @@ -1745,7 +1792,7 @@ fn instantiate_type_scheme(&self, /// generic type scheme. fn instantiate_bounds(&self, span: Span, def_id: DefId, substs: &Substs<'tcx>) -> ty::InstantiatedPredicates<'tcx> { - let bounds = self.tcx.item_predicates(def_id); + let bounds = self.tcx.predicates_of(def_id); let result = bounds.instantiate(self.tcx, substs); let result = self.normalize_associated_types_in(span, &result); debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", @@ -1770,8 +1817,8 @@ fn instantiate_anon_types>(&self, value: &T) -> T { let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span)); self.anon_types.borrow_mut().insert(id, ty_var); - let item_predicates = self.tcx.item_predicates(def_id); - let bounds = item_predicates.instantiate(self.tcx, substs); + let predicates_of = self.tcx.predicates_of(def_id); + let bounds = predicates_of.instantiate(self.tcx, substs); for predicate in bounds.predicates { // Change the predicate to refer to the type variable, @@ -1907,7 +1954,7 @@ pub fn register_old_wf_obligation(&self, // // FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_region_obligation(ty, self.tcx.mk_region(ty::ReEmpty), cause); + self.register_region_obligation(ty, self.tcx.types.re_empty, cause); } /// Registers obligations that all types appearing in `substs` are well-formed. @@ -2466,7 +2513,7 @@ fn check_lit(&self, match lit.node { ast::LitKind::Str(..) => tcx.mk_static_str(), ast::LitKind::ByteStr(ref v) => { - tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), + tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_array(tcx.types.u8, v.len())) } ast::LitKind::Byte(_) => tcx.types.u8, @@ -2567,7 +2614,7 @@ pub fn impl_self_ty(&self, span: Span, // (potential) receiver for this impl did: DefId) -> TypeAndSubsts<'tcx> { - let ity = self.tcx.item_type(did); + let ity = self.tcx.type_of(did); debug!("impl_self_ty: ity={:?}", ity); let substs = self.fresh_substs_for_item(span, did); @@ -4161,11 +4208,11 @@ pub fn instantiate_value_path(&self, Def::VariantCtor(def_id, ..) => { // Everything but the final segment should have no // parameters at all. - let mut generics = self.tcx.item_generics(def_id); + let mut generics = self.tcx.generics_of(def_id); if let Some(def_id) = generics.parent { // Variant and struct constructors use the // generics of their parent type definition. - generics = self.tcx.item_generics(def_id); + generics = self.tcx.generics_of(def_id); } type_segment = Some((segments.last().unwrap(), generics)); } @@ -4175,7 +4222,7 @@ pub fn instantiate_value_path(&self, Def::Const(def_id) | Def::Static(def_id, _) => { fn_segment = Some((segments.last().unwrap(), - self.tcx.item_generics(def_id))); + self.tcx.generics_of(def_id))); } // Case 3. Reference to a method or associated const. @@ -4189,9 +4236,9 @@ pub fn instantiate_value_path(&self, ty::ImplContainer(_) => {} } - let generics = self.tcx.item_generics(def_id); + let generics = self.tcx.generics_of(def_id); if segments.len() >= 2 { - let parent_generics = self.tcx.item_generics(generics.parent.unwrap()); + let parent_generics = self.tcx.generics_of(generics.parent.unwrap()); type_segment = Some((&segments[segments.len() - 2], parent_generics)); } else { // `::assoc` will end up here, and so can `T::assoc`. @@ -4304,7 +4351,7 @@ pub fn instantiate_value_path(&self, self.to_ty(ast_ty) } else if !infer_types && def.has_default { // No type parameter provided, but a default exists. - let default = self.tcx.item_type(def.def_id); + let default = self.tcx.type_of(def.def_id); self.normalize_ty( span, default.subst_spanned(self.tcx, substs, Some(span)) @@ -4320,7 +4367,7 @@ pub fn instantiate_value_path(&self, // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. - let ty = self.tcx.item_type(def.def_id()); + let ty = self.tcx.type_of(def.def_id()); assert!(!substs.has_escaping_regions()); assert!(!ty.has_escaping_regions()); @@ -4340,7 +4387,7 @@ pub fn instantiate_value_path(&self, // is inherent, there is no `Self` parameter, instead, the impl needs // type parameters, which we can infer by unifying the provided `Self` // with the substituted impl type. - let ty = self.tcx.item_type(impl_def_id); + let ty = self.tcx.type_of(impl_def_id); let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); match self.sub_types(false, &self.misc(span), self_ty, impl_ty) { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 8bfb390bd2a..3508ddbe5f4 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -457,7 +457,8 @@ fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) { self.type_of_node_must_outlive(origin, id, var_region); let typ = self.resolve_node_type(id); - dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope); + let _ = dropck::check_safety_of_destructor_if_necessary( + self, typ, span, var_scope); }) } } @@ -995,10 +996,8 @@ fn check_safety_of_rvalue_destructor_if_necessary(&mut self, match *region { ty::ReScope(rvalue_scope) => { let typ = self.resolve_type(cmt.ty); - dropck::check_safety_of_destructor_if_necessary(self, - typ, - span, - rvalue_scope); + let _ = dropck::check_safety_of_destructor_if_necessary( + self, typ, span, rvalue_scope); } ty::ReStatic => {} _ => { @@ -1726,7 +1725,7 @@ fn declared_projection_bounds_from_trait(&self, // ``` // // we can thus deduce that `>::SomeType : 'a`. - let trait_predicates = self.tcx.item_predicates(projection_ty.trait_ref.def_id); + let trait_predicates = self.tcx.predicates_of(projection_ty.trait_ref.def_id); assert_eq!(trait_predicates.parent, None); let predicates = trait_predicates.predicates.as_slice().to_vec(); traits::elaborate_predicates(self.tcx, predicates) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 85c87adf9be..503212f2c97 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -105,11 +105,11 @@ fn check_item_well_formed(&mut self, item: &hir::Item) { /// /// won't be allowed unless there's an *explicit* implementation of `Send` /// for `T` - hir::ItemImpl(_, hir::ImplPolarity::Positive, _, + hir::ItemImpl(_, hir::ImplPolarity::Positive, _, _, ref trait_ref, ref self_ty, _) => { self.check_impl(item, self_ty, trait_ref); } - hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => { + hir::ItemImpl(_, hir::ImplPolarity::Negative, _, _, Some(_), ..) => { // FIXME(#27579) what amount of WF checking do we need for neg impls? let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap(); @@ -168,18 +168,18 @@ fn check_associated_item(&mut self, let (mut implied_bounds, self_ty) = match item.container { ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()), ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span), - fcx.tcx.item_type(def_id)) + fcx.tcx.type_of(def_id)) }; match item.kind { ty::AssociatedKind::Const => { - let ty = fcx.tcx.item_type(item.def_id); + let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } ty::AssociatedKind::Method => { reject_shadowing_type_parameters(fcx.tcx, item.def_id); - let method_ty = fcx.tcx.item_type(item.def_id); + let method_ty = fcx.tcx.type_of(item.def_id); let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs); let sig = method_ty.fn_sig(); @@ -191,7 +191,7 @@ fn check_associated_item(&mut self, } ty::AssociatedKind::Type => { if item.defaultness.has_value() { - let ty = fcx.tcx.item_type(item.def_id); + let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } @@ -262,7 +262,7 @@ fn check_auto_trait(&mut self, trait_def_id: DefId, span: Span) { // // 3) that the trait definition does not have any type parameters - let predicates = self.tcx.item_predicates(trait_def_id); + let predicates = self.tcx.predicates_of(trait_def_id); // We must exclude the Self : Trait predicate contained by all // traits. @@ -277,7 +277,7 @@ fn check_auto_trait(&mut self, trait_def_id: DefId, span: Span) { } }); - let has_ty_params = self.tcx.item_generics(trait_def_id).types.len() > 1; + let has_ty_params = self.tcx.generics_of(trait_def_id).types.len() > 1; // We use an if-else here, since the generics will also trigger // an extraneous error message when we find predicates like @@ -334,7 +334,7 @@ fn check_item_fn(&mut self, self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; let def_id = fcx.tcx.hir.local_def_id(item.id); - let ty = fcx.tcx.item_type(def_id); + let ty = fcx.tcx.type_of(def_id); let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &ty); let sig = item_ty.fn_sig(); @@ -354,7 +354,7 @@ fn check_item_type(&mut self, debug!("check_item_type: {:?}", item); self.for_item(item).with_fcx(|fcx, this| { - let ty = fcx.tcx.item_type(fcx.tcx.hir.local_def_id(item.id)); + let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id)); let item_ty = fcx.instantiate_type_scheme(item.span, &fcx.parameter_environment .free_substs, @@ -393,7 +393,7 @@ fn check_impl(&mut self, } } None => { - let self_ty = fcx.tcx.item_type(item_def_id); + let self_ty = fcx.tcx.type_of(item_def_id); let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty); fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone()); } @@ -468,7 +468,7 @@ fn check_method_receiver<'fcx, 'tcx>(&mut self, let span = method_sig.decl.inputs[0].span; let free_substs = &fcx.parameter_environment.free_substs; - let method_ty = fcx.tcx.item_type(method.def_id); + let method_ty = fcx.tcx.type_of(method.def_id); let fty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.fn_sig()); @@ -502,14 +502,14 @@ fn check_variances_for_type_defn(&self, ast_generics: &hir::Generics) { let item_def_id = self.tcx.hir.local_def_id(item.id); - let ty = self.tcx.item_type(item_def_id); + let ty = self.tcx.type_of(item_def_id); if self.tcx.has_error_field(ty) { return; } - let ty_predicates = self.tcx.item_predicates(item_def_id); + let ty_predicates = self.tcx.predicates_of(item_def_id); assert_eq!(ty_predicates.parent, None); - let variances = self.tcx.item_variances(item_def_id); + let variances = self.tcx.variances_of(item_def_id); let mut constrained_parameters: FxHashSet<_> = variances.iter().enumerate() @@ -561,8 +561,8 @@ fn report_bivariance(&self, } fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) { - let generics = tcx.item_generics(def_id); - let parent = tcx.item_generics(generics.parent.unwrap()); + let generics = tcx.generics_of(def_id); + let parent = tcx.generics_of(generics.parent.unwrap()); let impl_params: FxHashMap<_, _> = parent.types .iter() .map(|tp| (tp.name, tp.def_id)) @@ -631,7 +631,7 @@ fn struct_variant(&self, struct_def: &hir::VariantData) -> AdtVariant<'tcx> { let fields = struct_def.fields().iter() .map(|field| { - let field_ty = self.tcx.item_type(self.tcx.hir.local_def_id(field.id)); + let field_ty = self.tcx.type_of(self.tcx.hir.local_def_id(field.id)); let field_ty = self.instantiate_type_scheme(field.span, &self.parameter_environment .free_substs, @@ -660,7 +660,7 @@ fn impl_implied_bounds(&self, impl_def_id: DefId, span: Span) -> Vec> { None => { // Inherent impl: take implied bounds from the self type. - let self_ty = self.tcx.item_type(impl_def_id); + let self_ty = self.tcx.type_of(impl_def_id); let self_ty = self.instantiate_type_scheme(span, free_substs, &self_ty); vec![self_ty] } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index f196aa82b1e..35b2e8f8afc 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -288,8 +288,8 @@ fn visit_anon_types(&mut self) { let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| { match *r { // 'static is valid everywhere. - ty::ReStatic | - ty::ReEmpty => gcx.mk_region(*r), + ty::ReStatic => gcx.types.re_static, + ty::ReEmpty => gcx.types.re_empty, // Free regions that come from early-bound regions are valid. ty::ReFree(ty::FreeRegion { @@ -307,7 +307,7 @@ fn visit_anon_types(&mut self) { span_err!(self.tcx().sess, span, E0564, "only named lifetimes are allowed in `impl Trait`, \ but `{}` was found in the type `{}`", r, inside_ty); - gcx.mk_region(ty::ReStatic) + gcx.types.re_static } ty::ReVar(_) | @@ -526,7 +526,7 @@ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { match self.infcx.fully_resolve(&r) { Ok(r) => r, Err(_) => { - self.tcx.mk_region(ty::ReStatic) + self.tcx.types.re_static } } } diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index c9479c5cebc..a985ac61cb3 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -67,7 +67,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let item_def_id = tcx.hir.local_def_id(item_id); // this will have been written by the main typeck pass - if let Some(tables) = tcx.maps.typeck_tables.borrow().get(&item_def_id) { + if let Some(tables) = tcx.maps.typeck_tables_of.borrow().get(&item_def_id) { let imports = &tables.used_trait_imports; debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports); used_trait_imports.extend(imports); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 47b41a75cf5..57193b3584d 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -57,7 +57,7 @@ fn check(&self, trait_def_id: Option, mut f: F) -> &Self fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _drop_did: DefId, impl_did: DefId) { - match tcx.item_type(impl_did).sty { + match tcx.type_of(impl_did).sty { ty::TyAdt(..) => {} _ => { // Destructors only work on nominal types. @@ -101,7 +101,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return; }; - let self_type = tcx.item_type(impl_did); + let self_type = tcx.type_of(impl_did); debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type); @@ -170,7 +170,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // course. if impl_did.is_local() { let span = tcx.def_span(impl_did); - ty::queries::coerce_unsized_info::get(tcx, span, impl_did); + tcx.at(span).coerce_unsized_info(impl_did); } } @@ -192,7 +192,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did) }); - let source = tcx.item_type(impl_did); + let source = tcx.type_of(impl_did); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); assert_eq!(trait_ref.def_id, coerce_unsized_trait); let target = trait_ref.substs.type_at(1); @@ -259,7 +259,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .filter_map(|(i, f)| { let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); - if tcx.item_type(f.did).is_phantom_data() { + if tcx.type_of(f.did).is_phantom_data() { // Ignore PhantomData fields return None; } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index dc4bd7733fc..400aaf82fe4 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -14,7 +14,7 @@ //! for any change, but it is very cheap to compute. In practice, most //! code in the compiler never *directly* requests this map. Instead, //! it requests the inherent impls specific to some type (via -//! `ty::queries::inherent_impls::get(def_id)`). That value, however, +//! `tcx.inherent_impls(def_id)`). That value, however, //! is computed by selecting an idea from this table. use rustc::dep_graph::DepNode; @@ -26,7 +26,7 @@ use std::rc::Rc; use syntax::ast; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::Span; /// On-demand query: yields a map containing all types mapped to their inherent impls. pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -67,7 +67,7 @@ pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4 let result = tcx.dep_graph.with_ignore(|| { - let crate_map = ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, ty_def_id.krate); + let crate_map = tcx.crate_inherent_impls(ty_def_id.krate); match crate_map.inherent_impls.get(&ty_def_id) { Some(v) => v.clone(), None => Rc::new(vec![]), @@ -106,7 +106,7 @@ fn visit_item(&mut self, item: &hir::Item) { } let def_id = self.tcx.hir.local_def_id(item.id); - let self_ty = self.tcx.item_type(def_id); + let self_ty = self.tcx.type_of(def_id); match self_ty.sty { ty::TyAdt(def, _) => { self.check_def_id(item, def.did); diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 33280fb931a..34aec8ef1ac 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -14,8 +14,6 @@ use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt}; -use syntax_pos::DUMMY_SP; - pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) { assert_eq!(crate_num, LOCAL_CRATE); @@ -68,7 +66,7 @@ enum Namespace { } fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) { - let impls = ty::queries::inherent_impls::get(self.tcx, DUMMY_SP, ty_def_id); + let impls = self.tcx.inherent_impls(ty_def_id); for (i, &impl1_def_id) in impls.iter().enumerate() { for &impl2_def_id in &impls[(i + 1)..] { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index b385ddc49c1..56ae9d54575 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -16,11 +16,10 @@ // mappings. That mapping code resides here. use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc::ty::{self, TyCtxt, TypeFoldable}; +use rustc::ty::{TyCtxt, TypeFoldable}; use rustc::ty::maps::Providers; use syntax::ast; -use syntax_pos::DUMMY_SP; mod builtin; mod inherent_impls; @@ -47,7 +46,7 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { } enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id); - let trait_def = tcx.lookup_trait_def(trait_ref.def_id); + let trait_def = tcx.trait_def(trait_ref.def_id); trait_def.record_local_impl(tcx, impl_def_id, trait_ref); } } @@ -132,7 +131,7 @@ fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { for &trait_def_id in tcx.hir.krate().trait_impls.keys() { - ty::queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, trait_def_id)); + tcx.coherent_trait((LOCAL_CRATE, trait_def_id)); } unsafety::check(tcx); @@ -140,6 +139,6 @@ pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { overlap::check_default_impls(tcx); // these queries are executed for side-effects (error reporting): - ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE); - ty::queries::crate_inherent_impls_overlap_check::get(tcx, DUMMY_SP, LOCAL_CRATE); + tcx.crate_inherent_impls(LOCAL_CRATE); + tcx.crate_inherent_impls_overlap_check(LOCAL_CRATE); } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 74edc7bff49..383a9e0e695 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -41,7 +41,7 @@ pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { let _task = tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id)); - let def = tcx.lookup_trait_def(trait_def_id); + let def = tcx.trait_def(trait_def_id); // attempt to insert into the specialization graph let insert_result = def.add_impl_for_specialization(tcx, impl_def_id); diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 22247d2531a..4672975d056 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -34,7 +34,7 @@ fn check_unsafety_coherence(&mut self, None => {} Some(trait_ref) => { - let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id); + let trait_def = self.tcx.trait_def(trait_ref.def_id); let unsafe_attr = impl_generics.and_then(|g| g.carries_unsafe_attr()); match (trait_def.unsafety, unsafe_attr, unsafety, polarity) { (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => { @@ -87,7 +87,7 @@ fn visit_item(&mut self, item: &'v hir::Item) { hir::ItemDefaultImpl(unsafety, _) => { self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive); } - hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => { + hir::ItemImpl(unsafety, polarity, _, ref generics, ..) => { self.check_unsafety_coherence(item, Some(generics), unsafety, polarity); } _ => {} diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index af0ef279e4f..3cd8b8bd489 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -31,7 +31,7 @@ arbitrary interdependencies. So instead we generally convert things lazilly and on demand, and include logic that checks for cycles. Demand is driven by calls to `AstConv::get_item_type_scheme` or -`AstConv::lookup_trait_def`. +`AstConv::trait_def`. Currently, we "convert" types and traits in two phases (note that conversion only affects the types of items / enum variants / methods; @@ -91,14 +91,16 @@ pub fn collect_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { pub fn provide(providers: &mut Providers) { *providers = Providers { - ty, - generics, - predicates, - super_predicates, + type_of, + generics_of, + predicates_of, + super_predicates_of, type_param_predicates, trait_def, adt_def, impl_trait_ref, + impl_polarity, + is_foreign_item, ..*providers }; } @@ -139,7 +141,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics) { for param in &generics.ty_params { if param.default.is_some() { let def_id = self.tcx.hir.local_def_id(param.id); - self.tcx.item_type(def_id); + self.tcx.type_of(def_id); } } intravisit::walk_generics(self, generics); @@ -148,8 +150,8 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics) { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { if let hir::ExprClosure(..) = expr.node { let def_id = self.tcx.hir.local_def_id(expr.id); - self.tcx.item_generics(def_id); - self.tcx.item_type(def_id); + self.tcx.generics_of(def_id); + self.tcx.type_of(def_id); } intravisit::walk_expr(self, expr); } @@ -157,8 +159,8 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) { fn visit_ty(&mut self, ty: &'tcx hir::Ty) { if let hir::TyImplTrait(..) = ty.node { let def_id = self.tcx.hir.local_def_id(ty.id); - self.tcx.item_generics(def_id); - self.tcx.item_predicates(def_id); + self.tcx.generics_of(def_id); + self.tcx.predicates_of(def_id); } intravisit::walk_ty(self, ty); } @@ -205,7 +207,7 @@ fn get_type_parameter_bounds(&self, def_id: DefId) -> ty::GenericPredicates<'tcx> { - ty::queries::type_param_predicates::get(self.tcx, span, (self.item_def_id, def_id)) + self.tcx.at(span).type_param_predicates((self.item_def_id, def_id)) } fn get_free_substs(&self) -> Option<&Substs<'tcx>> { @@ -269,7 +271,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_id = tcx.hir.as_local_node_id(def_id).unwrap(); let param_owner = tcx.hir.ty_param_owner(param_id); let param_owner_def_id = tcx.hir.local_def_id(param_owner); - let generics = tcx.item_generics(param_owner_def_id); + let generics = tcx.generics_of(param_owner_def_id); let index = generics.type_param_to_index[&def_id.index]; let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id)); @@ -277,7 +279,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let parent = if item_def_id == param_owner_def_id { None } else { - tcx.item_generics(item_def_id).parent + tcx.generics_of(item_def_id).parent }; let mut result = parent.map_or(ty::GenericPredicates { @@ -307,7 +309,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) | + ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -450,43 +452,43 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { hir::ItemForeignMod(ref foreign_mod) => { for item in &foreign_mod.items { let def_id = tcx.hir.local_def_id(item.id); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } } hir::ItemEnum(ref enum_definition, _) => { - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); convert_enum_variant_types(tcx, def_id, &enum_definition.variants); }, hir::ItemDefaultImpl(..) => { tcx.impl_trait_ref(def_id); } hir::ItemImpl(..) => { - tcx.item_generics(def_id); - tcx.item_type(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); tcx.impl_trait_ref(def_id); - tcx.item_predicates(def_id); + tcx.predicates_of(def_id); }, hir::ItemTrait(..) => { - tcx.item_generics(def_id); - tcx.lookup_trait_def(def_id); - ty::queries::super_predicates::get(tcx, it.span, def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.trait_def(def_id); + tcx.at(it.span).super_predicates_of(def_id); + tcx.predicates_of(def_id); }, hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); for f in struct_def.fields() { let def_id = tcx.hir.local_def_id(f.id); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } if !struct_def.is_struct() { @@ -495,14 +497,14 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { }, hir::ItemTy(_, ref generics) => { ensure_no_ty_param_bounds(tcx, it.span, generics, "type"); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => { - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } } } @@ -510,40 +512,40 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: ast::NodeId) { let trait_item = tcx.hir.expect_trait_item(trait_item_id); let def_id = tcx.hir.local_def_id(trait_item.id); - tcx.item_generics(def_id); + tcx.generics_of(def_id); match trait_item.node { hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(_, Some(_)) | hir::TraitItemKind::Method(..) => { - tcx.item_type(def_id); + tcx.type_of(def_id); } hir::TraitItemKind::Type(_, None) => {} }; - tcx.item_predicates(def_id); + tcx.predicates_of(def_id); } fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_id: ast::NodeId) { let def_id = tcx.hir.local_def_id(impl_item_id); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ctor_id: ast::NodeId) { let def_id = tcx.hir.local_def_id(ctor_id); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, variants: &[hir::Variant]) { - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); let repr_type = def.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx); let mut prev_discr = None::; @@ -553,7 +555,8 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr()); prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); - let result = ty::queries::monomorphic_const_eval::get(tcx, variant.span, expr_did); + let substs = Substs::empty(); + let result = tcx.at(variant.span).const_eval((expr_did, substs)); // enum variant evaluation happens before the global constant check // so we need to report the real error @@ -580,9 +583,9 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for f in variant.node.data.fields() { let def_id = tcx.hir.local_def_id(f.id); - tcx.item_generics(def_id); - tcx.item_type(def_id); - tcx.item_predicates(def_id); + tcx.generics_of(def_id); + tcx.type_of(def_id); + tcx.predicates_of(def_id); } // Convert the ctor, if any. This also registers the variant as @@ -683,9 +686,9 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// Ensures that the super-predicates of the trait with def-id /// trait_def_id are converted and stored. This also ensures that /// the transitive super-predicates are converted; -fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_def_id: DefId) - -> ty::GenericPredicates<'tcx> { +fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + trait_def_id: DefId) + -> ty::GenericPredicates<'tcx> { debug!("super_predicates(trait_def_id={:?})", trait_def_id); let trait_node_id = tcx.hir.as_local_node_id(trait_def_id).unwrap(); @@ -722,7 +725,7 @@ fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Now require that immediate supertraits are converted, // which will, in turn, reach indirect supertraits. for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) { - ty::queries::super_predicates::get(tcx, item.span, bound.def_id()); + tcx.at(item.span).super_predicates_of(bound.def_id()); } ty::GenericPredicates { @@ -764,9 +767,9 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.alloc_trait_def(def) } -fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> &'tcx ty::Generics { +fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> &'tcx ty::Generics { use rustc::hir::map::*; use rustc::hir::*; @@ -822,7 +825,7 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) => generics, + ItemImpl(_, _, _, ref generics, ..) => generics, ItemTy(_, ref generics) | ItemEnum(_, ref generics) | @@ -870,7 +873,7 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut parent_has_self = false; let mut own_start = has_self as u32; let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| { - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); assert_eq!(has_self, false); parent_has_self = generics.has_self; own_start = generics.count() as u32; @@ -955,9 +958,9 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> Ty<'tcx> { +fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Ty<'tcx> { use rustc::hir::map::*; use rustc::hir::*; @@ -1014,7 +1017,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemEnum(..) | ItemStruct(..) | ItemUnion(..) => { - let def = tcx.lookup_adt_def(def_id); + let def = tcx.adt_def(def_id); let substs = Substs::identity_for_item(tcx, def_id); tcx.mk_adt(def, substs) } @@ -1046,12 +1049,12 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeStructCtor(&ref def) | NodeVariant(&Spanned { node: hir::Variant_ { data: ref def, .. }, .. }) => { - let ty = tcx.item_type(tcx.hir.get_parent_did(node_id)); + let ty = tcx.type_of(tcx.hir.get_parent_did(node_id)); match *def { VariantData::Unit(..) | VariantData::Struct(..) => ty, VariantData::Tuple(ref fields, _) => { let inputs = fields.iter().map(|f| { - tcx.item_type(tcx.hir.local_def_id(f.id)) + tcx.type_of(tcx.hir.local_def_id(f.id)) }); let substs = Substs::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig( @@ -1086,7 +1089,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeVariant(&Spanned { node: Variant_ { disr_expr: Some(e), .. }, .. }) if e.node_id == node_id => { - tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id)) + tcx.adt_def(tcx.hir.get_parent_did(node_id)) .repr.discr_type().to_ty(tcx) } @@ -1101,7 +1104,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => { let owner = tcx.hir.get_parent_did(node_id); - tcx.item_tables(owner).node_id_to_type(node_id) + tcx.typeck_tables_of(owner).node_id_to_type(node_id) } x => { @@ -1124,7 +1127,7 @@ fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } hir::ItemImpl(.., ref opt_trait_ref, _, _) => { opt_trait_ref.as_ref().map(|ast_trait_ref| { - let selfty = tcx.item_type(def_id); + let selfty = tcx.type_of(def_id); AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty) }) } @@ -1132,6 +1135,16 @@ fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> hir::ImplPolarity { + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + match tcx.hir.expect_item(node_id).node { + hir::ItemImpl(_, polarity, ..) => polarity, + ref item => bug!("impl_polarity: {:?} not an impl", item) + } +} + // Is it marked with ?Sized fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, ast_bounds: &[hir::TyParamBound], @@ -1192,9 +1205,9 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>( .filter(move |l| !tcx.named_region_map.late_bound.contains(&l.lifetime.id)) } -fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> ty::GenericPredicates<'tcx> { +fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> ty::GenericPredicates<'tcx> { use rustc::hir::map::*; use rustc::hir::*; @@ -1223,7 +1236,7 @@ fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) | + ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -1267,7 +1280,7 @@ fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => &no_generics }; - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); let parent_count = generics.parent_count() as u32; let has_own_self = generics.has_self && parent_count == 0; @@ -1278,7 +1291,7 @@ fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // on a trait we need to add in the supertrait bounds and bounds found on // associated types. if let Some((trait_ref, _)) = is_trait { - predicates = tcx.item_super_predicates(def_id).predicates; + predicates = tcx.super_predicates_of(def_id).predicates; // Add in a predicate that `Self:Trait` (where `Trait` is the // current trait). This is needed for builtin bounds. @@ -1397,7 +1410,7 @@ fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // in trait checking. See `setup_constraining_predicates` // for details. if let NodeItem(&Item { node: ItemImpl(..), .. }) = node { - let self_ty = tcx.item_type(def_id); + let self_ty = tcx.type_of(def_id); let trait_ref = tcx.impl_trait_ref(def_id); ctp::setup_constraining_predicates(&mut predicates, trait_ref, @@ -1530,3 +1543,13 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( let substs = Substs::identity_for_item(tcx, def_id); tcx.mk_fn_def(def_id, substs, fty) } + +fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> bool { + match tcx.hir.get_if_local(def_id) { + Some(hir_map::NodeForeignItem(..)) => true, + Some(_) => false, + _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id) + } +} diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 68afcae2b67..2bae6a0d9e1 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4154,7 +4154,6 @@ fn main() { } // E0248, // value used as a type, now reported earlier during resolution as E0412 // E0249, // E0319, // trait impls for defaulted traits allowed just for structs/enums - E0320, // recursive overflow during dropck // E0372, // coherence not object safe E0377, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with the same definition @@ -4168,5 +4167,6 @@ fn main() { } // but `{}` was found in the type `{}` E0567, // auto traits can not have type parameters E0568, // auto-traits can not have predicates, + E0588, // packed struct cannot transitively contain a `[repr(align)]` struct E0592, // duplicate definitions with name `{}` } diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index 5751dc5ab8a..1c44572fbb4 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -95,9 +95,9 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_refs: &[hir::ImplItemRef]) { // Every lifetime used in an associated type must be constrained. - let impl_self_ty = tcx.item_type(impl_def_id); - let impl_generics = tcx.item_generics(impl_def_id); - let impl_predicates = tcx.item_predicates(impl_def_id); + let impl_self_ty = tcx.type_of(impl_def_id); + let impl_generics = tcx.generics_of(impl_def_id); + let impl_predicates = tcx.predicates_of(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref); @@ -120,7 +120,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item.kind == ty::AssociatedKind::Type && item.defaultness.has_value() }) .flat_map(|def_id| { - ctp::parameters_for(&tcx.item_type(def_id), true) + ctp::parameters_for(&tcx.type_of(def_id), true) }).collect(); for (ty_lifetime, lifetime) in impl_generics.regions.iter() .zip(&impl_hir_generics.lifetimes) diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0754b52cf28..94b4bfade94 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -179,7 +179,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: ast::NodeId, main_span: Span) { let main_def_id = tcx.hir.local_def_id(main_id); - let main_t = tcx.item_type(main_def_id); + let main_t = tcx.type_of(main_def_id); match main_t.sty { ty::TyFnDef(..) => { match tcx.hir.find(main_id) { @@ -229,7 +229,7 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, start_id: ast::NodeId, start_span: Span) { let start_def_id = tcx.hir.local_def_id(start_id); - let start_t = tcx.item_type(start_def_id); + let start_t = tcx.type_of(start_def_id); match start_t.sty { ty::TyFnDef(..) => { match tcx.hir.find(start_id) { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 1bde1eea37c..5bbc285c3d5 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -81,7 +81,7 @@ fn visit_item(&mut self, item: &hir::Item) { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { - let generics = tcx.item_generics(did); + let generics = tcx.generics_of(did); // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion @@ -89,14 +89,14 @@ fn visit_item(&mut self, item: &hir::Item) { // // self.add_constraints_from_generics(generics); - for field in tcx.lookup_adt_def(did).all_fields() { + for field in tcx.adt_def(did).all_fields() { self.add_constraints_from_ty(generics, - tcx.item_type(field.did), + tcx.type_of(field.did), self.covariant); } } hir::ItemTrait(..) => { - let generics = tcx.item_generics(did); + let generics = tcx.generics_of(did); let trait_ref = ty::TraitRef { def_id: did, substs: Substs::identity_for_item(tcx, did) @@ -233,7 +233,7 @@ fn declared_variance(&self, } else { // Parameter on an item defined within another crate: // variance already inferred, just look it up. - let variances = self.tcx().item_variances(item_def_id); + let variances = self.tcx().variances_of(item_def_id); self.constant_term(variances[index]) } } @@ -286,10 +286,10 @@ fn add_constraints_from_trait_ref(&mut self, trait_ref, variance); - let trait_generics = self.tcx().item_generics(trait_ref.def_id); + let trait_generics = self.tcx().generics_of(trait_ref.def_id); // This edge is actually implied by the call to - // `lookup_trait_def`, but I'm trying to be future-proof. See + // `trait_def`, but I'm trying to be future-proof. See // README.md for a discussion on dep-graph management. self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id)); @@ -345,10 +345,10 @@ fn add_constraints_from_ty(&mut self, } ty::TyAdt(def, substs) => { - let adt_generics = self.tcx().item_generics(def.did); + let adt_generics = self.tcx().generics_of(def.did); // This edge is actually implied by the call to - // `lookup_trait_def`, but I'm trying to be future-proof. See + // `trait_def`, but I'm trying to be future-proof. See // README.md for a discussion on dep-graph management. self.tcx().dep_graph.read(VarianceDepNode(def.did)); @@ -362,10 +362,10 @@ fn add_constraints_from_ty(&mut self, ty::TyProjection(ref data) => { let trait_ref = &data.trait_ref; - let trait_generics = self.tcx().item_generics(trait_ref.def_id); + let trait_generics = self.tcx().generics_of(trait_ref.def_id); // This edge is actually implied by the call to - // `lookup_trait_def`, but I'm trying to be future-proof. See + // `trait_def`, but I'm trying to be future-proof. See // README.md for a discussion on dep-graph management. self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id)); diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index 6628c7c521f..27116cbbb7a 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -137,8 +137,7 @@ fn write(&self) { item_variances); } - tcx.maps.variances - .borrow_mut() + tcx.maps.variances_of.borrow_mut() .insert(item_def_id, Rc::new(item_variances)); } } diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 890414e317c..61ff154e458 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -178,8 +178,7 @@ fn add_inferreds_for_item(&mut self, // parameters". if self.num_inferred() == inferreds_on_entry { let item_def_id = self.tcx.hir.local_def_id(item_id); - self.tcx.maps.variances - .borrow_mut() + self.tcx.maps.variances_of.borrow_mut() .insert(item_def_id, self.empty_variances.clone()); } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cc30fdf56fc..71bb53e9b81 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -15,7 +15,6 @@ use std::iter::once; use syntax::ast; -use syntax_pos::DUMMY_SP; use rustc::hir; use rustc::hir::def::{Def, CtorKind}; @@ -152,12 +151,12 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect(); - let predicates = cx.tcx.item_predicates(did); - let generics = (cx.tcx.item_generics(did), &predicates).clean(cx); + let predicates = cx.tcx.predicates_of(did); + let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); clean::Trait { - unsafety: cx.tcx.lookup_trait_def(did).unsafety, + unsafety: cx.tcx.trait_def(did).unsafety, generics: generics, items: trait_items, bounds: supertrait_bounds, @@ -165,7 +164,7 @@ pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { } fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { - let sig = cx.tcx.item_type(did).fn_sig(); + let sig = cx.tcx.type_of(did).fn_sig(); let constness = if cx.tcx.sess.cstore.is_const_fn(did) { hir::Constness::Const @@ -173,10 +172,10 @@ fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { hir::Constness::NotConst }; - let predicates = cx.tcx.item_predicates(did); + let predicates = cx.tcx.predicates_of(did); clean::Function { decl: (did, sig).clean(cx), - generics: (cx.tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.generics_of(did), &predicates).clean(cx), unsafety: sig.unsafety(), constness: constness, abi: sig.abi(), @@ -184,18 +183,18 @@ fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { } fn build_enum(cx: &DocContext, did: DefId) -> clean::Enum { - let predicates = cx.tcx.item_predicates(did); + let predicates = cx.tcx.predicates_of(did); clean::Enum { - generics: (cx.tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.generics_of(did), &predicates).clean(cx), variants_stripped: false, - variants: cx.tcx.lookup_adt_def(did).variants.clean(cx), + variants: cx.tcx.adt_def(did).variants.clean(cx), } } fn build_struct(cx: &DocContext, did: DefId) -> clean::Struct { - let predicates = cx.tcx.item_predicates(did); - let variant = cx.tcx.lookup_adt_def(did).struct_variant(); + let predicates = cx.tcx.predicates_of(did); + let variant = cx.tcx.adt_def(did).struct_variant(); clean::Struct { struct_type: match variant.ctor_kind { @@ -203,30 +202,30 @@ fn build_struct(cx: &DocContext, did: DefId) -> clean::Struct { CtorKind::Fn => doctree::Tuple, CtorKind::Const => doctree::Unit, }, - generics: (cx.tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.generics_of(did), &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } } fn build_union(cx: &DocContext, did: DefId) -> clean::Union { - let predicates = cx.tcx.item_predicates(did); - let variant = cx.tcx.lookup_adt_def(did).struct_variant(); + let predicates = cx.tcx.predicates_of(did); + let variant = cx.tcx.adt_def(did).struct_variant(); clean::Union { struct_type: doctree::Plain, - generics: (cx.tcx.item_generics(did), &predicates).clean(cx), + generics: (cx.tcx.generics_of(did), &predicates).clean(cx), fields: variant.fields.clean(cx), fields_stripped: false, } } fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef { - let predicates = cx.tcx.item_predicates(did); + let predicates = cx.tcx.predicates_of(did); clean::Typedef { - type_: cx.tcx.item_type(did).clean(cx), - generics: (cx.tcx.item_generics(did), &predicates).clean(cx), + type_: cx.tcx.type_of(did).clean(cx), + generics: (cx.tcx.generics_of(did), &predicates).clean(cx), } } @@ -234,7 +233,7 @@ pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { let tcx = cx.tcx; let mut impls = Vec::new(); - for &did in ty::queries::inherent_impls::get(tcx, DUMMY_SP, did).iter() { + for &did in tcx.inherent_impls(did).iter() { build_impl(cx, did, &mut impls); } @@ -326,7 +325,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { }); } - let for_ = tcx.item_type(did).clean(cx); + let for_ = tcx.type_of(did).clean(cx); // Only inline impl if the implementing type is // reachable in rustdoc generated documentation @@ -336,7 +335,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { } } - let predicates = tcx.item_predicates(did); + let predicates = tcx.predicates_of(did); let trait_items = tcx.associated_items(did).filter_map(|item| { match item.kind { ty::AssociatedKind::Const => { @@ -348,7 +347,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { Some(clean::Item { name: Some(item.name.clean(cx)), inner: clean::AssociatedConstItem( - tcx.item_type(item.def_id).clean(cx), + tcx.type_of(item.def_id).clean(cx), default, ), source: tcx.def_span(item.def_id).clean(cx), @@ -388,7 +387,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { } ty::AssociatedKind::Type => { let typedef = clean::Typedef { - type_: tcx.item_type(item.def_id).clean(cx), + type_: tcx.type_of(item.def_id).clean(cx), generics: clean::Generics { lifetimes: vec![], type_params: vec![], @@ -408,7 +407,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { } } }).collect::>(); - let polarity = tcx.trait_impl_polarity(did); + let polarity = tcx.impl_polarity(did); let trait_ = associated_trait.clean(cx).map(|bound| { match bound { clean::TraitBound(polyt, _) => polyt.trait_, @@ -432,7 +431,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { provided_trait_methods: provided, trait_: trait_, for_: for_, - generics: (tcx.item_generics(did), &predicates).clean(cx), + generics: (tcx.generics_of(did), &predicates).clean(cx), items: trait_items, polarity: Some(polarity.clean(cx)), }), @@ -487,7 +486,7 @@ fn nested(&self, state: &mut hir::print::State, nested: hir::print::Nested) } fn print_inlined_const(cx: &DocContext, did: DefId) -> String { - let body = cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap(); + let body = cx.tcx.sess.cstore.item_body(cx.tcx, did); let inlined = InlinedConst { nested_bodies: cx.tcx.sess.cstore.item_body_nested_bodies(did) }; @@ -496,14 +495,14 @@ fn print_inlined_const(cx: &DocContext, did: DefId) -> String { fn build_const(cx: &DocContext, did: DefId) -> clean::Constant { clean::Constant { - type_: cx.tcx.item_type(did).clean(cx), + type_: cx.tcx.type_of(did).clean(cx), expr: print_inlined_const(cx, did) } } fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static { clean::Static { - type_: cx.tcx.item_type(did).clean(cx), + type_: cx.tcx.type_of(did).clean(cx), mutability: if mutable {clean::Mutable} else {clean::Immutable}, expr: "\n\n\n".to_string(), // trigger the "[definition]" links } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index cf872db6823..a25eb60d2a2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -606,7 +606,7 @@ fn clean(&self, cx: &DocContext) -> TyParam { did: self.def_id, bounds: vec![], // these are filled in from the where-clauses default: if self.has_default { - Some(cx.tcx.item_type(self.def_id).clean(cx)) + Some(cx.tcx.type_of(self.def_id).clean(cx)) } else { None } @@ -1356,19 +1356,19 @@ impl<'tcx> Clean for ty::AssociatedItem { fn clean(&self, cx: &DocContext) -> Item { let inner = match self.kind { ty::AssociatedKind::Const => { - let ty = cx.tcx.item_type(self.def_id); + let ty = cx.tcx.type_of(self.def_id); AssociatedConstItem(ty.clean(cx), None) } ty::AssociatedKind::Method => { - let generics = (cx.tcx.item_generics(self.def_id), - &cx.tcx.item_predicates(self.def_id)).clean(cx); - let sig = cx.tcx.item_type(self.def_id).fn_sig(); + let generics = (cx.tcx.generics_of(self.def_id), + &cx.tcx.predicates_of(self.def_id)).clean(cx); + let sig = cx.tcx.type_of(self.def_id).fn_sig(); let mut decl = (self.def_id, sig).clean(cx); if self.method_has_self_argument { let self_ty = match self.container { ty::ImplContainer(def_id) => { - cx.tcx.item_type(def_id) + cx.tcx.type_of(def_id) } ty::TraitContainer(_) => cx.tcx.mk_self_type() }; @@ -1418,8 +1418,8 @@ fn clean(&self, cx: &DocContext) -> Item { // are actually located on the trait/impl itself, so we need to load // all of the generics from there and then look for bounds that are // applied to this associated type in question. - let predicates = cx.tcx.item_predicates(did); - let generics = (cx.tcx.item_generics(did), &predicates).clean(cx); + let predicates = cx.tcx.predicates_of(did); + let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { WherePredicate::BoundPredicate { @@ -1454,7 +1454,7 @@ fn clean(&self, cx: &DocContext) -> Item { } let ty = if self.defaultness.has_value() { - Some(cx.tcx.item_type(self.def_id)) + Some(cx.tcx.type_of(self.def_id)) } else { None }; @@ -1922,9 +1922,9 @@ fn clean(&self, cx: &DocContext) -> Type { ty::TyAnon(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let item_predicates = cx.tcx.item_predicates(def_id); + let predicates_of = cx.tcx.predicates_of(def_id); let substs = cx.tcx.lift(&substs).unwrap(); - let bounds = item_predicates.instantiate(cx.tcx, substs); + let bounds = predicates_of.instantiate(cx.tcx, substs); ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| { predicate.to_opt_poly_trait_ref().clean(cx) }).collect()) @@ -1963,7 +1963,7 @@ fn clean(&self, cx: &DocContext) -> Item { stability: get_stability(cx, self.did), deprecation: get_deprecation(cx, self.did), def_id: self.did, - inner: StructFieldItem(cx.tcx.item_type(self.did).clean(cx)), + inner: StructFieldItem(cx.tcx.type_of(self.did).clean(cx)), } } } @@ -2116,7 +2116,7 @@ fn clean(&self, cx: &DocContext) -> Item { CtorKind::Const => VariantKind::CLike, CtorKind::Fn => { VariantKind::Tuple( - self.fields.iter().map(|f| cx.tcx.item_type(f.did).clean(cx)).collect() + self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect() ) } CtorKind::Fictive => { @@ -2132,7 +2132,7 @@ fn clean(&self, cx: &DocContext) -> Item { def_id: field.did, stability: get_stability(cx, field.did), deprecation: get_deprecation(cx, field.did), - inner: StructFieldItem(cx.tcx.item_type(field.did).clean(cx)) + inner: StructFieldItem(cx.tcx.type_of(field.did).clean(cx)) } }).collect() }) diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 7240f0aedbd..be02d24e441 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -153,7 +153,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId, if child == trait_ { return true } - let predicates = cx.tcx.item_super_predicates(child).predicates; + let predicates = cx.tcx.super_predicates_of(child).predicates; predicates.iter().filter_map(|pred| { if let ty::Predicate::Trait(ref pred) = *pred { if pred.0.trait_ref.self_ty().is_self() { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index d819268240b..71594825cdb 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -214,6 +214,7 @@ pub struct Trait { pub struct Impl { pub unsafety: hir::Unsafety, pub polarity: hir::ImplPolarity, + pub defaultness: hir::Defaultness, pub generics: hir::Generics, pub trait_: Option, pub for_: P, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b02b60531d1..85a28bbfbc6 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -32,6 +32,7 @@ use std::cell::RefCell; use std::collections::{HashMap, VecDeque}; use std::default::Default; +use std::ffi::CString; use std::fmt::{self, Write}; use std::str; use syntax::feature_gate::UnstableFeatures; @@ -40,21 +41,28 @@ use html::render::derive_id; use html::toc::TocBuilder; use html::highlight; +use html::escape::Escape; use test; use pulldown_cmark::{html, Event, Tag, Parser}; use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES}; +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum RenderType { + Hoedown, + Pulldown, +} + /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. // The second parameter is whether we need a shorter version or not. -pub struct Markdown<'a>(pub &'a str); +pub struct Markdown<'a>(pub &'a str, pub RenderType); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. -pub struct MarkdownWithToc<'a>(pub &'a str); +pub struct MarkdownWithToc<'a>(pub &'a str, pub RenderType); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. -pub struct MarkdownHtml<'a>(pub &'a str); +pub struct MarkdownHtml<'a>(pub &'a str, pub RenderType); /// A unit struct like `Markdown`, that renders only the first paragraph. pub struct MarkdownSummaryLine<'a>(pub &'a str); @@ -73,6 +81,14 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { } } +/// Returns a new string with all consecutive whitespace collapsed into +/// single spaces. +/// +/// Any leading or trailing whitespace will be trimmed. +fn collapse_whitespace(s: &str) -> String { + s.split_whitespace().collect::>().join(" ") +} + /// Convert chars from a title for an id. /// /// "Hello, world!" -> "hello-world" @@ -368,6 +384,7 @@ fn next(&mut self) -> Option { const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4; const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8; const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2; +const HOEDOWN_HTML_ESCAPE: libc::c_uint = 1 << 1; const HOEDOWN_EXTENSIONS: libc::c_uint = HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES | @@ -462,6 +479,13 @@ struct hoedown_buffer { unit: libc::size_t, } +struct MyOpaque { + dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + *const hoedown_buffer, *const hoedown_renderer_data, + libc::size_t), + toc_builder: Option, +} + extern { fn hoedown_html_renderer_new(render_flags: libc::c_uint, nesting_level: libc::c_int) @@ -478,6 +502,7 @@ fn hoedown_document_render(doc: *mut hoedown_document, fn hoedown_document_free(md: *mut hoedown_document); fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer; + fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char); fn hoedown_buffer_free(b: *mut hoedown_buffer); } @@ -487,6 +512,208 @@ fn as_bytes(&self) -> &[u8] { } } +pub fn render(w: &mut fmt::Formatter, + s: &str, + print_toc: bool, + html_flags: libc::c_uint) -> fmt::Result { + extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer, + lang: *const hoedown_buffer, data: *const hoedown_renderer_data, + line: libc::size_t) { + unsafe { + if orig_text.is_null() { return } + + let opaque = (*data).opaque as *mut hoedown_html_renderer_state; + let my_opaque: &MyOpaque = &*((*opaque).opaque as *const MyOpaque); + let text = (*orig_text).as_bytes(); + let origtext = str::from_utf8(text).unwrap(); + let origtext = origtext.trim_left(); + debug!("docblock: ==============\n{:?}\n=======", text); + let rendered = if lang.is_null() || origtext.is_empty() { + false + } else { + let rlang = (*lang).as_bytes(); + let rlang = str::from_utf8(rlang).unwrap(); + if !LangString::parse(rlang).rust { + (my_opaque.dfltblk)(ob, orig_text, lang, + opaque as *const hoedown_renderer_data, + line); + true + } else { + false + } + }; + + let lines = origtext.lines().filter(|l| { + stripped_filtered_line(*l).is_none() + }); + let text = lines.collect::>().join("\n"); + if rendered { return } + PLAYGROUND.with(|play| { + // insert newline to clearly separate it from the + // previous block so we can shorten the html output + let mut s = String::from("\n"); + let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { + if url.is_empty() { + return None; + } + let test = origtext.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }).collect::>().join("\n"); + let krate = krate.as_ref().map(|s| &**s); + let test = test::maketest(&test, krate, false, + &Default::default()); + let channel = if test.contains("#![feature(") { + "&version=nightly" + } else { + "" + }; + // These characters don't need to be escaped in a URI. + // FIXME: use a library function for percent encoding. + fn dont_escape(c: u8) -> bool { + (b'a' <= c && c <= b'z') || + (b'A' <= c && c <= b'Z') || + (b'0' <= c && c <= b'9') || + c == b'-' || c == b'_' || c == b'.' || + c == b'~' || c == b'!' || c == b'\'' || + c == b'(' || c == b')' || c == b'*' + } + let mut test_escaped = String::new(); + for b in test.bytes() { + if dont_escape(b) { + test_escaped.push(char::from(b)); + } else { + write!(test_escaped, "%{:02X}", b).unwrap(); + } + } + Some(format!( + r#"Run"#, + url, test_escaped, channel + )) + }); + s.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); + let output = CString::new(s).unwrap(); + hoedown_buffer_puts(ob, output.as_ptr()); + }) + } + } + + extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer, + level: libc::c_int, data: *const hoedown_renderer_data, + _: libc::size_t) { + // hoedown does this, we may as well too + unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); } + + // Extract the text provided + let s = if text.is_null() { + "".to_owned() + } else { + let s = unsafe { (*text).as_bytes() }; + str::from_utf8(&s).unwrap().to_owned() + }; + + // Discard '', '' tags and some escaped characters, + // transform the contents of the header into a hyphenated string + // without non-alphanumeric characters other than '-' and '_'. + // + // This is a terrible hack working around how hoedown gives us rendered + // html for text rather than the raw text. + let mut id = s.clone(); + let repl_sub = vec!["", "", "", "", + "", "", + "<", ">", "&", "'", """]; + for sub in repl_sub { + id = id.replace(sub, ""); + } + let id = id.chars().filter_map(|c| { + if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } + }).collect::(); + + let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state }; + let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; + + let id = derive_id(id); + + let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| { + format!("{} ", builder.push(level as u32, s.clone(), id.clone())) + }); + + // Render the HTML + let text = format!("\ + {sec}{}", + s, lvl = level, id = id, sec = sec); + + let text = CString::new(text).unwrap(); + unsafe { hoedown_buffer_puts(ob, text.as_ptr()) } + } + + extern fn codespan( + ob: *mut hoedown_buffer, + text: *const hoedown_buffer, + _: *const hoedown_renderer_data, + _: libc::size_t + ) -> libc::c_int { + let content = if text.is_null() { + "".to_owned() + } else { + let bytes = unsafe { (*text).as_bytes() }; + let s = str::from_utf8(bytes).unwrap(); + collapse_whitespace(s) + }; + + let content = format!("{}", Escape(&content)); + let element = CString::new(content).unwrap(); + unsafe { hoedown_buffer_puts(ob, element.as_ptr()); } + // Return anything except 0, which would mean "also print the code span verbatim". + 1 + } + + unsafe { + let ob = hoedown_buffer_new(DEF_OUNIT); + let renderer = hoedown_html_renderer_new(html_flags, 0); + let mut opaque = MyOpaque { + dfltblk: (*renderer).blockcode.unwrap(), + toc_builder: if print_toc {Some(TocBuilder::new())} else {None} + }; + (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque + = &mut opaque as *mut _ as *mut libc::c_void; + (*renderer).blockcode = Some(block); + (*renderer).header = Some(header); + (*renderer).codespan = Some(codespan); + + let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); + hoedown_document_render(document, ob, s.as_ptr(), + s.len() as libc::size_t); + hoedown_document_free(document); + + hoedown_html_renderer_free(renderer); + + let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| { + write!(w, "", builder.into_toc()) + }); + + if ret.is_ok() { + let buf = (*ob).as_bytes(); + ret = w.write_str(str::from_utf8(buf).unwrap()); + } + hoedown_buffer_free(ob); + ret + } +} + pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { extern fn block(_ob: *mut hoedown_buffer, text: *const hoedown_buffer, @@ -503,11 +730,26 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position LangString::parse(s) }; if !block_info.rust { return } + let text = (*text).as_bytes(); let opaque = (*data).opaque as *mut hoedown_html_renderer_state; let tests = &mut *((*opaque).opaque as *mut ::test::Collector); - let line = tests.get_line() + line; + let text = str::from_utf8(text).unwrap(); + let lines = text.lines().map(|l| { + stripped_filtered_line(l).unwrap_or(l) + }); + let text = lines.collect::>().join("\n"); let filename = tests.get_filename(); - tests.add_old_test(line, filename); + + if tests.render_type == RenderType::Hoedown { + let line = tests.get_line() + line; + tests.add_test(text.to_owned(), + block_info.should_panic, block_info.no_run, + block_info.ignore, block_info.test_harness, + block_info.compile_fail, block_info.error_codes, + line, filename); + } else { + tests.add_old_test(text, filename); + } } } @@ -529,7 +771,6 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position } tests.set_position(position); - unsafe { let ob = hoedown_buffer_new(DEF_OUNIT); let renderer = hoedown_html_renderer_new(0, 0); @@ -698,72 +939,84 @@ fn parse(string: &str) -> LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let Markdown(md) = *self; + let Markdown(md, render_type) = *self; + // This is actually common enough to special-case if md.is_empty() { return Ok(()) } + if render_type == RenderType::Hoedown { + render(fmt, md, false, 0) + } else { + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); - - let p = Parser::new_ext(md, opts); + let p = Parser::new_ext(md, opts); - let mut s = String::with_capacity(md.len() * 3 / 2); + let mut s = String::with_capacity(md.len() * 3 / 2); - html::push_html(&mut s, - Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); - fmt.write_str(&s) + fmt.write_str(&s) + } } } impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let MarkdownWithToc(md) = *self; + let MarkdownWithToc(md, render_type) = *self; - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); + if render_type == RenderType::Hoedown { + render(fmt, md, true, 0) + } else { + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); - let p = Parser::new_ext(md, opts); + let p = Parser::new_ext(md, opts); - let mut s = String::with_capacity(md.len() * 3 / 2); + let mut s = String::with_capacity(md.len() * 3 / 2); - let mut toc = TocBuilder::new(); + let mut toc = TocBuilder::new(); - html::push_html(&mut s, - Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc))))); + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc))))); - write!(fmt, "", toc.into_toc())?; + write!(fmt, "", toc.into_toc())?; - fmt.write_str(&s) + fmt.write_str(&s) + } } } impl<'a> fmt::Display for MarkdownHtml<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let MarkdownHtml(md) = *self; + let MarkdownHtml(md, render_type) = *self; + // This is actually common enough to special-case if md.is_empty() { return Ok(()) } + if render_type == RenderType::Hoedown { + render(fmt, md, false, HOEDOWN_HTML_ESCAPE) + } else { + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); - let mut opts = Options::empty(); - opts.insert(OPTION_ENABLE_TABLES); - opts.insert(OPTION_ENABLE_FOOTNOTES); - - let p = Parser::new_ext(md, opts); + let p = Parser::new_ext(md, opts); - // Treat inline HTML as plain text. - let p = p.map(|event| match event { - Event::Html(text) | Event::InlineHtml(text) => Event::Text(text), - _ => event - }); + // Treat inline HTML as plain text. + let p = p.map(|event| match event { + Event::Html(text) | Event::InlineHtml(text) => Event::Text(text), + _ => event + }); - let mut s = String::with_capacity(md.len() * 3 / 2); + let mut s = String::with_capacity(md.len() * 3 / 2); - html::push_html(&mut s, - Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); - fmt.write_str(&s) + fmt.write_str(&s) + } } } @@ -837,6 +1090,7 @@ fn next(&mut self) -> Option { mod tests { use super::{LangString, Markdown, MarkdownHtml}; use super::plain_summary_line; + use super::RenderType; use html::render::reset_ids; #[test] @@ -877,14 +1131,14 @@ fn t(s: &str, #[test] fn issue_17736() { let markdown = "# title"; - format!("{}", Markdown(markdown)); + format!("{}", Markdown(markdown, RenderType::Pulldown)); reset_ids(true); } #[test] fn test_header() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); + let output = format!("{}", Markdown(input, RenderType::Pulldown)); assert_eq!(output, expect, "original: {}", input); reset_ids(true); } @@ -906,7 +1160,7 @@ fn t(input: &str, expect: &str) { #[test] fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input)); + let output = format!("{}", Markdown(input, RenderType::Pulldown)); assert_eq!(output, expect, "original: {}", input); } @@ -947,7 +1201,7 @@ fn t(input: &str, expect: &str) { #[test] fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { - let output = format!("{}", MarkdownHtml(input)); + let output = format!("{}", MarkdownHtml(input, RenderType::Pulldown)); assert_eq!(output, expect, "original: {}", input); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d55a0640562..57d71e6c4e0 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -72,7 +72,7 @@ use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::format::fmt_impl_for_trait_page; use html::item_type::ItemType; -use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine}; +use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, RenderType}; use html::{highlight, layout}; /// A pair of name and its optional document. @@ -98,6 +98,7 @@ pub struct Context { /// publicly reused items to redirect to the right location. pub render_redirect_pages: bool, pub shared: Arc, + pub render_type: RenderType, } pub struct SharedContext { @@ -433,7 +434,8 @@ pub fn run(mut krate: clean::Crate, dst: PathBuf, passes: FxHashSet, css_file_extension: Option, - renderinfo: RenderInfo) -> Result<(), Error> { + renderinfo: RenderInfo, + render_type: RenderType) -> Result<(), Error> { let src_root = match krate.src.parent() { Some(p) => p.to_path_buf(), None => PathBuf::new(), @@ -495,6 +497,7 @@ pub fn run(mut krate: clean::Crate, dst: dst, render_redirect_pages: false, shared: Arc::new(scx), + render_type: render_type, }; // Crawl the crate to build various caches used for the output @@ -1638,11 +1641,12 @@ fn plain_summary_line(s: Option<&str>) -> String { fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result { document_stability(w, cx, item)?; - document_full(w, item)?; + document_full(w, item, cx.render_type)?; Ok(()) } -fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink) -> fmt::Result { +fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink, + render_type: RenderType) -> fmt::Result { if let Some(s) = item.doc_value() { let markdown = if s.contains('\n') { format!("{} [Read more]({})", @@ -1651,7 +1655,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin format!("{}", &plain_summary_line(Some(s))) }; write!(w, "
{}
", - Markdown(&markdown))?; + Markdown(&markdown, render_type))?; } Ok(()) } @@ -1681,10 +1685,11 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> { } } -fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { +fn document_full(w: &mut fmt::Formatter, item: &clean::Item, + render_type: RenderType) -> fmt::Result { if let Some(s) = get_doc_value(item) { write!(w, "
{}
", - Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s), render_type))?; } Ok(()) } @@ -1872,7 +1877,13 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering ", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = MarkdownSummaryLine(doc_value), + docs = if cx.render_type == RenderType::Hoedown { + format!("{}", + shorter(Some(&Markdown(doc_value, + RenderType::Hoedown).to_string()))) + } else { + format!("{}", MarkdownSummaryLine(doc_value)) + }, class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -1915,7 +1926,9 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec{}", text)) }; @@ -1944,7 +1957,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec🔬 \ This is a nightly-only experimental API. {}\ {}", - unstable_extra, MarkdownHtml(&stab.unstable_reason)); + unstable_extra, + MarkdownHtml(&stab.unstable_reason, cx.render_type)); stability.push(format!("
{}
", text)); } @@ -1964,7 +1978,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec{}", text)) } @@ -2900,7 +2914,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "")?; write!(w, "\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "
{}
", Markdown(dox))?; + write!(w, "
{}
", Markdown(dox, cx.render_type))?; } } @@ -2999,11 +3013,11 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, // because impls can't have a stability. document_stability(w, cx, it)?; if get_doc_value(item).is_some() { - document_full(w, item)?; + document_full(w, item, cx.render_type)?; } else { // In case the item isn't documented, // provide short documentation from the trait. - document_short(w, it, link)?; + document_short(w, it, link, cx.render_type)?; } } } else { @@ -3011,7 +3025,7 @@ fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, } } else { document_stability(w, cx, item)?; - document_short(w, item, link)?; + document_short(w, item, link, cx.render_type)?; } } Ok(()) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d5b997001bb..2a6134fde5c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -27,6 +27,7 @@ #![feature(staged_api)] #![feature(test)] #![feature(unicode)] +#![feature(vec_remove_item)] extern crate arena; extern crate getopts; @@ -92,6 +93,8 @@ pub mod html { use clean::AttributesExt; +use html::markdown::RenderType; + struct Output { krate: clean::Crate, renderinfo: html::render::RenderInfo, @@ -168,6 +171,7 @@ pub fn opts() -> Vec { "URL to send code snippets to, may be reset by --markdown-playground-url \ or `#![doc(html_playground_url=...)]`", "URL")), + unstable(optflag("", "enable-commonmark", "to enable commonmark doc rendering/testing")), ] } @@ -249,6 +253,12 @@ pub fn main_args(args: &[String]) -> isize { let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s)); let cfgs = matches.opt_strs("cfg"); + let render_type = if matches.opt_present("enable-commonmark") { + RenderType::Pulldown + } else { + RenderType::Hoedown + }; + if let Some(ref p) = css_file_extension { if !p.is_file() { writeln!( @@ -272,15 +282,17 @@ pub fn main_args(args: &[String]) -> isize { match (should_test, markdown_input) { (true, true) => { - return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot) + return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type) } (true, false) => { - return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot) + return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot, + render_type) } (false, true) => return markdown::render(input, output.unwrap_or(PathBuf::from("doc")), &matches, &external_html, - !matches.opt_present("markdown-no-toc")), + !matches.opt_present("markdown-no-toc"), + render_type), (false, false) => {} } @@ -294,7 +306,8 @@ pub fn main_args(args: &[String]) -> isize { output.unwrap_or(PathBuf::from("doc")), passes.into_iter().collect(), css_file_extension, - renderinfo) + renderinfo, + render_type) .expect("failed to generate documentation"); 0 } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index f75144c23ac..b9ed0eeaef7 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -26,6 +26,7 @@ use html::escape::Escape; use html::markdown; use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code}; +use html::markdown::RenderType; use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `# ` or `%`. @@ -50,7 +51,8 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { /// Render `input` (e.g. "foo.md") into an HTML file in `output` /// (e.g. output = "bar" => "bar/foo.html"). pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, - external_html: &ExternalHtml, include_toc: bool) -> isize { + external_html: &ExternalHtml, include_toc: bool, + render_type: RenderType) -> isize { let input_p = Path::new(input); output.push(input_p.file_stem().unwrap()); output.set_extension("html"); @@ -94,9 +96,9 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, reset_ids(false); let rendered = if include_toc { - format!("{}", MarkdownWithToc(text)) + format!("{}", MarkdownWithToc(text, render_type)) } else { - format!("{}", Markdown(text)) + format!("{}", Markdown(text, render_type)) }; let err = write!( @@ -147,7 +149,8 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, /// Run any tests/code examples in the markdown file `input`. pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, - mut test_args: Vec, maybe_sysroot: Option) -> isize { + mut test_args: Vec, maybe_sysroot: Option, + render_type: RenderType) -> isize { let input_str = match load_string(input) { Ok(s) => s, Err(LoadStringError::ReadFail) => return 1, @@ -158,7 +161,8 @@ pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, opts.no_crate_inject = true; let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, true, opts, maybe_sysroot, None, - Some(input.to_owned())); + Some(input.to_owned()), + render_type); old_find_testable_code(&input_str, &mut collector, DUMMY_SP); find_testable_code(&input_str, &mut collector, DUMMY_SP); test_args.insert(0, "rustdoctest".to_string()); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index fb681b20065..5b9ab304db0 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::HashMap; use std::env; use std::ffi::OsString; use std::io::prelude::*; @@ -42,7 +43,7 @@ use errors::emitter::ColorConfig; use clean::Attributes; -use html::markdown; +use html::markdown::{self, RenderType}; #[derive(Clone, Default)] pub struct TestOptions { @@ -56,7 +57,8 @@ pub fn run(input: &str, externs: Externs, mut test_args: Vec, crate_name: Option, - maybe_sysroot: Option) + maybe_sysroot: Option, + render_type: RenderType) -> isize { let input_path = PathBuf::from(input); let input = config::Input::File(input_path.clone()); @@ -105,7 +107,8 @@ pub fn run(input: &str, opts, maybe_sysroot, Some(codemap), - None); + None, + render_type); { let dep_graph = DepGraph::new(false); @@ -381,7 +384,7 @@ fn partition_source(s: &str) -> (String, String) { pub struct Collector { pub tests: Vec, // to be removed when hoedown will be definitely gone - pub old_tests: Vec, + pub old_tests: HashMap>, names: Vec, cfgs: Vec, libs: SearchPaths, @@ -395,15 +398,18 @@ pub struct Collector { position: Span, codemap: Option>, filename: Option, + // to be removed when hoedown will be removed as well + pub render_type: RenderType, } impl Collector { pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, use_headers: bool, opts: TestOptions, maybe_sysroot: Option, - codemap: Option>, filename: Option) -> Collector { + codemap: Option>, filename: Option, + render_type: RenderType) -> Collector { Collector { tests: Vec::new(), - old_tests: Vec::new(), + old_tests: HashMap::new(), names: Vec::new(), cfgs: cfgs, libs: libs, @@ -417,6 +423,7 @@ pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Ext position: DUMMY_SP, codemap: codemap, filename: filename, + render_type: render_type, } } @@ -432,9 +439,24 @@ fn generate_name(&self, line: usize, filename: &str) -> String { } } - pub fn add_old_test(&mut self, line: usize, filename: String) { - let name = self.generate_name(line, &filename); - self.old_tests.push(name); + // to be removed once hoedown is gone + fn generate_name_beginning(&self, filename: &str) -> String { + if self.use_headers { + if let Some(ref header) = self.current_header { + format!("{} - {} (line", filename, header) + } else { + format!("{} - (line", filename) + } + } else { + format!("{} - {} (line", filename, self.names.join("::")) + } + } + + pub fn add_old_test(&mut self, test: String, filename: String) { + let name_beg = self.generate_name_beginning(&filename); + let entry = self.old_tests.entry(name_beg) + .or_insert(Vec::new()); + entry.push(test.trim().to_owned()); } pub fn add_test(&mut self, test: String, @@ -442,13 +464,22 @@ pub fn add_test(&mut self, test: String, as_test_harness: bool, compile_fail: bool, error_codes: Vec, line: usize, filename: String) { let name = self.generate_name(line, &filename); - if self.old_tests.iter().find(|&x| x == &name).is_none() { - let _ = writeln!(&mut io::stderr(), - "WARNING: {} Code block is not currently run as a test, but will in \ - future versions of rustdoc. Please ensure this code block is a \ - runnable test, or use the `ignore` directive.", - name); - return + // to be removed when hoedown is removed + if self.render_type == RenderType::Pulldown { + let name_beg = self.generate_name_beginning(&filename); + let mut found = false; + let test = test.trim().to_owned(); + if let Some(entry) = self.old_tests.get_mut(&name_beg) { + found = entry.remove_item(&test).is_some(); + } + if !found { + let _ = writeln!(&mut io::stderr(), + "WARNING: {} Code block is not currently run as a test, but will \ + in future versions of rustdoc. Please ensure this code block is \ + a runnable test, or use the `ignore` directive.", + name); + return + } } let cfgs = self.cfgs.clone(); let libs = self.libs.clone(); @@ -564,10 +595,15 @@ fn visit_testable(&mut self, attrs.unindent_doc_comments(); if let Some(doc) = attrs.doc_value() { self.collector.cnt = 0; - markdown::old_find_testable_code(doc, self.collector, + if self.collector.render_type == RenderType::Pulldown { + markdown::old_find_testable_code(doc, self.collector, + attrs.span.unwrap_or(DUMMY_SP)); + markdown::find_testable_code(doc, self.collector, attrs.span.unwrap_or(DUMMY_SP)); - markdown::find_testable_code(doc, self.collector, - attrs.span.unwrap_or(DUMMY_SP)); + } else { + markdown::old_find_testable_code(doc, self.collector, + attrs.span.unwrap_or(DUMMY_SP)); + } } nested(self); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4252f2981ed..d463e41c58a 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -502,7 +502,13 @@ pub fn visit_item(&mut self, item: &hir::Item, om.traits.push(t); }, - hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref item_ids) => { + hir::ItemImpl(unsafety, + polarity, + defaultness, + ref gen, + ref tr, + ref ty, + ref item_ids) => { // Don't duplicate impls when inlining, we'll pick them up // regardless of where they're located. if !self.inlining { @@ -512,6 +518,7 @@ pub fn visit_item(&mut self, item: &hir::Item, let i = Impl { unsafety: unsafety, polarity: polarity, + defaultness: defaultness, generics: gen.clone(), trait_: tr.clone(), for_: ty.clone(), diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 46511452a72..717892be2ab 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -23,6 +23,10 @@ compiler_builtins = { path = "../libcompiler_builtins" } std_unicode = { path = "../libstd_unicode" } unwind = { path = "../libunwind" } +[target.x86_64-apple-darwin.dependencies] +rustc_asan = { path = "../librustc_asan" } +rustc_tsan = { path = "../librustc_tsan" } + [target.x86_64-unknown-linux-gnu.dependencies] rustc_asan = { path = "../librustc_asan" } rustc_lsan = { path = "../librustc_lsan" } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index eacb59d375a..51d127f8ba7 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1377,7 +1377,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> { /// An owning iterator over the entries of a `HashMap`. /// -/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// This `struct` is created by the [`into_iter`] method on [`HashMap`][`HashMap`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: struct.HashMap.html#method.into_iter @@ -2017,13 +2017,6 @@ pub fn key(&self) -> &K { self.elem.read().0 } - /// Deprecated, renamed to `remove_entry` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] - pub fn remove_pair(self) -> (K, V) { - self.remove_entry() - } - /// Take the ownership of the key and value from the map. /// /// # Examples diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e3fad285025..7215e1bde85 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -890,7 +890,7 @@ pub struct Iter<'a, K: 'a> { /// An owning iterator over the items of a `HashSet`. /// -/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// This `struct` is created by the [`into_iter`] method on [`HashSet`][`HashSet`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`HashSet`]: struct.HashSet.html diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 316e6841c4f..4abad7e24f8 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -22,8 +22,6 @@ #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use libc::c_int; -#[cfg(not(test))] use num::FpCategory; @@ -73,8 +71,6 @@ mod cmath { pub fn atan2f(a: c_float, b: c_float) -> c_float; pub fn atanf(n: c_float) -> c_float; pub fn coshf(n: c_float) -> c_float; - pub fn frexpf(n: c_float, value: &mut c_int) -> c_float; - pub fn ldexpf(x: c_float, n: c_int) -> c_float; pub fn sinhf(n: c_float) -> c_float; pub fn tanf(n: c_float) -> c_float; pub fn tanhf(n: c_float) -> c_float; @@ -84,7 +80,7 @@ mod cmath { pub use self::shims::*; #[cfg(target_env = "msvc")] mod shims { - use libc::{c_float, c_int}; + use libc::c_float; #[inline] pub unsafe fn acosf(n: c_float) -> c_float { @@ -111,20 +107,6 @@ pub unsafe fn coshf(n: c_float) -> c_float { f64::cosh(n as f64) as c_float } - #[inline] - #[allow(deprecated)] - pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float { - let (a, b) = f64::frexp(x as f64); - *value = b as c_int; - a as c_float - } - - #[inline] - #[allow(deprecated)] - pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float { - f64::ldexp(x as f64, n as isize) as c_float - } - #[inline] pub unsafe fn sinhf(n: c_float) -> c_float { f64::sinh(n as f64) as c_float @@ -244,40 +226,6 @@ pub fn is_normal(self) -> bool { num::Float::is_normal(self) } #[inline] pub fn classify(self) -> FpCategory { num::Float::classify(self) } - /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. - /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. - /// The floating point encoding is documented in the [Reference][floating-point]. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let num = 2.0f32; - /// - /// // (8388608, -22, 1) - /// let (mantissa, exponent, sign) = num.integer_decode(); - /// let sign_f = sign as f32; - /// let mantissa_f = mantissa as f32; - /// let exponent_f = num.powf(exponent as f32); - /// - /// // 1 * 8388608 * 2^(-22) == 2 - /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - /// [floating-point]: ../reference/types.html#machine-types - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - #[allow(deprecated)] - pub fn integer_decode(self) -> (u64, i16, i8) { - num::Float::integer_decode(self) - } - /// Returns the largest integer less than or equal to a number. /// /// ``` @@ -712,89 +660,6 @@ pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) } #[inline] pub fn to_radians(self) -> f32 { num::Float::to_radians(self) } - /// Constructs a floating point number of `x*2^exp`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// // 3*2^2 - 12 == 0 - /// let abs_difference = (f32::ldexp(3.0, 2) - 12.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn ldexp(x: f32, exp: isize) -> f32 { - unsafe { cmath::ldexpf(x, exp as c_int) } - } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// * `self = x * 2^exp` - /// * `0.5 <= abs(x) < 1.0` - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let x = 4.0f32; - /// - /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 - /// let f = x.frexp(); - /// let abs_difference_0 = (f.0 - 0.5).abs(); - /// let abs_difference_1 = (f.1 as f32 - 3.0).abs(); - /// - /// assert!(abs_difference_0 <= f32::EPSILON); - /// assert!(abs_difference_1 <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn frexp(self) -> (f32, isize) { - unsafe { - let mut exp = 0; - let x = cmath::frexpf(self, &mut exp); - (x, exp as isize) - } - } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// use std::f32; - /// - /// let x = 1.0f32; - /// - /// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs(); - /// - /// assert!(abs_diff <= f32::EPSILON); - /// ``` - #[unstable(feature = "float_extras", - reason = "unsure about its place in the world", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn next_after(self, other: f32) -> f32 { - unsafe { cmath::nextafterf(self, other) } - } - /// Returns the maximum of the two numbers. /// /// ``` @@ -1462,23 +1327,6 @@ fn test_classify() { assert_eq!(1e-38f32.classify(), Fp::Subnormal); } - #[test] - #[allow(deprecated)] - fn test_integer_decode() { - assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); - assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); - assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); - assert_eq!(0f32.integer_decode(), (0, -150, 1)); - assert_eq!((-0f32).integer_decode(), (0, -150, -1)); - assert_eq!(INFINITY.integer_decode(), (8388608, 105, 1)); - assert_eq!(NEG_INFINITY.integer_decode(), (8388608, 105, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (12582912, 105)); - } - #[test] fn test_floor() { assert_approx_eq!(1.0f32.floor(), 1.0f32); @@ -1790,58 +1638,6 @@ fn test_to_radians() { assert_eq!(neg_inf.to_radians(), neg_inf); } - #[test] - #[allow(deprecated)] - fn test_ldexp() { - let f1 = 2.0f32.powi(-123); - let f2 = 2.0f32.powi(-111); - let f3 = 1.75 * 2.0f32.powi(-12); - assert_eq!(f32::ldexp(1f32, -123), f1); - assert_eq!(f32::ldexp(1f32, -111), f2); - assert_eq!(f32::ldexp(1.75f32, -12), f3); - - assert_eq!(f32::ldexp(0f32, -123), 0f32); - assert_eq!(f32::ldexp(-0f32, -123), -0f32); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(f32::ldexp(inf, -123), inf); - assert_eq!(f32::ldexp(neg_inf, -123), neg_inf); - assert!(f32::ldexp(nan, -123).is_nan()); - } - - #[test] - #[allow(deprecated)] - fn test_frexp() { - let f1 = 2.0f32.powi(-123); - let f2 = 2.0f32.powi(-111); - let f3 = 1.75 * 2.0f32.powi(-123); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - let (x3, exp3) = f3.frexp(); - assert_eq!((x1, exp1), (0.5f32, -122)); - assert_eq!((x2, exp2), (0.5f32, -110)); - assert_eq!((x3, exp3), (0.875f32, -122)); - assert_eq!(f32::ldexp(x1, exp1), f1); - assert_eq!(f32::ldexp(x2, exp2), f2); - assert_eq!(f32::ldexp(x3, exp3), f3); - - assert_eq!(0f32.frexp(), (0f32, 0)); - assert_eq!((-0f32).frexp(), (-0f32, 0)); - } - - #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 - #[allow(deprecated)] - fn test_frexp_nowin() { - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(match inf.frexp() { (x, _) => x }, inf); - assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); - assert!(match nan.frexp() { (x, _) => x.is_nan() }) - } - #[test] fn test_asinh() { assert_eq!(0.0f32.asinh(), 0.0f32); diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index be55cb80c92..82e3903eec7 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -22,8 +22,6 @@ #[cfg(not(test))] use intrinsics; #[cfg(not(test))] -use libc::c_int; -#[cfg(not(test))] use num::FpCategory; #[stable(feature = "rust1", since = "1.0.0")] @@ -188,36 +186,6 @@ pub fn is_normal(self) -> bool { num::Float::is_normal(self) } #[inline] pub fn classify(self) -> FpCategory { num::Float::classify(self) } - /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. - /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. - /// The floating point encoding is documented in the [Reference][floating-point]. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let num = 2.0f64; - /// - /// // (8388608, -22, 1) - /// let (mantissa, exponent, sign) = num.integer_decode(); - /// let sign_f = sign as f64; - /// let mantissa_f = mantissa as f64; - /// let exponent_f = num.powf(exponent as f64); - /// - /// // 1 * 8388608 * 2^(-22) == 2 - /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - /// [floating-point]: ../reference/types.html#machine-types - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - #[allow(deprecated)] - pub fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) } - /// Returns the largest integer less than or equal to a number. /// /// ``` @@ -606,84 +574,6 @@ pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) } #[inline] pub fn to_radians(self) -> f64 { num::Float::to_radians(self) } - /// Constructs a floating point number of `x*2^exp`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// // 3*2^2 - 12 == 0 - /// let abs_difference = (f64::ldexp(3.0, 2) - 12.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn ldexp(x: f64, exp: isize) -> f64 { - unsafe { cmath::ldexp(x, exp as c_int) } - } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// * `self = x * 2^exp` - /// * `0.5 <= abs(x) < 1.0` - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let x = 4.0_f64; - /// - /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 - /// let f = x.frexp(); - /// let abs_difference_0 = (f.0 - 0.5).abs(); - /// let abs_difference_1 = (f.1 as f64 - 3.0).abs(); - /// - /// assert!(abs_difference_0 < 1e-10); - /// assert!(abs_difference_1 < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "pending integer conventions", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn frexp(self) -> (f64, isize) { - unsafe { - let mut exp = 0; - let x = cmath::frexp(self, &mut exp); - (x, exp as isize) - } - } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - /// - /// ``` - /// #![feature(float_extras)] - /// - /// let x = 1.0f64; - /// - /// let abs_diff = (x.next_after(2.0) - 1.0000000000000002220446049250313_f64).abs(); - /// - /// assert!(abs_diff < 1e-10); - /// ``` - #[unstable(feature = "float_extras", - reason = "unsure about its place in the world", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - #[inline] - pub fn next_after(self, other: f64) -> f64 { - unsafe { cmath::nextafter(self, other) } - } - /// Returns the maximum of the two numbers. /// /// ``` @@ -1353,23 +1243,6 @@ fn test_classify() { assert_eq!(1e-308f64.classify(), Fp::Subnormal); } - #[test] - #[allow(deprecated)] - fn test_integer_decode() { - assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); - assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); - assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); - assert_eq!(0f64.integer_decode(), (0, -1075, 1)); - assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); - assert_eq!(INFINITY.integer_decode(), (4503599627370496, 972, 1)); - assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); - - // Ignore the "sign" (quiet / signalling flag) of NAN. - // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (6755399441055744, 972)); - } - #[test] fn test_floor() { assert_approx_eq!(1.0f64.floor(), 1.0f64); @@ -1681,58 +1554,6 @@ fn test_to_radians() { assert_eq!(neg_inf.to_radians(), neg_inf); } - #[test] - #[allow(deprecated)] - fn test_ldexp() { - let f1 = 2.0f64.powi(-123); - let f2 = 2.0f64.powi(-111); - let f3 = 1.75 * 2.0f64.powi(-12); - assert_eq!(f64::ldexp(1f64, -123), f1); - assert_eq!(f64::ldexp(1f64, -111), f2); - assert_eq!(f64::ldexp(1.75f64, -12), f3); - - assert_eq!(f64::ldexp(0f64, -123), 0f64); - assert_eq!(f64::ldexp(-0f64, -123), -0f64); - - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(f64::ldexp(inf, -123), inf); - assert_eq!(f64::ldexp(neg_inf, -123), neg_inf); - assert!(f64::ldexp(nan, -123).is_nan()); - } - - #[test] - #[allow(deprecated)] - fn test_frexp() { - let f1 = 2.0f64.powi(-123); - let f2 = 2.0f64.powi(-111); - let f3 = 1.75 * 2.0f64.powi(-123); - let (x1, exp1) = f1.frexp(); - let (x2, exp2) = f2.frexp(); - let (x3, exp3) = f3.frexp(); - assert_eq!((x1, exp1), (0.5f64, -122)); - assert_eq!((x2, exp2), (0.5f64, -110)); - assert_eq!((x3, exp3), (0.875f64, -122)); - assert_eq!(f64::ldexp(x1, exp1), f1); - assert_eq!(f64::ldexp(x2, exp2), f2); - assert_eq!(f64::ldexp(x3, exp3), f3); - - assert_eq!(0f64.frexp(), (0f64, 0)); - assert_eq!((-0f64).frexp(), (-0f64, 0)); - } - - #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 - #[allow(deprecated)] - fn test_frexp_nowin() { - let inf: f64 = INFINITY; - let neg_inf: f64 = NEG_INFINITY; - let nan: f64 = NAN; - assert_eq!(match inf.frexp() { (x, _) => x }, inf); - assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); - assert!(match nan.frexp() { (x, _) => x.is_nan() }) - } - #[test] fn test_asinh() { assert_eq!(0.0f64.asinh(), 0.0f64); diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index cd096c115ba..e2832873e2e 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -466,6 +466,9 @@ pub trait Read { /// variant will be returned. If an error is returned then it must be /// guaranteed that no bytes were read. /// + /// An error of the `ErrorKind::Interrupted` kind is non-fatal and the read + /// operation should be retried if there is nothing else to do. + /// /// # Examples /// /// [`File`][file]s implement `Read`: @@ -481,7 +484,7 @@ pub trait Read { /// let mut f = File::open("foo.txt")?; /// let mut buffer = [0; 10]; /// - /// // read 10 bytes + /// // read up to 10 bytes /// f.read(&mut buffer[..])?; /// # Ok(()) /// # } @@ -885,6 +888,9 @@ pub trait Write { /// It is **not** considered an error if the entire buffer could not be /// written to this writer. /// + /// An error of the `ErrorKind::Interrupted` kind is non-fatal and the + /// write operation should be retried if there is nothing else to do. + /// /// # Examples /// /// ``` @@ -894,6 +900,7 @@ pub trait Write { /// # fn foo() -> std::io::Result<()> { /// let mut buffer = File::create("foo.txt")?; /// + /// // Writes some prefix of the byte string, not necessarily all of it. /// buffer.write(b"some bytes")?; /// # Ok(()) /// # } @@ -929,14 +936,17 @@ pub trait Write { /// Attempts to write an entire buffer into this write. /// - /// This method will continuously call `write` while there is more data to - /// write. This method will not return until the entire buffer has been - /// successfully written or an error occurs. The first error generated from - /// this method will be returned. + /// This method will continuously call `write` until there is no more data + /// to be written or an error of non-`ErrorKind::Interrupted` kind is + /// returned. This method will not return until the entire buffer has been + /// successfully written or such an error occurs. The first error that is + /// not of `ErrorKind::Interrupted` kind generated from this method will be + /// returned. /// /// # Errors /// - /// This function will return the first error that `write` returns. + /// This function will return the first error of + /// non-`ErrorKind::Interrupted` kind that `write` returns. /// /// # Examples /// @@ -1494,6 +1504,87 @@ pub struct Chain { done_first: bool, } +impl Chain { + /// Consumes the `Chain`, returning the wrapped readers. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// # use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.into_inner(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="41519")] + pub fn into_inner(self) -> (T, U) { + (self.first, self.second) + } + + /// Gets references to the underlying readers in this `Chain`. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// # use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_ref(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="41519")] + pub fn get_ref(&self) -> (&T, &U) { + (&self.first, &self.second) + } + + /// Gets mutable references to the underlying readers in this `Chain`. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying readers as doing so may corrupt the internal state of this + /// `Chain`. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// # use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut foo_file = File::open("foo.txt")?; + /// let mut bar_file = File::open("bar.txt")?; + /// + /// let mut chain = foo_file.chain(bar_file); + /// let (foo_file, bar_file) = chain.get_mut(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="41519")] + pub fn get_mut(&mut self) -> (&mut T, &mut U) { + (&mut self.first, &mut self.second) + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Chain { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -1606,6 +1697,64 @@ pub fn limit(&self) -> u64 { self.limit } pub fn into_inner(self) -> T { self.inner } + + /// Gets a reference to the underlying reader. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; + /// + /// let file = handle.get_ref(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="41519")] + pub fn get_ref(&self) -> &T { + &self.inner + } + + /// Gets a mutable reference to the underlying reader. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying reader as doing so may corrupt the internal limit of this + /// `Take`. + /// + /// # Examples + /// + /// ``` + /// #![feature(more_io_inner_methods)] + /// + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// handle.read(&mut buffer)?; + /// + /// let file = handle.get_mut(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "more_io_inner_methods", issue="41519")] + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 367779bb701..70225da5f33 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -248,7 +248,6 @@ #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_consts)] -#![feature(borrow_state)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] @@ -263,7 +262,6 @@ #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] -#![feature(float_extras)] #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] @@ -319,7 +317,6 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_push_all)] -#![feature(zero_one)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(stage0, feature(pub_restricted))] #![cfg_attr(test, feature(float_bits_conv))] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index bc315d54100..8def11295fd 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -177,6 +177,13 @@ pub fn local_addr(&self) -> io::Result { /// /// [`Shutdown`]: ../../std/net/enum.Shutdown.html /// + /// # Platform-specific behavior + /// + /// Calling this function multiple times may result in different behavior, + /// depending on the operating system. On Linux, the second call will + /// return `Ok(())`, but on macOS, it will return `ErrorKind::NotConnected`. + /// This may change in the future. + /// /// # Examples /// /// ```no_run diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 5f83d077a13..ff89887ac92 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -16,9 +16,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -pub use core::num::{Zero, One}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/os/android/raw.rs b/src/libstd/os/android/raw.rs index 5e473a933a6..60ad8fcc54c 100644 --- a/src/libstd/os/android/raw.rs +++ b/src/libstd/os/android/raw.rs @@ -165,3 +165,66 @@ pub struct stat { } } +#[cfg(target_arch = "x86_64")] +mod arch { + use os::raw::{c_uint, c_long, c_ulong}; + use os::unix::raw::{uid_t, gid_t}; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type dev_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type mode_t = u32; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blkcnt_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blksize_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type nlink_t = u32; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type off_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: ino_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: c_uint, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: uid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: gid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_ulong, + __unused: [c_long; 3], + } +} + diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 812b65b61e7..9d66430bc93 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -10,7 +10,7 @@ //! Cross-platform path manipulation. //! -//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`] +//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`] //! and [`str`]), for working with paths abstractly. These types are thin wrappers //! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly //! on strings according to the local platform's path syntax. @@ -1189,8 +1189,13 @@ pub fn pop(&mut self) -> bool { /// If [`self.file_name`] was [`None`], this is equivalent to pushing /// `file_name`. /// + /// Otherwise it is equivalent to calling [`pop`] and then pushing + /// `file_name`. The new path will be a sibling of the original path. + /// (That is, it will have the same parent.) + /// /// [`self.file_name`]: struct.PathBuf.html#method.file_name /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`pop`]: struct.PathBuf.html#method.pop /// /// # Examples /// @@ -1725,7 +1730,10 @@ pub fn parent(&self) -> Option<&Path> { }) } - /// Returns the final component of the `Path`, if it is a normal file. + /// Returns the final component of the `Path`, if there is one. + /// + /// If the path is a normal file, this is the file name. If it's the path of a directory, this + /// is the directory name. /// /// Returns [`None`] If the path terminates in `..`. /// @@ -1737,10 +1745,12 @@ pub fn parent(&self) -> Option<&Path> { /// use std::path::Path; /// use std::ffi::OsStr; /// - /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt").file_name()); + /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name()); + /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name()); /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name()); /// assert_eq!(None, Path::new("foo.txt/..").file_name()); + /// assert_eq!(None, Path::new("/").file_name()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_name(&self) -> Option<&OsStr> { @@ -1926,6 +1936,9 @@ fn _join(&self, path: &Path) -> PathBuf { /// /// let path = Path::new("/tmp/foo.txt"); /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt")); + /// + /// let path = Path::new("/tmp"); + /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_file_name>(&self, file_name: S) -> PathBuf { diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 3795c42f5ef..4ec9076de61 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -73,6 +73,15 @@ /// spawning process and can itself be constructed using a builder-style /// interface. /// +/// There is no implementation of [`Drop`] for child processes, +/// so if you do not ensure the `Child` has exited then it will continue to +/// run, even after the `Child` handle to the child process has gone out of +/// scope. +/// +/// Calling [`wait`](#method.wait) (or other functions that wrap around it) will make +/// the parent process wait until the child has actually exited before +/// continuing. +/// /// # Examples /// /// ```should_panic @@ -89,17 +98,6 @@ /// assert!(ecode.success()); /// ``` /// -/// # Note -/// -/// Take note that there is no implementation of [`Drop`] for child processes, -/// so if you do not ensure the `Child` has exited then it will continue to -/// run, even after the `Child` handle to the child process has gone out of -/// scope. -/// -/// Calling [`wait`][`wait`] (or other functions that wrap around it) will make -/// the parent process wait until the child has actually exited before -/// continuing. -/// /// [`Command`]: struct.Command.html /// [`Drop`]: ../../core/ops/trait.Drop.html /// [`wait`]: #method.wait diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 852675edc02..6c8839224f7 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -452,7 +452,7 @@ impl !Sync for SyncSender {} /// An error returned from the [`recv`] function on a [`Receiver`]. /// /// The [`recv`] operation can only fail if the sending half of a -/// [`channel`] (or [`sync_channel`]) is disconnected, implying that no further +/// [`channel`][`channel`] (or [`sync_channel`]) is disconnected, implying that no further /// messages will ever be received. /// /// [`recv`]: struct.Receiver.html#method.recv diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index a08cec38f73..a1ad94872de 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -157,7 +157,7 @@ pub fn add_duration(&self, other: &Duration) -> Instant { pub fn sub_duration(&self, other: &Duration) -> Instant { Instant { t: self.t.checked_sub(dur2intervals(other)) - .expect("overflow when adding duration to instant"), + .expect("overflow when subtracting duration from instant"), } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 131adfe47af..e5bb02fe082 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1852,6 +1852,7 @@ pub enum ItemKind { /// E.g. `impl Foo { .. }` or `impl Trait for Foo { .. }` Impl(Unsafety, ImplPolarity, + Defaultness, Generics, Option, // (optional) trait this impl implements P, // self diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 6f5f52ff1e9..82492d97627 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -147,6 +147,24 @@ pub fn value_str(&self) -> Option { self.meta_item().and_then(|meta_item| meta_item.value_str()) } + /// Returns a name and single literal value tuple of the MetaItem. + pub fn name_value_literal(&self) -> Option<(Name, &Lit)> { + self.meta_item().and_then( + |meta_item| meta_item.meta_item_list().and_then( + |meta_item_list| { + if meta_item_list.len() == 1 { + let nested_item = &meta_item_list[0]; + if nested_item.is_literal() { + Some((meta_item.name(), nested_item.literal().unwrap())) + } else { + None + } + } + else { + None + }})) + } + /// Returns a MetaItem if self is a MetaItem with Kind Word. pub fn word(&self) -> Option<&MetaItem> { self.meta_item().and_then(|meta_item| if meta_item.is_word() { @@ -931,6 +949,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec continue } + let mut recognised = false; if let Some(mi) = item.word() { let word = &*mi.name().as_str(); let hint = match word { @@ -941,20 +960,43 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec _ => match int_type_of_word(word) { Some(ity) => Some(ReprInt(ity)), None => { - // Not a word we recognize - span_err!(diagnostic, item.span, E0552, - "unrecognized representation hint"); None } } }; if let Some(h) = hint { + recognised = true; acc.push(h); } - } else { - span_err!(diagnostic, item.span, E0553, - "unrecognized enum representation hint"); + } else if let Some((name, value)) = item.name_value_literal() { + if name == "align" { + recognised = true; + let mut align_error = None; + if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node { + if align.is_power_of_two() { + // rustc::ty::layout::Align restricts align to <= 32768 + if align <= 32768 { + acc.push(ReprAlign(align as u16)); + } else { + align_error = Some("larger than 32768"); + } + } else { + align_error = Some("not a power of two"); + } + } else { + align_error = Some("not an unsuffixed integer"); + } + if let Some(align_error) = align_error { + span_err!(diagnostic, item.span, E0589, + "invalid `repr(align)` attribute: {}", align_error); + } + } + } + if !recognised { + // Not a word we recognize + span_err!(diagnostic, item.span, E0552, + "unrecognized representation hint"); } } } @@ -986,6 +1028,7 @@ pub enum ReprAttr { ReprExtern, ReprPacked, ReprSimd, + ReprAlign(u16), } #[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 2d59051ec4a..01d1277ea62 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -287,10 +287,10 @@ fn foo() {} E0550, // multiple deprecated attributes E0551, // incorrect meta item E0552, // unrecognized representation hint - E0553, // unrecognized enum representation hint E0554, // #[feature] may not be used on the [] release channel E0555, // malformed feature attribute, expected #![feature(...)] E0556, // malformed feature, expected just one word E0557, // feature has been removed E0584, // file for module `..` found at both .. and .. + E0589, // invalid `repr(align)` attribute } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 680bd7599ac..842398ea02b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -205,6 +205,8 @@ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { module.directory.pop(); self.cx.current_expansion.module = Rc::new(module); + let orig_mod_span = krate.module.inner; + let krate_item = Expansion::Items(SmallVector::one(P(ast::Item { attrs: krate.attrs, span: krate.span, @@ -214,11 +216,19 @@ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { vis: ast::Visibility::Public, }))); - match self.expand(krate_item).make_items().pop().unwrap().unwrap() { - ast::Item { attrs, node: ast::ItemKind::Mod(module), .. } => { + match self.expand(krate_item).make_items().pop().map(P::unwrap) { + Some(ast::Item { attrs, node: ast::ItemKind::Mod(module), .. }) => { krate.attrs = attrs; krate.module = module; }, + None => { + // Resolution failed so we return an empty expansion + krate.attrs = vec![]; + krate.module = ast::Mod { + inner: orig_mod_span, + items: vec![], + }; + }, _ => unreachable!(), }; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 175447e1112..b6a2c983fd4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -338,6 +338,9 @@ pub fn new() -> Features { // Allows the `catch {...}` expression (active, catch_expr, "1.17.0", Some(31436)), + // Allows `repr(align(u16))` struct attribute (RFC 1358) + (active, repr_align, "1.17.0", Some(33626)), + // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), @@ -1189,6 +1192,11 @@ fn visit_item(&mut self, i: &'a ast::Item) { and possibly buggy"); } + if item.check_name("align") { + gate_feature_post!(&self, repr_align, i.span, + "the struct `#[repr(align(u16))]` attribute \ + is experimental"); + } } } } @@ -1207,7 +1215,7 @@ fn visit_item(&mut self, i: &'a ast::Item) { and possibly buggy"); } - ast::ItemKind::Impl(_, polarity, _, _, _, _) => { + ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { match polarity { ast::ImplPolarity::Negative => { gate_feature_post!(&self, optin_builtin_traits, @@ -1217,6 +1225,12 @@ fn visit_item(&mut self, i: &'a ast::Item) { }, _ => {} } + + if let ast::Defaultness::Default = defaultness { + gate_feature_post!(&self, specialization, + i.span, + "specialization is unstable"); + } } _ => {} diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index f39399a62e8..58cf50cdc00 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -897,9 +897,16 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::DefaultImpl(unsafety, ref trait_ref) => { ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) } - ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => ItemKind::Impl( + ItemKind::Impl(unsafety, + polarity, + defaultness, + generics, + ifce, + ty, + impl_items) => ItemKind::Impl( unsafety, polarity, + defaultness, folder.fold_generics(generics), ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())), folder.fold_ty(ty), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0cdb09a842f..cba77335143 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -57,9 +57,11 @@ use symbol::{Symbol, keywords}; use util::ThinVec; +use std::cmp; use std::collections::HashSet; -use std::{cmp, mem, slice}; +use std::mem; use std::path::{self, Path, PathBuf}; +use std::slice; bitflags! { flags Restrictions: u8 { @@ -152,6 +154,7 @@ fn maybe_append(mut lhs: Vec, rhs: Option>) enum PrevTokenKind { DocComment, Comma, + Plus, Interpolated, Eof, Other, @@ -1061,6 +1064,7 @@ pub fn bump(&mut self) { self.prev_token_kind = match self.token { token::DocComment(..) => PrevTokenKind::DocComment, token::Comma => PrevTokenKind::Comma, + token::BinOp(token::Plus) => PrevTokenKind::Plus, token::Interpolated(..) => PrevTokenKind::Interpolated, token::Eof => PrevTokenKind::Eof, _ => PrevTokenKind::Other, @@ -1354,20 +1358,26 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P> { break; } } + let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; self.expect(&token::CloseDelim(token::Paren))?; if ts.len() == 1 && !last_comma { let ty = ts.into_iter().nth(0).unwrap().unwrap(); + let maybe_bounds = allow_plus && self.token == token::BinOp(token::Plus); match ty.node { - // Accept `(Trait1) + Trait2 + 'a` for backward compatibility (#39318). - TyKind::Path(None, ref path) - if allow_plus && self.token == token::BinOp(token::Plus) => { - self.bump(); // `+` - let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; - bounds.append(&mut self.parse_ty_param_bounds()?); - TyKind::TraitObject(bounds) + // `(TY_BOUND_NOPAREN) + BOUND + ...`. + TyKind::Path(None, ref path) if maybe_bounds => { + self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? } + TyKind::TraitObject(ref bounds) + if maybe_bounds && bounds.len() == 1 && !trailing_plus => { + let path = match bounds[0] { + TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(), + _ => self.bug("unexpected lifetime bound"), + }; + self.parse_remaining_bounds(Vec::new(), path, lo, true)? + } + // `(TYPE)` _ => TyKind::Paren(P(ty)) } } else { @@ -1418,11 +1428,8 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P> { // Just a type path or bound list (trait object type) starting with a trait. // `Type` // `Trait1 + Trait2 + 'a` - if allow_plus && self.eat(&token::BinOp(token::Plus)) { - let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; - bounds.append(&mut self.parse_ty_param_bounds()?); - TyKind::TraitObject(bounds) + if allow_plus && self.check(&token::BinOp(token::Plus)) { + self.parse_remaining_bounds(Vec::new(), path, lo, true)? } else { TyKind::Path(None, path) } @@ -1440,12 +1447,8 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P> { self.parse_ty_bare_fn(lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; - if allow_plus && self.eat(&token::BinOp(token::Plus)) { - bounds.append(&mut self.parse_ty_param_bounds()?) - } - TyKind::TraitObject(bounds) + let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus)); + self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(keywords::Impl) { // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). @@ -1468,6 +1471,17 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P> { Ok(P(ty)) } + fn parse_remaining_bounds(&mut self, lifetime_defs: Vec, path: ast::Path, + lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { + let poly_trait_ref = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)]; + if parse_plus { + self.bump(); // `+` + bounds.append(&mut self.parse_ty_param_bounds()?); + } + Ok(TyKind::TraitObject(bounds)) + } + fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { // Do not add `+` to expected tokens. if !allow_plus || self.token != token::BinOp(token::Plus) { @@ -4070,28 +4084,43 @@ fn warn_missing_semicolon(&self) { // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) - // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) + // TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) + // TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if self.check_lifetime() { - if let Some(question_span) = question { - self.span_err(question_span, - "`?` may only modify trait bounds, not lifetime bounds"); - } - bounds.push(RegionTyParamBound(self.expect_lifetime())); - } else if self.check_keyword(keywords::For) || self.check_path() { - let lo = self.span; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); - let modifier = if question.is_some() { - TraitBoundModifier::Maybe + let is_bound_start = self.check_path() || self.check_lifetime() || + self.check(&token::Question) || + self.check_keyword(keywords::For) || + self.check(&token::OpenDelim(token::Paren)); + if is_bound_start { + let has_parens = self.eat(&token::OpenDelim(token::Paren)); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if self.token.is_lifetime() { + if let Some(question_span) = question { + self.span_err(question_span, + "`?` may only modify trait bounds, not lifetime bounds"); + } + bounds.push(RegionTyParamBound(self.expect_lifetime())); } else { - TraitBoundModifier::None - }; - bounds.push(TraitTyParamBound(poly_trait, modifier)); + let lo = self.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let modifier = if question.is_some() { + TraitBoundModifier::Maybe + } else { + TraitBoundModifier::None + }; + bounds.push(TraitTyParamBound(poly_trait, modifier)); + } + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + if let Some(&RegionTyParamBound(..)) = bounds.last() { + self.span_err(self.prev_span, + "parenthesized lifetime bounds are not supported"); + } + } } else { break } @@ -4836,7 +4865,9 @@ fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> { /// impl Foo { ... } /// impl ToString for &'static T { ... } /// impl Send for .. {} - fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo> { + fn parse_item_impl(&mut self, + unsafety: ast::Unsafety, + defaultness: Defaultness) -> PResult<'a, ItemInfo> { let impl_span = self.span; // First, parse type parameters if necessary. @@ -4889,6 +4920,11 @@ fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo> allowed to have generics"); } + if let ast::Defaultness::Default = defaultness { + self.span_err(impl_span, "`default impl` is not allowed for \ + default trait implementations"); + } + self.expect(&token::OpenDelim(token::Brace))?; self.expect(&token::CloseDelim(token::Brace))?; Ok((keywords::Invalid.ident(), @@ -4917,7 +4953,7 @@ fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo> } Ok((keywords::Invalid.ident(), - ItemKind::Impl(unsafety, polarity, generics, opt_trait, ty, impl_items), + ItemKind::Impl(unsafety, polarity, defaultness, generics, opt_trait, ty, impl_items), Some(attrs))) } } @@ -5336,24 +5372,25 @@ fn submod_path(&mut self, } let mut err = self.diagnostic().struct_span_err(id_sp, "cannot declare a new module at this location"); - let this_module = match self.directory.path.file_name() { - Some(file_name) => file_name.to_str().unwrap().to_owned(), - None => self.root_module_name.as_ref().unwrap().clone(), - }; - err.span_note(id_sp, - &format!("maybe move this module `{0}` to its own directory \ - via `{0}{1}mod.rs`", - this_module, - path::MAIN_SEPARATOR)); + if id_sp != syntax_pos::DUMMY_SP { + let src_path = PathBuf::from(self.sess.codemap().span_to_filename(id_sp)); + if let Some(stem) = src_path.file_stem() { + let mut dest_path = src_path.clone(); + dest_path.set_file_name(stem); + dest_path.push("mod.rs"); + err.span_note(id_sp, + &format!("maybe move this module `{}` to its own \ + directory via `{}`", src_path.to_string_lossy(), + dest_path.to_string_lossy())); + } + } if paths.path_exists { err.span_note(id_sp, &format!("... or maybe `use` the module `{}` instead \ of possibly redeclaring it", paths.name)); - Err(err) - } else { - Err(err) } + Err(err) } else { paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) } @@ -5729,13 +5766,19 @@ fn parse_item_(&mut self, attrs: Vec, maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.check_keyword(keywords::Unsafe) && - self.look_ahead(1, |t| t.is_keyword(keywords::Impl)) + if (self.check_keyword(keywords::Unsafe) && + self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) || + (self.check_keyword(keywords::Default) && + self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) && + self.look_ahead(2, |t| t.is_keyword(keywords::Impl))) { // IMPL ITEM + let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Unsafe)?; self.expect_keyword(keywords::Impl)?; - let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?; + let (ident, + item_, + extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe, defaultness)?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, @@ -5829,9 +5872,16 @@ fn parse_item_(&mut self, attrs: Vec, maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.eat_keyword(keywords::Impl) { + if (self.check_keyword(keywords::Impl)) || + (self.check_keyword(keywords::Default) && + self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) + { // IMPL ITEM - let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?; + let defaultness = self.parse_defaultness()?; + self.expect_keyword(keywords::Impl)?; + let (ident, + item_, + extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal, defaultness)?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index be1d26f8fe4..a911c21ed98 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1317,12 +1317,14 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> { } ast::ItemKind::Impl(unsafety, polarity, + defaultness, ref generics, ref opt_trait, ref ty, ref impl_items) => { self.head("")?; self.print_visibility(&item.vis)?; + self.print_defaultness(defaultness)?; self.print_unsafety(unsafety)?; self.word_nbsp("impl")?; @@ -1477,6 +1479,13 @@ pub fn print_visibility(&mut self, vis: &ast::Visibility) -> io::Result<()> { } } + pub fn print_defaultness(&mut self, defatulness: ast::Defaultness) -> io::Result<()> { + if let ast::Defaultness::Default = defatulness { + try!(self.word_nbsp("default")); + } + Ok(()) + } + pub fn print_struct(&mut self, struct_def: &ast::VariantData, generics: &ast::Generics, @@ -1602,9 +1611,7 @@ pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> { self.hardbreak_if_not_bol()?; self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - if let ast::Defaultness::Default = ii.defaultness { - self.word_nbsp("default")?; - } + self.print_defaultness(ii.defaultness)?; match ii.node { ast::ImplItemKind::Const(ref ty, ref expr) => { self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis)?; diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index a74f59b004b..dc9b22c37e2 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -128,9 +128,9 @@ fn foo() { --> test.rs:2:10 | 2 | fn foo() { - | __________^ starting here... + | __________^ 3 | | } - | |_^ ...ending here: test + | |_^ test "#); } @@ -161,11 +161,11 @@ fn foo() { --> test.rs:2:10 | 2 | fn foo() { - | __________^ starting here... + | __________^ 3 | | 4 | | 5 | | } - | |___^ ...ending here: test + | |___^ test "#); } @@ -207,14 +207,14 @@ fn foo() { --> test.rs:3:3 | 3 | X0 Y0 - | ____^__- starting here... + | ____^__- | | ___| - | || starting here... + | || 4 | || X1 Y1 5 | || X2 Y2 - | ||____^__- ...ending here: `Y` is a good letter too + | ||____^__- `Y` is a good letter too | |____| - | ...ending here: `X` is a good letter + | `X` is a good letter "#); } @@ -256,13 +256,13 @@ fn foo() { --> test.rs:3:3 | 3 | X0 Y0 - | ____^__- starting here... + | ____^__- | | ___| - | || starting here... + | || 4 | || Y1 X1 - | ||____-__^ ...ending here: `X` is a good letter + | ||____-__^ `X` is a good letter | |_____| - | ...ending here: `Y` is a good letter too + | `Y` is a good letter too "#); } @@ -306,13 +306,13 @@ fn foo() { --> test.rs:3:6 | 3 | X0 Y0 Z0 - | ______^ starting here... + | ______^ 4 | | X1 Y1 Z1 - | |_________- starting here... + | |_________- 5 | || X2 Y2 Z2 - | ||____^ ...ending here: `X` is a good letter + | ||____^ `X` is a good letter 6 | | X3 Y3 Z3 - | |_____- ...ending here: `Y` is a good letter too + | |_____- `Y` is a good letter too "#); } @@ -366,16 +366,16 @@ fn foo() { --> test.rs:3:3 | 3 | X0 Y0 Z0 - | _____^__-__- starting here... + | _____^__-__- | | ____|__| - | || ___| starting here... - | ||| starting here... + | || ___| + | ||| 4 | ||| X1 Y1 Z1 5 | ||| X2 Y2 Z2 - | |||____^__-__- ...ending here: `Z` label + | |||____^__-__- `Z` label | ||____|__| - | |____| ...ending here: `Y` is a good letter too - | ...ending here: `X` is a good letter + | |____| `Y` is a good letter too + | `X` is a good letter "#); } @@ -430,17 +430,17 @@ fn foo() { --> test.rs:3:6 | 3 | X0 Y0 Z0 - | ______^ starting here... + | ______^ 4 | | X1 Y1 Z1 - | |____^_- starting here... + | |____^_- | ||____| - | | ...ending here: `X` is a good letter + | | `X` is a good letter 5 | | X2 Y2 Z2 - | |____-______- ...ending here: `Y` is a good letter too + | |____-______- `Y` is a good letter too | ____| - | | starting here... + | | 6 | | X3 Y3 Z3 - | |________- ...ending here: `Z` + | |________- `Z` "#); } @@ -458,7 +458,7 @@ fn foo() { vec![ SpanLabel { start: Position { - string: "Y0", + string: "X0", count: 1, }, end: Position { @@ -481,16 +481,15 @@ fn foo() { ], r#" error: foo - --> test.rs:3:6 + --> test.rs:3:3 | -3 | X0 Y0 Z0 - | ______^ starting here... +3 | / X0 Y0 Z0 4 | | X1 Y1 Z1 - | |____^ ...ending here: `X` is a good letter + | |____^ `X` is a good letter 5 | X2 Y2 Z2 - | ______- starting here... + | ______- 6 | | X3 Y3 Z3 - | |__________- ...ending here: `Y` is a good letter too + | |__________- `Y` is a good letter too "#); } @@ -534,14 +533,14 @@ fn foo() { --> test.rs:3:6 | 3 | X0 Y0 Z0 - | ______^ starting here... + | ______^ 4 | | X1 Y1 Z1 - | |____^____- starting here... + | |____^____- | ||____| - | | ...ending here: `X` is a good letter + | | `X` is a good letter 5 | | X2 Y2 Z2 6 | | X3 Y3 Z3 - | |___________- ...ending here: `Y` is a good letter too + | |___________- `Y` is a good letter too "#); } @@ -982,18 +981,18 @@ fn foo() { --> test.rs:3:6 | 3 | X0 Y0 Z0 - | ______^ starting here... + | ______^ 4 | | X1 Y1 Z1 - | |____^____- starting here... + | |____^____- | ||____| - | | ...ending here: `X` is a good letter + | | `X` is a good letter 5 | | 1 6 | | 2 7 | | 3 ... | 15 | | X2 Y2 Z2 16 | | X3 Y3 Z3 - | |___________- ...ending here: `Y` is a good letter too + | |___________- `Y` is a good letter too "#); } @@ -1047,21 +1046,21 @@ fn foo() { --> test.rs:3:6 | 3 | X0 Y0 Z0 - | ______^ starting here... + | ______^ 4 | | 1 5 | | 2 6 | | 3 7 | | X1 Y1 Z1 - | |_________- starting here... + | |_________- 8 | || 4 9 | || 5 10 | || 6 11 | || X2 Y2 Z2 - | ||__________- ...ending here: `Z` is a good letter too + | ||__________- `Z` is a good letter too ... | 15 | | 10 16 | | X3 Y3 Z3 - | |_______^ ...ending here: `Y` is a good letter + | |_______^ `Y` is a good letter "#); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index bae1c56db00..2e42c6986e6 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -266,7 +266,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::DefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) } - ItemKind::Impl(_, _, + ItemKind::Impl(_, _, _, ref type_parameters, ref opt_trait_reference, ref typ, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 1ff0fec1c96..be7883cad5f 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -658,6 +658,7 @@ fn create_derived_impl(&self, a, ast::ItemKind::Impl(unsafety, ast::ImplPolarity::Positive, + ast::Defaultness::Final, trait_generics, opt_trait_ref, self_type, @@ -773,7 +774,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> & for a in type_attrs { for r in &attr::find_repr_attrs(diagnostic, a) { repr_type_name = match *r { - attr::ReprPacked | attr::ReprSimd => continue, + attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) => continue, attr::ReprExtern => "i32", attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize", diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index 9b8099d55a0..be9aa6c5d40 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -39,5 +39,7 @@ fn main() { println!("cargo:rustc-link-lib=static-nobundle=pthread"); } else if target.contains("fuchsia") { println!("cargo:rustc-link-lib=unwind"); + } else if target.contains("haiku") { + println!("cargo:rustc-link-lib=gcc_s"); } } diff --git a/src/llvm b/src/llvm index 2e951c3ae35..878af191434 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 2e951c3ae354bcbd2e50b30798e232949a926b75 +Subproject commit 878af191434cd716eeb13c2be7a2b1e21abf2749 diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index 65c85697ce7..e8b92aab1da 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -22,7 +22,7 @@ // object (usually called `crtX.o), which then invokes initialization callbacks // of other runtime components (registered via yet another special image section). -#![feature(no_core, lang_items)] +#![feature(no_core, lang_items, optin_builtin_traits)] #![crate_type="rlib"] #![no_core] #![allow(non_camel_case_types)] @@ -31,9 +31,12 @@ trait Sized {} #[lang = "sync"] trait Sync {} +impl Sync for .. {} #[lang = "copy"] trait Copy {} -impl Sync for T {} +#[cfg_attr(not(stage0), lang = "freeze")] +trait Freeze {} +impl Freeze for .. {} #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] pub mod eh_frames { diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index c410a6b1349..b938f94cda2 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -147,6 +147,12 @@ extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) { #define SUBTARGET_SPARC #endif +#ifdef LLVM_COMPONENT_HEXAGON +#define SUBTARGET_HEXAGON SUBTARGET(Hexagon) +#else +#define SUBTARGET_HEXAGON +#endif + #define GEN_SUBTARGETS \ SUBTARGET_X86 \ SUBTARGET_ARM \ @@ -155,7 +161,8 @@ extern "C" void LLVMRustAddPass(LLVMPassManagerRef PMR, LLVMPassRef RustPass) { SUBTARGET_PPC \ SUBTARGET_SYSTEMZ \ SUBTARGET_MSP430 \ - SUBTARGET_SPARC + SUBTARGET_SPARC \ + SUBTARGET_HEXAGON #define SUBTARGET(x) \ namespace llvm { \ diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index c8732e27b82..52ebf449d60 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # 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. -2017-03-23 +2017-04-25 diff --git a/src/test/codegen/drop.rs b/src/test/codegen/drop.rs index a4bd5cf2c15..d7e2cb6d9a5 100644 --- a/src/test/codegen/drop.rs +++ b/src/test/codegen/drop.rs @@ -36,7 +36,7 @@ pub fn droppy() { // CHECK-NOT: call{{.*}}drop{{.*}}SomeUniqueName // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName -// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName +// CHECK: call{{.*}}drop{{.*}}SomeUniqueName // CHECK-NOT: {{(call|invoke).*}}drop{{.*}}SomeUniqueName // The next line checks for the } that ends the function definition // CHECK-LABEL: {{^[}]}} diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs index e0de64b26df..9fd600b32e6 100644 --- a/src/test/codegen/personality_lifetimes.rs +++ b/src/test/codegen/personality_lifetimes.rs @@ -37,5 +37,6 @@ pub fn test() { // CHECK: bitcast{{.*}}personalityslot // CHECK-NEXT: call void @llvm.lifetime.start might_unwind(); + let _t = S; might_unwind(); } diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs new file mode 100644 index 00000000000..99400bd147c --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/issue-41211.rs @@ -0,0 +1,23 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro)] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn emit_unchanged(_args: TokenStream, input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs new file mode 100644 index 00000000000..17237912be4 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/issue-41211.rs @@ -0,0 +1,22 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-41211.rs + +// FIXME: https://github.com/rust-lang/rust/issues/41430 +// This is a temporary regression test for the ICE reported in #41211 + +#![feature(proc_macro)] +#![emit_unchanged] +//~^ ERROR: cannot find attribute macro `emit_unchanged` in this scope +extern crate issue_41211; +use issue_41211::emit_unchanged; + +fn main() {} diff --git a/src/test/compile-fail/attr-usage-repr.rs b/src/test/compile-fail/attr-usage-repr.rs index b07d3e2f906..c0bfd3690c8 100644 --- a/src/test/compile-fail/attr-usage-repr.rs +++ b/src/test/compile-fail/attr-usage-repr.rs @@ -9,6 +9,7 @@ // except according to those terms. #![allow(dead_code)] +#![feature(attr_literals)] #![feature(repr_simd)] #[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union @@ -29,6 +30,9 @@ fn f() {} #[repr(C)] enum EExtern { A, B } +#[repr(align(8))] //~ ERROR: attribute should be applied to struct +enum EAlign { A, B } + #[repr(packed)] //~ ERROR: attribute should be applied to struct enum EPacked { A, B } diff --git a/src/test/compile-fail/coercion-slice.rs b/src/test/compile-fail/coercion-slice.rs index 6b468ff9662..7c5a4e0c3c6 100644 --- a/src/test/compile-fail/coercion-slice.rs +++ b/src/test/compile-fail/coercion-slice.rs @@ -14,6 +14,5 @@ fn main() { let _: &[i32] = [0]; //~^ ERROR mismatched types //~| expected type `&[i32]` - //~| found type `[{integer}; 1]` //~| expected &[i32], found array of 1 elements } diff --git a/src/test/compile-fail/conflicting-repr-hints.rs b/src/test/compile-fail/conflicting-repr-hints.rs index 9e0c0d845ca..01fa3ffbaa6 100644 --- a/src/test/compile-fail/conflicting-repr-hints.rs +++ b/src/test/compile-fail/conflicting-repr-hints.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] #![allow(dead_code)] +#![feature(attr_literals)] +#![feature(repr_align)] #[repr(C)] enum A { A } @@ -26,5 +27,7 @@ enum D { D } #[repr(C, packed)] struct E(i32); -#[rustc_error] -fn main() {} //~ ERROR compilation successful +#[repr(packed, align(8))] //~ ERROR conflicting packed and align representation hints +struct F(i32); + +fn main() {} diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs index ff83dd004a2..0745ac02d07 100644 --- a/src/test/compile-fail/const-call.rs +++ b/src/test/compile-fail/const-call.rs @@ -17,6 +17,4 @@ fn f(x: usize) -> usize { fn main() { let _ = [0; f(2)]; //~^ ERROR calls in constants are limited to constant functions - //~| ERROR constant evaluation error [E0080] - //~| non-constant path in constant expression } diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs index b40aa2a8e27..71cac3edbc1 100644 --- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs +++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs @@ -10,21 +10,22 @@ #![feature(const_fn)] +#[derive(PartialEq, Eq)] enum Cake { BlackForest, Marmor, } use Cake::*; -const BOO: (Cake, Cake) = (Marmor, BlackForest); +struct Pair(A, B); + +const BOO: Pair = Pair(Marmor, BlackForest); //~^ ERROR: constant evaluation error [E0080] -//~| unimplemented constant expression: enum variants +//~| unimplemented constant expression: tuple struct constructors const FOO: Cake = BOO.1; const fn foo() -> Cake { Marmor - //~^ ERROR: constant evaluation error [E0080] - //~| unimplemented constant expression: enum variants } const WORKS: Cake = Marmor; @@ -34,7 +35,7 @@ const fn foo() -> Cake { fn main() { match BlackForest { FOO => println!("hi"), //~ NOTE: for pattern here - GOO => println!("meh"), //~ NOTE: for pattern here + GOO => println!("meh"), WORKS => println!("möp"), _ => println!("bye"), } diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs index e5afccb9cf3..847a82c0826 100644 --- a/src/test/compile-fail/cross-borrow-trait.rs +++ b/src/test/compile-fail/cross-borrow-trait.rs @@ -17,7 +17,7 @@ impl Trait for Foo {} pub fn main() { let x: Box = Box::new(Foo); - let _y: &Trait = x; //~ ERROR mismatched types + let _y: &Trait = x; //~ ERROR E0308 //~| expected type `&Trait` //~| found type `std::boxed::Box` } diff --git a/src/test/compile-fail/feature-gate-repr_align.rs b/src/test/compile-fail/feature-gate-repr_align.rs new file mode 100644 index 00000000000..8e986e197f2 --- /dev/null +++ b/src/test/compile-fail/feature-gate-repr_align.rs @@ -0,0 +1,15 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(attr_literals)] + +#[repr(align(64))] +struct Foo(u64, u64); //~ error: the struct `#[repr(align(u16))]` attribute is experimental + +fn main() {} diff --git a/src/test/compile-fail/issue-11374.rs b/src/test/compile-fail/issue-11374.rs index f78786a2889..1e444a6bebf 100644 --- a/src/test/compile-fail/issue-11374.rs +++ b/src/test/compile-fail/issue-11374.rs @@ -33,5 +33,5 @@ pub fn for_stdin<'a>() -> Container<'a> { fn main() { let mut c = for_stdin(); let mut v = Vec::new(); - c.read_to(v); //~ ERROR mismatched types + c.read_to(v); //~ ERROR E0308 } diff --git a/src/test/compile-fail/issue-13058.rs b/src/test/compile-fail/issue-13058.rs index 408c6d411de..ed163444149 100644 --- a/src/test/compile-fail/issue-13058.rs +++ b/src/test/compile-fail/issue-13058.rs @@ -35,4 +35,5 @@ fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool fn main() { check((3, 5)); //~^ ERROR mismatched types +//~| HELP try with `&(3, 5)` } diff --git a/src/test/compile-fail/issue-28514.rs b/src/test/compile-fail/issue-28514.rs deleted file mode 100644 index 3488310b128..00000000000 --- a/src/test/compile-fail/issue-28514.rs +++ /dev/null @@ -1,47 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![deny(private_in_public)] - -pub use inner::C; - -mod inner { - trait A { - fn a(&self) { } - } - - pub trait B { - fn b(&self) { } - } - - pub trait C: A + B { //~ ERROR private trait `inner::A` in public interface - //~^ WARN will become a hard error - fn c(&self) { } - } - - impl A for i32 {} - impl B for i32 {} - impl C for i32 {} - -} - -fn main() { - // A is private - // B is pub, not reexported - // C : A + B is pub, reexported - - // 0.a(); // can't call - // 0.b(); // can't call - 0.c(); // ok - - C::a(&0); // can call - C::b(&0); // can call - C::c(&0); // ok -} diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs index 06e8406cbc0..b7f767f109c 100644 --- a/src/test/compile-fail/issue-39559.rs +++ b/src/test/compile-fail/issue-39559.rs @@ -28,10 +28,6 @@ pub struct Vector { fn main() { let array: [usize; Dim3::dim()] //~^ ERROR calls in constants are limited to constant functions - //~| ERROR constant evaluation error - //~| non-constant path in constant expression = [0; Dim3::dim()]; //~^ ERROR calls in constants are limited to constant functions - //~| ERROR constant evaluation error - //~| non-constant path in constant expression } diff --git a/src/test/compile-fail/issue-41394.rs b/src/test/compile-fail/issue-41394.rs new file mode 100644 index 00000000000..1fb3b7c4ee1 --- /dev/null +++ b/src/test/compile-fail/issue-41394.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Foo { + A = "" + 1 + //~^ ERROR binary operation `+` cannot be applied to type `&'static str` +} + +enum Bar { + A = Foo::A as isize +} + +fn main() {} diff --git a/src/test/compile-fail/no-method-suggested-traits.rs b/src/test/compile-fail/no-method-suggested-traits.rs index ea8796d38f9..a8d97d4674c 100644 --- a/src/test/compile-fail/no-method-suggested-traits.rs +++ b/src/test/compile-fail/no-method-suggested-traits.rs @@ -16,7 +16,7 @@ enum Bar { X } mod foo { - trait Bar { + pub trait Bar { fn method(&self) {} fn method2(&self) {} diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs deleted file mode 100644 index cadfec5a38d..00000000000 --- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs +++ /dev/null @@ -1,20 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Note: This test is checking that we forbid a coding pattern that -// Issue #5873 explicitly wants to allow. - -enum State { ST_NULL, ST_WHITESPACE } - -fn main() { - [State::ST_NULL; (State::ST_WHITESPACE as usize)]; - //~^ ERROR constant evaluation error - //~| unimplemented constant expression: enum variants -} diff --git a/src/test/compile-fail/object-safety-associated-consts.rs b/src/test/compile-fail/object-safety-associated-consts.rs new file mode 100644 index 00000000000..c442cd40836 --- /dev/null +++ b/src/test/compile-fail/object-safety-associated-consts.rs @@ -0,0 +1,28 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that we correctly prevent users from making trait objects +// from traits with associated consts. + +#![feature(associated_consts)] + +trait Bar { + const X: usize; +} + +fn make_bar(t: &T) -> &Bar { + //~^ ERROR E0038 + //~| NOTE the trait cannot contain associated consts like `X` + //~| NOTE the trait `Bar` cannot be made into an object + t +} + +fn main() { +} diff --git a/src/test/compile-fail/privacy/union-field-privacy-1.rs b/src/test/compile-fail/privacy/union-field-privacy-1.rs index bddcd391b20..807be619f6c 100644 --- a/src/test/compile-fail/privacy/union-field-privacy-1.rs +++ b/src/test/compile-fail/privacy/union-field-privacy-1.rs @@ -18,7 +18,7 @@ pub union U { } } -fn main() { +fn main() { unsafe { let u = m::U { a: 0 }; // OK let u = m::U { b: 0 }; // OK let u = m::U { c: 0 }; //~ ERROR field `c` of union `m::U` is private @@ -26,4 +26,4 @@ fn main() { let m::U { a } = u; // OK let m::U { b } = u; // OK let m::U { c } = u; //~ ERROR field `c` of union `m::U` is private -} +}} diff --git a/src/test/compile-fail/repr-align.rs b/src/test/compile-fail/repr-align.rs new file mode 100644 index 00000000000..eb0b27fe9c0 --- /dev/null +++ b/src/test/compile-fail/repr-align.rs @@ -0,0 +1,23 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![allow(dead_code)] +#![feature(attr_literals)] +#![feature(repr_align)] + +#[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer +struct A(i32); + +#[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two +struct B(i32); + +#[repr(align(65536))] //~ ERROR: invalid `repr(align)` attribute: larger than 32768 +struct C(i32); + +fn main() {} diff --git a/src/test/compile-fail/repr-packed-contains-align.rs b/src/test/compile-fail/repr-packed-contains-align.rs new file mode 100644 index 00000000000..c584dcf3e59 --- /dev/null +++ b/src/test/compile-fail/repr-packed-contains-align.rs @@ -0,0 +1,25 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(attr_literals)] +#![feature(repr_align)] +#![allow(dead_code)] + +#[repr(align(16))] +struct A(i32); + +struct B(A); + +#[repr(packed)] +struct C(A); //~ ERROR: packed struct cannot transitively contain a `[repr(align)]` struct + +#[repr(packed)] +struct D(B); //~ ERROR: packed struct cannot transitively contain a `[repr(align)]` struct + +fn main() {} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs new file mode 100644 index 00000000000..ad55f44255b --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs @@ -0,0 +1,46 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +// Make sure we can't project defaulted associated types + +trait Foo { + type Assoc; +} + +default impl Foo for T { + type Assoc = (); +} + +impl Foo for u8 { + type Assoc = String; +} + +fn generic() -> ::Assoc { + // `T` could be some downstream crate type that specializes (or, + // for that matter, `u8`). + + () //~ ERROR mismatched types +} + +fn monomorphic() -> () { + // Even though we know that `()` is not specialized in a + // downstream crate, typeck refuses to project here. + + generic::<()>() //~ ERROR mismatched types +} + +fn main() { + // No error here, we CAN project from `u8`, as there is no `default` + // in that impl. + let s: String = generic::(); + println!("{}", s); // bad news if this all compiles +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs new file mode 100644 index 00000000000..7353f7ac8c5 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs @@ -0,0 +1,45 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// It should not be possible to use the concrete value of a defaulted +// associated type in the impl defining it -- otherwise, what happens +// if it's overridden? + +#![feature(specialization)] + +trait Example { + type Output; + fn generate(self) -> Self::Output; +} + +default impl Example for T { + type Output = Box; + fn generate(self) -> Self::Output { + Box::new(self) //~ ERROR mismatched types + } +} + +impl Example for bool { + type Output = bool; + fn generate(self) -> bool { self } +} + +fn trouble(t: T) -> Box { + Example::generate(t) //~ ERROR mismatched types +} + +fn weaponize() -> bool { + let b: Box = trouble(true); + *b +} + +fn main() { + weaponize(); +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs new file mode 100644 index 00000000000..5bab4c5438e --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that specialization must be ungated to use the `default` keyword + +trait Foo { + fn foo(&self); +} + +default impl Foo for T { //~ ERROR specialization is unstable + fn foo(&self) {} +} + +fn main() {} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs new file mode 100644 index 00000000000..c1746d765dd --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] +#![feature(optin_builtin_traits)] + +trait Foo {} + +default impl Foo for .. {} +//~^ ERROR `default impl` is not allowed for default trait implementations + +fn main() {} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs new file mode 100644 index 00000000000..2874108157d --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs @@ -0,0 +1,95 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +// Check a number of scenarios in which one impl tries to override another, +// without correctly using `default`. + +//////////////////////////////////////////////////////////////////////////////// +// Test 1: one layer of specialization, multiple methods, missing `default` +//////////////////////////////////////////////////////////////////////////////// + +trait Foo { + fn foo(&self); + fn bar(&self); +} + +impl Foo for T { + fn foo(&self) {} + fn bar(&self) {} +} + +impl Foo for u8 {} +impl Foo for u16 { + fn foo(&self) {} //~ ERROR E0520 +} +impl Foo for u32 { + fn bar(&self) {} //~ ERROR E0520 +} + +//////////////////////////////////////////////////////////////////////////////// +// Test 2: one layer of specialization, missing `default` on associated type +//////////////////////////////////////////////////////////////////////////////// + +trait Bar { + type T; +} + +impl Bar for T { + type T = u8; +} + +impl Bar for u8 { + type T = (); //~ ERROR E0520 +} + +//////////////////////////////////////////////////////////////////////////////// +// Test 3a: multiple layers of specialization, missing interior `default` +//////////////////////////////////////////////////////////////////////////////// + +trait Baz { + fn baz(&self); +} + +default impl Baz for T { + fn baz(&self) {} +} + +impl Baz for T { + fn baz(&self) {} +} + +impl Baz for i32 { + fn baz(&self) {} //~ ERROR E0520 +} + +//////////////////////////////////////////////////////////////////////////////// +// Test 3b: multiple layers of specialization, missing interior `default`, +// redundant `default` in bottom layer. +//////////////////////////////////////////////////////////////////////////////// + +trait Redundant { + fn redundant(&self); +} + +default impl Redundant for T { + fn redundant(&self) {} +} + +impl Redundant for T { + fn redundant(&self) {} +} + +default impl Redundant for i32 { + fn redundant(&self) {} //~ ERROR E0520 +} + +fn main() {} diff --git a/src/test/compile-fail/trait-item-privacy.rs b/src/test/compile-fail/trait-item-privacy.rs new file mode 100644 index 00000000000..721d7583230 --- /dev/null +++ b/src/test/compile-fail/trait-item-privacy.rs @@ -0,0 +1,135 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_consts)] +#![feature(associated_type_defaults)] + +struct S; + +mod method { + trait A { + fn a(&self) { } + } + + pub trait B { + fn b(&self) { } + } + + pub trait C: A + B { + fn c(&self) { } + } + + impl A for ::S {} + impl B for ::S {} + impl C for ::S {} +} + +mod assoc_const { + trait A { + const A: u8 = 0; + } + + pub trait B { + const B: u8 = 0; + } + + pub trait C: A + B { + const C: u8 = 0; + } + + impl A for ::S {} + impl B for ::S {} + impl C for ::S {} +} + +mod assoc_ty { + trait A { + type A = u8; + } + + pub trait B { + type B = u8; + } + + pub trait C: A + B { + type C = u8; + } + + impl A for ::S {} + impl B for ::S {} + impl C for ::S {} +} + +fn check_method() { + // A is private + // B is pub, not in scope + // C : A + B is pub, in scope + use method::C; + + // Methods, method call + // a, b, c are resolved as trait items, their traits need to be in scope + S.a(); //~ ERROR no method named `a` found for type `S` in the current scope + S.b(); //~ ERROR no method named `b` found for type `S` in the current scope + S.c(); // OK + // a, b, c are resolved as inherent items, their traits don't need to be in scope + let c = &S as &C; + c.a(); //~ ERROR method `a` is private + c.b(); // OK + c.c(); // OK + + // Methods, UFCS + // a, b, c are resolved as trait items, their traits need to be in scope + S::a(&S); //~ ERROR no associated item named `a` found for type `S` in the current scope + S::b(&S); //~ ERROR no associated item named `b` found for type `S` in the current scope + S::c(&S); // OK + // a, b, c are resolved as inherent items, their traits don't need to be in scope + C::a(&S); //~ ERROR method `a` is private + C::b(&S); // OK + C::c(&S); // OK +} + +fn check_assoc_const() { + // A is private + // B is pub, not in scope + // C : A + B is pub, in scope + use assoc_const::C; + + // Associated constants + // A, B, C are resolved as trait items, their traits need to be in scope + S::A; //~ ERROR no associated item named `A` found for type `S` in the current scope + S::B; //~ ERROR no associated item named `B` found for type `S` in the current scope + S::C; // OK + // A, B, C are resolved as inherent items, their traits don't need to be in scope + C::A; //~ ERROR associated constant `A` is private + //~^ ERROR the trait `assoc_const::C` cannot be made into an object + //~| ERROR the trait bound `assoc_const::C: assoc_const::A` is not satisfied + C::B; // ERROR the trait `assoc_const::C` cannot be made into an object + //~^ ERROR the trait bound `assoc_const::C: assoc_const::B` is not satisfied + C::C; // OK +} + +fn check_assoc_ty() { + // A is private + // B is pub, not in scope + // C : A + B is pub, in scope + use assoc_ty::C; + + // Associated types + // A, B, C are resolved as trait items, their traits need to be in scope, not implemented yet + let _: S::A; //~ ERROR ambiguous associated type + let _: S::B; //~ ERROR ambiguous associated type + let _: S::C; //~ ERROR ambiguous associated type + // A, B, C are resolved as inherent items, their traits don't need to be in scope + let _: T::A; //~ ERROR associated type `A` is private + let _: T::B; // OK + let _: T::C; // OK +} + +fn main() {} diff --git a/src/test/compile-fail/trait-not-accessible.rs b/src/test/compile-fail/trait-not-accessible.rs deleted file mode 100644 index 5feef0a24eb..00000000000 --- a/src/test/compile-fail/trait-not-accessible.rs +++ /dev/null @@ -1,28 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -mod m { - trait Priv { - fn f(&self) {} - } - impl Priv for super::S {} - pub trait Pub: Priv {} -} - -struct S; -impl m::Pub for S {} - -fn g(arg: T) { - arg.f(); //~ ERROR: source trait `m::Priv` is private -} - -fn main() { - g(S); -} diff --git a/src/test/parse-fail/bound-single-question-mark.rs b/src/test/parse-fail/bound-single-question-mark.rs new file mode 100644 index 00000000000..9dde5268c08 --- /dev/null +++ b/src/test/parse-fail/bound-single-question-mark.rs @@ -0,0 +1,13 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn f() {} //~ ERROR expected identifier, found `>` diff --git a/src/test/parse-fail/trait-object-bad-parens.rs b/src/test/parse-fail/trait-object-bad-parens.rs new file mode 100644 index 00000000000..a44c0c3f32f --- /dev/null +++ b/src/test/parse-fail/trait-object-bad-parens.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +fn main() { + let _: Box<((Copy)) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `((Copy))` + let _: Box<(Copy + Copy) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy + Copy)` + let _: Box<(Copy +) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy)` +} diff --git a/src/test/parse-fail/trait-object-lifetime-parens.rs b/src/test/parse-fail/trait-object-lifetime-parens.rs new file mode 100644 index 00000000000..6be62d966eb --- /dev/null +++ b/src/test/parse-fail/trait-object-lifetime-parens.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +fn f() {} //~ ERROR parenthesized lifetime bounds are not supported + +fn main() { + let _: Box; //~ ERROR parenthesized lifetime bounds are not supported + let _: Box<('a) + Copy>; //~ ERROR expected type, found `'a` +} diff --git a/src/test/parse-fail/trait-object-trait-parens.rs b/src/test/parse-fail/trait-object-trait-parens.rs new file mode 100644 index 00000000000..dc44f4f3fb1 --- /dev/null +++ b/src/test/parse-fail/trait-object-trait-parens.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn f Trait<'a>)>() {} + +fn main() { + let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; + let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; + let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; +} + +FAIL //~ ERROR diff --git a/src/test/run-make/sanitizer-address/Makefile b/src/test/run-make/sanitizer-address/Makefile index 5931145f3a4..61b25df1451 100644 --- a/src/test/run-make/sanitizer-address/Makefile +++ b/src/test/run-make/sanitizer-address/Makefile @@ -1,11 +1,19 @@ -include ../tools.mk -# NOTE the address sanitizer only supports x86_64 linux -ifdef SANITIZER_SUPPORT -all: - $(RUSTC) -g -Z sanitizer=address -Z print-link-args overflow.rs | grep -q librustc_asan - $(TMPDIR)/overflow 2>&1 | grep -q stack-buffer-overflow +# NOTE the address sanitizer only supports x86_64 linux and macOS + +ifeq ($(TARGET),x86_64-apple-darwin) +ASAN_SUPPORT=$(SANITIZER_SUPPORT) +EXTRA_RUSTFLAG=-C rpath else -all: +ifeq ($(TARGET),x86_64-unknown-linux-gnu) +ASAN_SUPPORT=$(SANITIZER_SUPPORT) +EXTRA_RUSTFLAG= +endif +endif +all: +ifeq ($(ASAN_SUPPORT),1) + $(RUSTC) -g -Z sanitizer=address -Z print-link-args $(EXTRA_RUSTFLAG) overflow.rs | grep -q librustc_asan + $(TMPDIR)/overflow 2>&1 | grep -q stack-buffer-overflow endif diff --git a/src/test/run-make/sanitizer-invalid-target/Makefile b/src/test/run-make/sanitizer-invalid-target/Makefile index 6a1ce8bab2f..82e32f09952 100644 --- a/src/test/run-make/sanitizer-invalid-target/Makefile +++ b/src/test/run-make/sanitizer-invalid-target/Makefile @@ -1,4 +1,4 @@ -include ../tools.mk all: - $(RUSTC) -Z sanitizer=leak --target i686-unknown-linux-gnu hello.rs 2>&1 | grep -q 'Sanitizers only work with the `x86_64-unknown-linux-gnu` target' + $(RUSTC) -Z sanitizer=leak --target i686-unknown-linux-gnu hello.rs 2>&1 | grep -q 'LeakSanitizer only works with the `x86_64-unknown-linux-gnu` target' diff --git a/src/test/run-make/sanitizer-leak/Makefile b/src/test/run-make/sanitizer-leak/Makefile index f02d948fdc8..b18dd1d45ed 100644 --- a/src/test/run-make/sanitizer-leak/Makefile +++ b/src/test/run-make/sanitizer-leak/Makefile @@ -1,10 +1,10 @@ -include ../tools.mk -ifdef SANITIZER_SUPPORT all: +ifeq ($(TARGET),x86_64-unknown-linux-gnu) +ifdef SANITIZER_SUPPORT $(RUSTC) -C opt-level=1 -g -Z sanitizer=leak -Z print-link-args leak.rs | grep -q librustc_lsan $(TMPDIR)/leak 2>&1 | grep -q 'detected memory leaks' -else -all: - endif +endif + diff --git a/src/test/run-make/sanitizer-memory/Makefile b/src/test/run-make/sanitizer-memory/Makefile index 08682e5975e..7502ef0e7a7 100644 --- a/src/test/run-make/sanitizer-memory/Makefile +++ b/src/test/run-make/sanitizer-memory/Makefile @@ -1,10 +1,10 @@ -include ../tools.mk -ifdef SANITIZER_SUPPORT all: +ifeq ($(TARGET),x86_64-unknown-linux-gnu) +ifdef SANITIZER_SUPPORT $(RUSTC) -g -Z sanitizer=memory -Z print-link-args uninit.rs | grep -q librustc_msan $(TMPDIR)/uninit 2>&1 | grep -q use-of-uninitialized-value -else -all: - endif +endif + diff --git a/src/test/run-make/simd-ffi/simd.rs b/src/test/run-make/simd-ffi/simd.rs index 49fec6f3619..8ab8f471575 100644 --- a/src/test/run-make/simd-ffi/simd.rs +++ b/src/test/run-make/simd-ffi/simd.rs @@ -12,7 +12,7 @@ #![crate_type = "lib"] // we can compile to a variety of platforms, because we don't need // cross-compiled standard libraries. -#![feature(no_core)] +#![feature(no_core, optin_builtin_traits)] #![no_core] #![feature(repr_simd, simd_ffi, link_llvm_intrinsics, lang_items)] @@ -78,3 +78,7 @@ pub trait Copy { } pub mod marker { pub use Copy; } + +#[lang = "freeze"] +trait Freeze {} +impl Freeze for .. {} diff --git a/src/test/run-make/sysroot-crates-are-unstable/Makefile b/src/test/run-make/sysroot-crates-are-unstable/Makefile index 2bdc76e01db..4b7052f9b94 100644 --- a/src/test/run-make/sysroot-crates-are-unstable/Makefile +++ b/src/test/run-make/sysroot-crates-are-unstable/Makefile @@ -1,7 +1,7 @@ -include ../tools.mk -# This is a whitelist of crates which are stable, we don't check for the -# instability of these crates as they're all stable! +# This is a whitelist of files which are stable crates or simply are not crates, +# we don't check for the instability of these crates as they're all stable! STABLE_CRATES := \ std \ core \ @@ -9,7 +9,8 @@ STABLE_CRATES := \ rsbegin.o \ rsend.o \ dllcrt2.o \ - crt2.o + crt2.o \ + clang_rt.%_dynamic.dylib # Generate a list of all crates in the sysroot. To do this we list all files in # rustc's sysroot, look at the filename, strip everything after the `-`, and diff --git a/src/test/run-make/target-specs/foo.rs b/src/test/run-make/target-specs/foo.rs index 15b56977232..af24c3b460b 100644 --- a/src/test/run-make/target-specs/foo.rs +++ b/src/test/run-make/target-specs/foo.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(lang_items, no_core)] +#![feature(lang_items, no_core, optin_builtin_traits)] #![no_core] #[lang="copy"] @@ -17,6 +17,10 @@ trait Copy { } #[lang="sized"] trait Sized { } +#[lang = "freeze"] +trait Freeze {} +impl Freeze for .. {} + #[lang="start"] fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs new file mode 100644 index 00000000000..0b9a3594502 --- /dev/null +++ b/src/test/run-pass/align-struct.rs @@ -0,0 +1,196 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(attr_literals)] +#![feature(repr_align)] + +use std::mem; + +// Raising alignment +#[repr(align(16))] +struct Align16(i32); + +// Lowering has no effect +#[repr(align(1))] +struct Align1(i32); + +// Multiple attributes take the max +#[repr(align(4))] +#[repr(align(16))] +#[repr(align(8))] +struct AlignMany(i32); + +// Raising alignment may not alter size. +#[repr(align(8))] +#[allow(dead_code)] +struct Align8Many { + a: i32, + b: i32, + c: i32, + d: u8, +} + +enum Enum { + #[allow(dead_code)] + A(i32), + B(Align16) +} + +// Nested alignment - use `#[repr(C)]` to suppress field reordering for sizeof test +#[repr(C)] +struct Nested { + a: i32, + b: i32, + c: Align16, + d: i8, +} + +#[repr(packed)] +struct Packed(i32); + +#[repr(align(16))] +struct AlignContainsPacked { + a: Packed, + b: Packed, +} + +impl Align16 { + // return aligned type + pub fn new(i: i32) -> Align16 { + Align16(i) + } + // pass aligned type + pub fn consume(a: Align16) -> i32 { + a.0 + } +} + +const CONST_ALIGN16: Align16 = Align16(7); +static STATIC_ALIGN16: Align16 = Align16(8); + +// Check the actual address is aligned +fn is_aligned_to(p: &T, align: usize) -> bool { + let addr = p as *const T as usize; + (addr & (align - 1)) == 0 +} + +pub fn main() { + // check alignment and size by type and value + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 16); + + let a = Align16(7); + assert_eq!(a.0, 7); + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::size_of_val(&a), 16); + + assert!(is_aligned_to(&a, 16)); + + // lowering should have no effect + assert_eq!(mem::align_of::(), 4); + assert_eq!(mem::size_of::(), 4); + let a = Align1(7); + assert_eq!(a.0, 7); + assert_eq!(mem::align_of_val(&a), 4); + assert_eq!(mem::size_of_val(&a), 4); + assert!(is_aligned_to(&a, 4)); + + // when multiple attributes are specified the max should be used + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 16); + let a = AlignMany(7); + assert_eq!(a.0, 7); + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::size_of_val(&a), 16); + assert!(is_aligned_to(&a, 16)); + + // raising alignment should not reduce size + assert_eq!(mem::align_of::(), 8); + assert_eq!(mem::size_of::(), 16); + let a = Align8Many { a: 1, b: 2, c: 3, d: 4 }; + assert_eq!(a.a, 1); + assert_eq!(mem::align_of_val(&a), 8); + assert_eq!(mem::size_of_val(&a), 16); + assert!(is_aligned_to(&a, 8)); + + // return type + let a = Align16::new(1); + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::size_of_val(&a), 16); + assert_eq!(a.0, 1); + assert!(is_aligned_to(&a, 16)); + assert_eq!(Align16::consume(a), 1); + + // check const alignment, size and value + assert_eq!(mem::align_of_val(&CONST_ALIGN16), 16); + assert_eq!(mem::size_of_val(&CONST_ALIGN16), 16); + assert_eq!(CONST_ALIGN16.0, 7); + assert!(is_aligned_to(&CONST_ALIGN16, 16)); + + // check global static alignment, size and value + assert_eq!(mem::align_of_val(&STATIC_ALIGN16), 16); + assert_eq!(mem::size_of_val(&STATIC_ALIGN16), 16); + assert_eq!(STATIC_ALIGN16.0, 8); + assert!(is_aligned_to(&STATIC_ALIGN16, 16)); + + // Note that the size of Nested may change if struct field re-ordering is enabled + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 48); + let a = Nested{ a: 1, b: 2, c: Align16(3), d: 4}; + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::align_of_val(&a.b), 4); + assert_eq!(mem::align_of_val(&a.c), 16); + assert_eq!(mem::size_of_val(&a), 48); + assert!(is_aligned_to(&a, 16)); + // check the correct fields are indexed + assert_eq!(a.a, 1); + assert_eq!(a.b, 2); + assert_eq!(a.c.0, 3); + assert_eq!(a.d, 4); + + // enum should be aligned to max alignment + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::align_of_val(&Enum::B(Align16(0))), 16); + let e = Enum::B(Align16(15)); + match e { + Enum::B(ref a) => { + assert_eq!(a.0, 15); + assert_eq!(mem::align_of_val(a), 16); + assert_eq!(mem::size_of_val(a), 16); + }, + _ => () + } + assert!(is_aligned_to(&e, 16)); + + // arrays of aligned elements should also be aligned + assert_eq!(mem::align_of::<[Align16;2]>(), 16); + assert_eq!(mem::size_of::<[Align16;2]>(), 32); + + let a = [Align16(0), Align16(1)]; + assert_eq!(mem::align_of_val(&a[0]), 16); + assert_eq!(mem::align_of_val(&a[1]), 16); + assert!(is_aligned_to(&a, 16)); + + // check heap value is aligned + assert_eq!(mem::align_of_val(Box::new(Align16(0)).as_ref()), 16); + + // check heap array is aligned + let a = vec!(Align16(0), Align16(1)); + assert_eq!(mem::align_of_val(&a[0]), 16); + assert_eq!(mem::align_of_val(&a[1]), 16); + + assert_eq!(mem::align_of::(), 16); + assert_eq!(mem::size_of::(), 16); + let a = AlignContainsPacked { a: Packed(1), b: Packed(2) }; + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::align_of_val(&a.a), 1); + assert_eq!(mem::align_of_val(&a.b), 1); + assert_eq!(mem::size_of_val(&a), 16); + assert!(is_aligned_to(&a, 16)); +} diff --git a/src/test/run-pass/auxiliary/issue-41394.rs b/src/test/run-pass/auxiliary/issue-41394.rs new file mode 100644 index 00000000000..f06b81279ac --- /dev/null +++ b/src/test/run-pass/auxiliary/issue-41394.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] + +#[repr(u32)] +pub enum Foo { + Foo = Private::Variant as u32 +} + +#[repr(u8)] +enum Private { + Variant = 42 +} + +#[inline(always)] +pub fn foo() -> Foo { + Foo::Foo +} diff --git a/src/test/run-pass/const-pattern-variant.rs b/src/test/run-pass/const-pattern-variant.rs new file mode 100644 index 00000000000..104ab6e19db --- /dev/null +++ b/src/test/run-pass/const-pattern-variant.rs @@ -0,0 +1,38 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(const_fn)] + +#[derive(PartialEq, Eq)] +enum Cake { + BlackForest, + Marmor, +} +use Cake::*; + +const BOO: (Cake, Cake) = (Marmor, BlackForest); +const FOO: Cake = BOO.1; + +const fn foo() -> Cake { + Marmor +} + +const WORKS: Cake = Marmor; + +const GOO: Cake = foo(); + +fn main() { + match BlackForest { + FOO => println!("hi"), + GOO => println!("meh"), + WORKS => println!("möp"), + _ => println!("bye"), + } +} diff --git a/src/test/run-pass/issue-23898.rs b/src/test/run-pass/issue-23898.rs new file mode 100644 index 00000000000..3f5546ce83d --- /dev/null +++ b/src/test/run-pass/issue-23898.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Note: This test was used to demonstrate #5873 (now #23898). + +enum State { ST_NULL, ST_WHITESPACE } + +fn main() { + [State::ST_NULL; (State::ST_WHITESPACE as usize)]; +} diff --git a/src/test/run-pass/issue-29663.rs b/src/test/run-pass/issue-29663.rs index 9a77be049fe..cf925662fc3 100644 --- a/src/test/run-pass/issue-29663.rs +++ b/src/test/run-pass/issue-29663.rs @@ -10,6 +10,8 @@ // write_volatile causes an LLVM assert with composite types +// ignore-emscripten See #41299: probably a bad optimization + #![feature(volatile)] use std::ptr::{read_volatile, write_volatile}; diff --git a/src/test/run-pass/issue-33287.rs b/src/test/run-pass/issue-33287.rs new file mode 100644 index 00000000000..a2021e0e527 --- /dev/null +++ b/src/test/run-pass/issue-33287.rs @@ -0,0 +1,18 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const A: [u32; 1] = [0]; + +fn test() { + let range = A[1]..; +} + +fn main() { } + diff --git a/src/test/run-pass/issue-41394.rs b/src/test/run-pass/issue-41394.rs new file mode 100644 index 00000000000..798905599a8 --- /dev/null +++ b/src/test/run-pass/issue-41394.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-41394.rs + +extern crate issue_41394 as lib; + +fn main() { + assert_eq!(lib::foo() as u32, 42); +} diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs index 5148be5af83..17ea5b9a794 100644 --- a/src/test/run-pass/issue-8460.rs +++ b/src/test/run-pass/issue-8460.rs @@ -9,11 +9,22 @@ // except according to those terms. // ignore-emscripten no threads support -#![feature(rustc_attrs, zero_one)] +#![feature(rustc_attrs)] -use std::num::Zero; use std::thread; +trait Int { + fn zero() -> Self; + fn one() -> Self; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl Int for $t { + fn zero() -> $t { 0 } + fn one() -> $t { 1 } + })*) +} +doit! { i8 i16 i32 i64 isize } + macro_rules! check { ($($e:expr),*) => { $(assert!(thread::spawn({ @@ -24,21 +35,21 @@ macro_rules! check { fn main() { check![ - isize::min_value() / -1, - i8::min_value() / -1, - i16::min_value() / -1, - i32::min_value() / -1, - i64::min_value() / -1, + isize::min_value() / -isize::one(), + i8::min_value() / -i8::one(), + i16::min_value() / -i16::one(), + i32::min_value() / -i32::one(), + i64::min_value() / -i64::one(), 1isize / isize::zero(), 1i8 / i8::zero(), 1i16 / i16::zero(), 1i32 / i32::zero(), 1i64 / i64::zero(), - isize::min_value() % -1, - i8::min_value() % -1, - i16::min_value() % -1, - i32::min_value() % -1, - i64::min_value() % -1, + isize::min_value() % -isize::one(), + i8::min_value() % -i8::one(), + i16::min_value() % -i16::one(), + i32::min_value() % -i32::one(), + i64::min_value() % -i64::one(), 1isize % isize::zero(), 1i8 % i8::zero(), 1i16 % i16::zero(), diff --git a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs index 1c273fcba02..ebbb00a4a9f 100644 --- a/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs +++ b/src/test/run-pass/panic-runtime/abort-link-to-unwinding-crates.rs @@ -27,7 +27,17 @@ fn main() { exit_success_if_unwind::bar(do_panic); } } - let s = Command::new(env::args_os().next().unwrap()).arg("foo").status(); + + let mut cmd = Command::new(env::args_os().next().unwrap()); + cmd.arg("foo"); + + + // ARMv6 hanges while printing the backtrace, see #41004 + if cfg!(target_arch = "arm") && cfg!(target_env = "gnu") { + cmd.env("RUST_BACKTRACE", "0"); + } + + let s = cmd.status(); assert!(s.unwrap().code() != Some(0)); } diff --git a/src/test/run-pass/panic-runtime/abort.rs b/src/test/run-pass/panic-runtime/abort.rs index be38f6ea364..3ba3bd61c2e 100644 --- a/src/test/run-pass/panic-runtime/abort.rs +++ b/src/test/run-pass/panic-runtime/abort.rs @@ -35,6 +35,15 @@ fn main() { panic!("try to catch me"); } } - let s = Command::new(env::args_os().next().unwrap()).arg("foo").status(); + + let mut cmd = Command::new(env::args_os().next().unwrap()); + cmd.arg("foo"); + + // ARMv6 hanges while printing the backtrace, see #41004 + if cfg!(target_arch = "arm") && cfg!(target_env = "gnu") { + cmd.env("RUST_BACKTRACE", "0"); + } + + let s = cmd.status(); assert!(s.unwrap().code() != Some(0)); } diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs new file mode 100644 index 00000000000..dd060f8ef40 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs @@ -0,0 +1,53 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +// Common code used for tests that model the Fn/FnMut/FnOnce hierarchy. + +pub trait Go { + fn go(&self, arg: isize); +} + +pub fn go(this: &G, arg: isize) { + this.go(arg) +} + +pub trait GoMut { + fn go_mut(&mut self, arg: isize); +} + +pub fn go_mut(this: &mut G, arg: isize) { + this.go_mut(arg) +} + +pub trait GoOnce { + fn go_once(self, arg: isize); +} + +pub fn go_once(this: G, arg: isize) { + this.go_once(arg) +} + +default impl GoMut for G + where G : Go +{ + fn go_mut(&mut self, arg: isize) { + go(&*self, arg) + } +} + +default impl GoOnce for G + where G : GoMut +{ + fn go_once(mut self, arg: isize) { + go_mut(&mut self, arg) + } +} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs new file mode 100644 index 00000000000..71dd7c99009 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs @@ -0,0 +1,82 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +pub trait Foo { + fn foo(&self) -> &'static str; +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +default impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +default impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +default impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +default impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +pub trait MyMarker {} +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs new file mode 100644 index 00000000000..9d0ea64fed4 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs @@ -0,0 +1,49 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +#![feature(specialization)] + +// First, test only use of explicit `default` items: + +pub trait Foo { + fn foo(&self) -> bool; +} + +default impl Foo for T { + fn foo(&self) -> bool { false } +} + +impl Foo for i32 {} + +impl Foo for i64 { + fn foo(&self) -> bool { true } +} + +// Next, test mixture of explicit `default` and provided methods: + +pub trait Bar { + fn bar(&self) -> i32 { 0 } +} + +impl Bar for T {} // use the provided method + +impl Bar for i32 { + fn bar(&self) -> i32 { 1 } +} +impl<'a> Bar for &'a str {} + +default impl Bar for Vec { + fn bar(&self) -> i32 { 2 } +} +impl Bar for Vec {} +impl Bar for Vec { + fn bar(&self) -> i32 { 3 } +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs new file mode 100644 index 00000000000..6b999f38358 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:go_trait.rs + +#![feature(specialization)] + +extern crate go_trait; + +use go_trait::{Go,GoMut}; +use std::fmt::Debug; +use std::default::Default; + +struct MyThingy; + +impl Go for MyThingy { + fn go(&self, arg: isize) { } +} + +impl GoMut for MyThingy { + fn go_mut(&mut self, arg: isize) { } +} + +fn main() { } diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs b/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs new file mode 100644 index 00000000000..b99ba3d0f1c --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs @@ -0,0 +1,37 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that non-method associated functions can be specialized + +#![feature(specialization)] + +trait Foo { + fn mk() -> Self; +} + +default impl Foo for T { + fn mk() -> T { + T::default() + } +} + +impl Foo for Vec { + fn mk() -> Vec { + vec![0] + } +} + +fn main() { + let v1: Vec = Foo::mk(); + let v2: Vec = Foo::mk(); + + assert!(v1.len() == 0); + assert!(v2.len() == 1); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs new file mode 100644 index 00000000000..7daecc842f3 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs @@ -0,0 +1,106 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +// Tests a variety of basic specialization scenarios and method +// dispatch for them. + +unsafe trait Foo { + fn foo(&self) -> &'static str; +} + +default unsafe impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +default unsafe impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +default unsafe impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +default unsafe impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +default unsafe impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +default unsafe impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +default unsafe impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +default unsafe impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +default unsafe impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +default unsafe impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +struct NotClone; + +unsafe trait MyMarker {} +default unsafe impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} + +#[derive(Clone)] +struct MarkedAndClone; +unsafe impl MyMarker for MarkedAndClone {} + +fn main() { + assert!(NotClone.foo() == "generic"); + assert!(0u8.foo() == "generic Clone"); + assert!(vec![NotClone].foo() == "generic"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); + assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs b/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs new file mode 100644 index 00000000000..594f1e4fcdf --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs @@ -0,0 +1,106 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +// Tests a variety of basic specialization scenarios and method +// dispatch for them. + +trait Foo { + fn foo(&self) -> &'static str; +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +default impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +default impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +default impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +default impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +struct NotClone; + +trait MyMarker {} +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} + +#[derive(Clone)] +struct MarkedAndClone; +impl MyMarker for MarkedAndClone {} + +fn main() { + assert!(NotClone.foo() == "generic"); + assert!(0u8.foo() == "generic Clone"); + assert!(vec![NotClone].foo() == "generic"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); + assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs new file mode 100644 index 00000000000..62c7e3e2e44 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs @@ -0,0 +1,49 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:specialization_cross_crate_defaults.rs + +#![feature(specialization)] + +extern crate specialization_cross_crate_defaults; + +use specialization_cross_crate_defaults::*; + +struct LocalDefault; +struct LocalOverride; + +impl Foo for LocalDefault {} + +impl Foo for LocalOverride { + fn foo(&self) -> bool { true } +} + +fn test_foo() { + assert!(!0i8.foo()); + assert!(!0i32.foo()); + assert!(0i64.foo()); + + assert!(!LocalDefault.foo()); + assert!(LocalOverride.foo()); +} + +fn test_bar() { + assert!(0u8.bar() == 0); + assert!(0i32.bar() == 1); + assert!("hello".bar() == 0); + assert!(vec![()].bar() == 2); + assert!(vec![0i32].bar() == 2); + assert!(vec![0i64].bar() == 3); +} + +fn main() { + test_foo(); + test_bar(); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs new file mode 100644 index 00000000000..b9548539e16 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that specialization works even if only the upstream crate enables it + +// aux-build:specialization_cross_crate.rs + +extern crate specialization_cross_crate; + +use specialization_cross_crate::*; + +fn main() { + assert!(0u8.foo() == "generic Clone"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs new file mode 100644 index 00000000000..7517824b62b --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs @@ -0,0 +1,58 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:specialization_cross_crate.rs + +#![feature(specialization)] + +extern crate specialization_cross_crate; + +use specialization_cross_crate::*; + +struct NotClone; + +#[derive(Clone)] +struct MarkedAndClone; +impl MyMarker for MarkedAndClone {} + +struct MyType(T); +default impl Foo for MyType { + fn foo(&self) -> &'static str { + "generic MyType" + } +} + +impl Foo for MyType { + fn foo(&self) -> &'static str { + "MyType" + } +} + +struct MyOtherType; +impl Foo for MyOtherType {} + +fn main() { + assert!(NotClone.foo() == "generic"); + assert!(0u8.foo() == "generic Clone"); + assert!(vec![NotClone].foo() == "generic"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); + assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); + + assert!(MyType(()).foo() == "generic MyType"); + assert!(MyType(0u8).foo() == "MyType"); + assert!(MyOtherType.foo() == "generic"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs b/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs new file mode 100644 index 00000000000..4ac9afc1c89 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs @@ -0,0 +1,94 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +// Test that default methods are cascaded correctly + +// First, test only use of explicit `default` items: + +trait Foo { + fn foo(&self) -> bool; +} + +// Specialization tree for Foo: +// +// T +// / \ +// i32 i64 + +default impl Foo for T { + fn foo(&self) -> bool { false } +} + +impl Foo for i32 {} + +impl Foo for i64 { + fn foo(&self) -> bool { true } +} + +fn test_foo() { + assert!(!0i8.foo()); + assert!(!0i32.foo()); + assert!(0i64.foo()); +} + +// Next, test mixture of explicit `default` and provided methods: + +trait Bar { + fn bar(&self) -> i32 { 0 } +} + +// Specialization tree for Bar. +// Uses of $ designate that method is provided +// +// $Bar (the trait) +// | +// T +// /|\ +// / | \ +// / | \ +// / | \ +// / | \ +// / | \ +// $i32 &str $Vec +// /\ +// / \ +// Vec $Vec + +// use the provided method +impl Bar for T {} + +impl Bar for i32 { + fn bar(&self) -> i32 { 1 } +} +impl<'a> Bar for &'a str {} + +default impl Bar for Vec { + fn bar(&self) -> i32 { 2 } +} +impl Bar for Vec {} +impl Bar for Vec { + fn bar(&self) -> i32 { 3 } +} + +fn test_bar() { + assert!(0u8.bar() == 0); + assert!(0i32.bar() == 1); + assert!("hello".bar() == 0); + assert!(vec![()].bar() == 2); + assert!(vec![0i32].bar() == 2); + assert!(vec![0i64].bar() == 3); +} + +fn main() { + test_foo(); + test_bar(); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs b/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs new file mode 100644 index 00000000000..f77b88e2f85 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs @@ -0,0 +1,27 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that you can list the more specific impl before the more general one. + +#![feature(specialization)] + +trait Foo { + type Out; +} + +impl Foo for bool { + type Out = (); +} + +default impl Foo for T { + type Out = bool; +} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs b/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs new file mode 100644 index 00000000000..500cded38c1 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs @@ -0,0 +1,33 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that impls on projected self types can resolve overlap, even when the +// projections involve specialization, so long as the associated type is +// provided by the most specialized impl. + +#![feature(specialization)] + +trait Assoc { + type Output; +} + +default impl Assoc for T { + type Output = bool; +} + +impl Assoc for u8 { type Output = u8; } +impl Assoc for u16 { type Output = u16; } + +trait Foo {} +impl Foo for u32 {} +impl Foo for ::Output {} +impl Foo for ::Output {} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs b/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs new file mode 100644 index 00000000000..2397c3e2bff --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs @@ -0,0 +1,32 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +// Regression test for ICE when combining specialized associated types and type +// aliases + +trait Id_ { + type Out; +} + +type Id = ::Out; + +default impl Id_ for T { + type Out = T; +} + +fn test_proection() { + let x: Id = panic!(); +} + +fn main() { + +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs b/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs new file mode 100644 index 00000000000..6a833ba6760 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs @@ -0,0 +1,49 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(specialization)] + +// Make sure we *can* project non-defaulted associated types +// cf compile-fail/specialization-default-projection.rs + +// First, do so without any use of specialization + +trait Foo { + type Assoc; +} + +impl Foo for T { + type Assoc = (); +} + +fn generic_foo() -> ::Assoc { + () +} + +// Next, allow for one layer of specialization + +trait Bar { + type Assoc; +} + +default impl Bar for T { + type Assoc = (); +} + +impl Bar for T { + type Assoc = u8; +} + +fn generic_bar_clone() -> ::Assoc { + 0u8 +} + +fn main() { +} diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index d046705c94b..ea154590dee 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -10,13 +10,12 @@ #![allow(warnings)] #![feature(collections)] -#![feature(drain, enumset, collections_bound, btree_range, vecmap)] +#![feature(drain, collections_bound, btree_range, vecmap)] extern crate collections; use collections::BinaryHeap; use collections::{BTreeMap, BTreeSet}; -use collections::EnumSet; use collections::LinkedList; use collections::String; use collections::Vec; @@ -25,7 +24,6 @@ use std::collections::HashSet; use collections::Bound::Included; -use collections::enum_set::CLike; use std::mem; fn is_sync(_: T) where T: Sync {} @@ -76,21 +74,6 @@ fn main() { all_sync_send!(LinkedList::::new(), iter, iter_mut, into_iter); - #[derive(Copy, Clone)] - #[repr(usize)] - #[allow(dead_code)] - enum Foo { A, B, C } - impl CLike for Foo { - fn to_usize(&self) -> usize { - *self as usize - } - - fn from_usize(v: usize) -> Foo { - unsafe { mem::transmute(v) } - } - } - all_sync_send!(EnumSet::::new(), iter); - all_sync_send!(VecDeque::::new(), iter, iter_mut, into_iter); is_sync_send!(VecDeque::::new(), drain(..)); diff --git a/src/test/run-pass/union/union-transmute.rs b/src/test/run-pass/union/union-transmute.rs index 4eb66268ab8..7a0b4c6aaca 100644 --- a/src/test/run-pass/union/union-transmute.rs +++ b/src/test/run-pass/union/union-transmute.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(core_float)] -#![feature(float_extras)] #![feature(untagged_unions)] extern crate core; -use core::num::Float; +use core::f32; union U { a: (u8, u8), @@ -33,8 +31,8 @@ fn main() { assert_eq!(u.a, (2, 2)); let mut w = W { a: 0b0_11111111_00000000000000000000000 }; - assert_eq!(w.b, f32::infinity()); - w.b = f32::neg_infinity(); + assert_eq!(w.b, f32::INFINITY); + w.b = f32::NEG_INFINITY; assert_eq!(w.a, 0b1_11111111_00000000000000000000000); } } diff --git a/src/test/run-pass/while-let.rs b/src/test/run-pass/while-let.rs index 9ffba2c7999..aed6986c5fe 100644 --- a/src/test/run-pass/while-let.rs +++ b/src/test/run-pass/while-let.rs @@ -9,8 +9,6 @@ // except according to those terms. -#![feature(binary_heap_extras)] - use std::collections::BinaryHeap; fn make_pq() -> BinaryHeap { diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs deleted file mode 100644 index f048b64d104..00000000000 --- a/src/test/rustdoc/check-hard-break.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name = "foo"] - -// ignore-tidy-end-whitespace - -// @has foo/fn.f.html -// @has - '

hard break:
' -// @has - 'after hard break

' -/// hard break: -/// after hard break -pub fn f() {} diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs deleted file mode 100644 index 46542677857..00000000000 --- a/src/test/rustdoc/check-rule-image-footnote.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name = "foo"] - -// ignore-tidy-linelength - -// @has foo/fn.f.html -// @has - '

markdown test

' -// @has - '

this is a link.

' -// @has - '
' -// @has - '

a footnote1.

' -// @has - '

another footnote2.

' -// @has - '

Rust

' -// @has - '

  1. ' -// @has - '

    Thing â†©

  2. ' -// @has - '

    Another Thing â†©

' -/// markdown test -/// -/// this is a [link]. -/// -/// [link]: https://example.com "this is a title" -/// -/// ----------- -/// -/// a footnote[^footnote]. -/// -/// another footnote[^footnotebis]. -/// -/// [^footnote]: Thing -/// -/// -/// [^footnotebis]: Another Thing -/// -/// -/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png) -pub fn f() {} diff --git a/src/test/ui/compare-method/region-extra-2.stderr b/src/test/ui/compare-method/region-extra-2.stderr index 12b0ecabcc7..af974d50183 100644 --- a/src/test/ui/compare-method/region-extra-2.stderr +++ b/src/test/ui/compare-method/region-extra-2.stderr @@ -4,12 +4,11 @@ error[E0276]: impl has stricter requirements than trait 15 | fn renew<'b: 'a>(self) -> &'b mut [T]; | -------------------------------------- definition of `renew` from trait ... -19 | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { - | _____^ starting here... +19 | / fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { 20 | | //~^ ERROR E0276 21 | | &mut self[..] 22 | | } - | |_____^ ...ending here: impl has extra requirement `'a: 'b` + | |_____^ impl has extra requirement `'a: 'b` error: aborting due to previous error diff --git a/src/test/ui/compare-method/traits-misc-mismatch-2.stderr b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr index 77b056f6978..622e144c53a 100644 --- a/src/test/ui/compare-method/traits-misc-mismatch-2.stderr +++ b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr @@ -4,12 +4,11 @@ error[E0276]: impl has stricter requirements than trait 19 | fn zip>(self, other: U) -> ZipIterator; | ------------------------------------------------------------------ definition of `zip` from trait ... -23 | fn zip>(self, other: U) -> ZipIterator { - | _____^ starting here... +23 | / fn zip>(self, other: U) -> ZipIterator { 24 | | //~^ ERROR E0276 25 | | ZipIterator{a: self, b: other} 26 | | } - | |_____^ ...ending here: impl has extra requirement `U: Iterator` + | |_____^ impl has extra requirement `U: Iterator` error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 29ff0cee3af..8e8773eba3e 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -2,17 +2,17 @@ error: missing `fn`, `type`, or `const` for impl-item declaration --> $DIR/issue-40006.rs:11:9 | 11 | impl X { - | _________^ starting here... + | _________^ 12 | | Y - | |____^ ...ending here: missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, or `const` error: missing `fn`, `type`, or `const` for trait-item declaration --> $DIR/issue-40006.rs:17:10 | 17 | trait X { - | __________^ starting here... + | __________^ 18 | | X() {} - | |____^ ...ending here: missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, or `const` error: expected `[`, found `#` --> $DIR/issue-40006.rs:19:17 @@ -24,17 +24,17 @@ error: missing `fn`, `type`, or `const` for trait-item declaration --> $DIR/issue-40006.rs:19:21 | 19 | fn xxx() { ### } - | _____________________^ starting here... + | _____________________^ 20 | | L = M; - | |____^ ...ending here: missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, or `const` error: missing `fn`, `type`, or `const` for trait-item declaration --> $DIR/issue-40006.rs:20:11 | 20 | L = M; - | ___________^ starting here... + | ___________^ 21 | | Z = { 2 + 3 }; - | |____^ ...ending here: missing `fn`, `type`, or `const` + | |____^ missing `fn`, `type`, or `const` error: expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;` --> $DIR/issue-40006.rs:21:18 diff --git a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr index 92e2fe8e936..2c788e952ed 100644 --- a/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr +++ b/src/test/ui/dropck/dropck-eyepatch-implies-unsafe-impl.stderr @@ -1,26 +1,24 @@ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:32:1 | -32 | impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { - | _^ starting here... +32 | / impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt { 33 | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute 34 | | 35 | | // (unsafe to access self.1 due to #[may_dangle] on A) 36 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } 37 | | } - | |_^ ...ending here + | |_^ error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute --> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:38:1 | -38 | impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { - | _^ starting here... +38 | / impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { 39 | | //~^ ERROR requires an `unsafe impl` declaration due to `#[may_dangle]` attribute 40 | | 41 | | // (unsafe to access self.1 due to #[may_dangle] on 'a) 42 | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } 43 | | } - | |_^ ...ending here + | |_^ error: aborting due to 2 previous errors diff --git a/src/test/ui/invalid-module-declaration/auxiliary/foo/bar.rs b/src/test/ui/invalid-module-declaration/auxiliary/foo/bar.rs new file mode 100644 index 00000000000..4b6b4f5ebf8 --- /dev/null +++ b/src/test/ui/invalid-module-declaration/auxiliary/foo/bar.rs @@ -0,0 +1,11 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub mod baz; diff --git a/src/test/ui/invalid-module-declaration/auxiliary/foo/mod.rs b/src/test/ui/invalid-module-declaration/auxiliary/foo/mod.rs new file mode 100644 index 00000000000..6d77fb60a35 --- /dev/null +++ b/src/test/ui/invalid-module-declaration/auxiliary/foo/mod.rs @@ -0,0 +1,11 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub mod bar; diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs b/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs new file mode 100644 index 00000000000..c15cfb8cc8e --- /dev/null +++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength + +// error-pattern: cannot declare a new module at this location +// error-pattern: maybe move this module + +mod auxiliary { + mod foo; +} + +fn main() {} diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr new file mode 100644 index 00000000000..3e9b21cdb74 --- /dev/null +++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr @@ -0,0 +1,14 @@ +error: cannot declare a new module at this location + --> $DIR/auxiliary/foo/bar.rs:11:9 + | +11 | pub mod baz; + | ^^^ + | +note: maybe move this module `$DIR/auxiliary/foo/bar.rs` to its own directory via `$DIR/auxiliary/foo/bar/mod.rs` + --> $DIR/auxiliary/foo/bar.rs:11:9 + | +11 | pub mod baz; + | ^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr b/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr index 5a63d235a7f..b51b683a1ac 100644 --- a/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr +++ b/src/test/ui/issue-37311-type-length-limit/issue-37311.stderr @@ -1,11 +1,10 @@ error: reached the type-length limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(), &()), &(&()...` --> $DIR/issue-37311.rs:23:5 | -23 | fn recurse(&self) { - | _____^ starting here... +23 | / fn recurse(&self) { 24 | | (self, self).recurse(); 25 | | } - | |_____^ ...ending here + | |_____^ | = note: consider adding a `#![type_length_limit="2097152"]` attribute to your crate diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr index 85e05422ab3..cf272b63128 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.stderr @@ -8,18 +8,18 @@ note: ...the reference is valid for the lifetime 'a as defined on the body at 11 --> $DIR/ex1-return-one-existing-name-if-else.rs:11:44 | 11 | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { - | ____________________________________________^ starting here... + | ____________________________________________^ 12 | | if x > y { x } else { y } 13 | | } - | |_^ ...ending here + | |_^ note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the body at 11:43 --> $DIR/ex1-return-one-existing-name-if-else.rs:11:44 | 11 | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { - | ____________________________________________^ starting here... + | ____________________________________________^ 12 | | if x > y { x } else { y } 13 | | } - | |_^ ...ending here + | |_^ error: aborting due to previous error diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr index 6956a043cc6..6e03e66dd25 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.stderr @@ -10,18 +10,18 @@ note: the anonymous lifetime #2 defined on the body at 15:51... --> $DIR/ex2a-push-one-existing-name.rs:15:52 | 15 | fn foo<'a>(x: &mut Vec>, y: Ref) { - | ____________________________________________________^ starting here... + | ____________________________________________________^ 16 | | x.push(y); 17 | | } - | |_^ ...ending here + | |_^ note: ...does not necessarily outlive the lifetime 'a as defined on the body at 15:51 --> $DIR/ex2a-push-one-existing-name.rs:15:52 | 15 | fn foo<'a>(x: &mut Vec>, y: Ref) { - | ____________________________________________________^ starting here... + | ____________________________________________________^ 16 | | x.push(y); 17 | | } - | |_^ ...ending here + | |_^ error: aborting due to previous error diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr index 990ae65ba98..028f54ce978 100644 --- a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr +++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.stderr @@ -10,18 +10,18 @@ note: the anonymous lifetime #3 defined on the body at 15:43... --> $DIR/ex2b-push-no-existing-names.rs:15:44 | 15 | fn foo(x: &mut Vec>, y: Ref) { - | ____________________________________________^ starting here... + | ____________________________________________^ 16 | | x.push(y); 17 | | } - | |_^ ...ending here + | |_^ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 15:43 --> $DIR/ex2b-push-no-existing-names.rs:15:44 | 15 | fn foo(x: &mut Vec>, y: Ref) { - | ____________________________________________^ starting here... + | ____________________________________________^ 16 | | x.push(y); 17 | | } - | |_^ ...ending here + | |_^ error: aborting due to previous error diff --git a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr index 82f6c71ec1c..4621214419e 100644 --- a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr +++ b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.stderr @@ -8,11 +8,11 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body --> $DIR/ex2c-push-inference-variable.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let z = Ref { data: y.data }; 17 | | x.push(z); 18 | | } - | |_^ ...ending here + | |_^ note: ...so that reference does not outlive borrowed content --> $DIR/ex2c-push-inference-variable.rs:16:25 | @@ -22,11 +22,11 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body --> $DIR/ex2c-push-inference-variable.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let z = Ref { data: y.data }; 17 | | x.push(z); 18 | | } - | |_^ ...ending here + | |_^ note: ...so that expression is assignable (expected Ref<'b, _>, found Ref<'_, _>) --> $DIR/ex2c-push-inference-variable.rs:17:12 | diff --git a/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr b/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr index daa6ea2d91a..a69694fdc2e 100644 --- a/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr +++ b/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.stderr @@ -8,12 +8,12 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body --> $DIR/ex2d-push-inference-variable-2.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let a: &mut Vec> = x; 17 | | let b = Ref { data: y.data }; 18 | | a.push(b); 19 | | } - | |_^ ...ending here + | |_^ note: ...so that reference does not outlive borrowed content --> $DIR/ex2d-push-inference-variable-2.rs:17:25 | @@ -23,12 +23,12 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body --> $DIR/ex2d-push-inference-variable-2.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let a: &mut Vec> = x; 17 | | let b = Ref { data: y.data }; 18 | | a.push(b); 19 | | } - | |_^ ...ending here + | |_^ note: ...so that expression is assignable (expected &mut std::vec::Vec>, found &mut std::vec::Vec>) --> $DIR/ex2d-push-inference-variable-2.rs:16:33 | diff --git a/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr b/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr index b679532a4d9..eff15bb794b 100644 --- a/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr +++ b/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.stderr @@ -8,12 +8,12 @@ note: first, the lifetime cannot outlive the lifetime 'c as defined on the body --> $DIR/ex2e-push-inference-variable-3.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let a: &mut Vec> = x; 17 | | let b = Ref { data: y.data }; 18 | | Vec::push(a, b); 19 | | } - | |_^ ...ending here + | |_^ note: ...so that reference does not outlive borrowed content --> $DIR/ex2e-push-inference-variable-3.rs:17:25 | @@ -23,12 +23,12 @@ note: but, the lifetime must be valid for the lifetime 'b as defined on the body --> $DIR/ex2e-push-inference-variable-3.rs:15:67 | 15 | fn foo<'a, 'b, 'c>(x: &'a mut Vec>, y: Ref<'c, i32>) { - | ___________________________________________________________________^ starting here... + | ___________________________________________________________________^ 16 | | let a: &mut Vec> = x; 17 | | let b = Ref { data: y.data }; 18 | | Vec::push(a, b); 19 | | } - | |_^ ...ending here + | |_^ note: ...so that expression is assignable (expected &mut std::vec::Vec>, found &mut std::vec::Vec>) --> $DIR/ex2e-push-inference-variable-3.rs:16:33 | diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr index c67c6113d17..36bdec8d43a 100644 --- a/src/test/ui/mismatched_types/abridged.stderr +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -37,15 +37,14 @@ error[E0308]: mismatched types error[E0308]: mismatched types --> $DIR/abridged.rs:42:5 | -42 | X { - | _____^ starting here... +42 | / X { 43 | | x: X { 44 | | x: "".to_string(), 45 | | y: 2, 46 | | }, 47 | | y: 3, 48 | | } - | |_____^ ...ending here: expected struct `std::string::String`, found integral variable + | |_____^ expected struct `std::string::String`, found integral variable | = note: expected type `X, std::string::String>` found type `X, {integer}>` @@ -53,15 +52,14 @@ error[E0308]: mismatched types error[E0308]: mismatched types --> $DIR/abridged.rs:52:5 | -52 | X { - | _____^ starting here... +52 | / X { 53 | | x: X { 54 | | x: "".to_string(), 55 | | y: 2, 56 | | }, 57 | | y: "".to_string(), 58 | | } - | |_____^ ...ending here: expected struct `std::string::String`, found integral variable + | |_____^ expected struct `std::string::String`, found integral variable | = note: expected type `X, _>` found type `X, _>` diff --git a/src/test/ui/mismatched_types/main.stderr b/src/test/ui/mismatched_types/main.stderr index 5dd124ebcdf..c8941fbf950 100644 --- a/src/test/ui/mismatched_types/main.stderr +++ b/src/test/ui/mismatched_types/main.stderr @@ -2,9 +2,9 @@ error[E0308]: mismatched types --> $DIR/main.rs:12:18 | 12 | let x: u32 = ( - | __________________^ starting here... + | __________________^ 13 | | ); - | |_____^ ...ending here: expected u32, found () + | |_____^ expected u32, found () | = note: expected type `u32` found type `()` diff --git a/src/test/ui/missing-items/m2.stderr b/src/test/ui/missing-items/m2.stderr index 33135434544..503ce5618d4 100644 --- a/src/test/ui/missing-items/m2.stderr +++ b/src/test/ui/missing-items/m2.stderr @@ -3,10 +3,9 @@ error: main function not found error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `method` --> $DIR/m2.rs:20:1 | -20 | impl m1::X for X { - | _^ starting here... +20 | / impl m1::X for X { 21 | | } - | |_^ ...ending here: missing `CONSTANT`, `Type`, `method` in implementation + | |_^ missing `CONSTANT`, `Type`, `method` in implementation | = note: `CONSTANT` from trait: `const CONSTANT: u32;` = note: `Type` from trait: `type Type;` diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs new file mode 100644 index 00000000000..e9b43145de4 --- /dev/null +++ b/src/test/ui/print_type_sizes/repr-align.rs @@ -0,0 +1,43 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes + +// This file illustrates how padding is handled: alignment +// requirements can lead to the introduction of padding, either before +// fields or at the end of the structure as a whole. +// +// It avoids using u64/i64 because on some targets that is only 4-byte +// aligned (while on most it is 8-byte aligned) and so the resulting +// padding and overall computed sizes can be quite different. +#![feature(attr_literals)] +#![feature(repr_align)] +#![allow(dead_code)] + +#[repr(align(16))] +#[derive(Default)] +struct A(i32); + +enum E { + A(i32), + B(A) +} + +#[derive(Default)] +struct S { + a: i32, + b: i32, + c: A, + d: i8, +} + +fn main() { + let _s: S = Default::default(); +} diff --git a/src/test/ui/print_type_sizes/repr-align.stdout b/src/test/ui/print_type_sizes/repr-align.stdout new file mode 100644 index 00000000000..7df12f040b1 --- /dev/null +++ b/src/test/ui/print_type_sizes/repr-align.stdout @@ -0,0 +1,16 @@ +print-type-size type: `E`: 32 bytes, alignment: 16 bytes +print-type-size discriminant: 4 bytes +print-type-size variant `A`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size variant `B`: 28 bytes +print-type-size padding: 12 bytes +print-type-size field `.0`: 16 bytes, alignment: 16 bytes +print-type-size type: `S`: 32 bytes, alignment: 16 bytes +print-type-size field `.c`: 16 bytes +print-type-size field `.a`: 4 bytes +print-type-size field `.b`: 4 bytes +print-type-size field `.d`: 1 bytes +print-type-size end padding: 7 bytes +print-type-size type: `A`: 16 bytes, alignment: 16 bytes +print-type-size field `.0`: 4 bytes +print-type-size end padding: 12 bytes diff --git a/src/test/ui/span/coerce-suggestions.rs b/src/test/ui/span/coerce-suggestions.rs index 3177e858ff4..bc3122bf71c 100644 --- a/src/test/ui/span/coerce-suggestions.rs +++ b/src/test/ui/span/coerce-suggestions.rs @@ -32,7 +32,6 @@ fn main() { //~| NOTE types differ in mutability //~| NOTE expected type `&mut std::string::String` //~| NOTE found type `&std::string::String` - //~| HELP try with `&mut y` test2(&y); //~^ ERROR E0308 //~| NOTE types differ in mutability diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index 6a70b8ff851..220b2f471da 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -18,11 +18,7 @@ error[E0308]: mismatched types | = note: expected type `&str` found type `std::string::String` - = help: here are some functions which might fulfill your needs: - - .as_str() - - .trim() - - .trim_left() - - .trim_right() + = help: try with `&String::new()` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:30:10 @@ -34,18 +30,18 @@ error[E0308]: mismatched types found type `&std::string::String` error[E0308]: mismatched types - --> $DIR/coerce-suggestions.rs:36:11 + --> $DIR/coerce-suggestions.rs:35:11 | -36 | test2(&y); +35 | test2(&y); | ^^ types differ in mutability | = note: expected type `&mut i32` found type `&std::string::String` error[E0308]: mismatched types - --> $DIR/coerce-suggestions.rs:42:9 + --> $DIR/coerce-suggestions.rs:41:9 | -42 | f = box f; +41 | f = box f; | ^^^^^ cyclic type of infinite size | = note: expected type `_` diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr index 367af12bb6b..ae290b3b11a 100644 --- a/src/test/ui/span/impl-wrong-item-for-trait.stderr +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -19,15 +19,14 @@ error[E0046]: not all trait items implemented, missing: `bar` 16 | fn bar(&self); | -------------- `bar` from trait ... -22 | impl Foo for FooConstForMethod { - | _^ starting here... +22 | / impl Foo for FooConstForMethod { 23 | | //~^ ERROR E0046 24 | | //~| NOTE missing `bar` in implementation 25 | | const bar: u64 = 1; ... | 28 | | const MY_CONST: u32 = 1; 29 | | } - | |_^ ...ending here: missing `bar` in implementation + | |_^ missing `bar` in implementation error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `Foo` --> $DIR/impl-wrong-item-for-trait.rs:37:5 @@ -44,15 +43,14 @@ error[E0046]: not all trait items implemented, missing: `MY_CONST` 17 | const MY_CONST: u32; | -------------------- `MY_CONST` from trait ... -33 | impl Foo for FooMethodForConst { - | _^ starting here... +33 | / impl Foo for FooMethodForConst { 34 | | //~^ ERROR E0046 35 | | //~| NOTE missing `MY_CONST` in implementation 36 | | fn bar(&self) {} ... | 39 | | //~| NOTE does not match trait 40 | | } - | |_^ ...ending here: missing `MY_CONST` in implementation + | |_^ missing `MY_CONST` in implementation error[E0325]: item `bar` is an associated type, which doesn't match its trait `Foo` --> $DIR/impl-wrong-item-for-trait.rs:47:5 @@ -69,23 +67,21 @@ error[E0046]: not all trait items implemented, missing: `bar` 16 | fn bar(&self); | -------------- `bar` from trait ... -44 | impl Foo for FooTypeForMethod { - | _^ starting here... +44 | / impl Foo for FooTypeForMethod { 45 | | //~^ ERROR E0046 46 | | //~| NOTE missing `bar` in implementation 47 | | type bar = u64; ... | 50 | | const MY_CONST: u32 = 1; 51 | | } - | |_^ ...ending here: missing `bar` in implementation + | |_^ missing `bar` in implementation error[E0046]: not all trait items implemented, missing: `fmt` --> $DIR/impl-wrong-item-for-trait.rs:53:1 | -53 | impl Debug for FooTypeForMethod { - | _^ starting here... +53 | / impl Debug for FooTypeForMethod { 54 | | } - | |_^ ...ending here: missing `fmt` in implementation + | |_^ missing `fmt` in implementation | = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` diff --git a/src/test/ui/span/issue-23729.stderr b/src/test/ui/span/issue-23729.stderr index 701576ff6f4..d9f4bacce35 100644 --- a/src/test/ui/span/issue-23729.stderr +++ b/src/test/ui/span/issue-23729.stderr @@ -1,15 +1,14 @@ error[E0046]: not all trait items implemented, missing: `Item` --> $DIR/issue-23729.rs:20:9 | -20 | impl Iterator for Recurrence { - | _________^ starting here... +20 | / impl Iterator for Recurrence { 21 | | //~^ ERROR E0046 22 | | //~| NOTE missing `Item` in implementation 23 | | //~| NOTE `Item` from trait: `type Item;` ... | 36 | | } 37 | | } - | |_________^ ...ending here: missing `Item` in implementation + | |_________^ missing `Item` in implementation | = note: `Item` from trait: `type Item;` diff --git a/src/test/ui/span/issue-23827.stderr b/src/test/ui/span/issue-23827.stderr index 457fed34ff1..3127af157a6 100644 --- a/src/test/ui/span/issue-23827.stderr +++ b/src/test/ui/span/issue-23827.stderr @@ -1,15 +1,14 @@ error[E0046]: not all trait items implemented, missing: `Output` --> $DIR/issue-23827.rs:36:1 | -36 | impl FnOnce<(C,)> for Prototype { - | _^ starting here... +36 | / impl FnOnce<(C,)> for Prototype { 37 | | //~^ ERROR E0046 38 | | //~| NOTE missing `Output` in implementation 39 | | //~| NOTE `Output` from trait: `type Output;` ... | 42 | | } 43 | | } - | |_^ ...ending here: missing `Output` in implementation + | |_^ missing `Output` in implementation | = note: `Output` from trait: `type Output;` diff --git a/src/test/ui/span/issue-24356.stderr b/src/test/ui/span/issue-24356.stderr index 963f4bd9bbc..71ab82d98b8 100644 --- a/src/test/ui/span/issue-24356.stderr +++ b/src/test/ui/span/issue-24356.stderr @@ -1,14 +1,13 @@ error[E0046]: not all trait items implemented, missing: `Target` --> $DIR/issue-24356.rs:30:9 | -30 | impl Deref for Thing { - | _________^ starting here... +30 | / impl Deref for Thing { 31 | | //~^ ERROR E0046 32 | | //~| NOTE missing `Target` in implementation 33 | | //~| NOTE `Target` from trait: `type Target;` 34 | | fn deref(&self) -> i8 { self.0 } 35 | | } - | |_________^ ...ending here: missing `Target` in implementation + | |_________^ missing `Target` in implementation | = note: `Target` from trait: `type Target;` diff --git a/src/test/ui/span/issue-33884.rs b/src/test/ui/span/issue-33884.rs new file mode 100644 index 00000000000..93aa502ee15 --- /dev/null +++ b/src/test/ui/span/issue-33884.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::net::TcpListener; +use std::net::TcpStream; +use std::io::{self, Read, Write}; + +fn handle_client(stream: TcpStream) -> io::Result<()> { + stream.write_fmt(format!("message received")) +} + +fn main() { + if let Ok(listener) = TcpListener::bind("127.0.0.1:8080") { + for incoming in listener.incoming() { + if let Ok(stream) = incoming { + handle_client(stream); + } + } + } +} diff --git a/src/test/ui/span/issue-33884.stderr b/src/test/ui/span/issue-33884.stderr new file mode 100644 index 00000000000..2a874181c7a --- /dev/null +++ b/src/test/ui/span/issue-33884.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/issue-33884.rs:16:22 + | +16 | stream.write_fmt(format!("message received")) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::fmt::Arguments`, found struct `std::string::String` + | + = note: expected type `std::fmt::Arguments<'_>` + found type `std::string::String` + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr index 765aceffe65..8b813220d78 100644 --- a/src/test/ui/span/issue-7575.stderr +++ b/src/test/ui/span/issue-7575.stderr @@ -38,11 +38,10 @@ error: no method named `fff` found for type `Myisize` in the current scope note: candidate #1 is defined in an impl for the type `Myisize` --> $DIR/issue-7575.rs:51:5 | -51 | fn fff(i: isize) -> isize { //~ NOTE candidate - | _____^ starting here... +51 | / fn fff(i: isize) -> isize { //~ NOTE candidate 52 | | i 53 | | } - | |_____^ ...ending here + | |_____^ error: no method named `is_str` found for type `T` in the current scope --> $DIR/issue-7575.rs:85:7 @@ -54,11 +53,10 @@ error: no method named `is_str` found for type `T` in the current scope note: candidate #1 is defined in the trait `ManyImplTrait` --> $DIR/issue-7575.rs:57:5 | -57 | fn is_str() -> bool { //~ NOTE candidate - | _____^ starting here... +57 | / fn is_str() -> bool { //~ NOTE candidate 58 | | false 59 | | } - | |_____^ ...ending here + | |_____^ = help: to disambiguate the method call, write `ManyImplTrait::is_str(t)` instead = help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `is_str`, perhaps you need to implement it: = help: candidate #1: `ManyImplTrait` diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.stderr index 0df3fa43022..f4998e08907 100644 --- a/src/test/ui/span/lint-unused-unsafe.stderr +++ b/src/test/ui/span/lint-unused-unsafe.stderr @@ -49,68 +49,62 @@ note: because it's nested under this `unsafe` fn error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:33:9 | -33 | unsafe { //~ ERROR: unnecessary `unsafe` block - | _________^ starting here... +33 | / unsafe { //~ ERROR: unnecessary `unsafe` block 34 | | unsf() 35 | | } - | |_________^ ...ending here: unnecessary `unsafe` block + | |_________^ unnecessary `unsafe` block | note: because it's nested under this `unsafe` block --> $DIR/lint-unused-unsafe.rs:32:5 | -32 | unsafe { // don't put the warning here - | _____^ starting here... +32 | / unsafe { // don't put the warning here 33 | | unsafe { //~ ERROR: unnecessary `unsafe` block 34 | | unsf() 35 | | } 36 | | } - | |_____^ ...ending here + | |_____^ error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:39:5 | -39 | unsafe { //~ ERROR: unnecessary `unsafe` block - | _____^ starting here... +39 | / unsafe { //~ ERROR: unnecessary `unsafe` block 40 | | unsafe { //~ ERROR: unnecessary `unsafe` block 41 | | unsf() 42 | | } 43 | | } - | |_____^ ...ending here: unnecessary `unsafe` block + | |_____^ unnecessary `unsafe` block | note: because it's nested under this `unsafe` fn --> $DIR/lint-unused-unsafe.rs:38:1 | -38 | unsafe fn bad7() { - | _^ starting here... +38 | / unsafe fn bad7() { 39 | | unsafe { //~ ERROR: unnecessary `unsafe` block 40 | | unsafe { //~ ERROR: unnecessary `unsafe` block 41 | | unsf() 42 | | } 43 | | } 44 | | } - | |_^ ...ending here + | |_^ error: unnecessary `unsafe` block --> $DIR/lint-unused-unsafe.rs:40:9 | -40 | unsafe { //~ ERROR: unnecessary `unsafe` block - | _________^ starting here... +40 | / unsafe { //~ ERROR: unnecessary `unsafe` block 41 | | unsf() 42 | | } - | |_________^ ...ending here: unnecessary `unsafe` block + | |_________^ unnecessary `unsafe` block | note: because it's nested under this `unsafe` fn --> $DIR/lint-unused-unsafe.rs:38:1 | -38 | unsafe fn bad7() { - | _^ starting here... +38 | / unsafe fn bad7() { 39 | | unsafe { //~ ERROR: unnecessary `unsafe` block 40 | | unsafe { //~ ERROR: unnecessary `unsafe` block 41 | | unsf() 42 | | } 43 | | } 44 | | } - | |_^ ...ending here + | |_^ error: aborting due to 8 previous errors diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr index 58cdc502300..9c6816e7363 100644 --- a/src/test/ui/span/multiline-span-E0072.stderr +++ b/src/test/ui/span/multiline-span-E0072.stderr @@ -1,14 +1,13 @@ error[E0072]: recursive type `ListNode` has infinite size --> $DIR/multiline-span-E0072.rs:12:1 | -12 | struct - | _^ starting here... +12 | / struct 13 | | ListNode 14 | | { 15 | | head: u8, 16 | | tail: Option, 17 | | } - | |_^ ...ending here: recursive type has infinite size + | |_^ recursive type has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 161b6ca48b2..843c1e811d5 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -2,12 +2,12 @@ error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied --> $DIR/multiline-span-simple.rs:23:9 | 23 | foo(1 as u32 + - | _________^ starting here... + | _________^ 24 | | 25 | | bar(x, 26 | | 27 | | y), - | |______________^ ...ending here: the trait `std::ops::Add<()>` is not implemented for `u32` + | |______________^ the trait `std::ops::Add<()>` is not implemented for `u32` | = note: no implementation for `u32 + ()` diff --git a/src/test/ui/type-check/issue-40294.stderr b/src/test/ui/type-check/issue-40294.stderr index 5c388c9d602..7a76799889b 100644 --- a/src/test/ui/type-check/issue-40294.stderr +++ b/src/test/ui/type-check/issue-40294.stderr @@ -1,15 +1,14 @@ error[E0282]: type annotations needed --> $DIR/issue-40294.rs:15:1 | -15 | fn foo<'a,'b,T>(x: &'a T, y: &'b T) - | _^ starting here... +15 | / fn foo<'a,'b,T>(x: &'a T, y: &'b T) 16 | | where &'a T : Foo, 17 | | &'b T : Foo 18 | | { 19 | | x.foo(); 20 | | y.foo(); 21 | | } - | |_^ ...ending here: cannot infer type for `&'a T` + | |_^ cannot infer type for `&'a T` error: aborting due to previous error diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 28c8d227073..a8cb30da435 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -81,6 +81,7 @@ "s390x-unknown-linux-gnu", "sparc64-unknown-linux-gnu", "wasm32-unknown-emscripten", + "x86_64-linux-android", "x86_64-apple-darwin", "x86_64-apple-ios", "x86_64-pc-windows-gnu", diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index c7113edbf9e..012ee835494 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -22,12 +22,6 @@ struct Test { } const TEST_REPOS: &'static [Test] = &[ - Test { - name: "cargo", - repo: "https://github.com/rust-lang/cargo", - sha: "0e1e34be7540bdaed4918457654fbf028cf69e56", - lock: None, - }, Test { name: "iron", repo: "https://github.com/iron/iron", @@ -61,20 +55,6 @@ struct Test { ]; fn main() { - // One of the projects being tested here is Cargo, and when being tested - // Cargo will at some point call `nmake.exe` on Windows MSVC. Unfortunately - // `nmake` will read these two environment variables below and try to - // intepret them. We're likely being run, however, from MSYS `make` which - // uses the same variables. - // - // As a result, to prevent confusion and errors, we remove these variables - // from our environment to prevent passing MSYS make flags to nmake, causing - // it to blow up. - if cfg!(target_env = "msvc") { - env::remove_var("MAKE"); - env::remove_var("MAKEFLAGS"); - } - let args = env::args().collect::>(); let ref cargo = args[1]; let out_dir = Path::new(&args[2]); diff --git a/src/tools/compiletest/src/procsrv.rs b/src/tools/compiletest/src/procsrv.rs index 3d8f2296236..dbda8f4d802 100644 --- a/src/tools/compiletest/src/procsrv.rs +++ b/src/tools/compiletest/src/procsrv.rs @@ -20,6 +20,8 @@ pub fn dylib_env_var() -> &'static str { "PATH" } else if cfg!(target_os = "macos") { "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" } else { "LD_LIBRARY_PATH" } diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index efadde99227..ca383b5add0 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -24,7 +24,7 @@ use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::{Markdown, PLAYGROUND}; +use rustdoc::html::markdown::{Markdown, PLAYGROUND, RenderType}; use rustc_serialize::json; enum OutputFormat { @@ -100,7 +100,7 @@ fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata, // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc))?, + Some(ref desc) => write!(output, "{}", Markdown(desc, RenderType::Hoedown))?, None => write!(output, "

No description.

\n")?, }