diff --git a/.mailmap b/.mailmap index be18190e12b38..1ae0aae2d01ba 100644 --- a/.mailmap +++ b/.mailmap @@ -43,8 +43,8 @@ Brian Anderson Brian Dawn Brian Leibig Brian Leibig Carl-Anton Ingmarsson -Carol (Nichols || Goulding) Carol Nichols -Carol (Nichols || Goulding) Carol Nichols +Carol (Nichols || Goulding) +Carol (Nichols || Goulding) Carol Willing Chris C Cerami Chris C Cerami Chris Pressey @@ -53,6 +53,7 @@ Clark Gaebel Clinton Ryan Corey Farwell Corey Farwell Corey Richardson Elaine "See More" Nemo +Cyryl Płotnicki Damien Schoof Daniel Ramos David Klein @@ -102,6 +103,7 @@ Jason Toffaletti Jason Toffaletti Jauhien Piatlicki Jauhien Piatlicki Jay True Jeremy Letang +Jethro Beekman Jihyun Yu Jihyun Yu jihyun Jihyun Yu Jihyun Yu @@ -165,6 +167,7 @@ Ožbolt Menegatti gareins Paul Faria Peer Aramillo Irizar parir Peter Elmers +Peter Liniker Peter Zotov Phil Dawes Phil Dawes Philipp Brüschweiler diff --git a/.travis.yml b/.travis.yml index bbe0cdfb6f8f0..ea405413e78f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,7 @@ matrix: - env: IMAGE=x86_64-gnu-make - env: IMAGE=x86_64-gnu-llvm-3.7 ALLOW_PR=1 RUST_BACKTRACE=1 - env: IMAGE=x86_64-gnu-distcheck + - env: IMAGE=x86_64-gnu-incremental # OSX builders - env: > @@ -43,17 +44,9 @@ matrix: SRC=. os: osx osx_image: xcode8.2 - before_script: &osx_before_script > - ulimit -c unlimited install: &osx_install_sccache > curl -L https://api.pub.build.mozilla.org/tooltool/sha512/d0025b286468cc5ada83b23d3fafbc936b9f190eaa7d4a981715b18e8e3bf720a7bcee7bfe758cfdeb8268857f6098fd52dcdd8818232692a30ce91039936596 | tar xJf - -C /usr/local/bin --strip-components=1 - after_failure: &osx_after_failure > - echo 'bt all' > cmds; - for file in $(ls /cores); do - echo core file $file; - lldb -c /cores/$file `which ld` -b -s cmds; - done - env: > SCRIPT="./x.py test && ./x.py dist" @@ -62,18 +55,14 @@ matrix: DEPLOY=1 os: osx osx_image: xcode8.2 - before_script: *osx_before_script install: *osx_install_sccache - after_failure: *osx_after_failure - env: > RUST_CHECK_TARGET=check RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin --disable-rustbuild SRC=. os: osx osx_image: xcode8.2 - before_script: *osx_before_script install: *osx_install_sccache - after_failure: *osx_after_failure - 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" @@ -81,9 +70,7 @@ matrix: DEPLOY=1 os: osx osx_image: xcode8.2 - before_script: *osx_before_script install: *osx_install_sccache - after_failure: *osx_after_failure env: global: @@ -124,9 +111,11 @@ before_deploy: - mkdir -p deploy/$TRAVIS_COMMIT - > if [ "$TRAVIS_OS_NAME" == "osx" ]; then - cp build/dist/*.tar.gz deploy/$TRAVIS_COMMIT; + rm -rf build/dist/doc && + cp -r build/dist/* deploy/$TRAVIS_COMMIT; else - cp obj/build/dist/*.tar.gz deploy/$TRAVIS_COMMIT; + rm -rf obj/build/dist/doc && + cp -r obj/build/dist/* deploy/$TRAVIS_COMMIT; fi deploy: diff --git a/appveyor.yml b/appveyor.yml index f158d788d16af..c617ac8a4e342 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -137,7 +137,8 @@ branches: before_deploy: - ps: | New-Item -Path deploy -ItemType directory - Get-ChildItem -Path build\dist -Filter '*.tar.gz' | Move-Item -Destination deploy + Remove-Item -Recurse -Force build\dist\doc + Get-ChildItem -Path build\dist | Move-Item -Destination deploy Get-ChildItem -Path deploy | Foreach-Object { Push-AppveyorArtifact $_.FullName -FileName ${env:APPVEYOR_REPO_COMMIT}/$_ } @@ -151,7 +152,7 @@ deploy: bucket: rust-lang-ci set_public: true region: us-east-1 - artifact: /.*\.tar.gz/ + artifact: /.*/ folder: rustc-builds on: branch: auto diff --git a/src/Cargo.lock b/src/Cargo.lock index 7db243c5eb9d0..c058586410dac 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -50,9 +50,20 @@ dependencies = [ "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "build-manifest" +version = "0.1.0" +dependencies = [ + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "build_helper" version = "0.1.0" +dependencies = [ + "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "cargotest" @@ -586,7 +597,7 @@ dependencies = [ [[package]] name = "std_shim" -version = "0.1.0" +version = "0.0.0" dependencies = [ "core 0.0.0", "std 0.0.0", @@ -645,7 +656,7 @@ dependencies = [ [[package]] name = "test_shim" -version = "0.1.0" +version = "0.0.0" dependencies = [ "test 0.0.0", ] diff --git a/src/Cargo.toml b/src/Cargo.toml index 8fb5c70c41bf1..0db26ea5ae021 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -10,6 +10,7 @@ members = [ "tools/linkchecker", "tools/rustbook", "tools/tidy", + "tools/build-manifest", ] # Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 4aca843558fd0..19aac0f36bb27 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -383,7 +383,7 @@ pub fn krate(build: &Build, // helper crate, not tested. If it leaks through then it ends up // messing with various mtime calculations and such. if !name.contains("jemalloc") && name != "build_helper" { - cargo.arg("-p").arg(name); + cargo.arg("-p").arg(&format!("{}:0.0.0", name)); } for dep in build.crates[name].deps.iter() { if visited.insert(dep) { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 7c35151a6d274..776b91028a1a3 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -21,10 +21,10 @@ use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::process::Command; -use build_helper::output; +use build_helper::{output, mtime}; use filetime::FileTime; -use util::{exe, libdir, mtime, is_dylib, copy}; +use util::{exe, libdir, is_dylib, copy}; use {Build, Compiler, Mode}; /// Build the standard library. diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 7d1abcfa6f6e7..6e077691b3a05 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -78,6 +78,11 @@ pub struct Config { pub cargo: Option, pub local_rebuild: bool, + // dist misc + pub dist_sign_folder: Option, + pub dist_upload_addr: Option, + pub dist_gpg_password_file: Option, + // libstd features pub debug_jemalloc: bool, pub use_jemalloc: bool, @@ -123,6 +128,7 @@ struct TomlConfig { llvm: Option, rust: Option, target: Option>, + dist: Option, } /// TOML representation of various global build decisions. @@ -166,6 +172,13 @@ struct Llvm { targets: Option, } +#[derive(RustcDecodable, Default, Clone)] +struct Dist { + sign_folder: Option, + gpg_password_file: Option, + upload_addr: Option, +} + #[derive(RustcDecodable)] enum StringOrBool { String(String), @@ -352,6 +365,12 @@ impl Config { } } + if let Some(ref t) = toml.dist { + config.dist_sign_folder = t.sign_folder.clone().map(PathBuf::from); + config.dist_gpg_password_file = t.gpg_password_file.clone().map(PathBuf::from); + config.dist_upload_addr = t.upload_addr.clone(); + } + return config } @@ -497,7 +516,7 @@ impl Config { "CFG_JEMALLOC_ROOT" if value.len() > 0 => { let target = self.target_config.entry(self.build.clone()) .or_insert(Target::default()); - target.jemalloc = Some(parse_configure_path(value)); + target.jemalloc = Some(parse_configure_path(value).join("libjemalloc_pic.a")); } "CFG_ARM_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => { let target = "arm-linux-androideabi".to_string(); diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 4b859482562d2..a53419ad7fd78 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -242,3 +242,33 @@ # that this option only makes sense for MUSL targets that produce statically # linked binaries #musl-root = "..." + +# ============================================================================= +# Distribution options +# +# These options are related to distribution, mostly for the Rust project itself. +# You probably won't need to concern yourself with any of these options +# ============================================================================= +[dist] + +# This is the folder of artifacts that the build system will sign. All files in +# this directory will be signed with the default gpg key using the system `gpg` +# binary. The `asc` and `sha256` files will all be output into the standard dist +# output folder (currently `build/dist`) +# +# This folder should be populated ahead of time before the build system is +# invoked. +#sign-folder = "path/to/folder/to/sign" + +# This is a file which contains the password of the default gpg key. This will +# be passed to `gpg` down the road when signing all files in `sign-folder` +# above. This should be stored in plaintext. +#gpg-password-file = "path/to/gpg/password" + +# The remote address that all artifacts will eventually be uploaded to. The +# build system generates manifests which will point to these urls, and for the +# manifests to be correct they'll have to have the right URLs encoded. +# +# Note that this address should not contain a trailing slash as file names will +# be appended to it. +#upload-addr = "https://example.com/folder" diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e5f0505952318..5fac142f777ff 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -22,7 +22,7 @@ use std::env; use std::fs::{self, File}; use std::io::{Read, Write}; use std::path::{PathBuf, Path}; -use std::process::Command; +use std::process::{Command, Stdio}; use build_helper::output; @@ -827,7 +827,7 @@ pub fn extended(build: &Build, stage: u32, target: &str) { cmd.arg("-nologo") .arg("-ext").arg("WixUIExtension") .arg("-ext").arg("WixUtilExtension") - .arg("-out").arg(distdir(build).join(filename)) + .arg("-out").arg(exe.join(&filename)) .arg("rust.wixobj") .arg("ui.wixobj") .arg("rustwelcomedlg.wixobj") @@ -844,6 +844,8 @@ pub fn extended(build: &Build, stage: u32, target: &str) { cmd.arg("-sice:ICE57"); build.run(&mut cmd); + + t!(fs::rename(exe.join(&filename), distdir(build).join(&filename))); } } @@ -876,3 +878,34 @@ fn add_env(build: &Build, cmd: &mut Command, target: &str) { cmd.env("CFG_PLATFORM", "x86"); } } + +pub fn hash_and_sign(build: &Build) { + let compiler = Compiler::new(0, &build.config.build); + let mut cmd = build.tool_cmd(&compiler, "build-manifest"); + let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n") + }); + let addr = build.config.dist_upload_addr.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n") + }); + let file = build.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n") + }); + let mut pass = String::new(); + t!(t!(File::open(&file)).read_to_string(&mut pass)); + + let today = output(Command::new("date").arg("+%Y-%m-%d")); + + cmd.arg(sign); + cmd.arg(distdir(build)); + cmd.arg(today.trim()); + cmd.arg(package_vers(build)); + cmd.arg(addr); + + t!(fs::create_dir_all(distdir(build))); + + let mut child = t!(cmd.stdin(Stdio::piped()).spawn()); + t!(child.stdin.take().unwrap().write_all(pass.as_bytes())); + let status = t!(child.wait()); + assert!(status.success()); +} diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index d1c9918a73373..3dc9b8375550c 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -22,7 +22,8 @@ use std::io::prelude::*; use std::process::Command; use {Build, Compiler, Mode}; -use util::{up_to_date, cp_r}; +use util::cp_r; +use build_helper::up_to_date; /// Invoke `rustbook` as compiled in `stage` for `target` for the doc book /// `name` into the `out` path. diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index db2fe2db813a6..df1218752d1c9 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -66,6 +66,7 @@ #![deny(warnings)] +#[macro_use] extern crate build_helper; extern crate cmake; extern crate filetime; @@ -83,24 +84,9 @@ use std::fs::{self, File}; use std::path::{Component, PathBuf, Path}; use std::process::Command; -use build_helper::{run_silent, output}; +use build_helper::{run_silent, output, mtime}; -use util::{exe, mtime, libdir, add_lib_path}; - -/// A helper macro to `unwrap` a result except also print out details like: -/// -/// * The file/line of the panic -/// * The expression that failed -/// * The error itself -/// -/// This is currently used judiciously throughout the build system rather than -/// using a `Result` with `try!`, but this may change one day... -macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {}", stringify!($e), e), - }) -} +use util::{exe, libdir, add_lib_path}; mod cc; mod channel; @@ -482,7 +468,8 @@ impl Build { // // These variables are primarily all read by // src/bootstrap/bin/{rustc.rs,rustdoc.rs} - cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc")) + cargo.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target)) + .env("RUSTC", self.out.join("bootstrap/debug/rustc")) .env("RUSTC_REAL", self.compiler_path(compiler)) .env("RUSTC_STAGE", stage.to_string()) .env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()) @@ -746,10 +733,15 @@ impl Build { } } + /// Directory for libraries built from C/C++ code and shared between stages. + fn native_dir(&self, target: &str) -> PathBuf { + self.out.join(target).join("native") + } + /// Root output directory for rust_test_helpers library compiled for /// `target` fn test_helpers_out(&self, target: &str) -> PathBuf { - self.out.join(target).join("rust-test-helpers") + self.native_dir(target).join("rust-test-helpers") } /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 4b6fef8edc17f..21fc61cc81484 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -28,7 +28,8 @@ use cmake; use gcc; use Build; -use util::{self, up_to_date}; +use util; +use build_helper::up_to_date; /// Compile LLVM for `target`. pub fn llvm(build: &Build, target: &str) { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 697b14c6050cc..3932a7cf8c563 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -513,6 +513,9 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.build("tool-compiletest", "src/tools/compiletest") .dep(|s| s.name("libtest")) .run(move |s| compile::tool(build, s.stage, s.target, "compiletest")); + rules.build("tool-build-manifest", "src/tools/build-manifest") + .dep(|s| s.name("libstd")) + .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest")); // ======================================================================== // Documentation targets @@ -633,6 +636,13 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|d| d.name("dist-cargo")) .run(move |s| dist::extended(build, s.stage, s.target)); + rules.dist("dist-sign", "hash-and-sign") + .host(true) + .only_build(true) + .only_host_build(true) + .dep(move |s| s.name("tool-build-manifest").target(&build.config.build).stage(0)) + .run(move |_| dist::hash_and_sign(build)); + rules.verify(); return rules; } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 2ab3776ada096..520514f5fc95a 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -20,8 +20,6 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::time::Instant; -use filetime::FileTime; - /// Returns the `name` as the filename of a static library for `target`. pub fn staticlib(name: &str, target: &str) -> String { if target.contains("windows") { @@ -31,13 +29,6 @@ pub fn staticlib(name: &str, target: &str) -> String { } } -/// Returns the last-modified time for `path`, or zero if it doesn't exist. -pub fn mtime(path: &Path) -> FileTime { - fs::metadata(path).map(|f| { - FileTime::from_last_modification_time(&f) - }).unwrap_or(FileTime::zero()) -} - /// Copies a file from `src` to `dst`, attempting to use hard links and then /// falling back to an actually filesystem copy if necessary. pub fn copy(src: &Path, dst: &Path) { @@ -132,34 +123,6 @@ pub fn add_lib_path(path: Vec, cmd: &mut Command) { cmd.env(dylib_path_var(), t!(env::join_paths(list))); } -/// Returns whether `dst` is up to date given that the file or files in `src` -/// are used to generate it. -/// -/// Uses last-modified time checks to verify this. -pub fn up_to_date(src: &Path, dst: &Path) -> bool { - let threshold = mtime(dst); - let meta = match fs::metadata(src) { - Ok(meta) => meta, - Err(e) => panic!("source {:?} failed to get metadata: {}", src, e), - }; - if meta.is_dir() { - dir_up_to_date(src, &threshold) - } else { - FileTime::from_last_modification_time(&meta) <= threshold - } -} - -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()); - if meta.is_dir() { - dir_up_to_date(&e.path(), threshold) - } else { - FileTime::from_last_modification_time(&meta) < *threshold - } - }) -} - /// Returns the environment variable which the dynamic library lookup path /// resides in for this platform. pub fn dylib_path_var() -> &'static str { diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml index 01d704f816bbc..f8ade0616a577 100644 --- a/src/build_helper/Cargo.toml +++ b/src/build_helper/Cargo.toml @@ -6,3 +6,6 @@ authors = ["The Rust Project Developers"] [lib] name = "build_helper" path = "lib.rs" + +[dependencies] +filetime = "0.1" diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index d0d588f46a754..3dfd293808286 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -10,9 +10,30 @@ #![deny(warnings)] +extern crate filetime; + +use std::fs; use std::process::{Command, Stdio}; use std::path::{Path, PathBuf}; +use filetime::FileTime; + +/// A helper macro to `unwrap` a result except also print out details like: +/// +/// * The file/line of the panic +/// * The expression that failed +/// * The error itself +/// +/// This is currently used judiciously throughout the build system rather than +/// using a `Result` with `try!`, but this may change one day... +#[macro_export] +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + pub fn run(cmd: &mut Command) { println!("running: {:?}", cmd); run_silent(cmd); @@ -88,6 +109,56 @@ pub fn output(cmd: &mut Command) -> String { String::from_utf8(output.stdout).unwrap() } +pub fn rerun_if_changed_anything_in_dir(dir: &Path) { + let mut stack = dir.read_dir().unwrap() + .map(|e| e.unwrap()) + .filter(|e| &*e.file_name() != ".git") + .collect::>(); + while let Some(entry) = stack.pop() { + let path = entry.path(); + if entry.file_type().unwrap().is_dir() { + stack.extend(path.read_dir().unwrap().map(|e| e.unwrap())); + } else { + println!("cargo:rerun-if-changed={}", path.display()); + } + } +} + +/// Returns the last-modified time for `path`, or zero if it doesn't exist. +pub fn mtime(path: &Path) -> FileTime { + fs::metadata(path).map(|f| { + FileTime::from_last_modification_time(&f) + }).unwrap_or(FileTime::zero()) +} + +/// Returns whether `dst` is up to date given that the file or files in `src` +/// are used to generate it. +/// +/// Uses last-modified time checks to verify this. +pub fn up_to_date(src: &Path, dst: &Path) -> bool { + let threshold = mtime(dst); + let meta = match fs::metadata(src) { + Ok(meta) => meta, + Err(e) => panic!("source {:?} failed to get metadata: {}", src, e), + }; + if meta.is_dir() { + dir_up_to_date(src, &threshold) + } else { + FileTime::from_last_modification_time(&meta) <= threshold + } +} + +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()); + if meta.is_dir() { + dir_up_to_date(&e.path(), threshold) + } else { + FileTime::from_last_modification_time(&meta) < *threshold + } + }) +} + fn fail(s: &str) -> ! { println!("\n\n{}\n\n", s); std::process::exit(1); diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 9a0a4c8cb530a..52f74ba90de6e 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -143,3 +143,58 @@ For targets: `aarch64-unknown-linux-gnu` - C-library > glibc version = 2.17 -- aarch64 support was introduced in this version - C compiler > gcc version = 5.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM + +## `powerpc-linux-gnu.config` + +For targets: `powerpc-unknown-linux-gnu` + +- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Patches origin = Bundled, then local +- Path and misc options > Local patch directory = /tmp/patches +- Target options > Target Architecture = powerpc +- Target options > Emit assembly for CPU = power4 -- (+) +- Target options > Tune for CPU = power6 -- (+) +- Operating System > Target OS = linux +- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel +- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc +- C compiler > gcc version = 4.9.3 +- C compiler > Core gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) +- C compiler > gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) +- C compiler > C++ = ENABLE -- to cross compile LLVM + +(+) These CPU options match the configuration of the toolchains in RHEL6. + +## `powerpc64-linux-gnu.config` + +For targets: `powerpc64-unknown-linux-gnu` + +- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Patches origin = Bundled, then local +- Path and misc options > Local patch directory = /tmp/patches +- Target options > Target Architecture = powerpc +- Target options > Bitness = 64-bit +- Target options > Emit assembly for CPU = power4 -- (+) +- Target options > Tune for CPU = power6 -- (+) +- Operating System > Target OS = linux +- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel +- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc +- C compiler > gcc version = 4.9.3 +- C compiler > C++ = ENABLE -- to cross compile LLVM + +(+) These CPU options match the configuration of the toolchains in RHEL6. + +## `s390x-linux-gnu.config` + +For targets: `s390x-unknown-linux-gnu` + +- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Patches origin = Bundled, then local +- Path and misc options > Local patch directory = /build/patches +- Target options > Target Architecture = s390 +- Target options > Bitness = 64-bit +- Operating System > Target OS = linux +- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel +- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc +- C compiler > gcc version = 4.9.3 +- C compiler > gcc extra config = --with-arch=z10 -- LLVM's minimum support +- C compiler > C++ = ENABLE -- to cross compile LLVM diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index ed4e9a35960f6..640bacc54eb30 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -1,18 +1,29 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ make \ - file \ - curl \ - ca-certificates \ + patch \ python2.7 \ - git \ - cmake \ sudo \ - gdb \ - xz-utils \ - g++-powerpc-linux-gnu + texinfo \ + wget \ + xz-utils ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783 RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \ @@ -23,6 +34,43 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini rm dumb-init_*.deb ENTRYPOINT ["/usr/bin/dumb-init", "--"] +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY patches/ /tmp/patches/ +COPY powerpc-linux-gnu.config build-powerpc-toolchain.sh /tmp/ +RUN ./build-powerpc-toolchain.sh + +USER root + +ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin + +ENV \ + CC_powerpc_unknown_linux_gnu=powerpc-unknown-linux-gnu-gcc \ + AR_powerpc_unknown_linux_gnu=powerpc-unknown-linux-gnu-ar \ + CXX_powerpc_unknown_linux_gnu=powerpc-unknown-linux-gnu-g++ + ENV HOSTS=powerpc-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended diff --git a/src/ci/docker/dist-powerpc-linux/build-powerpc-toolchain.sh b/src/ci/docker/dist-powerpc-linux/build-powerpc-toolchain.sh new file mode 100755 index 0000000000000..90a4df0c19583 --- /dev/null +++ b/src/ci/docker/dist-powerpc-linux/build-powerpc-toolchain.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# 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. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../powerpc-linux-gnu.config .config +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-powerpc-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch b/src/ci/docker/dist-powerpc-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch new file mode 100644 index 0000000000000..744eb180cd1f6 --- /dev/null +++ b/src/ci/docker/dist-powerpc-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch @@ -0,0 +1,24 @@ +From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001 +From: Tulio Magno Quites Machado Filho +Date: Thu, 1 Nov 2012 18:00:06 -0500 +Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics. + +--- + sysdeps/powerpc/Makefile | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile +index 79dd6fa976d5..7442b6709ad1 100644 +--- a/sysdeps/powerpc/Makefile ++++ b/sysdeps/powerpc/Makefile +@@ -1,7 +1,3 @@ +-# We always want to use the new mnemonic syntax even if we are on a RS6000 +-# machine. +-+cflags += -mnew-mnemonics +- + ifeq ($(subdir),gmon) + sysdep_routines += ppc-mcount + endif +-- +2.9.3 + diff --git a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config new file mode 100644 index 0000000000000..26e2de863a0f9 --- /dev/null +++ b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config @@ -0,0 +1,528 @@ +# +# Automatically generated file; DO NOT EDIT. +# Crosstool-NG Configuration +# +CT_CONFIGURE_has_make381=y +CT_CONFIGURE_has_xz=y +CT_MODULES=y + +# +# Paths and misc options +# + +# +# crosstool-NG behavior +# +# CT_OBSOLETE is not set +# CT_EXPERIMENTAL is not set +# CT_DEBUG_CT is not set + +# +# Paths +# +CT_LOCAL_TARBALLS_DIR="" +CT_WORK_DIR="${CT_TOP_DIR}/.build" +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_INSTALL_DIR="${CT_PREFIX_DIR}" +CT_RM_RF_PREFIX_DIR=y +CT_REMOVE_DOCS=y +CT_INSTALL_DIR_RO=y +CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y +# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set + +# +# Downloading +# +# CT_FORBID_DOWNLOAD is not set +# CT_FORCE_DOWNLOAD is not set +CT_CONNECT_TIMEOUT=10 +# CT_ONLY_DOWNLOAD is not set +# CT_USE_MIRROR is not set + +# +# Extracting +# +# CT_FORCE_EXTRACT is not set +CT_OVERIDE_CONFIG_GUESS_SUB=y +# CT_ONLY_EXTRACT is not set +# CT_PATCH_BUNDLED is not set +# CT_PATCH_LOCAL is not set +CT_PATCH_BUNDLED_LOCAL=y +# CT_PATCH_LOCAL_BUNDLED is not set +# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set +# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set +# CT_PATCH_NONE is not set +CT_PATCH_ORDER="bundled,local" +CT_PATCH_USE_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" + +# +# Build behavior +# +CT_PARALLEL_JOBS=0 +CT_LOAD="" +CT_USE_PIPES=y +CT_EXTRA_CFLAGS_FOR_BUILD="" +CT_EXTRA_LDFLAGS_FOR_BUILD="" +CT_EXTRA_CFLAGS_FOR_HOST="" +CT_EXTRA_LDFLAGS_FOR_HOST="" +# CT_CONFIG_SHELL_SH is not set +# CT_CONFIG_SHELL_ASH is not set +CT_CONFIG_SHELL_BASH=y +# CT_CONFIG_SHELL_CUSTOM is not set +CT_CONFIG_SHELL="${bash}" + +# +# Logging +# +# CT_LOG_ERROR is not set +# CT_LOG_WARN is not set +CT_LOG_INFO=y +# CT_LOG_EXTRA is not set +# CT_LOG_ALL is not set +# CT_LOG_DEBUG is not set +CT_LOG_LEVEL_MAX="INFO" +# CT_LOG_SEE_TOOLS_WARN is not set +CT_LOG_PROGRESS_BAR=y +CT_LOG_TO_FILE=y +CT_LOG_FILE_COMPRESS=y + +# +# Target options +# +CT_ARCH="powerpc" +CT_ARCH_SUPPORTS_BOTH_ENDIAN=y +CT_ARCH_SUPPORTS_32=y +CT_ARCH_SUPPORTS_64=y +CT_ARCH_SUPPORTS_WITH_ABI=y +CT_ARCH_SUPPORTS_WITH_CPU=y +CT_ARCH_SUPPORTS_WITH_TUNE=y +CT_ARCH_SUPPORTS_WITH_FLOAT=y +CT_ARCH_DEFAULT_BE=y +CT_ARCH_DEFAULT_32=y +CT_ARCH_ABI="" +CT_ARCH_CPU="power4" +CT_ARCH_TUNE="power6" +CT_ARCH_BE=y +# CT_ARCH_LE is not set +CT_ARCH_32=y +# CT_ARCH_64 is not set +CT_ARCH_BITNESS=32 +# CT_ARCH_FLOAT_HW is not set +# CT_ARCH_FLOAT_SW is not set +CT_TARGET_CFLAGS="" +CT_TARGET_LDFLAGS="" +# CT_ARCH_alpha is not set +# CT_ARCH_arm is not set +# CT_ARCH_avr is not set +# CT_ARCH_m68k is not set +# CT_ARCH_mips is not set +# CT_ARCH_nios2 is not set +CT_ARCH_powerpc=y +# CT_ARCH_s390 is not set +# CT_ARCH_sh is not set +# CT_ARCH_sparc is not set +# CT_ARCH_x86 is not set +# CT_ARCH_xtensa is not set +CT_ARCH_alpha_AVAILABLE=y +CT_ARCH_arm_AVAILABLE=y +CT_ARCH_avr_AVAILABLE=y +CT_ARCH_m68k_AVAILABLE=y +CT_ARCH_microblaze_AVAILABLE=y +CT_ARCH_mips_AVAILABLE=y +CT_ARCH_nios2_AVAILABLE=y +CT_ARCH_powerpc_AVAILABLE=y +CT_ARCH_s390_AVAILABLE=y +CT_ARCH_sh_AVAILABLE=y +CT_ARCH_sparc_AVAILABLE=y +CT_ARCH_x86_AVAILABLE=y +CT_ARCH_xtensa_AVAILABLE=y +CT_ARCH_SUFFIX="" + +# +# Generic target options +# +# CT_MULTILIB is not set +CT_ARCH_USE_MMU=y +CT_ARCH_ENDIAN="big" + +# +# Target optimisations +# +CT_ARCH_FLOAT_AUTO=y +CT_ARCH_FLOAT="auto" + +# +# powerpc other options +# +CT_ARCH_powerpc_ABI="" +CT_ARCH_powerpc_ABI_DEFAULT=y +# CT_ARCH_powerpc_ABI_SPE is not set + +# +# Toolchain options +# + +# +# General toolchain options +# +CT_FORCE_SYSROOT=y +CT_USE_SYSROOT=y +CT_SYSROOT_NAME="sysroot" +CT_SYSROOT_DIR_PREFIX="" +CT_WANTS_STATIC_LINK=y +# CT_STATIC_TOOLCHAIN is not set +CT_TOOLCHAIN_PKGVERSION="" +CT_TOOLCHAIN_BUGURL="" + +# +# Tuple completion and aliasing +# +CT_TARGET_VENDOR="unknown" +CT_TARGET_ALIAS_SED_EXPR="" +CT_TARGET_ALIAS="" + +# +# Toolchain type +# +CT_CROSS=y +# CT_CANADIAN is not set +CT_TOOLCHAIN_TYPE="cross" + +# +# Build system +# +CT_BUILD="" +CT_BUILD_PREFIX="" +CT_BUILD_SUFFIX="" + +# +# Misc options +# +# CT_TOOLCHAIN_ENABLE_NLS is not set + +# +# Operating System +# +CT_KERNEL_SUPPORTS_SHARED_LIBS=y +CT_KERNEL="linux" +CT_KERNEL_VERSION="2.6.32.68" +# CT_KERNEL_bare_metal is not set +CT_KERNEL_linux=y +CT_KERNEL_bare_metal_AVAILABLE=y +CT_KERNEL_linux_AVAILABLE=y +# CT_KERNEL_V_4_3 is not set +# CT_KERNEL_V_4_2 is not set +# CT_KERNEL_V_4_1 is not set +# CT_KERNEL_V_3_18 is not set +# CT_KERNEL_V_3_14 is not set +# CT_KERNEL_V_3_12 is not set +# CT_KERNEL_V_3_10 is not set +# CT_KERNEL_V_3_4 is not set +# CT_KERNEL_V_3_2 is not set +CT_KERNEL_V_2_6_32=y +# CT_KERNEL_LINUX_CUSTOM is not set +CT_KERNEL_windows_AVAILABLE=y + +# +# Common kernel options +# +CT_SHARED_LIBS=y + +# +# linux other options +# +CT_KERNEL_LINUX_VERBOSITY_0=y +# CT_KERNEL_LINUX_VERBOSITY_1 is not set +# CT_KERNEL_LINUX_VERBOSITY_2 is not set +CT_KERNEL_LINUX_VERBOSE_LEVEL=0 +CT_KERNEL_LINUX_INSTALL_CHECK=y + +# +# Binary utilities +# +CT_ARCH_BINFMT_ELF=y +CT_BINUTILS="binutils" +CT_BINUTILS_binutils=y + +# +# GNU binutils +# +# CT_CC_BINUTILS_SHOW_LINARO is not set +CT_BINUTILS_V_2_25_1=y +# CT_BINUTILS_V_2_25 is not set +# CT_BINUTILS_V_2_24 is not set +# CT_BINUTILS_V_2_23_2 is not set +# CT_BINUTILS_V_2_23_1 is not set +# CT_BINUTILS_V_2_22 is not set +# CT_BINUTILS_V_2_21_53 is not set +# CT_BINUTILS_V_2_21_1a is not set +# CT_BINUTILS_V_2_20_1a is not set +# CT_BINUTILS_V_2_19_1a is not set +# CT_BINUTILS_V_2_18a is not set +CT_BINUTILS_VERSION="2.25.1" +CT_BINUTILS_2_25_1_or_later=y +CT_BINUTILS_2_25_or_later=y +CT_BINUTILS_2_24_or_later=y +CT_BINUTILS_2_23_or_later=y +CT_BINUTILS_2_22_or_later=y +CT_BINUTILS_2_21_or_later=y +CT_BINUTILS_2_20_or_later=y +CT_BINUTILS_2_19_or_later=y +CT_BINUTILS_2_18_or_later=y +CT_BINUTILS_HAS_HASH_STYLE=y +CT_BINUTILS_HAS_GOLD=y +CT_BINUTILS_HAS_PLUGINS=y +CT_BINUTILS_HAS_PKGVERSION_BUGURL=y +CT_BINUTILS_FORCE_LD_BFD=y +CT_BINUTILS_LINKER_LD=y +CT_BINUTILS_LINKERS_LIST="ld" +CT_BINUTILS_LINKER_DEFAULT="bfd" +# CT_BINUTILS_PLUGINS is not set +CT_BINUTILS_EXTRA_CONFIG_ARRAY="" +# CT_BINUTILS_FOR_TARGET is not set + +# +# binutils other options +# + +# +# C-library +# +CT_LIBC="glibc" +CT_LIBC_VERSION="2.12.2" +CT_LIBC_glibc=y +# CT_LIBC_musl is not set +# CT_LIBC_uClibc is not set +CT_LIBC_avr_libc_AVAILABLE=y +CT_LIBC_glibc_AVAILABLE=y +CT_THREADS="nptl" +# CT_CC_GLIBC_SHOW_LINARO is not set +# CT_LIBC_GLIBC_V_2_22 is not set +# CT_LIBC_GLIBC_V_2_21 is not set +# CT_LIBC_GLIBC_V_2_20 is not set +# CT_LIBC_GLIBC_V_2_19 is not set +# CT_LIBC_GLIBC_V_2_18 is not set +# CT_LIBC_GLIBC_V_2_17 is not set +# CT_LIBC_GLIBC_V_2_16_0 is not set +# CT_LIBC_GLIBC_V_2_15 is not set +# CT_LIBC_GLIBC_V_2_14_1 is not set +# CT_LIBC_GLIBC_V_2_14 is not set +# CT_LIBC_GLIBC_V_2_13 is not set +CT_LIBC_GLIBC_V_2_12_2=y +# CT_LIBC_GLIBC_V_2_12_1 is not set +# CT_LIBC_GLIBC_V_2_11_1 is not set +# CT_LIBC_GLIBC_V_2_11 is not set +# CT_LIBC_GLIBC_V_2_10_1 is not set +# CT_LIBC_GLIBC_V_2_9 is not set +# CT_LIBC_GLIBC_V_2_8 is not set +CT_LIBC_mingw_AVAILABLE=y +CT_LIBC_musl_AVAILABLE=y +CT_LIBC_newlib_AVAILABLE=y +CT_LIBC_none_AVAILABLE=y +CT_LIBC_uClibc_AVAILABLE=y +CT_LIBC_SUPPORT_THREADS_ANY=y +CT_LIBC_SUPPORT_THREADS_NATIVE=y + +# +# Common C library options +# +CT_THREADS_NATIVE=y +CT_LIBC_XLDD=y + +# +# glibc other options +# +CT_LIBC_GLIBC_PORTS_EXTERNAL=y +CT_LIBC_glibc_familly=y +CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY="" +CT_LIBC_GLIBC_CONFIGPARMS="" +CT_LIBC_GLIBC_EXTRA_CFLAGS="" +CT_LIBC_EXTRA_CC_ARGS="" +# CT_LIBC_DISABLE_VERSIONING is not set +CT_LIBC_OLDEST_ABI="" +CT_LIBC_GLIBC_FORCE_UNWIND=y +# CT_LIBC_GLIBC_USE_PORTS is not set +CT_LIBC_ADDONS_LIST="" +# CT_LIBC_LOCALES is not set +# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set +CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y +# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set +CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68" + +# +# C compiler +# +CT_CC="gcc" +CT_CC_CORE_PASSES_NEEDED=y +CT_CC_CORE_PASS_1_NEEDED=y +CT_CC_CORE_PASS_2_NEEDED=y +CT_CC_gcc=y +# CT_CC_GCC_SHOW_LINARO is not set +# CT_CC_GCC_V_5_2_0 is not set +CT_CC_GCC_V_4_9_3=y +# CT_CC_GCC_V_4_8_5 is not set +# CT_CC_GCC_V_4_7_4 is not set +# CT_CC_GCC_V_4_6_4 is not set +# CT_CC_GCC_V_4_5_4 is not set +# CT_CC_GCC_V_4_4_7 is not set +# CT_CC_GCC_V_4_3_6 is not set +# CT_CC_GCC_V_4_2_4 is not set +CT_CC_GCC_4_2_or_later=y +CT_CC_GCC_4_3_or_later=y +CT_CC_GCC_4_4_or_later=y +CT_CC_GCC_4_5_or_later=y +CT_CC_GCC_4_6_or_later=y +CT_CC_GCC_4_7_or_later=y +CT_CC_GCC_4_8_or_later=y +CT_CC_GCC_4_9=y +CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_HAS_GRAPHITE=y +CT_CC_GCC_USE_GRAPHITE=y +CT_CC_GCC_HAS_LTO=y +CT_CC_GCC_USE_LTO=y +CT_CC_GCC_HAS_PKGVERSION_BUGURL=y +CT_CC_GCC_HAS_BUILD_ID=y +CT_CC_GCC_HAS_LNK_HASH_STYLE=y +CT_CC_GCC_USE_GMP_MPFR=y +CT_CC_GCC_USE_MPC=y +CT_CC_GCC_HAS_LIBQUADMATH=y +CT_CC_GCC_HAS_LIBSANITIZER=y +CT_CC_GCC_VERSION="4.9.3" +# CT_CC_LANG_FORTRAN is not set +CT_CC_GCC_ENABLE_CXX_FLAGS="" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" +CT_CC_GCC_EXTRA_ENV_ARRAY="" +CT_CC_GCC_STATIC_LIBSTDCXX=y +# CT_CC_GCC_SYSTEM_ZLIB is not set + +# +# Optimisation features +# + +# +# Settings for libraries running on target +# +CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y +# CT_CC_GCC_LIBMUDFLAP is not set +# CT_CC_GCC_LIBGOMP is not set +# CT_CC_GCC_LIBSSP is not set +# CT_CC_GCC_LIBQUADMATH is not set +# CT_CC_GCC_LIBSANITIZER is not set + +# +# Misc. obscure options. +# +CT_CC_CXA_ATEXIT=y +# CT_CC_GCC_DISABLE_PCH is not set +CT_CC_GCC_SJLJ_EXCEPTIONS=m +CT_CC_GCC_LDBL_128=m +# CT_CC_GCC_BUILD_ID is not set +CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y +# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set +# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set +# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set +CT_CC_GCC_LNK_HASH_STYLE="" +CT_CC_GCC_DEC_FLOAT_AUTO=y +# CT_CC_GCC_DEC_FLOAT_BID is not set +# CT_CC_GCC_DEC_FLOAT_DPD is not set +# CT_CC_GCC_DEC_FLOATS_NO is not set +CT_CC_SUPPORT_CXX=y +CT_CC_SUPPORT_FORTRAN=y +CT_CC_SUPPORT_JAVA=y +CT_CC_SUPPORT_ADA=y +CT_CC_SUPPORT_OBJC=y +CT_CC_SUPPORT_OBJCXX=y +CT_CC_SUPPORT_GOLANG=y + +# +# Additional supported languages: +# +CT_CC_LANG_CXX=y +# CT_CC_LANG_JAVA is not set + +# +# Debug facilities +# +# CT_DEBUG_dmalloc is not set +# CT_DEBUG_duma is not set +# CT_DEBUG_gdb is not set +# CT_DEBUG_ltrace is not set +# CT_DEBUG_strace is not set + +# +# Companion libraries +# +CT_COMPLIBS_NEEDED=y +CT_LIBICONV_NEEDED=y +CT_GETTEXT_NEEDED=y +CT_GMP_NEEDED=y +CT_MPFR_NEEDED=y +CT_ISL_NEEDED=y +CT_CLOOG_NEEDED=y +CT_MPC_NEEDED=y +CT_COMPLIBS=y +CT_LIBICONV=y +CT_GETTEXT=y +CT_GMP=y +CT_MPFR=y +CT_ISL=y +CT_CLOOG=y +CT_MPC=y +CT_LIBICONV_V_1_14=y +CT_LIBICONV_VERSION="1.14" +CT_GETTEXT_V_0_19_6=y +CT_GETTEXT_VERSION="0.19.6" +CT_GMP_V_6_0_0=y +# CT_GMP_V_5_1_3 is not set +# CT_GMP_V_5_1_1 is not set +# CT_GMP_V_5_0_2 is not set +# CT_GMP_V_5_0_1 is not set +# CT_GMP_V_4_3_2 is not set +# CT_GMP_V_4_3_1 is not set +# CT_GMP_V_4_3_0 is not set +CT_GMP_5_0_2_or_later=y +CT_GMP_VERSION="6.0.0a" +CT_MPFR_V_3_1_3=y +# CT_MPFR_V_3_1_2 is not set +# CT_MPFR_V_3_1_0 is not set +# CT_MPFR_V_3_0_1 is not set +# CT_MPFR_V_3_0_0 is not set +# CT_MPFR_V_2_4_2 is not set +# CT_MPFR_V_2_4_1 is not set +# CT_MPFR_V_2_4_0 is not set +CT_MPFR_VERSION="3.1.3" +CT_ISL_V_0_14=y +CT_ISL_V_0_14_or_later=y +CT_ISL_V_0_12_or_later=y +CT_ISL_VERSION="0.14" +CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_1 is not set +# CT_CLOOG_V_0_18_0 is not set +CT_CLOOG_VERSION="0.18.4" +CT_CLOOG_0_18_4_or_later=y +CT_CLOOG_0_18_or_later=y +CT_MPC_V_1_0_3=y +# CT_MPC_V_1_0_2 is not set +# CT_MPC_V_1_0_1 is not set +# CT_MPC_V_1_0 is not set +# CT_MPC_V_0_9 is not set +# CT_MPC_V_0_8_2 is not set +# CT_MPC_V_0_8_1 is not set +# CT_MPC_V_0_7 is not set +CT_MPC_VERSION="1.0.3" + +# +# Companion libraries common options +# +# CT_COMPLIBS_CHECK is not set + +# +# Companion tools +# + +# +# READ HELP before you say 'Y' below !!! +# +# CT_COMP_TOOLS is not set diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 6c04048f4ddf8..624763ef5de67 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -1,19 +1,29 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ make \ - file \ - curl \ - ca-certificates \ + patch \ python2.7 \ - git \ - cmake \ sudo \ - gdb \ - xz-utils \ - g++-powerpc64-linux-gnu \ - g++-powerpc64le-linux-gnu + texinfo \ + wget \ + xz-utils ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783 RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \ @@ -24,10 +34,49 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini rm dumb-init_*.deb ENTRYPOINT ["/usr/bin/dumb-init", "--"] +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY patches/ /tmp/patches/ +COPY powerpc64-linux-gnu.config build-powerpc64-toolchain.sh /tmp/ +RUN ./build-powerpc64-toolchain.sh + +USER root + +RUN apt-get install -y --no-install-recommends rpm2cpio cpio +COPY build-powerpc64le-toolchain.sh /tmp/ +RUN ./build-powerpc64le-toolchain.sh + +ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin + ENV \ - AR_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-ar \ - CC_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-gcc \ - CXX_powerpc64_unknown_linux_gnu=powerpc64-linux-gnu-g++ + AR_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-ar \ + CC_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-gcc \ + CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ \ + AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ + CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ + CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ ENV HOSTS=powerpc64-unknown-linux-gnu ENV HOSTS=$HOSTS,powerpc64le-unknown-linux-gnu diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh b/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh new file mode 100755 index 0000000000000..d70947d2dd9d6 --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/build-powerpc64-toolchain.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# 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. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../powerpc64-linux-gnu.config .config +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh new file mode 100755 index 0000000000000..8b924ca34c47c --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# 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. + +set -ex + +BINUTILS=2.25.1 +GCC=5.3.0 +TARGET=powerpc64le-linux-gnu +SYSROOT=/usr/local/$TARGET/sysroot + +# First, download the CentOS7 glibc.ppc64le and relevant header files. +# (upstream ppc64le support wasn't added until 2.19, which el7 backported.) +mkdir -p $SYSROOT +pushd $SYSROOT + +centos_base=http://mirror.centos.org/altarch/7.3.1611/os/ppc64le/Packages +glibc_v=2.17-157.el7 +kernel_v=3.10.0-514.el7 +for package in glibc{,-devel,-headers}-$glibc_v kernel-headers-$kernel_v; do + curl $centos_base/$package.ppc64le.rpm | \ + rpm2cpio - | cpio -idm +done + +ln -sT lib64 lib +ln -sT lib64 usr/lib + +popd + +# Next, download and build binutils. +mkdir binutils-$TARGET +pushd binutils-$TARGET +curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - +mkdir binutils-build +cd binutils-build +../binutils-$BINUTILS/configure --target=$TARGET --with-sysroot=$SYSROOT +make -j10 +make install +popd +rm -rf binutils-$TARGET + +# Finally, download and build gcc. +mkdir gcc-$TARGET +pushd gcc-$TARGET +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites + +mkdir ../gcc-build +cd ../gcc-build +../gcc-$GCC/configure \ + --enable-languages=c,c++ \ + --target=$TARGET \ + --with-cpu=power8 \ + --with-sysroot=$SYSROOT \ + --disable-libcilkrts \ + --disable-multilib \ + --disable-nls \ + --disable-libgomp \ + --disable-libquadmath \ + --disable-libssp \ + --disable-libvtv \ + --disable-libcilkrt \ + --disable-libada \ + --disable-libsanitizer \ + --disable-libquadmath-support \ + --disable-lto +make -j10 +make install + +popd +rm -rf gcc-$TARGET diff --git a/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch b/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch new file mode 100644 index 0000000000000..744eb180cd1f6 --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch @@ -0,0 +1,24 @@ +From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001 +From: Tulio Magno Quites Machado Filho +Date: Thu, 1 Nov 2012 18:00:06 -0500 +Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics. + +--- + sysdeps/powerpc/Makefile | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile +index 79dd6fa976d5..7442b6709ad1 100644 +--- a/sysdeps/powerpc/Makefile ++++ b/sysdeps/powerpc/Makefile +@@ -1,7 +1,3 @@ +-# We always want to use the new mnemonic syntax even if we are on a RS6000 +-# machine. +-+cflags += -mnew-mnemonics +- + ifeq ($(subdir),gmon) + sysdep_routines += ppc-mcount + endif +-- +2.9.3 + diff --git a/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/002-Prevent-inlining-in-PPC64-initfini.s.patch b/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/002-Prevent-inlining-in-PPC64-initfini.s.patch new file mode 100644 index 0000000000000..47cc8b28d225a --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/002-Prevent-inlining-in-PPC64-initfini.s.patch @@ -0,0 +1,26 @@ +From a4f388e111ce05e2ab7912cff3c9070334bb74ae Mon Sep 17 00:00:00 2001 +From: Josh Stone +Date: Fri, 20 Jan 2017 15:41:56 -0800 +Subject: [PATCH] Prevent inlining in PPC64 initfini.s + +Ref: https://sourceware.org/ml/libc-alpha/2012-01/msg00195.html +--- + sysdeps/powerpc/powerpc64/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/powerpc/powerpc64/Makefile b/sysdeps/powerpc/powerpc64/Makefile +index 78d4f07e575f..fe96aae4d43e 100644 +--- a/sysdeps/powerpc/powerpc64/Makefile ++++ b/sysdeps/powerpc/powerpc64/Makefile +@@ -28,7 +28,7 @@ elide-routines.os += hp-timing + ifneq ($(elf),no) + # The initfini generation code doesn't work in the presence of -fPIC, so + # we use -fpic instead which is much better. +-CFLAGS-initfini.s += -fpic -O1 ++CFLAGS-initfini.s += -fpic -O1 -fno-inline + endif + endif + +-- +2.9.3 + diff --git a/src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config b/src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config new file mode 100644 index 0000000000000..c2d02ee85cf25 --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config @@ -0,0 +1,528 @@ +# +# Automatically generated file; DO NOT EDIT. +# Crosstool-NG Configuration +# +CT_CONFIGURE_has_make381=y +CT_CONFIGURE_has_xz=y +CT_MODULES=y + +# +# Paths and misc options +# + +# +# crosstool-NG behavior +# +# CT_OBSOLETE is not set +# CT_EXPERIMENTAL is not set +# CT_DEBUG_CT is not set + +# +# Paths +# +CT_LOCAL_TARBALLS_DIR="" +CT_WORK_DIR="${CT_TOP_DIR}/.build" +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_INSTALL_DIR="${CT_PREFIX_DIR}" +CT_RM_RF_PREFIX_DIR=y +CT_REMOVE_DOCS=y +CT_INSTALL_DIR_RO=y +CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y +# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set + +# +# Downloading +# +# CT_FORBID_DOWNLOAD is not set +# CT_FORCE_DOWNLOAD is not set +CT_CONNECT_TIMEOUT=10 +# CT_ONLY_DOWNLOAD is not set +# CT_USE_MIRROR is not set + +# +# Extracting +# +# CT_FORCE_EXTRACT is not set +CT_OVERIDE_CONFIG_GUESS_SUB=y +# CT_ONLY_EXTRACT is not set +# CT_PATCH_BUNDLED is not set +# CT_PATCH_LOCAL is not set +CT_PATCH_BUNDLED_LOCAL=y +# CT_PATCH_LOCAL_BUNDLED is not set +# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set +# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set +# CT_PATCH_NONE is not set +CT_PATCH_ORDER="bundled,local" +CT_PATCH_USE_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" + +# +# Build behavior +# +CT_PARALLEL_JOBS=0 +CT_LOAD="" +CT_USE_PIPES=y +CT_EXTRA_CFLAGS_FOR_BUILD="" +CT_EXTRA_LDFLAGS_FOR_BUILD="" +CT_EXTRA_CFLAGS_FOR_HOST="" +CT_EXTRA_LDFLAGS_FOR_HOST="" +# CT_CONFIG_SHELL_SH is not set +# CT_CONFIG_SHELL_ASH is not set +CT_CONFIG_SHELL_BASH=y +# CT_CONFIG_SHELL_CUSTOM is not set +CT_CONFIG_SHELL="${bash}" + +# +# Logging +# +# CT_LOG_ERROR is not set +# CT_LOG_WARN is not set +CT_LOG_INFO=y +# CT_LOG_EXTRA is not set +# CT_LOG_ALL is not set +# CT_LOG_DEBUG is not set +CT_LOG_LEVEL_MAX="INFO" +# CT_LOG_SEE_TOOLS_WARN is not set +CT_LOG_PROGRESS_BAR=y +CT_LOG_TO_FILE=y +CT_LOG_FILE_COMPRESS=y + +# +# Target options +# +CT_ARCH="powerpc" +CT_ARCH_SUPPORTS_BOTH_ENDIAN=y +CT_ARCH_SUPPORTS_32=y +CT_ARCH_SUPPORTS_64=y +CT_ARCH_SUPPORTS_WITH_ABI=y +CT_ARCH_SUPPORTS_WITH_CPU=y +CT_ARCH_SUPPORTS_WITH_TUNE=y +CT_ARCH_SUPPORTS_WITH_FLOAT=y +CT_ARCH_DEFAULT_BE=y +CT_ARCH_DEFAULT_32=y +CT_ARCH_ABI="" +CT_ARCH_CPU="power4" +CT_ARCH_TUNE="power6" +CT_ARCH_BE=y +# CT_ARCH_LE is not set +# CT_ARCH_32 is not set +CT_ARCH_64=y +CT_ARCH_BITNESS=64 +# CT_ARCH_FLOAT_HW is not set +# CT_ARCH_FLOAT_SW is not set +CT_TARGET_CFLAGS="" +CT_TARGET_LDFLAGS="" +# CT_ARCH_alpha is not set +# CT_ARCH_arm is not set +# CT_ARCH_avr is not set +# CT_ARCH_m68k is not set +# CT_ARCH_mips is not set +# CT_ARCH_nios2 is not set +CT_ARCH_powerpc=y +# CT_ARCH_s390 is not set +# CT_ARCH_sh is not set +# CT_ARCH_sparc is not set +# CT_ARCH_x86 is not set +# CT_ARCH_xtensa is not set +CT_ARCH_alpha_AVAILABLE=y +CT_ARCH_arm_AVAILABLE=y +CT_ARCH_avr_AVAILABLE=y +CT_ARCH_m68k_AVAILABLE=y +CT_ARCH_microblaze_AVAILABLE=y +CT_ARCH_mips_AVAILABLE=y +CT_ARCH_nios2_AVAILABLE=y +CT_ARCH_powerpc_AVAILABLE=y +CT_ARCH_s390_AVAILABLE=y +CT_ARCH_sh_AVAILABLE=y +CT_ARCH_sparc_AVAILABLE=y +CT_ARCH_x86_AVAILABLE=y +CT_ARCH_xtensa_AVAILABLE=y +CT_ARCH_SUFFIX="" + +# +# Generic target options +# +# CT_MULTILIB is not set +CT_ARCH_USE_MMU=y +CT_ARCH_ENDIAN="big" + +# +# Target optimisations +# +CT_ARCH_FLOAT_AUTO=y +CT_ARCH_FLOAT="auto" + +# +# powerpc other options +# +CT_ARCH_powerpc_ABI="" +CT_ARCH_powerpc_ABI_DEFAULT=y +# CT_ARCH_powerpc_ABI_SPE is not set + +# +# Toolchain options +# + +# +# General toolchain options +# +CT_FORCE_SYSROOT=y +CT_USE_SYSROOT=y +CT_SYSROOT_NAME="sysroot" +CT_SYSROOT_DIR_PREFIX="" +CT_WANTS_STATIC_LINK=y +# CT_STATIC_TOOLCHAIN is not set +CT_TOOLCHAIN_PKGVERSION="" +CT_TOOLCHAIN_BUGURL="" + +# +# Tuple completion and aliasing +# +CT_TARGET_VENDOR="unknown" +CT_TARGET_ALIAS_SED_EXPR="" +CT_TARGET_ALIAS="" + +# +# Toolchain type +# +CT_CROSS=y +# CT_CANADIAN is not set +CT_TOOLCHAIN_TYPE="cross" + +# +# Build system +# +CT_BUILD="" +CT_BUILD_PREFIX="" +CT_BUILD_SUFFIX="" + +# +# Misc options +# +# CT_TOOLCHAIN_ENABLE_NLS is not set + +# +# Operating System +# +CT_KERNEL_SUPPORTS_SHARED_LIBS=y +CT_KERNEL="linux" +CT_KERNEL_VERSION="2.6.32.68" +# CT_KERNEL_bare_metal is not set +CT_KERNEL_linux=y +CT_KERNEL_bare_metal_AVAILABLE=y +CT_KERNEL_linux_AVAILABLE=y +# CT_KERNEL_V_4_3 is not set +# CT_KERNEL_V_4_2 is not set +# CT_KERNEL_V_4_1 is not set +# CT_KERNEL_V_3_18 is not set +# CT_KERNEL_V_3_14 is not set +# CT_KERNEL_V_3_12 is not set +# CT_KERNEL_V_3_10 is not set +# CT_KERNEL_V_3_4 is not set +# CT_KERNEL_V_3_2 is not set +CT_KERNEL_V_2_6_32=y +# CT_KERNEL_LINUX_CUSTOM is not set +CT_KERNEL_windows_AVAILABLE=y + +# +# Common kernel options +# +CT_SHARED_LIBS=y + +# +# linux other options +# +CT_KERNEL_LINUX_VERBOSITY_0=y +# CT_KERNEL_LINUX_VERBOSITY_1 is not set +# CT_KERNEL_LINUX_VERBOSITY_2 is not set +CT_KERNEL_LINUX_VERBOSE_LEVEL=0 +CT_KERNEL_LINUX_INSTALL_CHECK=y + +# +# Binary utilities +# +CT_ARCH_BINFMT_ELF=y +CT_BINUTILS="binutils" +CT_BINUTILS_binutils=y + +# +# GNU binutils +# +# CT_CC_BINUTILS_SHOW_LINARO is not set +CT_BINUTILS_V_2_25_1=y +# CT_BINUTILS_V_2_25 is not set +# CT_BINUTILS_V_2_24 is not set +# CT_BINUTILS_V_2_23_2 is not set +# CT_BINUTILS_V_2_23_1 is not set +# CT_BINUTILS_V_2_22 is not set +# CT_BINUTILS_V_2_21_53 is not set +# CT_BINUTILS_V_2_21_1a is not set +# CT_BINUTILS_V_2_20_1a is not set +# CT_BINUTILS_V_2_19_1a is not set +# CT_BINUTILS_V_2_18a is not set +CT_BINUTILS_VERSION="2.25.1" +CT_BINUTILS_2_25_1_or_later=y +CT_BINUTILS_2_25_or_later=y +CT_BINUTILS_2_24_or_later=y +CT_BINUTILS_2_23_or_later=y +CT_BINUTILS_2_22_or_later=y +CT_BINUTILS_2_21_or_later=y +CT_BINUTILS_2_20_or_later=y +CT_BINUTILS_2_19_or_later=y +CT_BINUTILS_2_18_or_later=y +CT_BINUTILS_HAS_HASH_STYLE=y +CT_BINUTILS_HAS_GOLD=y +CT_BINUTILS_HAS_PLUGINS=y +CT_BINUTILS_HAS_PKGVERSION_BUGURL=y +CT_BINUTILS_FORCE_LD_BFD=y +CT_BINUTILS_LINKER_LD=y +CT_BINUTILS_LINKERS_LIST="ld" +CT_BINUTILS_LINKER_DEFAULT="bfd" +# CT_BINUTILS_PLUGINS is not set +CT_BINUTILS_EXTRA_CONFIG_ARRAY="" +# CT_BINUTILS_FOR_TARGET is not set + +# +# binutils other options +# + +# +# C-library +# +CT_LIBC="glibc" +CT_LIBC_VERSION="2.12.2" +CT_LIBC_glibc=y +# CT_LIBC_musl is not set +# CT_LIBC_uClibc is not set +CT_LIBC_avr_libc_AVAILABLE=y +CT_LIBC_glibc_AVAILABLE=y +CT_THREADS="nptl" +# CT_CC_GLIBC_SHOW_LINARO is not set +# CT_LIBC_GLIBC_V_2_22 is not set +# CT_LIBC_GLIBC_V_2_21 is not set +# CT_LIBC_GLIBC_V_2_20 is not set +# CT_LIBC_GLIBC_V_2_19 is not set +# CT_LIBC_GLIBC_V_2_18 is not set +# CT_LIBC_GLIBC_V_2_17 is not set +# CT_LIBC_GLIBC_V_2_16_0 is not set +# CT_LIBC_GLIBC_V_2_15 is not set +# CT_LIBC_GLIBC_V_2_14_1 is not set +# CT_LIBC_GLIBC_V_2_14 is not set +# CT_LIBC_GLIBC_V_2_13 is not set +CT_LIBC_GLIBC_V_2_12_2=y +# CT_LIBC_GLIBC_V_2_12_1 is not set +# CT_LIBC_GLIBC_V_2_11_1 is not set +# CT_LIBC_GLIBC_V_2_11 is not set +# CT_LIBC_GLIBC_V_2_10_1 is not set +# CT_LIBC_GLIBC_V_2_9 is not set +# CT_LIBC_GLIBC_V_2_8 is not set +CT_LIBC_mingw_AVAILABLE=y +CT_LIBC_musl_AVAILABLE=y +CT_LIBC_newlib_AVAILABLE=y +CT_LIBC_none_AVAILABLE=y +CT_LIBC_uClibc_AVAILABLE=y +CT_LIBC_SUPPORT_THREADS_ANY=y +CT_LIBC_SUPPORT_THREADS_NATIVE=y + +# +# Common C library options +# +CT_THREADS_NATIVE=y +CT_LIBC_XLDD=y + +# +# glibc other options +# +CT_LIBC_GLIBC_PORTS_EXTERNAL=y +CT_LIBC_glibc_familly=y +CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY="" +CT_LIBC_GLIBC_CONFIGPARMS="" +CT_LIBC_GLIBC_EXTRA_CFLAGS="" +CT_LIBC_EXTRA_CC_ARGS="" +# CT_LIBC_DISABLE_VERSIONING is not set +CT_LIBC_OLDEST_ABI="" +CT_LIBC_GLIBC_FORCE_UNWIND=y +# CT_LIBC_GLIBC_USE_PORTS is not set +CT_LIBC_ADDONS_LIST="" +# CT_LIBC_LOCALES is not set +# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set +CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y +# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set +CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68" + +# +# C compiler +# +CT_CC="gcc" +CT_CC_CORE_PASSES_NEEDED=y +CT_CC_CORE_PASS_1_NEEDED=y +CT_CC_CORE_PASS_2_NEEDED=y +CT_CC_gcc=y +# CT_CC_GCC_SHOW_LINARO is not set +# CT_CC_GCC_V_5_2_0 is not set +CT_CC_GCC_V_4_9_3=y +# CT_CC_GCC_V_4_8_5 is not set +# CT_CC_GCC_V_4_7_4 is not set +# CT_CC_GCC_V_4_6_4 is not set +# CT_CC_GCC_V_4_5_4 is not set +# CT_CC_GCC_V_4_4_7 is not set +# CT_CC_GCC_V_4_3_6 is not set +# CT_CC_GCC_V_4_2_4 is not set +CT_CC_GCC_4_2_or_later=y +CT_CC_GCC_4_3_or_later=y +CT_CC_GCC_4_4_or_later=y +CT_CC_GCC_4_5_or_later=y +CT_CC_GCC_4_6_or_later=y +CT_CC_GCC_4_7_or_later=y +CT_CC_GCC_4_8_or_later=y +CT_CC_GCC_4_9=y +CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_HAS_GRAPHITE=y +CT_CC_GCC_USE_GRAPHITE=y +CT_CC_GCC_HAS_LTO=y +CT_CC_GCC_USE_LTO=y +CT_CC_GCC_HAS_PKGVERSION_BUGURL=y +CT_CC_GCC_HAS_BUILD_ID=y +CT_CC_GCC_HAS_LNK_HASH_STYLE=y +CT_CC_GCC_USE_GMP_MPFR=y +CT_CC_GCC_USE_MPC=y +CT_CC_GCC_HAS_LIBQUADMATH=y +CT_CC_GCC_HAS_LIBSANITIZER=y +CT_CC_GCC_VERSION="4.9.3" +# CT_CC_LANG_FORTRAN is not set +CT_CC_GCC_ENABLE_CXX_FLAGS="" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_ENV_ARRAY="" +CT_CC_GCC_STATIC_LIBSTDCXX=y +# CT_CC_GCC_SYSTEM_ZLIB is not set + +# +# Optimisation features +# + +# +# Settings for libraries running on target +# +CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y +# CT_CC_GCC_LIBMUDFLAP is not set +# CT_CC_GCC_LIBGOMP is not set +# CT_CC_GCC_LIBSSP is not set +# CT_CC_GCC_LIBQUADMATH is not set +# CT_CC_GCC_LIBSANITIZER is not set + +# +# Misc. obscure options. +# +CT_CC_CXA_ATEXIT=y +# CT_CC_GCC_DISABLE_PCH is not set +CT_CC_GCC_SJLJ_EXCEPTIONS=m +CT_CC_GCC_LDBL_128=m +# CT_CC_GCC_BUILD_ID is not set +CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y +# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set +# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set +# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set +CT_CC_GCC_LNK_HASH_STYLE="" +CT_CC_GCC_DEC_FLOAT_AUTO=y +# CT_CC_GCC_DEC_FLOAT_BID is not set +# CT_CC_GCC_DEC_FLOAT_DPD is not set +# CT_CC_GCC_DEC_FLOATS_NO is not set +CT_CC_SUPPORT_CXX=y +CT_CC_SUPPORT_FORTRAN=y +CT_CC_SUPPORT_JAVA=y +CT_CC_SUPPORT_ADA=y +CT_CC_SUPPORT_OBJC=y +CT_CC_SUPPORT_OBJCXX=y +CT_CC_SUPPORT_GOLANG=y + +# +# Additional supported languages: +# +CT_CC_LANG_CXX=y +# CT_CC_LANG_JAVA is not set + +# +# Debug facilities +# +# CT_DEBUG_dmalloc is not set +# CT_DEBUG_duma is not set +# CT_DEBUG_gdb is not set +# CT_DEBUG_ltrace is not set +# CT_DEBUG_strace is not set + +# +# Companion libraries +# +CT_COMPLIBS_NEEDED=y +CT_LIBICONV_NEEDED=y +CT_GETTEXT_NEEDED=y +CT_GMP_NEEDED=y +CT_MPFR_NEEDED=y +CT_ISL_NEEDED=y +CT_CLOOG_NEEDED=y +CT_MPC_NEEDED=y +CT_COMPLIBS=y +CT_LIBICONV=y +CT_GETTEXT=y +CT_GMP=y +CT_MPFR=y +CT_ISL=y +CT_CLOOG=y +CT_MPC=y +CT_LIBICONV_V_1_14=y +CT_LIBICONV_VERSION="1.14" +CT_GETTEXT_V_0_19_6=y +CT_GETTEXT_VERSION="0.19.6" +CT_GMP_V_6_0_0=y +# CT_GMP_V_5_1_3 is not set +# CT_GMP_V_5_1_1 is not set +# CT_GMP_V_5_0_2 is not set +# CT_GMP_V_5_0_1 is not set +# CT_GMP_V_4_3_2 is not set +# CT_GMP_V_4_3_1 is not set +# CT_GMP_V_4_3_0 is not set +CT_GMP_5_0_2_or_later=y +CT_GMP_VERSION="6.0.0a" +CT_MPFR_V_3_1_3=y +# CT_MPFR_V_3_1_2 is not set +# CT_MPFR_V_3_1_0 is not set +# CT_MPFR_V_3_0_1 is not set +# CT_MPFR_V_3_0_0 is not set +# CT_MPFR_V_2_4_2 is not set +# CT_MPFR_V_2_4_1 is not set +# CT_MPFR_V_2_4_0 is not set +CT_MPFR_VERSION="3.1.3" +CT_ISL_V_0_14=y +CT_ISL_V_0_14_or_later=y +CT_ISL_V_0_12_or_later=y +CT_ISL_VERSION="0.14" +CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_1 is not set +# CT_CLOOG_V_0_18_0 is not set +CT_CLOOG_VERSION="0.18.4" +CT_CLOOG_0_18_4_or_later=y +CT_CLOOG_0_18_or_later=y +CT_MPC_V_1_0_3=y +# CT_MPC_V_1_0_2 is not set +# CT_MPC_V_1_0_1 is not set +# CT_MPC_V_1_0 is not set +# CT_MPC_V_0_9 is not set +# CT_MPC_V_0_8_2 is not set +# CT_MPC_V_0_8_1 is not set +# CT_MPC_V_0_7 is not set +CT_MPC_VERSION="1.0.3" + +# +# Companion libraries common options +# +# CT_COMPLIBS_CHECK is not set + +# +# Companion tools +# + +# +# READ HELP before you say 'Y' below !!! +# +# CT_COMP_TOOLS is not set diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile index ec38855fe3a01..589b5fd530fc7 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile @@ -1,37 +1,81 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ make \ - file \ - curl \ - ca-certificates \ + patch \ python2.7 \ - git \ - cmake \ sudo \ - bzip2 \ - xz-utils \ + texinfo \ wget \ - patch \ - g++-s390x-linux-gnu + xz-utils -COPY build-toolchain.sh /tmp/ -RUN sh /tmp/build-toolchain.sh +ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783 +RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \ + tar xJf - -C /usr/local/bin --strip-components=1 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ dpkg -i dumb-init_*.deb && \ rm dumb-init_*.deb ENTRYPOINT ["/usr/bin/dumb-init", "--"] -ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783 -RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \ - tar xJf - -C /usr/local/bin --strip-components=1 +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY patches/ /tmp/patches/ +COPY s390x-linux-gnu.config build-s390x-toolchain.sh /tmp/ +RUN ./build-s390x-toolchain.sh + +USER root + +COPY build-netbsd-toolchain.sh /tmp/ +RUN ./build-netbsd-toolchain.sh + +ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin ENV \ AR_x86_64_unknown_netbsd=x86_64-unknown-netbsd-ar \ CC_x86_64_unknown_netbsd=x86_64-unknown-netbsd-gcc \ - CXX_x86_64_unknown_netbsd=x86_64-unknown-netbsd-g++ + CXX_x86_64_unknown_netbsd=x86_64-unknown-netbsd-g++ \ + CC_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-gcc \ + AR_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-ar \ + CXX_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-g++ ENV HOSTS=x86_64-unknown-netbsd ENV HOSTS=$HOSTS,s390x-unknown-linux-gnu diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-toolchain.sh b/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh old mode 100644 new mode 100755 similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/build-toolchain.sh rename to src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh b/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh new file mode 100755 index 0000000000000..b4995e20dc69b --- /dev/null +++ b/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# 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. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../s390x-linux-gnu.config .config +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch new file mode 100644 index 0000000000000..cba416ed2f70b --- /dev/null +++ b/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch @@ -0,0 +1,63 @@ +From 2739047682590b1df473401b4febf424f857fccf Mon Sep 17 00:00:00 2001 +From: Andreas Krebbel +Date: Sun, 17 Apr 2011 20:43:59 -0400 +Subject: [PATCH] Use .machine to prevent AS from complaining about z9-109 + instructions in iconv modules + +--- + sysdeps/s390/s390-64/utf16-utf32-z9.c | 5 ++++- + sysdeps/s390/s390-64/utf8-utf16-z9.c | 5 ++++- + sysdeps/s390/s390-64/utf8-utf32-z9.c | 5 ++++- + 3 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/sysdeps/s390/s390-64/utf16-utf32-z9.c b/sysdeps/s390/s390-64/utf16-utf32-z9.c +index 14daf2118fe5..5bcaaaedec9c 100644 +--- a/sysdeps/s390/s390-64/utf16-utf32-z9.c ++++ b/sysdeps/s390/s390-64/utf16-utf32-z9.c +@@ -169,7 +169,10 @@ gconv_end (struct __gconv_step *data) + register unsigned long long outlen asm("11") = outend - outptr; \ + uint64_t cc = 0; \ + \ +- asm volatile ("0: " INSTRUCTION " \n\t" \ ++ asm volatile (".machine push \n\t" \ ++ ".machine \"z9-109\" \n\t" \ ++ "0: " INSTRUCTION " \n\t" \ ++ ".machine pop \n\t" \ + " jo 0b \n\t" \ + " ipm %2 \n" \ + : "+a" (pOutput), "+a" (pInput), "+d" (cc), \ +diff --git a/sysdeps/s390/s390-64/utf8-utf16-z9.c b/sysdeps/s390/s390-64/utf8-utf16-z9.c +index 5f73f3c59e21..812a42fae44c 100644 +--- a/sysdeps/s390/s390-64/utf8-utf16-z9.c ++++ b/sysdeps/s390/s390-64/utf8-utf16-z9.c +@@ -151,7 +151,10 @@ gconv_end (struct __gconv_step *data) + register unsigned long long outlen asm("11") = outend - outptr; \ + uint64_t cc = 0; \ + \ +- asm volatile ("0: " INSTRUCTION " \n\t" \ ++ asm volatile (".machine push \n\t" \ ++ ".machine \"z9-109\" \n\t" \ ++ "0: " INSTRUCTION " \n\t" \ ++ ".machine pop \n\t" \ + " jo 0b \n\t" \ + " ipm %2 \n" \ + : "+a" (pOutput), "+a" (pInput), "+d" (cc), \ +diff --git a/sysdeps/s390/s390-64/utf8-utf32-z9.c b/sysdeps/s390/s390-64/utf8-utf32-z9.c +index 17ef8bc890c3..0ffd848c8124 100644 +--- a/sysdeps/s390/s390-64/utf8-utf32-z9.c ++++ b/sysdeps/s390/s390-64/utf8-utf32-z9.c +@@ -155,7 +155,10 @@ gconv_end (struct __gconv_step *data) + register unsigned long long outlen asm("11") = outend - outptr; \ + uint64_t cc = 0; \ + \ +- asm volatile ("0: " INSTRUCTION " \n\t" \ ++ asm volatile (".machine push \n\t" \ ++ ".machine \"z9-109\" \n\t" \ ++ "0: " INSTRUCTION " \n\t" \ ++ ".machine pop \n\t" \ + " jo 0b \n\t" \ + " ipm %2 \n" \ + : "+a" (pOutput), "+a" (pInput), "+d" (cc), \ +-- +2.9.3 + diff --git a/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config b/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config new file mode 100644 index 0000000000000..fa5e4510987f1 --- /dev/null +++ b/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config @@ -0,0 +1,508 @@ +# +# Automatically generated file; DO NOT EDIT. +# Crosstool-NG Configuration +# +CT_CONFIGURE_has_make381=y +CT_CONFIGURE_has_xz=y +CT_MODULES=y + +# +# Paths and misc options +# + +# +# crosstool-NG behavior +# +# CT_OBSOLETE is not set +# CT_EXPERIMENTAL is not set +# CT_DEBUG_CT is not set + +# +# Paths +# +CT_LOCAL_TARBALLS_DIR="" +CT_WORK_DIR="${CT_TOP_DIR}/.build" +CT_PREFIX_DIR="/x-tools/${CT_TARGET}" +CT_INSTALL_DIR="${CT_PREFIX_DIR}" +CT_RM_RF_PREFIX_DIR=y +CT_REMOVE_DOCS=y +CT_INSTALL_DIR_RO=y +CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y +# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set + +# +# Downloading +# +# CT_FORBID_DOWNLOAD is not set +# CT_FORCE_DOWNLOAD is not set +CT_CONNECT_TIMEOUT=10 +# CT_ONLY_DOWNLOAD is not set +# CT_USE_MIRROR is not set + +# +# Extracting +# +# CT_FORCE_EXTRACT is not set +CT_OVERIDE_CONFIG_GUESS_SUB=y +# CT_ONLY_EXTRACT is not set +# CT_PATCH_BUNDLED is not set +# CT_PATCH_LOCAL is not set +CT_PATCH_BUNDLED_LOCAL=y +# CT_PATCH_LOCAL_BUNDLED is not set +# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set +# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set +# CT_PATCH_NONE is not set +CT_PATCH_ORDER="bundled,local" +CT_PATCH_USE_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" + +# +# Build behavior +# +CT_PARALLEL_JOBS=0 +CT_LOAD="" +CT_USE_PIPES=y +CT_EXTRA_CFLAGS_FOR_BUILD="" +CT_EXTRA_LDFLAGS_FOR_BUILD="" +CT_EXTRA_CFLAGS_FOR_HOST="" +CT_EXTRA_LDFLAGS_FOR_HOST="" +# CT_CONFIG_SHELL_SH is not set +# CT_CONFIG_SHELL_ASH is not set +CT_CONFIG_SHELL_BASH=y +# CT_CONFIG_SHELL_CUSTOM is not set +CT_CONFIG_SHELL="${bash}" + +# +# Logging +# +# CT_LOG_ERROR is not set +# CT_LOG_WARN is not set +CT_LOG_INFO=y +# CT_LOG_EXTRA is not set +# CT_LOG_ALL is not set +# CT_LOG_DEBUG is not set +CT_LOG_LEVEL_MAX="INFO" +# CT_LOG_SEE_TOOLS_WARN is not set +CT_LOG_PROGRESS_BAR=y +CT_LOG_TO_FILE=y +CT_LOG_FILE_COMPRESS=y + +# +# Target options +# +CT_ARCH="s390" +CT_ARCH_SUPPORTS_32=y +CT_ARCH_SUPPORTS_64=y +CT_ARCH_SUPPORTS_WITH_FPU=y +CT_ARCH_DEFAULT_32=y +CT_ARCH_FPU="" +# CT_ARCH_32 is not set +CT_ARCH_64=y +CT_ARCH_BITNESS=64 +CT_TARGET_CFLAGS="" +CT_TARGET_LDFLAGS="" +# CT_ARCH_alpha is not set +# CT_ARCH_arm is not set +# CT_ARCH_avr is not set +# CT_ARCH_m68k is not set +# CT_ARCH_mips is not set +# CT_ARCH_nios2 is not set +# CT_ARCH_powerpc is not set +CT_ARCH_s390=y +# CT_ARCH_sh is not set +# CT_ARCH_sparc is not set +# CT_ARCH_x86 is not set +# CT_ARCH_xtensa is not set +CT_ARCH_alpha_AVAILABLE=y +CT_ARCH_arm_AVAILABLE=y +CT_ARCH_avr_AVAILABLE=y +CT_ARCH_m68k_AVAILABLE=y +CT_ARCH_microblaze_AVAILABLE=y +CT_ARCH_mips_AVAILABLE=y +CT_ARCH_nios2_AVAILABLE=y +CT_ARCH_powerpc_AVAILABLE=y +CT_ARCH_s390_AVAILABLE=y +CT_ARCH_sh_AVAILABLE=y +CT_ARCH_sparc_AVAILABLE=y +CT_ARCH_x86_AVAILABLE=y +CT_ARCH_xtensa_AVAILABLE=y +CT_ARCH_SUFFIX="" + +# +# Generic target options +# +# CT_MULTILIB is not set +CT_ARCH_USE_MMU=y + +# +# Target optimisations +# +CT_ARCH_FLOAT="" + +# +# Toolchain options +# + +# +# General toolchain options +# +CT_FORCE_SYSROOT=y +CT_USE_SYSROOT=y +CT_SYSROOT_NAME="sysroot" +CT_SYSROOT_DIR_PREFIX="" +CT_WANTS_STATIC_LINK=y +# CT_STATIC_TOOLCHAIN is not set +CT_TOOLCHAIN_PKGVERSION="" +CT_TOOLCHAIN_BUGURL="" + +# +# Tuple completion and aliasing +# +CT_TARGET_VENDOR="unknown" +CT_TARGET_ALIAS_SED_EXPR="" +CT_TARGET_ALIAS="" + +# +# Toolchain type +# +CT_CROSS=y +# CT_CANADIAN is not set +CT_TOOLCHAIN_TYPE="cross" + +# +# Build system +# +CT_BUILD="" +CT_BUILD_PREFIX="" +CT_BUILD_SUFFIX="" + +# +# Misc options +# +# CT_TOOLCHAIN_ENABLE_NLS is not set + +# +# Operating System +# +CT_KERNEL_SUPPORTS_SHARED_LIBS=y +CT_KERNEL="linux" +CT_KERNEL_VERSION="2.6.32.68" +# CT_KERNEL_bare_metal is not set +CT_KERNEL_linux=y +CT_KERNEL_bare_metal_AVAILABLE=y +CT_KERNEL_linux_AVAILABLE=y +# CT_KERNEL_V_4_3 is not set +# CT_KERNEL_V_4_2 is not set +# CT_KERNEL_V_4_1 is not set +# CT_KERNEL_V_3_18 is not set +# CT_KERNEL_V_3_14 is not set +# CT_KERNEL_V_3_12 is not set +# CT_KERNEL_V_3_10 is not set +# CT_KERNEL_V_3_4 is not set +# CT_KERNEL_V_3_2 is not set +CT_KERNEL_V_2_6_32=y +# CT_KERNEL_LINUX_CUSTOM is not set +CT_KERNEL_windows_AVAILABLE=y + +# +# Common kernel options +# +CT_SHARED_LIBS=y + +# +# linux other options +# +CT_KERNEL_LINUX_VERBOSITY_0=y +# CT_KERNEL_LINUX_VERBOSITY_1 is not set +# CT_KERNEL_LINUX_VERBOSITY_2 is not set +CT_KERNEL_LINUX_VERBOSE_LEVEL=0 +CT_KERNEL_LINUX_INSTALL_CHECK=y + +# +# Binary utilities +# +CT_ARCH_BINFMT_ELF=y +CT_BINUTILS="binutils" +CT_BINUTILS_binutils=y + +# +# GNU binutils +# +# CT_CC_BINUTILS_SHOW_LINARO is not set +CT_BINUTILS_V_2_25_1=y +# CT_BINUTILS_V_2_25 is not set +# CT_BINUTILS_V_2_24 is not set +# CT_BINUTILS_V_2_23_2 is not set +# CT_BINUTILS_V_2_23_1 is not set +# CT_BINUTILS_V_2_22 is not set +# CT_BINUTILS_V_2_21_53 is not set +# CT_BINUTILS_V_2_21_1a is not set +# CT_BINUTILS_V_2_20_1a is not set +# CT_BINUTILS_V_2_19_1a is not set +# CT_BINUTILS_V_2_18a is not set +CT_BINUTILS_VERSION="2.25.1" +CT_BINUTILS_2_25_1_or_later=y +CT_BINUTILS_2_25_or_later=y +CT_BINUTILS_2_24_or_later=y +CT_BINUTILS_2_23_or_later=y +CT_BINUTILS_2_22_or_later=y +CT_BINUTILS_2_21_or_later=y +CT_BINUTILS_2_20_or_later=y +CT_BINUTILS_2_19_or_later=y +CT_BINUTILS_2_18_or_later=y +CT_BINUTILS_HAS_HASH_STYLE=y +CT_BINUTILS_HAS_GOLD=y +CT_BINUTILS_HAS_PLUGINS=y +CT_BINUTILS_HAS_PKGVERSION_BUGURL=y +CT_BINUTILS_FORCE_LD_BFD=y +CT_BINUTILS_LINKER_LD=y +CT_BINUTILS_LINKERS_LIST="ld" +CT_BINUTILS_LINKER_DEFAULT="bfd" +# CT_BINUTILS_PLUGINS is not set +CT_BINUTILS_EXTRA_CONFIG_ARRAY="" +# CT_BINUTILS_FOR_TARGET is not set + +# +# binutils other options +# + +# +# C-library +# +CT_LIBC="glibc" +CT_LIBC_VERSION="2.12.2" +CT_LIBC_glibc=y +# CT_LIBC_musl is not set +# CT_LIBC_uClibc is not set +CT_LIBC_avr_libc_AVAILABLE=y +CT_LIBC_glibc_AVAILABLE=y +CT_THREADS="nptl" +# CT_CC_GLIBC_SHOW_LINARO is not set +# CT_LIBC_GLIBC_V_2_22 is not set +# CT_LIBC_GLIBC_V_2_21 is not set +# CT_LIBC_GLIBC_V_2_20 is not set +# CT_LIBC_GLIBC_V_2_19 is not set +# CT_LIBC_GLIBC_V_2_18 is not set +# CT_LIBC_GLIBC_V_2_17 is not set +# CT_LIBC_GLIBC_V_2_16_0 is not set +# CT_LIBC_GLIBC_V_2_15 is not set +# CT_LIBC_GLIBC_V_2_14_1 is not set +# CT_LIBC_GLIBC_V_2_14 is not set +# CT_LIBC_GLIBC_V_2_13 is not set +CT_LIBC_GLIBC_V_2_12_2=y +# CT_LIBC_GLIBC_V_2_12_1 is not set +# CT_LIBC_GLIBC_V_2_11_1 is not set +# CT_LIBC_GLIBC_V_2_11 is not set +# CT_LIBC_GLIBC_V_2_10_1 is not set +# CT_LIBC_GLIBC_V_2_9 is not set +# CT_LIBC_GLIBC_V_2_8 is not set +CT_LIBC_mingw_AVAILABLE=y +CT_LIBC_musl_AVAILABLE=y +CT_LIBC_newlib_AVAILABLE=y +CT_LIBC_none_AVAILABLE=y +CT_LIBC_uClibc_AVAILABLE=y +CT_LIBC_SUPPORT_THREADS_ANY=y +CT_LIBC_SUPPORT_THREADS_NATIVE=y + +# +# Common C library options +# +CT_THREADS_NATIVE=y +CT_LIBC_XLDD=y + +# +# glibc other options +# +CT_LIBC_GLIBC_PORTS_EXTERNAL=y +CT_LIBC_glibc_familly=y +CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY="" +CT_LIBC_GLIBC_CONFIGPARMS="" +CT_LIBC_GLIBC_EXTRA_CFLAGS="" +CT_LIBC_EXTRA_CC_ARGS="" +# CT_LIBC_DISABLE_VERSIONING is not set +CT_LIBC_OLDEST_ABI="" +CT_LIBC_GLIBC_FORCE_UNWIND=y +# CT_LIBC_GLIBC_USE_PORTS is not set +CT_LIBC_ADDONS_LIST="" +# CT_LIBC_LOCALES is not set +# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set +CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y +# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set +CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68" + +# +# C compiler +# +CT_CC="gcc" +CT_CC_CORE_PASSES_NEEDED=y +CT_CC_CORE_PASS_1_NEEDED=y +CT_CC_CORE_PASS_2_NEEDED=y +CT_CC_gcc=y +# CT_CC_GCC_SHOW_LINARO is not set +# CT_CC_GCC_V_5_2_0 is not set +CT_CC_GCC_V_4_9_3=y +# CT_CC_GCC_V_4_8_5 is not set +# CT_CC_GCC_V_4_7_4 is not set +# CT_CC_GCC_V_4_6_4 is not set +# CT_CC_GCC_V_4_5_4 is not set +# CT_CC_GCC_V_4_4_7 is not set +# CT_CC_GCC_V_4_3_6 is not set +# CT_CC_GCC_V_4_2_4 is not set +CT_CC_GCC_4_2_or_later=y +CT_CC_GCC_4_3_or_later=y +CT_CC_GCC_4_4_or_later=y +CT_CC_GCC_4_5_or_later=y +CT_CC_GCC_4_6_or_later=y +CT_CC_GCC_4_7_or_later=y +CT_CC_GCC_4_8_or_later=y +CT_CC_GCC_4_9=y +CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_HAS_GRAPHITE=y +CT_CC_GCC_USE_GRAPHITE=y +CT_CC_GCC_HAS_LTO=y +CT_CC_GCC_USE_LTO=y +CT_CC_GCC_HAS_PKGVERSION_BUGURL=y +CT_CC_GCC_HAS_BUILD_ID=y +CT_CC_GCC_HAS_LNK_HASH_STYLE=y +CT_CC_GCC_USE_GMP_MPFR=y +CT_CC_GCC_USE_MPC=y +CT_CC_GCC_HAS_LIBQUADMATH=y +CT_CC_GCC_HAS_LIBSANITIZER=y +CT_CC_GCC_VERSION="4.9.3" +# CT_CC_LANG_FORTRAN is not set +CT_CC_GCC_ENABLE_CXX_FLAGS="" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-arch=z10" +CT_CC_GCC_EXTRA_ENV_ARRAY="" +CT_CC_GCC_STATIC_LIBSTDCXX=y +# CT_CC_GCC_SYSTEM_ZLIB is not set + +# +# Optimisation features +# + +# +# Settings for libraries running on target +# +CT_CC_GCC_ENABLE_TARGET_OPTSPACE=y +# CT_CC_GCC_LIBMUDFLAP is not set +# CT_CC_GCC_LIBGOMP is not set +# CT_CC_GCC_LIBSSP is not set +# CT_CC_GCC_LIBQUADMATH is not set +# CT_CC_GCC_LIBSANITIZER is not set + +# +# Misc. obscure options. +# +CT_CC_CXA_ATEXIT=y +# CT_CC_GCC_DISABLE_PCH is not set +CT_CC_GCC_SJLJ_EXCEPTIONS=m +CT_CC_GCC_LDBL_128=m +# CT_CC_GCC_BUILD_ID is not set +CT_CC_GCC_LNK_HASH_STYLE_DEFAULT=y +# CT_CC_GCC_LNK_HASH_STYLE_SYSV is not set +# CT_CC_GCC_LNK_HASH_STYLE_GNU is not set +# CT_CC_GCC_LNK_HASH_STYLE_BOTH is not set +CT_CC_GCC_LNK_HASH_STYLE="" +CT_CC_GCC_DEC_FLOAT_AUTO=y +# CT_CC_GCC_DEC_FLOAT_BID is not set +# CT_CC_GCC_DEC_FLOAT_DPD is not set +# CT_CC_GCC_DEC_FLOATS_NO is not set +CT_CC_SUPPORT_CXX=y +CT_CC_SUPPORT_FORTRAN=y +CT_CC_SUPPORT_JAVA=y +CT_CC_SUPPORT_ADA=y +CT_CC_SUPPORT_OBJC=y +CT_CC_SUPPORT_OBJCXX=y +CT_CC_SUPPORT_GOLANG=y + +# +# Additional supported languages: +# +CT_CC_LANG_CXX=y +# CT_CC_LANG_JAVA is not set + +# +# Debug facilities +# +# CT_DEBUG_dmalloc is not set +# CT_DEBUG_duma is not set +# CT_DEBUG_gdb is not set +# CT_DEBUG_ltrace is not set +# CT_DEBUG_strace is not set + +# +# Companion libraries +# +CT_COMPLIBS_NEEDED=y +CT_LIBICONV_NEEDED=y +CT_GETTEXT_NEEDED=y +CT_GMP_NEEDED=y +CT_MPFR_NEEDED=y +CT_ISL_NEEDED=y +CT_CLOOG_NEEDED=y +CT_MPC_NEEDED=y +CT_COMPLIBS=y +CT_LIBICONV=y +CT_GETTEXT=y +CT_GMP=y +CT_MPFR=y +CT_ISL=y +CT_CLOOG=y +CT_MPC=y +CT_LIBICONV_V_1_14=y +CT_LIBICONV_VERSION="1.14" +CT_GETTEXT_V_0_19_6=y +CT_GETTEXT_VERSION="0.19.6" +CT_GMP_V_6_0_0=y +# CT_GMP_V_5_1_3 is not set +# CT_GMP_V_5_1_1 is not set +# CT_GMP_V_5_0_2 is not set +# CT_GMP_V_5_0_1 is not set +# CT_GMP_V_4_3_2 is not set +# CT_GMP_V_4_3_1 is not set +# CT_GMP_V_4_3_0 is not set +CT_GMP_5_0_2_or_later=y +CT_GMP_VERSION="6.0.0a" +CT_MPFR_V_3_1_3=y +# CT_MPFR_V_3_1_2 is not set +# CT_MPFR_V_3_1_0 is not set +# CT_MPFR_V_3_0_1 is not set +# CT_MPFR_V_3_0_0 is not set +# CT_MPFR_V_2_4_2 is not set +# CT_MPFR_V_2_4_1 is not set +# CT_MPFR_V_2_4_0 is not set +CT_MPFR_VERSION="3.1.3" +CT_ISL_V_0_14=y +CT_ISL_V_0_14_or_later=y +CT_ISL_V_0_12_or_later=y +CT_ISL_VERSION="0.14" +CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_1 is not set +# CT_CLOOG_V_0_18_0 is not set +CT_CLOOG_VERSION="0.18.4" +CT_CLOOG_0_18_4_or_later=y +CT_CLOOG_0_18_or_later=y +CT_MPC_V_1_0_3=y +# CT_MPC_V_1_0_2 is not set +# CT_MPC_V_1_0_1 is not set +# CT_MPC_V_1_0 is not set +# CT_MPC_V_0_9 is not set +# CT_MPC_V_0_8_2 is not set +# CT_MPC_V_0_8_1 is not set +# CT_MPC_V_0_7 is not set +CT_MPC_VERSION="1.0.3" + +# +# Companion libraries common options +# +# CT_COMPLIBS_CHECK is not set + +# +# Companion tools +# + +# +# READ HELP before you say 'Y' below !!! +# +# CT_COMP_TOOLS is not set diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile new file mode 100644 index 0000000000000..3e084f4a3c302 --- /dev/null +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -0,0 +1,27 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils + +ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783 +RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \ + tar xJf - -C /usr/local/bin --strip-components=1 + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu +ENV RUSTFLAGS -Zincremental=/tmp/rust-incr-cache +ENV RUST_CHECK_TARGET check diff --git a/src/doc/book/choosing-your-guarantees.md b/src/doc/book/choosing-your-guarantees.md index 9dca3479d35e8..17741cac10b78 100644 --- a/src/doc/book/choosing-your-guarantees.md +++ b/src/doc/book/choosing-your-guarantees.md @@ -118,7 +118,8 @@ These types are _generally_ found in struct fields, but they may be found elsewh ## `Cell` -[`Cell`][cell] is a type that provides zero-cost interior mutability, but only for `Copy` types. +[`Cell`][cell] is a type that provides zero-cost interior mutability by moving data in and +out of the cell. Since the compiler knows that all the data owned by the contained value is on the stack, there's no worry of leaking any data behind references (or worse!) by simply replacing the data. @@ -160,7 +161,7 @@ This relaxes the “no aliasing with mutability” restriction in places unnecessary. However, this also relaxes the guarantees that the restriction provides; so if your invariants depend on data stored within `Cell`, you should be careful. -This is useful for mutating primitives and other `Copy` types when there is no easy way of +This is useful for mutating primitives and other types when there is no easy way of doing it in line with the static rules of `&` and `&mut`. `Cell` does not let you obtain interior references to the data, which makes it safe to freely @@ -168,16 +169,17 @@ mutate. #### Cost -There is no runtime cost to using `Cell`, however if you are using it to wrap larger (`Copy`) +There is no runtime cost to using `Cell`, however if you are using it to wrap larger structs, it might be worthwhile to instead wrap individual fields in `Cell` since each write is otherwise a full copy of the struct. ## `RefCell` -[`RefCell`][refcell] also provides interior mutability, but isn't restricted to `Copy` types. +[`RefCell`][refcell] also provides interior mutability, but doesn't move data in and out of the +cell. -Instead, it has a runtime cost. `RefCell` enforces the read-write lock pattern at runtime (it's +However, it has a runtime cost. `RefCell` enforces the read-write lock pattern at runtime (it's like a single-threaded mutex), unlike `&T`/`&mut T` which do so at compile time. This is done by the `borrow()` and `borrow_mut()` functions, which modify an internal reference count and return smart pointers which can be dereferenced immutably and mutably respectively. The refcount is restored when diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 50d4d0170fc70..8d29f11aa0519 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -56,9 +56,9 @@ almost any function that takes a pointer argument isn't valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of Rust's safe memory model. -When declaring the argument types to a foreign function, the Rust compiler can -not check if the declaration is correct, so specifying it correctly is part of -keeping the binding correct at runtime. +When declaring the argument types to a foreign function, the Rust compiler +cannot check if the declaration is correct, so specifying it correctly is part +of keeping the binding correct at runtime. The `extern` block can be extended to cover the entire snappy API: @@ -710,7 +710,7 @@ Please note that [`catch_unwind()`] will only catch unwinding panics, not those who abort the process. See the documentation of [`catch_unwind()`] for more information. -[`catch_unwind()`]: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html +[`catch_unwind()`]: ../std/panic/fn.catch_unwind.html # Representing opaque structs diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 940367b397100..ef19c0dc7cc5e 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -499,6 +499,10 @@ be imported in every test with `mod common;` That's all there is to the `tests` directory. The `tests` module isn't needed here, since the whole thing is focused on tests. +Note, when building integration tests, cargo will not pass the `test` attribute +to the compiler. It means that all parts in `cfg(test)` won't be included in +the build used in your integration tests. + Let's finally check out that third section: documentation tests. # Documentation tests diff --git a/src/doc/nomicon/destructors.md b/src/doc/nomicon/destructors.md index c6fa5b079db02..be4730cf8bce6 100644 --- a/src/doc/nomicon/destructors.md +++ b/src/doc/nomicon/destructors.md @@ -26,7 +26,7 @@ this is totally fine. For instance, a custom implementation of `Box` might write `Drop` like this: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; @@ -57,7 +57,7 @@ use-after-free the `ptr` because when drop exits, it becomes inaccessible. However this wouldn't work: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; @@ -135,7 +135,7 @@ The classic safe solution to overriding recursive drop and allowing moving out of Self during `drop` is to use an Option: ```rust -#![feature(alloc, heap_api, drop_in_place, unique)] +#![feature(alloc, heap_api, unique)] extern crate alloc; diff --git a/src/doc/nomicon/dropck.md b/src/doc/nomicon/dropck.md index f54933827b330..6114006cbb341 100644 --- a/src/doc/nomicon/dropck.md +++ b/src/doc/nomicon/dropck.md @@ -199,24 +199,42 @@ assert (unsafely) that a generic type's destructor is *guaranteed* to not access any expired data, even if its type gives it the capability to do so. -That attribute is called `unsafe_destructor_blind_to_params`. +That attribute is called `may_dangle` and was introduced in [RFC 1327] +(https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md). To deploy it on the Inspector example from above, we would write: ```rust,ignore struct Inspector<'a>(&'a u8, &'static str); -impl<'a> Drop for Inspector<'a> { - #[unsafe_destructor_blind_to_params] +unsafe impl<#[may_dangle] 'a> Drop for Inspector<'a> { fn drop(&mut self) { println!("Inspector(_, {}) knows when *not* to inspect.", self.1); } } ``` -This attribute has the word `unsafe` in it because the compiler is not -checking the implicit assertion that no potentially expired data +Use of this attribute requires the `Drop` impl to be marked `unsafe` because the +compiler is not checking the implicit assertion that no potentially expired data (e.g. `self.0` above) is accessed. +The attribute can be applied to any number of lifetime and type parameters. In +the following example, we assert that we access no data behind a reference of +lifetime `'b` and that the only uses of `T` will be moves or drops, but omit +the attribute from `'a` and `U`, because we do access data with that lifetime +and that type: + +```rust,ignore +use std::fmt::Display; + +struct Inspector<'a, 'b, T, U: Display>(&'a u8, &'b u8, T, U); + +unsafe impl<'a, #[may_dangle] 'b, #[may_dangle] T, U: Display> Drop for Inspector<'a, 'b, T, U> { + fn drop(&mut self) { + println!("Inspector({}, _, _, {})", self.0, self.3); + } +} +``` + It is sometimes obvious that no such access can occur, like the case above. However, when dealing with a generic type parameter, such access can occur indirectly. Examples of such indirect access are: @@ -263,7 +281,7 @@ some other method invoked by the destructor, rather than being written directly within it. In all of the above cases where the `&'a u8` is accessed in the -destructor, adding the `#[unsafe_destructor_blind_to_params]` +destructor, adding the `#[may_dangle]` attribute makes the type vulnerable to misuse that the borrower checker will not catch, inviting havoc. It is better to avoid adding the attribute. diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 459dc94f33686..38d843263ffda 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -59,7 +59,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// as long as `T` implements [`Send`] and [`Sync`][sync]. The disadvantage is /// that atomic operations are more expensive than ordinary memory accesses. /// If you are not sharing reference-counted values between threads, consider -/// using [`rc::Rc`] for lower overhead. [`Rc`] is a safe default, because +/// using [`rc::Rc`][`Rc`] for lower overhead. [`Rc`] is a safe default, because /// the compiler will catch any attempt to send an [`Rc`] between threads. /// However, a library might choose `Arc` in order to give library consumers /// more flexibility. diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 5409ade292360..b6f490e09cddf 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -103,6 +103,7 @@ pub struct ExchangeHeapSingleton { /// /// See the [module-level documentation](../../std/boxed/index.html) for more. #[lang = "owned_box"] +#[fundamental] #[stable(feature = "rust1", since = "1.0.0")] pub struct Box(Unique); @@ -292,6 +293,14 @@ impl Box { } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T: ?Sized> Drop for Box { + fn drop(&mut self) { + // FIXME: Do nothing, drop is currently performed by compiler. + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box { /// Creates a `Box`, with the `Default` value for T. diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index c67106cf57aaf..0c01eabd593ff 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -47,7 +47,7 @@ //! that the contained type `T` is shareable. Additionally, `Arc` is itself //! sendable while `Rc` is not. //! -//! This types allows for shared access to the contained data, and is often +//! This type allows for shared access to the contained data, and is often //! paired with synchronization primitives such as mutexes to allow mutation of //! shared resources. //! diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 010e378ef2f48..6108a06634bb8 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -17,9 +17,11 @@ //! pointer to the same value in the heap. When the last [`Rc`] pointer to a //! given value is destroyed, the pointed-to value is also destroyed. //! -//! Shared references in Rust disallow mutation by default, and `Rc` is no -//! exception. If you need to mutate through an [`Rc`], use [`Cell`] or -//! [`RefCell`]. +//! Shared references in Rust disallow mutation by default, and [`Rc`] +//! is no exception: you cannot obtain a mutable reference to +//! something inside an [`Rc`]. If you need mutability, put a [`Cell`] +//! or [`RefCell`] inside the [`Rc`]; see [an example of mutability +//! inside an Rc][mutability]. //! //! [`Rc`] uses non-atomic reference counting. This means that overhead is very //! low, but an [`Rc`] cannot be sent between threads, and consequently [`Rc`] @@ -214,6 +216,7 @@ //! [upgrade]: struct.Weak.html#method.upgrade //! [`None`]: ../../std/option/enum.Option.html#variant.None //! [assoc]: ../../book/method-syntax.html#associated-functions +//! [mutability]: ../../std/cell/index.html#introducing-mutability-inside-of-something-immutable #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 1edcb0b1f24de..7e616c0ff27cf 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -10,23 +10,20 @@ #![deny(warnings)] +#[macro_use] extern crate build_helper; extern crate gcc; use std::env; -use std::path::PathBuf; +use std::fs::{self, File}; +use std::path::{Path, PathBuf}; use std::process::Command; -use build_helper::run; +use build_helper::{run, rerun_if_changed_anything_in_dir, up_to_date}; fn main() { println!("cargo:rustc-cfg=cargobuild"); println!("cargo:rerun-if-changed=build.rs"); - let target = env::var("TARGET").expect("TARGET was not set"); - let host = env::var("HOST").expect("HOST was not set"); - let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let src_dir = env::current_dir().unwrap(); - // FIXME: This is a hack to support building targets that don't // support jemalloc alongside hosts that do. The jemalloc build is // controlled by a feature of the std crate, and if that feature @@ -35,6 +32,8 @@ fn main() { // that the feature set used by std is the same across all // targets, which means we have to build the alloc_jemalloc crate // for targets like emscripten, even if we don't use it. + let target = env::var("TARGET").expect("TARGET was not set"); + let host = env::var("HOST").expect("HOST was not set"); if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") || target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") || target.contains("redox") { @@ -57,6 +56,28 @@ fn main() { return; } + let build_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap()); + let build_dir = PathBuf::from(build_dir).join("jemalloc"); + let _ = fs::create_dir_all(&build_dir); + + if target.contains("windows") { + println!("cargo:rustc-link-lib=static=jemalloc"); + } else { + println!("cargo:rustc-link-lib=static=jemalloc_pic"); + } + println!("cargo:rustc-link-search=native={}/lib", build_dir.display()); + if target.contains("android") { + println!("cargo:rustc-link-lib=gcc"); + } else if !target.contains("windows") && !target.contains("musl") { + println!("cargo:rustc-link-lib=pthread"); + } + let src_dir = env::current_dir().unwrap().join("../jemalloc"); + rerun_if_changed_anything_in_dir(&src_dir); + let timestamp = build_dir.join("rustbuild.timestamp"); + if up_to_date(&Path::new("build.rs"), ×tamp) && up_to_date(&src_dir, ×tamp) { + return + } + let compiler = gcc::Config::new().get_compiler(); // only msvc returns None for ar so unwrap is okay let ar = build_helper::cc2ar(compiler.path(), &target).unwrap(); @@ -66,23 +87,8 @@ fn main() { .collect::>() .join(" "); - let mut stack = src_dir.join("../jemalloc") - .read_dir() - .unwrap() - .map(|e| e.unwrap()) - .filter(|e| &*e.file_name() != ".git") - .collect::>(); - while let Some(entry) = stack.pop() { - let path = entry.path(); - if entry.file_type().unwrap().is_dir() { - stack.extend(path.read_dir().unwrap().map(|e| e.unwrap())); - } else { - println!("cargo:rerun-if-changed={}", path.display()); - } - } - let mut cmd = Command::new("sh"); - cmd.arg(src_dir.join("../jemalloc/configure") + cmd.arg(src_dir.join("configure") .to_str() .unwrap() .replace("C:\\", "/c/") @@ -158,6 +164,7 @@ fn main() { } run(&mut cmd); + let mut make = Command::new(build_helper::make(&host)); make.current_dir(&build_dir) .arg("build_lib_static"); @@ -170,15 +177,16 @@ fn main() { run(&mut make); - if target.contains("windows") { - println!("cargo:rustc-link-lib=static=jemalloc"); - } else { - println!("cargo:rustc-link-lib=static=jemalloc_pic"); - } - println!("cargo:rustc-link-search=native={}/lib", build_dir.display()); - if target.contains("android") { - println!("cargo:rustc-link-lib=gcc"); - } else if !target.contains("windows") && !target.contains("musl") { - println!("cargo:rustc-link-lib=pthread"); + // The pthread_atfork symbols is used by jemalloc on android but the really + // old android we're building on doesn't have them defined, so just make + // sure the symbols are available. + if target.contains("androideabi") { + println!("cargo:rerun-if-changed=pthread_atfork_dummy.c"); + gcc::Config::new() + .flag("-fvisibility=hidden") + .file("pthread_atfork_dummy.c") + .compile("libpthread_atfork_dummy.a"); } + + t!(File::create(×tamp)); } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 241f8149d24d2..fc8a5455d1d07 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -143,7 +143,7 @@ mod imp { // we're building on doesn't have them defined, so just make sure the symbols // are available. #[no_mangle] - #[cfg(target_os = "android")] + #[cfg(all(target_os = "android", not(cargobuild)))] pub extern "C" fn pthread_atfork(_prefork: *mut u8, _postfork_parent: *mut u8, _postfork_child: *mut u8) diff --git a/src/liballoc_jemalloc/pthread_atfork_dummy.c b/src/liballoc_jemalloc/pthread_atfork_dummy.c new file mode 100644 index 0000000000000..4e3df0ab26c37 --- /dev/null +++ b/src/liballoc_jemalloc/pthread_atfork_dummy.c @@ -0,0 +1,16 @@ +// 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. + +// See comments in build.rs for why this exists +int pthread_atfork(void* prefork, + void* postfork_parent, + void* postfork_child) { + return 0; +} diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 87bc5e59ef78c..78b6107977781 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -17,6 +17,8 @@ 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; diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 561d8860dc880..39de87c08407f 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -79,6 +79,7 @@ pub use btree_set::BTreeSet; #[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; diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index fc49c9f56438c..11f513ed798e0 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -509,7 +509,7 @@ impl [T] { core_slice::SliceExt::swap(self, a, b) } - /// Reverse the order of elements in a slice, in place. + /// Reverses the order of elements in a slice, in place. /// /// # Example /// @@ -1062,7 +1062,7 @@ impl [T] { core_slice::SliceExt::binary_search_by_key(self, b, f) } - /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`. + /// Sorts the slice. /// /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. /// diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 70cedce9a905e..458d5114829f4 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1607,7 +1607,6 @@ impl str { /// Basic usage: /// /// ``` - /// # #![feature(str_replacen)] /// let s = "foo foo 123 foo"; /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2)); /// assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3)); @@ -1617,13 +1616,10 @@ impl str { /// When the pattern doesn't match: /// /// ``` - /// # #![feature(str_replacen)] /// let s = "this is old"; /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10)); /// ``` - #[unstable(feature = "str_replacen", - issue = "36436", - reason = "only need to replace first N matches")] + #[stable(feature = "str_replacen", since = "1.16.0")] pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String { // Hope to reduce the times of re-allocation let mut result = String::with_capacity(32); @@ -1795,11 +1791,9 @@ impl str { /// Basic usage: /// /// ``` - /// #![feature(repeat_str)] - /// /// assert_eq!("abc".repeat(4), String::from("abcabcabcabc")); /// ``` - #[unstable(feature = "repeat_str", issue = "37079")] + #[stable(feature = "repeat_str", since = "1.16.0")] pub fn repeat(&self, n: usize) -> String { let mut s = String::with_capacity(self.len() * n); s.extend((0..n).map(|_| self)); diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 5210c25b4e5c8..b184a8603e6bd 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1166,8 +1166,6 @@ impl String { /// Basic usage: /// /// ``` - /// #![feature(insert_str)] - /// /// let mut s = String::from("bar"); /// /// s.insert_str(0, "foo"); @@ -1175,9 +1173,7 @@ impl String { /// assert_eq!("foobar", s); /// ``` #[inline] - #[unstable(feature = "insert_str", - reason = "recent addition", - issue = "35553")] + #[stable(feature = "insert_str", since = "1.16.0")] pub fn insert_str(&mut self, idx: usize, string: &str) { assert!(self.is_char_boundary(idx)); @@ -1270,7 +1266,6 @@ impl String { /// # Examples /// /// ``` - /// # #![feature(string_split_off)] /// # fn main() { /// let mut hello = String::from("Hello, World!"); /// let world = hello.split_off(7); @@ -1279,7 +1274,7 @@ impl String { /// # } /// ``` #[inline] - #[unstable(feature = "string_split_off", issue = "38080")] + #[stable(feature = "string_split_off", since = "1.16.0")] pub fn split_off(&mut self, mid: usize) -> String { assert!(self.is_char_boundary(mid)); let other = self.vec.split_off(mid); diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index c5b904c8a2f0e..c45518438bd83 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -820,15 +820,13 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(dedup_by)] - /// /// let mut vec = vec![10, 20, 21, 30, 20]; /// /// vec.dedup_by_key(|i| *i / 10); /// /// assert_eq!(vec, [10, 20, 30, 20]); /// ``` - #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")] + #[stable(feature = "dedup_by", since = "1.16.0")] #[inline] pub fn dedup_by_key(&mut self, mut key: F) where F: FnMut(&mut T) -> K, K: PartialEq { self.dedup_by(|a, b| key(a) == key(b)) @@ -841,7 +839,6 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(dedup_by)] /// use std::ascii::AsciiExt; /// /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; @@ -850,7 +847,7 @@ impl Vec { /// /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]); /// ``` - #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")] + #[stable(feature = "dedup_by", since = "1.16.0")] pub fn dedup_by(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool { unsafe { // Although we have a mutable reference to `self`, we cannot make @@ -1961,7 +1958,7 @@ impl IntoIter { /// assert_eq!(into_iter.next().unwrap(), 'z'); /// ``` #[stable(feature = "vec_into_iter_as_slice", since = "1.15.0")] - pub fn as_mut_slice(&self) -> &mut [T] { + pub fn as_mut_slice(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.ptr as *mut T, self.len()) } diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index fea2d111f472e..5e1adb3d808ce 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -469,9 +469,9 @@ impl VecDeque { /// buf.push_back(3); /// buf.push_back(4); /// buf.push_back(5); + /// assert_eq!(buf, [3, 4, 5]); /// buf.swap(0, 2); - /// assert_eq!(buf[0], 5); - /// assert_eq!(buf[2], 3); + /// assert_eq!(buf, [5, 4, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(&mut self, i: usize, j: usize) { @@ -643,21 +643,17 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(deque_extras)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); /// buf.push_back(5); /// buf.push_back(10); /// buf.push_back(15); + /// assert_eq!(buf, [5, 10, 15]); /// buf.truncate(1); - /// assert_eq!(buf.len(), 1); - /// assert_eq!(Some(&5), buf.get(0)); + /// assert_eq!(buf, [5]); /// ``` - #[unstable(feature = "deque_extras", - reason = "matches collection reform specification; waiting on panic semantics", - issue = "27788")] + #[stable(feature = "deque_extras", since = "1.16.0")] pub fn truncate(&mut self, len: usize) { for _ in len..self.len() { self.pop_back(); @@ -830,8 +826,9 @@ impl VecDeque { /// use std::collections::VecDeque; /// /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); - /// assert_eq!(vec![3].into_iter().collect::>(), v.drain(2..).collect()); - /// assert_eq!(vec![1, 2].into_iter().collect::>(), v); + /// let drained = v.drain(2..).collect::>(); + /// assert_eq!(drained, [3]); + /// assert_eq!(v, [1, 2]); /// /// // A full range clears all contents /// v.drain(..); @@ -1183,11 +1180,10 @@ impl VecDeque { /// buf.push_back(1); /// buf.push_back(2); /// buf.push_back(3); + /// assert_eq!(buf, [1, 2, 3]); /// /// assert_eq!(buf.swap_remove_back(0), Some(1)); - /// assert_eq!(buf.len(), 2); - /// assert_eq!(buf[0], 3); - /// assert_eq!(buf[1], 2); + /// assert_eq!(buf, [3, 2]); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn swap_remove_back(&mut self, index: usize) -> Option { @@ -1219,11 +1215,10 @@ impl VecDeque { /// buf.push_back(1); /// buf.push_back(2); /// buf.push_back(3); + /// assert_eq!(buf, [1, 2, 3]); /// /// assert_eq!(buf.swap_remove_front(2), Some(3)); - /// assert_eq!(buf.len(), 2); - /// assert_eq!(buf[0], 2); - /// assert_eq!(buf[1], 1); + /// assert_eq!(buf, [2, 1]); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn swap_remove_front(&mut self, index: usize) -> Option { @@ -1254,11 +1249,10 @@ impl VecDeque { /// vec_deque.push_back('a'); /// vec_deque.push_back('b'); /// vec_deque.push_back('c'); + /// assert_eq!(vec_deque, &['a', 'b', 'c']); /// /// vec_deque.insert(1, 'd'); - /// - /// let vec = vec_deque.into_iter().collect::>(); - /// assert_eq!(vec, ['a', 'd', 'b', 'c']); + /// assert_eq!(vec_deque, &['a', 'd', 'b', 'c']); /// ``` #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn insert(&mut self, index: usize, value: T) { @@ -1482,9 +1476,10 @@ impl VecDeque { /// buf.push_back(1); /// buf.push_back(2); /// buf.push_back(3); + /// assert_eq!(buf, [1, 2, 3]); /// /// assert_eq!(buf.remove(1), Some(2)); - /// assert_eq!(buf.get(1), Some(&3)); + /// assert_eq!(buf, [1, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, index: usize) -> Option { @@ -1663,9 +1658,8 @@ impl VecDeque { /// /// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect(); /// let buf2 = buf.split_off(1); - /// // buf = [1], buf2 = [2, 3] - /// assert_eq!(buf.len(), 1); - /// assert_eq!(buf2.len(), 2); + /// assert_eq!(buf, [1]); + /// assert_eq!(buf2, [2, 3]); /// ``` #[inline] #[stable(feature = "split_off", since = "1.4.0")] @@ -1722,11 +1716,11 @@ impl VecDeque { /// ``` /// use std::collections::VecDeque; /// - /// let mut buf: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); - /// let mut buf2: VecDeque<_> = vec![4, 5, 6].into_iter().collect(); + /// let mut buf: VecDeque<_> = vec![1, 2].into_iter().collect(); + /// let mut buf2: VecDeque<_> = vec![3, 4].into_iter().collect(); /// buf.append(&mut buf2); - /// assert_eq!(buf.len(), 6); - /// assert_eq!(buf2.len(), 0); + /// assert_eq!(buf, [1, 2, 3, 4]); + /// assert_eq!(buf2, []); /// ``` #[inline] #[stable(feature = "append", since = "1.4.0")] @@ -1749,9 +1743,7 @@ impl VecDeque { /// let mut buf = VecDeque::new(); /// buf.extend(1..5); /// buf.retain(|&x| x%2 == 0); - /// - /// let v: Vec<_> = buf.into_iter().collect(); - /// assert_eq!(&v[..], &[2, 4]); + /// assert_eq!(buf, [2, 4]); /// ``` #[stable(feature = "vec_deque_retain", since = "1.4.0")] pub fn retain(&mut self, mut f: F) @@ -1779,23 +1771,21 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(deque_extras)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); /// buf.push_back(5); /// buf.push_back(10); /// buf.push_back(15); + /// assert_eq!(buf, [5, 10, 15]); + /// /// buf.resize(2, 0); - /// buf.resize(6, 20); - /// for (a, b) in [5, 10, 20, 20, 20, 20].iter().zip(&buf) { - /// assert_eq!(a, b); - /// } + /// assert_eq!(buf, [5, 10]); + /// + /// buf.resize(5, 20); + /// assert_eq!(buf, [5, 10, 20, 20, 20]); /// ``` - #[unstable(feature = "deque_extras", - reason = "matches collection reform specification; waiting on panic semantics", - issue = "27788")] + #[stable(feature = "deque_extras", since = "1.16.0")] pub fn resize(&mut self, new_len: usize, value: T) { let len = self.len(); @@ -2170,6 +2160,46 @@ impl PartialEq for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for VecDeque {} +macro_rules! __impl_slice_eq1 { + ($Lhs: ty, $Rhs: ty) => { + __impl_slice_eq1! { $Lhs, $Rhs, Sized } + }; + ($Lhs: ty, $Rhs: ty, $Bound: ident) => { + #[stable(feature = "vec-deque-partial-eq-slice", since = "1.16.0")] + impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { + fn eq(&self, other: &$Rhs) -> bool { + if self.len() != other.len() { + return false; + } + let (sa, sb) = self.as_slices(); + let (oa, ob) = other[..].split_at(sa.len()); + sa == oa && sb == ob + } + } + } +} + +__impl_slice_eq1! { VecDeque, Vec } +__impl_slice_eq1! { VecDeque, &'b [B] } +__impl_slice_eq1! { VecDeque, &'b mut [B] } + +macro_rules! array_impls { + ($($N: expr)+) => { + $( + __impl_slice_eq1! { VecDeque, [B; $N] } + __impl_slice_eq1! { VecDeque, &'b [B; $N] } + __impl_slice_eq1! { VecDeque, &'b mut [B; $N] } + )+ + } +} + +array_impls! { + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 +} + #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for VecDeque { fn partial_cmp(&self, other: &VecDeque) -> Option { @@ -2442,7 +2472,7 @@ mod tests { let final_len = usable_cap / 2; for len in 0..final_len { - let expected = if back { + let expected: VecDeque<_> = if back { (0..len).collect() } else { (0..len).rev().collect() @@ -2491,7 +2521,7 @@ mod tests { // len is the length *after* insertion for len in 1..cap { // 0, 1, 2, .., len - 1 - let expected = (0..).take(len).collect(); + let expected = (0..).take(len).collect::>(); for tail_pos in 0..cap { for to_insert in 0..len { tester.tail = tail_pos; @@ -2524,7 +2554,7 @@ mod tests { // len is the length *after* removal for len in 0..cap - 1 { // 0, 1, 2, .., len - 1 - let expected = (0..).take(len).collect(); + let expected = (0..).take(len).collect::>(); for tail_pos in 0..cap { for to_remove in 0..len + 1 { tester.tail = tail_pos; @@ -2599,7 +2629,7 @@ mod tests { for len in 0..cap + 1 { // 0, 1, 2, .., len - 1 - let expected = (0..).take(len).collect(); + let expected = (0..).take(len).collect::>(); for tail_pos in 0..max_cap + 1 { tester.tail = tail_pos; tester.head = tail_pos; @@ -2632,9 +2662,9 @@ mod tests { // index to split at for at in 0..len + 1 { // 0, 1, 2, .., at - 1 (may be empty) - let expected_self = (0..).take(at).collect(); + let expected_self = (0..).take(at).collect::>(); // at, at + 1, .., len - 1 (may be empty) - let expected_other = (at..).take(len - at).collect(); + let expected_other = (at..).take(len - at).collect::>(); for tail_pos in 0..cap { tester.tail = tail_pos; diff --git a/src/libcollectionstest/enum_set.rs b/src/libcollectionstest/enum_set.rs deleted file mode 100644 index 972361326d7bb..0000000000000 --- a/src/libcollectionstest/enum_set.rs +++ /dev/null @@ -1,268 +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. - -use std::mem; - -use collections::enum_set::{CLike, EnumSet}; - -use self::Foo::*; - -#[derive(Copy, Clone, PartialEq, Debug)] -#[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) } - } -} - -#[test] -fn test_new() { - let e: EnumSet = EnumSet::new(); - assert!(e.is_empty()); -} - -#[test] -fn test_show() { - let mut e = EnumSet::new(); - assert!(format!("{:?}", e) == "{}"); - e.insert(A); - assert!(format!("{:?}", e) == "{A}"); - e.insert(C); - assert!(format!("{:?}", e) == "{A, C}"); -} - -#[test] -fn test_len() { - let mut e = EnumSet::new(); - assert_eq!(e.len(), 0); - e.insert(A); - e.insert(B); - e.insert(C); - assert_eq!(e.len(), 3); - e.remove(&A); - assert_eq!(e.len(), 2); - e.clear(); - assert_eq!(e.len(), 0); -} - -/////////////////////////////////////////////////////////////////////////// -// intersect - -#[test] -fn test_two_empties_do_not_intersect() { - let e1: EnumSet = EnumSet::new(); - let e2: EnumSet = EnumSet::new(); - assert!(e1.is_disjoint(&e2)); -} - -#[test] -fn test_empty_does_not_intersect_with_full() { - let e1: EnumSet = EnumSet::new(); - - let mut e2: EnumSet = EnumSet::new(); - e2.insert(A); - e2.insert(B); - e2.insert(C); - - assert!(e1.is_disjoint(&e2)); -} - -#[test] -fn test_disjoint_intersects() { - let mut e1: EnumSet = EnumSet::new(); - e1.insert(A); - - let mut e2: EnumSet = EnumSet::new(); - e2.insert(B); - - assert!(e1.is_disjoint(&e2)); -} - -#[test] -fn test_overlapping_intersects() { - let mut e1: EnumSet = EnumSet::new(); - e1.insert(A); - - let mut e2: EnumSet = EnumSet::new(); - e2.insert(A); - e2.insert(B); - - assert!(!e1.is_disjoint(&e2)); -} - -/////////////////////////////////////////////////////////////////////////// -// contains and contains_elem - -#[test] -fn test_superset() { - let mut e1: EnumSet = EnumSet::new(); - e1.insert(A); - - let mut e2: EnumSet = EnumSet::new(); - e2.insert(A); - e2.insert(B); - - let mut e3: EnumSet = EnumSet::new(); - e3.insert(C); - - assert!(e1.is_subset(&e2)); - assert!(e2.is_superset(&e1)); - assert!(!e3.is_superset(&e2)); - assert!(!e2.is_superset(&e3)) -} - -#[test] -fn test_contains() { - let mut e1: EnumSet = EnumSet::new(); - e1.insert(A); - assert!(e1.contains(&A)); - assert!(!e1.contains(&B)); - assert!(!e1.contains(&C)); - - e1.insert(A); - e1.insert(B); - assert!(e1.contains(&A)); - assert!(e1.contains(&B)); - assert!(!e1.contains(&C)); -} - -/////////////////////////////////////////////////////////////////////////// -// iter - -#[test] -fn test_iterator() { - let mut e1: EnumSet = EnumSet::new(); - - let elems: Vec = e1.iter().collect(); - assert!(elems.is_empty()); - - e1.insert(A); - let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A]); - - e1.insert(C); - let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A, C]); - - e1.insert(C); - let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A, C]); - - e1.insert(B); - let elems: Vec<_> = e1.iter().collect(); - assert_eq!(elems, [A, B, C]); -} - -/////////////////////////////////////////////////////////////////////////// -// operators - -#[test] -fn test_operators() { - let mut e1: EnumSet = EnumSet::new(); - e1.insert(A); - e1.insert(C); - - let mut e2: EnumSet = EnumSet::new(); - e2.insert(B); - e2.insert(C); - - let e_union = e1 | e2; - let elems: Vec<_> = e_union.iter().collect(); - assert_eq!(elems, [A, B, C]); - - let e_intersection = e1 & e2; - let elems: Vec<_> = e_intersection.iter().collect(); - assert_eq!(elems, [C]); - - // Another way to express intersection - let e_intersection = e1 - (e1 - e2); - let elems: Vec<_> = e_intersection.iter().collect(); - assert_eq!(elems, [C]); - - let e_subtract = e1 - e2; - let elems: Vec<_> = e_subtract.iter().collect(); - assert_eq!(elems, [A]); - - // Bitwise XOR of two sets, aka symmetric difference - let e_symmetric_diff = e1 ^ e2; - let elems: Vec<_> = e_symmetric_diff.iter().collect(); - assert_eq!(elems, [A, B]); - - // Another way to express symmetric difference - let e_symmetric_diff = (e1 - e2) | (e2 - e1); - let elems: Vec<_> = e_symmetric_diff.iter().collect(); - assert_eq!(elems, [A, B]); - - // Yet another way to express symmetric difference - let e_symmetric_diff = (e1 | e2) - (e1 & e2); - let elems: Vec<_> = e_symmetric_diff.iter().collect(); - assert_eq!(elems, [A, B]); -} - -#[test] -#[should_panic] -fn test_overflow() { - #[allow(dead_code)] - #[derive(Copy, Clone)] - #[repr(usize)] - enum Bar { - V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, - V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, - V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, - V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, - V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, - V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, - V60, V61, V62, V63, V64, V65, V66, V67, V68, V69, - } - - impl CLike for Bar { - fn to_usize(&self) -> usize { - *self as usize - } - - fn from_usize(v: usize) -> Bar { - unsafe { mem::transmute(v) } - } - } - let mut set = EnumSet::new(); - set.insert(Bar::V64); -} - -#[test] -fn test_extend_ref() { - let mut a = EnumSet::new(); - a.insert(A); - - a.extend(&[A, C]); - - assert_eq!(a.len(), 2); - assert!(a.contains(&A)); - assert!(a.contains(&C)); - - let mut b = EnumSet::new(); - b.insert(B); - - a.extend(&b); - - assert_eq!(a.len(), 3); - assert!(a.contains(&A)); - assert!(a.contains(&B)); - assert!(a.contains(&C)); -} diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index bec3965a9589b..b146672893f8d 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -18,17 +18,12 @@ #![feature(collections)] #![feature(collections_bound)] #![feature(const_fn)] -#![feature(dedup_by)] -#![feature(enumset)] #![feature(exact_size_is_empty)] #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(rand)] -#![feature(repeat_str)] #![feature(step_by)] #![feature(str_escape)] -#![feature(str_replacen)] -#![feature(string_split_off)] #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] @@ -47,7 +42,6 @@ mod bench; mod binary_heap; mod btree; mod cow_str; -mod enum_set; mod fmt; mod linked_list; mod slice; diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index cdf022e4f02f3..bb60f888f8be6 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -603,6 +603,25 @@ fn test_eq() { assert!(e == VecDeque::new()); } +#[test] +fn test_partial_eq_array() { + let d = VecDeque::::new(); + assert!(d == []); + + let mut d = VecDeque::new(); + d.push_front('a'); + assert!(d == ['a']); + + let mut d = VecDeque::new(); + d.push_back('a'); + assert!(d == ['a']); + + let mut d = VecDeque::new(); + d.push_back('a'); + d.push_back('b'); + assert!(d == ['a', 'b']); +} + #[test] fn test_hash() { let mut x = VecDeque::new(); diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index c3f862e7c5418..ab44342ebf02f 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -15,10 +15,18 @@ //! references. We say that `Cell` and `RefCell` provide 'interior mutability', in contrast //! with typical Rust types that exhibit 'inherited mutability'. //! -//! Cell types come in two flavors: `Cell` and `RefCell`. `Cell` provides `get` and `set` -//! methods that change the interior value with a single method call. `Cell` though is only -//! compatible with types that implement `Copy`. For other types, one must use the `RefCell` -//! type, acquiring a write lock before mutating. +//! Cell types come in two flavors: `Cell` and `RefCell`. `Cell` implements interior +//! mutability by moving values in and out of the `Cell`. To use references instead of values, +//! one must use the `RefCell` type, acquiring a write lock before mutating. `Cell` provides +//! methods to retrieve and change the current interior value: +//! +//! - For types that implement `Copy`, the `get` method retrieves the current interior value. +//! - For types that implement `Default`, the `take` method replaces the current interior value +//! with `Default::default()` and returns the replaced value. +//! - For all types, the `replace` method replaces the current interior value and returns the +//! replaced value and the `into_inner` method consumes the `Cell` and returns the interior +//! value. Additionally, the `set` method replaces the interior value, dropping the replaced +//! value. //! //! `RefCell` uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can //! claim temporary, exclusive, mutable access to the inner value. Borrows for `RefCell`s are @@ -176,9 +184,10 @@ use cmp::Ordering; use fmt::{self, Debug, Display}; use marker::Unsize; +use mem; use ops::{Deref, DerefMut, CoerceUnsized}; -/// A mutable memory location that admits only `Copy` data. +/// A mutable memory location. /// /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] @@ -187,23 +196,6 @@ pub struct Cell { } impl Cell { - /// Creates a new `Cell` containing the given value. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub const fn new(value: T) -> Cell { - Cell { - value: UnsafeCell::new(value), - } - } - /// Returns a copy of the contained value. /// /// # Examples @@ -221,25 +213,6 @@ impl Cell { unsafe{ *self.value.get() } } - /// Sets the contained value. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// c.set(10); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn set(&self, value: T) { - unsafe { - *self.value.get() = value; - } - } - /// Returns a reference to the underlying `UnsafeCell`. /// /// # Examples @@ -378,6 +351,100 @@ impl From for Cell { } } +impl Cell { + /// Creates a new `Cell` containing the given value. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub const fn new(value: T) -> Cell { + Cell { + value: UnsafeCell::new(value), + } + } + + /// Sets the contained value. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// + /// c.set(10); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn set(&self, val: T) { + let old = self.replace(val); + drop(old); + } + + /// Replaces the contained value. + /// + /// # Examples + /// + /// ``` + /// #![feature(move_cell)] + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// let old = c.replace(10); + /// + /// assert_eq!(5, old); + /// ``` + #[unstable(feature = "move_cell", issue = "39264")] + pub fn replace(&self, val: T) -> T { + mem::replace(unsafe { &mut *self.value.get() }, val) + } + + /// Unwraps the value. + /// + /// # Examples + /// + /// ``` + /// #![feature(move_cell)] + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// let five = c.into_inner(); + /// + /// assert_eq!(five, 5); + /// ``` + #[unstable(feature = "move_cell", issue = "39264")] + pub fn into_inner(self) -> T { + unsafe { self.value.into_inner() } + } +} + +impl Cell { + /// Takes the value of the cell, leaving `Default::default()` in its place. + /// + /// # Examples + /// + /// ``` + /// #![feature(move_cell)] + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// let five = c.take(); + /// + /// assert_eq!(five, 5); + /// assert_eq!(c.into_inner(), 0); + /// ``` + #[unstable(feature = "move_cell", issue = "39264")] + pub fn take(&self) -> T { + self.replace(Default::default()) + } +} + #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U> CoerceUnsized> for Cell {} diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 830bbc079ad1e..abd686b15e22b 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -18,25 +18,33 @@ //! 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 -//! - 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 +//! - Impl 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 //! -//! As a library author, you should prefer implementing `From` or `TryFrom` rather than -//! `Into` or `TryInto`, as `From` and `TryFrom` provide greater flexibility and offer -//! equivalent `Into` or `TryInto` implementations for free, thanks to a blanket implementation +//! 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. //! //! # Generic impl //! -//! - `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()` +//! - [`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 //! //! See each trait for usage examples. +//! +//! [`Into`]: trait.Into.html +//! [`From`]: trait.From.html +//! [`TryFrom`]: trait.TryFrom.html +//! [`TryInto`]: trait.TryInto.html +//! [`AsRef`]: trait.AsRef.html +//! [`AsMut`]: trait.AsMut.html #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 92657a6d0b1ca..dd6edc7d39af0 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -307,6 +307,7 @@ pub trait BuildHasher { /// [`BuildHasher`]: trait.BuildHasher.html /// [`Default`]: ../default/trait.Default.html /// [`Hasher`]: trait.Hasher.html +/// [`HashMap`]: ../../std/collections/struct.HashMap.html #[stable(since = "1.7.0", feature = "build_hasher")] pub struct BuildHasherDefault(marker::PhantomData); diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 91c09c5530565..3b406873d4b19 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1108,9 +1108,9 @@ pub trait Iterator { /// /// One of the keys to `collect()`'s power is that many things you might /// not think of as 'collections' actually are. For example, a [`String`] - /// is a collection of [`char`]s. And a collection of [`Result`] can - /// be thought of as single [`Result`]`, E>`. See the examples - /// below for more. + /// is a collection of [`char`]s. And a collection of + /// [`Result`][`Result`] can be thought of as single + /// [`Result`]`, E>`. See the examples below for more. /// /// Because `collect()` is so general, it can cause problems with type /// inference. As such, `collect()` is one of the few times you'll see diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 8871e1fa840ef..c4d7b2dcf96fb 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -60,7 +60,7 @@ //! the optional owned box, [`Option`]`<`[`Box`]`>`. //! //! The following example uses [`Option`] to create an optional box of -//! [`i32`]. Notice that in order to use the inner [`i32`] value first the +//! [`i32`]. Notice that in order to use the inner [`i32`] value first, the //! `check_optional` function needs to use pattern matching to //! determine whether the box has a value (i.e. it is [`Some(...)`][`Some`]) or //! not ([`None`]). @@ -74,8 +74,8 @@ //! //! fn check_optional(optional: &Option>) { //! match *optional { -//! Some(ref p) => println!("have value {}", p), -//! None => println!("have no value"), +//! Some(ref p) => println!("has value {}", p), +//! None => println!("has no value"), //! } //! } //! ``` diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index bf5a59c45e4d3..02851c224e2e3 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -448,7 +448,6 @@ impl *const T { /// Basic usage: /// /// ``` - /// #![feature(ptr_wrapping_offset)] /// // Iterate using a raw pointer in increments of two elements /// let data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *const u8 = data.as_ptr(); @@ -463,7 +462,7 @@ impl *const T { /// ptr = ptr.wrapping_offset(step); /// } /// ``` - #[unstable(feature = "ptr_wrapping_offset", issue = "37570")] + #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[inline] pub fn wrapping_offset(self, count: isize) -> *const T where T: Sized { unsafe { @@ -572,7 +571,6 @@ impl *mut T { /// Basic usage: /// /// ``` - /// #![feature(ptr_wrapping_offset)] /// // Iterate using a raw pointer in increments of two elements /// let mut data = [1u8, 2, 3, 4, 5]; /// let mut ptr: *mut u8 = data.as_mut_ptr(); @@ -587,7 +585,7 @@ impl *mut T { /// } /// assert_eq!(&data, &[0, 2, 0, 4, 0]); /// ``` - #[unstable(feature = "ptr_wrapping_offset", issue = "37570")] + #[stable(feature = "ptr_wrapping_offset", since = "1.16.0")] #[inline] pub fn wrapping_offset(self, count: isize) -> *mut T where T: Sized { unsafe { diff --git a/src/libcore/result.rs b/src/libcore/result.rs index f02df88bb2efa..0a2e363965347 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -840,8 +840,6 @@ impl Result { /// `Err` on error. /// /// ``` - /// #![feature(result_unwrap_or_default)] - /// /// let good_year_from_input = "1909"; /// let bad_year_from_input = "190blarg"; /// let good_year = good_year_from_input.parse().unwrap_or_default(); @@ -854,7 +852,7 @@ impl Result { /// [`FromStr`]: ../../std/str/trait.FromStr.html /// ``` #[inline] - #[unstable(feature = "result_unwrap_or_default", issue = "37516")] + #[stable(feature = "result_unwrap_or_default", since = "1.16.0")] pub fn unwrap_or_default(self) -> T { match self { Ok(x) => x, diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index a3cb12844777b..743e3c41170a3 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -24,7 +24,7 @@ //! same as [LLVM atomic orderings][1]. For more information see the [nomicon][2]. //! //! [1]: http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations -//! [2]: https://doc.rust-lang.org/nomicon/atomics.html +//! [2]: ../../../nomicon/atomics.html //! //! Atomic variables are safe to share between threads (they implement `Sync`) //! but they do not themselves provide the mechanism for sharing and follow the @@ -144,7 +144,7 @@ unsafe impl Sync for AtomicPtr {} /// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations). /// /// For more information see the [nomicon][1]. -/// [1]: https://doc.rust-lang.org/nomicon/atomics.html +/// [1]: ../../../nomicon/atomics.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Debug)] pub enum Ordering { diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index 724a312ea79e0..8585f2f087113 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -209,6 +209,37 @@ fn cell_default() { assert_eq!(0, cell.get()); } +#[test] +fn cell_set() { + let cell = Cell::new(10); + cell.set(20); + assert_eq!(20, cell.get()); + + let cell = Cell::new("Hello".to_owned()); + cell.set("World".to_owned()); + assert_eq!("World".to_owned(), cell.into_inner()); +} + +#[test] +fn cell_replace() { + let cell = Cell::new(10); + assert_eq!(10, cell.replace(20)); + assert_eq!(20, cell.get()); + + let cell = Cell::new("Hello".to_owned()); + assert_eq!("Hello".to_owned(), cell.replace("World".to_owned())); + assert_eq!("World".to_owned(), cell.into_inner()); +} + +#[test] +fn cell_into_inner() { + let cell = Cell::new(10); + assert_eq!(10, cell.into_inner()); + + let cell = Cell::new("Hello world".to_owned()); + assert_eq!("Hello world".to_owned(), cell.into_inner()); +} + #[test] fn refcell_default() { let cell: RefCell = Default::default(); diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 0d12433813343..53ac17c052f6a 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -66,7 +66,6 @@ fn test_writer_hasher() { assert_eq!(hash(& s), 97 + 0xFF); let cs: &[u8] = &[1, 2, 3]; assert_eq!(hash(& cs), 9); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let cs: Box<[u8]> = Box::new([1, 2, 3]); assert_eq!(hash(& cs), 9); diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index 99d312930533f..6d02f76c33d16 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -700,7 +700,6 @@ fn test_collect() { #[test] fn test_all() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); assert!(v.iter().all(|&x| x < 10)); assert!(!v.iter().all(|&x| x % 2 == 0)); @@ -710,7 +709,6 @@ fn test_all() { #[test] fn test_any() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let v: Box<[isize]> = Box::new([1, 2, 3, 4, 5]); assert!(v.iter().any(|&x| x < 10)); assert!(v.iter().any(|&x| x % 2 == 0)); diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index fed5b86c369e8..e06b757691e5a 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -32,8 +32,8 @@ #![feature(unicode)] #![feature(unique)] #![feature(ordering_chaining)] -#![feature(result_unwrap_or_default)] #![feature(ptr_unaligned)] +#![feature(move_cell)] #![feature(fmt_internals)] extern crate core; diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 2878ff5e2846e..b51a7d4104ab9 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -327,6 +327,69 @@ struct ListNode { This works because `Box` is a pointer, so its size is well-known. "##, +E0106: r##" +This error indicates that a lifetime is missing from a type. If it is an error +inside a function signature, the problem may be with failing to adhere to the +lifetime elision rules (see below). + +Here are some simple examples of where you'll run into this error: + +```compile_fail,E0106 +struct Foo { x: &bool } // error +struct Foo<'a> { x: &'a bool } // correct + +enum Bar { A(u8), B(&bool), } // error +enum Bar<'a> { A(u8), B(&'a bool), } // correct + +type MyStr = &str; // error +type MyStr<'a> = &'a str; // correct +``` + +Lifetime elision is a special, limited kind of inference for lifetimes in +function signatures which allows you to leave out lifetimes in certain cases. +For more background on lifetime elision see [the book][book-le]. + +The lifetime elision rules require that any function signature with an elided +output lifetime must either have + + - exactly one input lifetime + - or, multiple input lifetimes, but the function must also be a method with a + `&self` or `&mut self` receiver + +In the first case, the output lifetime is inferred to be the same as the unique +input lifetime. In the second case, the lifetime is instead inferred to be the +same as the lifetime on `&self` or `&mut self`. + +Here are some examples of elision errors: + +```compile_fail,E0106 +// error, no input lifetimes +fn foo() -> &str { } + +// error, `x` and `y` have distinct lifetimes inferred +fn bar(x: &str, y: &str) -> &str { } + +// error, `y`'s lifetime is inferred to be distinct from `x`'s +fn baz<'a>(x: &'a str, y: &str) -> &str { } +``` + +Here's an example that is currently an error, but may work in a future version +of Rust: + +```compile_fail,E0106 +struct Foo<'a>(&'a str); + +trait Quux { } +impl Quux for Foo { } +``` + +Lifetime elision in implementation headers was part of the lifetime elision +RFC. It is, however, [currently unimplemented][iss15872]. + +[book-le]: https://doc.rust-lang.org/nightly/book/lifetimes.html#lifetime-elision +[iss15872]: https://github.com/rust-lang/rust/issues/15872 +"##, + E0109: r##" You tried to give a type parameter to a type which doesn't need it. Erroneous code example: diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index d4095c6875c1d..4b3e0d29101e4 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -301,7 +301,7 @@ pub trait Visitor<'v> : Sized { fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) { walk_ty_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } fn visit_variant_data(&mut self, @@ -421,7 +421,7 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v PolyTraitRef, - _modifier: &'v TraitBoundModifier) + _modifier: TraitBoundModifier) where V: Visitor<'v> { walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes); @@ -547,8 +547,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyPtr(ref mutable_type) => { visitor.visit_ty(&mutable_type.ty) } - TyRptr(ref opt_lifetime, ref mutable_type) => { - walk_list!(visitor, visit_lifetime, opt_lifetime); + TyRptr(ref lifetime, ref mutable_type) => { + visitor.visit_lifetime(lifetime); visitor.visit_ty(&mutable_type.ty) } TyNever => {}, @@ -566,8 +566,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_ty(ty); visitor.visit_nested_body(length) } - TyTraitObject(ref bounds) => { - walk_list!(visitor, visit_ty_param_bound, bounds); + TyTraitObject(ref bounds, ref lifetime) => { + for bound in bounds { + visitor.visit_poly_trait_ref(bound, TraitBoundModifier::None); + } + visitor.visit_lifetime(lifetime); } TyImplTrait(ref bounds) => { walk_list!(visitor, visit_ty_param_bound, bounds); @@ -695,7 +698,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) { match *bound { - TraitTyParamBound(ref typ, ref modifier) => { + TraitTyParamBound(ref typ, modifier) => { visitor.visit_poly_trait_ref(typ, modifier); } RegionTyParamBound(ref lifetime) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 88d461cab9f40..8a4acb3d03880 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -41,12 +41,12 @@ // in the HIR, especially for multiple identifiers. use hir; -use hir::map::Definitions; +use hir::map::{Definitions, DefKey}; use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId}; use hir::def::{Def, PathResolution}; use session::Session; -use util::nodemap::{NodeMap, FxHashMap}; +use util::nodemap::{DefIdMap, NodeMap, FxHashMap}; use std::collections::BTreeMap; use std::iter; @@ -78,6 +78,8 @@ pub struct LoweringContext<'a> { trait_items: BTreeMap, impl_items: BTreeMap, bodies: FxHashMap, + + type_def_lifetime_params: DefIdMap, } pub trait Resolver { @@ -110,6 +112,7 @@ pub fn lower_crate(sess: &Session, trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), bodies: FxHashMap(), + type_def_lifetime_params: DefIdMap(), }.lower_crate(krate) } @@ -123,24 +126,33 @@ enum ParamMode { impl<'a> LoweringContext<'a> { fn lower_crate(mut self, c: &Crate) -> hir::Crate { - self.lower_items(c); - let module = self.lower_mod(&c.module); - let attrs = self.lower_attrs(&c.attrs); - let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); + /// Full-crate AST visitor that inserts into a fresh + /// `LoweringContext` any information that may be + /// needed from arbitrary locations in the crate. + /// E.g. The number of lifetime generic parameters + /// declared for every type and trait definition. + struct MiscCollector<'lcx, 'interner: 'lcx> { + lctx: &'lcx mut LoweringContext<'interner>, + } - hir::Crate { - module: module, - attrs: attrs, - span: c.span, - exported_macros: exported_macros, - items: self.items, - trait_items: self.trait_items, - impl_items: self.impl_items, - bodies: self.bodies, + impl<'lcx, 'interner> Visitor<'lcx> for MiscCollector<'lcx, 'interner> { + fn visit_item(&mut self, item: &'lcx Item) { + match item.node { + ItemKind::Struct(_, ref generics) | + ItemKind::Union(_, ref generics) | + ItemKind::Enum(_, ref generics) | + ItemKind::Ty(_, ref generics) | + ItemKind::Trait(_, ref generics, ..) => { + let def_id = self.lctx.resolver.definitions().local_def_id(item.id); + let count = generics.lifetimes.len(); + self.lctx.type_def_lifetime_params.insert(def_id, count); + } + _ => {} + } + visit::walk_item(self, item); + } } - } - fn lower_items(&mut self, c: &Crate) { struct ItemLowerer<'lcx, 'interner: 'lcx> { lctx: &'lcx mut LoweringContext<'interner>, } @@ -167,8 +179,23 @@ impl<'a> LoweringContext<'a> { } } - let mut item_lowerer = ItemLowerer { lctx: self }; - visit::walk_crate(&mut item_lowerer, c); + visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c); + visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c); + + let module = self.lower_mod(&c.module); + let attrs = self.lower_attrs(&c.attrs); + let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); + + hir::Crate { + module: module, + attrs: attrs, + span: c.span, + exported_macros: exported_macros, + items: self.items, + trait_items: self.trait_items, + impl_items: self.impl_items, + bodies: self.bodies, + } } fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>) @@ -232,6 +259,14 @@ impl<'a> LoweringContext<'a> { result } + fn def_key(&mut self, id: DefId) -> DefKey { + if id.is_local() { + self.resolver.definitions().def_key(id.index) + } else { + self.sess.cstore.def_key(id) + } + } + fn lower_opt_sp_ident(&mut self, o_id: Option>) -> Option> { o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name)) } @@ -279,7 +314,12 @@ impl<'a> LoweringContext<'a> { TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), TyKind::Rptr(ref region, ref mt) => { - hir::TyRptr(self.lower_opt_lifetime(region), self.lower_mt(mt)) + let span = Span { hi: t.span.lo, ..t.span }; + let lifetime = match *region { + Some(ref lt) => self.lower_lifetime(lt), + None => self.elided_lifetime(span) + }; + hir::TyRptr(lifetime, self.lower_mt(mt)) } TyKind::BareFn(ref f) => { hir::TyBareFn(P(hir::BareFnTy { @@ -297,7 +337,8 @@ impl<'a> LoweringContext<'a> { return self.lower_ty(ty); } TyKind::Path(ref qself, ref path) => { - hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit)) + let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit); + return self.ty_path(t.id, t.span, qpath); } TyKind::ImplicitSelf => { hir::TyPath(hir::QPath::Resolved(None, P(hir::Path { @@ -319,7 +360,23 @@ impl<'a> LoweringContext<'a> { hir::TyTypeof(self.record_body(expr, None)) } TyKind::TraitObject(ref bounds) => { - hir::TyTraitObject(self.lower_bounds(bounds)) + let mut lifetime_bound = None; + let bounds = bounds.iter().filter_map(|bound| { + match *bound { + TraitTyParamBound(ref ty, TraitBoundModifier::None) => { + Some(self.lower_poly_trait_ref(ty)) + } + TraitTyParamBound(_, TraitBoundModifier::Maybe) => None, + RegionTyParamBound(ref lifetime) => { + lifetime_bound = Some(self.lower_lifetime(lifetime)); + None + } + } + }).collect(); + let lifetime_bound = lifetime_bound.unwrap_or_else(|| { + self.elided_lifetime(t.span) + }); + hir::TyTraitObject(bounds, lifetime_bound) } TyKind::ImplTrait(ref bounds) => { hir::TyImplTrait(self.lower_bounds(bounds)) @@ -377,7 +434,40 @@ impl<'a> LoweringContext<'a> { } _ => param_mode }; - self.lower_path_segment(segment, param_mode) + + // Figure out if this is a type/trait segment, + // which may need lifetime elision performed. + let parent_def_id = |this: &mut Self, def_id: DefId| { + DefId { + krate: def_id.krate, + index: this.def_key(def_id).parent.expect("missing parent") + } + }; + let type_def_id = match resolution.base_def { + Def::AssociatedTy(def_id) if i + 2 == proj_start => { + Some(parent_def_id(self, def_id)) + } + Def::Variant(def_id) if i + 1 == proj_start => { + Some(parent_def_id(self, def_id)) + } + Def::Struct(def_id) | + Def::Union(def_id) | + Def::Enum(def_id) | + Def::TyAlias(def_id) | + Def::Trait(def_id) if i + 1 == proj_start => Some(def_id), + _ => None + }; + + let num_lifetimes = type_def_id.map_or(0, |def_id| { + if let Some(&n) = self.type_def_lifetime_params.get(&def_id) { + return n; + } + assert!(!def_id.is_local()); + let (n, _) = self.sess.cstore.item_generics_own_param_counts(def_id); + self.type_def_lifetime_params.insert(def_id, n); + n + }); + self.lower_path_segment(p.span, segment, param_mode, num_lifetimes) }).collect(), span: p.span, }); @@ -397,7 +487,8 @@ impl<'a> LoweringContext<'a> { // Otherwise, the base path is an implicit `Self` type path, // e.g. `Vec` in `Vec::new` or `::Item` in // `::Item::default`. - self.ty(p.span, hir::TyPath(hir::QPath::Resolved(qself, path))) + let new_id = self.next_id(); + self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path)) }; // Anything after the base path are associated "extensions", @@ -411,7 +502,7 @@ impl<'a> LoweringContext<'a> { // 3. `<>::IntoIter>::Item` // * final path is `<<>::IntoIter>::Item>::clone` for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { - let segment = P(self.lower_path_segment(segment, param_mode)); + let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0)); let qpath = hir::QPath::TypeRelative(ty, segment); // It's finished, return the extension of the right node type. @@ -420,7 +511,8 @@ impl<'a> LoweringContext<'a> { } // Wrap the associated extension in another type node. - ty = self.ty(p.span, hir::TyPath(qpath)); + let new_id = self.next_id(); + ty = self.ty_path(new_id, p.span, qpath); } // Should've returned in the for loop above. @@ -443,7 +535,7 @@ impl<'a> LoweringContext<'a> { hir::Path { def: self.expect_full_def(id), segments: segments.map(|segment| { - self.lower_path_segment(segment, param_mode) + self.lower_path_segment(p.span, segment, param_mode, 0) }).chain(name.map(|name| { hir::PathSegment { name: name, @@ -464,10 +556,12 @@ impl<'a> LoweringContext<'a> { } fn lower_path_segment(&mut self, + path_span: Span, segment: &PathSegment, - param_mode: ParamMode) + param_mode: ParamMode, + expected_lifetimes: usize) -> hir::PathSegment { - let parameters = if let Some(ref parameters) = segment.parameters { + let mut parameters = if let Some(ref parameters) = segment.parameters { match **parameters { PathParameters::AngleBracketed(ref data) => { let data = self.lower_angle_bracketed_parameter_data(data, param_mode); @@ -482,6 +576,14 @@ impl<'a> LoweringContext<'a> { hir::AngleBracketedParameters(data) }; + if let hir::AngleBracketedParameters(ref mut data) = parameters { + if data.lifetimes.is_empty() { + data.lifetimes = (0..expected_lifetimes).map(|_| { + self.elided_lifetime(path_span) + }).collect(); + } + } + hir::PathSegment { name: segment.identifier.name, parameters: parameters, @@ -628,10 +730,6 @@ impl<'a> LoweringContext<'a> { lts.iter().map(|l| self.lower_lifetime_def(l)).collect() } - fn lower_opt_lifetime(&mut self, o_lt: &Option) -> Option { - o_lt.as_ref().map(|lt| self.lower_lifetime(lt)) - } - fn lower_generics(&mut self, g: &Generics) -> hir::Generics { // Collect `?Trait` bounds in where clause and move them to parameter definitions. let mut add_bounds = NodeMap(); @@ -751,8 +849,12 @@ impl<'a> LoweringContext<'a> { } fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef { + let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit) { + hir::QPath::Resolved(None, path) => path.and_then(|path| path), + qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath) + }; hir::TraitRef { - path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit, false), + path: path, ref_id: p.ref_id, } } @@ -2269,11 +2371,40 @@ impl<'a> LoweringContext<'a> { self.expr_block(block, attrs) } - fn ty(&mut self, span: Span, node: hir::Ty_) -> P { - P(hir::Ty { + fn ty_path(&mut self, id: NodeId, span: Span, qpath: hir::QPath) -> P { + let mut id = id; + let node = match qpath { + hir::QPath::Resolved(None, path) => { + // Turn trait object paths into `TyTraitObject` instead. + if let Def::Trait(_) = path.def { + let principal = hir::PolyTraitRef { + bound_lifetimes: hir_vec![], + trait_ref: hir::TraitRef { + path: path.and_then(|path| path), + ref_id: id, + }, + span, + }; + + // The original ID is taken by the `PolyTraitRef`, + // so the `Ty` itself needs a different one. + id = self.next_id(); + + hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span)) + } else { + hir::TyPath(hir::QPath::Resolved(None, path)) + } + } + _ => hir::TyPath(qpath) + }; + P(hir::Ty { id, node, span }) + } + + fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime { + hir::Lifetime { id: self.next_id(), - node: node, span: span, - }) + name: keywords::Invalid.name() + } } } diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 91e88e2c73ff8..ff2f1dc1ba28a 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -38,7 +38,7 @@ use syntax_pos::Span; /// - The default implementation for a trait method. /// /// To construct one, use the `Code::from_node` function. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct FnLikeNode<'a> { node: map::Node<'a> } /// MaybeFnLike wraps a method that indicates if an object diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index fe086347884b0..4ebe416e1bfe6 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -77,6 +77,13 @@ pub mod svh; pub struct Lifetime { pub id: NodeId, pub span: Span, + + /// Either "'a", referring to a named lifetime definition, + /// or "" (aka keywords::Invalid), for elision placeholders. + /// + /// HIR lowering inserts these placeholders in type paths that + /// refer to type definitions needing lifetime parameters, + /// `&T` and `&mut T`, and trait objects without `... + 'a`. pub name: Name, } @@ -89,6 +96,12 @@ impl fmt::Debug for Lifetime { } } +impl Lifetime { + pub fn is_elided(&self) -> bool { + self.name == keywords::Invalid.name() + } +} + /// A lifetime definition, eg `'a: 'b+'c+'d` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct LifetimeDef { @@ -165,30 +178,6 @@ impl PathParameters { }) } - pub fn is_empty(&self) -> bool { - match *self { - AngleBracketedParameters(ref data) => data.is_empty(), - - // Even if the user supplied no types, something like - // `X()` is equivalent to `X<(),()>`. - ParenthesizedParameters(..) => false, - } - } - - pub fn has_lifetimes(&self) -> bool { - match *self { - AngleBracketedParameters(ref data) => !data.lifetimes.is_empty(), - ParenthesizedParameters(_) => false, - } - } - - pub fn has_types(&self) -> bool { - match *self { - AngleBracketedParameters(ref data) => !data.types.is_empty(), - ParenthesizedParameters(..) => true, - } - } - /// Returns the types that the user wrote. Note that these do not necessarily map to the type /// parameters in the parenthesized case. pub fn types(&self) -> HirVec<&P> { @@ -245,12 +234,6 @@ pub struct AngleBracketedParameterData { pub bindings: HirVec, } -impl AngleBracketedParameterData { - fn is_empty(&self) -> bool { - self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty() - } -} - /// A path like `Foo(A,B) -> C` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct ParenthesizedParameterData { @@ -1208,7 +1191,7 @@ pub enum Ty_ { /// A raw pointer (`*const T` or `*mut T`) TyPtr(MutTy), /// A reference (`&'a T` or `&'a mut T`) - TyRptr(Option, MutTy), + TyRptr(Lifetime, MutTy), /// A bare function (e.g. `fn(usize) -> bool`) TyBareFn(P), /// The never type (`!`) @@ -1222,7 +1205,7 @@ pub enum Ty_ { TyPath(QPath), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. - TyTraitObject(TyParamBounds), + TyTraitObject(HirVec, Lifetime), /// An `impl Bound1 + Bound2 + Bound3` type /// where `Bound` is a trait or a lifetime. TyImplTrait(TyParamBounds), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index d4bb2d37091b2..e058c48c59149 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -26,6 +26,7 @@ use syntax_pos::{self, BytePos}; use hir; use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier, RangeEnd}; +use std::cell::Cell; use std::io::{self, Write, Read}; pub enum AnnNode<'a> { @@ -359,9 +360,9 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_opt_lifetime(&mut self, lifetime: &Option) -> io::Result<()> { - if let Some(l) = *lifetime { - self.print_lifetime(&l)?; + pub fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> { + if !lifetime.is_elided() { + self.print_lifetime(lifetime)?; self.nbsp()?; } Ok(()) @@ -415,8 +416,21 @@ impl<'a> State<'a> { hir::TyPath(ref qpath) => { self.print_qpath(qpath, false)? } - hir::TyTraitObject(ref bounds) => { - self.print_bounds("", &bounds[..])?; + hir::TyTraitObject(ref bounds, ref lifetime) => { + let mut first = true; + for bound in bounds { + self.nbsp()?; + if first { + first = false; + } else { + self.word_space("+")?; + } + self.print_poly_trait_ref(bound)?; + } + if !lifetime.is_elided() { + self.word_space("+")?; + self.print_lifetime(lifetime)?; + } } hir::TyImplTrait(ref bounds) => { self.print_bounds("impl ", &bounds[..])?; @@ -1553,65 +1567,49 @@ impl<'a> State<'a> { parameters: &hir::PathParameters, colons_before_params: bool) -> io::Result<()> { - if parameters.is_empty() { - let infer_types = match *parameters { - hir::AngleBracketedParameters(ref data) => data.infer_types, - hir::ParenthesizedParameters(_) => false - }; - - // FIXME(eddyb) See the comment below about infer_types. - if !(infer_types && false) { - return Ok(()); - } - } - - if colons_before_params { - word(&mut self.s, "::")? - } - match *parameters { hir::AngleBracketedParameters(ref data) => { - word(&mut self.s, "<")?; + let start = if colons_before_params { "::<" } else { "<" }; + let empty = Cell::new(true); + let start_or_comma = |this: &mut Self| { + if empty.get() { + empty.set(false); + word(&mut this.s, start) + } else { + this.word_space(",") + } + }; - let mut comma = false; - for lifetime in &data.lifetimes { - if comma { - self.word_space(",")? + if !data.lifetimes.iter().all(|lt| lt.is_elided()) { + for lifetime in &data.lifetimes { + start_or_comma(self)?; + self.print_lifetime(lifetime)?; } - self.print_lifetime(lifetime)?; - comma = true; } if !data.types.is_empty() { - if comma { - self.word_space(",")? - } + start_or_comma(self)?; self.commasep(Inconsistent, &data.types, |s, ty| s.print_type(&ty))?; - comma = true; } // FIXME(eddyb) This would leak into error messages, e.g.: // "non-exhaustive patterns: `Some::<..>(_)` not covered". if data.infer_types && false { - if comma { - self.word_space(",")? - } + start_or_comma(self)?; word(&mut self.s, "..")?; - comma = true; } for binding in data.bindings.iter() { - if comma { - self.word_space(",")? - } + start_or_comma(self)?; self.print_name(binding.name)?; space(&mut self.s)?; self.word_space("=")?; self.print_type(&binding.ty)?; - comma = true; } - word(&mut self.s, ">")? + if !empty.get() { + word(&mut self.s, ">")? + } } hir::ParenthesizedParameters(ref data) => { diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 23106d2bdc7d3..2489a6a6c7a63 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -55,8 +55,6 @@ //! ported to this system, and which relies on string concatenation at the //! time of error detection. -use self::FreshOrKept::*; - use super::InferCtxt; use super::TypeTrace; use super::SubregionOrigin; @@ -71,13 +69,10 @@ use super::region_inference::ProcessedErrors; use super::region_inference::ProcessedErrorOrigin; use super::region_inference::SameRegions; -use std::collections::HashSet; - use hir::map as hir_map; use hir; use lint; -use hir::def::Def; use hir::def_id::DefId; use infer; use middle::region; @@ -86,13 +81,9 @@ use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, ReFree}; use ty::error::TypeError; -use std::cell::{Cell, RefCell}; -use std::char::from_u32; use std::fmt; use syntax::ast; -use syntax::ptr::P; -use syntax::symbol::Symbol; -use syntax_pos::{self, Pos, Span}; +use syntax_pos::{Pos, Span}; use errors::DiagnosticBuilder; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -292,7 +283,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ProcessedErrors(ref origins, ref same_regions) => { if !same_regions.is_empty() { - self.report_processed_errors(origins, same_regions); + self.report_processed_errors(origins); } } } @@ -1050,9 +1041,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn report_processed_errors(&self, - origins: &[ProcessedErrorOrigin<'tcx>], - same_regions: &[SameRegions]) { - for (i, origin) in origins.iter().enumerate() { + origins: &[ProcessedErrorOrigin<'tcx>]) { + for origin in origins.iter() { let mut err = match *origin { ProcessedErrorOrigin::VariableFailure(ref var_origin) => self.report_inference_failure(var_origin.clone()), @@ -1060,78 +1050,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.report_concrete_failure(sr_origin.clone(), sub, sup), }; - // attach the suggestion to the last such error - if i == origins.len() - 1 { - self.give_suggestion(&mut err, same_regions); - } - err.emit(); } } - fn give_suggestion(&self, err: &mut DiagnosticBuilder, same_regions: &[SameRegions]) { - let scope_id = same_regions[0].scope_id; - let parent = self.tcx.hir.get_parent(scope_id); - let parent_node = self.tcx.hir.find(parent); - let taken = lifetimes_in_scope(self.tcx, scope_id); - let life_giver = LifeGiver::with_taken(&taken[..]); - let node_inner = match parent_node { - Some(ref node) => match *node { - hir_map::NodeItem(ref item) => { - match item.node { - hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, body) => { - Some((fn_decl, gen, unsafety, constness, item.name, item.span, body)) - } - _ => None, - } - } - hir_map::NodeImplItem(item) => { - let id = self.tcx.hir.get_parent(item.id); - if let Some(hir_map::NodeItem(parent_scope)) = self.tcx.hir.find(id) { - if let hir::ItemImpl(_, _, _, None, _, _) = parent_scope.node { - // this impl scope implements a trait, do not recomend - // using explicit lifetimes (#37363) - return; - } - } - if let hir::ImplItemKind::Method(ref sig, body) = item.node { - Some((&sig.decl, - &sig.generics, - sig.unsafety, - sig.constness, - item.name, - item.span, - body)) - } else { - None - } - }, - hir_map::NodeTraitItem(item) => { - match item.node { - hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => { - Some((&sig.decl, - &sig.generics, - sig.unsafety, - sig.constness, - item.name, - item.span, - body)) - } - _ => None, - } - } - _ => None, - }, - None => None, - }; - let (fn_decl, generics, unsafety, constness, name, span, body) - = node_inner.expect("expect item fn"); - let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver); - let (fn_decl, generics) = rebuilder.rebuild(); - self.give_expl_lifetime_param( - err, &fn_decl, unsafety, constness, name, &generics, span, body); - } - pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) { for issue32330 in issue32330s { match *issue32330 { @@ -1154,530 +1076,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -struct RebuildPathInfo<'a> { - path: &'a hir::Path, - // indexes to insert lifetime on path.lifetimes - indexes: Vec, - // number of lifetimes we expect to see on the type referred by `path` - // (e.g., expected=1 for struct Foo<'a>) - expected: u32, - anon_nums: &'a HashSet, - region_names: &'a HashSet -} - -struct Rebuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - fn_decl: &'a hir::FnDecl, - generics: &'a hir::Generics, - same_regions: &'a [SameRegions], - life_giver: &'a LifeGiver, - cur_anon: Cell, - inserted_anons: RefCell>, -} - -enum FreshOrKept { - Fresh, - Kept -} - -impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { - fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - fn_decl: &'a hir::FnDecl, - generics: &'a hir::Generics, - same_regions: &'a [SameRegions], - life_giver: &'a LifeGiver) - -> Rebuilder<'a, 'gcx, 'tcx> { - Rebuilder { - tcx: tcx, - fn_decl: fn_decl, - generics: generics, - same_regions: same_regions, - life_giver: life_giver, - cur_anon: Cell::new(0), - inserted_anons: RefCell::new(HashSet::new()), - } - } - - fn rebuild(&self) -> (hir::FnDecl, hir::Generics) { - let mut inputs = self.fn_decl.inputs.clone(); - let mut output = self.fn_decl.output.clone(); - let mut ty_params = self.generics.ty_params.clone(); - let where_clause = self.generics.where_clause.clone(); - let mut kept_lifetimes = HashSet::new(); - for sr in self.same_regions { - self.cur_anon.set(0); - self.offset_cur_anon(); - let (anon_nums, region_names) = - self.extract_anon_nums_and_names(sr); - let (lifetime, fresh_or_kept) = self.pick_lifetime(®ion_names); - match fresh_or_kept { - Kept => { kept_lifetimes.insert(lifetime.name); } - _ => () - } - inputs = self.rebuild_args_ty(&inputs[..], lifetime, - &anon_nums, ®ion_names); - output = self.rebuild_output(&output, lifetime, &anon_nums, ®ion_names); - ty_params = self.rebuild_ty_params(ty_params, lifetime, - ®ion_names); - } - let fresh_lifetimes = self.life_giver.get_generated_lifetimes(); - let all_region_names = self.extract_all_region_names(); - let generics = self.rebuild_generics(self.generics, - &fresh_lifetimes, - &kept_lifetimes, - &all_region_names, - ty_params, - where_clause); - let new_fn_decl = hir::FnDecl { - inputs: inputs, - output: output, - variadic: self.fn_decl.variadic - }; - (new_fn_decl, generics) - } - - fn pick_lifetime(&self, - region_names: &HashSet) - -> (hir::Lifetime, FreshOrKept) { - if !region_names.is_empty() { - // It's not necessary to convert the set of region names to a - // vector of string and then sort them. However, it makes the - // choice of lifetime name deterministic and thus easier to test. - let mut names = Vec::new(); - for rn in region_names { - let lt_name = rn.to_string(); - names.push(lt_name); - } - names.sort(); - let name = Symbol::intern(&names[0]); - return (name_to_dummy_lifetime(name), Kept); - } - return (self.life_giver.give_lifetime(), Fresh); - } - - fn extract_anon_nums_and_names(&self, same_regions: &SameRegions) - -> (HashSet, HashSet) { - let mut anon_nums = HashSet::new(); - let mut region_names = HashSet::new(); - for br in &same_regions.regions { - match *br { - ty::BrAnon(i) => { - anon_nums.insert(i); - } - ty::BrNamed(_, name, _) => { - region_names.insert(name); - } - _ => () - } - } - (anon_nums, region_names) - } - - fn extract_all_region_names(&self) -> HashSet { - let mut all_region_names = HashSet::new(); - for sr in self.same_regions { - for br in &sr.regions { - match *br { - ty::BrNamed(_, name, _) => { - all_region_names.insert(name); - } - _ => () - } - } - } - all_region_names - } - - fn inc_cur_anon(&self, n: u32) { - let anon = self.cur_anon.get(); - self.cur_anon.set(anon+n); - } - - fn offset_cur_anon(&self) { - let mut anon = self.cur_anon.get(); - while self.inserted_anons.borrow().contains(&anon) { - anon += 1; - } - self.cur_anon.set(anon); - } - - fn inc_and_offset_cur_anon(&self, n: u32) { - self.inc_cur_anon(n); - self.offset_cur_anon(); - } - - fn track_anon(&self, anon: u32) { - self.inserted_anons.borrow_mut().insert(anon); - } - - fn rebuild_ty_params(&self, - ty_params: hir::HirVec, - lifetime: hir::Lifetime, - region_names: &HashSet) - -> hir::HirVec { - ty_params.into_iter().map(|ty_param| { - let bounds = self.rebuild_ty_param_bounds(ty_param.bounds, - lifetime, - region_names); - hir::TyParam { - name: ty_param.name, - id: ty_param.id, - bounds: bounds, - default: ty_param.default, - span: ty_param.span, - pure_wrt_drop: ty_param.pure_wrt_drop, - } - }).collect() - } - - fn rebuild_ty_param_bounds(&self, - ty_param_bounds: hir::TyParamBounds, - lifetime: hir::Lifetime, - region_names: &HashSet) - -> hir::TyParamBounds { - ty_param_bounds.iter().map(|tpb| { - match tpb { - &hir::RegionTyParamBound(lt) => { - // FIXME -- it's unclear whether I'm supposed to - // substitute lifetime here. I suspect we need to - // be passing down a map. - hir::RegionTyParamBound(lt) - } - &hir::TraitTyParamBound(ref poly_tr, modifier) => { - let tr = &poly_tr.trait_ref; - let last_seg = tr.path.segments.last().unwrap(); - let mut insert = Vec::new(); - let lifetimes = last_seg.parameters.lifetimes(); - for (i, lt) in lifetimes.iter().enumerate() { - if region_names.contains(<.name) { - insert.push(i as u32); - } - } - let rebuild_info = RebuildPathInfo { - path: &tr.path, - indexes: insert, - expected: lifetimes.len() as u32, - anon_nums: &HashSet::new(), - region_names: region_names - }; - let new_path = self.rebuild_path(rebuild_info, lifetime); - hir::TraitTyParamBound(hir::PolyTraitRef { - bound_lifetimes: poly_tr.bound_lifetimes.clone(), - trait_ref: hir::TraitRef { - path: new_path, - ref_id: tr.ref_id, - }, - span: poly_tr.span, - }, modifier) - } - } - }).collect() - } - - fn rebuild_generics(&self, - generics: &hir::Generics, - add: &Vec, - keep: &HashSet, - remove: &HashSet, - ty_params: hir::HirVec, - where_clause: hir::WhereClause) - -> hir::Generics { - let mut lifetimes = Vec::new(); - for lt in add { - lifetimes.push(hir::LifetimeDef { - lifetime: *lt, - bounds: hir::HirVec::new(), - pure_wrt_drop: false, - }); - } - for lt in &generics.lifetimes { - if keep.contains(<.lifetime.name) || - !remove.contains(<.lifetime.name) { - lifetimes.push((*lt).clone()); - } - } - hir::Generics { - lifetimes: lifetimes.into(), - ty_params: ty_params, - where_clause: where_clause, - span: generics.span, - } - } - - fn rebuild_args_ty(&self, - inputs: &[P], - lifetime: hir::Lifetime, - anon_nums: &HashSet, - region_names: &HashSet) - -> hir::HirVec> { - inputs.iter().map(|arg_ty| { - self.rebuild_arg_ty_or_output(arg_ty, lifetime, anon_nums, region_names) - }).collect() - } - - fn rebuild_output(&self, ty: &hir::FunctionRetTy, - lifetime: hir::Lifetime, - anon_nums: &HashSet, - region_names: &HashSet) -> hir::FunctionRetTy { - match *ty { - hir::Return(ref ret_ty) => hir::Return( - self.rebuild_arg_ty_or_output(&ret_ty, lifetime, anon_nums, region_names) - ), - hir::DefaultReturn(span) => hir::DefaultReturn(span), - } - } - - fn rebuild_arg_ty_or_output(&self, - ty: &hir::Ty, - lifetime: hir::Lifetime, - anon_nums: &HashSet, - region_names: &HashSet) - -> P { - let mut new_ty = P(ty.clone()); - let mut ty_queue = vec![ty]; - while !ty_queue.is_empty() { - let cur_ty = ty_queue.remove(0); - match cur_ty.node { - hir::TyRptr(lt_opt, ref mut_ty) => { - let rebuild = match lt_opt { - Some(lt) => region_names.contains(<.name), - None => { - let anon = self.cur_anon.get(); - let rebuild = anon_nums.contains(&anon); - if rebuild { - self.track_anon(anon); - } - self.inc_and_offset_cur_anon(1); - rebuild - } - }; - if rebuild { - let to = hir::Ty { - id: cur_ty.id, - node: hir::TyRptr(Some(lifetime), mut_ty.clone()), - span: cur_ty.span - }; - new_ty = self.rebuild_ty(new_ty, P(to)); - } - ty_queue.push(&mut_ty.ty); - } - hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => { - match path.def { - Def::Enum(did) | Def::TyAlias(did) | - Def::Struct(did) | Def::Union(did) => { - let generics = self.tcx.item_generics(did); - - let expected = - generics.regions.len() as u32; - let lifetimes = - path.segments.last().unwrap().parameters.lifetimes(); - let mut insert = Vec::new(); - if lifetimes.is_empty() { - let anon = self.cur_anon.get(); - for (i, a) in (anon..anon+expected).enumerate() { - if anon_nums.contains(&a) { - insert.push(i as u32); - } - self.track_anon(a); - } - self.inc_and_offset_cur_anon(expected); - } else { - for (i, lt) in lifetimes.iter().enumerate() { - if region_names.contains(<.name) { - insert.push(i as u32); - } - } - } - let rebuild_info = RebuildPathInfo { - path: path, - indexes: insert, - expected: expected, - anon_nums: anon_nums, - region_names: region_names - }; - let new_path = self.rebuild_path(rebuild_info, lifetime); - let qself = maybe_qself.as_ref().map(|qself| { - self.rebuild_arg_ty_or_output(qself, lifetime, - anon_nums, region_names) - }); - let to = hir::Ty { - id: cur_ty.id, - node: hir::TyPath(hir::QPath::Resolved(qself, P(new_path))), - span: cur_ty.span - }; - new_ty = self.rebuild_ty(new_ty, P(to)); - } - _ => () - } - } - - hir::TyPtr(ref mut_ty) => { - ty_queue.push(&mut_ty.ty); - } - hir::TySlice(ref ty) | - hir::TyArray(ref ty, _) => { - ty_queue.push(&ty); - } - hir::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)), - _ => {} - } - } - new_ty - } - - fn rebuild_ty(&self, - from: P, - to: P) - -> P { - - fn build_to(from: P, - to: &mut Option>) - -> P { - if Some(from.id) == to.as_ref().map(|ty| ty.id) { - return to.take().expect("`to` type found more than once during rebuild"); - } - from.map(|hir::Ty {id, node, span}| { - let new_node = match node { - hir::TyRptr(lifetime, mut_ty) => { - hir::TyRptr(lifetime, hir::MutTy { - mutbl: mut_ty.mutbl, - ty: build_to(mut_ty.ty, to), - }) - } - hir::TyPtr(mut_ty) => { - hir::TyPtr(hir::MutTy { - mutbl: mut_ty.mutbl, - ty: build_to(mut_ty.ty, to), - }) - } - hir::TySlice(ty) => hir::TySlice(build_to(ty, to)), - hir::TyArray(ty, e) => { - hir::TyArray(build_to(ty, to), e) - } - hir::TyTup(tys) => { - hir::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect()) - } - other => other - }; - hir::Ty { id: id, node: new_node, span: span } - }) - } - - build_to(from, &mut Some(to)) - } - - fn rebuild_path(&self, - rebuild_info: RebuildPathInfo, - lifetime: hir::Lifetime) - -> hir::Path - { - let RebuildPathInfo { - path, - indexes, - expected, - anon_nums, - region_names, - } = rebuild_info; - - let last_seg = path.segments.last().unwrap(); - let new_parameters = match last_seg.parameters { - hir::ParenthesizedParameters(..) => { - last_seg.parameters.clone() - } - - hir::AngleBracketedParameters(ref data) => { - let mut new_lts = Vec::new(); - if data.lifetimes.is_empty() { - // traverse once to see if there's a need to insert lifetime - let need_insert = (0..expected).any(|i| { - indexes.contains(&i) - }); - if need_insert { - for i in 0..expected { - if indexes.contains(&i) { - new_lts.push(lifetime); - } else { - new_lts.push(self.life_giver.give_lifetime()); - } - } - } - } else { - for (i, lt) in data.lifetimes.iter().enumerate() { - if indexes.contains(&(i as u32)) { - new_lts.push(lifetime); - } else { - new_lts.push(*lt); - } - } - } - let new_types = data.types.iter().map(|t| { - self.rebuild_arg_ty_or_output(&t, lifetime, anon_nums, region_names) - }).collect(); - let new_bindings = data.bindings.iter().map(|b| { - hir::TypeBinding { - id: b.id, - name: b.name, - ty: self.rebuild_arg_ty_or_output(&b.ty, - lifetime, - anon_nums, - region_names), - span: b.span - } - }).collect(); - hir::AngleBracketedParameters(hir::AngleBracketedParameterData { - lifetimes: new_lts.into(), - types: new_types, - infer_types: data.infer_types, - bindings: new_bindings, - }) - } - }; - let new_seg = hir::PathSegment { - name: last_seg.name, - parameters: new_parameters - }; - let mut new_segs = Vec::new(); - new_segs.extend_from_slice(path.segments.split_last().unwrap().1); - new_segs.push(new_seg); - hir::Path { - span: path.span, - def: path.def, - segments: new_segs.into() - } - } -} - impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn give_expl_lifetime_param(&self, - err: &mut DiagnosticBuilder, - decl: &hir::FnDecl, - unsafety: hir::Unsafety, - constness: hir::Constness, - name: ast::Name, - generics: &hir::Generics, - span: Span, - body: hir::BodyId) { - let s = hir::print::to_string(&self.tcx.hir, |s| { - use syntax::abi::Abi; - use syntax::print::pprust::PrintState; - - s.head("")?; - s.print_fn(decl, - unsafety, - constness, - Abi::Rust, - Some(name), - generics, - &hir::Inherited, - &[], - Some(body))?; - s.end()?; // Close the head box - s.end() // Close the outer box - }); - let msg = format!("consider using an explicit lifetime parameter as shown: {}", s); - err.span_help(span, &msg[..]); - } - fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> DiagnosticBuilder<'tcx> { @@ -1890,114 +1289,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - scope_id: ast::NodeId) - -> Vec { - let mut taken = Vec::new(); - let parent = tcx.hir.get_parent(scope_id); - let method_id_opt = match tcx.hir.find(parent) { - Some(node) => match node { - hir_map::NodeItem(item) => match item.node { - hir::ItemFn(.., ref gen, _) => { - taken.extend_from_slice(&gen.lifetimes); - None - }, - _ => None - }, - hir_map::NodeImplItem(ii) => { - match ii.node { - hir::ImplItemKind::Method(ref sig, _) => { - taken.extend_from_slice(&sig.generics.lifetimes); - Some(ii.id) - } - _ => None, - } - } - _ => None - }, - None => None - }; - if let Some(method_id) = method_id_opt { - let parent = tcx.hir.get_parent(method_id); - if let Some(node) = tcx.hir.find(parent) { - match node { - hir_map::NodeItem(item) => match item.node { - hir::ItemImpl(_, _, ref gen, ..) => { - taken.extend_from_slice(&gen.lifetimes); - } - _ => () - }, - _ => () - } - } - } - return taken; -} - -// LifeGiver is responsible for generating fresh lifetime names -struct LifeGiver { - taken: HashSet, - counter: Cell, - generated: RefCell>, -} - -impl LifeGiver { - fn with_taken(taken: &[hir::LifetimeDef]) -> LifeGiver { - let mut taken_ = HashSet::new(); - for lt in taken { - let lt_name = lt.lifetime.name.to_string(); - taken_.insert(lt_name); - } - LifeGiver { - taken: taken_, - counter: Cell::new(0), - generated: RefCell::new(Vec::new()), - } - } - - fn inc_counter(&self) { - let c = self.counter.get(); - self.counter.set(c+1); - } - - fn give_lifetime(&self) -> hir::Lifetime { - let lifetime; - loop { - let mut s = String::from("'"); - s.push_str(&num_to_string(self.counter.get())); - if !self.taken.contains(&s) { - lifetime = name_to_dummy_lifetime(Symbol::intern(&s)); - self.generated.borrow_mut().push(lifetime); - break; - } - self.inc_counter(); - } - self.inc_counter(); - return lifetime; - - // 0 .. 25 generates a .. z, 26 .. 51 generates aa .. zz, and so on - fn num_to_string(counter: usize) -> String { - let mut s = String::new(); - let (n, r) = (counter/26 + 1, counter % 26); - let letter: char = from_u32((r+97) as u32).unwrap(); - for _ in 0..n { - s.push(letter); - } - s - } - } - - fn get_generated_lifetimes(&self) -> Vec { - self.generated.borrow().clone() - } -} - -fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime { - hir::Lifetime { id: ast::DUMMY_NODE_ID, - span: syntax_pos::DUMMY_SP, - name: name } -} - impl<'tcx> ObligationCause<'tcx> { fn as_failure_str(&self) -> &'static str { use traits::ObligationCauseCode::*; @@ -2038,4 +1329,3 @@ impl<'tcx> ObligationCause<'tcx> { } } } - diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 19183892e4b0c..697a1ecadc456 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -156,7 +156,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyUint(..) | ty::TyFloat(..) | ty::TyAdt(..) | - ty::TyBox(..) | ty::TyStr | ty::TyError | ty::TyArray(..) | diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 619a3e995c3a5..855f4a8197e35 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,7 +29,9 @@ #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] +#![feature(field_init_shorthand)] #![feature(libc)] +#![feature(loop_break_value)] #![feature(nonzero)] #![feature(pub_restricted)] #![feature(quote)] @@ -107,7 +109,6 @@ pub mod util { pub mod common; pub mod ppaux; pub mod nodemap; - pub mod num; pub mod fs; } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index b0db3b75029fb..e1605959922c0 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -223,6 +223,12 @@ declare_lint! { "detects names that resolve to ambiguous glob imports with RFC 1560" } +declare_lint! { + pub LEGACY_CONSTRUCTOR_VISIBILITY, + Deny, + "detects use of struct constructors that would be invisible with new visibility rules" +} + declare_lint! { pub DEPRECATED, Warn, @@ -271,6 +277,7 @@ impl LintPass for HardwiredLints { EXTRA_REQUIREMENT_IN_IMPL, LEGACY_DIRECTORY_OWNERSHIP, LEGACY_IMPORTS, + LEGACY_CONSTRUCTOR_VISIBILITY, DEPRECATED ) } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 496a3d4a49847..d11e6e3fc72bd 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -28,6 +28,7 @@ use hir::map as hir_map; use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData}; use hir::svh::Svh; use middle::lang_items; +use middle::resolve_lifetime::ObjectLifetimeDefault; use ty::{self, Ty, TyCtxt}; use mir::Mir; use session::Session; @@ -182,6 +183,9 @@ pub trait CrateStore<'tcx> { -> ty::GenericPredicates<'tcx>; fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::Generics<'tcx>; + fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize); + fn item_generics_object_lifetime_defaults(&self, def: DefId) + -> Vec; fn item_attrs(&self, def_id: DefId) -> Vec; fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef; fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef; @@ -331,6 +335,11 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") } fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::Generics<'tcx> { bug!("item_generics") } + fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) + { bug!("item_generics_own_param_counts") } + fn item_generics_object_lifetime_defaults(&self, def: DefId) + -> Vec + { bug!("item_generics_object_lifetime_defaults") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef { bug!("trait_def") } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 955bec0043312..0e8e1921de700 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -194,6 +194,63 @@ pub struct cmt_<'tcx> { pub type cmt<'tcx> = Rc>; +impl<'tcx> cmt_<'tcx> { + pub fn get_field(&self, name: ast::Name) -> Option { + match self.cat { + Categorization::Deref(ref cmt, ..) | + Categorization::Interior(ref cmt, _) | + Categorization::Downcast(ref cmt, _) => { + if let Categorization::Local(_) = cmt.cat { + if let ty::TyAdt(def, _) = self.ty.sty { + return def.struct_variant().find_field_named(name).map(|x| x.did); + } + None + } else { + cmt.get_field(name) + } + } + _ => None + } + } + + pub fn get_field_name(&self) -> Option { + match self.cat { + Categorization::Interior(_, ref ik) => { + if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik { + Some(name) + } else { + None + } + } + Categorization::Deref(ref cmt, ..) | + Categorization::Downcast(ref cmt, _) => { + cmt.get_field_name() + } + _ => None, + } + } + + pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option { + match self.cat { + Categorization::Deref(ref cmt, ..) | + Categorization::Interior(ref cmt, _) | + Categorization::Downcast(ref cmt, _) => { + if let Categorization::Local(nid) = cmt.cat { + if let ty::TyAdt(_, _) = self.ty.sty { + if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty { + return Some(nid); + } + } + None + } else { + cmt.get_arg_if_immutable(map) + } + } + _ => None + } + } +} + pub trait ast_node { fn id(&self) -> ast::NodeId; fn span(&self) -> Span; @@ -904,7 +961,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { -> cmt<'tcx> { let ptr = match base_cmt.ty.sty { - ty::TyBox(..) => Unique, + ty::TyAdt(def, ..) if def.is_box() => Unique, ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl), ty::TyRef(r, mt) => { let bk = ty::BorrowKind::from_mutbl(mt.mutbl); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index dd99aea909faa..88ef2c69a04dc 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -15,9 +15,6 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore we break lifetime name resolution into a separate pass. -pub use self::DefRegion::*; -use self::ScopeChain::*; - use dep_graph::DepNode; use hir::map::Map; use session::Session; @@ -25,45 +22,149 @@ use hir::def::Def; use hir::def_id::DefId; use middle::region; use ty; + +use std::cell::Cell; use std::mem::replace; use syntax::ast; +use syntax::attr; +use syntax::ptr::P; use syntax::symbol::keywords; use syntax_pos::Span; -use util::nodemap::NodeMap; +use errors::DiagnosticBuilder; +use util::nodemap::{NodeMap, FxHashSet, FxHashMap, DefIdMap}; +use rustc_back::slice; -use rustc_data_structures::fx::FxHashSet; use hir; -use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; +use hir::intravisit::{self, Visitor, NestedVisitorMap}; #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] -pub enum DefRegion { - DefStaticRegion, - DefEarlyBoundRegion(/* index */ u32, - /* lifetime decl */ ast::NodeId), - DefLateBoundRegion(ty::DebruijnIndex, - /* lifetime decl */ ast::NodeId), - DefFreeRegion(region::CallSiteScopeData, - /* lifetime decl */ ast::NodeId), +pub enum Region { + Static, + EarlyBound(/* index */ u32, /* lifetime decl */ ast::NodeId), + LateBound(ty::DebruijnIndex, /* lifetime decl */ ast::NodeId), + LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32), + Free(region::CallSiteScopeData, /* lifetime decl */ ast::NodeId), } +impl Region { + fn early(index: &mut u32, def: &hir::LifetimeDef) -> (ast::Name, Region) { + let i = *index; + *index += 1; + (def.lifetime.name, Region::EarlyBound(i, def.lifetime.id)) + } + + fn late(def: &hir::LifetimeDef) -> (ast::Name, Region) { + let depth = ty::DebruijnIndex::new(1); + (def.lifetime.name, Region::LateBound(depth, def.lifetime.id)) + } + + fn late_anon(index: &Cell) -> Region { + let i = index.get(); + index.set(i + 1); + let depth = ty::DebruijnIndex::new(1); + Region::LateBoundAnon(depth, i) + } + + fn id(&self) -> Option { + match *self { + Region::Static | + Region::LateBoundAnon(..) => None, + + Region::EarlyBound(_, id) | + Region::LateBound(_, id) | + Region::Free(_, id) => Some(id) + } + } + + fn shifted(self, amount: u32) -> Region { + match self { + Region::LateBound(depth, id) => { + Region::LateBound(depth.shifted(amount), id) + } + Region::LateBoundAnon(depth, index) => { + Region::LateBoundAnon(depth.shifted(amount), index) + } + _ => self + } + } + + fn from_depth(self, depth: u32) -> Region { + match self { + Region::LateBound(debruijn, id) => { + Region::LateBound(ty::DebruijnIndex { + depth: debruijn.depth - (depth - 1) + }, id) + } + Region::LateBoundAnon(debruijn, index) => { + Region::LateBoundAnon(ty::DebruijnIndex { + depth: debruijn.depth - (depth - 1) + }, index) + } + _ => self + } + } + + fn subst(self, params: &[hir::Lifetime], map: &NamedRegionMap) + -> Option { + if let Region::EarlyBound(index, _) = self { + params.get(index as usize).and_then(|lifetime| { + map.defs.get(&lifetime.id).cloned() + }) + } else { + Some(self) + } + } +} + +/// A set containing, at most, one known element. +/// If two distinct values are inserted into a set, then it +/// becomes `Many`, which can be used to detect ambiguities. +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] +pub enum Set1 { + Empty, + One(T), + Many +} + +impl Set1 { + pub fn insert(&mut self, value: T) { + if let Set1::Empty = *self { + *self = Set1::One(value); + return; + } + if let Set1::One(ref old) = *self { + if *old == value { + return; + } + } + *self = Set1::Many; + } +} + +pub type ObjectLifetimeDefault = Set1; + // Maps the id of each lifetime reference to the lifetime decl // that it corresponds to. pub struct NamedRegionMap { // maps from every use of a named (not anonymous) lifetime to a - // `DefRegion` describing how that region is bound - pub defs: NodeMap, + // `Region` describing how that region is bound + pub defs: NodeMap, // the set of lifetime def ids that are late-bound; late-bound ids // are named regions appearing in fn arguments that do not appear // in where-clauses pub late_bound: NodeMap, + + // For each type and trait definition, maps type parameters + // to the trait object lifetime defaults computed from them. + pub object_lifetime_defaults: NodeMap>, } struct LifetimeContext<'a, 'tcx: 'a> { sess: &'a Session, hir_map: &'a Map<'tcx>, map: &'a mut NamedRegionMap, - scope: Scope<'a>, + scope: ScopeRef<'a>, // Deep breath. Our representation for poly trait refs contains a single // binder and thus we only allow a single level of quantification. However, // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>` @@ -83,28 +184,75 @@ struct LifetimeContext<'a, 'tcx: 'a> { // List of labels in the function/method currently under analysis. labels_in_fn: Vec<(ast::Name, Span)>, + + // Cache for cross-crate per-definition object lifetime defaults. + xcrate_object_lifetime_defaults: DefIdMap>, +} + +#[derive(Debug)] +enum Scope<'a> { + /// Declares lifetimes, and each can be early-bound or late-bound. + /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and + /// it should be shifted by the number of `Binder`s in between the + /// declaration `Binder` and the location it's referenced from. + Binder { + lifetimes: FxHashMap, + s: ScopeRef<'a> + }, + + /// Lifetimes introduced by a fn are scoped to the call-site for that fn, + /// if this is a fn body, otherwise the original definitions are used. + /// Unspecified lifetimes are inferred, unless an elision scope is nested, + /// e.g. `(&T, fn(&T) -> &T);` becomes `(&'_ T, for<'a> fn(&'a T) -> &'a T)`. + Body { + id: hir::BodyId, + s: ScopeRef<'a> + }, + + /// A scope which either determines unspecified lifetimes or errors + /// on them (e.g. due to ambiguity). For more details, see `Elide`. + Elision { + elide: Elide, + s: ScopeRef<'a> + }, + + /// Use a specific lifetime (if `Some`) or leave it unset (to be + /// inferred in a function body or potentially error outside one), + /// for the default choice of lifetime in a trait object type. + ObjectLifetimeDefault { + lifetime: Option, + s: ScopeRef<'a> + }, + + Root +} + +#[derive(Clone, Debug)] +enum Elide { + /// Use a fresh anonymous late-bound lifetime each time, by + /// incrementing the counter to generate sequential indices. + FreshLateAnon(Cell), + /// Always use this one lifetime. + Exact(Region), + /// Like `Exact(Static)` but requires `#![feature(static_in_const)]`. + Static, + /// Less or more than one lifetime were found, error on unspecified. + Error(Vec) } -#[derive(PartialEq, Debug)] -enum ScopeChain<'a> { - /// EarlyScope(['a, 'b, ...], start, s) extends s with early-bound - /// lifetimes, with consecutive parameter indices from `start`. - /// That is, 'a has index `start`, 'b has index `start + 1`, etc. - /// Indices before `start` correspond to other generic parameters - /// of a parent item (trait/impl of a method), or `Self` in traits. - EarlyScope(&'a [hir::LifetimeDef], u32, Scope<'a>), - /// LateScope(['a, 'b, ...], s) extends s with late-bound - /// lifetimes introduced by the declaration binder_id. - LateScope(&'a [hir::LifetimeDef], Scope<'a>), - - /// lifetimes introduced by a fn are scoped to the call-site for that fn. - FnScope { fn_id: ast::NodeId, body_id: ast::NodeId, s: Scope<'a> }, - RootScope +#[derive(Clone, Debug)] +struct ElisionFailureInfo { + /// Where we can find the argument pattern. + parent: Option, + /// The index of the argument in the original definition. + index: usize, + lifetime_count: usize, + have_bound_regions: bool } -type Scope<'a> = &'a ScopeChain<'a>; +type ScopeRef<'a> = &'a Scope<'a>; -static ROOT_SCOPE: ScopeChain<'static> = RootScope; +const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; pub fn krate(sess: &Session, hir_map: &Map) @@ -114,118 +262,104 @@ pub fn krate(sess: &Session, let mut map = NamedRegionMap { defs: NodeMap(), late_bound: NodeMap(), + object_lifetime_defaults: compute_object_lifetime_defaults(sess, hir_map), }; sess.track_errors(|| { - intravisit::walk_crate(&mut LifetimeContext { + let mut visitor = LifetimeContext { sess: sess, hir_map: hir_map, map: &mut map, - scope: &ROOT_SCOPE, + scope: ROOT_SCOPE, trait_ref_hack: false, labels_in_fn: vec![], - }, krate); + xcrate_object_lifetime_defaults: DefIdMap(), + }; + for (_, item) in &krate.items { + visitor.visit_item(item); + } })?; Ok(map) } impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { - // Override the nested functions -- lifetimes follow lexical scope, - // so it's convenient to walk the tree in lexical order. fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::All(&self.hir_map) + NestedVisitorMap::All(self.hir_map) + } + + // We want to nest trait/impl items in their parent, but nothing else. + fn visit_nested_item(&mut self, _: hir::ItemId) {} + + fn visit_nested_body(&mut self, body: hir::BodyId) { + // Each body has their own set of labels, save labels. + let saved = replace(&mut self.labels_in_fn, vec![]); + let body = self.hir_map.body(body); + extract_labels(self, body); + self.with(Scope::Body { id: body.id(), s: self.scope }, |_, this| { + this.visit_body(body); + }); + replace(&mut self.labels_in_fn, saved); } fn visit_item(&mut self, item: &'tcx hir::Item) { - // Save labels for nested items. - let saved_labels_in_fn = replace(&mut self.labels_in_fn, vec![]); - - // Items always introduce a new root scope - self.with(RootScope, |_, this| { - match item.node { - hir::ItemFn(..) => { - // Fn lifetimes get added in visit_fn below: + match item.node { + hir::ItemFn(ref decl, _, _, _, ref generics, _) => { + self.visit_early_late(item.id, None, decl, generics, |this| { intravisit::walk_item(this, item); - } - hir::ItemExternCrate(_) | - hir::ItemUse(..) | - hir::ItemMod(..) | - hir::ItemDefaultImpl(..) | - hir::ItemForeignMod(..) | - hir::ItemStatic(..) | - hir::ItemConst(..) => { - // These sorts of items have no lifetime parameters at all. + }); + } + hir::ItemExternCrate(_) | + hir::ItemUse(..) | + hir::ItemMod(..) | + hir::ItemDefaultImpl(..) | + hir::ItemForeignMod(..) => { + // These sorts of items have no lifetime parameters at all. + intravisit::walk_item(self, item); + } + hir::ItemStatic(..) | + hir::ItemConst(..) => { + // No lifetime parameters, but implied 'static. + let scope = Scope::Elision { + elide: Elide::Static, + s: ROOT_SCOPE + }; + self.with(scope, |_, this| intravisit::walk_item(this, item)); + } + hir::ItemTy(_, ref generics) | + hir::ItemEnum(_, ref generics) | + hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) | + hir::ItemTrait(_, 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 + } else { + 0 + }; + let lifetimes = generics.lifetimes.iter().map(|def| { + Region::early(&mut index, def) + }).collect(); + let scope = Scope::Binder { + lifetimes: lifetimes, + s: ROOT_SCOPE + }; + self.with(scope, |old_scope, this| { + this.check_lifetime_defs(old_scope, &generics.lifetimes); intravisit::walk_item(this, item); - } - hir::ItemTy(_, ref generics) | - hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) | - hir::ItemUnion(_, ref generics) | - hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { - // These kinds of items have only early bound lifetime parameters. - let lifetimes = &generics.lifetimes; - let start = if let hir::ItemTrait(..) = item.node { - 1 // Self comes before lifetimes - } else { - 0 - }; - this.with(EarlyScope(lifetimes, start, &ROOT_SCOPE), |old_scope, this| { - this.check_lifetime_defs(old_scope, lifetimes); - intravisit::walk_item(this, item); - }); - } + }); } - }); - - // Done traversing the item; remove any labels it created - self.labels_in_fn = saved_labels_in_fn; + } } fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { - // Items save/restore the set of labels. This way inner items - // can freely reuse names, be they loop labels or lifetimes. - let saved = replace(&mut self.labels_in_fn, vec![]); - - // Items always introduce a new root scope - self.with(RootScope, |_, this| { - match item.node { - hir::ForeignItemFn(ref decl, _, ref generics) => { - this.visit_early_late(item.id, decl, generics, |this| { - intravisit::walk_foreign_item(this, item); - }) - } - hir::ForeignItemStatic(..) => { + match item.node { + hir::ForeignItemFn(ref decl, _, ref generics) => { + self.visit_early_late(item.id, None, decl, generics, |this| { intravisit::walk_foreign_item(this, item); - } - } - }); - - // Done traversing the item; restore saved set of labels. - replace(&mut self.labels_in_fn, saved); - } - - fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl, - b: hir::BodyId, s: Span, fn_id: ast::NodeId) { - match fk { - FnKind::ItemFn(_, generics, ..) => { - self.visit_early_late(fn_id,decl, generics, |this| { - this.add_scope_and_walk_fn(fk, decl, b, s, fn_id) }) } - FnKind::Method(_, sig, ..) => { - self.visit_early_late( - fn_id, - decl, - &sig.generics, - |this| this.add_scope_and_walk_fn(fk, decl, b, s, fn_id)); - } - FnKind::Closure(_) => { - // Closures have their own set of labels, save labels just - // like for foreign items above. - let saved = replace(&mut self.labels_in_fn, vec![]); - let result = self.add_scope_and_walk_fn(fk, decl, b, s, fn_id); - replace(&mut self.labels_in_fn, saved); - result + hir::ForeignItemStatic(..) => { + intravisit::walk_foreign_item(self, item); } } } @@ -233,27 +367,35 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty) { match ty.node { hir::TyBareFn(ref c) => { - self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| { + let scope = Scope::Binder { + lifetimes: c.lifetimes.iter().map(Region::late).collect(), + s: self.scope + }; + self.with(scope, |old_scope, this| { // a bare fn has no bounds, so everything // contained within is scoped within its binder. this.check_lifetime_defs(old_scope, &c.lifetimes); intravisit::walk_ty(this, ty); }); } - hir::TyPath(hir::QPath::Resolved(None, ref path)) => { - // if this path references a trait, then this will resolve to - // a trait ref, which introduces a binding scope. - match path.def { - Def::Trait(..) => { - self.with(LateScope(&[], self.scope), |_, this| { - this.visit_path(path, ty.id); - }); - } - _ => { - intravisit::walk_ty(self, ty); - } + hir::TyTraitObject(ref bounds, ref lifetime) => { + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + if lifetime.is_elided() { + self.resolve_object_lifetime_default(lifetime) + } else { + self.visit_lifetime(lifetime); } } + hir::TyRptr(ref lifetime_ref, ref mt) => { + self.visit_lifetime(lifetime_ref); + let scope = Scope::ObjectLifetimeDefault { + lifetime: self.map.defs.get(&lifetime_ref.id).cloned(), + s: self.scope + }; + self.with(scope, |_, this| this.visit_ty(&mt.ty)); + } _ => { intravisit::walk_ty(self, ty) } @@ -261,31 +403,56 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - // We reset the labels on every trait item, so that different - // methods in an impl can reuse label names. - let saved = replace(&mut self.labels_in_fn, vec![]); - - if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = - trait_item.node { + if let hir::TraitItemKind::Method(ref sig, _) = trait_item.node { self.visit_early_late( trait_item.id, + Some(self.hir_map.get_parent(trait_item.id)), &sig.decl, &sig.generics, |this| intravisit::walk_trait_item(this, trait_item)) } else { intravisit::walk_trait_item(self, trait_item); } + } - replace(&mut self.labels_in_fn, saved); + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { + self.visit_early_late( + impl_item.id, + Some(self.hir_map.get_parent(impl_item.id)), + &sig.decl, &sig.generics, + |this| intravisit::walk_impl_item(this, impl_item)) + } else { + intravisit::walk_impl_item(self, impl_item); + } } fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { + if lifetime_ref.is_elided() { + self.resolve_elided_lifetimes(slice::ref_slice(lifetime_ref)); + return; + } if lifetime_ref.name == keywords::StaticLifetime.name() { - self.insert_lifetime(lifetime_ref, DefStaticRegion); + self.insert_lifetime(lifetime_ref, Region::Static); return; } self.resolve_lifetime_ref(lifetime_ref); } + fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) { + for (i, segment) in path.segments.iter().enumerate() { + let depth = path.segments.len() - i - 1; + self.visit_segment_parameters(path.def, depth, &segment.parameters); + } + } + + fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl) { + let output = match fd.output { + hir::DefaultReturn(_) => None, + hir::Return(ref ty) => Some(ty) + }; + self.visit_fn_like_elision(&fd.inputs, output); + } + fn visit_generics(&mut self, generics: &'tcx hir::Generics) { for ty_param in generics.ty_params.iter() { walk_list!(self, visit_ty_param_bound, &ty_param.bounds); @@ -301,8 +468,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { .. }) => { if !bound_lifetimes.is_empty() { self.trait_ref_hack = true; - let result = self.with(LateScope(bound_lifetimes, self.scope), - |old_scope, this| { + let scope = Scope::Binder { + lifetimes: bound_lifetimes.iter().map(Region::late).collect(), + s: self.scope + }; + let result = self.with(scope, |old_scope, this| { this.check_lifetime_defs(old_scope, bound_lifetimes); this.visit_ty(&bounded_ty); walk_list!(this, visit_ty_param_bound, bounds); @@ -335,7 +505,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef, - _modifier: &'tcx hir::TraitBoundModifier) { + _modifier: hir::TraitBoundModifier) { debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref); if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() { @@ -343,12 +513,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { span_err!(self.sess, trait_ref.span, E0316, "nested quantification of lifetimes"); } - self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| { + let scope = Scope::Binder { + lifetimes: trait_ref.bound_lifetimes.iter().map(Region::late).collect(), + s: self.scope + }; + self.with(scope, |old_scope, this| { this.check_lifetime_defs(old_scope, &trait_ref.bound_lifetimes); for lifetime in &trait_ref.bound_lifetimes { this.visit_lifetime_def(lifetime); } - intravisit::walk_path(this, &trait_ref.trait_ref.path) + this.visit_trait_ref(&trait_ref.trait_ref) }) } else { self.visit_trait_ref(&trait_ref.trait_ref) @@ -367,8 +541,8 @@ fn original_label(span: Span) -> Original { fn shadower_label(span: Span) -> Shadower { Shadower { kind: ShadowKind::Label, span: span } } -fn original_lifetime(l: &hir::Lifetime) -> Original { - Original { kind: ShadowKind::Lifetime, span: l.span } +fn original_lifetime(span: Span) -> Original { + Original { kind: ShadowKind::Lifetime, span: span } } fn shadower_lifetime(l: &hir::Lifetime) -> Shadower { Shadower { kind: ShadowKind::Lifetime, span: l.span } @@ -406,33 +580,28 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning // if one of the label shadows a lifetime or another label. -fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { - struct GatherLabels<'a> { +fn extract_labels(ctxt: &mut LifetimeContext, body: &hir::Body) { + struct GatherLabels<'a, 'tcx: 'a> { sess: &'a Session, - scope: Scope<'a>, + hir_map: &'a Map<'tcx>, + scope: ScopeRef<'a>, labels_in_fn: &'a mut Vec<(ast::Name, Span)>, } let mut gather = GatherLabels { sess: ctxt.sess, + hir_map: ctxt.hir_map, scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn, }; - gather.visit_body(ctxt.hir_map.body(b)); - return; + gather.visit_body(body); - impl<'v, 'a> Visitor<'v> for GatherLabels<'a> { + impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { NestedVisitorMap::None } - fn visit_expr(&mut self, ex: &'v hir::Expr) { - // do not recurse into closures defined in the block - // since they are treated as separate fns from the POV of - // labels_in_fn - if let hir::ExprClosure(..) = ex.node { - return - } + fn visit_expr(&mut self, ex: &hir::Expr) { if let Some((label, label_span)) = expression_label(ex) { for &(prior, prior_span) in &self.labels_in_fn[..] { // FIXME (#24278): non-hygienic comparison @@ -445,6 +614,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { } check_if_label_shadows_lifetime(self.sess, + self.hir_map, self.scope, label, label_span); @@ -453,10 +623,6 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { } intravisit::walk_expr(self, ex) } - - fn visit_item(&mut self, _: &hir::Item) { - // do not recurse into items defined in the block - } } fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> { @@ -468,26 +634,27 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { } fn check_if_label_shadows_lifetime<'a>(sess: &'a Session, - mut scope: Scope<'a>, + hir_map: &Map, + mut scope: ScopeRef<'a>, label: ast::Name, label_span: Span) { loop { match *scope { - FnScope { s, .. } => { scope = s; } - RootScope => { return; } - - EarlyScope(lifetimes, _, s) | - LateScope(lifetimes, s) => { - for lifetime_def in lifetimes { - // FIXME (#24278): non-hygienic comparison - if label == lifetime_def.lifetime.name { - signal_shadowing_problem( - sess, - label, - original_lifetime(&lifetime_def.lifetime), - shadower_label(label_span)); - return; - } + Scope::Body { s, .. } | + Scope::Elision { s, .. } | + Scope::ObjectLifetimeDefault { s, .. } => { scope = s; } + + Scope::Root => { return; } + + Scope::Binder { ref lifetimes, s } => { + // FIXME (#24278): non-hygienic comparison + if let Some(def) = lifetimes.get(&label) { + signal_shadowing_problem( + sess, + label, + original_lifetime(hir_map.span(def.id().unwrap())), + shadower_label(label_span)); + return; } scope = s; } @@ -496,35 +663,104 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) { } } -impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { - fn add_scope_and_walk_fn(&mut self, - fk: FnKind<'tcx>, - fd: &'tcx hir::FnDecl, - fb: hir::BodyId, - _span: Span, - fn_id: ast::NodeId) { - match fk { - FnKind::ItemFn(_, generics, ..) => { - intravisit::walk_fn_decl(self, fd); - self.visit_generics(generics); - } - FnKind::Method(_, sig, ..) => { - intravisit::walk_fn_decl(self, fd); - self.visit_generics(&sig.generics); +fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map) + -> NodeMap> { + let mut map = NodeMap(); + for item in hir_map.krate().items.values() { + match item.node { + hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) | + hir::ItemEnum(_, ref generics) | + hir::ItemTy(_, ref generics) | + hir::ItemTrait(_, ref generics, ..) => { + let result = object_lifetime_defaults_for_item(hir_map, generics); + + // Debugging aid. + if attr::contains_name(&item.attrs, "rustc_object_lifetime_default") { + let object_lifetime_default_reprs: String = + result.iter().map(|set| { + match *set { + Set1::Empty => "BaseDefault".to_string(), + Set1::One(Region::Static) => "'static".to_string(), + Set1::One(Region::EarlyBound(i, _)) => { + generics.lifetimes[i as usize].lifetime.name.to_string() + } + Set1::One(_) => bug!(), + Set1::Many => "Ambiguous".to_string(), + } + }).collect::>().join(","); + sess.span_err(item.span, &object_lifetime_default_reprs); + } + + map.insert(item.id, result); } - FnKind::Closure(_) => { - intravisit::walk_fn_decl(self, fd); + _ => {} + } + } + map +} + +/// Scan the bounds and where-clauses on parameters to extract bounds +/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault` +/// for each type parameter. +fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics) + -> Vec { + fn add_bounds(set: &mut Set1, bounds: &[hir::TyParamBound]) { + for bound in bounds { + if let hir::RegionTyParamBound(ref lifetime) = *bound { + set.insert(lifetime.name); } } + } - // After inpsecting the decl, add all labels from the body to - // `self.labels_in_fn`. - extract_labels(self, fb); + generics.ty_params.iter().map(|param| { + let mut set = Set1::Empty; - self.with(FnScope { fn_id: fn_id, body_id: fb.node_id, s: self.scope }, - |_old_scope, this| this.visit_nested_body(fb)) - } + add_bounds(&mut set, ¶m.bounds); + + let param_def_id = hir_map.local_def_id(param.id); + for predicate in &generics.where_clause.predicates { + // Look for `type: ...` where clauses. + let data = match *predicate { + hir::WherePredicate::BoundPredicate(ref data) => data, + _ => continue + }; + + // Ignore `for<'a> type: ...` as they can change what + // lifetimes mean (although we could "just" handle it). + if !data.bound_lifetimes.is_empty() { + continue; + } + + let def = match data.bounded_ty.node { + hir::TyPath(hir::QPath::Resolved(None, ref path)) => path.def, + _ => continue + }; + if def == Def::TyParam(param_def_id) { + add_bounds(&mut set, &data.bounds); + } + } + + match set { + Set1::Empty => Set1::Empty, + Set1::One(name) => { + if name == keywords::StaticLifetime.name() { + Set1::One(Region::Static) + } else { + generics.lifetimes.iter().enumerate().find(|&(_, def)| { + def.lifetime.name == name + }).map_or(Set1::Many, |(i, def)| { + Set1::One(Region::EarlyBound(i as u32, def.lifetime.id)) + }) + } + } + Set1::Many => Set1::Many + } + }).collect() +} + +impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // FIXME(#37666) this works around a limitation in the region inferencer fn hack(&mut self, f: F) where F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), @@ -532,21 +768,27 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { f(self) } - fn with(&mut self, wrap_scope: ScopeChain, f: F) where - F: for<'b> FnOnce(Scope, &mut LifetimeContext<'b, 'tcx>), + fn with(&mut self, wrap_scope: Scope, f: F) where + F: for<'b> FnOnce(ScopeRef, &mut LifetimeContext<'b, 'tcx>), { let LifetimeContext {sess, hir_map, ref mut map, ..} = *self; + let labels_in_fn = replace(&mut self.labels_in_fn, vec![]); + let xcrate_object_lifetime_defaults = + replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap()); let mut this = LifetimeContext { sess: sess, hir_map: hir_map, map: *map, scope: &wrap_scope, trait_ref_hack: self.trait_ref_hack, - labels_in_fn: self.labels_in_fn.clone(), + labels_in_fn: labels_in_fn, + xcrate_object_lifetime_defaults: xcrate_object_lifetime_defaults, }; debug!("entering scope {:?}", this.scope); f(self.scope, &mut this); debug!("exiting scope {:?}", this.scope); + self.labels_in_fn = this.labels_in_fn; + self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; } /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. @@ -569,6 +811,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// ordering is not important there. fn visit_early_late(&mut self, fn_id: ast::NodeId, + parent_id: Option, decl: &'tcx hir::FnDecl, generics: &'tcx hir::Generics, walk: F) where @@ -580,156 +823,618 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { decl, generics); - let (late, early): (Vec<_>, _) = - generics.lifetimes - .iter() - .cloned() - .partition(|l| self.map.late_bound.contains_key(&l.lifetime.id)); - // Find the start of nested early scopes, e.g. in methods. - let mut start = 0; - if let EarlyScope(..) = *self.scope { - let parent = self.hir_map.expect_item(self.hir_map.get_parent(fn_id)); + let mut index = 0; + if let Some(parent_id) = parent_id { + let parent = self.hir_map.expect_item(parent_id); if let hir::ItemTrait(..) = parent.node { - start += 1; // Self comes first. + index += 1; // Self comes first. } match parent.node { hir::ItemTrait(_, ref generics, ..) | hir::ItemImpl(_, _, ref generics, ..) => { - start += generics.lifetimes.len() + generics.ty_params.len(); + index += (generics.lifetimes.len() + generics.ty_params.len()) as u32; } _ => {} } } - self.with(EarlyScope(&early, start as u32, self.scope), move |old_scope, this| { - this.with(LateScope(&late, this.scope), move |_, this| { - this.check_lifetime_defs(old_scope, &generics.lifetimes); - this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` - }); + let lifetimes = generics.lifetimes.iter().map(|def| { + if self.map.late_bound.contains_key(&def.lifetime.id) { + Region::late(def) + } else { + Region::early(&mut index, def) + } + }).collect(); + + let scope = Scope::Binder { + lifetimes: lifetimes, + s: self.scope + }; + self.with(scope, move |old_scope, this| { + this.check_lifetime_defs(old_scope, &generics.lifetimes); + this.hack(walk); // FIXME(#37666) workaround in place of `walk(this)` }); } fn resolve_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) { // Walk up the scope chain, tracking the number of fn scopes // that we pass through, until we find a lifetime with the - // given name or we run out of scopes. If we encounter a code - // block, then the lifetime is not bound but free, so switch - // over to `resolve_free_lifetime_ref()` to complete the + // given name or we run out of scopes. // search. let mut late_depth = 0; let mut scope = self.scope; - loop { + let mut outermost_body = None; + let result = loop { match *scope { - FnScope {fn_id, body_id, s } => { - return self.resolve_free_lifetime_ref( - region::CallSiteScopeData { fn_id: fn_id, body_id: body_id }, - lifetime_ref, - s); + Scope::Body { id, s } => { + outermost_body = Some(id); + scope = s; } - RootScope => { - break; + Scope::Root => { + break None; } - EarlyScope(lifetimes, start, s) => { - match search_lifetimes(lifetimes, lifetime_ref) { - Some((index, lifetime_def)) => { - let decl_id = lifetime_def.id; - let def = DefEarlyBoundRegion(start + index, decl_id); - self.insert_lifetime(lifetime_ref, def); - return; - } - None => { + Scope::Binder { ref lifetimes, s } => { + if let Some(&def) = lifetimes.get(&lifetime_ref.name) { + break Some(def.shifted(late_depth)); + } else { + late_depth += 1; + scope = s; + } + } + + Scope::Elision { s, .. } | + Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + } + }; + + if let Some(mut def) = result { + if let Some(body_id) = outermost_body { + let fn_id = self.hir_map.body_owner(body_id); + let scope_data = region::CallSiteScopeData { + fn_id: fn_id, body_id: body_id.node_id + }; + match self.hir_map.get(fn_id) { + hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(..), .. + }) | + hir::map::NodeTraitItem(&hir::TraitItem { + node: hir::TraitItemKind::Method(..), .. + }) | + hir::map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(..), .. + }) => { + def = Region::Free(scope_data, def.id().unwrap()); + } + _ => {} + } + } + self.insert_lifetime(lifetime_ref, def); + } else { + struct_span_err!(self.sess, lifetime_ref.span, E0261, + "use of undeclared lifetime name `{}`", lifetime_ref.name) + .span_label(lifetime_ref.span, &format!("undeclared lifetime")) + .emit(); + } + } + + fn visit_segment_parameters(&mut self, + def: Def, + depth: usize, + params: &'tcx hir::PathParameters) { + let data = match *params { + hir::ParenthesizedParameters(ref data) => { + self.visit_fn_like_elision(&data.inputs, data.output.as_ref()); + return; + } + hir::AngleBracketedParameters(ref data) => data + }; + + if data.lifetimes.iter().all(|l| l.is_elided()) { + self.resolve_elided_lifetimes(&data.lifetimes); + } else { + for l in &data.lifetimes { self.visit_lifetime(l); } + } + + // Figure out if this is a type/trait segment, + // which requires object lifetime defaults. + let parent_def_id = |this: &mut Self, def_id: DefId| { + let def_key = if def_id.is_local() { + this.hir_map.def_key(def_id) + } else { + this.sess.cstore.def_key(def_id) + }; + DefId { + krate: def_id.krate, + index: def_key.parent.expect("missing parent") + } + }; + let type_def_id = match def { + Def::AssociatedTy(def_id) if depth == 1 => { + Some(parent_def_id(self, def_id)) + } + Def::Variant(def_id) if depth == 0 => { + Some(parent_def_id(self, def_id)) + } + Def::Struct(def_id) | + Def::Union(def_id) | + Def::Enum(def_id) | + Def::TyAlias(def_id) | + Def::Trait(def_id) if depth == 0 => Some(def_id), + _ => None + }; + + let object_lifetime_defaults = type_def_id.map_or(vec![], |def_id| { + let in_body = { + let mut scope = self.scope; + loop { + match *scope { + Scope::Root => break false, + + Scope::Body { .. } => break true, + + Scope::Binder { s, .. } | + Scope::Elision { s, .. } | + Scope::ObjectLifetimeDefault { s, .. } => { scope = s; } } } + }; + + let map = &self.map; + let unsubst = if let Some(id) = self.hir_map.as_local_node_id(def_id) { + &map.object_lifetime_defaults[&id] + } else { + let cstore = &self.sess.cstore; + self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| { + cstore.item_generics_object_lifetime_defaults(def_id) + }) + }; + unsubst.iter().map(|set| { + match *set { + Set1::Empty => { + if in_body { + None + } else { + Some(Region::Static) + } + } + Set1::One(r) => r.subst(&data.lifetimes, map), + Set1::Many => None + } + }).collect() + }); + + for (i, ty) in data.types.iter().enumerate() { + if let Some(<) = object_lifetime_defaults.get(i) { + let scope = Scope::ObjectLifetimeDefault { + lifetime: lt, + s: self.scope + }; + self.with(scope, |_, this| this.visit_ty(ty)); + } else { + self.visit_ty(ty); + } + } + + for b in &data.bindings { self.visit_assoc_type_binding(b); } + } + + fn visit_fn_like_elision(&mut self, inputs: &'tcx [P], + output: Option<&'tcx P>) { + let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); + let arg_scope = Scope::Elision { + elide: arg_elide.clone(), + s: self.scope + }; + self.with(arg_scope, |_, this| { + for input in inputs { + this.visit_ty(input); + } + match *this.scope { + Scope::Elision { ref elide, .. } => { + arg_elide = elide.clone(); + } + _ => bug!() + } + }); + + let output = match output { + Some(ty) => ty, + None => return + }; + + // Figure out if there's a body we can get argument names from, + // and whether there's a `self` argument (treated specially). + let mut assoc_item_kind = None; + let mut impl_self = None; + let parent = self.hir_map.get_parent_node(output.id); + let body = match self.hir_map.get(parent) { + // `fn` definitions and methods. + hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(.., body), .. + }) => Some(body), + + hir::map::NodeTraitItem(&hir::TraitItem { + node: hir::TraitItemKind::Method(_, ref m), .. + }) => { + match self.hir_map.expect_item(self.hir_map.get_parent(parent)).node { + hir::ItemTrait(.., ref trait_items) => { + assoc_item_kind = trait_items.iter().find(|ti| ti.id.node_id == parent) + .map(|ti| ti.kind); + } + _ => {} + } + match *m { + hir::TraitMethod::Required(_) => None, + hir::TraitMethod::Provided(body) => Some(body), + } + } + + hir::map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(_, body), .. + }) => { + match self.hir_map.expect_item(self.hir_map.get_parent(parent)).node { + hir::ItemImpl(.., ref self_ty, ref impl_items) => { + impl_self = Some(self_ty); + assoc_item_kind = impl_items.iter().find(|ii| ii.id.node_id == parent) + .map(|ii| ii.kind); + } + _ => {} + } + Some(body) + } + + // `fn(...) -> R` and `Trait(...) -> R` (both types and bounds). + hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => None, + + // Foreign `fn` decls are terrible because we messed up, + // and their return types get argument type elision. + // And now too much code out there is abusing this rule. + hir::map::NodeForeignItem(_) => { + let arg_scope = Scope::Elision { + elide: arg_elide, + s: self.scope + }; + self.with(arg_scope, |_, this| this.visit_ty(output)); + return; + } + + // Everything else (only closures?) doesn't + // actually enjoy elision in return types. + _ => { + self.visit_ty(output); + return; + } + }; + + let has_self = match assoc_item_kind { + Some(hir::AssociatedItemKind::Method { has_self }) => has_self, + _ => false + }; + + // In accordance with the rules for lifetime elision, we can determine + // what region to use for elision in the output type in two ways. + // First (determined here), if `self` is by-reference, then the + // implied output region is the region of the self parameter. + if has_self { + // Look for `self: &'a Self` - also desugared from `&'a self`, + // and if that matches, use it for elision and return early. + let is_self_ty = |def: Def| { + if let Def::SelfTy(..) = def { + return true; + } + + // Can't always rely on literal (or implied) `Self` due + // to the way elision rules were originally specified. + let impl_self = impl_self.map(|ty| &ty.node); + if let Some(&hir::TyPath(hir::QPath::Resolved(None, ref path))) = impl_self { + match path.def { + // Whitelist the types that unambiguously always + // result in the same type constructor being used + // (it can't differ between `Self` and `self`). + Def::Struct(_) | + Def::Union(_) | + Def::Enum(_) | + Def::PrimTy(_) => return def == path.def, + _ => {} + } + } - LateScope(lifetimes, s) => { - match search_lifetimes(lifetimes, lifetime_ref) { - Some((_index, lifetime_def)) => { - let decl_id = lifetime_def.id; - let debruijn = ty::DebruijnIndex::new(late_depth + 1); - let def = DefLateBoundRegion(debruijn, decl_id); - self.insert_lifetime(lifetime_ref, def); + false + }; + + if let hir::TyRptr(lifetime_ref, ref mt) = inputs[0].node { + if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = mt.ty.node { + if is_self_ty(path.def) { + if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) { + let scope = Scope::Elision { + elide: Elide::Exact(lifetime), + s: self.scope + }; + self.with(scope, |_, this| this.visit_ty(output)); return; } + } + } + } + } - None => { - late_depth += 1; - scope = s; + // Second, if there was exactly one lifetime (either a substitution or a + // reference) in the arguments, then any anonymous regions in the output + // have that lifetime. + let mut possible_implied_output_region = None; + let mut lifetime_count = 0; + let arg_lifetimes = inputs.iter().enumerate().skip(has_self as usize).map(|(i, input)| { + let mut gather = GatherLifetimes { + map: self.map, + binder_depth: 1, + have_bound_regions: false, + lifetimes: FxHashSet() + }; + gather.visit_ty(input); + + lifetime_count += gather.lifetimes.len(); + + if lifetime_count == 1 && gather.lifetimes.len() == 1 { + // there's a chance that the unique lifetime of this + // iteration will be the appropriate lifetime for output + // parameters, so lets store it. + possible_implied_output_region = gather.lifetimes.iter().cloned().next(); + } + + ElisionFailureInfo { + parent: body, + index: i, + lifetime_count: gather.lifetimes.len(), + have_bound_regions: gather.have_bound_regions + } + }).collect(); + + let elide = if lifetime_count == 1 { + Elide::Exact(possible_implied_output_region.unwrap()) + } else { + Elide::Error(arg_lifetimes) + }; + + let scope = Scope::Elision { + elide: elide, + s: self.scope + }; + self.with(scope, |_, this| this.visit_ty(output)); + + struct GatherLifetimes<'a> { + map: &'a NamedRegionMap, + binder_depth: u32, + have_bound_regions: bool, + lifetimes: FxHashSet, + } + + impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &hir::Ty) { + if let hir::TyBareFn(_) = ty.node { + self.binder_depth += 1; + } + if let hir::TyTraitObject(ref bounds, ref lifetime) = ty.node { + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } + + // Stay on the safe side and don't include the object + // lifetime default (which may not end up being used). + if !lifetime.is_elided() { + self.visit_lifetime(lifetime); + } + } else { + intravisit::walk_ty(self, ty); + } + if let hir::TyBareFn(_) = ty.node { + self.binder_depth -= 1; + } + } + + fn visit_poly_trait_ref(&mut self, + trait_ref: &hir::PolyTraitRef, + modifier: hir::TraitBoundModifier) { + self.binder_depth += 1; + intravisit::walk_poly_trait_ref(self, trait_ref, modifier); + self.binder_depth -= 1; + } + + fn visit_lifetime_def(&mut self, lifetime_def: &hir::LifetimeDef) { + for l in &lifetime_def.bounds { self.visit_lifetime(l); } + } + + fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { + if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) { + match lifetime { + Region::LateBound(debruijn, _) | + Region::LateBoundAnon(debruijn, _) + if debruijn.depth < self.binder_depth => { + self.have_bound_regions = true; + } + _ => { + self.lifetimes.insert(lifetime.from_depth(self.binder_depth)); } } } } } - self.unresolved_lifetime_ref(lifetime_ref); } - fn resolve_free_lifetime_ref(&mut self, - scope_data: region::CallSiteScopeData, - lifetime_ref: &hir::Lifetime, - scope: Scope) { - debug!("resolve_free_lifetime_ref \ - scope_data: {:?} lifetime_ref: {:?} scope: {:?}", - scope_data, lifetime_ref, scope); + fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[hir::Lifetime]) { + if lifetime_refs.is_empty() { + return; + } - // Walk up the scope chain, tracking the outermost free scope, - // until we encounter a scope that contains the named lifetime - // or we run out of scopes. - let mut scope_data = scope_data; - let mut scope = scope; - let mut search_result = None; - loop { - debug!("resolve_free_lifetime_ref \ - scope_data: {:?} scope: {:?} search_result: {:?}", - scope_data, scope, search_result); + let span = lifetime_refs[0].span; + let mut late_depth = 0; + let mut scope = self.scope; + let error = loop { match *scope { - FnScope { fn_id, body_id, s } => { - scope_data = region::CallSiteScopeData { - fn_id: fn_id, body_id: body_id - }; + // Do not assign any resolution, it will be inferred. + Scope::Body { .. } => return, + + Scope::Root => break None, + + Scope::Binder { s, .. } => { + late_depth += 1; scope = s; } - RootScope => { - break; + Scope::Elision { ref elide, .. } => { + let lifetime = match *elide { + Elide::FreshLateAnon(ref counter) => { + for lifetime_ref in lifetime_refs { + let lifetime = Region::late_anon(counter).shifted(late_depth); + self.insert_lifetime(lifetime_ref, lifetime); + } + return; + } + Elide::Exact(l) => l.shifted(late_depth), + Elide::Static => { + if !self.sess.features.borrow().static_in_const { + self.sess + .struct_span_err(span, + "this needs a `'static` lifetime or the \ + `static_in_const` feature, see #35897") + .emit(); + } + Region::Static + } + Elide::Error(ref e) => break Some(e) + }; + for lifetime_ref in lifetime_refs { + self.insert_lifetime(lifetime_ref, lifetime); + } + return; } - EarlyScope(lifetimes, _, s) | - LateScope(lifetimes, s) => { - search_result = search_lifetimes(lifetimes, lifetime_ref); - if search_result.is_some() { - break; - } + Scope::ObjectLifetimeDefault { s, .. } => { scope = s; } } - } + }; - match search_result { - Some((_depth, lifetime)) => { - let def = DefFreeRegion(scope_data, lifetime.id); - self.insert_lifetime(lifetime_ref, def); + let mut err = struct_span_err!(self.sess, span, E0106, + "missing lifetime specifier{}", + if lifetime_refs.len() > 1 { "s" } else { "" }); + let msg = if lifetime_refs.len() > 1 { + format!("expected {} lifetime parameters", lifetime_refs.len()) + } else { + format!("expected lifetime parameter") + }; + err.span_label(span, &msg); + + if let Some(params) = error { + if lifetime_refs.len() == 1 { + self.report_elision_failure(&mut err, params); } + } + err.emit(); + } - None => { - self.unresolved_lifetime_ref(lifetime_ref); + fn report_elision_failure(&mut self, + db: &mut DiagnosticBuilder, + params: &[ElisionFailureInfo]) { + let mut m = String::new(); + let len = params.len(); + + let elided_params: Vec<_> = params.iter().cloned() + .filter(|info| info.lifetime_count > 0) + .collect(); + + let elided_len = elided_params.len(); + + for (i, info) in elided_params.into_iter().enumerate() { + let ElisionFailureInfo { + parent, index, lifetime_count: n, have_bound_regions + } = info; + + let help_name = if let Some(body) = parent { + let arg = &self.hir_map.body(body).arguments[index]; + format!("`{}`", self.hir_map.node_to_pretty_string(arg.pat.id)) + } else { + format!("argument {}", index + 1) + }; + + m.push_str(&(if n == 1 { + help_name + } else { + format!("one of {}'s {} elided {}lifetimes", help_name, n, + if have_bound_regions { "free " } else { "" } ) + })[..]); + + if elided_len == 2 && i == 0 { + m.push_str(" or "); + } else if i + 2 == elided_len { + m.push_str(", or "); + } else if i != elided_len - 1 { + m.push_str(", "); } + } + if len == 0 { + help!(db, + "this function's return type contains a borrowed value, but \ + there is no value for it to be borrowed from"); + help!(db, + "consider giving it a 'static lifetime"); + } else if elided_len == 0 { + help!(db, + "this function's return type contains a borrowed value with \ + an elided lifetime, but the lifetime cannot be derived from \ + the arguments"); + help!(db, + "consider giving it an explicit bounded or 'static \ + lifetime"); + } else if elided_len == 1 { + help!(db, + "this function's return type contains a borrowed value, but \ + the signature does not say which {} it is borrowed from", + m); + } else { + help!(db, + "this function's return type contains a borrowed value, but \ + the signature does not say whether it is borrowed from {}", + m); + } } - fn unresolved_lifetime_ref(&self, lifetime_ref: &hir::Lifetime) { - struct_span_err!(self.sess, lifetime_ref.span, E0261, - "use of undeclared lifetime name `{}`", lifetime_ref.name) - .span_label(lifetime_ref.span, &format!("undeclared lifetime")) - .emit(); + fn resolve_object_lifetime_default(&mut self, lifetime_ref: &hir::Lifetime) { + let mut late_depth = 0; + let mut scope = self.scope; + let lifetime = loop { + match *scope { + Scope::Binder { s, .. } => { + late_depth += 1; + scope = s; + } + + Scope::Root | + Scope::Elision { .. } => break Region::Static, + + Scope::Body { .. } | + Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, + + Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l + } + }; + self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); } - fn check_lifetime_defs(&mut self, old_scope: Scope, lifetimes: &[hir::LifetimeDef]) { + fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::LifetimeDef]) { for i in 0..lifetimes.len() { let lifetime_i = &lifetimes[i]; @@ -770,7 +1475,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn check_lifetime_def_for_shadowing(&self, - mut old_scope: Scope, + mut old_scope: ScopeRef, lifetime: &hir::Lifetime) { for &(label, label_span) in &self.labels_in_fn { @@ -786,21 +1491,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { loop { match *old_scope { - FnScope { s, .. } => { + Scope::Body { s, .. } | + Scope::Elision { s, .. } | + Scope::ObjectLifetimeDefault { s, .. } => { old_scope = s; } - RootScope => { + Scope::Root => { return; } - EarlyScope(lifetimes, _, s) | - LateScope(lifetimes, s) => { - if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) { + Scope::Binder { ref lifetimes, s } => { + if let Some(&def) = lifetimes.get(&lifetime.name) { signal_shadowing_problem( self.sess, lifetime.name, - original_lifetime(&lifetime_def), + original_lifetime(self.hir_map.span(def.id().unwrap())), shadower_lifetime(&lifetime)); return; } @@ -813,7 +1519,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn insert_lifetime(&mut self, lifetime_ref: &hir::Lifetime, - def: DefRegion) { + def: Region) { if lifetime_ref.id == ast::DUMMY_NODE_ID { span_bug!(lifetime_ref.span, "lifetime reference not renumbered, \ @@ -828,17 +1534,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } -fn search_lifetimes<'a>(lifetimes: &'a [hir::LifetimeDef], - lifetime_ref: &hir::Lifetime) - -> Option<(u32, &'a hir::Lifetime)> { - for (i, lifetime_decl) in lifetimes.iter().enumerate() { - if lifetime_decl.lifetime.name == lifetime_ref.name { - return Some((i as u32, &lifetime_decl.lifetime)); - } - } - return None; -} - /////////////////////////////////////////////////////////////////////////// /// Detects late-bound lifetimes and inserts them into diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 7d8f7fcefe639..7419d74287b97 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -899,6 +899,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "attempt to recover from parse errors (experimental)"), incremental: Option = (None, parse_opt_string, [UNTRACKED], "enable incremental compilation (experimental)"), + incremental_cc: bool = (false, parse_bool, [UNTRACKED], + "enable cross-crate incremental compilation (even more experimental)"), incremental_info: bool = (false, parse_bool, [UNTRACKED], "print high-level information about incremental reuse (or the lack thereof)"), incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 58cb52e897786..383fab3fcd766 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -199,7 +199,7 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt, fn uncovered_tys<'tcx>(tcx: TyCtxt, ty: Ty<'tcx>, infer_is_local: InferIsLocal) -> Vec> { - if ty_is_local_constructor(tcx, ty, infer_is_local) { + if ty_is_local_constructor(ty, infer_is_local) { vec![] } else if fundamental_ty(tcx, ty) { ty.walk_shallow() @@ -219,13 +219,13 @@ fn is_type_parameter(ty: Ty) -> bool { } fn ty_is_local(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal) -> bool { - ty_is_local_constructor(tcx, ty, infer_is_local) || + ty_is_local_constructor(ty, infer_is_local) || fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, infer_is_local)) } fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool { match ty.sty { - ty::TyBox(..) | ty::TyRef(..) => true, + ty::TyRef(..) => true, ty::TyAdt(def, _) => def.is_fundamental(), ty::TyDynamic(ref data, ..) => { data.principal().map_or(false, |p| tcx.has_attr(p.def_id(), "fundamental")) @@ -234,7 +234,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool { } } -fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> bool { +fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal)-> bool { debug!("ty_is_local_constructor({:?})", ty); match ty.sty { @@ -265,11 +265,6 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> def.did.is_local() } - ty::TyBox(_) => { // Box - let krate = tcx.lang_items.owned_box().map(|d| d.krate); - krate == Some(LOCAL_CRATE) - } - ty::TyDynamic(ref tt, ..) => { tt.principal().map_or(false, |p| p.def_id().is_local()) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 1658efb03235a..661d47199df13 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -154,7 +154,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyStr => Some(2), ty::TyInt(..) | ty::TyUint(..) | ty::TyInfer(ty::IntVar(..)) => Some(3), ty::TyFloat(..) | ty::TyInfer(ty::FloatVar(..)) => Some(4), - ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(5), + ty::TyRef(..) | ty::TyRawPtr(..) => Some(5), ty::TyArray(..) | ty::TySlice(..) => Some(6), ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(7), ty::TyDynamic(..) => Some(8), diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4990bb9f521d3..d51332f833d77 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1735,7 +1735,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) | - ty::TyChar | ty::TyBox(_) | ty::TyRef(..) | + ty::TyChar | ty::TyRef(..) | ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever | ty::TyError => { // safe for everything @@ -1788,7 +1788,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(Vec::new())) } - ty::TyBox(_) | ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | + ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | ty::TyClosure(..) | ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { Never @@ -1865,10 +1865,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { t); } - ty::TyBox(referent_ty) => { // Box - vec![referent_ty] - } - ty::TyRawPtr(ty::TypeAndMut { ty: element_ty, ..}) | ty::TyRef(_, ty::TypeAndMut { ty: element_ty, ..}) => { vec![element_ty] diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index ed5b470849c41..00c6dca21b1ef 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -56,12 +56,8 @@ def_type_content_sets! { // InteriorAll = 0b00000000__00000000__1111, // Things that are owned by the value (second and third nibbles): - OwnsOwned = 0b0000_0000__0000_0001__0000, OwnsDtor = 0b0000_0000__0000_0010__0000, - OwnsAll = 0b0000_0000__1111_1111__0000, - - // Things that mean drop glue is necessary - NeedsDrop = 0b0000_0000__0000_0111__0000, + // OwnsAll = 0b0000_0000__1111_1111__0000, // All bits All = 0b1111_1111__1111_1111__1111 @@ -77,10 +73,6 @@ impl TypeContents { (self.bits & tc.bits) != 0 } - pub fn owns_owned(&self) -> bool { - self.intersects(TC::OwnsOwned) - } - pub fn interior_param(&self) -> bool { self.intersects(TC::InteriorParam) } @@ -90,12 +82,7 @@ impl TypeContents { } pub fn needs_drop(&self, _: TyCtxt) -> bool { - self.intersects(TC::NeedsDrop) - } - - /// Includes only those bits that still apply when indirected through a `Box` pointer - pub fn owned_pointer(&self) -> TypeContents { - TC::OwnsOwned | (*self & TC::OwnsAll) + self.intersects(TC::OwnsDtor) } pub fn union(v: I, mut f: F) -> TypeContents where @@ -104,10 +91,6 @@ impl TypeContents { { v.into_iter().fold(TC::None, |tc, ty| tc | f(ty)) } - - pub fn has_dtor(&self) -> bool { - self.intersects(TC::OwnsDtor) - } } impl ops::BitOr for TypeContents { @@ -191,10 +174,6 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TC::None } - ty::TyBox(typ) => { - tc_ty(tcx, typ, cache).owned_pointer() - } - ty::TyDynamic(..) => { TC::All - TC::InteriorParam } @@ -237,7 +216,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { if def.is_union() { // unions don't have destructors regardless of the child types - res = res - TC::NeedsDrop; + res = res - TC::OwnsDtor; } if def.has_dtor() { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index c78ba3b8a9bbf..ce4a6a3182635 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -19,6 +19,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; use hir::map::DisambiguatedDefPathData; use middle::free_region::FreeRegionMap; +use middle::lang_items; use middle::region::RegionMaps; use middle::resolve_lifetime; use middle::stability; @@ -231,7 +232,11 @@ pub struct TypeckTables<'tcx> { /// of the struct - this is needed because it is non-trivial to /// normalize while preserving regions. This table is used only in /// MIR construction and hence is not serialized to metadata. - pub fru_field_types: NodeMap>> + pub fru_field_types: NodeMap>>, + + /// Maps a cast expression to its kind. This is keyed on the + /// *from* expression of the cast, not the cast itself. + pub cast_kinds: NodeMap, } impl<'tcx> TypeckTables<'tcx> { @@ -246,7 +251,8 @@ impl<'tcx> TypeckTables<'tcx> { closure_tys: NodeMap(), closure_kinds: NodeMap(), liberated_fn_sigs: NodeMap(), - fru_field_types: NodeMap() + fru_field_types: NodeMap(), + cast_kinds: NodeMap(), } } @@ -533,10 +539,6 @@ pub struct GlobalCtxt<'tcx> { /// expression defining the closure. pub closure_kinds: RefCell>>, - /// Maps a cast expression to its kind. This is keyed on the - /// *from* expression of the cast, not the cast itself. - pub cast_kinds: RefCell>, - /// Maps Fn items to a collection of fragment infos. /// /// The main goal is to identify data (each of which may be moved @@ -792,7 +794,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { custom_coerce_unsized_kinds: RefCell::new(DefIdMap()), closure_tys: RefCell::new(DepTrackingMap::new(dep_graph.clone())), closure_kinds: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - cast_kinds: RefCell::new(NodeMap()), fragment_infos: RefCell::new(DefIdMap()), crate_name: Symbol::intern(crate_name), data_layout: data_layout, @@ -1088,7 +1089,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - TyAdt, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, + TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); println!("Substs interner: #{}", self.interners.substs.borrow().len()); @@ -1336,7 +1337,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyBox(ty)) + let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); + let adt_def = self.lookup_adt_def(def_id); + let substs = self.mk_substs(iter::once(Kind::from(ty))); + self.mk_ty(TyAdt(adt_def, substs)) } pub fn mk_ptr(self, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 91087a3dcecd0..29d855a7fcb78 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -181,7 +181,6 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(), ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), - ty::TyBox(_) => "box".to_string(), ty::TyArray(_, n) => format!("array of {} elements", n), ty::TySlice(_) => "slice".to_string(), ty::TyRawPtr(_) => "*-ptr".to_string(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 7b4d76ad4973e..94b9abc72025f 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -11,7 +11,6 @@ use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; use syntax::ast; -use middle::lang_items::OwnedBoxLangItem; use self::SimplifiedType::*; @@ -69,10 +68,6 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // view of possibly unifying simplify_type(tcx, mt.ty, can_simplify_params) } - ty::TyBox(_) => { - // treat like we would treat `Box` - Some(AdtSimplifiedType(tcx.require_lang_item(OwnedBoxLangItem))) - } ty::TyClosure(def_id, _) => { Some(ClosureSimplifiedType(def_id)) } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index a06d3ed6cf4fb..0de77526b5a46 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -138,7 +138,7 @@ impl FlagComputation { self.add_region(r); } - &ty::TyBox(tt) | &ty::TyArray(tt, _) | &ty::TySlice(tt) => { + &ty::TyArray(tt, _) | &ty::TySlice(tt) => { self.add_ty(tt) } diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 92395e3c381aa..6c49493a65559 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -191,11 +191,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } TyRef(_, ref tm) => { - if tcx.sess.features.borrow().never_type { - tm.ty.uninhabited_from(visited, tcx) - } else { - DefIdForest::empty() - } + tm.ty.uninhabited_from(visited, tcx) } _ => DefIdForest::empty(), diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index d488cd1c42711..b719911d18cf8 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -314,8 +314,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option { ty::TyDynamic(data, ..) => data.principal().map(|p| p.def_id()), ty::TyArray(subty, _) | - ty::TySlice(subty) | - ty::TyBox(subty) => characteristic_def_id_of_type(subty), + ty::TySlice(subty) => characteristic_def_id_of_type(subty), ty::TyRawPtr(mt) | ty::TyRef(_, mt) => characteristic_def_id_of_type(mt.ty), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ff95554dbbfcd..78364abdaecba 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1053,6 +1053,23 @@ impl<'a, 'gcx, 'tcx> Layout { let dl = &tcx.data_layout; assert!(!ty.has_infer_types()); + let ptr_layout = |pointee: Ty<'gcx>| { + let non_zero = !ty.is_unsafe_ptr(); + let pointee = normalize_associated_type(infcx, pointee); + if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) { + Ok(Scalar { value: Pointer, non_zero: non_zero }) + } else { + let unsized_part = tcx.struct_tail(pointee); + let meta = match unsized_part.sty { + ty::TySlice(_) | ty::TyStr => { + Int(dl.ptr_sized_integer()) + } + ty::TyDynamic(..) => Pointer, + _ => return Err(LayoutError::Unknown(unsized_part)) + }; + Ok(FatPointer { metadata: meta, non_zero: non_zero }) + } + }; let layout = match ty.sty { // Basic scalars. @@ -1082,24 +1099,12 @@ impl<'a, 'gcx, 'tcx> Layout { }, // Potentially-fat pointers. - ty::TyBox(pointee) | ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - let non_zero = !ty.is_unsafe_ptr(); - let pointee = normalize_associated_type(infcx, pointee); - if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) { - Scalar { value: Pointer, non_zero: non_zero } - } else { - let unsized_part = tcx.struct_tail(pointee); - let meta = match unsized_part.sty { - ty::TySlice(_) | ty::TyStr => { - Int(dl.ptr_sized_integer()) - } - ty::TyDynamic(..) => Pointer, - _ => return Err(LayoutError::Unknown(unsized_part)) - }; - FatPointer { metadata: meta, non_zero: non_zero } - } + ptr_layout(pointee)? + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_layout(ty.boxed_ty())? } // Arrays and slices. @@ -1560,26 +1565,32 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { Err(err) => err }; + let ptr_skeleton = |pointee: Ty<'gcx>| { + let non_zero = !ty.is_unsafe_ptr(); + let tail = tcx.struct_tail(pointee); + match tail.sty { + ty::TyParam(_) | ty::TyProjection(_) => { + assert!(tail.has_param_types() || tail.has_self_ty()); + Ok(SizeSkeleton::Pointer { + non_zero: non_zero, + tail: tcx.erase_regions(&tail) + }) + } + _ => { + bug!("SizeSkeleton::compute({}): layout errored ({}), yet \ + tail `{}` is not a type parameter or a projection", + ty, err, tail) + } + } + }; + match ty.sty { - ty::TyBox(pointee) | ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - let non_zero = !ty.is_unsafe_ptr(); - let tail = tcx.struct_tail(pointee); - match tail.sty { - ty::TyParam(_) | ty::TyProjection(_) => { - assert!(tail.has_param_types() || tail.has_self_ty()); - Ok(SizeSkeleton::Pointer { - non_zero: non_zero, - tail: tcx.erase_regions(&tail) - }) - } - _ => { - bug!("SizeSkeleton::compute({}): layout errored ({}), yet \ - tail `{}` is not a type parameter or a projection", - ty, err, tail) - } - } + ptr_skeleton(pointee) + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_skeleton(ty.boxed_ty()) } ty::TyAdt(def, substs) => { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5681e8c776623..5ab45e746e7f2 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -9,7 +9,6 @@ // except according to those terms. pub use self::Variance::*; -pub use self::DtorKind::*; pub use self::AssociatedItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; @@ -120,21 +119,6 @@ pub struct Resolutions { pub maybe_unused_trait_imports: NodeSet, } -#[derive(Copy, Clone)] -pub enum DtorKind { - NoDtor, - TraitDtor -} - -impl DtorKind { - pub fn is_present(&self) -> bool { - match *self { - TraitDtor => true, - _ => false - } - } -} - #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum AssociatedItemContainer { TraitContainer(DefId), @@ -514,7 +498,7 @@ pub enum BorrowKind { /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in - /// implicit closure bindings. It is needed when you the closure + /// implicit closure bindings. It is needed when the closure /// is borrowing or mutating a mutable referent, e.g.: /// /// let x: &mut isize = ...; @@ -592,24 +576,6 @@ pub enum IntVarValue { UintType(ast::UintTy), } -/// Default region to use for the bound of objects that are -/// supplied as the value for this type parameter. This is derived -/// from `T:'a` annotations appearing in the type definition. If -/// this is `None`, then the default is inherited from the -/// surrounding context. See RFC #599 for details. -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub enum ObjectLifetimeDefault<'tcx> { - /// Require an explicit annotation. Occurs when multiple - /// `T:'a` constraints are found. - Ambiguous, - - /// Use the base default, typically 'static, but in a fn body it is a fresh variable - BaseDefault, - - /// Use the given region as the default. - Specific(&'tcx Region), -} - #[derive(Clone, RustcEncodable, RustcDecodable)] pub struct TypeParameterDef<'tcx> { pub name: Name, @@ -617,7 +583,6 @@ pub struct TypeParameterDef<'tcx> { pub index: u32, pub default_def_id: DefId, // for use in error reporing about defaults pub default: Option>, - pub object_lifetime_default: ObjectLifetimeDefault<'tcx>, /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute /// on generic parameter `T`, asserts data behind the parameter @@ -625,12 +590,11 @@ pub struct TypeParameterDef<'tcx> { pub pure_wrt_drop: bool, } -#[derive(Clone, RustcEncodable, RustcDecodable)] -pub struct RegionParameterDef<'tcx> { +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +pub struct RegionParameterDef { pub name: Name, pub def_id: DefId, pub index: u32, - pub bounds: Vec<&'tcx ty::Region>, /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute /// on generic parameter `'a`, asserts data of lifetime `'a` @@ -638,7 +602,7 @@ pub struct RegionParameterDef<'tcx> { pub pure_wrt_drop: bool, } -impl<'tcx> RegionParameterDef<'tcx> { +impl RegionParameterDef { pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion { ty::EarlyBoundRegion { index: self.index, @@ -659,7 +623,7 @@ pub struct Generics<'tcx> { pub parent: Option, pub parent_regions: u32, pub parent_types: u32, - pub regions: Vec>, + pub regions: Vec, pub types: Vec>, pub has_self: bool, } @@ -677,7 +641,7 @@ impl<'tcx> Generics<'tcx> { self.parent_count() + self.own_count() } - pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef<'tcx> { + pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef { &self.regions[param.index as usize - self.has_self as usize] } @@ -1322,9 +1286,11 @@ bitflags! { const IS_SIMD = 1 << 4, const IS_FUNDAMENTAL = 1 << 5, const IS_UNION = 1 << 6, + const IS_BOX = 1 << 7, } } +#[derive(Debug)] pub struct VariantDef { /// The variant's DefId. If this is a tuple-like struct, /// this is the DefId of the struct's ctor. @@ -1335,6 +1301,7 @@ pub struct VariantDef { pub ctor_kind: CtorKind, } +#[derive(Debug)] pub struct FieldDef { pub did: DefId, pub name: Name, @@ -1394,6 +1361,9 @@ impl<'a, 'gcx, 'tcx> AdtDef { if Some(did) == tcx.lang_items.phantom_data() { flags = flags | AdtFlags::IS_PHANTOM_DATA; } + if Some(did) == tcx.lang_items.owned_box() { + flags = flags | AdtFlags::IS_BOX; + } match kind { AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM, AdtKind::Union => flags = flags | AdtFlags::IS_UNION, @@ -1486,9 +1456,15 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA) } + /// Returns true if this is Box. + #[inline] + pub fn is_box(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_BOX) + } + /// Returns whether this type has a destructor. pub fn has_dtor(&self) -> bool { - self.dtor_kind().is_present() + self.destructor.get().is_some() } /// Asserts this is a struct and returns the struct's unique @@ -1551,13 +1527,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.destructor.set(Some(dtor)); } - pub fn dtor_kind(&self) -> DtorKind { - match self.destructor.get() { - Some(_) => TraitDtor, - None => NoDtor, - } - } - /// Returns a simpler type such that `Self: Sized` if and only /// if that type is Sized, or `TyErr` if this type is recursive. /// @@ -1659,7 +1628,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { -> Vec> { let result = match ty.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | TyArray(..) | TyClosure(..) | TyNever => { vec![] } diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index eb384eec6a6f1..bc30f1fb71722 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -167,7 +167,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::TyFloat(..) | // OutlivesScalar ty::TyNever | // ... ty::TyAdt(..) | // OutlivesNominalType - ty::TyBox(..) | // OutlivesNominalType (ish) ty::TyAnon(..) | // OutlivesNominalType (ish) ty::TyStr | // OutlivesScalar (ish) ty::TyArray(..) | // ... diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 76c26d01ac8e2..89514085e1c78 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -418,12 +418,6 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.mk_closure_from_closure_substs(a_id, substs)) } - (&ty::TyBox(a_inner), &ty::TyBox(b_inner)) => - { - let typ = relation.relate(&a_inner, &b_inner)?; - Ok(tcx.mk_box(typ)) - } - (&ty::TyRawPtr(ref a_mt), &ty::TyRawPtr(ref b_mt)) => { let mt = relation.relate(a_mt, b_mt)?; diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 0f0478bc8cdb0..05f4abad46921 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -353,7 +353,7 @@ macro_rules! CopyImpls { } } -CopyImpls! { (), hir::Unsafety, abi::Abi } +CopyImpls! { (), hir::Unsafety, abi::Abi, ty::RegionParameterDef } impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) { @@ -468,7 +468,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let sty = match self.sty { - ty::TyBox(typ) => ty::TyBox(typ.fold_with(folder)), ty::TyRawPtr(tm) => ty::TyRawPtr(tm.fold_with(folder)), ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz), ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)), @@ -506,7 +505,6 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match self.sty { - ty::TyBox(typ) => typ.visit_with(visitor), ty::TyRawPtr(ref tm) => tm.visit_with(visitor), ty::TyArray(typ, _sz) => typ.visit_with(visitor), ty::TySlice(typ) => typ.visit_with(visitor), @@ -726,52 +724,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { index: self.index, default: self.default.fold_with(folder), default_def_id: self.default_def_id, - object_lifetime_default: self.object_lifetime_default.fold_with(folder), pure_wrt_drop: self.pure_wrt_drop, } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.default.visit_with(visitor) || - self.object_lifetime_default.visit_with(visitor) - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - ty::ObjectLifetimeDefault::Ambiguous => - ty::ObjectLifetimeDefault::Ambiguous, - - ty::ObjectLifetimeDefault::BaseDefault => - ty::ObjectLifetimeDefault::BaseDefault, - - ty::ObjectLifetimeDefault::Specific(r) => - ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)), - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - ty::ObjectLifetimeDefault::Specific(r) => r.visit_with(visitor), - _ => false, - } - } -} - -impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::RegionParameterDef { - name: self.name, - def_id: self.def_id, - index: self.index, - bounds: self.bounds.fold_with(folder), - pure_wrt_drop: self.pure_wrt_drop, - } - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.bounds.visit_with(visitor) + self.default.visit_with(visitor) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index b02bb7c6e4dd8..113534e4529cd 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -115,12 +115,6 @@ pub enum TypeVariants<'tcx> { /// definition and not a concrete use of it. TyAdt(&'tcx AdtDef, &'tcx Substs<'tcx>), - /// `Box`; this is nominally a struct in the documentation, but is - /// special-cased internally. For example, it is possible to implicitly - /// move the contents of a box out of that box, and methods of any type - /// can have type `Box`. - TyBox(Ty<'tcx>), - /// The pointee of a string slice. Written as `str`. TyStr, @@ -134,7 +128,7 @@ pub enum TypeVariants<'tcx> { TyRawPtr(TypeAndMut<'tcx>), /// A reference; a pointer with an associated lifetime. Written as - /// `&a mut T` or `&'a T`. + /// `&'a mut T` or `&'a T`. TyRef(&'tcx Region, TypeAndMut<'tcx>), /// The anonymous type of a function declaration/definition. Each @@ -1139,10 +1133,17 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn is_unique(&self) -> bool { + pub fn is_box(&self) -> bool { match self.sty { - TyBox(_) => true, - _ => false + TyAdt(def, _) => def.is_box(), + _ => false, + } + } + + pub fn boxed_ty(&self) -> Ty<'tcx> { + match self.sty { + TyAdt(def, substs) if def.is_box() => substs.type_at(0), + _ => bug!("`boxed_ty` is called on non-box type {:?}", self), } } @@ -1247,9 +1248,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { -> Option> { match self.sty { - TyBox(ty) => { + TyAdt(def, _) if def.is_box() => { Some(TypeAndMut { - ty: ty, + ty: self.boxed_ty(), mutbl: if pref == ty::PreferMutLvalue { hir::MutMutable } else { @@ -1349,7 +1350,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyInt(_) | TyUint(_) | TyFloat(_) | - TyBox(_) | TyStr | TyArray(..) | TySlice(_) | diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c05375c47b03a..ba49aa1ef4866 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -481,7 +481,6 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyBool | TyChar | TyStr | - TyBox(_) | TySlice(_) => {} TyError | @@ -563,7 +562,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { mutbl: hir::MutImmutable, .. }) => Some(false), - TyStr | TyBox(..) | TyRef(_, TypeAndMut { + TyStr | TyRef(_, TypeAndMut { mutbl: hir::MutMutable, .. }) => Some(true), @@ -606,7 +605,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { // Fast-path for primitive types let result = match self.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | TyArray(..) | TyTuple(..) | TyClosure(..) | TyNever => Some(true), TyStr | TyDynamic(..) | TySlice(_) => Some(false), diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 3fa7a803141d1..0d1dc2e4d7c21 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -83,7 +83,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => { } - ty::TyBox(ty) | ty::TyArray(ty, _) | ty::TySlice(ty) => { + ty::TyArray(ty, _) | ty::TySlice(ty) => { stack.push(ty); } ty::TyRawPtr(ref mt) | ty::TyRef(_, ref mt) => { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index bab9964651dca..33b70b09dcb7b 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -323,7 +323,6 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } - ty::TyBox(_) | ty::TyRawPtr(_) => { // simple cases that are WF if their type args are WF } diff --git a/src/librustc/util/num.rs b/src/librustc/util/num.rs deleted file mode 100644 index da04976a96a37..0000000000000 --- a/src/librustc/util/num.rs +++ /dev/null @@ -1,98 +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. - -pub trait ToPrimitive { - fn to_i8(&self) -> Option; - fn to_i16(&self) -> Option; - fn to_i32(&self) -> Option; - fn to_i64(&self) -> Option; - fn to_u8(&self) -> Option; - fn to_u16(&self) -> Option; - fn to_u32(&self) -> Option; - fn to_u64(&self) -> Option; -} - -impl ToPrimitive for i64 { - fn to_i8(&self) -> Option { - if *self < i8::min_value() as i64 || *self > i8::max_value() as i64 { - None - } else { - Some(*self as i8) - } - } - fn to_i16(&self) -> Option { - if *self < i16::min_value() as i64 || *self > i16::max_value() as i64 { - None - } else { - Some(*self as i16) - } - } - fn to_i32(&self) -> Option { - if *self < i32::min_value() as i64 || *self > i32::max_value() as i64 { - None - } else { - Some(*self as i32) - } - } - fn to_i64(&self) -> Option { - Some(*self) - } - fn to_u8(&self) -> Option { - if *self < 0 || *self > u8::max_value() as i64 { - None - } else { - Some(*self as u8) - } - } - fn to_u16(&self) -> Option { - if *self < 0 || *self > u16::max_value() as i64 { - None - } else { - Some(*self as u16) - } - } - fn to_u32(&self) -> Option { - if *self < 0 || *self > u32::max_value() as i64 { - None - } else { - Some(*self as u32) - } - } - fn to_u64(&self) -> Option { - if *self < 0 {None} else {Some(*self as u64)} - } -} - -impl ToPrimitive for u64 { - fn to_i8(&self) -> Option { - if *self > i8::max_value() as u64 {None} else {Some(*self as i8)} - } - fn to_i16(&self) -> Option { - if *self > i16::max_value() as u64 {None} else {Some(*self as i16)} - } - fn to_i32(&self) -> Option { - if *self > i32::max_value() as u64 {None} else {Some(*self as i32)} - } - fn to_i64(&self) -> Option { - if *self > i64::max_value() as u64 {None} else {Some(*self as i64)} - } - fn to_u8(&self) -> Option { - if *self > u8::max_value() as u64 {None} else {Some(*self as u8)} - } - fn to_u16(&self) -> Option { - if *self > u16::max_value() as u64 {None} else {Some(*self as u16)} - } - fn to_u32(&self) -> Option { - if *self > u32::max_value() as u64 {None} else {Some(*self as u32)} - } - fn to_u64(&self) -> Option { - Some(*self) - } -} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e90e1a94be951..aa2eb2955debe 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -16,7 +16,7 @@ use ty::{TyBool, TyChar, TyAdt}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::{TyClosure, TyProjection, TyAnon}; -use ty::{TyBox, TyDynamic, TyInt, TyUint, TyInfer}; +use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use std::cell::Cell; @@ -336,13 +336,12 @@ impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> { } } -impl<'tcx> fmt::Debug for ty::RegionParameterDef<'tcx> { +impl fmt::Debug for ty::RegionParameterDef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionParameterDef({}, {:?}, {}, {:?})", + write!(f, "RegionParameterDef({}, {:?}, {})", self.name, self.def_id, - self.index, - self.bounds) + self.index) } } @@ -523,16 +522,6 @@ impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"), - ty::ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"), - ty::ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r), - } - } -} - impl fmt::Display for ty::Region { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if verbose() { @@ -719,7 +708,6 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyInt(t) => write!(f, "{}", t.ty_to_string()), TyUint(t) => write!(f, "{}", t.ty_to_string()), TyFloat(t) => write!(f, "{}", t.ty_to_string()), - TyBox(typ) => write!(f, "Box<{}>", typ), TyRawPtr(ref tm) => { write!(f, "*{} {}", match tm.mutbl { hir::MutMutable => "mut", diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs index 0c2c5433e6c41..2947726139207 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -14,6 +14,7 @@ pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); + base.eliminate_frame_pointer = false; // Required for backtraces // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 7f7f73d9a9678..1783ca74a2592 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -195,7 +195,8 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, bccx.report_aliasability_violation( borrow_span, loan_cause, - mc::AliasableReason::UnaliasableImmutable); + mc::AliasableReason::UnaliasableImmutable, + cmt); Err(()) } (mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) | @@ -203,7 +204,8 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, bccx.report_aliasability_violation( borrow_span, loan_cause, - alias_cause); + alias_cause, + cmt); Err(()) } (..) => { diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 8e0d9c147824d..9e89a3689c7ac 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -709,9 +709,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn open_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyAdt(def, substs) => { - self.open_drop_for_adt(c, def, substs) - } ty::TyClosure(def_id, substs) => { let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx).collect(); self.open_drop_for_tuple(c, &tys) @@ -719,8 +716,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { ty::TyTuple(tys) => { self.open_drop_for_tuple(c, tys) } - ty::TyBox(ty) => { - self.open_drop_for_box(c, ty) + ty::TyAdt(def, _) if def.is_box() => { + self.open_drop_for_box(c, ty.boxed_ty()) + } + ty::TyAdt(def, substs) => { + self.open_drop_for_adt(c, def, substs) } _ => bug!("open drop from non-ADT `{:?}`", ty) } @@ -895,7 +895,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { match ty.sty { ty::TyAdt(def, _) => { - if def.has_dtor() { + if def.has_dtor() && !def.is_box() { self.tcx.sess.span_warn( c.source_info.span, &format!("dataflow bug??? moving out of type with dtor {:?}", diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 2a9acaf58b8f2..7cf6ab2999c05 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -289,7 +289,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { // error: can't move out of borrowed content ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove), // error: can't move out of struct with destructor - ty::TyAdt(adt, _) if adt.has_dtor() => + ty::TyAdt(adt, _) if adt.has_dtor() && !adt.is_box() => return Err(MovePathError::IllegalMove), // move out of union - always move the entire union ty::TyAdt(adt, _) if adt.is_union() => diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 372eb1d5d64f0..a0c36139ddcd2 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -248,7 +248,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx lv, ty); true } - ty::TyAdt(def, _) if def.has_dtor() || def.is_union() => { + ty::TyAdt(def, _) if (def.has_dtor() && !def.is_box()) || def.is_union() => { debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true", lv, ty); true diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 4a92578fed512..46179b31d5cb4 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -540,7 +540,7 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option>> { // Errors // Errors that can occur -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub enum bckerr_code<'tcx> { err_mutbl, /// superscope, subscope, loan cause @@ -550,7 +550,7 @@ pub enum bckerr_code<'tcx> { // Combination of an error code and the categorization of the expression // that caused it -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub struct BckError<'tcx> { span: Span, cause: AliasableViolationKind, @@ -601,12 +601,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { _ => { } } - // General fallback. - let span = err.span.clone(); - let mut db = self.struct_span_err( - err.span, - &self.bckerr_to_string(&err)); - self.note_and_explain_bckerr(&mut db, err, span); + let mut db = self.bckerr_to_diag(&err); + self.note_and_explain_bckerr(&mut db, err); db.emit(); } @@ -771,8 +767,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err_with_code(s, msg, code); } - pub fn bckerr_to_string(&self, err: &BckError<'tcx>) -> String { - match err.code { + pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { + let span = err.span.clone(); + let mut immutable_field = None; + + let msg = &match err.code { err_mutbl => { let descr = match err.cmt.note { mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => { @@ -783,6 +782,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { format!("{} {}", err.cmt.mutbl.to_user_str(), self.cmt_to_string(&err.cmt)) + } Some(lp) => { format!("{} {} `{}`", @@ -807,6 +807,19 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::AutoUnsafe) | BorrowViolation(euv::ForLoop) | BorrowViolation(euv::MatchDiscriminant) => { + // Check for this field's definition to see if it is an immutable reference + // and suggest making it mutable if that is the case. + immutable_field = err.cmt.get_field_name() + .and_then(|name| err.cmt.get_field(name)) + .and_then(|did| self.tcx.hir.as_local_node_id(did)) + .and_then(|nid| { + if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) { + return self.suggest_mut_for_immutable(&field.ty) + .map(|msg| (self.tcx.hir.span(nid), msg)); + } + None + }); + format!("cannot borrow {} as mutable", descr) } BorrowViolation(euv::ClosureInvocation) => { @@ -830,13 +843,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { its contents can be safely reborrowed", descr) } + }; + + let mut db = self.struct_span_err(span, msg); + if let Some((span, msg)) = immutable_field { + db.span_label(span, &msg); } + db } pub fn report_aliasability_violation(&self, span: Span, kind: AliasableViolationKind, - cause: mc::AliasableReason) { + cause: mc::AliasableReason, + cmt: mc::cmt<'tcx>) { let mut is_closure = false; let prefix = match kind { MutabilityViolation => { @@ -903,6 +923,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess, span, E0389, "{} in a `&` reference", prefix); e.span_label(span, &"assignment into an immutable reference"); + if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) { + self.immutable_argument_should_be_mut(nid, &mut e); + } e } }; @@ -913,6 +936,55 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { err.emit(); } + /// Given a type, if it is an immutable reference, return a suggestion to make it mutable + fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option { + // Check wether the argument is an immutable reference + if let hir::TyRptr(lifetime, hir::MutTy { + mutbl: hir::Mutability::MutImmutable, + ref ty + }) = pty.node { + // Account for existing lifetimes when generating the message + if !lifetime.is_elided() { + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(ty.span) { + if let Ok(lifetime_snippet) = self.tcx.sess.codemap() + .span_to_snippet(lifetime.span) { + return Some(format!("use `&{} mut {}` here to make mutable", + lifetime_snippet, + snippet)); + } + } + } else if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(pty.span) { + if snippet.starts_with("&") { + return Some(format!("use `{}` here to make mutable", + snippet.replace("&", "&mut "))); + } + } else { + bug!("couldn't find a snippet for span: {:?}", pty.span); + } + } + None + } + + fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) { + let parent = self.tcx.hir.get_parent_node(nid); + let parent_node = self.tcx.hir.get(parent); + + // The parent node is like a fn + if let Some(fn_like) = FnLikeNode::from_node(parent_node) { + // `nid`'s parent's `Body` + let fn_body = self.tcx.hir.body(fn_like.body()); + // Get the position of `nid` in the arguments list + let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid); + if let Some(i) = arg_pos { + // The argument's `Ty` + let arg_ty = &fn_like.decl().inputs[i]; + if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) { + db.span_label(arg_ty.span, &msg); + } + } + } + } + fn report_out_of_scope_escaping_closure_capture(&self, err: &BckError<'tcx>, capture_span: Span) @@ -961,8 +1033,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>, - error_span: Span) { + pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { + let error_span = err.span.clone(); match err.code { err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span), err_out_of_scope(super_scope, sub_scope, cause) => { @@ -1114,41 +1186,13 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ } } _ => { - if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat { - if let Categorization::Local(local_id) = inner_cmt.cat { - let parent = self.tcx.hir.get_parent_node(local_id); - - if let Some(fn_like) = FnLikeNode::from_node(self.tcx.hir.get(parent)) { - if let Some(i) = self.tcx.hir.body(fn_like.body()).arguments.iter() - .position(|arg| arg.pat.id == local_id) { - let arg_ty = &fn_like.decl().inputs[i]; - if let hir::TyRptr( - opt_lifetime, - hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) = - arg_ty.node { - if let Some(lifetime) = opt_lifetime { - if let Ok(snippet) = self.tcx.sess.codemap() - .span_to_snippet(ty.span) { - if let Ok(lifetime_snippet) = self.tcx.sess.codemap() - .span_to_snippet(lifetime.span) { - db.span_label(arg_ty.span, - &format!("use `&{} mut {}` \ - here to make mutable", - lifetime_snippet, - snippet)); - } - } - } - else if let Ok(snippet) = self.tcx.sess.codemap() - .span_to_snippet(arg_ty.span) { - if snippet.starts_with("&") { - db.span_label(arg_ty.span, - &format!("use `{}` here to make mutable", - snippet.replace("&", "&mut "))); - } - } - } - } + if let Categorization::Deref(..) = err.cmt.cat { + db.span_label(*error_span, &"cannot borrow as mutable"); + if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) { + self.immutable_argument_should_be_mut(local_id, db); + } else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat { + if let Categorization::Local(local_id) = inner_cmt.cat { + self.immutable_argument_should_be_mut(local_id, db); } } } else if let Categorization::Local(local_id) = err.cmt.cat { diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index bb5dacf71e175..94b2ba58c9aa5 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -379,19 +379,24 @@ impl<'tcx> Witness<'tcx> { fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, pcx: PatternContext<'tcx>) -> Vec { + let check_inhabited = cx.tcx.sess.features.borrow().never_type; debug!("all_constructors({:?})", pcx.ty); match pcx.ty.sty { ty::TyBool => [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(), ty::TySlice(ref sub_ty) => { - if sub_ty.is_uninhabited_from(cx.module, cx.tcx) { + if sub_ty.is_uninhabited_from(cx.module, cx.tcx) + && check_inhabited + { vec![Slice(0)] } else { (0..pcx.max_slice_length+1).map(|length| Slice(length)).collect() } } ty::TyArray(ref sub_ty, length) => { - if length == 0 || !sub_ty.is_uninhabited_from(cx.module, cx.tcx) { + if length == 0 || !(sub_ty.is_uninhabited_from(cx.module, cx.tcx) + && check_inhabited) + { vec![Slice(length)] } else { vec![] @@ -403,7 +408,9 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let forest = v.uninhabited_from(&mut visited, cx.tcx, substs, AdtKind::Enum); - if forest.contains(cx.tcx, cx.module) { + if forest.contains(cx.tcx, cx.module) + && check_inhabited + { None } else { Some(Variant(v.did)) @@ -411,7 +418,9 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, }).collect() } _ => { - if pcx.ty.is_uninhabited_from(cx.module, cx.tcx) { + if pcx.ty.is_uninhabited_from(cx.module, cx.tcx) + && check_inhabited + { vec![] } else { vec![Single] @@ -713,7 +722,6 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize debug!("constructor_arity({:?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs) => fs.len(), - ty::TyBox(_) => 1, ty::TySlice(..) | ty::TyArray(..) => match *ctor { Slice(length) => length, ConstantValue(_) => 0, @@ -738,7 +746,6 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, debug!("constructor_sub_pattern_tys({:?}, {:?})", ctor, ty); match ty.sty { ty::TyTuple(ref fs) => fs.into_iter().map(|t| *t).collect(), - ty::TyBox(ty) => vec![ty], ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor { Slice(length) => repeat(ty).take(length).collect(), ConstantValue(_) => vec![], diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index a9dcb1ed89613..47a98155fc4b0 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//#![allow(non_camel_case_types)] - use rustc::middle::const_val::ConstVal::*; use rustc::middle::const_val::ConstVal; use self::ErrKind::*; diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index a3b80ebddcf00..c6272613f4d09 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -215,7 +215,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { } PatternKind::Deref { ref subpattern } => { match self.ty.sty { - ty::TyBox(_) => write!(f, "box ")?, + ty::TyAdt(def, _) if def.is_box() => write!(f, "box ")?, ty::TyRef(_, mt) => { write!(f, "&")?; if mt.mutbl == hir::MutMutable { diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index 78af655852d1b..d4bd9e707fdcb 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -25,7 +25,7 @@ use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use array_vec::{self, Array, ArrayVec}; -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(Hash, Debug)] pub enum AccumulateVec { Array(ArrayVec), Heap(Vec) diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index c0b5b7f517330..51e6e09ab5003 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -52,14 +52,6 @@ impl Hash for ArrayVec } } -impl PartialEq for ArrayVec { - fn eq(&self, other: &Self) -> bool { - self == other - } -} - -impl Eq for ArrayVec {} - impl Clone for ArrayVec where A: Array, A::Element: Clone { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index a7188f6da1ff9..a04a5b106b8f1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -741,15 +741,15 @@ pub fn phase_2_configure_and_expand(sess: &Session, "checking for inline asm in case the target doesn't support it", || no_asm::check_crate(sess, &krate)); - time(sess.time_passes(), + time(time_passes, "early lint checks", || lint::check_ast_crate(sess, &krate)); - time(sess.time_passes(), + time(time_passes, "AST validation", || ast_validation::check_crate(sess, &krate)); - time(sess.time_passes(), "name resolution", || -> CompileResult { + time(time_passes, "name resolution", || -> CompileResult { // Since import resolution will eventually happen in expansion, // don't perform `after_expand` until after import resolution. after_expand(&krate)?; @@ -770,7 +770,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, })?; // Lower ast -> hir. - let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || { + let hir_forest = time(time_passes, "lowering ast -> hir", || { let hir_crate = lower_crate(sess, &krate, &mut resolver); if sess.opts.debugging_opts.hir_stats { @@ -780,7 +780,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, hir_map::Forest::new(hir_crate, &sess.dep_graph) }); - // Discard hygiene data, which isn't required past lowering to HIR. + // Discard hygiene data, which isn't required after lowering to HIR. if !keep_hygiene_data(sess) { syntax::ext::hygiene::reset_hygiene_data(); } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 59f6889ba4d94..1086d75f02cb4 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -805,10 +805,9 @@ fn walk_ty() { let uint_ty = tcx.types.usize; let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]); let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]); - let uniq_ty = tcx.mk_box(tup2_ty); - let walked: Vec<_> = uniq_ty.walk().collect(); + let walked: Vec<_> = tup2_ty.walk().collect(); assert_eq!(walked, - [uniq_ty, tup2_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, tup1_ty, int_ty, + [tup2_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, uint_ty]); }) } @@ -821,12 +820,10 @@ fn walk_ty_skip_subtree() { let uint_ty = tcx.types.usize; let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]); let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]); - let uniq_ty = tcx.mk_box(tup2_ty); // types we expect to see (in order), plus a boolean saying // whether to skip the subtree. - let mut expected = vec![(uniq_ty, false), - (tup2_ty, false), + let mut expected = vec![(tup2_ty, false), (tup1_ty, false), (int_ty, false), (uint_ty, false), @@ -836,7 +833,7 @@ fn walk_ty_skip_subtree() { (uint_ty, false)]; expected.reverse(); - let mut walker = uniq_ty.walk(); + let mut walker = tup2_ty.walk(); while let Some(t) = walker.next() { debug!("walked to {:?}", t); let (expected_ty, skip) = expected.pop().unwrap(); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 69237f406760d..c7512f2971b33 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -828,7 +828,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_ty_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: &'tcx TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) { debug!("visit_poly_trait_ref: st={:?}", self.st); SawPolyTraitRef.hash(self.st); m.hash(self.st); diff --git a/src/librustc_incremental/persist/preds.rs b/src/librustc_incremental/persist/preds.rs index c75a325941f15..3daeacfe87d82 100644 --- a/src/librustc_incremental/persist/preds.rs +++ b/src/librustc_incremental/persist/preds.rs @@ -33,8 +33,12 @@ pub struct Predecessors<'query> { impl<'q> Predecessors<'q> { pub fn new(query: &'q DepGraphQuery, hcx: &mut HashContext) -> Self { - // Find nodes for which we want to know the full set of preds let tcx = hcx.tcx; + + let collect_for_metadata = tcx.sess.opts.debugging_opts.incremental_cc || + tcx.sess.opts.debugging_opts.query_dep_graph; + + // Find nodes for which we want to know the full set of preds let node_count = query.graph.len_nodes(); // Set up some data structures the cache predecessor search needs: @@ -52,7 +56,7 @@ impl<'q> Predecessors<'q> { .enumerate() .filter(|&(_, node)| match node.data { DepNode::WorkProduct(_) => true, - DepNode::MetaData(ref def_id) => def_id.is_local(), + DepNode::MetaData(ref def_id) => collect_for_metadata && def_id.is_local(), // if -Z query-dep-graph is passed, save more extended data // to enable better unit testing diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 356eb845fed9a..f626905f27d4a 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -55,17 +55,21 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let preds = Predecessors::new(&query, &mut hcx); let mut current_metadata_hashes = FxHashMap(); - // IMPORTANT: We are saving the metadata hashes *before* the dep-graph, - // since metadata-encoding might add new entries to the - // DefIdDirectory (which is saved in the dep-graph file). - save_in(sess, - metadata_hash_export_path(sess), - |e| encode_metadata_hashes(tcx, - svh, - &preds, - &mut builder, - &mut current_metadata_hashes, - e)); + if sess.opts.debugging_opts.incremental_cc || + sess.opts.debugging_opts.query_dep_graph { + // IMPORTANT: We are saving the metadata hashes *before* the dep-graph, + // since metadata-encoding might add new entries to the + // DefIdDirectory (which is saved in the dep-graph file). + save_in(sess, + metadata_hash_export_path(sess), + |e| encode_metadata_hashes(tcx, + svh, + &preds, + &mut builder, + &mut current_metadata_hashes, + e)); + } + save_in(sess, dep_graph_path(sess), |e| encode_dep_graph(&preds, &mut builder, e)); diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index d4ab31da8a31e..05ba262ef90c0 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -377,8 +377,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { - if path.segments.len() == 1 && path.segments[0].parameters.is_empty() { - if let Def::Const(..) = path.def { + if let Def::Const(..) = path.def { + if path.segments.len() == 1 { NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", path.segments[0].name, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2892d61b8bd6f..1592d17817641 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -95,7 +95,7 @@ pub struct BoxPointers; impl BoxPointers { fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext, span: Span, ty: Ty) { for leaf_ty in ty.walk() { - if let ty::TyBox(_) = leaf_ty.sty { + if leaf_ty.is_box() { let m = format!("type uses owned (Box type) pointers: {}", ty); cx.span_lint(BOX_POINTERS, span, &m); } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 34bc57884ecbb..18067cb86739b 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -240,6 +240,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(LEGACY_IMPORTS), reference: "issue #38260 ", }, + FutureIncompatibleInfo { + id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY), + reference: "issue #39207 ", + }, ]); // Register renamed and removed lints diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 532e602226450..9669efa2d86b3 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -519,11 +519,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Primitive types with a stable representation. ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe, - ty::TyBox(..) => { - FfiUnsafe("found Rust type Box<_> in foreign module, \ - consider using a raw pointer instead") - } - ty::TySlice(_) => { FfiUnsafe("found Rust slice type in foreign module, \ consider using a raw pointer instead") diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index caa27404086b9..58b2017ceb66e 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -804,7 +804,7 @@ extern "C" { Name: *const c_char) -> ValueRef; pub fn LLVMRustAddHandler(CatchSwitch: ValueRef, Handler: BasicBlockRef); - pub fn LLVMRustSetPersonalityFn(B: BuilderRef, Pers: ValueRef); + pub fn LLVMSetPersonalityFn(Func: ValueRef, Pers: ValueRef); // Add a case to the switch instruction pub fn LLVMAddCase(Switch: ValueRef, OnVal: ValueRef, Dest: BasicBlockRef); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index d100cb53a8b01..39581a4696088 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -17,6 +17,7 @@ use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternC use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro}; use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; +use rustc::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -110,6 +111,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def.krate).get_generics(def.index, tcx) } + fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) { + self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).generics_own_param_counts(def.index) + } + + fn item_generics_object_lifetime_defaults(&self, def: DefId) + -> Vec { + self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).generics_object_lifetime_defaults(def.index) + } + fn item_attrs(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 101531b52afb8..dd44ef202dc27 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -20,6 +20,7 @@ use rustc::middle::cstore::LinkagePreference; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::middle::lang_items; +use rustc::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; @@ -598,7 +599,26 @@ impl<'a, 'tcx> CrateMetadata { item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Generics<'tcx> { - self.entry(item_id).generics.unwrap().decode((self, tcx)) + let g = self.entry(item_id).generics.unwrap().decode(self); + ty::Generics { + parent: g.parent, + parent_regions: g.parent_regions, + parent_types: g.parent_types, + regions: g.regions.decode((self, tcx)).collect(), + types: g.types.decode((self, tcx)).collect(), + has_self: g.has_self, + } + } + + pub fn generics_own_param_counts(&self, item_id: DefIndex) -> (usize, usize) { + let g = self.entry(item_id).generics.unwrap().decode(self); + (g.regions.len, g.types.len) + } + + pub fn generics_object_lifetime_defaults(&self, item_id: DefIndex) + -> Vec { + self.entry(item_id).generics.unwrap().decode(self) + .object_lifetime_defaults.decode(self).collect() } pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 2f71776ecf758..b9c2f0622b698 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -396,10 +396,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let struct_id = tcx.hir.as_local_node_id(adt_def_id).unwrap(); let struct_vis = &tcx.hir.expect_item(struct_id).vis; + let mut ctor_vis = ty::Visibility::from_hir(struct_vis, struct_id, tcx); + for field in &variant.fields { + if ctor_vis.is_at_least(field.vis, tcx) { + ctor_vis = field.vis; + } + } Entry { kind: EntryKind::Struct(self.lazy(&data)), - visibility: self.lazy(&ty::Visibility::from_hir(struct_vis, struct_id, tcx)), + visibility: self.lazy(&ctor_vis), span: self.lazy(&tcx.def_span(def_id)), attributes: LazySeq::empty(), children: LazySeq::empty(), @@ -417,9 +423,26 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_generics(&mut self, def_id: DefId) -> Lazy> { + fn encode_generics(&mut self, def_id: DefId) -> Lazy> { let tcx = self.tcx; - self.lazy(tcx.item_generics(def_id)) + let g = tcx.item_generics(def_id); + let regions = self.lazy_seq_ref(&g.regions); + let types = self.lazy_seq_ref(&g.types); + let mut object_lifetime_defaults = LazySeq::empty(); + if let Some(id) = tcx.hir.as_local_node_id(def_id) { + if let Some(o) = tcx.named_region_map.object_lifetime_defaults.get(&id) { + object_lifetime_defaults = self.lazy_seq_ref(o); + } + } + self.lazy(&Generics { + parent: g.parent, + parent_regions: g.parent_regions, + parent_types: g.parent_types, + regions: regions, + types: types, + has_self: g.has_self, + object_lifetime_defaults: object_lifetime_defaults, + }) } fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 74825a5c6e3f6..d9c639f2bc573 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -16,6 +16,7 @@ use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary}; use rustc::middle::lang_items; +use rustc::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc::mir; use rustc::ty::{self, Ty}; use rustc_back::PanicStrategy; @@ -213,7 +214,7 @@ pub struct Entry<'tcx> { pub ty: Option>>, pub inherent_impls: LazySeq, pub variances: LazySeq, - pub generics: Option>>, + pub generics: Option>>, pub predicates: Option>>, pub ast: Option>>, @@ -247,6 +248,20 @@ pub enum EntryKind<'tcx> { AssociatedConst(AssociatedContainer), } +/// A copy of `ty::Generics` which allows lazy decoding of +/// `regions` and `types` (e.g. knowing the number of type +/// and lifetime parameters before `TyCtxt` is created). +#[derive(RustcEncodable, RustcDecodable)] +pub struct Generics<'tcx> { + pub parent: Option, + pub parent_regions: u32, + pub parent_types: u32, + pub regions: LazySeq, + pub types: LazySeq>, + pub has_self: bool, + pub object_lifetime_defaults: LazySeq, +} + #[derive(RustcEncodable, RustcDecodable)] pub struct ModData { pub reexports: LazySeq, diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 73d3875ba2384..121d592da0316 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -16,8 +16,6 @@ use rustc::hir; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn ast_block(&mut self, destination: &Lvalue<'tcx>, - // FIXME(#32959): temporary measure for the issue - dest_is_unit: bool, mut block: BasicBlock, ast_block: &'tcx hir::Block) -> BlockAnd<()> { @@ -83,8 +81,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // of the block. if let Some(expr) = expr { unpack!(block = this.into(destination, block, expr)); - } else if dest_is_unit { - // FIXME(#31472) + } else { let source_info = this.source_info(span); this.cfg.push_assign_unit(block, source_info, destination); } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 24b9c955658fd..3d4af259ec9f7 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -40,7 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { this.in_scope(extent, block, |this| this.into(destination, block, value)) } ExprKind::Block { body: ast_block } => { - this.ast_block(destination, expr.ty.is_nil(), block, ast_block) + this.ast_block(destination, block, ast_block) } ExprKind::Match { discriminant, arms } => { this.match_expr(destination, expr_span, block, discriminant, arms) diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index b071834122367..e94d35195c213 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -99,20 +99,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { - let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { - i == variant_index || { - let mut visited = FxHashSet::default(); - let node_set = v.uninhabited_from(&mut visited, - self.hir.tcx(), - substs, - adt_def.adt_kind()); - !node_set.is_empty() + if self.hir.tcx().sess.features.borrow().never_type { + let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { + i == variant_index || { + let mut visited = FxHashSet::default(); + let node_set = v.uninhabited_from(&mut visited, + self.hir.tcx(), + substs, + adt_def.adt_kind()); + !node_set.is_empty() + } + }); + if irrefutable { + let lvalue = match_pair.lvalue.downcast(adt_def, variant_index); + candidate.match_pairs.extend(self.field_match_pairs(lvalue, subpatterns)); + Ok(()) + } else { + Err(match_pair) } - }); - if irrefutable { - let lvalue = match_pair.lvalue.downcast(adt_def, variant_index); - candidate.match_pairs.extend(self.field_match_pairs(lvalue, subpatterns)); - Ok(()) } else { Err(match_pair) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 477a1086e815e..7eaf1fe139865 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -663,7 +663,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprCast(ref source, _) => { // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). - if let Some(&TyCastKind::CoercionCast) = cx.tcx.cast_kinds.borrow().get(&source.id) { + if let Some(&TyCastKind::CoercionCast) = cx.tables().cast_kinds.get(&source.id) { // Convert the lexpr to a vexpr. ExprKind::Use { source: source.to_ref() } } else { diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index bfe3e143e7c50..35734dcce2beb 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -92,7 +92,7 @@ pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>, where I: Iterator, 'tcx: 'a { let mut first = true; - for def_id in iter { + for def_id in iter.filter(DefId::is_local) { let mir = &tcx.item_mir(def_id); if first { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index af9f7fb578138..9c1107344f241 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -350,7 +350,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { base: Lvalue::Local(index), elem: ProjectionElem::Deref }) if self.mir.local_kind(index) == LocalKind::Temp - && self.mir.local_decls[index].ty.is_unique() + && self.mir.local_decls[index].ty.is_box() && self.temp_qualif[index].map_or(false, |qualif| { qualif.intersects(Qualif::NOT_CONST) }) => { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 0fabbe6678ad8..c9195f29f1784 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -580,9 +580,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { return; } - let arg_ty = match args[0].ty(mir, self.tcx()).sty { + let ty = args[0].ty(mir, self.tcx()); + let arg_ty = match ty.sty { ty::TyRawPtr(mt) => mt.ty, - ty::TyBox(ty) => ty, + ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(), _ => { span_mirbug!(self, term, "box_free called with bad arg ty"); return; diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index b7b027102b2af..0933fdfd357cd 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -144,8 +144,25 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } TyKind::TraitObject(ref bounds) => { + let mut any_lifetime_bounds = false; + for bound in bounds { + if let RegionTyParamBound(ref lifetime) = *bound { + if any_lifetime_bounds { + span_err!(self.session, lifetime.span, E0226, + "only a single explicit lifetime bound is permitted"); + break; + } + any_lifetime_bounds = true; + } + } self.no_questions_in_bounds(bounds, "trait object types", false); } + TyKind::ImplTrait(ref bounds) => { + if !bounds.iter() + .any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) { + self.err_handler().span_err(ty.span, "at least one trait must be specified"); + } + } _ => {} } @@ -284,6 +301,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_vis(self, vis) } + + fn visit_generics(&mut self, g: &'a Generics) { + let mut seen_default = None; + for ty_param in &g.ty_params { + if ty_param.default.is_some() { + seen_default = Some(ty_param.span); + } else if let Some(span) = seen_default { + self.err_handler() + .span_err(span, "type parameters with a default must be trailing"); + break + } + } + for predicate in &g.where_clause.predicates { + if let WherePredicate::EqPredicate(ref predicate) = *predicate { + self.err_handler().span_err(predicate.span, "equality constraints are not yet \ + supported in where clauses (#20041)"); + } + } + visit::walk_generics(self, g) + } } pub fn check_crate(session: &Session, krate: &Crate) { diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index b6241c618df2f..0b55513f8318c 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -314,7 +314,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } hir::ExprCast(ref from, _) => { debug!("Checking const cast(id={})", from.id); - match v.tcx.cast_kinds.borrow().get(&from.id) { + match v.tables.cast_kinds.get(&from.id) { None => span_bug!(e.span, "no kind for cast"), Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => { v.promotable = false; diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index c414d71836818..ef871959176af 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -244,6 +244,7 @@ match 5u32 { } register_diagnostics! { + E0226, // only a single explicit lifetime bound is permitted E0472, // asm! is unsupported on this target E0561, // patterns aren't allowed in function pointer types E0571, // `break` with a value in a non-`loop`-loop diff --git a/src/librustc_privacy/diagnostics.rs b/src/librustc_privacy/diagnostics.rs index 66afe5835bf6f..49f2ccb7c57f5 100644 --- a/src/librustc_privacy/diagnostics.rs +++ b/src/librustc_privacy/diagnostics.rs @@ -115,45 +115,6 @@ pub enum Foo { ``` "##, -E0450: r##" -A tuple constructor was invoked while some of its fields are private. Erroneous -code example: - -```compile_fail,E0450 -mod Bar { - pub struct Foo(isize); -} - -let f = Bar::Foo(0); // error: cannot invoke tuple struct constructor with - // private fields -``` - -To solve this issue, please ensure that all of the fields of the tuple struct -are public. Alternatively, provide a `new()` method to the tuple struct to -construct it from a given inner value. Example: - -``` -mod Bar { - pub struct Foo(pub isize); // we set its field to public -} - -let f = Bar::Foo(0); // ok! - -// or: -mod bar { - pub struct Foo(isize); - - impl Foo { - pub fn new(x: isize) -> Foo { - Foo(x) - } - } -} - -let f = bar::Foo::new(1); -``` -"##, - E0451: r##" A struct constructor with private fields was invoked. Erroneous code example: @@ -204,3 +165,7 @@ let f = Bar::Foo::new(); // ok! "##, } + +register_diagnostics! { +// E0450, moved into resolve +} diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 7357d6f38b651..9dc94745cff7b 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -27,7 +27,7 @@ extern crate syntax_pos; use rustc::dep_graph::DepNode; use rustc::hir::{self, PatKind}; -use rustc::hir::def::{self, Def, CtorKind}; +use rustc::hir::def::{self, Def}; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::DeepVisitor; @@ -478,33 +478,6 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> { } } } - hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { - if let Def::StructCtor(_, CtorKind::Fn) = path.def { - let adt_def = self.tcx.expect_variant_def(path.def); - let private_indexes = adt_def.fields.iter().enumerate().filter(|&(_, field)| { - !field.vis.is_accessible_from(self.curitem, self.tcx) - }).map(|(i, _)| i).collect::>(); - - if !private_indexes.is_empty() { - let mut error = struct_span_err!(self.tcx.sess, expr.span, E0450, - "cannot invoke tuple struct constructor \ - with private fields"); - error.span_label(expr.span, - &format!("cannot construct with a private field")); - - if let Some(node_id) = self.tcx.hir.as_local_node_id(adt_def.did) { - let node = self.tcx.hir.find(node_id); - if let Some(hir::map::NodeStructCtor(vdata)) = node { - for i in private_indexes { - error.span_label(vdata.fields()[i].span, - &format!("private field declared here")); - } - } - } - error.emit(); - } - } - } _ => {} } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f74af416cde09..eb6c7f4bed5de 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -327,21 +327,26 @@ impl<'a> Resolver<'a> { let def = Def::Struct(self.definitions.local_def_id(item.id)); self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); - // If this is a tuple or unit struct, define a name - // in the value namespace as well. - if !struct_def.is_struct() { - let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), - CtorKind::from_ast(struct_def)); - self.define(parent, ident, ValueNS, (ctor_def, vis, sp, expansion)); - } - // Record field names for error reporting. + let mut ctor_vis = vis; let field_names = struct_def.fields().iter().filter_map(|field| { - self.resolve_visibility(&field.vis); + let field_vis = self.resolve_visibility(&field.vis); + if ctor_vis.is_at_least(field_vis, &*self) { + ctor_vis = field_vis; + } field.ident.map(|ident| ident.name) }).collect(); let item_def_id = self.definitions.local_def_id(item.id); self.insert_field_names(item_def_id, field_names); + + // If this is a tuple or unit struct, define a name + // in the value namespace as well. + if !struct_def.is_struct() { + let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), + CtorKind::from_ast(struct_def)); + self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, sp, expansion)); + self.struct_constructors.insert(def.def_id(), (ctor_def, ctor_vis)); + } } ItemKind::Union(ref vdata, _) => { @@ -434,9 +439,17 @@ impl<'a> Resolver<'a> { Def::Variant(..) | Def::TyAlias(..) => { self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root())); } - Def::Fn(..) | Def::Static(..) | Def::Const(..) | - Def::VariantCtor(..) | Def::StructCtor(..) => { + Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => { + self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root())); + } + Def::StructCtor(..) => { self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root())); + + if let Some(struct_def_id) = + self.session.cstore.def_key(def_id).parent + .map(|index| DefId { krate: def_id.krate, index: index }) { + self.struct_constructors.insert(struct_def_id, (def, vis)); + } } Def::Trait(..) => { let module_kind = ModuleKind::Def(def, ident.name); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b5e2715ab4f0b..676ff98e602d6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -45,7 +45,7 @@ use rustc::hir::def::*; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; -use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet}; +use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy}; @@ -1131,6 +1131,10 @@ pub struct Resolver<'a> { warned_proc_macros: FxHashSet, potentially_unused_imports: Vec<&'a ImportDirective<'a>>, + + // This table maps struct IDs into struct constructor IDs, + // it's not used during normal resolution, only for better error reporting. + struct_constructors: DefIdMap<(Def, ty::Visibility)>, } pub struct ResolverArenas<'a> { @@ -1310,6 +1314,7 @@ impl<'a> Resolver<'a> { proc_macro_enabled: features.proc_macro, warned_proc_macros: FxHashSet(), potentially_unused_imports: Vec::new(), + struct_constructors: DefIdMap(), } } @@ -2205,6 +2210,15 @@ impl<'a> Resolver<'a> { _ => {} }, _ if ns == ValueNS && is_struct_like(def) => { + if let Def::Struct(def_id) = def { + if let Some((ctor_def, ctor_vis)) + = this.struct_constructors.get(&def_id).cloned() { + if is_expected(ctor_def) && !this.is_accessible(ctor_vis) { + err.span_label(span, &format!("constructor is not visible \ + here due to private fields")); + } + } + } err.span_label(span, &format!("did you mean `{} {{ /* fields */ }}`?", path_str)); return err; @@ -2235,7 +2249,23 @@ impl<'a> Resolver<'a> { if is_expected(resolution.base_def) || resolution.base_def == Def::Err { resolution } else { - report_errors(self, Some(resolution.base_def)) + // Add a temporary hack to smooth the transition to new struct ctor + // visibility rules. See #38932 for more details. + let mut res = None; + if let Def::Struct(def_id) = resolution.base_def { + if let Some((ctor_def, ctor_vis)) + = self.struct_constructors.get(&def_id).cloned() { + if is_expected(ctor_def) && self.is_accessible(ctor_vis) { + let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY; + self.session.add_lint(lint, id, span, + "private struct constructors are not usable through \ + reexports in outer modules".to_string()); + res = Some(PathResolution::new(ctor_def)); + } + } + } + + res.unwrap_or_else(|| report_errors(self, Some(resolution.base_def))) } } Some(resolution) if source.defer_to_typeck() => { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 74521fe465bcd..f128167bbf621 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -111,11 +111,16 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { fn nest_tables(&mut self, item_id: NodeId, f: F) where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>) { - let old_tables = self.save_ctxt.tables; let item_def_id = self.tcx.hir.local_def_id(item_id); - self.save_ctxt.tables = self.tcx.item_tables(item_def_id); - f(self); - self.save_ctxt.tables = old_tables; + match self.tcx.tables.borrow().get(&item_def_id) { + Some(tables) => { + let old_tables = self.save_ctxt.tables; + self.save_ctxt.tables = tables; + f(self); + self.save_ctxt.tables = old_tables; + } + None => f(self), + } } pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) { diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 577744653f09b..d392ebaa33d42 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -429,7 +429,7 @@ impl FnType { if !type_is_fat_ptr(ccx, ret_ty) { // The `noalias` attribute on the return value is useful to a // function ptr caller. - if let ty::TyBox(_) = ret_ty.sty { + if ret_ty.is_box() { // `Box` pointer return values never alias because ownership // is transferred ret.attrs.set(ArgAttribute::NoAlias); @@ -438,12 +438,16 @@ impl FnType { // We can also mark the return value as `dereferenceable` in certain cases match ret_ty.sty { // These are not really pointers but pairs, (pointer, len) - ty::TyRef(_, ty::TypeAndMut { ty, .. }) | - ty::TyBox(ty) => { + ty::TyRef(_, ty::TypeAndMut { ty, .. }) => { let llty = type_of::sizing_type_of(ccx, ty); let llsz = llsize_of_alloc(ccx, llty); ret.attrs.set_dereferenceable(llsz); } + ty::TyAdt(def, _) if def.is_box() => { + let llty = type_of::sizing_type_of(ccx, ret_ty.boxed_ty()); + let llsz = llsize_of_alloc(ccx, llty); + ret.attrs.set_dereferenceable(llsz); + } _ => {} } } @@ -453,9 +457,9 @@ impl FnType { // Handle safe Rust thin and fat pointers. let rust_ptr_attrs = |ty: Ty<'tcx>, arg: &mut ArgType| match ty.sty { // `Box` pointer parameters never alias because ownership is transferred - ty::TyBox(inner) => { + ty::TyAdt(def, _) if def.is_box() => { arg.attrs.set(ArgAttribute::NoAlias); - Some(inner) + Some(ty.boxed_ty()) } ty::TyRef(b, mt) => { diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 81be2d02f125b..bea3ca8df70e0 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -81,11 +81,25 @@ impl ExportedSymbols { for cnum in scx.sess().cstore.crates() { debug_assert!(cnum != LOCAL_CRATE); + // If this crate is a plugin and/or a custom derive crate, then + // we're not even going to link those in so we skip those crates. if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() || scx.sess().cstore.derive_registrar_fn(cnum).is_some() { continue; } + // Check to see if this crate is a "special runtime crate". These + // crates, implementation details of the standard library, typically + // have a bunch of `pub extern` and `#[no_mangle]` functions as the + // ABI between them. We don't want their symbols to have a `C` + // export level, however, as they're just implementation details. + // Down below we'll hardwire all of the symbols to the `Rust` export + // level instead. + let special_runtime_crate = + scx.sess().cstore.is_allocator(cnum) || + scx.sess().cstore.is_panic_runtime(cnum) || + scx.sess().cstore.is_compiler_builtins(cnum); + let crate_exports = scx .sess() .cstore @@ -93,7 +107,24 @@ impl ExportedSymbols { .iter() .map(|&def_id| { let name = Instance::mono(scx, def_id).symbol_name(scx); - let export_level = export_level(scx, def_id); + let export_level = if special_runtime_crate { + // We can probably do better here by just ensuring that + // it has hidden visibility rather than public + // visibility, as this is primarily here to ensure it's + // not stripped during LTO. + // + // In general though we won't link right if these + // symbols are stripped, and LTO currently strips them. + if name == "rust_eh_personality" || + name == "rust_eh_register_frames" || + name == "rust_eh_unregister_frames" { + SymbolExportLevel::C + } else { + SymbolExportLevel::Rust + } + } else { + export_level(scx, def_id) + }; debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level); (name, export_level) }) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 32fe3effcc9f8..9bd19d5bbb3e4 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -227,7 +227,6 @@ pub fn unsize_thin_ptr<'a, 'tcx>( ) -> (ValueRef, ValueRef) { debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); match (&src_ty.sty, &dst_ty.sty) { - (&ty::TyBox(a), &ty::TyBox(b)) | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), @@ -238,6 +237,12 @@ pub fn unsize_thin_ptr<'a, 'tcx>( let ptr_ty = type_of::in_memory_type_of(bcx.ccx, b).ptr_to(); (bcx.pointercast(src, ptr_ty), unsized_info(bcx.ccx, a, b, None)) } + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { + let (a, b) = (src_ty.boxed_ty(), dst_ty.boxed_ty()); + assert!(bcx.ccx.shared().type_is_sized(a)); + let ptr_ty = type_of::in_memory_type_of(bcx.ccx, b).ptr_to(); + (bcx.pointercast(src, ptr_ty), unsized_info(bcx.ccx, a, b, None)) + } _ => bug!("unsize_thin_ptr: called on bad types"), } } @@ -249,25 +254,30 @@ pub fn coerce_unsized_into<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, src_ty: Ty<'tcx>, dst: ValueRef, dst_ty: Ty<'tcx>) { + let coerce_ptr = || { + let (base, info) = if common::type_is_fat_ptr(bcx.ccx, src_ty) { + // fat-ptr to fat-ptr unsize preserves the vtable + // i.e. &'a fmt::Debug+Send => &'a fmt::Debug + // So we need to pointercast the base to ensure + // the types match up. + let (base, info) = load_fat_ptr(bcx, src, src_ty); + let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx, dst_ty); + let base = bcx.pointercast(base, llcast_ty); + (base, info) + } else { + let base = load_ty(bcx, src, src_ty); + unsize_thin_ptr(bcx, base, src_ty, dst_ty) + }; + store_fat_ptr(bcx, base, info, dst, dst_ty); + }; match (&src_ty.sty, &dst_ty.sty) { - (&ty::TyBox(..), &ty::TyBox(..)) | (&ty::TyRef(..), &ty::TyRef(..)) | (&ty::TyRef(..), &ty::TyRawPtr(..)) | (&ty::TyRawPtr(..), &ty::TyRawPtr(..)) => { - let (base, info) = if common::type_is_fat_ptr(bcx.ccx, src_ty) { - // fat-ptr to fat-ptr unsize preserves the vtable - // i.e. &'a fmt::Debug+Send => &'a fmt::Debug - // So we need to pointercast the base to ensure - // the types match up. - let (base, info) = load_fat_ptr(bcx, src, src_ty); - let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx, dst_ty); - let base = bcx.pointercast(base, llcast_ty); - (base, info) - } else { - let base = load_ty(bcx, src, src_ty); - unsize_thin_ptr(bcx, base, src_ty, dst_ty) - }; - store_fat_ptr(bcx, base, info, dst, dst_ty); + coerce_ptr() + } + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { + coerce_ptr() } (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) => { @@ -414,7 +424,7 @@ pub fn load_ty<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> V // a char is a Unicode codepoint, and so takes values from 0 // to 0x10FFFF inclusive only. b.load_range_assert(ptr, 0, 0x10FFFF + 1, llvm::False) - } else if (t.is_region_ptr() || t.is_unique()) && !common::type_is_fat_ptr(ccx, t) { + } else if (t.is_region_ptr() || t.is_box()) && !common::type_is_fat_ptr(ccx, t) { b.load_nonnull(ptr) } else { b.load(ptr) @@ -449,7 +459,7 @@ pub fn load_fat_ptr<'a, 'tcx>( b: &Builder<'a, 'tcx>, src: ValueRef, t: Ty<'tcx> ) -> (ValueRef, ValueRef) { let ptr = get_dataptr(b, src); - let ptr = if t.is_region_ptr() || t.is_unique() { + let ptr = if t.is_region_ptr() || t.is_box() { b.load_nonnull(ptr) } else { b.load(ptr) diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index cf7f3e9501d1a..c113716ca5c74 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -1107,7 +1107,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn set_personality_fn(&self, personality: ValueRef) { unsafe { - llvm::LLVMRustSetPersonalityFn(self.llbuilder, personality); + llvm::LLVMSetPersonalityFn(self.llfn(), personality); } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index d30766dc5392a..392c270c130a8 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -52,7 +52,7 @@ //! the LLVM artifact produced for A references the LLVM artifact produced //! for B. //! -//! - Translation items and the references between them for a directed graph, +//! - Translation items and the references between them form a directed graph, //! where the translation items are the nodes and references form the edges. //! Let's call this graph the "translation item graph". //! @@ -721,14 +721,13 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, debug!("find_drop_glue_neighbors: {}", type_to_string(scx.tcx(), ty)); // Make sure the BoxFreeFn lang-item gets translated if there is a boxed value. - if let ty::TyBox(content_type) = ty.sty { + if ty.is_box() { let def_id = scx.tcx().require_lang_item(BoxFreeFnLangItem); - if should_trans_locally(scx.tcx(), def_id) { let box_free_fn_trans_item = create_fn_trans_item(scx, def_id, - scx.tcx().mk_substs(iter::once(Kind::from(content_type))), + scx.tcx().mk_substs(iter::once(Kind::from(ty.boxed_ty()))), scx.tcx().intern_substs(&[])); output.push(box_free_fn_trans_item); } @@ -741,7 +740,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, _ => None }; - if let Some(destructor_did) = destructor_did { + if let (Some(destructor_did), false) = (destructor_did, ty.is_box()) { use rustc::ty::ToPolyTraitRef; let drop_trait_def_id = scx.tcx() @@ -790,8 +789,14 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, ty::TyDynamic(..) => { /* nothing to do */ } - ty::TyAdt(adt_def, substs) => { - for field in adt_def.all_fields() { + ty::TyAdt(def, _) if def.is_box() => { + let inner_type = glue::get_drop_glue_type(scx, ty.boxed_ty()); + if scx.type_needs_drop(inner_type) { + output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type))); + } + } + ty::TyAdt(def, substs) => { + for field in def.all_fields() { let field_type = scx.tcx().item_type(field.did); let field_type = monomorphize::apply_param_substs(scx, substs, @@ -811,7 +816,6 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } } - ty::TyBox(inner_type) | ty::TySlice(inner_type) | ty::TyArray(inner_type, _) => { let inner_type = glue::get_drop_glue_type(scx, inner_type); @@ -1008,21 +1012,24 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, source_ty: ty::Ty<'tcx>, target_ty: ty::Ty<'tcx>) -> (ty::Ty<'tcx>, ty::Ty<'tcx>) { + let ptr_vtable = |inner_source: ty::Ty<'tcx>, inner_target: ty::Ty<'tcx>| { + if !scx.type_is_sized(inner_source) { + (inner_source, inner_target) + } else { + scx.tcx().struct_lockstep_tails(inner_source, inner_target) + } + }; match (&source_ty.sty, &target_ty.sty) { - (&ty::TyBox(a), &ty::TyBox(b)) | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) | (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) | (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }), &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => { - let (inner_source, inner_target) = (a, b); - - if !scx.type_is_sized(inner_source) { - (inner_source, inner_target) - } else { - scx.tcx().struct_lockstep_tails(inner_source, inner_target) - } + ptr_vtable(a, b) + } + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => { + ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) } (&ty::TyAdt(source_adt_def, source_substs), diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 419267cb269c9..0ba94fdfe635c 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -234,7 +234,8 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { pub fn C_big_integral(t: Type, u: u128, sign_extend: bool) -> ValueRef { if ::std::mem::size_of::() == 16 { unsafe { - llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, &u as *const u128 as *const u64) + let words = [u as u64, u.wrapping_shr(64) as u64]; + llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, words.as_ptr()) } } else { // SNAP: remove after snapshot diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 0de3c13dc21a9..b7e319f2de434 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -490,6 +490,35 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, debug!("type_metadata: {:?}", t); let sty = &t.sty; + let ptr_metadata = |ty: Ty<'tcx>| { + match ty.sty { + ty::TySlice(typ) => { + Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)) + } + ty::TyStr => { + Ok(vec_slice_metadata(cx, t, cx.tcx().types.u8, unique_type_id, usage_site_span)) + } + ty::TyDynamic(..) => { + Ok(MetadataCreationResult::new( + trait_pointer_metadata(cx, ty, Some(t), unique_type_id), + false)) + } + _ => { + let pointee_metadata = type_metadata(cx, ty, usage_site_span); + + match debug_context(cx).type_map + .borrow() + .find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => return Err(metadata), + None => { /* proceed normally */ } + }; + + Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), + false)) + } + } + }; + let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty { ty::TyNever | ty::TyBool | @@ -516,34 +545,17 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, trait_pointer_metadata(cx, t, None, unique_type_id), false) } - ty::TyBox(ty) | ty::TyRawPtr(ty::TypeAndMut{ty, ..}) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) => { - match ty.sty { - ty::TySlice(typ) => { - vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span) - } - ty::TyStr => { - vec_slice_metadata(cx, t, cx.tcx().types.u8, unique_type_id, usage_site_span) - } - ty::TyDynamic(..) => { - MetadataCreationResult::new( - trait_pointer_metadata(cx, ty, Some(t), unique_type_id), - false) - } - _ => { - let pointee_metadata = type_metadata(cx, ty, usage_site_span); - - match debug_context(cx).type_map - .borrow() - .find_metadata_for_unique_id(unique_type_id) { - Some(metadata) => return metadata, - None => { /* proceed normally */ } - }; - - MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), - false) - } + match ptr_metadata(ty) { + Ok(res) => res, + Err(metadata) => return metadata, + } + } + ty::TyAdt(def, _) if def.is_box() => { + match ptr_metadata(t.boxed_ty()) { + Ok(res) => res, + Err(metadata) => return metadata, } } ty::TyFnDef(.., ref barefnty) | ty::TyFnPtr(ref barefnty) => { diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index f05d48566daae..e9468e56637d2 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -400,7 +400,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g. `<*mut T>::null`). match impl_self_ty.sty { - ty::TyAdt(..) => { + ty::TyAdt(def, ..) if !def.is_box() => { Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) } _ => None diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 788ce32937d84..8e11bf6b8976a 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -60,11 +60,6 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } output.push(')'); }, - ty::TyBox(inner_type) => { - output.push_str("Box<"); - push_debuginfo_type_name(cx, inner_type, true, output); - output.push('>'); - }, ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { output.push('*'); match mutbl { diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 3ee2497009f65..8d634c0e292ad 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -60,8 +60,7 @@ pub fn bytes_to_bits(bytes: u64) -> u64 { #[inline] pub fn debug_context<'a, 'tcx>(cx: &'a CrateContext<'a, 'tcx>) -> &'a CrateDebugContext<'tcx> { - let debug_context: &'a CrateDebugContext<'tcx> = cx.dbg_cx().as_ref().unwrap(); - debug_context + cx.dbg_cx().as_ref().unwrap() } #[inline] diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index b24f00ee6976d..1415ca6029f53 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -79,16 +79,21 @@ pub fn get_drop_glue_type<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'t return scx.tcx().types.i8; } match t.sty { - ty::TyBox(typ) if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) => { - scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { - let layout = t.layout(&infcx).unwrap(); - if layout.size(&scx.tcx().data_layout).bytes() == 0 { - // `Box` does not allocate. - scx.tcx().types.i8 - } else { - t - } - }) + ty::TyAdt(def, _) if def.is_box() => { + let typ = t.boxed_ty(); + if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) { + scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| { + let layout = t.layout(&infcx).unwrap(); + if layout.size(&scx.tcx().data_layout).bytes() == 0 { + // `Box` does not allocate. + scx.tcx().types.i8 + } else { + t + } + }) + } else { + t + } } _ => t } @@ -205,11 +210,11 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi }; let bcx = match t.sty { - ty::TyBox(content_ty) => { - // Support for TyBox is built-in and its drop glue is - // special. It may move to library and have Drop impl. As - // a safe-guard, assert TyBox not used with TyContents. + ty::TyAdt(def, _) if def.is_box() => { + // Support for Box is built-in as yet and its drop glue is special + // despite having a dummy Drop impl in the library. assert!(!skip_dtor); + let content_ty = t.boxed_ty(); let ptr = if !bcx.ccx.shared().type_is_sized(content_ty) { let llbox = bcx.load(get_dataptr(&bcx, ptr.llval)); let info = bcx.load(get_meta(&bcx, ptr.llval)); @@ -230,7 +235,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi bcx.call(dtor, &[ptr.llval], None); bcx } - ty::TyAdt(def, ..) if def.dtor_kind().is_present() && !skip_dtor => { + ty::TyAdt(def, ..) if def.has_dtor() && !skip_dtor => { let shallow_drop = def.is_union(); let tcx = bcx.tcx(); diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 8df24da713588..2a1ab10d74e16 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -30,7 +30,7 @@ pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector { let ty = mircx.monomorphize(&ty); debug!("local {} has type {:?}", index, ty); if ty.is_scalar() || - ty.is_unique() || + ty.is_box() || ty.is_region_ptr() || ty.is_simd() || common::type_is_zero_size(mircx.ccx, ty) diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index eedd7956805b6..30c138310da9c 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -319,7 +319,9 @@ pub fn trans_mir<'a, 'tcx: 'a>( mircx.cleanup_kinds.iter_enumerated().map(|(bb, cleanup_kind)| { if let CleanupKind::Funclet = *cleanup_kind { let bcx = mircx.get_builder(bb); - bcx.set_personality_fn(mircx.ccx.eh_personality()); + unsafe { + llvm::LLVMSetPersonalityFn(mircx.llfn, mircx.ccx.eh_personality()); + } if base::wants_msvc_seh(ccx.sess()) { return Some(Funclet::new(bcx.cleanup_pad(None, &[]))); } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 43ea1e56a5a4d..d58a93e3cb71c 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -421,11 +421,6 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { } output.push(')'); }, - ty::TyBox(inner_type) => { - output.push_str("Box<"); - self.push_type_name(inner_type, output); - output.push('>'); - }, ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { output.push('*'); match mutbl { diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 469214b466e1a..4df0e989ada99 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -38,6 +38,13 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ debug!("sizing_type_of {:?}", t); let _recursion_lock = cx.enter_type_of(t); + let ptr_sizing_ty = |ty: Ty<'tcx>| { + if cx.shared().type_is_sized(ty) { + Type::i8p(cx) + } else { + Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false) + } + }; let llsizingty = match t.sty { _ if !cx.shared().type_is_sized(t) => { Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, t)], false) @@ -50,14 +57,12 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ ty::TyFloat(t) => Type::float_from_ty(cx, t), ty::TyNever => Type::nil(cx), - ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) | ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => { - if cx.shared().type_is_sized(ty) { - Type::i8p(cx) - } else { - Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false) - } + ptr_sizing_ty(ty) + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_sizing_ty(t.boxed_ty()) } ty::TyFnDef(..) => Type::nil(cx), @@ -131,11 +136,13 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { match ty.sty { - ty::TyBox(t) | ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) | ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if !ccx.shared().type_is_sized(t) => { in_memory_type_of(ccx, t).ptr_to() } + ty::TyAdt(def, _) if def.is_box() => { + in_memory_type_of(ccx, ty.boxed_ty()).ptr_to() + } _ => bug!("expected fat ptr ty but got {:?}", ty) } } @@ -214,6 +221,22 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> return llty; } + let ptr_ty = |ty: Ty<'tcx>| { + if !cx.shared().type_is_sized(ty) { + if let ty::TyStr = ty.sty { + // This means we get a nicer name in the output (str is always + // unsized). + cx.str_slice_type() + } else { + let ptr_ty = in_memory_type_of(cx, ty).ptr_to(); + let info_ty = unsized_info_ty(cx, ty); + Type::struct_(cx, &[ptr_ty, info_ty], false) + } + } else { + in_memory_type_of(cx, ty).ptr_to() + } + }; + let mut llty = match t.sty { ty::TyBool => Type::bool(cx), ty::TyChar => Type::char(cx), @@ -227,22 +250,12 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> adt::incomplete_type_of(cx, t, "closure") } - ty::TyBox(ty) | ty::TyRef(_, ty::TypeAndMut{ty, ..}) | ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => { - if !cx.shared().type_is_sized(ty) { - if let ty::TyStr = ty.sty { - // This means we get a nicer name in the output (str is always - // unsized). - cx.str_slice_type() - } else { - let ptr_ty = in_memory_type_of(cx, ty).ptr_to(); - let info_ty = unsized_info_ty(cx, ty); - Type::struct_(cx, &[ptr_ty, info_ty], false) - } - } else { - in_memory_type_of(cx, ty).ptr_to() - } + ptr_ty(ty) + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_ty(t.boxed_ty()) } ty::TyArray(ty, size) => { @@ -300,7 +313,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // If this was an enum or struct, fill in the type now. match t.sty { - ty::TyAdt(..) | ty::TyClosure(..) if !t.is_simd() => { + ty::TyAdt(..) | ty::TyClosure(..) if !t.is_simd() && !t.is_box() => { adt::finish_type_of(cx, t, &mut llty); } _ => () diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1af8b59cdfa7d..bb9a487802e7b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -10,7 +10,7 @@ //! Conversion from AST representation of types to the ty.rs //! representation. The main routine here is `ast_ty_to_ty()`: each use -//! is parameterized by an instance of `AstConv` and a `RegionScope`. +//! is parameterized by an instance of `AstConv`. //! //! The parameterization of `ast_ty_to_ty()` is because it behaves //! somewhat differently during the collect and check phases, @@ -22,31 +22,6 @@ //! an error). In the check phase, when the FnCtxt is used as the //! `AstConv`, `get_item_type()` just looks up the item type in //! `tcx.types` (using `TyCtxt::item_type`). -//! -//! The `RegionScope` trait controls what happens when the user does -//! not specify a region in some location where a region is required -//! (e.g., if the user writes `&Foo` as a type rather than `&'a Foo`). -//! See the `rscope` module for more details. -//! -//! Unlike the `AstConv` trait, the region scope can change as we descend -//! the type. This is to accommodate the fact that (a) fn types are binding -//! scopes and (b) the default region may change. To understand case (a), -//! consider something like: -//! -//! type foo = { x: &a.int, y: |&a.int| } -//! -//! The type of `x` is an error because there is no region `a` in scope. -//! In the type of `y`, however, region `a` is considered a bound region -//! as it does not already appear in scope. -//! -//! Case (b) says that if you have a type: -//! type foo<'a> = ...; -//! type bar = fn(&foo, &a.foo) -//! The fully expanded version of type bar is: -//! type bar = fn(&'foo &, &a.foo<'a>) -//! Note that the self region for the `foo` defaulted to `&` in the first -//! case but `&a` in the second. Basically, defaults that appear inside -//! an rptr (`&r.T`) use the region `r` that appears in the rptr. use rustc_const_eval::eval_length; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -61,10 +36,6 @@ use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; use rustc_back::slice; use require_c_abi_if_variadic; -use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, - ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope, - ElisionFailureInfo, ElidedLifetime}; -use rscope::{AnonTypeScope, MaybeWithAnonTypes}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::{NodeMap, FxHashSet}; @@ -74,7 +45,6 @@ use syntax::{abi, ast}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::symbol::{Symbol, keywords}; use syntax_pos::Span; -use errors::DiagnosticBuilder; pub trait AstConv<'gcx, 'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>; @@ -111,6 +81,10 @@ pub trait AstConv<'gcx, 'tcx> { /// See ParameterEnvironment::free_substs for more information. fn get_free_substs(&self) -> Option<&Substs<'tcx>>; + /// What lifetime should we use when a lifetime is omitted (and not elided)? + fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>) + -> Option<&'tcx ty::Region>; + /// What type should we use when a type is omitted? fn ty_infer(&self, span: Span) -> Ty<'tcx>; @@ -161,171 +135,71 @@ struct ConvertedBinding<'tcx> { /// This type must not appear anywhere in other converted types. const TRAIT_OBJECT_DUMMY_SELF: ty::TypeVariants<'static> = ty::TyInfer(ty::FreshTy(0)); -pub fn ast_region_to_region<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - lifetime: &hir::Lifetime) - -> &'tcx ty::Region { - let r = match tcx.named_region_map.defs.get(&lifetime.id) { - None => { - // should have been recorded by the `resolve_lifetime` pass - span_bug!(lifetime.span, "unresolved lifetime"); - } +impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { + pub fn ast_region_to_region(&self, + lifetime: &hir::Lifetime, + def: Option<&ty::RegionParameterDef>) + -> &'tcx ty::Region + { + let tcx = self.tcx(); + let r = match tcx.named_region_map.defs.get(&lifetime.id) { + Some(&rl::Region::Static) => { + tcx.mk_region(ty::ReStatic) + } - Some(&rl::DefStaticRegion) => { - ty::ReStatic - } + Some(&rl::Region::LateBound(debruijn, id)) => { + // If this region is declared on a function, it will have + // an entry in `late_bound`, but if it comes from + // `for<'a>` in some type or something, it won't + // necessarily have one. In that case though, we won't be + // changed from late to early bound, so we can just + // substitute false. + let issue_32330 = tcx.named_region_map + .late_bound + .get(&id) + .cloned() + .unwrap_or(ty::Issue32330::WontChange); + let name = tcx.hir.name(id); + tcx.mk_region(ty::ReLateBound(debruijn, + ty::BrNamed(tcx.hir.local_def_id(id), name, issue_32330))) + } - Some(&rl::DefLateBoundRegion(debruijn, id)) => { - // If this region is declared on a function, it will have - // an entry in `late_bound`, but if it comes from - // `for<'a>` in some type or something, it won't - // necessarily have one. In that case though, we won't be - // changed from late to early bound, so we can just - // substitute false. - let issue_32330 = tcx.named_region_map - .late_bound - .get(&id) - .cloned() - .unwrap_or(ty::Issue32330::WontChange); - ty::ReLateBound(debruijn, ty::BrNamed(tcx.hir.local_def_id(id), - lifetime.name, - issue_32330)) - } + Some(&rl::Region::LateBoundAnon(debruijn, index)) => { + tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(index))) + } - Some(&rl::DefEarlyBoundRegion(index, _)) => { - ty::ReEarlyBound(ty::EarlyBoundRegion { - index: index, - name: lifetime.name - }) - } + Some(&rl::Region::EarlyBound(index, id)) => { + let name = tcx.hir.name(id); + tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { + index: index, + name: name + })) + } - Some(&rl::DefFreeRegion(scope, id)) => { - // As in DefLateBoundRegion above, could be missing for some late-bound - // regions, but also for early-bound regions. - let issue_32330 = tcx.named_region_map - .late_bound - .get(&id) - .cloned() - .unwrap_or(ty::Issue32330::WontChange); - ty::ReFree(ty::FreeRegion { + Some(&rl::Region::Free(scope, id)) => { + // As in Region::LateBound above, could be missing for some late-bound + // regions, but also for early-bound regions. + let issue_32330 = tcx.named_region_map + .late_bound + .get(&id) + .cloned() + .unwrap_or(ty::Issue32330::WontChange); + let name = tcx.hir.name(id); + tcx.mk_region(ty::ReFree(ty::FreeRegion { scope: scope.to_code_extent(&tcx.region_maps), - bound_region: ty::BrNamed(tcx.hir.local_def_id(id), - lifetime.name, - issue_32330) - }) - - // (*) -- not late-bound, won't change - } - }; - - debug!("ast_region_to_region(lifetime={:?} id={}) yields {:?}", - lifetime, - lifetime.id, - r); + bound_region: ty::BrNamed(tcx.hir.local_def_id(id), name, issue_32330) + })) - tcx.mk_region(r) -} - -fn report_elision_failure( - tcx: TyCtxt, - db: &mut DiagnosticBuilder, - params: Vec) -{ - let mut m = String::new(); - let len = params.len(); - - let elided_params: Vec<_> = params.into_iter() - .filter(|info| info.lifetime_count > 0) - .collect(); - - let elided_len = elided_params.len(); - - for (i, info) in elided_params.into_iter().enumerate() { - let ElisionFailureInfo { - parent, index, lifetime_count: n, have_bound_regions - } = info; - - let help_name = if let Some(body) = parent { - let arg = &tcx.hir.body(body).arguments[index]; - format!("`{}`", tcx.hir.node_to_pretty_string(arg.pat.id)) - } else { - format!("argument {}", index + 1) - }; - - m.push_str(&(if n == 1 { - help_name - } else { - format!("one of {}'s {} elided {}lifetimes", help_name, n, - if have_bound_regions { "free " } else { "" } ) - })[..]); - - if elided_len == 2 && i == 0 { - m.push_str(" or "); - } else if i + 2 == elided_len { - m.push_str(", or "); - } else if i != elided_len - 1 { - m.push_str(", "); - } - - } - - if len == 0 { - help!(db, - "this function's return type contains a borrowed value, but \ - there is no value for it to be borrowed from"); - help!(db, - "consider giving it a 'static lifetime"); - } else if elided_len == 0 { - help!(db, - "this function's return type contains a borrowed value with \ - an elided lifetime, but the lifetime cannot be derived from \ - the arguments"); - help!(db, - "consider giving it an explicit bounded or 'static \ - lifetime"); - } else if elided_len == 1 { - help!(db, - "this function's return type contains a borrowed value, but \ - the signature does not say which {} it is borrowed from", - m); - } else { - help!(db, - "this function's return type contains a borrowed value, but \ - the signature does not say whether it is borrowed from {}", - m); - } -} - -impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { - pub fn opt_ast_region_to_region(&self, - rscope: &RegionScope, - default_span: Span, - opt_lifetime: &Option) -> &'tcx ty::Region - { - let r = match *opt_lifetime { - Some(ref lifetime) => { - ast_region_to_region(self.tcx(), lifetime) + // (*) -- not late-bound, won't change } - None => self.tcx().mk_region(match rscope.anon_regions(default_span, 1) { - Ok(rs) => rs[0], - Err(params) => { - let ampersand_span = Span { hi: default_span.lo, ..default_span}; - - let mut err = struct_span_err!(self.tcx().sess, ampersand_span, E0106, - "missing lifetime specifier"); - err.span_label(ampersand_span, &format!("expected lifetime parameter")); - - if let Some(params) = params { - report_elision_failure(self.tcx(), &mut err, params); - } - err.emit(); - ty::ReStatic - } - }) + None => { + self.re_infer(lifetime.span, def).expect("unelided lifetime in signature") + } }; - debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}", - opt_lifetime, + debug!("ast_region_to_region(lifetime={:?}) yields {:?}", + lifetime, r); r @@ -334,7 +208,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, /// returns an appropriate set of substitutions for this particular reference to `I`. pub fn ast_path_substs_for_ty(&self, - rscope: &RegionScope, span: Span, def_id: DefId, item_segment: &hir::PathSegment) @@ -359,8 +232,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } let (substs, assoc_bindings) = - self.create_substs_for_ast_path(rscope, - span, + self.create_substs_for_ast_path(span, def_id, &item_segment.parameters, None); @@ -376,7 +248,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// /// Note that the type listing given here is *exactly* what the user provided. fn create_substs_for_ast_path(&self, - rscope: &RegionScope, span: Span, def_id: DefId, parameters: &hir::PathParameters, @@ -409,23 +280,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }; let expected_num_region_params = decl_generics.regions.len(); let supplied_num_region_params = lifetimes.len(); - let regions = if expected_num_region_params == supplied_num_region_params { - lifetimes.iter().map(|l| *ast_region_to_region(tcx, l)).collect() - } else { - let anon_regions = - rscope.anon_regions(span, expected_num_region_params); - - if supplied_num_region_params != 0 || anon_regions.is_err() { - report_lifetime_number_error(tcx, span, - supplied_num_region_params, - expected_num_region_params); - } - - match anon_regions { - Ok(anon_regions) => anon_regions, - Err(_) => (0..expected_num_region_params).map(|_| ty::ReStatic).collect() - } - }; + if expected_num_region_params != supplied_num_region_params { + report_lifetime_number_error(tcx, span, + supplied_num_region_params, + expected_num_region_params); + } // If a self-type was declared, one should be provided. assert_eq!(decl_generics.has_self, self_ty.is_some()); @@ -452,7 +311,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut output_assoc_binding = None; let substs = Substs::for_item(tcx, def_id, |def, _| { let i = def.index as usize - self_ty.is_some() as usize; - tcx.mk_region(regions[i]) + if let Some(lifetime) = lifetimes.get(i) { + self.ast_region_to_region(lifetime, Some(def)) + } else { + tcx.mk_region(ty::ReStatic) + } }, |def, substs| { let i = def.index as usize; @@ -466,12 +329,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // A provided type parameter. match *parameters { hir::AngleBracketedParameters(ref data) => { - self.ast_ty_arg_to_ty(rscope, Some(def), substs, &data.types[i]) + self.ast_ty_to_ty(&data.types[i]) } hir::ParenthesizedParameters(ref data) => { assert_eq!(i, 0); - let (ty, assoc) = - self.convert_parenthesized_parameters(rscope, substs, data); + let (ty, assoc) = self.convert_parenthesized_parameters(data); output_assoc_binding = Some(assoc); ty } @@ -516,7 +378,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { data.bindings.iter().map(|b| { ConvertedBinding { item_name: b.name, - ty: self.ast_ty_to_ty(rscope, &b.ty), + ty: self.ast_ty_to_ty(&b.ty), span: b.span } }).collect() @@ -525,7 +387,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { vec![output_assoc_binding.unwrap_or_else(|| { // This is an error condition, but we should // get the associated type binding anyway. - self.convert_parenthesized_parameters(rscope, substs, data).1 + self.convert_parenthesized_parameters(data).1 })] } }; @@ -536,92 +398,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { (substs, assoc_bindings) } - /// Returns the appropriate lifetime to use for any output lifetimes - /// (if one exists) and a vector of the (pattern, number of lifetimes) - /// corresponding to each input type/pattern. - fn find_implied_output_region(&self, - input_tys: &[Ty<'tcx>], - parent: Option, - input_indices: I) -> ElidedLifetime - where I: Iterator - { - let tcx = self.tcx(); - let mut lifetimes_for_params = Vec::with_capacity(input_tys.len()); - let mut possible_implied_output_region = None; - let mut lifetimes = 0; - - for (input_type, index) in input_tys.iter().zip(input_indices) { - let mut regions = FxHashSet(); - let have_bound_regions = tcx.collect_regions(input_type, &mut regions); - - debug!("find_implied_output_regions: collected {:?} from {:?} \ - have_bound_regions={:?}", ®ions, input_type, have_bound_regions); - - lifetimes += regions.len(); - - if lifetimes == 1 && regions.len() == 1 { - // there's a chance that the unique lifetime of this - // iteration will be the appropriate lifetime for output - // parameters, so lets store it. - possible_implied_output_region = regions.iter().cloned().next(); - } - - lifetimes_for_params.push(ElisionFailureInfo { - parent: parent, - index: index, - lifetime_count: regions.len(), - have_bound_regions: have_bound_regions - }); - } - - if lifetimes == 1 { - Ok(*possible_implied_output_region.unwrap()) - } else { - Err(Some(lifetimes_for_params)) - } - } - - fn convert_ty_with_lifetime_elision(&self, - elided_lifetime: ElidedLifetime, - ty: &hir::Ty, - anon_scope: Option) - -> Ty<'tcx> - { - match elided_lifetime { - Ok(implied_output_region) => { - let rb = ElidableRscope::new(implied_output_region); - self.ast_ty_to_ty(&MaybeWithAnonTypes::new(rb, anon_scope), ty) - } - Err(param_lifetimes) => { - // All regions must be explicitly specified in the output - // if the lifetime elision rules do not apply. This saves - // the user from potentially-confusing errors. - let rb = UnelidableRscope::new(param_lifetimes); - self.ast_ty_to_ty(&MaybeWithAnonTypes::new(rb, anon_scope), ty) - } - } - } - fn convert_parenthesized_parameters(&self, - rscope: &RegionScope, - region_substs: &[Kind<'tcx>], data: &hir::ParenthesizedParameterData) -> (Ty<'tcx>, ConvertedBinding<'tcx>) { - let anon_scope = rscope.anon_type_scope(); - let binding_rscope = MaybeWithAnonTypes::new(BindingRscope::new(), anon_scope); let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| { - self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t) + self.ast_ty_to_ty(a_t) })); - let input_params = 0..inputs.len(); - let implied_output_region = self.find_implied_output_region(&inputs, None, input_params); let (output, output_span) = match data.output { Some(ref output_ty) => { - (self.convert_ty_with_lifetime_elision(implied_output_region, - &output_ty, - anon_scope), - output_ty.span) + (self.ast_ty_to_ty(output_ty), output_ty.span) } None => { (self.tcx().mk_nil(), data.span) @@ -637,24 +424,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { (self.tcx().mk_ty(ty::TyTuple(inputs)), output_binding) } - pub fn instantiate_poly_trait_ref(&self, - rscope: &RegionScope, - ast_trait_ref: &hir::PolyTraitRef, - self_ty: Ty<'tcx>, - poly_projections: &mut Vec>) - -> ty::PolyTraitRef<'tcx> - { - let trait_ref = &ast_trait_ref.trait_ref; - let trait_def_id = self.trait_def_id(trait_ref); - self.ast_path_to_poly_trait_ref(rscope, - trait_ref.path.span, - trait_def_id, - self_ty, - trait_ref.ref_id, - trait_ref.path.segments.last().unwrap(), - poly_projections) - } - /// Instantiates the path for the given trait reference, assuming that it's /// bound to a valid trait type. Returns the def_id for the defining trait. /// Fails if the type is a type other than a trait type. @@ -662,14 +431,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// If the `projections` argument is `None`, then assoc type bindings like `Foo` /// are disallowed. Otherwise, they are pushed onto the vector given. pub fn instantiate_mono_trait_ref(&self, - rscope: &RegionScope, trait_ref: &hir::TraitRef, self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> { let trait_def_id = self.trait_def_id(trait_ref); - self.ast_path_to_mono_trait_ref(rscope, - trait_ref.path.span, + self.ast_path_to_mono_trait_ref(trait_ref.path.span, trait_def_id, self_ty, trait_ref.path.segments.last().unwrap()) @@ -689,48 +456,39 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - fn ast_path_to_poly_trait_ref(&self, - rscope: &RegionScope, - span: Span, - trait_def_id: DefId, + pub fn instantiate_poly_trait_ref(&self, + ast_trait_ref: &hir::PolyTraitRef, self_ty: Ty<'tcx>, - path_id: ast::NodeId, - trait_segment: &hir::PathSegment, poly_projections: &mut Vec>) -> ty::PolyTraitRef<'tcx> { - debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment); - // The trait reference introduces a binding level here, so - // we need to shift the `rscope`. It'd be nice if we could - // do away with this rscope stuff and work this knowledge - // into resolve_lifetimes, as we do with non-omitted - // lifetimes. Oh well, not there yet. - let shifted_rscope = &ShiftedRscope::new(rscope); + let trait_ref = &ast_trait_ref.trait_ref; + let trait_def_id = self.trait_def_id(trait_ref); + + debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); let (substs, assoc_bindings) = - self.create_substs_for_ast_trait_ref(shifted_rscope, - span, + self.create_substs_for_ast_trait_ref(trait_ref.path.span, trait_def_id, self_ty, - trait_segment); + trait_ref.path.segments.last().unwrap()); let poly_trait_ref = ty::Binder(ty::TraitRef::new(trait_def_id, substs)); poly_projections.extend(assoc_bindings.iter().filter_map(|binding| { // specify type to assert that error was already reported in Err case: let predicate: Result<_, ErrorReported> = - self.ast_type_binding_to_poly_projection_predicate(path_id, + self.ast_type_binding_to_poly_projection_predicate(trait_ref.ref_id, poly_trait_ref, binding); predicate.ok() // ok to ignore Err() because ErrorReported (see above) })); - debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}", - trait_segment, poly_projections, poly_trait_ref); + debug!("ast_path_to_poly_trait_ref({:?}, projections={:?}) -> {:?}", + trait_ref, poly_projections, poly_trait_ref); poly_trait_ref } fn ast_path_to_mono_trait_ref(&self, - rscope: &RegionScope, span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, @@ -738,8 +496,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { -> ty::TraitRef<'tcx> { let (substs, assoc_bindings) = - self.create_substs_for_ast_trait_ref(rscope, - span, + self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment); @@ -748,7 +505,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn create_substs_for_ast_trait_ref(&self, - rscope: &RegionScope, span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, @@ -792,8 +548,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - self.create_substs_for_ast_path(rscope, - span, + self.create_substs_for_ast_path(span, trait_def_id, &trait_segment.parameters, Some(self_ty)) @@ -902,7 +657,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn ast_path_to_ty(&self, - rscope: &RegionScope, span: Span, did: DefId, item_segment: &hir::PathSegment) @@ -916,17 +670,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } }; - let substs = self.ast_path_substs_for_ty(rscope, - span, - did, - item_segment); - - // FIXME(#12938): This is a hack until we have full support for DST. - if Some(did) == self.tcx().lang_items.owned_box() { - assert_eq!(substs.types().count(), 1); - return self.tcx().mk_box(substs.type_at(0)); - } - + let substs = self.ast_path_substs_for_ty(span, did, item_segment); decl_ty.subst(self.tcx(), substs) } @@ -938,32 +682,27 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref) } - fn trait_path_to_object_type(&self, - rscope: &RegionScope, - path_span: Span, - trait_def_id: DefId, - trait_path_ref_id: ast::NodeId, - trait_segment: &hir::PathSegment, - span: Span, - partitioned_bounds: PartitionedBounds) - -> Ty<'tcx> { + fn conv_object_ty_poly_trait_ref(&self, + span: Span, + trait_bounds: &[hir::PolyTraitRef], + lifetime: &hir::Lifetime) + -> Ty<'tcx> + { let tcx = self.tcx(); + if trait_bounds.is_empty() { + span_err!(tcx.sess, span, E0224, + "at least one non-builtin trait is required for an object type"); + return tcx.types.err; + } + let mut projection_bounds = vec![]; let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF); - let principal = self.ast_path_to_poly_trait_ref(rscope, - path_span, - trait_def_id, + let principal = self.instantiate_poly_trait_ref(&trait_bounds[0], dummy_self, - trait_path_ref_id, - trait_segment, &mut projection_bounds); - let PartitionedBounds { trait_bounds, - region_bounds } = - partitioned_bounds; - - let (auto_traits, trait_bounds) = split_auto_traits(tcx, trait_bounds); + let (auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]); if !trait_bounds.is_empty() { let b = &trait_bounds[0]; @@ -1038,23 +777,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { v.sort_by(|a, b| a.cmp(tcx, b)); let existential_predicates = ty::Binder(tcx.mk_existential_predicates(v.into_iter())); - let region_bound = self.compute_object_lifetime_bound(span, - ®ion_bounds, - existential_predicates); - let region_bound = match region_bound { - Some(r) => r, - None => { - tcx.mk_region(match rscope.object_lifetime_default(span) { - Some(r) => r, - None => { - span_err!(self.tcx().sess, span, E0228, + // Explicitly specified region bound. Use that. + let region_bound = if !lifetime.is_elided() { + self.ast_region_to_region(lifetime, None) + } else { + self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { + if tcx.named_region_map.defs.contains_key(&lifetime.id) { + self.ast_region_to_region(lifetime, None) + } else { + self.re_infer(span, None).unwrap_or_else(|| { + span_err!(tcx.sess, span, E0228, "the lifetime bound for this object type cannot be deduced \ from context; please supply an explicit bound"); - ty::ReStatic - } - }) - } + tcx.mk_region(ty::ReStatic) + }) + } + }) }; debug!("region_bound: {:?}", region_bound); @@ -1265,7 +1004,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn qpath_to_ty(&self, - rscope: &RegionScope, span: Span, opt_self_ty: Option>, trait_def_id: DefId, @@ -1290,8 +1028,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("qpath_to_ty: self_type={:?}", self_ty); - let trait_ref = self.ast_path_to_mono_trait_ref(rscope, - span, + let trait_ref = self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment); @@ -1301,41 +1038,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.projected_ty(span, trait_ref, item_segment.name) } - /// Convert a type supplied as value for a type argument from AST into our - /// our internal representation. This is the same as `ast_ty_to_ty` but that - /// it applies the object lifetime default. - /// - /// # Parameters - /// - /// * `this`, `rscope`: the surrounding context - /// * `def`: the type parameter being instantiated (if available) - /// * `region_substs`: a partial substitution consisting of - /// only the region type parameters being supplied to this type. - /// * `ast_ty`: the ast representation of the type being supplied - fn ast_ty_arg_to_ty(&self, - rscope: &RegionScope, - def: Option<&ty::TypeParameterDef<'tcx>>, - region_substs: &[Kind<'tcx>], - ast_ty: &hir::Ty) - -> Ty<'tcx> - { - let tcx = self.tcx(); - - if let Some(def) = def { - let object_lifetime_default = def.object_lifetime_default.subst(tcx, region_substs); - let rscope1 = &ObjectLifetimeDefaultRscope::new(rscope, object_lifetime_default); - self.ast_ty_to_ty(rscope1, ast_ty) - } else { - self.ast_ty_to_ty(rscope, ast_ty) - } - } - // Check a type Path and convert it to a Ty. pub fn def_to_ty(&self, - rscope: &RegionScope, opt_self_ty: Option>, path: &hir::Path, - path_id: ast::NodeId, permit_variants: bool) -> Ty<'tcx> { let tcx = self.tcx(); @@ -1345,33 +1051,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let span = path.span; match path.def { - Def::Trait(trait_def_id) => { - // N.B. this case overlaps somewhat with - // TyTraitObject, see that fn for details - - assert_eq!(opt_self_ty, None); - tcx.prohibit_type_params(path.segments.split_last().unwrap().1); - - self.trait_path_to_object_type(rscope, - span, - trait_def_id, - path_id, - path.segments.last().unwrap(), - span, - partition_bounds(&[])) - } Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { assert_eq!(opt_self_ty, None); tcx.prohibit_type_params(path.segments.split_last().unwrap().1); - self.ast_path_to_ty(rscope, span, did, path.segments.last().unwrap()) + self.ast_path_to_ty(span, did, path.segments.last().unwrap()) } Def::Variant(did) if permit_variants => { // Convert "variant type" as if it were a real type. // The resulting `Ty` is type of the variant's enum for now. assert_eq!(opt_self_ty, None); tcx.prohibit_type_params(path.segments.split_last().unwrap().1); - self.ast_path_to_ty(rscope, - span, + self.ast_path_to_ty(span, tcx.parent_def_id(did).unwrap(), path.segments.last().unwrap()) } @@ -1429,8 +1119,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Def::AssociatedTy(def_id) => { tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]); let trait_did = tcx.parent_def_id(def_id).unwrap(); - self.qpath_to_ty(rscope, - span, + self.qpath_to_ty(span, opt_self_ty, trait_did, &path.segments[path.segments.len()-2], @@ -1450,7 +1139,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// Parses the programmer's textual representation of a type into our /// internal notion of a type. - pub fn ast_ty_to_ty(&self, rscope: &RegionScope, ast_ty: &hir::Ty) -> Ty<'tcx> { + pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})", ast_ty.id, ast_ty); @@ -1463,40 +1152,29 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let result_ty = match ast_ty.node { hir::TySlice(ref ty) => { - tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty)) + tcx.mk_slice(self.ast_ty_to_ty(&ty)) } hir::TyPtr(ref mt) => { tcx.mk_ptr(ty::TypeAndMut { - ty: self.ast_ty_to_ty(rscope, &mt.ty), + ty: self.ast_ty_to_ty(&mt.ty), mutbl: mt.mutbl }) } hir::TyRptr(ref region, ref mt) => { - let r = self.opt_ast_region_to_region(rscope, ast_ty.span, region); + let r = self.ast_region_to_region(region, None); debug!("TyRef r={:?}", r); - let rscope1 = - &ObjectLifetimeDefaultRscope::new( - rscope, - ty::ObjectLifetimeDefault::Specific(r)); - let t = self.ast_ty_to_ty(rscope1, &mt.ty); + let t = self.ast_ty_to_ty(&mt.ty); tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl}) } hir::TyNever => { tcx.types.never }, hir::TyTup(ref fields) => { - tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(rscope, &t))) + tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t))) } hir::TyBareFn(ref bf) => { require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); - let anon_scope = rscope.anon_type_scope(); - let bare_fn_ty = self.ty_of_method_or_bare_fn(bf.unsafety, - bf.abi, - None, - &bf.decl, - None, - anon_scope, - anon_scope); + let bare_fn_ty = self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl); // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not wellformed. @@ -1537,22 +1215,60 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } tcx.mk_fn_ptr(bare_fn_ty) } - hir::TyTraitObject(ref bounds) => { - self.conv_object_ty_poly_trait_ref(rscope, ast_ty.span, bounds) + hir::TyTraitObject(ref bounds, ref lifetime) => { + self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime) } hir::TyImplTrait(ref bounds) => { use collect::{compute_bounds, SizedByDefault}; + // Figure out if we can allow an `impl Trait` here, by walking up + // to a `fn` or inherent `impl` method, going only through `Ty` + // or `TraitRef` nodes (as nothing else should be in types) and + // ensuring that we reach the `fn`/method signature's return type. + let mut node_id = ast_ty.id; + let fn_decl = loop { + let parent = tcx.hir.get_parent_node(node_id); + match tcx.hir.get(parent) { + hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(ref fn_decl, ..), .. + }) => break Some(fn_decl), + + hir::map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(ref sig, _), .. + }) => { + match tcx.hir.expect_item(tcx.hir.get_parent(parent)).node { + hir::ItemImpl(.., None, _, _) => { + break Some(&sig.decl) + } + _ => break None + } + } + + hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => {} + + _ => break None + } + node_id = parent; + }; + let allow = fn_decl.map_or(false, |fd| { + match fd.output { + hir::DefaultReturn(_) => false, + hir::Return(ref ty) => ty.id == node_id + } + }); + // Create the anonymized type. - let def_id = tcx.hir.local_def_id(ast_ty.id); - if let Some(anon_scope) = rscope.anon_type_scope() { - let substs = anon_scope.fresh_substs(self, ast_ty.span); + if allow { + let def_id = tcx.hir.local_def_id(ast_ty.id); + if let Err(ErrorReported) = self.get_generics(ast_ty.span, def_id) { + return tcx.types.err; + } + let substs = Substs::identity_for_item(tcx, def_id); let ty = tcx.mk_anon(tcx.hir.local_def_id(ast_ty.id), substs); // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`. let bounds = compute_bounds(self, ty, bounds, SizedByDefault::Yes, - Some(anon_scope), ast_ty.span); let predicates = bounds.predicates(tcx, ty); let predicates = tcx.lift_to_global(&predicates).unwrap(); @@ -1572,13 +1288,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => { debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); let opt_self_ty = maybe_qself.as_ref().map(|qself| { - self.ast_ty_to_ty(rscope, qself) + self.ast_ty_to_ty(qself) }); - self.def_to_ty(rscope, opt_self_ty, path, ast_ty.id, false) + self.def_to_ty(opt_self_ty, path, false) } hir::TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => { debug!("ast_ty_to_ty: qself={:?} segment={:?}", qself, segment); - let ty = self.ast_ty_to_ty(rscope, qself); + let ty = self.ast_ty_to_ty(qself); let def = if let hir::TyPath(hir::QPath::Resolved(_, ref path)) = qself.node { path.def @@ -1589,7 +1305,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } hir::TyArray(ref ty, length) => { if let Ok(length) = eval_length(tcx.global_tcx(), length, "array length") { - tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length) + tcx.mk_array(self.ast_ty_to_ty(&ty), length) } else { self.tcx().types.err } @@ -1617,7 +1333,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } pub fn ty_of_arg(&self, - rscope: &RegionScope, ty: &hir::Ty, expected_ty: Option>) -> Ty<'tcx> @@ -1625,87 +1340,26 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { match ty.node { hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(), hir::TyInfer => self.ty_infer(ty.span), - _ => self.ast_ty_to_ty(rscope, ty), + _ => self.ast_ty_to_ty(ty), } } - pub fn ty_of_method(&self, - sig: &hir::MethodSig, - opt_self_value_ty: Option>, - body: Option, - anon_scope: Option) - -> &'tcx ty::BareFnTy<'tcx> { - self.ty_of_method_or_bare_fn(sig.unsafety, - sig.abi, - opt_self_value_ty, - &sig.decl, - body, - None, - anon_scope) - } - - pub fn ty_of_bare_fn(&self, - unsafety: hir::Unsafety, - abi: abi::Abi, - decl: &hir::FnDecl, - body: hir::BodyId, - anon_scope: Option) - -> &'tcx ty::BareFnTy<'tcx> { - self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, Some(body), None, anon_scope) - } - - fn ty_of_method_or_bare_fn(&self, - unsafety: hir::Unsafety, - abi: abi::Abi, - opt_self_value_ty: Option>, - decl: &hir::FnDecl, - body: Option, - arg_anon_scope: Option, - ret_anon_scope: Option) - -> &'tcx ty::BareFnTy<'tcx> - { - debug!("ty_of_method_or_bare_fn"); - - // New region names that appear inside of the arguments of the function - // declaration are bound to that function type. - let rb = MaybeWithAnonTypes::new(BindingRscope::new(), arg_anon_scope); + pub fn ty_of_fn(&self, + unsafety: hir::Unsafety, + abi: abi::Abi, + decl: &hir::FnDecl) + -> &'tcx ty::BareFnTy<'tcx> { + debug!("ty_of_fn"); let input_tys: Vec = - decl.inputs.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect(); - - let has_self = opt_self_value_ty.is_some(); - let explicit_self = opt_self_value_ty.map(|self_value_ty| { - ExplicitSelf::determine(self_value_ty, input_tys[0]) - }); - - let implied_output_region = match explicit_self { - // `implied_output_region` is the region that will be assumed for any - // region parameters in the return type. In accordance with the rules for - // lifetime elision, we can determine it in two ways. First (determined - // here), if self is by-reference, then the implied output region is the - // region of the self parameter. - Some(ExplicitSelf::ByReference(region, _)) => Ok(*region), - - // Second, if there was exactly one lifetime (either a substitution or a - // reference) in the arguments, then any anonymous regions in the output - // have that lifetime. - _ => { - let arg_tys = &input_tys[has_self as usize..]; - let arg_params = has_self as usize..input_tys.len(); - self.find_implied_output_region(arg_tys, body, arg_params) - - } - }; + decl.inputs.iter().map(|a| self.ty_of_arg(a, None)).collect(); let output_ty = match decl.output { - hir::Return(ref output) => - self.convert_ty_with_lifetime_elision(implied_output_region, - &output, - ret_anon_scope), + hir::Return(ref output) => self.ast_ty_to_ty(output), hir::DefaultReturn(..) => self.tcx().mk_nil(), }; - debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty); + debug!("ty_of_fn: output_ty={:?}", output_ty); self.tcx().mk_bare_fn(ty::BareFnTy { unsafety: unsafety, @@ -1728,10 +1382,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("ty_of_closure(expected_sig={:?})", expected_sig); - // new region names that appear inside of the fn decl are bound to - // that function type - let rb = rscope::BindingRscope::new(); - let input_tys = decl.inputs.iter().enumerate().map(|(i, a)| { let expected_arg_ty = expected_sig.as_ref().and_then(|e| { // no guarantee that the correct number of expected args @@ -1742,7 +1392,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { None } }); - self.ty_of_arg(&rb, a, expected_arg_ty) + self.ty_of_arg(a, expected_arg_ty) }); let expected_ret_ty = expected_sig.as_ref().map(|e| e.output()); @@ -1758,7 +1408,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { expected_ret_ty.unwrap(), _ if is_infer => self.ty_infer(decl.output.span()), hir::Return(ref output) => - self.ast_ty_to_ty(&rb, &output), + self.ast_ty_to_ty(&output), hir::DefaultReturn(..) => bug!(), }; @@ -1771,33 +1421,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - fn conv_object_ty_poly_trait_ref(&self, - rscope: &RegionScope, - span: Span, - ast_bounds: &[hir::TyParamBound]) - -> Ty<'tcx> - { - let mut partitioned_bounds = partition_bounds(ast_bounds); - - let trait_bound = if !partitioned_bounds.trait_bounds.is_empty() { - partitioned_bounds.trait_bounds.remove(0) - } else { - span_err!(self.tcx().sess, span, E0224, - "at least one non-builtin trait is required for an object type"); - return self.tcx().types.err; - }; - - let trait_ref = &trait_bound.trait_ref; - let trait_def_id = self.trait_def_id(trait_ref); - self.trait_path_to_object_type(rscope, - trait_ref.path.span, - trait_def_id, - trait_ref.ref_id, - trait_ref.path.segments.last().unwrap(), - span, - partitioned_bounds) - } - /// Given the bounds on an object, determines what single region bound (if any) we can /// use to summarize this type. The basic idea is that we will use the bound the user /// provided, if they provided one, and otherwise search the supertypes of trait bounds @@ -1805,27 +1428,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { /// we return `None`. fn compute_object_lifetime_bound(&self, span: Span, - explicit_region_bounds: &[&hir::Lifetime], existential_predicates: ty::Binder<&'tcx ty::Slice>>) -> Option<&'tcx ty::Region> // if None, use the default { let tcx = self.tcx(); - debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \ - existential_predicates={:?})", - explicit_region_bounds, + debug!("compute_opt_region_bound(existential_predicates={:?})", existential_predicates); - if explicit_region_bounds.len() > 1 { - span_err!(tcx.sess, explicit_region_bounds[1].span, E0226, - "only a single explicit lifetime bound is permitted"); - } - - if let Some(&r) = explicit_region_bounds.get(0) { - // Explicitly specified region bound. Use that. - return Some(ast_region_to_region(tcx, r)); - } - if let Some(principal) = existential_predicates.principal() { if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) { return Some(tcx.mk_region(ty::ReStatic)); @@ -1861,18 +1471,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } -pub struct PartitionedBounds<'a> { - pub trait_bounds: Vec<&'a hir::PolyTraitRef>, - pub region_bounds: Vec<&'a hir::Lifetime>, -} - /// Divides a list of general trait bounds into two groups: builtin bounds (Sync/Send) and the /// remaining general trait bounds. fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_bounds: Vec<&'b hir::PolyTraitRef>) + trait_bounds: &'b [hir::PolyTraitRef]) -> (Vec, Vec<&'b hir::PolyTraitRef>) { - let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.into_iter().partition(|bound| { + let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.iter().partition(|bound| { match bound.trait_ref.path.def { Def::Trait(trait_did) => { // Checks whether `trait_did` refers to one of the builtin @@ -1909,30 +1514,6 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, (auto_traits, trait_bounds) } -/// Divides a list of bounds from the AST into two groups: general trait bounds and region bounds -pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(ast_bounds: &'b [hir::TyParamBound]) - -> PartitionedBounds<'b> -{ - let mut region_bounds = Vec::new(); - let mut trait_bounds = Vec::new(); - for ast_bound in ast_bounds { - match *ast_bound { - hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => { - trait_bounds.push(b); - } - hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {} - hir::RegionTyParamBound(ref l) => { - region_bounds.push(l); - } - } - } - - PartitionedBounds { - trait_bounds: trait_bounds, - region_bounds: region_bounds, - } -} - fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize, ty_param_defs: &[ty::TypeParameterDef]) { let accepted = ty_param_defs.len(); @@ -2084,7 +1665,7 @@ impl<'tcx> ExplicitSelf<'tcx> { fn count_modifiers(ty: Ty) -> usize { match ty.sty { ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1, - ty::TyBox(t) => count_modifiers(t) + 1, + ty::TyAdt(def, _) if def.is_box() => count_modifiers(ty.boxed_ty()) + 1, _ => 0, } } @@ -2097,7 +1678,7 @@ impl<'tcx> ExplicitSelf<'tcx> { } else { match self_arg_ty.sty { ty::TyRef(r, mt) => ExplicitSelf::ByReference(r, mt.mutbl), - ty::TyBox(_) => ExplicitSelf::ByBox, + ty::TyAdt(def, _) if def.is_box() => ExplicitSelf::ByBox, _ => ExplicitSelf::ByValue, } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 265dcada1f810..6215b4498dc68 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -288,7 +288,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { tstr); } } - ty::TyBox(..) => { + ty::TyAdt(def, ..) if def.is_box() => { match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) { Ok(s) => { err.span_suggestion(self.cast_span, @@ -348,12 +348,12 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } else if self.try_coercion_cast(fcx) { self.trivial_cast_lint(fcx); debug!(" -> CoercionCast"); - fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, CastKind::CoercionCast); + fcx.tables.borrow_mut().cast_kinds.insert(self.expr.id, CastKind::CoercionCast); } else { match self.do_check(fcx) { Ok(k) => { debug!(" -> {:?}", k); - fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, k); + fcx.tables.borrow_mut().cast_kinds.insert(self.expr.id, k); } Err(e) => self.report_cast_error(fcx, e), }; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 91b772a748c72..34aa4eda772ad 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -448,7 +448,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( Ok(()) } - ty::TyBox(ity) | ty::TyArray(ity, _) | ty::TySlice(ity) => { + 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) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index e2d7d31a8a890..300caca30fec8 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -391,11 +391,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::TyAdt(def, _) => { self.assemble_inherent_impl_candidates_for_type(def.did); } - ty::TyBox(_) => { - if let Some(box_did) = self.tcx.lang_items.owned_box() { - self.assemble_inherent_impl_candidates_for_type(box_did); - } - } ty::TyParam(p) => { self.assemble_inherent_candidates_from_param(self_ty, p); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7b87ec5dd5d2f..c435f9341253e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -80,7 +80,7 @@ pub use self::Expectation::*; pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::TupleArgumentsFlag::*; -use astconv::{AstConv, ast_region_to_region}; +use astconv::AstConv; use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; use hir::def::{Def, CtorKind}; @@ -97,7 +97,6 @@ use rustc::ty::adjustment; use rustc::ty::fold::{BottomUpFolder, TypeFoldable}; use rustc::ty::util::{Representability, IntTypeExt}; use require_c_abi_if_variadic; -use rscope::{ElisionFailureInfo, RegionScope}; use session::{Session, CompileResult}; use CrateCtxt; use TypeAndSubsts; @@ -1410,6 +1409,15 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { Ok(r) } + fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>) + -> Option<&'tcx ty::Region> { + let v = match def { + Some(def) => infer::EarlyBoundRegion(span, def.name), + None => infer::MiscVariable(span) + }; + Some(self.next_region_var(v)) + } + fn ty_infer(&self, span: Span) -> Ty<'tcx> { self.next_ty_var(TypeVariableOrigin::TypeInference(span)) } @@ -1450,30 +1458,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> { - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { - // RFC #599 specifies that object lifetime defaults take - // precedence over other defaults. But within a fn body we - // don't have a *default* region, rather we use inference to - // find the *correct* region, which is strictly more general - // (and anyway, within a fn body the right region may not even - // be something the user can write explicitly, since it might - // be some expression). - *self.next_region_var(infer::MiscVariable(span)) - } - - fn anon_regions(&self, span: Span, count: usize) - -> Result, Option>> { - Ok((0..count).map(|_| { - *self.next_region_var(infer::MiscVariable(span)) - }).collect()) - } -} - /// Controls whether the arguments are tupled. This is used for the call /// operator. /// @@ -1830,7 +1814,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> { - let t = AstConv::ast_ty_to_ty(self, self, ast_t); + let t = AstConv::ast_ty_to_ty(self, ast_t); self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); t } @@ -3306,16 +3290,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Def::Struct(..) | Def::Union(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => { - match def { - Def::AssociatedTy(..) | Def::SelfTy(..) - if !self.tcx.sess.features.borrow().more_struct_aliases => { - emit_feature_err(&self.tcx.sess.parse_sess, - "more_struct_aliases", path_span, GateIssue::Language, - "`Self` and associated types in struct \ - expressions and patterns are unstable"); - } - _ => {} - } match ty.sty { ty::TyAdt(adt, substs) if !adt.is_enum() => { Some((adt.struct_variant(), adt.did, substs)) @@ -3464,7 +3438,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprBox(ref subexpr) => { let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| { match ty.sty { - ty::TyBox(ty) => Expectation::rvalue_hint(self, ty), + ty::TyAdt(def, _) if def.is_box() + => Expectation::rvalue_hint(self, ty.boxed_ty()), _ => NoExpectation } }); @@ -3984,7 +3959,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match *qpath { hir::QPath::Resolved(ref maybe_qself, ref path) => { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); - let ty = AstConv::def_to_ty(self, self, opt_self_ty, path, node_id, true); + let ty = AstConv::def_to_ty(self, opt_self_ty, path, true); (path.def, ty) } hir::QPath::TypeRelative(ref qself, ref segment) => { @@ -4416,10 +4391,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None => &[] }; - if let Some(ast_lifetime) = lifetimes.get(i) { - ast_region_to_region(self.tcx, ast_lifetime) + if let Some(lifetime) = lifetimes.get(i) { + AstConv::ast_region_to_region(self, lifetime, Some(def)) } else { - self.region_var_for_def(span, def) + self.re_infer(span, Some(def)).unwrap() } }, |def, substs| { let mut i = def.index as usize; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index d1a9b8ef85ae4..0dcdab07e6fc8 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -12,8 +12,10 @@ use super::FnCtxt; use hir::def_id::DefId; -use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue}; +use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue, TypeVariants}; +use rustc::ty::TypeVariants::{TyStr, TyRef}; use rustc::infer::type_variable::TypeVariableOrigin; +use errors; use syntax::ast; use syntax::symbol::Symbol; use rustc::hir; @@ -204,6 +206,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { "binary operation `{}` cannot be applied to type `{}`", op.node.as_str(), lhs_ty); + + if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { + if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && + self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var], + Symbol::intern(name), trait_def_id, + lhs_expr).is_ok() { + err.span_note( + lhs_expr.span, + &format!( + "this is a reference of type that `{}` can be applied to, \ + you need to dereference this variable once for this \ + operation to work", + op.node.as_str())); + } + } + let missing_trait = match op.node { hir::BiAdd => Some("std::ops::Add"), hir::BiSub => Some("std::ops::Sub"), @@ -221,9 +239,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(missing_trait) = missing_trait { - span_note!(&mut err, lhs_expr.span, - "an implementation of `{}` might be missing for `{}`", - missing_trait, lhs_ty); + if missing_trait == "std::ops::Add" && + self.check_str_addition(expr, lhs_expr, lhs_ty, + rhs_expr, rhs_ty_var, &mut err) { + // This has nothing here because it means we did string + // concatenation (e.g. "Hello " + "World!"). This means + // we don't want the span in the else clause to be emmitted + } else { + span_note!(&mut err, lhs_expr.span, + "an implementation of `{}` might be missing for `{}`", + missing_trait, lhs_ty); + } } err.emit(); } @@ -238,6 +264,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (rhs_ty_var, return_ty) } + fn check_str_addition(&self, + expr: &'gcx hir::Expr, + lhs_expr: &'gcx hir::Expr, + lhs_ty: Ty<'tcx>, + rhs_expr: &'gcx hir::Expr, + rhs_ty_var: Ty<'tcx>, + mut err: &mut errors::DiagnosticBuilder) -> bool { + // If this function returns false it means we use it to make sure we print + // out the an "implementation of span_note!" above where this function is + // called and if true we don't. + let mut is_string_addition = false; + let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); + if let TyRef(_, l_ty) = lhs_ty.sty { + if let TyRef(_, r_ty) = rhs_ty.sty { + if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr { + span_note!(&mut err, lhs_expr.span, + "`+` can't be used to concatenate two `&str` strings"); + let codemap = self.tcx.sess.codemap(); + let suggestion = + match (codemap.span_to_snippet(lhs_expr.span), + codemap.span_to_snippet(rhs_expr.span)) { + (Ok(lstring), Ok(rstring)) => + format!("{}.to_owned() + {}", lstring, rstring), + _ => format!("") + }; + err.span_suggestion(expr.span, + &format!("to_owned() can be used to create an owned `String` \ + from a string reference. String concatenation \ + appends the string on the right to the string \ + on the left and may require reallocation. This \ + requires ownership of the string on the left."), suggestion); + is_string_addition = true; + } + + } + + } + + is_string_addition + } + pub fn check_user_unop(&self, op_str: &str, mname: &str, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 7d515a36cfdff..d84e9d3fd3731 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -815,9 +815,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.type_must_outlive(infer::RelateObjectBound(cast_expr.span), from_ty, r); } - /*From:*/ (&ty::TyBox(from_referent_ty), - /*To: */ &ty::TyBox(to_referent_ty)) => { - self.walk_cast(cast_expr, from_referent_ty, to_referent_ty); + /*From:*/ (&ty::TyAdt(from_def, _), + /*To: */ &ty::TyAdt(to_def, _)) if from_def.is_box() && to_def.is_box() => { + self.walk_cast(cast_expr, from_ty.boxed_ty(), to_ty.boxed_ty()); } _ => { } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index b95126af56aa7..7f82d7829ce52 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -51,6 +51,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_anon_types(); wbcx.visit_deferred_obligations(item_id); wbcx.visit_type_nodes(); + wbcx.visit_cast_types(); let tables = self.tcx.alloc_tables(wbcx.tables); self.tcx.tables.borrow_mut().insert(item_def_id, tables); @@ -291,6 +292,15 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } + fn visit_cast_types(&mut self) { + if self.fcx.writeback_errors.get() { + return + } + + self.tables.cast_kinds.extend( + self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value))); + } + fn visit_anon_types(&self) { if self.fcx.writeback_errors.get() { return diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 086484c643ad1..96875fce468d2 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -220,8 +220,6 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (mt_a.ty, mt_b.ty, unsize_trait, None) }; let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) { - (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None), - (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => { infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 5af9ea29fafa7..e9c710d2fec4c 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -21,7 +21,7 @@ use rustc::ty::{Ty, TyBool, TyChar, TyError}; use rustc::ty::{TyParam, TyRawPtr}; use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple}; use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; -use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; +use rustc::ty::{TyUint, TyClosure, TyFnDef, TyFnPtr}; use rustc::ty::{TyProjection, TyAnon}; use CrateCtxt; use syntax_pos::Span; @@ -61,8 +61,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()), - TyBox(_) => self.tcx.lang_items.owned_box(), - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError | TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None, diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index c3417ab08d7fa..9ef231499df51 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -91,12 +91,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { ty::TyDynamic(ref data, ..) if data.principal().is_some() => { self.check_def_id(item, data.principal().unwrap().def_id()); } - ty::TyBox(..) => { - match self.tcx.lang_items.require_owned_box() { - Ok(trait_id) => self.check_def_id(item, trait_id), - Err(msg) => self.tcx.sess.span_fatal(item.span, &msg), - } - } ty::TyChar => { self.check_primitive_impl(def_id, self.tcx.lang_items.char_impl(), @@ -263,6 +257,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { .span_label(item.span, &format!("impl doesn't use types inside crate")) .note(&format!("the impl does not reference any types defined in \ this crate")) + .note("define and implement a trait or new type instead") .emit(); return; } @@ -320,7 +315,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { ty::TyAdt(self_def, _) => Some(self_def.did), - ty::TyBox(..) => self.tcx.lang_items.owned_box(), _ => None, }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 841b4516a18f3..bbd0c8058151f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -57,7 +57,7 @@ There are some shortcomings in this design: */ -use astconv::{AstConv, ast_region_to_region, Bounds, PartitionedBounds, partition_bounds}; +use astconv::{AstConv, Bounds}; use lint; use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; @@ -68,10 +68,9 @@ use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::util::IntTypeExt; -use rscope::*; use rustc::dep_graph::DepNode; use util::common::{ErrorReported, MemoizationMap}; -use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; +use util::nodemap::{NodeMap, FxHashMap}; use CrateCtxt; use rustc_const_math::ConstInt; @@ -373,8 +372,8 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { } impl<'a,'tcx> ItemCtxt<'a,'tcx> { - fn to_ty(&self, rs: &RS, ast_ty: &hir::Ty) -> Ty<'tcx> { - AstConv::ast_ty_to_ty(self, rs, ast_ty) + fn to_ty(&self, ast_ty: &hir::Ty) -> Ty<'tcx> { + AstConv::ast_ty_to_ty(self, ast_ty) } } @@ -437,6 +436,11 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { None } + fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>) + -> Option<&'tcx ty::Region> { + None + } + fn ty_infer(&self, span: Span) -> Ty<'tcx> { struct_span_err!( self.tcx().sess, @@ -626,7 +630,7 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, field: &hir::StructField, ty_f: &'tcx ty::FieldDef) { - let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &field.ty); + let tt = ccx.icx(struct_predicates).to_ty(&field.ty); ccx.tcx.item_types.borrow_mut().insert(ty_f.did, tt); let def_id = ccx.tcx.hir.local_def_id(field.id); @@ -636,11 +640,8 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: AssociatedItemContainer, id: ast::NodeId, sig: &hir::MethodSig, - untransformed_rcvr_ty: Ty<'tcx>, - body: Option, rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) { let def_id = ccx.tcx.hir.local_def_id(id); let ty_generics = generics_of_def_id(ccx, def_id); @@ -648,18 +649,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ty_generic_predicates = ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false); - let anon_scope = match container { - ImplContainer(_) => Some(AnonTypeScope::new(def_id)), - TraitContainer(_) => None - }; - let assoc_item = ccx.tcx.associated_item(def_id); - let self_value_ty = if assoc_item.method_has_self_argument { - Some(untransformed_rcvr_ty) - } else { - None - }; - let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - sig, self_value_ty, body, anon_scope); + let fty = AstConv::ty_of_fn(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), + sig.unsafety, sig.abi, &sig.decl); let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), ccx.tcx.hir.span(id), def_id); @@ -765,7 +756,6 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { hir::ItemDefaultImpl(_, ref ast_trait_ref) => { let trait_ref = AstConv::instantiate_mono_trait_ref(&ccx.icx(&()), - &ExplicitRscope, ast_trait_ref, tcx.mk_self_type()); @@ -787,12 +777,11 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { debug!("convert: impl_bounds={:?}", ty_predicates); - let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &selfty); + let selfty = ccx.icx(&ty_predicates).to_ty(&selfty); tcx.item_types.borrow_mut().insert(def_id, selfty); let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| { AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), - &ExplicitRscope, ast_trait_ref, selfty) }); @@ -858,8 +847,7 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) { hir::TraitItemKind::Const(ref ty, _) => { let const_def_id = ccx.tcx.hir.local_def_id(trait_item.id); generics_of_def_id(ccx, const_def_id); - let ty = ccx.icx(&trait_predicates) - .to_ty(&ExplicitRscope, &ty); + let ty = ccx.icx(&trait_predicates).to_ty(&ty); tcx.item_types.borrow_mut().insert(const_def_id, ty); convert_associated_const(ccx, TraitContainer(trait_def_id), trait_item.id, ty); @@ -870,20 +858,14 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) { generics_of_def_id(ccx, type_def_id); let typ = opt_ty.as_ref().map({ - |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty) + |ty| ccx.icx(&trait_predicates).to_ty(&ty) }); convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ); } - hir::TraitItemKind::Method(ref sig, ref method) => { - let body = match *method { - hir::TraitMethod::Required(_) => None, - hir::TraitMethod::Provided(body) => Some(body) - }; - convert_method(ccx, TraitContainer(trait_def_id), - trait_item.id, sig, tcx.mk_self_type(), - body, &trait_predicates); + hir::TraitItemKind::Method(ref sig, _) => { + convert_method(ccx, trait_item.id, sig, &trait_predicates); } } } @@ -896,14 +878,12 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { let impl_def_id = tcx.hir.get_parent_did(impl_item.id); let impl_predicates = tcx.item_predicates(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); - let impl_self_ty = tcx.item_type(impl_def_id); match impl_item.node { hir::ImplItemKind::Const(ref ty, _) => { let const_def_id = ccx.tcx.hir.local_def_id(impl_item.id); generics_of_def_id(ccx, const_def_id); - let ty = ccx.icx(&impl_predicates) - .to_ty(&ExplicitRscope, &ty); + let ty = ccx.icx(&impl_predicates).to_ty(&ty); tcx.item_types.borrow_mut().insert(const_def_id, ty); convert_associated_const(ccx, ImplContainer(impl_def_id), impl_item.id, ty); @@ -918,15 +898,13 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { "associated types are not allowed in inherent impls"); } - let typ = ccx.icx(&impl_predicates).to_ty(&ExplicitRscope, ty); + let typ = ccx.icx(&impl_predicates).to_ty(ty); convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ)); } - hir::ImplItemKind::Method(ref sig, body) => { - convert_method(ccx, ImplContainer(impl_def_id), - impl_item.id, sig, impl_self_ty, - Some(body), &impl_predicates); + hir::ImplItemKind::Method(ref sig, _) => { + convert_method(ccx, impl_item.id, sig, &impl_predicates); } } } @@ -1197,7 +1175,6 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, self_param_ty, bounds, SizedByDefault::No, - None, item.span); let superbounds1 = superbounds1.predicates(tcx, self_param_ty); @@ -1334,7 +1311,6 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) assoc_ty, bounds, SizedByDefault::Yes, - None, trait_item.span); bounds.predicates(ccx.tcx, assoc_ty).into_iter() @@ -1429,7 +1405,6 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: tcx.hir.local_def_id(param_id), default_def_id: tcx.hir.local_def_id(parent), default: None, - object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, pure_wrt_drop: false, }; tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); @@ -1471,9 +1446,6 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, name: l.lifetime.name, index: own_start + i as u32, def_id: tcx.hir.local_def_id(l.lifetime.id), - bounds: l.bounds.iter().map(|l| { - ast_region_to_region(tcx, l) - }).collect(), pure_wrt_drop: l.pure_wrt_drop, } }).collect::>(); @@ -1482,7 +1454,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let type_start = own_start + regions.len() as u32; let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| { let i = type_start + i as u32; - get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults) + get_or_create_type_parameter_def(ccx, i, p, allow_defaults) }); let mut types: Vec<_> = opt_self.into_iter().chain(types).collect(); @@ -1497,24 +1469,11 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: def_id, default_def_id: parent_def_id.unwrap(), default: None, - object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, pure_wrt_drop: false, })); }); } - // Debugging aid. - if tcx.has_attr(def_id, "rustc_object_lifetime_default") { - let object_lifetime_default_reprs: String = - types.iter().map(|t| { - match t.object_lifetime_default { - ty::ObjectLifetimeDefault::Specific(r) => r.to_string(), - d => format!("{:?}", d), - } - }).collect::>().join(","); - tcx.sess.span_err(tcx.hir.span(node_id), &object_lifetime_default_reprs); - } - tcx.alloc_generics(ty::Generics { parent: parent_def_id, parent_regions: parent_regions, @@ -1545,16 +1504,15 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, NodeItem(item) => { match item.node { ItemStatic(ref t, ..) | ItemConst(ref t, _) => { - ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t) + ccx.icx(&()).to_ty(&t) } - ItemFn(ref decl, unsafety, _, abi, ref generics, body) => { - let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl, - body, Some(AnonTypeScope::new(def_id))); + ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { + let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); ccx.tcx.mk_fn_def(def_id, substs, tofd) } ItemTy(ref t, ref generics) => { - ccx.icx(generics).to_ty(&ExplicitRscope, &t) + ccx.icx(generics).to_ty(&t) } ItemEnum(ref ei, ref generics) => { let def = convert_enum_def(ccx, item, ei); @@ -1595,7 +1553,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn_decl, generics, abi) } ForeignItemStatic(ref t, _) => { - ccx.icx(&()).to_ty(&ExplicitRscope, t) + ccx.icx(&()).to_ty(t) } } } @@ -1765,7 +1723,7 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, name: param.lifetime.name })); for bound in ¶m.bounds { - let bound_region = ast_region_to_region(ccx.tcx, bound); + let bound_region = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None); let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); predicates.push(outlives.to_predicate()); } @@ -1781,7 +1739,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, param_ty, ¶m.bounds, SizedByDefault::Yes, - None, param.span); predicates.extend(bounds.predicates(ccx.tcx, param_ty)); } @@ -1792,7 +1749,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, match predicate { &hir::WherePredicate::BoundPredicate(ref bound_pred) => { let ty = AstConv::ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)), - &ExplicitRscope, &bound_pred.bounded_ty); for bound in bound_pred.bounds.iter() { @@ -1803,7 +1759,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let trait_ref = AstConv::instantiate_poly_trait_ref(&ccx.icx(&(base_predicates, ast_generics)), - &ExplicitRscope, poly_trait_ref, ty, &mut projections); @@ -1816,7 +1771,9 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } &hir::TyParamBound::RegionTyParamBound(ref lifetime) => { - let region = ast_region_to_region(tcx, lifetime); + let region = AstConv::ast_region_to_region(&ccx.icx(&()), + lifetime, + None); let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); predicates.push(ty::Predicate::TypeOutlives(pred)) } @@ -1825,19 +1782,16 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } &hir::WherePredicate::RegionPredicate(ref region_pred) => { - let r1 = ast_region_to_region(tcx, ®ion_pred.lifetime); + let r1 = AstConv::ast_region_to_region(&ccx.icx(&()), ®ion_pred.lifetime, None); for bound in ®ion_pred.bounds { - let r2 = ast_region_to_region(tcx, bound); + let r2 = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None); let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); predicates.push(ty::Predicate::RegionOutlives(pred)) } } - &hir::WherePredicate::EqPredicate(ref eq_pred) => { + &hir::WherePredicate::EqPredicate(..) => { // FIXME(#20041) - span_bug!(eq_pred.span, - "Equality constraints are not yet \ - implemented (#20041)") } } } @@ -1849,7 +1803,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - ast_generics: &hir::Generics, index: u32, param: &hir::TyParam, allow_defaults: bool) @@ -1862,11 +1815,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } let default = - param.default.as_ref().map(|def| ccx.icx(&()).to_ty(&ExplicitRscope, def)); - - let object_lifetime_default = - compute_object_lifetime_default(ccx, param.id, - ¶m.bounds, &ast_generics.where_clause); + param.default.as_ref().map(|def| ccx.icx(&()).to_ty(def)); let parent = tcx.hir.get_parent(param.id); @@ -1887,7 +1836,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, def_id: ccx.tcx.hir.local_def_id(param.id), default_def_id: ccx.tcx.hir.local_def_id(parent), default: default, - object_lifetime_default: object_lifetime_default, pure_wrt_drop: param.pure_wrt_drop, }; @@ -1902,75 +1850,6 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, def } -/// Scan the bounds and where-clauses on a parameter to extract bounds -/// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`. -/// This runs as part of computing the minimal type scheme, so we -/// intentionally avoid just asking astconv to convert all the where -/// clauses into a `ty::Predicate`. This is because that could induce -/// artificial cycles. -fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - param_id: ast::NodeId, - param_bounds: &[hir::TyParamBound], - where_clause: &hir::WhereClause) - -> ty::ObjectLifetimeDefault<'tcx> -{ - let inline_bounds = from_bounds(ccx, param_bounds); - let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates); - let all_bounds: FxHashSet<_> = inline_bounds.into_iter() - .chain(where_bounds) - .collect(); - return if all_bounds.len() > 1 { - ty::ObjectLifetimeDefault::Ambiguous - } else if all_bounds.len() == 0 { - ty::ObjectLifetimeDefault::BaseDefault - } else { - ty::ObjectLifetimeDefault::Specific( - all_bounds.into_iter().next().unwrap()) - }; - - fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - bounds: &[hir::TyParamBound]) - -> Vec<&'tcx ty::Region> - { - bounds.iter() - .filter_map(|bound| { - match *bound { - hir::TraitTyParamBound(..) => - None, - hir::RegionTyParamBound(ref lifetime) => - Some(ast_region_to_region(ccx.tcx, lifetime)), - } - }) - .collect() - } - - fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, - param_id: ast::NodeId, - predicates: &[hir::WherePredicate]) - -> Vec<&'tcx ty::Region> - { - predicates.iter() - .flat_map(|predicate| { - match *predicate { - hir::WherePredicate::BoundPredicate(ref data) => { - if data.bound_lifetimes.is_empty() && - is_param(ccx.tcx, &data.bounded_ty, param_id) - { - from_bounds(ccx, &data.bounds).into_iter() - } else { - Vec::new().into_iter() - } - } - hir::WherePredicate::RegionPredicate(..) | - hir::WherePredicate::EqPredicate(..) => { - Vec::new().into_iter() - } - } - }) - .collect() - } -} - pub enum SizedByDefault { Yes, No, } /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or @@ -1980,28 +1859,33 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, param_ty: ty::Ty<'tcx>, ast_bounds: &[hir::TyParamBound], sized_by_default: SizedByDefault, - anon_scope: Option, span: Span) -> Bounds<'tcx> { - let tcx = astconv.tcx(); - let PartitionedBounds { - trait_bounds, - region_bounds - } = partition_bounds(&ast_bounds); + let mut region_bounds = vec![]; + let mut trait_bounds = vec![]; + for ast_bound in ast_bounds { + match *ast_bound { + hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => { + trait_bounds.push(b); + } + hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {} + hir::RegionTyParamBound(ref l) => { + region_bounds.push(l); + } + } + } let mut projection_bounds = vec![]; - let rscope = MaybeWithAnonTypes::new(ExplicitRscope, anon_scope); let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| { - astconv.instantiate_poly_trait_ref(&rscope, - bound, + astconv.instantiate_poly_trait_ref(bound, param_ty, &mut projection_bounds) }).collect(); let region_bounds = region_bounds.into_iter().map(|r| { - ast_region_to_region(tcx, r) + astconv.ast_region_to_region(r, None) }).collect(); trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); @@ -2033,8 +1917,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, match *bound { hir::TraitTyParamBound(ref tr, hir::TraitBoundModifier::None) => { let mut projections = Vec::new(); - let pred = astconv.instantiate_poly_trait_ref(&ExplicitRscope, - tr, + let pred = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut projections); projections.into_iter() @@ -2043,7 +1926,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, .collect() } hir::RegionTyParamBound(ref lifetime) => { - let region = ast_region_to_region(astconv.tcx(), lifetime); + let region = astconv.ast_region_to_region(lifetime, None); let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region)); vec![ty::Predicate::TypeOutlives(pred)] } @@ -2061,18 +1944,7 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( abi: abi::Abi) -> Ty<'tcx> { - let rb = BindingRscope::new(); - let input_tys = decl.inputs - .iter() - .map(|a| AstConv::ty_of_arg(&ccx.icx(ast_generics), &rb, a, None)) - .collect::>(); - - let output = match decl.output { - hir::Return(ref ty) => - AstConv::ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &ty), - hir::DefaultReturn(..) => - ccx.tcx.mk_nil(), - }; + let fty = AstConv::ty_of_fn(&ccx.icx(ast_generics), hir::Unsafety::Unsafe, abi, decl); // feature gate SIMD types in FFI, since I (huonw) am not sure the // ABIs are handled at all correctly. @@ -2088,27 +1960,23 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( .emit(); } }; - for (input, ty) in decl.inputs.iter().zip(&input_tys) { + for (input, ty) in decl.inputs.iter().zip(*fty.sig.inputs().skip_binder()) { check(&input, ty) } if let hir::Return(ref ty) = decl.output { - check(&ty, output) + check(&ty, *fty.sig.output().skip_binder()) } } let id = ccx.tcx.hir.as_local_node_id(def_id).unwrap(); let substs = mk_item_substs(&ccx.icx(ast_generics), ccx.tcx.hir.span(id), def_id); - ccx.tcx.mk_fn_def(def_id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy { - abi: abi, - unsafety: hir::Unsafety::Unsafe, - sig: ty::Binder(ccx.tcx.mk_fn_sig(input_tys.into_iter(), output, decl.variadic)), - })) + ccx.tcx.mk_fn_def(def_id, substs, fty) } -pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, - span: Span, - def_id: DefId) - -> &'tcx Substs<'tcx> { +fn mk_item_substs<'tcx>(astconv: &AstConv<'tcx, 'tcx>, + span: Span, + def_id: DefId) + -> &'tcx Substs<'tcx> { let tcx = astconv.tcx(); // FIXME(eddyb) Do this request from Substs::for_item in librustc. if let Err(ErrorReported) = astconv.get_generics(span, def_id) { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 6d943f3ca2ef6..c41d40b41e42a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1412,85 +1412,19 @@ fn main() { ``` "##, -E0106: r##" -This error indicates that a lifetime is missing from a type. If it is an error -inside a function signature, the problem may be with failing to adhere to the -lifetime elision rules (see below). - -Here are some simple examples of where you'll run into this error: - -```compile_fail,E0106 -struct Foo { x: &bool } // error -struct Foo<'a> { x: &'a bool } // correct - -enum Bar { A(u8), B(&bool), } // error -enum Bar<'a> { A(u8), B(&'a bool), } // correct - -type MyStr = &str; // error -type MyStr<'a> = &'a str; // correct -``` - -Lifetime elision is a special, limited kind of inference for lifetimes in -function signatures which allows you to leave out lifetimes in certain cases. -For more background on lifetime elision see [the book][book-le]. - -The lifetime elision rules require that any function signature with an elided -output lifetime must either have - - - exactly one input lifetime - - or, multiple input lifetimes, but the function must also be a method with a - `&self` or `&mut self` receiver - -In the first case, the output lifetime is inferred to be the same as the unique -input lifetime. In the second case, the lifetime is instead inferred to be the -same as the lifetime on `&self` or `&mut self`. - -Here are some examples of elision errors: - -```compile_fail,E0106 -// error, no input lifetimes -fn foo() -> &str { } - -// error, `x` and `y` have distinct lifetimes inferred -fn bar(x: &str, y: &str) -> &str { } - -// error, `y`'s lifetime is inferred to be distinct from `x`'s -fn baz<'a>(x: &'a str, y: &str) -> &str { } -``` - -[book-le]: https://doc.rust-lang.org/nightly/book/lifetimes.html#lifetime-elision -"##, - E0107: r##" This error means that an incorrect number of lifetime parameters were provided -for a type (like a struct or enum) or trait. - -Some basic examples include: +for a type (like a struct or enum) or trait: ```compile_fail,E0107 -struct Foo<'a>(&'a str); +struct Foo<'a, 'b>(&'a str, &'b str); enum Bar { A, B, C } struct Baz<'a> { - foo: Foo, // error: expected 1, found 0 + foo: Foo<'a>, // error: expected 2, found 1 bar: Bar<'a>, // error: expected 0, found 1 } ``` - -Here's an example that is currently an error, but may work in a future version -of Rust: - -```compile_fail,E0107 -struct Foo<'a>(&'a str); - -trait Quux { } -impl Quux for Foo { } // error: expected 1, found 0 -``` - -Lifetime elision in implementation headers was part of the lifetime elision -RFC. It is, however, [currently unimplemented][iss15872]. - -[iss15872]: https://github.com/rust-lang/rust/issues/15872 "##, E0116: r##" @@ -4162,7 +4096,6 @@ register_diagnostics! { // E0222, // Error code E0045 (variadic function must have C calling // convention) duplicate E0224, // at least one non-builtin train is required for an object type - E0226, // only a single explicit lifetime bound is permitted E0227, // ambiguous lifetime bound, explicit lifetime bound required E0228, // explicit lifetime bound required E0231, // only named substitution parameters are allowed diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0e7daa03404c5..4ed116b88f6d9 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,6 +77,7 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] +#![feature(loop_break_value)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -126,7 +127,6 @@ pub mod diagnostics; pub mod check; pub mod check_unused; -mod rscope; mod astconv; pub mod collect; mod constrained_type_params; diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs deleted file mode 100644 index 3f5e443a20a68..0000000000000 --- a/src/librustc_typeck/rscope.rs +++ /dev/null @@ -1,393 +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. - -use rustc::hir; -use rustc::hir::def_id::DefId; -use rustc::ty; -use rustc::ty::subst::Substs; - -use astconv::AstConv; - -use std::cell::Cell; -use syntax_pos::Span; - -#[derive(Clone)] -pub struct ElisionFailureInfo { - /// Where we can find the argument pattern. - pub parent: Option, - /// The index of the argument in the original definition. - pub index: usize, - pub lifetime_count: usize, - pub have_bound_regions: bool -} - -pub type ElidedLifetime = Result>>; - -/// Defines strategies for handling regions that are omitted. For -/// example, if one writes the type `&Foo`, then the lifetime of -/// this reference has been omitted. When converting this -/// type, the generic functions in astconv will invoke `anon_regions` -/// on the provided region-scope to decide how to translate this -/// omitted region. -/// -/// It is not always legal to omit regions, therefore `anon_regions` -/// can return `Err(())` to indicate that this is not a scope in which -/// regions can legally be omitted. -pub trait RegionScope { - fn anon_regions(&self, - span: Span, - count: usize) - -> Result, Option>>; - - /// If an object omits any explicit lifetime bound, and none can - /// be derived from the object traits, what should we use? If - /// `None` is returned, an explicit annotation is required. - fn object_lifetime_default(&self, span: Span) -> Option; - - /// The "base" default is the initial default for a scope. This is - /// 'static except for in fn bodies, where it is a fresh inference - /// variable. You shouldn't call this except for as part of - /// computing `object_lifetime_default` (in particular, in legacy - /// modes, it may not be relevant). - fn base_object_lifetime_default(&self, span: Span) -> ty::Region; - - /// If this scope allows anonymized types, return the generics in - /// scope, that anonymized types will close over. For example, - /// if you have a function like: - /// - /// fn foo<'a, T>() -> impl Trait { ... } - /// - /// then, for the rscope that is used when handling the return type, - /// `anon_type_scope()` would return a `Some(AnonTypeScope {...})`, - /// on which `.fresh_substs(...)` can be used to obtain identity - /// Substs for `'a` and `T`, to track them in `TyAnon`. This property - /// is controlled by the region scope because it's fine-grained enough - /// to allow restriction of anonymized types to the syntactical extent - /// of a function's return type. - fn anon_type_scope(&self) -> Option { - None - } -} - -#[derive(Copy, Clone)] -pub struct AnonTypeScope { - enclosing_item: DefId -} - -impl<'gcx: 'tcx, 'tcx> AnonTypeScope { - pub fn new(enclosing_item: DefId) -> AnonTypeScope { - AnonTypeScope { - enclosing_item: enclosing_item - } - } - - pub fn fresh_substs(&self, astconv: &AstConv<'gcx, 'tcx>, span: Span) - -> &'tcx Substs<'tcx> { - use collect::mk_item_substs; - - mk_item_substs(astconv, span, self.enclosing_item) - } -} - -/// A scope wrapper which optionally allows anonymized types. -#[derive(Copy, Clone)] -pub struct MaybeWithAnonTypes { - base_scope: R, - anon_scope: Option -} - -impl MaybeWithAnonTypes { - pub fn new(base_scope: R, anon_scope: Option) -> Self { - MaybeWithAnonTypes { - base_scope: base_scope, - anon_scope: anon_scope - } - } -} - -impl RegionScope for MaybeWithAnonTypes { - fn object_lifetime_default(&self, span: Span) -> Option { - self.base_scope.object_lifetime_default(span) - } - - fn anon_regions(&self, - span: Span, - count: usize) - -> Result, Option>> { - self.base_scope.anon_regions(span, count) - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { - self.base_scope.base_object_lifetime_default(span) - } - - fn anon_type_scope(&self) -> Option { - self.anon_scope - } -} - -// A scope in which all regions must be explicitly named. This is used -// for types that appear in structs and so on. -#[derive(Copy, Clone)] -pub struct ExplicitRscope; - -impl RegionScope for ExplicitRscope { - fn anon_regions(&self, - _span: Span, - _count: usize) - -> Result, Option>> { - Err(None) - } - - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { - ty::ReStatic - } -} - -// Same as `ExplicitRscope`, but provides some extra information for diagnostics -pub struct UnelidableRscope(Option>); - -impl UnelidableRscope { - pub fn new(v: Option>) -> UnelidableRscope { - UnelidableRscope(v) - } -} - -impl RegionScope for UnelidableRscope { - fn anon_regions(&self, - _span: Span, - _count: usize) - -> Result, Option>> { - let UnelidableRscope(ref v) = *self; - Err(v.clone()) - } - - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { - ty::ReStatic - } -} - -// A scope in which omitted anonymous region defaults to -// `default`. This is used after the `->` in function signatures. The -// latter use may go away. Note that object-lifetime defaults work a -// bit differently, as specified in RFC #599. -pub struct ElidableRscope { - default: ty::Region, -} - -impl ElidableRscope { - pub fn new(r: ty::Region) -> ElidableRscope { - ElidableRscope { default: r } - } -} - -impl RegionScope for ElidableRscope { - fn object_lifetime_default(&self, span: Span) -> Option { - // Per RFC #599, object-lifetimes default to 'static unless - // overridden by context, and this takes precedence over - // lifetime elision. - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { - ty::ReStatic - } - - fn anon_regions(&self, - _span: Span, - count: usize) - -> Result, Option>> - { - Ok(vec![self.default; count]) - } -} - -/// A scope that behaves as an ElidabeRscope with a `'static` default region -/// that should also warn if the `static_in_const` feature is unset. -#[derive(Copy, Clone)] -pub struct StaticRscope<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>, -} - -impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> { - /// create a new StaticRscope from a reference to the `TyCtxt` - pub fn new(tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>) -> Self { - StaticRscope { tcx: tcx } - } -} - -impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> { - fn anon_regions(&self, - span: Span, - count: usize) - -> Result, Option>> { - if !self.tcx.sess.features.borrow().static_in_const { - self.tcx - .sess - .struct_span_err(span, - "this needs a `'static` lifetime or the \ - `static_in_const` feature, see #35897") - .emit(); - } - Ok(vec![ty::ReStatic; count]) - } - - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { - ty::ReStatic - } -} - -/// A scope in which we generate anonymous, late-bound regions for -/// omitted regions. This occurs in function signatures. -pub struct BindingRscope { - anon_bindings: Cell, -} - -impl BindingRscope { - pub fn new() -> BindingRscope { - BindingRscope { - anon_bindings: Cell::new(0), - } - } - - fn next_region(&self) -> ty::Region { - let idx = self.anon_bindings.get(); - self.anon_bindings.set(idx + 1); - ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(idx)) - } -} - -impl RegionScope for BindingRscope { - fn object_lifetime_default(&self, span: Span) -> Option { - // Per RFC #599, object-lifetimes default to 'static unless - // overridden by context, and this takes precedence over the - // binding defaults in a fn signature. - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { - ty::ReStatic - } - - fn anon_regions(&self, - _: Span, - count: usize) - -> Result, Option>> - { - Ok((0..count).map(|_| self.next_region()).collect()) - } -} - -/// A scope which overrides the default object lifetime but has no other effect. -pub struct ObjectLifetimeDefaultRscope<'r> { - base_scope: &'r (RegionScope+'r), - default: ty::ObjectLifetimeDefault<'r>, -} - -impl<'r> ObjectLifetimeDefaultRscope<'r> { - pub fn new(base_scope: &'r (RegionScope+'r), - default: ty::ObjectLifetimeDefault<'r>) - -> ObjectLifetimeDefaultRscope<'r> - { - ObjectLifetimeDefaultRscope { - base_scope: base_scope, - default: default, - } - } -} - -impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { - fn object_lifetime_default(&self, span: Span) -> Option { - match self.default { - ty::ObjectLifetimeDefault::Ambiguous => - None, - - ty::ObjectLifetimeDefault::BaseDefault => - // NB: This behavior changed in Rust 1.3. - Some(self.base_object_lifetime_default(span)), - - ty::ObjectLifetimeDefault::Specific(r) => - Some(*r), - } - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { - self.base_scope.base_object_lifetime_default(span) - } - - fn anon_regions(&self, - span: Span, - count: usize) - -> Result, Option>> - { - self.base_scope.anon_regions(span, count) - } - - fn anon_type_scope(&self) -> Option { - self.base_scope.anon_type_scope() - } -} - -/// A scope which simply shifts the Debruijn index of other scopes -/// to account for binding levels. -pub struct ShiftedRscope<'r> { - base_scope: &'r (RegionScope+'r) -} - -impl<'r> ShiftedRscope<'r> { - pub fn new(base_scope: &'r (RegionScope+'r)) -> ShiftedRscope<'r> { - ShiftedRscope { base_scope: base_scope } - } -} - -impl<'r> RegionScope for ShiftedRscope<'r> { - fn object_lifetime_default(&self, span: Span) -> Option { - self.base_scope.object_lifetime_default(span) - .map(|r| ty::fold::shift_region(r, 1)) - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { - ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1) - } - - fn anon_regions(&self, - span: Span, - count: usize) - -> Result, Option>> - { - match self.base_scope.anon_regions(span, count) { - Ok(mut v) => { - for r in &mut v { - *r = ty::fold::shift_region(*r, 1); - } - Ok(v) - } - Err(errs) => { - Err(errs) - } - } - } - - fn anon_type_scope(&self) -> Option { - self.base_scope.anon_type_scope() - } -} diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 55033330a4490..40e82959336de 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -154,7 +154,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let tcx = self.terms_cx.tcx; assert!(is_lifetime(&tcx.hir, param_id)); match tcx.named_region_map.defs.get(¶m_id) { - Some(&rl::DefEarlyBoundRegion(_, lifetime_decl_id)) => lifetime_decl_id, + Some(&rl::Region::EarlyBound(_, lifetime_decl_id)) => lifetime_decl_id, Some(_) => bug!("should not encounter non early-bound cases"), // The lookup should only fail when `param_id` is @@ -329,7 +329,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_mt(generics, mt, variance); } - ty::TyBox(typ) | ty::TyArray(typ, _) | ty::TySlice(typ) => { self.add_constraints_from_ty(generics, typ, variance); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index eedca0ffb6327..cdb24a56367fc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -28,7 +28,7 @@ use syntax::symbol::keywords; use syntax_pos::{self, DUMMY_SP, Pos}; use rustc::middle::privacy::AccessLevels; -use rustc::middle::resolve_lifetime::DefRegion::*; +use rustc::middle::resolve_lifetime as rl; use rustc::middle::lang_items; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -765,9 +765,9 @@ impl Clean for hir::Lifetime { fn clean(&self, cx: &DocContext) -> Lifetime { let def = cx.tcx.named_region_map.defs.get(&self.id).cloned(); match def { - Some(DefEarlyBoundRegion(_, node_id)) | - Some(DefLateBoundRegion(_, node_id)) | - Some(DefFreeRegion(_, node_id)) => { + Some(rl::Region::EarlyBound(_, node_id)) | + Some(rl::Region::LateBound(_, node_id)) | + Some(rl::Region::Free(_, node_id)) => { if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() { return lt; } @@ -794,7 +794,7 @@ impl Clean for hir::LifetimeDef { } } -impl<'tcx> Clean for ty::RegionParameterDef<'tcx> { +impl Clean for ty::RegionParameterDef { fn clean(&self, _: &DocContext) -> Lifetime { Lifetime(self.name.to_string()) } @@ -842,8 +842,11 @@ impl Clean for hir::WherePredicate { } } - hir::WherePredicate::EqPredicate(_) => { - unimplemented!() // FIXME(#20041) + hir::WherePredicate::EqPredicate(ref wrp) => { + WherePredicate::EqPredicate { + lhs: wrp.lhs_ty.clean(cx), + rhs: wrp.rhs_ty.clean(cx) + } } } } @@ -967,11 +970,6 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, Some(tp.clean(cx)) } }).collect::>(); - let stripped_lifetimes = gens.regions.iter().map(|rp| { - let mut srp = rp.clone(); - srp.bounds = Vec::new(); - srp.clean(cx) - }).collect::>(); let mut where_predicates = preds.predicates.to_vec().clean(cx); @@ -1014,7 +1012,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, Generics { type_params: simplify::ty_params(stripped_typarams), - lifetimes: stripped_lifetimes, + lifetimes: gens.regions.clean(cx), where_predicates: simplify::where_clauses(cx, where_predicates), } } @@ -1685,9 +1683,15 @@ impl Clean for hir::Ty { match self.node { TyNever => Never, TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)), - TyRptr(ref l, ref m) => - BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx), - type_: box m.ty.clean(cx)}, + TyRptr(ref l, ref m) => { + let lifetime = if l.is_elided() { + None + } else { + Some(l.clean(cx)) + }; + BorrowedRef {lifetime: lifetime, mutability: m.mutbl.clean(cx), + type_: box m.ty.clean(cx)} + } TySlice(ref ty) => Vector(box ty.clean(cx)), TyArray(ref ty, length) => { use rustc_const_eval::eval_length; @@ -1726,7 +1730,9 @@ impl Clean for hir::Ty { for (i, lt_param) in generics.lifetimes.iter().enumerate() { if let Some(lt) = provided_params.lifetimes().get(i).cloned() .cloned() { - lt_substs.insert(lt_param.lifetime.id, lt.clean(cx)); + if !lt.is_elided() { + lt_substs.insert(lt_param.lifetime.id, lt.clean(cx)); + } } } return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx)); @@ -1765,20 +1771,20 @@ impl Clean for hir::Ty { trait_: box resolve_type(cx, trait_path.clean(cx), self.id) } } - TyTraitObject(ref bounds) => { - let lhs_ty = bounds[0].clean(cx); - match lhs_ty { - TraitBound(poly_trait, ..) => { - match poly_trait.trait_ { - ResolvedPath { path, typarams: None, did, is_generic } => { - ResolvedPath { - path: path, - typarams: Some(bounds[1..].clean(cx)), - did: did, - is_generic: is_generic, - } - } - _ => Infer // shouldn't happen + TyTraitObject(ref bounds, ref lifetime) => { + match bounds[0].clean(cx).trait_ { + ResolvedPath { path, typarams: None, did, is_generic } => { + let mut bounds: Vec<_> = bounds[1..].iter().map(|bound| { + TraitBound(bound.clean(cx), hir::TraitBoundModifier::None) + }).collect(); + if !lifetime.is_elided() { + bounds.push(RegionBound(lifetime.clean(cx))); + } + ResolvedPath { + path: path, + typarams: Some(bounds), + did: did, + is_generic: is_generic, } } _ => Infer // shouldn't happen @@ -1802,10 +1808,6 @@ impl<'tcx> Clean for ty::Ty<'tcx> { ty::TyUint(uint_ty) => Primitive(uint_ty.into()), ty::TyFloat(float_ty) => Primitive(float_ty.into()), ty::TyStr => Primitive(PrimitiveType::Str), - ty::TyBox(t) => { - let box_did = cx.tcx.lang_items.owned_box(); - lang_struct(cx, box_did, t, "Box", Unique) - } ty::TySlice(ty) => Vector(box ty.clean(cx)), ty::TyArray(ty, i) => FixedVector(box ty.clean(cx), format!("{}", i)), @@ -2239,7 +2241,11 @@ impl Clean for hir::PathParameters { match *self { hir::AngleBracketedParameters(ref data) => { PathParameters::AngleBracketed { - lifetimes: data.lifetimes.clean(cx), + lifetimes: if data.lifetimes.iter().all(|lt| lt.is_elided()) { + vec![] + } else { + data.lifetimes.clean(cx) + }, types: data.types.clean(cx), bindings: data.bindings.clean(cx) } @@ -2878,33 +2884,6 @@ impl Clean for attr::Deprecation { } } -fn lang_struct(cx: &DocContext, did: Option, - t: ty::Ty, name: &str, - fallback: fn(Box) -> Type) -> Type { - let did = match did { - Some(did) => did, - None => return fallback(box t.clean(cx)), - }; - inline::record_extern_fqn(cx, did, TypeKind::Struct); - ResolvedPath { - typarams: None, - did: did, - path: Path { - global: false, - def: Def::Err, - segments: vec![PathSegment { - name: name.to_string(), - params: PathParameters::AngleBracketed { - lifetimes: vec![], - types: vec![t.clean(cx)], - bindings: vec![] - } - }], - }, - is_generic: false, - } -} - /// An equality constraint on an associated type, e.g. `A=Bar` in `Foo` #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug)] pub struct TypeBinding { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index f2427008a7d45..442a2f4074215 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -237,8 +237,9 @@ pub fn render(w: &mut fmt::Formatter, 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() { + let rendered = if lang.is_null() || origtext.is_empty() { false } else { let rlang = (*lang).as_bytes(); @@ -659,8 +660,6 @@ mod tests { t("no_run", false, true, false, true, false, false, Vec::new()); t("test_harness", false, false, false, true, true, false, Vec::new()); t("compile_fail", false, true, false, true, false, true, Vec::new()); - t("E0450", false, false, false, true, false, false, - vec!["E0450".to_owned()]); t("{.no_run .example}", false, true, false, true, false, false, Vec::new()); t("{.sh .should_panic}", true, false, false, true, false, false, Vec::new()); t("{.example .rust}", false, false, false, true, false, false, Vec::new()); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 52257653405e0..40eb7e5ab78c3 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1806,12 +1806,13 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, String::new() }; - let mut unsafety_flag = ""; - if let clean::FunctionItem(ref func) = myitem.inner { - if func.unsafety == hir::Unsafety::Unsafe { - unsafety_flag = ""; + let unsafety_flag = match myitem.inner { + clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func) + if func.unsafety == hir::Unsafety::Unsafe => { + "" } - } + _ => "", + }; let doc_value = myitem.doc_value().unwrap_or(""); write!(w, " diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 1f224cac9e91f..ab0ac02fd88f1 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -429,8 +429,12 @@ impl Collector { should_panic: testing::ShouldPanic::No, }, testfn: testing::DynTestFn(box move |()| { + let panic = io::set_panic(None); + let print = io::set_print(None); match { rustc_driver::in_rustc_thread(move || { + io::set_panic(panic); + io::set_print(print); runtest(&test, &cratename, cfgs, diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index ba9bf2b86a60f..05cfb6352fbb8 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -11,11 +11,9 @@ //! Implementations of serialization for structures found in libcollections use std::hash::{Hash, BuildHasher}; -use std::mem; use {Decodable, Encodable, Decoder, Encoder}; use std::collections::{LinkedList, VecDeque, BTreeMap, BTreeSet, HashMap, HashSet}; -use collections::enum_set::{EnumSet, CLike}; impl< T: Encodable @@ -128,33 +126,6 @@ impl< } } -impl< - T: Encodable + CLike -> Encodable for EnumSet { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - let mut bits = 0; - for item in self { - bits |= 1 << item.to_usize(); - } - s.emit_usize(bits) - } -} - -impl< - T: Decodable + CLike -> Decodable for EnumSet { - fn decode(d: &mut D) -> Result, D::Error> { - let bits = d.read_usize()?; - let mut set = EnumSet::new(); - for bit in 0..(mem::size_of::()*8) { - if bits & (1 << bit) != 0 { - set.insert(CLike::from_usize(bit)); - } - } - Ok(set) - } -} - impl Encodable for HashMap where K: Encodable + Hash + Eq, V: Encodable, diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 2cfc3924c036e..1cb83fa33da06 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -30,7 +30,6 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(collections)] #![feature(core_intrinsics)] -#![feature(enumset)] #![feature(specialization)] #![feature(staged_api)] #![cfg_attr(test, feature(test))] diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 5e1c3a2851568..a084482170937 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -10,14 +10,15 @@ #![deny(warnings)] -extern crate gcc; +#[macro_use] extern crate build_helper; +extern crate gcc; use std::env; -use std::path::PathBuf; +use std::fs::{self, File}; +use std::path::{Path, PathBuf}; use std::process::Command; - -use build_helper::run; +use build_helper::{run, rerun_if_changed_anything_in_dir, up_to_date}; fn main() { println!("cargo:rustc-cfg=cargobuild"); @@ -66,29 +67,25 @@ fn main() { } fn build_libbacktrace(host: &str, target: &str) { - let src_dir = env::current_dir().unwrap().join("../libbacktrace"); - let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let build_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap()); + let build_dir = PathBuf::from(build_dir).join("libbacktrace"); + let _ = fs::create_dir_all(&build_dir); println!("cargo:rustc-link-lib=static=backtrace"); println!("cargo:rustc-link-search=native={}/.libs", build_dir.display()); - - let mut stack = src_dir.read_dir().unwrap() - .map(|e| e.unwrap()) - .collect::>(); - while let Some(entry) = stack.pop() { - let path = entry.path(); - if entry.file_type().unwrap().is_dir() { - stack.extend(path.read_dir().unwrap().map(|e| e.unwrap())); - } else { - println!("cargo:rerun-if-changed={}", path.display()); - } + let src_dir = env::current_dir().unwrap().join("../libbacktrace"); + rerun_if_changed_anything_in_dir(&src_dir); + let timestamp = build_dir.join("rustbuild.timestamp"); + if up_to_date(&Path::new("build.rs"), ×tamp) && up_to_date(&src_dir, ×tamp) { + return } let compiler = gcc::Config::new().get_compiler(); // only msvc returns None for ar so unwrap is okay let ar = build_helper::cc2ar(compiler.path(), target).unwrap(); - let cflags = compiler.args().iter().map(|s| s.to_str().unwrap()) - .collect::>().join(" "); + let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap()) + .collect::>().join(" "); + cflags.push_str(" -fvisibility=hidden"); run(Command::new("sh") .current_dir(&build_dir) .arg(src_dir.join("configure").to_str().unwrap() @@ -104,8 +101,11 @@ fn build_libbacktrace(host: &str, target: &str) { .env("AR", &ar) .env("RANLIB", format!("{} s", ar.display())) .env("CFLAGS", cflags)); + run(Command::new(build_helper::make(host)) .current_dir(&build_dir) .arg(format!("INCDIR={}", src_dir.display())) .arg("-j").arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"))); + + t!(File::create(×tamp)); } diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 80c64ae860f8f..c3a6b2433ed88 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -222,7 +222,7 @@ fn _var_os(key: &OsStr) -> Option { /// Possible errors from the [`env::var`] function. /// -/// [env::var]: fn.var.html +/// [`env::var`]: fn.var.html #[derive(Debug, PartialEq, Eq, Clone)] #[stable(feature = "env", since = "1.0.0")] pub enum VarError { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index f1dc36ae79335..249627c430cb7 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -404,7 +404,6 @@ impl File { /// # Examples /// /// ``` - /// #![feature(set_permissions_atomic)] /// # fn foo() -> std::io::Result<()> { /// use std::fs::File; /// @@ -415,7 +414,7 @@ impl File { /// # Ok(()) /// # } /// ``` - #[unstable(feature = "set_permissions_atomic", issue="37916")] + #[stable(feature = "set_permissions_atomic", since = "1.16.0")] pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> { self.inner.set_permissions(perm.0) } diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index d186a53311dab..751878c687c01 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -148,8 +148,6 @@ impl SocketAddr { /// # Examples /// /// ``` - /// #![feature(sockaddr_checker)] - /// /// use std::net::{IpAddr, Ipv4Addr, SocketAddr}; /// /// fn main() { @@ -158,7 +156,7 @@ impl SocketAddr { /// assert_eq!(socket.is_ipv6(), false); /// } /// ``` - #[unstable(feature = "sockaddr_checker", issue = "36949")] + #[stable(feature = "sockaddr_checker", since = "1.16.0")] pub fn is_ipv4(&self) -> bool { match *self { SocketAddr::V4(_) => true, @@ -172,8 +170,6 @@ impl SocketAddr { /// # Examples /// /// ``` - /// #![feature(sockaddr_checker)] - /// /// use std::net::{IpAddr, Ipv6Addr, SocketAddr}; /// /// fn main() { @@ -183,7 +179,7 @@ impl SocketAddr { /// assert_eq!(socket.is_ipv6(), true); /// } /// ``` - #[unstable(feature = "sockaddr_checker", issue = "36949")] + #[stable(feature = "sockaddr_checker", since = "1.16.0")] pub fn is_ipv6(&self) -> bool { match *self { SocketAddr::V4(_) => false, diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 05e3d38b17eb1..7803cf728f2e9 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -196,8 +196,6 @@ impl IpAddr { /// # Examples /// /// ``` - /// #![feature(ipaddr_checker)] - /// /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// fn main() { @@ -206,7 +204,7 @@ impl IpAddr { /// false); /// } /// ``` - #[unstable(feature = "ipaddr_checker", issue = "36949")] + #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv4(&self) -> bool { match *self { IpAddr::V4(_) => true, @@ -219,8 +217,6 @@ impl IpAddr { /// # Examples /// /// ``` - /// #![feature(ipaddr_checker)] - /// /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// /// fn main() { @@ -229,7 +225,7 @@ impl IpAddr { /// true); /// } /// ``` - #[unstable(feature = "ipaddr_checker", issue = "36949")] + #[stable(feature = "ipaddr_checker", since = "1.16.0")] pub fn is_ipv6(&self) -> bool { match *self { IpAddr::V4(_) => false, diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index 7ad8d27b48330..fc81cc737d9f0 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -160,6 +160,10 @@ impl OpenOptionsExt for OpenOptions { // casts and rely on manual lowering to `stat` if the raw type is desired. #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { + #[stable(feature = "metadata_ext", since = "1.1.0")] + fn dev(&self) -> u64; + #[stable(feature = "metadata_ext", since = "1.1.0")] + fn ino(&self) -> u64; #[stable(feature = "metadata_ext", since = "1.1.0")] fn mode(&self) -> u32; #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -184,6 +188,12 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for fs::Metadata { + fn dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } fn mode(&self) -> u32 { self.as_inner().as_inner().st_mode as u32 } diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs index d7c05e513f68c..1eef89bf66f74 100644 --- a/src/libstd/sys/unix/backtrace/mod.rs +++ b/src/libstd/sys/unix/backtrace/mod.rs @@ -89,3 +89,14 @@ pub use self::tracing::write; mod tracing; // symbol resolvers: mod printing; + +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "emscripten")))] +pub mod gnu { + use io; + use fs; + use libc::c_char; + + pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { + Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) + } +} diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index a8ed415b7f47f..51e00fc1ab96a 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -13,7 +13,7 @@ use io; use libc::{self, c_int}; use mem; use ptr; -use sys::cvt_r; +use sys::{cvt, cvt_r}; use sys::fd::FileDesc; //////////////////////////////////////////////////////////////////////////////// @@ -29,34 +29,29 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in // 2.6.27, however, and because we support 2.6.18 we must detect this // support dynamically. - if cfg!(target_os = "linux") { + if cfg!(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd")) + { weak! { fn pipe2(*mut c_int, c_int) -> c_int } if let Some(pipe) = pipe2.get() { - match cvt_r(|| unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { - Ok(_) => { - return Ok((AnonPipe(FileDesc::new(fds[0])), - AnonPipe(FileDesc::new(fds[1])))) - } - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} - Err(e) => return Err(e), - } + cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) })?; + return Ok((AnonPipe(FileDesc::new(fds[0])), + AnonPipe(FileDesc::new(fds[1])))); } } - if unsafe { libc::pipe(fds.as_mut_ptr()) == 0 } { - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - Ok((AnonPipe::from_fd(fd0)?, AnonPipe::from_fd(fd1)?)) - } else { - Err(io::Error::last_os_error()) - } + cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; + + let fd0 = FileDesc::new(fds[0]); + let fd1 = FileDesc::new(fds[1]); + fd0.set_cloexec()?; + fd1.set_cloexec()?; + Ok((AnonPipe(fd0), AnonPipe(fd1))) } impl AnonPipe { - pub fn from_fd(fd: FileDesc) -> io::Result { - fd.set_cloexec()?; - Ok(AnonPipe(fd)) - } - pub fn read(&self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 82a44c1c1103b..94aaf439f3d57 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -51,6 +51,10 @@ mod printing; #[path = "printing/gnu.rs"] mod printing; +#[cfg(target_env = "gnu")] +#[path = "backtrace_gnu.rs"] +pub mod gnu; + type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL; diff --git a/src/libstd/sys/windows/backtrace_gnu.rs b/src/libstd/sys/windows/backtrace_gnu.rs new file mode 100644 index 0000000000000..f0d29dd4178d1 --- /dev/null +++ b/src/libstd/sys/windows/backtrace_gnu.rs @@ -0,0 +1,62 @@ +// 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. + +use io; +use sys::c; +use libc::c_char; +use path::PathBuf; +use fs::{OpenOptions, File}; +use sys::ext::fs::OpenOptionsExt; +use sys::handle::Handle; +use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte}; + +fn query_full_process_image_name() -> io::Result { + unsafe { + let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION, + c::FALSE, + c::GetCurrentProcessId())); + fill_utf16_buf(|buf, mut sz| { + if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 { + 0 + } else { + sz + } + }, os2path) + } +} + +fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> { + // We query the current image name, open the file without FILE_SHARE_DELETE so it + // can't be moved and then get the current image name again. If the names are the + // same than we have successfully locked the file + let image_name1 = query_full_process_image_name()?; + let file = OpenOptions::new() + .read(true) + .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE) + .open(&image_name1)?; + let image_name2 = query_full_process_image_name()?; + + if image_name1 != image_name2 { + return Err(io::Error::new(io::ErrorKind::Other, + "executable moved while trying to lock it")); + } + + Ok((image_name1, file)) +} + +// Get the executable filename for libbacktrace +// This returns the path in the ANSI code page and a File which should remain open +// for as long as the path should remain valid +pub fn get_executable_filename() -> io::Result<(Vec, File)> { + let (executable, file) = lock_and_get_executable_filename()?; + let u16_executable = to_u16s(executable.into_os_string())?; + Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS, + &u16_executable, true)?, file)) +} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index dc7b2fc9a6bab..1b29bf73c7aec 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -69,6 +69,7 @@ pub type LPWCH = *mut WCHAR; pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; pub type LPWSADATA = *mut WSADATA; pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; +pub type LPSTR = *mut CHAR; pub type LPWSTR = *mut WCHAR; pub type LPFILETIME = *mut FILETIME; @@ -973,6 +974,14 @@ extern "system" { pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; + pub fn WideCharToMultiByte(CodePage: UINT, + dwFlags: DWORD, + lpWideCharStr: LPCWSTR, + cchWideChar: c_int, + lpMultiByteStr: LPSTR, + cbMultiByte: c_int, + lpDefaultChar: LPCSTR, + lpUsedDefaultChar: LPBOOL) -> c_int; pub fn closesocket(socket: SOCKET) -> c_int; pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, @@ -1178,3 +1187,34 @@ compat_fn! { panic!("rwlocks not available") } } + +#[cfg(target_env = "gnu")] +mod gnu { + use super::*; + + pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400; + + pub const CP_ACP: UINT = 0; + + pub const WC_NO_BEST_FIT_CHARS: DWORD = 0x00000400; + + extern "system" { + pub fn OpenProcess(dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwProcessId: DWORD) -> HANDLE; + } + + compat_fn! { + kernel32: + + pub fn QueryFullProcessImageNameW(_hProcess: HANDLE, + _dwFlags: DWORD, + _lpExeName: LPWSTR, + _lpdwSize: LPDWORD) -> BOOL { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } + } +} + +#[cfg(target_env = "gnu")] +pub use self::gnu::*; diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 0a3221aeae6fa..1419a4af42738 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -99,17 +99,17 @@ impl ExitStatusExt for process::ExitStatus { } /// Windows-specific extensions to the `std::process::Command` builder -#[unstable(feature = "windows_process_extensions", issue = "37827")] +#[stable(feature = "windows_process_extensions", since = "1.16.0")] pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. /// /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx - #[unstable(feature = "windows_process_extensions", issue = "37827")] + #[stable(feature = "windows_process_extensions", since = "1.16.0")] fn creation_flags(&mut self, flags: u32) -> &mut process::Command; } -#[unstable(feature = "windows_process_extensions", issue = "37827")] +#[stable(feature = "windows_process_extensions", since = "1.16.0")] impl CommandExt for process::Command { fn creation_flags(&mut self, flags: u32) -> &mut process::Command { self.as_inner_mut().creation_flags(flags); diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index defc41c5f46a3..4424c6c6136c5 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -10,6 +10,7 @@ #![allow(missing_docs, bad_style)] +use ptr; use ffi::{OsStr, OsString}; use io::{self, ErrorKind}; use os::windows::ffi::{OsStrExt, OsStringExt}; @@ -171,6 +172,52 @@ fn os2path(s: &[u16]) -> PathBuf { PathBuf::from(OsString::from_wide(s)) } +#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename() +fn wide_char_to_multi_byte(code_page: u32, + flags: u32, + s: &[u16], + no_default_char: bool) + -> io::Result> { + unsafe { + let mut size = c::WideCharToMultiByte(code_page, + flags, + s.as_ptr(), + s.len() as i32, + ptr::null_mut(), + 0, + ptr::null(), + ptr::null_mut()); + if size == 0 { + return Err(io::Error::last_os_error()); + } + + let mut buf = Vec::with_capacity(size as usize); + buf.set_len(size as usize); + + let mut used_default_char = c::FALSE; + size = c::WideCharToMultiByte(code_page, + flags, + s.as_ptr(), + s.len() as i32, + buf.as_mut_ptr(), + buf.len() as i32, + ptr::null(), + if no_default_char { &mut used_default_char } + else { ptr::null_mut() }); + if size == 0 { + return Err(io::Error::last_os_error()); + } + if no_default_char && used_default_char == c::TRUE { + return Err(io::Error::new(io::ErrorKind::InvalidData, + "string cannot be converted to requested code page")); + } + + buf.set_len(size as usize); + + Ok(buf) + } +} + pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { match v.iter().position(|c| *c == 0) { // don't include the 0 diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs index b5802afc10943..d464a13ad1d3f 100644 --- a/src/libstd/sys_common/gnu/libbacktrace.rs +++ b/src/libstd/sys_common/gnu/libbacktrace.rs @@ -16,6 +16,7 @@ use sys_common::backtrace::{output, output_fileline}; pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, symaddr: *mut libc::c_void) -> io::Result<()> { use ffi::CStr; + use mem; use ptr; //////////////////////////////////////////////////////////////////////// @@ -124,7 +125,21 @@ pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, unsafe fn init_state() -> *mut backtrace_state { static mut STATE: *mut backtrace_state = ptr::null_mut(); if !STATE.is_null() { return STATE } - STATE = backtrace_create_state(ptr::null(), 0, error_cb, + + let filename = match ::sys::backtrace::gnu::get_executable_filename() { + Ok((filename, file)) => { + // filename is purposely leaked here since libbacktrace requires + // it to stay allocated permanently, file is also leaked so that + // the file stays locked + let filename_ptr = filename.as_ptr(); + mem::forget(filename); + mem::forget(file); + filename_ptr + }, + Err(_) => ptr::null(), + }; + + STATE = backtrace_create_state(filename, 0, error_cb, ptr::null_mut()); STATE } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 07a9b4bed9920..8789006436c0c 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -391,7 +391,7 @@ impl Builder { /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html /// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join /// [`Err`]: ../../std/result/enum.Result.html#variant.Err -/// [`panic!`]: ../../std/macro.panic.html +/// [`panic`]: ../../std/macro.panic.html /// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn /// /// # Examples @@ -974,7 +974,7 @@ impl JoinHandle { /// to [`panic`]. /// /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// [`panic!`]: ../../std/macro.panic.html + /// [`panic`]: ../../std/macro.panic.html /// /// # Examples /// diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 2c4e2bbff93a1..af7eaeb3106b2 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -154,14 +154,12 @@ impl Duration { /// Basic usage: /// /// ``` - /// #![feature(duration_checked_ops)] - /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); /// ``` - #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[stable(feature = "duration_checked_ops", since = "1.16.0")] #[inline] pub fn checked_add(self, rhs: Duration) -> Option { if let Some(mut secs) = self.secs.checked_add(rhs.secs) { @@ -194,14 +192,12 @@ impl Duration { /// Basic usage: /// /// ``` - /// #![feature(duration_checked_ops)] - /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); /// ``` - #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[stable(feature = "duration_checked_ops", since = "1.16.0")] #[inline] pub fn checked_sub(self, rhs: Duration) -> Option { if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { @@ -232,14 +228,12 @@ impl Duration { /// Basic usage: /// /// ``` - /// #![feature(duration_checked_ops)] - /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); /// ``` - #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[stable(feature = "duration_checked_ops", since = "1.16.0")] #[inline] pub fn checked_mul(self, rhs: u32) -> Option { // Multiply nanoseconds as u64, because it cannot overflow that way. @@ -269,15 +263,13 @@ impl Duration { /// Basic usage: /// /// ``` - /// #![feature(duration_checked_ops)] - /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); /// assert_eq!(Duration::new(2, 0).checked_div(0), None); /// ``` - #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[stable(feature = "duration_checked_ops", since = "1.16.0")] #[inline] pub fn checked_div(self, rhs: u32) -> Option { if rhs != 0 { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d4448da932eae..112211851ec05 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -297,10 +297,6 @@ declare_features! ( // The #![windows_subsystem] attribute (active, windows_subsystem, "1.14.0", Some(37499)), - // Allows using `Self` and associated types in struct expressions and patterns. - (active, more_struct_aliases, "1.14.0", Some(37544)), - - // Allows #[link(..., cfg(..))] (active, link_cfg, "1.14.0", Some(37406)), @@ -381,6 +377,8 @@ declare_features! ( // Allows `..` in tuple (struct) patterns (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)), (accepted, item_like_imports, "1.14.0", Some(35120)), + // Allows using `Self` and associated types in struct expressions and patterns. + (accepted, more_struct_aliases, "1.14.0", Some(37544)), ); // (changing above list without updating src/doc/reference.md makes @cmr sad) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b564cc337e468..2532a1def7dda 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -22,7 +22,7 @@ use ast::{Expr, ExprKind, RangeLimits}; use ast::{Field, FnDecl}; use ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; use ast::{Ident, ImplItem, Item, ItemKind}; -use ast::{Lit, LitKind, UintTy}; +use ast::{Lifetime, LifetimeDef, Lit, LitKind, UintTy}; use ast::Local; use ast::MacStmtStyle; use ast::Mac_; @@ -193,14 +193,22 @@ pub enum TokenType { Token(token::Token), Keyword(keywords::Keyword), Operator, + Lifetime, + Ident, + Path, + Type, } impl TokenType { fn to_string(&self) -> String { match *self { TokenType::Token(ref t) => format!("`{}`", Parser::token_to_string(t)), - TokenType::Operator => "an operator".to_string(), TokenType::Keyword(kw) => format!("`{}`", kw.name()), + TokenType::Operator => "an operator".to_string(), + TokenType::Lifetime => "lifetime".to_string(), + TokenType::Ident => "identifier".to_string(), + TokenType::Path => "path".to_string(), + TokenType::Type => "type".to_string(), } } } @@ -553,6 +561,33 @@ impl<'a> Parser<'a> { } } + fn check_ident(&mut self) -> bool { + if self.token.is_ident() { + true + } else { + self.expected_tokens.push(TokenType::Ident); + false + } + } + + fn check_path(&mut self) -> bool { + if self.token.is_path_start() { + true + } else { + self.expected_tokens.push(TokenType::Path); + false + } + } + + fn check_type(&mut self) -> bool { + if self.token.can_begin_type() { + true + } else { + self.expected_tokens.push(TokenType::Type); + false + } + } + /// Expect and consume an `&`. If `&&` is seen, replace it with a single /// `&` and continue. If an `&` is not seen, signal an error. fn expect_and(&mut self) -> PResult<'a, ()> { @@ -639,13 +674,7 @@ impl<'a> Parser<'a> { let lo = span.lo + BytePos(1); Ok(self.bump_with(token::Eq, lo, span.hi)) } - _ => { - let gt_str = Parser::token_to_string(&token::Gt); - let this_token_str = self.this_token_to_string(); - Err(self.fatal(&format!("expected `{}`, found `{}`", - gt_str, - this_token_str))) - } + _ => self.unexpected() } } @@ -972,20 +1001,11 @@ impl<'a> Parser<'a> { Parses whatever can come after a `for` keyword in a type. The `for` hasn't been consumed. - Deprecated: - - - for <'lt> |S| -> T - - Eventually: - - for <'lt> [unsafe] [extern "ABI"] fn (S) -> T - - for <'lt> path::foo(a, b) - + - for <'lt> path::foo(a, b) + Trait + 'a */ - // parse <'lt> let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; // examine next token to decide to do @@ -994,9 +1014,9 @@ impl<'a> Parser<'a> { } else { let hi = self.span.hi; let trait_ref = self.parse_trait_ref()?; - let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs, - trait_ref: trait_ref, - span: mk_sp(lo, hi)}; + let poly_trait_ref = PolyTraitRef { bound_lifetimes: lifetime_defs, + trait_ref: trait_ref, + span: mk_sp(lo, hi)}; let other_bounds = if self.eat(&token::BinOp(token::Plus)) { self.parse_ty_param_bounds()? } else { @@ -1011,18 +1031,9 @@ impl<'a> Parser<'a> { } pub fn parse_impl_trait_type(&mut self) -> PResult<'a, TyKind> { - /* - Parses whatever can come after a `impl` keyword in a type. - The `impl` has already been consumed. - */ - - let bounds = self.parse_ty_param_bounds()?; - - if !bounds.iter().any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) { - self.span_err(self.prev_span, "at least one trait must be specified"); - } - - Ok(ast::TyKind::ImplTrait(bounds)) + // Parses whatever can come after a `impl` keyword in a type. + // The `impl` has already been consumed. + Ok(ast::TyKind::ImplTrait(self.parse_ty_param_bounds()?)) } pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> { @@ -1030,7 +1041,7 @@ impl<'a> Parser<'a> { } /// parse a TyKind::BareFn type: - pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) + pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) -> PResult<'a, TyKind> { /* @@ -1202,13 +1213,6 @@ impl<'a> Parser<'a> { }) } - /// Parse a possibly mutable type - pub fn parse_mt(&mut self) -> PResult<'a, MutTy> { - let mutbl = self.parse_mutability()?; - let t = self.parse_ty_no_plus()?; - Ok(MutTy { ty: t, mutbl: mutbl }) - } - /// Parse optional return type [ -> TY ] in function decl pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> { if self.eat(&token::RArrow) { @@ -1260,8 +1264,8 @@ impl<'a> Parser<'a> { pprust::ty_to_string(&lhs)); err.span_label(lhs.span, &format!("expected a path")); let hi = bounds.iter().map(|x| match *x { - ast::TraitTyParamBound(ref tr, _) => tr.span.hi, - ast::RegionTyParamBound(ref r) => r.span.hi, + TraitTyParamBound(ref tr, _) => tr.span.hi, + RegionTyParamBound(ref r) => r.span.hi, }).max_by_key(|x| x.to_usize()); let full_span = hi.map(|hi| Span { lo: lhs.span.lo, @@ -1309,9 +1313,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - let t = if self.check(&token::OpenDelim(token::Paren)) { - self.bump(); - + let t = if self.eat(&token::OpenDelim(token::Paren)) { // (t) is a parenthesized ty // (t,) is the type of a tuple with only one field, // of type t @@ -1319,9 +1321,8 @@ impl<'a> Parser<'a> { let mut last_comma = false; while self.token != token::CloseDelim(token::Paren) { ts.push(self.parse_ty()?); - if self.check(&token::Comma) { + if self.eat(&token::Comma) { last_comma = true; - self.bump(); } else { last_comma = false; break; @@ -1336,13 +1337,11 @@ impl<'a> Parser<'a> { } } else if self.eat(&token::Not) { TyKind::Never - } else if self.check(&token::BinOp(token::Star)) { + } else if self.eat(&token::BinOp(token::Star)) { // STAR POINTER (bare pointer?) - self.bump(); TyKind::Ptr(self.parse_ptr()?) - } else if self.check(&token::OpenDelim(token::Bracket)) { + } else if self.eat(&token::OpenDelim(token::Bracket)) { // VECTOR - self.expect(&token::OpenDelim(token::Bracket))?; let t = self.parse_ty()?; // Parse the `; e` in `[ i32; e ]` @@ -1354,13 +1353,15 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Bracket))?; t } else if self.check(&token::BinOp(token::And)) || - self.token == token::AndAnd { + self.check(&token::AndAnd) { // BORROWED POINTER self.expect_and()?; self.parse_borrowed_pointee()? } else if self.check_keyword(keywords::For) { + // FIXME `+` has incorrect priority in trait object types starting with `for` (#39317). self.parse_for_in_type()? } else if self.eat_keyword(keywords::Impl) { + // FIXME figure out priority of `+` in `impl Trait1 + Trait2` (#34511). self.parse_impl_trait_type()? } else if self.token_is_bare_fn_keyword() { // BARE FUNCTION @@ -1373,10 +1374,7 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Paren))?; TyKind::Typeof(e) } else if self.eat_lt() { - - let (qself, path) = - self.parse_qualified_path(PathStyle::Type)?; - + let (qself, path) = self.parse_qualified_path(PathStyle::Type)?; TyKind::Path(Some(qself), path) } else if self.token.is_path_start() { let path = self.parse_path(PathStyle::Type)?; @@ -1406,10 +1404,10 @@ impl<'a> Parser<'a> { pub fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: - let opt_lifetime = self.parse_opt_lifetime()?; - - let mt = self.parse_mt()?; - return Ok(TyKind::Rptr(opt_lifetime, mt)); + let opt_lifetime = self.eat_lifetime(); + let mutbl = self.parse_mutability()?; + let ty = self.parse_ty_no_plus()?; + return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl })); } pub fn parse_ptr(&mut self) -> PResult<'a, MutTy> { @@ -1505,8 +1503,7 @@ impl<'a> Parser<'a> { } pub fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option>> { - if self.check(&token::Semi) { - self.bump(); + if self.eat(&token::Semi) { Ok(Some(self.parse_expr()?)) } else { Ok(None) @@ -1728,7 +1725,8 @@ impl<'a> Parser<'a> { // Parse types, optionally. let parameters = if self.eat_lt() { - let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?; + let (lifetimes, types, bindings) = self.parse_generic_args()?; + self.expect_gt()?; ast::AngleBracketedParameterData { lifetimes: lifetimes, types: types, @@ -1786,7 +1784,8 @@ impl<'a> Parser<'a> { // Check for a type segment. if self.eat_lt() { // Consumed `a::b::<`, go look for types - let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?; + let (lifetimes, types, bindings) = self.parse_generic_args()?; + self.expect_gt()?; segments.push(ast::PathSegment { identifier: identifier, parameters: ast::AngleBracketedParameterData { @@ -1828,121 +1827,21 @@ impl<'a> Parser<'a> { } } - /// parses 0 or 1 lifetime - pub fn parse_opt_lifetime(&mut self) -> PResult<'a, Option> { - match self.token { - token::Lifetime(..) => { - Ok(Some(self.parse_lifetime()?)) - } - _ => { - Ok(None) - } - } - } - - /// Parses a single lifetime - /// Matches lifetime = LIFETIME - pub fn parse_lifetime(&mut self) -> PResult<'a, ast::Lifetime> { + /// Parse single lifetime 'a or nothing. + pub fn eat_lifetime(&mut self) -> Option { match self.token { - token::Lifetime(i) => { - let span = self.span; + token::Lifetime(ident) => { self.bump(); - return Ok(ast::Lifetime { + Some(Lifetime { id: ast::DUMMY_NODE_ID, - span: span, - name: i.name - }); + span: self.prev_span, + name: ident.name + }) } _ => { - return Err(self.fatal("expected a lifetime name")); - } - } - } - - /// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def = - /// lifetime [':' lifetimes]` - /// - /// If `followed_by_ty_params` is None, then we are in a context - /// where only lifetime parameters are allowed, and thus we should - /// error if we encounter attributes after the bound lifetimes. - /// - /// If `followed_by_ty_params` is Some(r), then there may be type - /// parameter bindings after the lifetimes, so we should pass - /// along the parsed attributes to be attached to the first such - /// type parmeter. - pub fn parse_lifetime_defs(&mut self, - followed_by_ty_params: Option<&mut Vec>) - -> PResult<'a, Vec> - { - let mut res = Vec::new(); - loop { - let attrs = self.parse_outer_attributes()?; - match self.token { - token::Lifetime(_) => { - let lifetime = self.parse_lifetime()?; - let bounds = - if self.eat(&token::Colon) { - self.parse_lifetimes(token::BinOp(token::Plus))? - } else { - Vec::new() - }; - res.push(ast::LifetimeDef { attrs: attrs.into(), - lifetime: lifetime, - bounds: bounds }); - } - - _ => { - if let Some(recv) = followed_by_ty_params { - assert!(recv.is_empty()); - *recv = attrs; - debug!("parse_lifetime_defs ret {:?}", res); - return Ok(res); - } else if !attrs.is_empty() { - let msg = "trailing attribute after lifetime parameters"; - return Err(self.fatal(msg)); - } - } - } - - match self.token { - token::Comma => { self.bump();} - token::Gt => { return Ok(res); } - token::BinOp(token::Shr) => { return Ok(res); } - _ => { - let this_token_str = self.this_token_to_string(); - let msg = format!("expected `,` or `>` after lifetime \ - name, found `{}`", - this_token_str); - return Err(self.fatal(&msg[..])); - } - } - } - } - - /// matches lifetimes = ( lifetime ) | ( lifetime , lifetimes ) actually, it matches the empty - /// one too, but putting that in there messes up the grammar.... - /// - /// Parses zero or more comma separated lifetimes. Expects each lifetime to be followed by - /// either a comma or `>`. Used when parsing type parameter lists, where we expect something - /// like `<'a, 'b, T>`. - pub fn parse_lifetimes(&mut self, sep: token::Token) -> PResult<'a, Vec> { - - let mut res = Vec::new(); - loop { - match self.token { - token::Lifetime(_) => { - res.push(self.parse_lifetime()?); - } - _ => { - return Ok(res); - } - } - - if self.token != sep { - return Ok(res); + self.expected_tokens.push(TokenType::Lifetime); + None } - - self.bump(); } } @@ -2459,7 +2358,9 @@ impl<'a> Parser<'a> { -> PResult<'a, P> { let (_, tys, bindings) = if self.eat(&token::ModSep) { self.expect_lt()?; - self.parse_generic_values_after_lt()? + let args = self.parse_generic_args()?; + self.expect_gt()?; + args } else { (Vec::new(), Vec::new(), Vec::new()) }; @@ -2555,9 +2456,21 @@ impl<'a> Parser<'a> { Some(f) => f, None => continue, }; - err.help(&format!("try parenthesizing the first index; e.g., `(foo.{}){}`", - float.trunc() as usize, - format!(".{}", fstr.splitn(2, ".").last().unwrap()))); + let sugg = pprust::to_string(|s| { + use print::pprust::PrintState; + use print::pp::word; + s.popen()?; + s.print_expr(&e)?; + word(&mut s.s, ".")?; + s.print_usize(float.trunc() as usize)?; + s.pclose()?; + word(&mut s.s, ".")?; + word(&mut s.s, fstr.splitn(2, ".").last().unwrap()) + }); + err.span_suggestion( + prev_span, + "try parenthesizing the first index", + sugg); } return Err(err); @@ -3999,7 +3912,14 @@ impl<'a> Parser<'a> { if self.eat(&token::Semi) { stmt_span.hi = self.prev_span.hi; } - e.span_help(stmt_span, "try placing this code inside a block"); + let sugg = pprust::to_string(|s| { + use print::pprust::{PrintState, INDENT_UNIT}; + s.ibox(INDENT_UNIT)?; + s.bopen()?; + s.print_stmt(&stmt)?; + s.bclose_maybe_open(stmt.span, INDENT_UNIT, false) + }); + e.span_suggestion(stmt_span, "try placing this code inside a block", sugg); } Err(mut e) => { self.recover_stmt_(SemiColonMode::Break); @@ -4094,69 +4014,68 @@ impl<'a> Parser<'a> { }).emit(); } - // Parses a sequence of bounds if a `:` is found, - // otherwise returns empty list. - fn parse_colon_then_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> - { - if !self.eat(&token::Colon) { - Ok(Vec::new()) - } else { - self.parse_ty_param_bounds() - } - } - - // matches bounds = ( boundseq )? - // where boundseq = ( polybound + boundseq ) | polybound - // and polybound = ( 'for' '<' 'region '>' )? bound - // and bound = 'region | trait_ref + // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without 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>`) fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> { - let mut result = vec![]; + let mut bounds = Vec::new(); loop { - let question_span = self.span; - let ate_question = self.eat(&token::Question); - match self.token { - token::Lifetime(lifetime) => { - if ate_question { - self.span_err(question_span, - "`?` may only modify trait bounds, not lifetime bounds"); - } - result.push(RegionTyParamBound(ast::Lifetime { - id: ast::DUMMY_NODE_ID, - span: self.span, - name: lifetime.name - })); - self.bump(); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if let Some(lifetime) = self.eat_lifetime() { + if let Some(question_span) = question { + self.span_err(question_span, + "`?` may only modify trait bounds, not lifetime bounds"); } - _ if self.token.is_path_start() || self.token.is_keyword(keywords::For) => { - let poly_trait_ref = self.parse_poly_trait_ref()?; - let modifier = if ate_question { - TraitBoundModifier::Maybe - } else { - TraitBoundModifier::None - }; - result.push(TraitTyParamBound(poly_trait_ref, modifier)) - } - _ => break, - } + bounds.push(RegionTyParamBound(lifetime)); + } else {if self.check_keyword(keywords::For) || self.check_path() { + let poly_trait_ref = self.parse_poly_trait_ref()?; + let modifier = if question.is_some() { + TraitBoundModifier::Maybe + } else { + TraitBoundModifier::None + }; + bounds.push(TraitTyParamBound(poly_trait_ref, modifier)); + } else { + break + }} if !self.eat(&token::BinOp(token::Plus)) { - break; + break } } - return Ok(result); + return Ok(bounds); + } + + // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. + // BOUND = LT_BOUND (e.g. `'a`) + fn parse_lt_param_bounds(&mut self) -> Vec { + let mut lifetimes = Vec::new(); + while let Some(lifetime) = self.eat_lifetime() { + lifetimes.push(lifetime); + + if !self.eat(&token::BinOp(token::Plus)) { + break + } + } + lifetimes } /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )? - fn parse_ty_param(&mut self, preceding_attrs: Vec) -> PResult<'a, TyParam> { + fn parse_ty_param(&mut self, preceding_attrs: Vec) -> PResult<'a, TyParam> { let span = self.span; let ident = self.parse_ident()?; - let bounds = self.parse_colon_then_ty_param_bounds()?; + // Parse optional colon and param bounds. + let bounds = if self.eat(&token::Colon) { + self.parse_ty_param_bounds()? + } else { + Vec::new() + }; - let default = if self.check(&token::Eq) { - self.bump(); + let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None @@ -4172,6 +4091,51 @@ impl<'a> Parser<'a> { }) } + /// Parses (possibly empty) list of lifetime and type parameters, possibly including + /// trailing comma and erroneous trailing attributes. + pub fn parse_generic_params(&mut self) -> PResult<'a, (Vec, Vec)> { + let mut lifetime_defs = Vec::new(); + let mut ty_params = Vec::new(); + let mut seen_ty_param = false; + loop { + let attrs = self.parse_outer_attributes()?; + if let Some(lifetime) = self.eat_lifetime() { + // Parse lifetime parameter. + let bounds = if self.eat(&token::Colon) { + self.parse_lt_param_bounds() + } else { + Vec::new() + }; + lifetime_defs.push(LifetimeDef { + attrs: attrs.into(), + lifetime: lifetime, + bounds: bounds, + }); + if seen_ty_param { + self.span_err(self.prev_span, + "lifetime parameters must be declared prior to type parameters"); + } + } else {if self.check_ident() { + // Parse type parameter. + ty_params.push(self.parse_ty_param(attrs)?); + seen_ty_param = true; + } else { + // Check for trailing attributes and stop parsing. + if !attrs.is_empty() { + let param_kind = if seen_ty_param { "type" } else { "lifetime" }; + self.span_err(attrs[0].span, + &format!("trailing attribute after {} parameters", param_kind)); + } + break + }} + + if !self.eat(&token::Comma) { + break + } + } + Ok((lifetime_defs, ty_params)) + } + /// Parse a set of optional generic type parameter declarations. Where /// clauses are not parsed here, and must be added later via /// `parse_where_clause()`. @@ -4181,45 +4145,11 @@ impl<'a> Parser<'a> { /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { maybe_whole!(self, NtGenerics, |x| x); - let span_lo = self.span.lo; - if self.eat(&token::Lt) { - // Upon encountering attribute in generics list, we do not - // know if it is attached to lifetime or to type param. - // - // Solution: 1. eagerly parse attributes in tandem with - // lifetime defs, 2. store last set of parsed (and unused) - // attributes in `attrs`, and 3. pass in those attributes - // when parsing formal type param after lifetime defs. - let mut attrs = vec![]; - let lifetime_defs = self.parse_lifetime_defs(Some(&mut attrs))?; - let mut seen_default = false; - let mut post_lifetime_attrs = Some(attrs); - let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| { - p.forbid_lifetime()?; - // Move out of `post_lifetime_attrs` if present. O/w - // not first type param: parse attributes anew. - let attrs = match post_lifetime_attrs.as_mut() { - None => p.parse_outer_attributes()?, - Some(attrs) => mem::replace(attrs, vec![]), - }; - post_lifetime_attrs = None; - let ty_param = p.parse_ty_param(attrs)?; - if ty_param.default.is_some() { - seen_default = true; - } else if seen_default { - let prev_span = p.prev_span; - p.span_err(prev_span, - "type parameters with a default must be trailing"); - } - Ok(ty_param) - })?; - if let Some(attrs) = post_lifetime_attrs { - if !attrs.is_empty() { - self.span_err(attrs[0].span, - "trailing attribute after lifetime parameters"); - } - } + let span_lo = self.span.lo; + if self.eat_lt() { + let (lifetime_defs, ty_params) = self.parse_generic_params()?; + self.expect_gt()?; Ok(ast::Generics { lifetimes: lifetime_defs, ty_params: ty_params, @@ -4234,85 +4164,52 @@ impl<'a> Parser<'a> { } } - fn parse_generic_values_after_lt(&mut self) -> PResult<'a, (Vec, - Vec>, - Vec)> { - let span_lo = self.span.lo; - let lifetimes = self.parse_lifetimes(token::Comma)?; - - let missing_comma = !lifetimes.is_empty() && - !self.token.is_like_gt() && - self.prev_token_kind != PrevTokenKind::Comma; - - if missing_comma { - - let msg = format!("expected `,` or `>` after lifetime \ - name, found `{}`", - self.this_token_to_string()); - let mut err = self.diagnostic().struct_span_err(self.span, &msg); - - let span_hi = self.span.hi; - let span_hi = match self.parse_ty_no_plus() { - Ok(..) => self.span.hi, - Err(ref mut err) => { - self.cancel(err); - span_hi - } - }; - - let msg = format!("did you mean a single argument type &'a Type, \ - or did you mean the comma-separated arguments \ - 'a, Type?"); - err.span_note(mk_sp(span_lo, span_hi), &msg); - return Err(err); - } - - // First parse types. - let (types, returned) = self.parse_seq_to_gt_or_return( - Some(token::Comma), - |p| { - p.forbid_lifetime()?; - if p.look_ahead(1, |t| t == &token::Eq) { - Ok(None) - } else { - Ok(Some(p.parse_ty()?)) + /// Parses (possibly empty) list of lifetime and type arguments and associated type bindings, + /// possibly including trailing comma. + fn parse_generic_args(&mut self) -> PResult<'a, (Vec, Vec>, Vec)> { + let mut lifetimes = Vec::new(); + let mut types = Vec::new(); + let mut bindings = Vec::new(); + let mut seen_type = false; + let mut seen_binding = false; + loop { + if let Some(lifetime) = self.eat_lifetime() { + // Parse lifetime argument. + lifetimes.push(lifetime); + if seen_type || seen_binding { + self.span_err(self.prev_span, + "lifetime parameters must be declared prior to type parameters"); } - } - )?; - - // If we found the `>`, don't continue. - if !returned { - return Ok((lifetimes, types, Vec::new())); - } - - // Then parse type bindings. - let bindings = self.parse_seq_to_gt( - Some(token::Comma), - |p| { - p.forbid_lifetime()?; - let lo = p.span.lo; - let ident = p.parse_ident()?; - p.expect(&token::Eq)?; - let ty = p.parse_ty_no_plus()?; - let hi = ty.span.hi; - let span = mk_sp(lo, hi); - return Ok(TypeBinding{id: ast::DUMMY_NODE_ID, + } else {if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { + // Parse associated type binding. + let lo = self.span.lo; + let ident = self.parse_ident()?; + self.bump(); + let ty = self.parse_ty()?; + bindings.push(TypeBinding { + id: ast::DUMMY_NODE_ID, ident: ident, ty: ty, - span: span, + span: mk_sp(lo, self.prev_span.hi), }); - } - )?; - Ok((lifetimes, types, bindings)) - } + seen_binding = true; + } else if self.check_type() { + // Parse type argument. + types.push(self.parse_ty()?); + if seen_binding { + self.span_err(types[types.len() - 1].span, + "type parameters must be declared prior to associated type bindings"); + } + seen_type = true; + } else { + break + }} - fn forbid_lifetime(&mut self) -> PResult<'a, ()> { - if self.token.is_lifetime() { - let span = self.span; - return Err(self.diagnostic().struct_span_err(span, "lifetime parameters must be \ - declared prior to type parameters")) + if !self.eat(&token::Comma) { + break + } } - Ok(()) + Ok((lifetimes, types, bindings)) } /// Parses an optional `where` clause and places it in `generics`. @@ -4320,7 +4217,7 @@ impl<'a> Parser<'a> { /// ```ignore /// where T : Trait + 'b, 'a : 'b /// ``` - pub fn parse_where_clause(&mut self) -> PResult<'a, ast::WhereClause> { + pub fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> { maybe_whole!(self, NtWhereClause, |x| x); let mut where_clause = WhereClause { @@ -4332,7 +4229,7 @@ impl<'a> Parser<'a> { return Ok(where_clause); } - // This is a temporary hack. + // This is a temporary future proofing. // // We are considering adding generics to the `where` keyword as an alternative higher-rank // parameter syntax (as in `where<'a>` or `where`. To avoid that being a breaking @@ -4349,106 +4246,64 @@ impl<'a> Parser<'a> { } } - let mut parsed_something = false; loop { let lo = self.span.lo; - match self.token { - token::OpenDelim(token::Brace) => { - break - } - - token::Lifetime(..) => { - let bounded_lifetime = - self.parse_lifetime()?; - - self.expect(&token::Colon)?; - - let bounds = - self.parse_lifetimes(token::BinOp(token::Plus))?; - - let hi = self.prev_span.hi; - let span = mk_sp(lo, hi); - - where_clause.predicates.push(ast::WherePredicate::RegionPredicate( - ast::WhereRegionPredicate { - span: span, - lifetime: bounded_lifetime, - bounds: bounds + if let Some(lifetime) = self.eat_lifetime() { + // Bounds starting with a colon are mandatory, but possibly empty. + self.expect(&token::Colon)?; + let bounds = self.parse_lt_param_bounds(); + where_clause.predicates.push(ast::WherePredicate::RegionPredicate( + ast::WhereRegionPredicate { + span: mk_sp(lo, self.prev_span.hi), + lifetime: lifetime, + bounds: bounds, + } + )); + } else {if self.check_type() { + // Parse optional `for<'a, 'b>`. + // This `for` is parsed greedily and applies to the whole predicate, + // the bounded type can have its own `for` applying only to it. + // Example 1: for<'a> Trait1<'a>: Trait2<'a /*ok*/> + // Example 2: (for<'a> Trait1<'a>): Trait2<'a /*not ok*/> + // Example 3: for<'a> for<'b> Trait1<'a, 'b>: Trait2<'a /*ok*/, 'b /*not ok*/> + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + + // Parse type with mandatory colon and (possibly empty) bounds, + // or with mandatory equality sign and the second type. + let ty = self.parse_ty()?; + if self.eat(&token::Colon) { + let bounds = self.parse_ty_param_bounds()?; + where_clause.predicates.push(ast::WherePredicate::BoundPredicate( + ast::WhereBoundPredicate { + span: mk_sp(lo, self.prev_span.hi), + bound_lifetimes: lifetime_defs, + bounded_ty: ty, + bounds: bounds, } )); - - parsed_something = true; - } - - _ => { - let bound_lifetimes = if self.eat_keyword(keywords::For) { - // Higher ranked constraint. - self.expect(&token::Lt)?; - let lifetime_defs = self.parse_lifetime_defs(None)?; - self.expect_gt()?; - lifetime_defs - } else { - vec![] - }; - - let bounded_ty = self.parse_ty_no_plus()?; - - if self.eat(&token::Colon) { - let bounds = self.parse_ty_param_bounds()?; - let hi = self.prev_span.hi; - let span = mk_sp(lo, hi); - - if bounds.is_empty() { - self.span_err(span, - "each predicate in a `where` clause must have \ - at least one bound in it"); + // FIXME: Decide what should be used here, `=` or `==`. + } else if self.eat(&token::Eq) || self.eat(&token::EqEq) { + let rhs_ty = self.parse_ty()?; + where_clause.predicates.push(ast::WherePredicate::EqPredicate( + ast::WhereEqPredicate { + span: mk_sp(lo, self.prev_span.hi), + lhs_ty: ty, + rhs_ty: rhs_ty, + id: ast::DUMMY_NODE_ID, } - - where_clause.predicates.push(ast::WherePredicate::BoundPredicate( - ast::WhereBoundPredicate { - span: span, - bound_lifetimes: bound_lifetimes, - bounded_ty: bounded_ty, - bounds: bounds, - })); - - parsed_something = true; - } else if self.eat(&token::Eq) { - // let ty = try!(self.parse_ty_no_plus()); - let hi = self.prev_span.hi; - let span = mk_sp(lo, hi); - // where_clause.predicates.push( - // ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { - // id: ast::DUMMY_NODE_ID, - // span: span, - // path: panic!("NYI"), //bounded_ty, - // ty: ty, - // })); - // parsed_something = true; - // // FIXME(#18433) - self.span_err(span, - "equality constraints are not yet supported \ - in where clauses (#20041)"); - } else { - let prev_span = self.prev_span; - self.span_err(prev_span, - "unexpected token in `where` clause"); - } + )); + } else { + return self.unexpected(); } - }; + } else { + break + }} if !self.eat(&token::Comma) { break } } - if !parsed_something { - let prev_span = self.prev_span; - self.span_err(prev_span, - "a `where` clause must have at least one predicate \ - in it"); - } - Ok(where_clause) } @@ -4547,13 +4402,13 @@ impl<'a> Parser<'a> { } else if self.look_ahead(1, |t| t.is_lifetime()) && isolated_self(self, 2) { self.bump(); - let lt = self.parse_lifetime()?; + let lt = self.eat_lifetime().expect("not a lifetime"); (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) && isolated_self(self, 3) { self.bump(); - let lt = self.parse_lifetime()?; + let lt = self.eat_lifetime().expect("not a lifetime"); self.bump(); (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self)) } else { @@ -4855,8 +4710,12 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; let mut tps = self.parse_generics()?; - // Parse supertrait bounds. - let bounds = self.parse_colon_then_ty_param_bounds()?; + // Parse optional colon and supertrait bounds. + let bounds = if self.eat(&token::Colon) { + self.parse_ty_param_bounds()? + } else { + Vec::new() + }; tps.where_clause = self.parse_where_clause()?; @@ -4947,17 +4806,21 @@ impl<'a> Parser<'a> { /// Parse a::B fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> { - Ok(ast::TraitRef { + Ok(TraitRef { path: self.parse_path(PathStyle::Type)?, ref_id: ast::DUMMY_NODE_ID, }) } - fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { + fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(keywords::For) { - self.expect(&token::Lt)?; - let lifetime_defs = self.parse_lifetime_defs(None)?; + self.expect_lt()?; + let (lifetime_defs, ty_params) = self.parse_generic_params()?; self.expect_gt()?; + if !ty_params.is_empty() { + self.span_err(ty_params[0].span, + "only lifetime parameters can be used in this context"); + } Ok(lifetime_defs) } else { Ok(Vec::new()) @@ -4969,7 +4832,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - Ok(ast::PolyTraitRef { + Ok(PolyTraitRef { bound_lifetimes: lifetime_defs, trait_ref: self.parse_trait_ref()?, span: mk_sp(lo, self.prev_span.hi), diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index bf790b96e37f6..0f0c6d0ca83f5 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -80,6 +80,28 @@ impl Lit { } } +fn ident_can_begin_expr(ident: ast::Ident) -> bool { + let ident_token: Token = Ident(ident); + + !ident_token.is_any_keyword() || + ident_token.is_path_segment_keyword() || + [ + keywords::Box.name(), + keywords::Break.name(), + keywords::Continue.name(), + keywords::False.name(), + keywords::For.name(), + keywords::If.name(), + keywords::Loop.name(), + keywords::Match.name(), + keywords::Move.name(), + keywords::Return.name(), + keywords::True.name(), + keywords::Unsafe.name(), + keywords::While.name(), + ].contains(&ident.name) +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)] pub enum Token { /* Expression-operator symbols. */ @@ -163,7 +185,7 @@ impl Token { pub fn can_begin_expr(&self) -> bool { match *self { OpenDelim(..) => true, - Ident(..) => true, + Ident(ident) => ident_can_begin_expr(ident), Literal(..) => true, Not => true, BinOp(Minus) => true, @@ -187,6 +209,29 @@ impl Token { } } + /// Returns `true` if the token can appear at the start of a type. + pub fn can_begin_type(&self) -> bool { + match *self { + OpenDelim(Paren) => true, // tuple + OpenDelim(Bracket) => true, // array + Ident(..) => true, // type name or keyword + Underscore => true, // placeholder + Not => true, // never + BinOp(Star) => true, // raw pointer + BinOp(And) => true, // reference + AndAnd => true, // double reference + Lt | BinOp(Shl) => true, // associated path + ModSep => true, // global path + Interpolated(ref nt) => match **nt { + NtTy(..) => true, + NtIdent(..) => true, + NtPath(..) => true, + _ => false, + }, + _ => false, + } + } + /// Returns `true` if the token is any literal pub fn is_lit(&self) -> bool { match *self { diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index c2123ea5a0798..c278171aa109a 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -140,7 +140,7 @@ macro_rules! declare_keywords {( $( #[allow(non_upper_case_globals)] pub const $konst: Keyword = Keyword { - ident: ast::Ident::with_empty_ctxt(ast::Name($index)) + ident: ast::Ident::with_empty_ctxt(super::Symbol($index)) }; )* } @@ -282,25 +282,24 @@ impl Encodable for InternedString { #[cfg(test)] mod tests { use super::*; - use ast::Name; #[test] fn interner_tests() { let mut i: Interner = Interner::new(); // first one is zero: - assert_eq!(i.intern("dog"), Name(0)); + assert_eq!(i.intern("dog"), Symbol(0)); // re-use gets the same entry: - assert_eq!(i.intern ("dog"), Name(0)); + assert_eq!(i.intern ("dog"), Symbol(0)); // different string gets a different #: - assert_eq!(i.intern("cat"), Name(1)); - assert_eq!(i.intern("cat"), Name(1)); + assert_eq!(i.intern("cat"), Symbol(1)); + assert_eq!(i.intern("cat"), Symbol(1)); // dog is still at zero - assert_eq!(i.intern("dog"), Name(0)); + assert_eq!(i.intern("dog"), Symbol(0)); // gensym gets 3 - assert_eq!(i.gensym("zebra"), Name(2)); + assert_eq!(i.gensym("zebra"), Symbol(2)); // gensym of same string gets new number : - assert_eq!(i.gensym("zebra"), Name(3)); + assert_eq!(i.gensym("zebra"), Symbol(3)); // gensym of *existing* string gets new number: - assert_eq!(i.gensym("dog"), Name(4)); + assert_eq!(i.gensym("dog"), Symbol(4)); } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index f29a168e6df19..86b0fcebeb21e 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -17,7 +17,7 @@ //! expansion). //! //! ## Ownership -//! TokenStreams are persistant data structures construced as ropes with reference +//! TokenStreams are persistent data structures constructed as ropes with reference //! counted-children. In general, this means that calling an operation on a TokenStream //! (such as `slice`) produces an entirely new TokenStream from the borrowed reference to //! the original. This essentially coerces TokenStreams into 'views' of their subparts, diff --git a/src/rt/rust_test_helpers.c b/src/rt/rust_test_helpers.c index 5900b21b6126a..2a14b3da7b7d0 100644 --- a/src/rt/rust_test_helpers.c +++ b/src/rt/rust_test_helpers.c @@ -269,7 +269,7 @@ LARGE_INTEGER increment_all_parts(LARGE_INTEGER li) { return li; } -#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && defined(__amd64__) +#if __SIZEOF_INT128__ == 16 unsigned __int128 identity(unsigned __int128 a) { return a; diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml index 7260a8440734d..14c9c5544b188 100644 --- a/src/rustc/std_shim/Cargo.toml +++ b/src/rustc/std_shim/Cargo.toml @@ -21,7 +21,7 @@ [package] name = "std_shim" -version = "0.1.0" +version = "0.0.0" authors = ["The Rust Project Developers"] [lib] diff --git a/src/rustc/test_shim/Cargo.toml b/src/rustc/test_shim/Cargo.toml index ac7842770f5bb..6ef613eee0628 100644 --- a/src/rustc/test_shim/Cargo.toml +++ b/src/rustc/test_shim/Cargo.toml @@ -5,7 +5,7 @@ [package] name = "test_shim" -version = "0.1.0" +version = "0.0.0" authors = ["The Rust Project Developers"] [lib] diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index bd0ff9e8d83cc..34ee7d552f346 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1082,14 +1082,6 @@ extern "C" void LLVMRustAddHandler(LLVMValueRef CatchSwitchRef, #endif } -extern "C" void LLVMRustSetPersonalityFn(LLVMBuilderRef B, - LLVMValueRef Personality) { -#if LLVM_VERSION_GE(3, 8) - unwrap(B)->GetInsertBlock()->getParent()->setPersonalityFn( - cast(unwrap(Personality))); -#endif -} - #if LLVM_VERSION_GE(3, 8) extern "C" OperandBundleDef *LLVMRustBuildOperandBundleDef(const char *Name, LLVMValueRef *Inputs, diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index dc88bfc40595f..61b1a0a0b4d25 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -36,11 +36,9 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_macro("identity", expand_identity); reg.register_syntax_extension( Symbol::intern("into_multi_foo"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiModifier(Box::new(expand_into_foo_multi))); reg.register_syntax_extension( Symbol::intern("duplicate"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiDecorator(Box::new(expand_duplicate))); } diff --git a/src/test/compile-fail-fulldeps/explore-issue-38412.rs b/src/test/compile-fail-fulldeps/explore-issue-38412.rs index aab92575321e3..b9839edea2dc4 100644 --- a/src/test/compile-fail-fulldeps/explore-issue-38412.rs +++ b/src/test/compile-fail-fulldeps/explore-issue-38412.rs @@ -25,21 +25,14 @@ use pub_and_stability::{Record, Trait, Tuple}; fn main() { // Okay let Record { .. } = Record::new(); - // Okay (for now; see RFC Issue #902) - let Tuple(..) = Tuple::new(); // Okay let Record { a_stable_pub: _, a_unstable_declared_pub: _, .. } = Record::new(); - // Okay (for now; see RFC Issue #902) - let Tuple(_, _, ..) = Tuple::new(); // analogous to above let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } = Record::new(); //~^^ ERROR use of unstable library feature 'unstable_undeclared' - let Tuple(_, _, _, ..) = Tuple::new(); // analogous to previous - //~^ ERROR use of unstable library feature 'unstable_undeclared' - let r = Record::new(); let t = Tuple::new(); diff --git a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs b/src/test/compile-fail-fulldeps/gated-macro-reexports.rs index b3dbcb743a135..22c92623e1c19 100644 --- a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs +++ b/src/test/compile-fail-fulldeps/gated-macro-reexports.rs @@ -11,6 +11,7 @@ // Test that macro reexports item are gated by `macro_reexport` feature gate. // aux-build:macro_reexport_1.rs +// gate-test-macro_reexport #![crate_type = "dylib"] diff --git a/src/test/compile-fail-fulldeps/gated-quote.rs b/src/test/compile-fail-fulldeps/gated-quote.rs index dade0e946c5bf..51a9a87744a20 100644 --- a/src/test/compile-fail-fulldeps/gated-quote.rs +++ b/src/test/compile-fail-fulldeps/gated-quote.rs @@ -15,6 +15,8 @@ // FIXME the error message that is current emitted seems pretty bad. +// gate-test-quote + #![feature(rustc_private)] #![allow(dead_code, unused_imports, unused_variables)] diff --git a/src/test/compile-fail/E0106.rs b/src/test/compile-fail/E0106.rs index dab03f0bccfd0..d5644ab060887 100644 --- a/src/test/compile-fail/E0106.rs +++ b/src/test/compile-fail/E0106.rs @@ -23,5 +23,17 @@ type MyStr = &str; //~^ ERROR E0106 //~| NOTE expected lifetime parameter +struct Baz<'a>(&'a str); +struct Buzz<'a, 'b>(&'a str, &'b str); + +struct Quux { + baz: Baz, + //~^ ERROR E0106 + //~| expected lifetime parameter + buzz: Buzz, + //~^ ERROR E0106 + //~| expected 2 lifetime parameters +} + fn main() { } diff --git a/src/test/compile-fail/E0107.rs b/src/test/compile-fail/E0107.rs index 5f333e17c478e..16ebd3e9ca5f2 100644 --- a/src/test/compile-fail/E0107.rs +++ b/src/test/compile-fail/E0107.rs @@ -18,9 +18,6 @@ enum Bar { } struct Baz<'a, 'b, 'c> { - foo: Foo, - //~^ ERROR E0107 - //~| expected 1 lifetime parameter buzz: Buzz<'a>, //~^ ERROR E0107 //~| expected 2 lifetime parameters diff --git a/src/test/compile-fail/E0117.rs b/src/test/compile-fail/E0117.rs index e9375e673253f..4ba9c3382f35d 100644 --- a/src/test/compile-fail/E0117.rs +++ b/src/test/compile-fail/E0117.rs @@ -11,6 +11,7 @@ impl Drop for u32 {} //~ ERROR E0117 //~^ NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead fn main() { } diff --git a/src/test/compile-fail/E0206.rs b/src/test/compile-fail/E0206.rs index 888e42ed3a18c..1131e8e1b01ca 100644 --- a/src/test/compile-fail/E0206.rs +++ b/src/test/compile-fail/E0206.rs @@ -16,6 +16,7 @@ impl Copy for Foo { } //~| ERROR only traits defined in the current crate can be implemented for arbitrary types //~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead #[derive(Copy, Clone)] struct Bar; diff --git a/src/test/compile-fail/E0451.rs b/src/test/compile-fail/E0451.rs index f7b106d160dae..ace96c9983e66 100644 --- a/src/test/compile-fail/E0451.rs +++ b/src/test/compile-fail/E0451.rs @@ -25,11 +25,6 @@ fn pat_match(foo: Bar::Foo) { //~^ NOTE field `b` is private } -fn pat_match_tuple(foo: Bar::FooTuple) { - let Bar::FooTuple(a,b) = foo; //~ ERROR E0451 - //~^ NOTE field `1` is private -} - fn main() { let f = Bar::Foo{ a: 0, b: 0 }; //~ ERROR E0451 //~^ NOTE field `b` is private diff --git a/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs b/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs index 44ad0bb01138f..e6251a0d318a3 100644 --- a/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs +++ b/src/test/compile-fail/associated-types-project-from-hrtb-in-struct.rs @@ -22,10 +22,11 @@ struct SomeStruct Foo<&'x isize>> { //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context } -struct AnotherStruct Foo<&'x isize>> { - field: >::A - //~^ ERROR missing lifetime specifier -} +// FIXME(eddyb) This one doesn't even compile because of the unsupported syntax. + +// struct AnotherStruct Foo<&'x isize>> { +// field: Foo<&'y isize>>::A +// } struct YetAnotherStruct<'a, I : for<'x> Foo<&'x isize>> { field: >::A diff --git a/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs b/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs index a38a7bfb93785..5e09473ab77da 100644 --- a/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs +++ b/src/test/compile-fail/attrs-with-no-formal-in-generics-2.rs @@ -17,10 +17,7 @@ struct RefAny<'a, T>(&'a T); -impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> { - //~^ ERROR expected identifier, found `>` -} +impl<#[rustc_1] 'a, #[rustc_2] T, #[oops]> RefAny<'a, T> {} +//~^ ERROR trailing attribute after type parameters -fn main() { - -} +fn main() {} diff --git a/src/test/compile-fail/autoderef-full-lval.rs b/src/test/compile-fail/autoderef-full-lval.rs index 0d666a4920038..c152fdd929682 100644 --- a/src/test/compile-fail/autoderef-full-lval.rs +++ b/src/test/compile-fail/autoderef-full-lval.rs @@ -22,13 +22,14 @@ struct fish { fn main() { let a: clam = clam{x: box 1, y: box 2}; let b: clam = clam{x: box 10, y: box 20}; - let z: isize = a.x + b.y; //~ ERROR binary operation `+` cannot be applied to type `Box` + let z: isize = a.x + b.y; + //~^ ERROR binary operation `+` cannot be applied to type `std::boxed::Box` println!("{}", z); assert_eq!(z, 21); let forty: fish = fish{a: box 40}; let two: fish = fish{a: box 2}; let answer: isize = forty.a + two.a; - //~^ ERROR binary operation `+` cannot be applied to type `Box` + //~^ ERROR binary operation `+` cannot be applied to type `std::boxed::Box` println!("{}", answer); assert_eq!(answer, 42); } diff --git a/src/test/compile-fail/binary-op-on-double-ref.rs b/src/test/compile-fail/binary-op-on-double-ref.rs new file mode 100644 index 0000000000000..a49cfaa17606d --- /dev/null +++ b/src/test/compile-fail/binary-op-on-double-ref.rs @@ -0,0 +1,20 @@ +// Copyright 2012-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. + +fn main() { + let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9]; + let vr = v.iter().filter(|x| { + x % 2 == 0 + //~^ ERROR binary operation `%` cannot be applied to type `&&{integer}` + //~| NOTE this is a reference of type that `%` can be applied to + //~| NOTE an implementation of `std::ops::Rem` might be missing for `&&{integer}` + }); + println!("{:?}", vr); +} diff --git a/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue.rs b/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue.rs index e4eca7e7eceb4..f58eca7c8ae39 100644 --- a/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue.rs @@ -17,7 +17,6 @@ use std::collections::HashMap; fn main() { let tmp: Box<_>; let mut buggy_map: HashMap = HashMap::new(); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. buggy_map.insert(42, &*Box::new(1)); //~ ERROR borrowed value does not live long enough // but it is ok if we use a temporary diff --git a/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs b/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs index 530822f6c5baf..d09cb73d6702a 100644 --- a/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs +++ b/src/test/compile-fail/borrowck/borrowck-box-insensitivity.rs @@ -35,7 +35,7 @@ fn copy_after_move() { let _x = a.x; //~^ value moved here let _y = a.y; //~ ERROR use of moved - //~^ move occurs because `a.x` has type `Box` + //~^ move occurs because `a.x` has type `std::boxed::Box` //~| value used here after move } @@ -44,7 +44,7 @@ fn move_after_move() { let _x = a.x; //~^ value moved here let _y = a.y; //~ ERROR use of moved - //~^ move occurs because `a.x` has type `Box` + //~^ move occurs because `a.x` has type `std::boxed::Box` //~| value used here after move } @@ -53,7 +53,7 @@ fn borrow_after_move() { let _x = a.x; //~^ value moved here let _y = &a.y; //~ ERROR use of moved - //~^ move occurs because `a.x` has type `Box` + //~^ move occurs because `a.x` has type `std::boxed::Box` //~| value used here after move } @@ -106,7 +106,7 @@ fn copy_after_move_nested() { let _x = a.x.x; //~^ value moved here let _y = a.y; //~ ERROR use of collaterally moved - //~^ NOTE move occurs because `a.x.x` has type `Box` + //~^ NOTE move occurs because `a.x.x` has type `std::boxed::Box` //~| value used here after move } @@ -115,7 +115,7 @@ fn move_after_move_nested() { let _x = a.x.x; //~^ value moved here let _y = a.y; //~ ERROR use of collaterally moved - //~^ NOTE move occurs because `a.x.x` has type `Box` + //~^ NOTE move occurs because `a.x.x` has type `std::boxed::Box` //~| value used here after move } @@ -124,7 +124,7 @@ fn borrow_after_move_nested() { let _x = a.x.x; //~^ value moved here let _y = &a.y; //~ ERROR use of collaterally moved - //~^ NOTE move occurs because `a.x.x` has type `Box` + //~^ NOTE move occurs because `a.x.x` has type `std::boxed::Box` //~| value used here after move } diff --git a/src/test/compile-fail/can-begin-expr-check.rs b/src/test/compile-fail/can-begin-expr-check.rs new file mode 100644 index 0000000000000..68f219c6ed993 --- /dev/null +++ b/src/test/compile-fail/can-begin-expr-check.rs @@ -0,0 +1,30 @@ +// 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. + +pub fn main() { + + return; + return (); + return as (); + return return as (); + return return return; + + return if true { + () + } else { + () + }; + + loop { + return break as (); + } + + return enum; //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `enum` +} diff --git a/src/test/compile-fail/coherence-impls-copy.rs b/src/test/compile-fail/coherence-impls-copy.rs index f686a146042ce..fe121a3bc48ff 100644 --- a/src/test/compile-fail/coherence-impls-copy.rs +++ b/src/test/compile-fail/coherence-impls-copy.rs @@ -37,6 +37,7 @@ impl Copy for (MyType, MyType) {} //~| ERROR only traits defined in the current crate can be implemented for arbitrary types //~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead impl Copy for &'static NotSync {} //~^ ERROR the trait `Copy` may not be implemented for this type @@ -46,8 +47,9 @@ impl Copy for [MyType] {} //~^ ERROR the trait `Copy` may not be implemented for this type //~| NOTE type is not a structure or enumeration //~| ERROR only traits defined in the current crate can be implemented for arbitrary types -//~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead +//~| NOTE impl doesn't use types inside crate impl Copy for &'static [NotSync] {} //~^ ERROR the trait `Copy` may not be implemented for this type @@ -55,6 +57,7 @@ impl Copy for &'static [NotSync] {} //~| ERROR only traits defined in the current crate can be implemented for arbitrary types //~| NOTE impl doesn't use types inside crate //~| NOTE the impl does not reference any types defined in this crate +//~| NOTE define and implement a trait or new type instead fn main() { } diff --git a/src/test/compile-fail/cross-borrow-trait.rs b/src/test/compile-fail/cross-borrow-trait.rs index 672ff464718f8..e5afccb9cf394 100644 --- a/src/test/compile-fail/cross-borrow-trait.rs +++ b/src/test/compile-fail/cross-borrow-trait.rs @@ -16,10 +16,8 @@ trait Trait { fn foo(&self) {} } impl Trait for Foo {} pub fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let x: Box = Box::new(Foo); let _y: &Trait = x; //~ ERROR mismatched types //~| expected type `&Trait` - //~| found type `Box` - //~| expected &Trait, found box + //~| found type `std::boxed::Box` } diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs index 89fb1e105900d..835ec8e4a5e7e 100644 --- a/src/test/compile-fail/destructure-trait-ref.rs +++ b/src/test/compile-fail/destructure-trait-ref.rs @@ -51,6 +51,5 @@ fn main() { let box box x = box 1isize as Box; //~^ ERROR mismatched types //~| expected type `T` - //~| found type `Box<_>` - //~| expected trait T, found box + //~| found type `std::boxed::Box<_>` } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs index 241fabf053c0b..10c8f1eed00b0 100644 --- a/src/test/compile-fail/dst-bad-assign-2.rs +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -41,7 +41,6 @@ impl ToBar for Bar1 { pub fn main() { // Assignment. let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = *z; //~^ ERROR `ToBar: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs index 9e71ad2417792..4f7d07600ad15 100644 --- a/src/test/compile-fail/dst-bad-assign.rs +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -41,7 +41,6 @@ impl ToBar for Bar1 { pub fn main() { // Assignment. let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let z: Box = Box::new(Bar1 {f: 36}); f5.ptr = Bar1 {f: 36}; //~^ ERROR mismatched types diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs index e01a0412cef4e..6377550d3d22f 100644 --- a/src/test/compile-fail/fn-trait-formatting.rs +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -16,18 +16,15 @@ fn main() { let _: () = (box |_: isize| {}) as Box; //~^ ERROR mismatched types //~| expected type `()` - //~| found type `Box` - //~| expected (), found box + //~| found type `std::boxed::Box` let _: () = (box |_: isize, isize| {}) as Box; //~^ ERROR mismatched types //~| expected type `()` - //~| found type `Box` - //~| expected (), found box + //~| found type `std::boxed::Box` let _: () = (box || -> isize { unimplemented!() }) as Box isize>; //~^ ERROR mismatched types //~| expected type `()` - //~| found type `Box isize>` - //~| expected (), found box + //~| found type `std::boxed::Box isize>` needs_fn(1); //~^ ERROR : std::ops::Fn<(isize,)>` diff --git a/src/test/compile-fail/generic-non-trailing-defaults.rs b/src/test/compile-fail/generic-non-trailing-defaults.rs new file mode 100644 index 0000000000000..77e5520326379 --- /dev/null +++ b/src/test/compile-fail/generic-non-trailing-defaults.rs @@ -0,0 +1,20 @@ +// 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. + +struct Heap; + +struct Vec; +//~^ ERROR type parameters with a default must be trailing + +struct Foo, C>; +//~^ ERROR type parameters with a default must be trailing +//~| ERROR type parameters with a default cannot use forward declared identifiers + +fn main() {} diff --git a/src/test/compile-fail/impl-trait/disallowed.rs b/src/test/compile-fail/impl-trait/disallowed.rs index 09aba5d8c9168..0467c49b0311d 100644 --- a/src/test/compile-fail/impl-trait/disallowed.rs +++ b/src/test/compile-fail/impl-trait/disallowed.rs @@ -26,9 +26,9 @@ trait LazyToString { //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types } -// Note that the following impl doesn't error, because the trait is invalid. impl LazyToString for String { fn lazy_to_string<'a>(&'a self) -> impl Fn() -> String { + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types || self.clone() } } diff --git a/src/test/compile-fail/impl-trait/no-trait.rs b/src/test/compile-fail/impl-trait/no-trait.rs new file mode 100644 index 0000000000000..ce61c5bf63d83 --- /dev/null +++ b/src/test/compile-fail/impl-trait/no-trait.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(conservative_impl_trait)] + +fn f() -> impl 'static {} //~ ERROR at least one trait must be specified + +fn main() {} diff --git a/src/test/compile-fail/issue-10291.rs b/src/test/compile-fail/issue-10291.rs index 43255db2ff3ab..d4e7dc7e9a35d 100644 --- a/src/test/compile-fail/issue-10291.rs +++ b/src/test/compile-fail/issue-10291.rs @@ -9,7 +9,6 @@ // except according to those terms. fn test<'x>(x: &'x isize) { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { x //~ ERROR E0312 })); diff --git a/src/test/compile-fail/issue-11515.rs b/src/test/compile-fail/issue-11515.rs index f682d618ab646..7afb8314ea689 100644 --- a/src/test/compile-fail/issue-11515.rs +++ b/src/test/compile-fail/issue-11515.rs @@ -15,7 +15,6 @@ struct Test { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let closure: Box = Box::new(|| ()); let test = box Test { func: closure }; //~ ERROR mismatched types } diff --git a/src/test/compile-fail/issue-13058.rs b/src/test/compile-fail/issue-13058.rs index de578257e4684..408c6d411de90 100644 --- a/src/test/compile-fail/issue-13058.rs +++ b/src/test/compile-fail/issue-13058.rs @@ -20,7 +20,6 @@ impl<'r> Itble<'r, usize, Range> for (usize, usize) { } fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool -//~^ HELP as shown: fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &'r T) { let cont_iter = cont.iter(); //~^ ERROR cannot infer an appropriate lifetime for autoref due to conflicting requirements diff --git a/src/test/compile-fail/issue-14915.rs b/src/test/compile-fail/issue-14915.rs index 18e4ccc331196..810d6656a8f62 100644 --- a/src/test/compile-fail/issue-14915.rs +++ b/src/test/compile-fail/issue-14915.rs @@ -13,5 +13,6 @@ fn main() { let x: Box = box 0; - println!("{}", x + 1); //~ ERROR binary operation `+` cannot be applied to type `Box` + println!("{}", x + 1); + //~^ ERROR binary operation `+` cannot be applied to type `std::boxed::Box` } diff --git a/src/test/compile-fail/issue-17441.rs b/src/test/compile-fail/issue-17441.rs index 7d300bfb14831..bddc9c13815e7 100644 --- a/src/test/compile-fail/issue-17441.rs +++ b/src/test/compile-fail/issue-17441.rs @@ -13,9 +13,8 @@ fn main() { //~^ ERROR cast to unsized type: `&[usize; 2]` as `[usize]` //~^^ HELP consider using an implicit coercion to `&[usize]` instead - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let _bar = Box::new(1_usize) as std::fmt::Debug; - //~^ ERROR cast to unsized type: `Box` as `std::fmt::Debug` + //~^ ERROR cast to unsized type: `std::boxed::Box` as `std::fmt::Debug` //~^^ HELP try casting to a `Box` instead let _baz = 1_usize as std::fmt::Debug; diff --git a/src/test/compile-fail/issue-17651.rs b/src/test/compile-fail/issue-17651.rs index 3ea136aca4bec..4996da057dd8e 100644 --- a/src/test/compile-fail/issue-17651.rs +++ b/src/test/compile-fail/issue-17651.rs @@ -12,7 +12,6 @@ // and rejected. fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. (|| Box::new(*(&[0][..])))(); //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/issue-18783.rs b/src/test/compile-fail/issue-18783.rs index 5eb3c439df2f3..9a7b3781f1e24 100644 --- a/src/test/compile-fail/issue-18783.rs +++ b/src/test/compile-fail/issue-18783.rs @@ -10,8 +10,6 @@ use std::cell::RefCell; -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - fn main() { let mut y = 1; let c = RefCell::new(vec![]); diff --git a/src/test/compile-fail/issue-20616-1.rs b/src/test/compile-fail/issue-20616-1.rs index 5b4f9942d28b6..a1949df661a34 100644 --- a/src/test/compile-fail/issue-20616-1.rs +++ b/src/test/compile-fail/issue-20616-1.rs @@ -16,7 +16,7 @@ type Type_1_<'a, T> = &'a T; -type Type_1<'a T> = &'a T; //~ error: expected `,` or `>` after lifetime name, found `T` +type Type_1<'a T> = &'a T; //~ error: expected one of `,`, `:`, or `>`, found `T` //type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(` diff --git a/src/test/compile-fail/issue-20616-2.rs b/src/test/compile-fail/issue-20616-2.rs index 65305ff3ac82f..87b836d687274 100644 --- a/src/test/compile-fail/issue-20616-2.rs +++ b/src/test/compile-fail/issue-20616-2.rs @@ -19,7 +19,7 @@ type Type_1_<'a, T> = &'a T; //type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T` -type Type_2 = Type_1_<'static ()>; //~ error: expected `,` or `>` after lifetime name, found `(` +type Type_2 = Type_1_<'static ()>; //~ error: expected one of `,` or `>`, found `(` //type Type_3 = Box; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-3.rs b/src/test/compile-fail/issue-20616-3.rs index 101f81019d97c..e5ed46d2cb3b0 100644 --- a/src/test/compile-fail/issue-20616-3.rs +++ b/src/test/compile-fail/issue-20616-3.rs @@ -22,7 +22,7 @@ type Type_1_<'a, T> = &'a T; //type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(` -type Type_3 = Box; //~ error: expected type, found `,` +type Type_3 = Box; //~ error: expected one of `>`, identifier, lifetime, or type, found `,` //type Type_4 = Type_1_<'static,, T>; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-4.rs b/src/test/compile-fail/issue-20616-4.rs index 6450e9ed68cb7..9b731289e138b 100644 --- a/src/test/compile-fail/issue-20616-4.rs +++ b/src/test/compile-fail/issue-20616-4.rs @@ -25,7 +25,8 @@ type Type_1_<'a, T> = &'a T; //type Type_3 = Box; // error: expected type, found `,` -type Type_4 = Type_1_<'static,, T>; //~ error: expected type, found `,` +type Type_4 = Type_1_<'static,, T>; +//~^ error: expected one of `>`, identifier, lifetime, or type, found `,` type Type_5_<'a> = Type_1_<'a, ()>; diff --git a/src/test/compile-fail/issue-20616-5.rs b/src/test/compile-fail/issue-20616-5.rs index d1840427ad8b2..5e3b024da9a07 100644 --- a/src/test/compile-fail/issue-20616-5.rs +++ b/src/test/compile-fail/issue-20616-5.rs @@ -31,7 +31,8 @@ type Type_1_<'a, T> = &'a T; type Type_5_<'a> = Type_1_<'a, ()>; -type Type_5<'a> = Type_1_<'a, (),,>; //~ error: expected type, found `,` +type Type_5<'a> = Type_1_<'a, (),,>; +//~^ error: expected one of `>`, identifier, lifetime, or type, found `,` //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-6.rs b/src/test/compile-fail/issue-20616-6.rs index b0b5bc653f6d0..b6ee26f9f62b8 100644 --- a/src/test/compile-fail/issue-20616-6.rs +++ b/src/test/compile-fail/issue-20616-6.rs @@ -34,7 +34,8 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,` -type Type_6 = Type_5_<'a,,>; //~ error: expected type, found `,` +type Type_6 = Type_5_<'a,,>; +//~^ error: expected one of `>`, identifier, lifetime, or type, found `,` //type Type_7 = Box<(),,>; // error: expected type, found `,` diff --git a/src/test/compile-fail/issue-20616-7.rs b/src/test/compile-fail/issue-20616-7.rs index 0958f8b4ed22c..fef3dd4e31d5a 100644 --- a/src/test/compile-fail/issue-20616-7.rs +++ b/src/test/compile-fail/issue-20616-7.rs @@ -37,7 +37,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_6 = Type_5_<'a,,>; // error: expected type, found `,` -type Type_7 = Box<(),,>; //~ error: expected type, found `,` +type Type_7 = Box<(),,>; //~ error: expected one of `>`, identifier, lifetime, or type, found `,` //type Type_8<'a,,> = &'a (); // error: expected ident, found `,` diff --git a/src/test/compile-fail/issue-20616-8.rs b/src/test/compile-fail/issue-20616-8.rs index d6cf9acae9b0b..b7bef47c4f442 100644 --- a/src/test/compile-fail/issue-20616-8.rs +++ b/src/test/compile-fail/issue-20616-8.rs @@ -40,7 +40,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_7 = Box<(),,>; // error: expected type, found `,` -type Type_8<'a,,> = &'a (); //~ error: expected identifier, found `,` +type Type_8<'a,,> = &'a (); //~ error: expected one of `>`, identifier, or lifetime, found `,` //type Type_9 = Box; // error: expected identifier, found `,` diff --git a/src/test/compile-fail/issue-20616-9.rs b/src/test/compile-fail/issue-20616-9.rs index d64cec446ef3d..5c16d24cef854 100644 --- a/src/test/compile-fail/issue-20616-9.rs +++ b/src/test/compile-fail/issue-20616-9.rs @@ -43,4 +43,4 @@ type Type_5_<'a> = Type_1_<'a, ()>; //type Type_8<'a,,> = &'a (); // error: expected identifier, found `,` -type Type_9 = Box; //~ error: expected identifier, found `,` +type Type_9 = Box; //~ error: expected one of `>`, identifier, or lifetime, found `,` diff --git a/src/test/compile-fail/issue-3763.rs b/src/test/compile-fail/issue-3763.rs index 085b4e76afbf7..851f5dfeabe8a 100644 --- a/src/test/compile-fail/issue-3763.rs +++ b/src/test/compile-fail/issue-3763.rs @@ -25,13 +25,11 @@ fn main() { let _woohoo = (&my_struct).priv_field; //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let _woohoo = (Box::new(my_struct)).priv_field; //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private (&my_struct).happyfun(); //~ ERROR method `happyfun` is private - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. (Box::new(my_struct)).happyfun(); //~ ERROR method `happyfun` is private let nope = my_struct.priv_field; //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private diff --git a/src/test/compile-fail/issue-38412.rs b/src/test/compile-fail/issue-38412.rs index 00305eb2bc04b..3b62aaf2ab8e9 100644 --- a/src/test/compile-fail/issue-38412.rs +++ b/src/test/compile-fail/issue-38412.rs @@ -10,7 +10,8 @@ fn main() { let Box(a) = loop { }; - //~^ ERROR field `0` of struct `std::boxed::Box` is private + //~^ ERROR expected tuple struct/variant, found struct `Box` + //~| ERROR expected tuple struct/variant, found struct `Box` // (The below is a trick to allow compiler to infer a type for // variable `a` without attempting to ascribe a type to the diff --git a/src/test/compile-fail/issue-4335.rs b/src/test/compile-fail/issue-4335.rs index 51f5fc5ee98e1..c5aae894c3ecb 100644 --- a/src/test/compile-fail/issue-4335.rs +++ b/src/test/compile-fail/issue-4335.rs @@ -13,7 +13,6 @@ fn id(t: T) -> T { t } fn f<'r, T>(v: &'r T) -> Box T + 'r> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. id(Box::new(|| *v)) //~^ ERROR E0373 //~| NOTE `v` is borrowed here diff --git a/src/test/compile-fail/issue-5100.rs b/src/test/compile-fail/issue-5100.rs index a1f5d74b30e36..9ef780aac8e27 100644 --- a/src/test/compile-fail/issue-5100.rs +++ b/src/test/compile-fail/issue-5100.rs @@ -43,8 +43,7 @@ fn main() { box (true, false) => () //~^ ERROR mismatched types //~| expected type `(bool, bool)` -//~| found type `Box<_>` -//~| expected tuple, found box +//~| found type `std::boxed::Box<_>` } match (true, false) { diff --git a/src/test/compile-fail/issue-7061.rs b/src/test/compile-fail/issue-7061.rs index da6f49f3efe91..b99f5b707ee2d 100644 --- a/src/test/compile-fail/issue-7061.rs +++ b/src/test/compile-fail/issue-7061.rs @@ -13,9 +13,8 @@ struct BarStruct; impl<'a> BarStruct { fn foo(&'a mut self) -> Box { self } //~^ ERROR mismatched types - //~| expected type `Box` + //~| expected type `std::boxed::Box` //~| found type `&'a mut BarStruct` - //~| expected box, found mutable reference } fn main() {} diff --git a/src/test/compile-fail/kindck-impl-type-params-2.rs b/src/test/compile-fail/kindck-impl-type-params-2.rs index a455a7b2d5d0f..21aefc4f9c1bc 100644 --- a/src/test/compile-fail/kindck-impl-type-params-2.rs +++ b/src/test/compile-fail/kindck-impl-type-params-2.rs @@ -21,5 +21,5 @@ fn take_param(foo: &T) { } fn main() { let x: Box<_> = box 3; take_param(&x); - //~^ ERROR `Box<{integer}>: std::marker::Copy` is not satisfied + //~^ ERROR `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied } diff --git a/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs b/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs index 7355c70ff95e8..43371eb6340f4 100644 --- a/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs +++ b/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs @@ -38,4 +38,28 @@ fn i(_x: isize) -> &isize { //~ ERROR missing lifetime specifier panic!() } +// Cases which used to work but now don't. + +type StaticStr = &'static str; // hides 'static +trait WithLifetime<'a> { + type Output; // can hide 'a +} + +// This worked because the type of the first argument contains +// 'static, although StaticStr doesn't even have parameters. +fn j(_x: StaticStr) -> &isize { //~ ERROR missing lifetime specifier +//~^ HELP this function's return type contains a borrowed value +//~| HELP consider giving it an explicit bounded or 'static lifetime + panic!() +} + +// This worked because the compiler resolved the argument type +// to >::Output which has the hidden 'a. +fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &isize { +//~^ ERROR missing lifetime specifier +//~| HELP this function's return type contains a borrowed value +//~| HELP consider giving it an explicit bounded or 'static lifetime + panic!() +} + fn main() {} diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-2.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-2.rs deleted file mode 100644 index d2d0dbf3e981f..0000000000000 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-2.rs +++ /dev/null @@ -1,36 +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. - -// ignore-tidy-linelength - -use std::ops::Range; - -trait Itble<'r, T, I: Iterator> { fn iter(&'r self) -> I; } - -impl<'r> Itble<'r, usize, Range> for (usize, usize) { - fn iter(&'r self) -> Range { - let &(min, max) = self; - min..max - } -} - -fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &'r T) - let cont_iter = cont.iter(); //~ ERROR: cannot infer - let result = cont_iter.fold(Some(0), |state, val| { - state.map_or(None, |mask| { - let bit = 1 << val; - if mask & bit == 0 {Some(mask|bit)} else {None} - }) - }); - result.is_some() -} - -fn main() {} diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs deleted file mode 100644 index 6b22d434804ff..0000000000000 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param-3.rs +++ /dev/null @@ -1,32 +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. - -// ignore-tidy-linelength - -use std::marker::PhantomData; - -struct Bar<'x, 'y, 'z> { bar: &'y i32, baz: i32, marker: PhantomData<(&'x(),&'y(),&'z())> } -fn bar1<'a>(x: &Bar) -> (&'a i32, &'a i32, &'a i32) { - //~^ HELP consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32) - (x.bar, &x.baz, &x.baz) - //~^ ERROR E0312 - //~| ERROR cannot infer - //~| ERROR cannot infer -} - -fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a i32, &'a i32, &'a i32) { - //~^ HELP: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a i32, &'a i32, &'a i32) - (x.bar, &x.baz, &x.baz) - //~^ ERROR E0312 - //~| ERROR cannot infer - //~| ERROR cannot infer -} - -fn main() { } diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs deleted file mode 100644 index 4323929e2e37a..0000000000000 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ /dev/null @@ -1,57 +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. - -// ignore-tidy-linelength - -use std::marker::PhantomData; - -struct Foo<'x> { bar: isize, marker: PhantomData<&'x ()> } -fn foo1<'a>(x: &Foo) -> &'a isize { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo1<'a>(x: &'a Foo) -> &'a isize - &x.bar //~ ERROR: cannot infer -} - -fn foo2<'a, 'b>(x: &'a Foo) -> &'b isize { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo2<'a>(x: &'a Foo) -> &'a isize - &x.bar //~ ERROR: cannot infer -} - -fn foo3<'a>(x: &Foo) -> (&'a isize, &'a isize) { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo3<'a>(x: &'a Foo) -> (&'a isize, &'a isize) - (&x.bar, &x.bar) //~ ERROR: cannot infer - //~^ ERROR: cannot infer -} - -fn foo4<'a, 'b>(x: &'a Foo) -> (&'b isize, &'a isize, &'b isize) { -//~^ HELP: consider using an explicit lifetime parameter as shown: fn foo4<'a>(x: &'a Foo) -> (&'a isize, &'a isize, &'a isize) - (&x.bar, &x.bar, &x.bar) //~ ERROR: cannot infer - //~^ ERROR: cannot infer -} - -struct Cat<'x, T> { cat: &'x isize, t: T } -struct Dog<'y> { dog: &'y isize } - -fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'x isize { - //~^ HELP consider using an explicit lifetime parameter as shown: fn cat2<'x>(x: Cat<'x, Dog<'x>>) -> &'x isize - x.t.dog //~ ERROR E0312 -} - -struct Baz<'x> { - bar: &'x isize -} - -impl<'a> Baz<'a> { - fn baz2<'b>(&self, x: &isize) -> (&'b isize, &'b isize) { - (self.bar, x) //~ ERROR E0312 - //~^ ERROR E0312 - } -} - -fn main() {} diff --git a/src/test/compile-fail/lint-ctypes.rs b/src/test/compile-fail/lint-ctypes.rs index 731c1edbfc00b..ccc25b58228bd 100644 --- a/src/test/compile-fail/lint-ctypes.rs +++ b/src/test/compile-fail/lint-ctypes.rs @@ -34,7 +34,7 @@ extern { pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type pub fn str_type(p: &str); //~ ERROR: found Rust type - pub fn box_type(p: Box); //~ ERROR found Rust type + pub fn box_type(p: Box); //~ ERROR found struct without pub fn char_type(p: char); //~ ERROR found Rust type pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type @@ -42,7 +42,7 @@ extern { pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust - pub fn fn_contained(p: RustBadRet); //~ ERROR: found Rust type + pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without pub fn good1(size: *const libc::c_int); pub fn good2(size: *const libc::c_uint); diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs index e24441c5497d5..9dcf902a69f91 100644 --- a/src/test/compile-fail/map-types.rs +++ b/src/test/compile-fail/map-types.rs @@ -24,7 +24,6 @@ impl Map for HashMap {} fn main() { let x: Box> = box HashMap::new(); let x: Box> = x; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let y: Box> = Box::new(x); - //~^ ERROR `Box>: Map` is not satisfied + //~^ ERROR `std::boxed::Box>: Map` is not satisfied } diff --git a/src/test/compile-fail/missing-block-hint.rs b/src/test/compile-fail/missing-block-hint.rs index 1f29ff4e05c09..6a140e6f21c19 100644 --- a/src/test/compile-fail/missing-block-hint.rs +++ b/src/test/compile-fail/missing-block-hint.rs @@ -15,6 +15,7 @@ fn main() { { if (foo) bar; //~ ERROR expected `{`, found `bar` - //^ HELP try placing this code inside a block + //~^ HELP try placing this code inside a block + //~| SUGGESTION { bar; } } } diff --git a/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs b/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs index df9a3519d5d61..d529606599994 100644 --- a/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs +++ b/src/test/compile-fail/moves-based-on-type-no-recursive-stack-closure.rs @@ -38,7 +38,6 @@ fn innocent_looking_victim() { } fn conspirator(mut f: F) where F: FnMut(&mut R, bool) { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let mut r = R {c: Box::new(f)}; f(&mut r, false) //~ ERROR use of moved value } diff --git a/src/test/compile-fail/object-does-not-impl-trait.rs b/src/test/compile-fail/object-does-not-impl-trait.rs index 6fa261dea71cb..8babc734c84cc 100644 --- a/src/test/compile-fail/object-does-not-impl-trait.rs +++ b/src/test/compile-fail/object-does-not-impl-trait.rs @@ -14,5 +14,5 @@ trait Foo {} fn take_foo(f: F) {} fn take_object(f: Box) { take_foo(f); } -//~^ ERROR `Box: Foo` is not satisfied +//~^ ERROR `std::boxed::Box: Foo` is not satisfied fn main() {} diff --git a/src/test/compile-fail/occurs-check-2.rs b/src/test/compile-fail/occurs-check-2.rs index 5cb60079fa4b8..a276af83dee25 100644 --- a/src/test/compile-fail/occurs-check-2.rs +++ b/src/test/compile-fail/occurs-check-2.rs @@ -17,6 +17,6 @@ fn main() { f = box g; //~^ ERROR mismatched types //~| expected type `_` - //~| found type `Box<_>` + //~| found type `std::boxed::Box<_>` //~| cyclic type of infinite size } diff --git a/src/test/compile-fail/occurs-check.rs b/src/test/compile-fail/occurs-check.rs index 499124cb0573b..5b6a11e58c27c 100644 --- a/src/test/compile-fail/occurs-check.rs +++ b/src/test/compile-fail/occurs-check.rs @@ -15,6 +15,6 @@ fn main() { f = box f; //~^ ERROR mismatched types //~| expected type `_` - //~| found type `Box<_>` + //~| found type `std::boxed::Box<_>` //~| cyclic type of infinite size } diff --git a/src/test/compile-fail/struct-path-self-feature-gate.rs b/src/test/compile-fail/privacy/legacy-ctor-visibility.rs similarity index 50% rename from src/test/compile-fail/struct-path-self-feature-gate.rs rename to src/test/compile-fail/privacy/legacy-ctor-visibility.rs index c40d057495591..fb65af230ace5 100644 --- a/src/test/compile-fail/struct-path-self-feature-gate.rs +++ b/src/test/compile-fail/privacy/legacy-ctor-visibility.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,23 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// gate-test-more_struct_aliases +#![allow(unused)] -struct S; +use m::S; -trait Tr { - type A; -} - -fn f>() { - let _ = T::A {}; - //~^ ERROR `Self` and associated types in struct expressions and patterns are unstable -} +mod m { + pub struct S(u8); -impl S { - fn f() { - let _ = Self {}; - //~^ ERROR `Self` and associated types in struct expressions and patterns are unstable + mod n { + use S; + fn f() { + S(10); + //~^ ERROR private struct constructors are not usable through reexports in outer modules + //~| WARN this was previously accepted + } } } diff --git a/src/test/compile-fail/privacy5.rs b/src/test/compile-fail/privacy5.rs index 9d6ae187cd381..599c1f8716044 100644 --- a/src/test/compile-fail/privacy5.rs +++ b/src/test/compile-fail/privacy5.rs @@ -58,30 +58,31 @@ mod a { } fn this_crate() { - let a = a::A(()); //~ ERROR: cannot invoke tuple struct constructor - let b = a::B(2); //~ ERROR: cannot invoke tuple struct constructor - let c = a::C(2, 3); //~ ERROR: cannot invoke tuple struct constructor + let a = a::A(()); //~ ERROR tuple struct `A` is private + let b = a::B(2); //~ ERROR tuple struct `B` is private + let c = a::C(2, 3); //~ ERROR tuple struct `C` is private let d = a::D(4); - let a::A(()) = a; //~ ERROR: field `0` of struct `a::A` is private - let a::A(_) = a; - match a { a::A(()) => {} } //~ ERROR: field `0` of struct `a::A` is private - match a { a::A(_) => {} } - - let a::B(_) = b; - let a::B(_b) = b; //~ ERROR: field `0` of struct `a::B` is private - match b { a::B(_) => {} } - match b { a::B(_b) => {} } //~ ERROR: field `0` of struct `a::B` is private - match b { a::B(1) => {} a::B(_) => {} } //~ ERROR: field `0` of struct `a::B` is private - - let a::C(_, _) = c; - let a::C(_a, _) = c; - let a::C(_, _b) = c; //~ ERROR: field `1` of struct `a::C` is private - let a::C(_a, _b) = c; //~ ERROR: field `1` of struct `a::C` is private - match c { a::C(_, _) => {} } - match c { a::C(_a, _) => {} } - match c { a::C(_, _b) => {} } //~ ERROR: field `1` of struct `a::C` is private - match c { a::C(_a, _b) => {} } //~ ERROR: field `1` of struct `a::C` is private + let a::A(()) = a; //~ ERROR tuple struct `A` is private + let a::A(_) = a; //~ ERROR tuple struct `A` is private + match a { a::A(()) => {} } //~ ERROR tuple struct `A` is private + match a { a::A(_) => {} } //~ ERROR tuple struct `A` is private + + let a::B(_) = b; //~ ERROR tuple struct `B` is private + let a::B(_b) = b; //~ ERROR tuple struct `B` is private + match b { a::B(_) => {} } //~ ERROR tuple struct `B` is private + match b { a::B(_b) => {} } //~ ERROR tuple struct `B` is private + match b { a::B(1) => {} a::B(_) => {} } //~ ERROR tuple struct `B` is private + //~^ ERROR tuple struct `B` is private + + let a::C(_, _) = c; //~ ERROR tuple struct `C` is private + let a::C(_a, _) = c; //~ ERROR tuple struct `C` is private + let a::C(_, _b) = c; //~ ERROR tuple struct `C` is private + let a::C(_a, _b) = c; //~ ERROR tuple struct `C` is private + match c { a::C(_, _) => {} } //~ ERROR tuple struct `C` is private + match c { a::C(_a, _) => {} } //~ ERROR tuple struct `C` is private + match c { a::C(_, _b) => {} } //~ ERROR tuple struct `C` is private + match c { a::C(_a, _b) => {} } //~ ERROR tuple struct `C` is private let a::D(_) = d; let a::D(_d) = d; @@ -89,42 +90,38 @@ fn this_crate() { match d { a::D(_d) => {} } match d { a::D(1) => {} a::D(_) => {} } - let a2 = a::A; //~ ERROR: cannot invoke tuple struct constructor - let b2 = a::B; //~ ERROR: cannot invoke tuple struct constructor - let c2 = a::C; //~ ERROR: cannot invoke tuple struct constructor + let a2 = a::A; //~ ERROR tuple struct `A` is private + let b2 = a::B; //~ ERROR tuple struct `B` is private + let c2 = a::C; //~ ERROR tuple struct `C` is private let d2 = a::D; } fn xcrate() { - let a = other::A(()); //~ ERROR: cannot invoke tuple struct constructor - let b = other::B(2); //~ ERROR: cannot invoke tuple struct constructor - let c = other::C(2, 3); //~ ERROR: cannot invoke tuple struct constructor + let a = other::A(()); //~ ERROR tuple struct `A` is private + let b = other::B(2); //~ ERROR tuple struct `B` is private + let c = other::C(2, 3); //~ ERROR tuple struct `C` is private let d = other::D(4); - let other::A(()) = a; //~ ERROR: field `0` of struct `other::A` is private - let other::A(_) = a; - match a { other::A(()) => {} } - //~^ ERROR: field `0` of struct `other::A` is private - match a { other::A(_) => {} } - - let other::B(_) = b; - let other::B(_b) = b; //~ ERROR: field `0` of struct `other::B` is private - match b { other::B(_) => {} } - match b { other::B(_b) => {} } - //~^ ERROR: field `0` of struct `other::B` is private - match b { other::B(1) => {} other::B(_) => {} } - //~^ ERROR: field `0` of struct `other::B` is private - - let other::C(_, _) = c; - let other::C(_a, _) = c; - let other::C(_, _b) = c; //~ ERROR: field `1` of struct `other::C` is private - let other::C(_a, _b) = c; //~ ERROR: field `1` of struct `other::C` is private - match c { other::C(_, _) => {} } - match c { other::C(_a, _) => {} } - match c { other::C(_, _b) => {} } - //~^ ERROR: field `1` of struct `other::C` is private - match c { other::C(_a, _b) => {} } - //~^ ERROR: field `1` of struct `other::C` is private + let other::A(()) = a; //~ ERROR tuple struct `A` is private + let other::A(_) = a; //~ ERROR tuple struct `A` is private + match a { other::A(()) => {} } //~ ERROR tuple struct `A` is private + match a { other::A(_) => {} } //~ ERROR tuple struct `A` is private + + let other::B(_) = b; //~ ERROR tuple struct `B` is private + let other::B(_b) = b; //~ ERROR tuple struct `B` is private + match b { other::B(_) => {} } //~ ERROR tuple struct `B` is private + match b { other::B(_b) => {} } //~ ERROR tuple struct `B` is private + match b { other::B(1) => {} other::B(_) => {} } //~ ERROR tuple struct `B` is private + //~^ ERROR tuple struct `B` is private + + let other::C(_, _) = c; //~ ERROR tuple struct `C` is private + let other::C(_a, _) = c; //~ ERROR tuple struct `C` is private + let other::C(_, _b) = c; //~ ERROR tuple struct `C` is private + let other::C(_a, _b) = c; //~ ERROR tuple struct `C` is private + match c { other::C(_, _) => {} } //~ ERROR tuple struct `C` is private + match c { other::C(_a, _) => {} } //~ ERROR tuple struct `C` is private + match c { other::C(_, _b) => {} } //~ ERROR tuple struct `C` is private + match c { other::C(_a, _b) => {} } //~ ERROR tuple struct `C` is private let other::D(_) = d; let other::D(_d) = d; @@ -132,9 +129,9 @@ fn xcrate() { match d { other::D(_d) => {} } match d { other::D(1) => {} other::D(_) => {} } - let a2 = other::A; //~ ERROR: cannot invoke tuple struct constructor - let b2 = other::B; //~ ERROR: cannot invoke tuple struct constructor - let c2 = other::C; //~ ERROR: cannot invoke tuple struct constructor + let a2 = other::A; //~ ERROR tuple struct `A` is private + let b2 = other::B; //~ ERROR tuple struct `B` is private + let c2 = other::C; //~ ERROR tuple struct `C` is private let d2 = other::D; } diff --git a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs index b8cbbdbe9ec3e..503b577b1f1b4 100644 --- a/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs +++ b/src/test/compile-fail/region-bounds-on-objects-and-type-parameters.rs @@ -18,7 +18,7 @@ trait SomeTrait { } // Bounds on object types: -struct Foo<'a,'b,'c> { +struct Foo<'a,'b,'c> { //~ ERROR parameter `'b` is never used // All of these are ok, because we can derive exactly one bound: a: Box, b: Box>, @@ -28,7 +28,9 @@ struct Foo<'a,'b,'c> { f: Box, // OK, defaults to 'static due to RFC 599. g: Box, - z: Box+'b+'c>, //~ ERROR only a single explicit lifetime bound is permitted + z: Box+'b+'c>, + //~^ ERROR only a single explicit lifetime bound is permitted + //~| ERROR lifetime bound not satisfied } fn test< diff --git a/src/test/compile-fail/region-object-lifetime-in-coercion.rs b/src/test/compile-fail/region-object-lifetime-in-coercion.rs index f95ee405895a9..687b2c344a3b7 100644 --- a/src/test/compile-fail/region-object-lifetime-in-coercion.rs +++ b/src/test/compile-fail/region-object-lifetime-in-coercion.rs @@ -14,8 +14,6 @@ trait Foo {} impl<'a> Foo for &'a [u8] {} -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - fn a(v: &[u8]) -> Box { let x: Box = Box::new(v); //~^ ERROR cannot infer an appropriate lifetime due to conflicting diff --git a/src/test/compile-fail/regions-close-associated-type-into-object.rs b/src/test/compile-fail/regions-close-associated-type-into-object.rs index 61897aac18769..6b88abfca6c91 100644 --- a/src/test/compile-fail/regions-close-associated-type-into-object.rs +++ b/src/test/compile-fail/regions-close-associated-type-into-object.rs @@ -10,8 +10,6 @@ #![feature(box_syntax)] -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - trait X {} trait Iter { diff --git a/src/test/compile-fail/regions-close-param-into-object.rs b/src/test/compile-fail/regions-close-param-into-object.rs index 7324d4a4a0ed6..c9063405bd7e2 100644 --- a/src/test/compile-fail/regions-close-param-into-object.rs +++ b/src/test/compile-fail/regions-close-param-into-object.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - trait X { fn foo(&self) {} } fn p1(v: T) -> Box diff --git a/src/test/compile-fail/regions-infer-paramd-indirect.rs b/src/test/compile-fail/regions-infer-paramd-indirect.rs index fad115c2aedf8..c559992c86531 100644 --- a/src/test/compile-fail/regions-infer-paramd-indirect.rs +++ b/src/test/compile-fail/regions-infer-paramd-indirect.rs @@ -32,8 +32,8 @@ impl<'a> set_f<'a> for c<'a> { fn set_f_bad(&mut self, b: Box) { self.f = b; //~^ ERROR mismatched types - //~| expected type `Box>` - //~| found type `Box>` + //~| expected type `std::boxed::Box>` + //~| found type `std::boxed::Box>` //~| lifetime mismatch } } diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index 5ef2a701a6005..010b7d1768812 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - fn ignore(t: T) {} fn nested<'x>(x: &'x isize) { diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs index 48b6e8b773f3b..fb726e31af586 100644 --- a/src/test/compile-fail/regions-proc-bound-capture.rs +++ b/src/test/compile-fail/regions-proc-bound-capture.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { // This is legal, because the region bound on `proc` // states that it captures `x`. diff --git a/src/test/compile-fail/regions-steal-closure.rs b/src/test/compile-fail/regions-steal-closure.rs index 59fe1ce3af1af..7ca63b9896fe0 100644 --- a/src/test/compile-fail/regions-steal-closure.rs +++ b/src/test/compile-fail/regions-steal-closure.rs @@ -21,7 +21,6 @@ fn box_it<'r>(x: Box) -> closure_box<'r> { fn main() { let mut cl_box = { let mut i = 3; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. box_it(Box::new(|| i += 1)) //~ ERROR `i` does not live long enough }; cl_box.cl.call_mut(()); diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 083cc218eecf3..93635e7fddea7 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -15,8 +15,10 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { } // the boundaries of elision -static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = &(non_elidable as fn(&u8, &u8) -> &u8); +static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = //~^ ERROR missing lifetime specifier [E0106] + &(non_elidable as fn(&u8, &u8) -> &u8); + //~^ ERROR missing lifetime specifier [E0106] struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, diff --git a/src/test/compile-fail/E0450.rs b/src/test/compile-fail/str-concat-on-double-ref.rs similarity index 52% rename from src/test/compile-fail/E0450.rs rename to src/test/compile-fail/str-concat-on-double-ref.rs index 200b58a329344..f85422f76d40e 100644 --- a/src/test/compile-fail/E0450.rs +++ b/src/test/compile-fail/str-concat-on-double-ref.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,14 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -mod Bar { - pub struct Foo( bool, pub i32, f32, bool); - //~^ NOTE private field declared here - //~| NOTE private field declared here - //~| NOTE private field declared here -} - fn main() { - let f = Bar::Foo(false,1,0.1, true); //~ ERROR E0450 - //~^ NOTE cannot construct with a private field + let a: &String = &"1".to_owned(); + let b: &str = &"2"; + let c = a + b; + //~^ ERROR binary operation `+` cannot be applied to type `&std::string::String` + //~| NOTE an implementation of `std::ops::Add` might be missing for `&std::string::String` + println!("{:?}", c); } diff --git a/src/test/compile-fail/struct-path-associated-type.rs b/src/test/compile-fail/struct-path-associated-type.rs index ecaf269fcb1ae..660ac44ce0b53 100644 --- a/src/test/compile-fail/struct-path-associated-type.rs +++ b/src/test/compile-fail/struct-path-associated-type.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(more_struct_aliases)] - struct S; trait Tr { diff --git a/src/test/compile-fail/struct-path-self-type-mismatch.rs b/src/test/compile-fail/struct-path-self-type-mismatch.rs index 8352bd6751f50..f694e7d277c7f 100644 --- a/src/test/compile-fail/struct-path-self-type-mismatch.rs +++ b/src/test/compile-fail/struct-path-self-type-mismatch.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(more_struct_aliases)] - struct Foo { inner: A } trait Bar { fn bar(); } diff --git a/src/test/compile-fail/struct-path-self.rs b/src/test/compile-fail/struct-path-self.rs index aeac199227b75..067d6ac22dc6f 100644 --- a/src/test/compile-fail/struct-path-self.rs +++ b/src/test/compile-fail/struct-path-self.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(more_struct_aliases)] - struct S; trait Tr { diff --git a/src/test/compile-fail/terr-sorts.rs b/src/test/compile-fail/terr-sorts.rs index 592d7b3929bfc..fd92a26d0fcec 100644 --- a/src/test/compile-fail/terr-sorts.rs +++ b/src/test/compile-fail/terr-sorts.rs @@ -20,8 +20,7 @@ fn want_foo(f: foo) {} fn have_bar(b: bar) { want_foo(b); //~ ERROR mismatched types //~| expected type `foo` - //~| found type `Box` - //~| expected struct `foo`, found box + //~| found type `std::boxed::Box` } fn main() {} diff --git a/src/test/compile-fail/trait-coercion-generic-bad.rs b/src/test/compile-fail/trait-coercion-generic-bad.rs index dd64085f6f666..3839e90ed9fe7 100644 --- a/src/test/compile-fail/trait-coercion-generic-bad.rs +++ b/src/test/compile-fail/trait-coercion-generic-bad.rs @@ -23,7 +23,6 @@ impl Trait<&'static str> for Struct { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let s: Box> = Box::new(Struct { person: "Fred" }); //~^ ERROR `Struct: Trait` is not satisfied s.f(1); diff --git a/src/test/compile-fail/trait-coercion-generic-regions.rs b/src/test/compile-fail/trait-coercion-generic-regions.rs index 9ba017e150e61..18d3ded77f8f3 100644 --- a/src/test/compile-fail/trait-coercion-generic-regions.rs +++ b/src/test/compile-fail/trait-coercion-generic-regions.rs @@ -25,6 +25,5 @@ impl Trait<&'static str> for Struct { fn main() { let person = "Fred".to_string(); let person: &str = &person; //~ ERROR `person` does not live long enough - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let s: Box> = Box::new(Struct { person: person }); } diff --git a/src/test/compile-fail/trivial_casts.rs b/src/test/compile-fail/trivial_casts.rs index 7693d98a2f7b0..aabf0d26d5ba7 100644 --- a/src/test/compile-fail/trivial_casts.rs +++ b/src/test/compile-fail/trivial_casts.rs @@ -52,7 +52,8 @@ pub fn main() { let _: *mut [u32] = x; let x: Box<[u32; 3]> = Box::new([42, 43, 44]); - let _ = x as Box<[u32]>; //~ERROR trivial cast: `Box<[u32; 3]>` as `Box<[u32]>` + let _ = x as Box<[u32]>; + //~^ ERROR trivial cast: `std::boxed::Box<[u32; 3]>` as `std::boxed::Box<[u32]>` let x: Box<[u32; 3]> = Box::new([42, 43, 44]); let _: Box<[u32]> = x; @@ -70,7 +71,7 @@ pub fn main() { let _: *mut Foo = x; let x: Box = Box::new(Bar); - let _ = x as Box; //~ERROR trivial cast: `Box` as `Box` + let _ = x as Box; //~ERROR trivial cast: `std::boxed::Box` as `std::boxed::Box` let x: Box = Box::new(Bar); let _: Box = x; diff --git a/src/test/compile-fail/type-mismatch-same-crate-name.rs b/src/test/compile-fail/type-mismatch-same-crate-name.rs index e74acaa71b0f3..4295d08a4709c 100644 --- a/src/test/compile-fail/type-mismatch-same-crate-name.rs +++ b/src/test/compile-fail/type-mismatch-same-crate-name.rs @@ -33,7 +33,7 @@ fn main() { //~^ ERROR mismatched types //~| Perhaps two different versions of crate `crate_a1` //~| expected trait `main::a::Bar` - //~| expected type `Box` - //~| found type `Box` + //~| expected type `std::boxed::Box` + //~| found type `std::boxed::Box` } } diff --git a/src/test/compile-fail/unboxed-closure-illegal-move.rs b/src/test/compile-fail/unboxed-closure-illegal-move.rs index 564b1b4669f7d..427be5607600d 100644 --- a/src/test/compile-fail/unboxed-closure-illegal-move.rs +++ b/src/test/compile-fail/unboxed-closure-illegal-move.rs @@ -18,8 +18,6 @@ fn to_fn>(f: F) -> F { f } fn to_fn_mut>(f: F) -> F { f } fn to_fn_once>(f: F) -> F { f } -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - fn main() { // By-ref cases { diff --git a/src/test/compile-fail/unboxed-closure-sugar-region.rs b/src/test/compile-fail/unboxed-closure-sugar-region.rs index 057b496bd43eb..18a1185d695f7 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-region.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-region.rs @@ -38,9 +38,9 @@ fn test<'a,'b>() { } fn test2(x: &Foo<(isize,),Output=()>, y: &Foo(isize)) { +//~^ ERROR wrong number of lifetime parameters: expected 1, found 0 // Here, the omitted lifetimes are expanded to distinct things. - same_type(x, y) //~ ERROR cannot infer - //~^ ERROR cannot infer + same_type(x, y) } fn main() { } diff --git a/src/test/compile-fail/uninhabited-matches-feature-gated.rs b/src/test/compile-fail/uninhabited-matches-feature-gated.rs new file mode 100644 index 0000000000000..0f8b0a6c238d0 --- /dev/null +++ b/src/test/compile-fail/uninhabited-matches-feature-gated.rs @@ -0,0 +1,50 @@ +// 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(slice_patterns)] + +enum Void {} + +fn main() { + let x: Result = Ok(23); + let _ = match x { //~ ERROR non-exhaustive + Ok(n) => n, + }; + + let x: &Void = unsafe { std::mem::uninitialized() }; + let _ = match x {}; + //~^ ERROR non-exhaustive + + let x: (Void,) = unsafe { std::mem::uninitialized() }; + let _ = match x {}; + //~^ ERROR non-exhaustive + + let x: [Void; 1] = unsafe { std::mem::uninitialized() }; + let _ = match x {}; + //~^ ERROR non-exhaustive + + let x: &[Void] = unsafe { std::mem::uninitialized() }; + let _ = match x { //~ ERROR non-exhaustive + &[] => (), + }; + + let x: Void = unsafe { std::mem::uninitialized() }; + let _ = match x {}; // okay + + let x: Result = Ok(23); + let _ = match x { //~ ERROR non-exhaustive + Ok(x) => x, + }; + + let x: Result = Ok(23); + let Ok(x) = x; + //~^ ERROR refutable +} + diff --git a/src/test/compile-fail/unique-pinned-nocopy.rs b/src/test/compile-fail/unique-pinned-nocopy.rs index d971940db38f5..c09feec1d4af2 100644 --- a/src/test/compile-fail/unique-pinned-nocopy.rs +++ b/src/test/compile-fail/unique-pinned-nocopy.rs @@ -18,7 +18,6 @@ impl Drop for r { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let i = Box::new(r { b: true }); let _j = i.clone(); //~ ERROR no method named `clone` found println!("{:?}", i); diff --git a/src/test/compile-fail/where-equality-constraints.rs b/src/test/compile-fail/where-equality-constraints.rs new file mode 100644 index 0000000000000..e449a736c753a --- /dev/null +++ b/src/test/compile-fail/where-equality-constraints.rs @@ -0,0 +1,16 @@ +// 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. + +fn f() where u8 = u16 {} +//~^ ERROR equality constraints are not yet supported in where clauses +fn g() where for<'a> &'static (u8,) == u16, {} +//~^ ERROR equality constraints are not yet supported in where clauses + +fn main() {} diff --git a/src/test/compile-fail/where-lifetime-resolution.rs b/src/test/compile-fail/where-lifetime-resolution.rs new file mode 100644 index 0000000000000..f4c6842206db1 --- /dev/null +++ b/src/test/compile-fail/where-lifetime-resolution.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. + +trait Trait1 {} +trait Trait2 {} + +fn f() where + for<'a> Trait1<'a>: Trait1<'a>, // OK + (for<'a> Trait1<'a>): Trait1<'a>, + //~^ ERROR use of undeclared lifetime name `'a` + for<'a> for<'b> Trait2<'a, 'b>: Trait2<'a, 'b>, + //~^ ERROR use of undeclared lifetime name `'b` + //~| ERROR nested quantification of lifetimes +{} + +fn main() {} diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index 438a78743bb1e..57d40cccf2d80 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -70,12 +70,12 @@ // BOX // gdb-command:whatis box1 -// gdbg-check:type = struct (Box, i32) -// gdbr-check:type = (Box, i32) +// gdbg-check:type = struct (alloc::boxed::Box, i32) +// gdbr-check:type = (alloc::boxed::Box, i32) // gdb-command:whatis box2 -// gdbg-check:type = struct (Box>, i32) -// gdbr-check:type = (Box>, i32) +// gdbg-check:type = struct (alloc::boxed::Box>, i32) +// gdbr-check:type = (alloc::boxed::Box>, i32) // REFERENCES @@ -196,8 +196,8 @@ // gdbr-check:type = (unsafe fn(type_names::GenericStruct) -> type_names::mod1::Struct2, usize) // gdb-command:whatis extern_stdcall_fn_with_return_value -// gdbg-check:type = struct (extern "stdcall" fn(Box) -> usize, usize) -// gdbr-check:type = (extern "stdcall" fn(Box) -> usize, usize) +// gdbg-check:type = struct (extern "stdcall" fn(alloc::boxed::Box) -> usize, usize) +// gdbr-check:type = (extern "stdcall" fn(alloc::boxed::Box) -> usize, usize) // gdb-command:whatis generic_function_int // gdbg-check:type = struct (fn(isize) -> isize, usize) diff --git a/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs b/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs index adc2b23441ef8..1064c97b744a4 100644 --- a/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs +++ b/src/test/incremental/add_private_fn_at_krate_root_cc/auxiliary/point.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + pub struct Point { pub x: f32, pub y: f32, diff --git a/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs index d802c9a8352eb..a02b71a753cc3 100644 --- a/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + #![crate_type="rlib"] #[cfg(rpass1)] diff --git a/src/test/incremental/change_private_fn_cc/auxiliary/point.rs b/src/test/incremental/change_private_fn_cc/auxiliary/point.rs index dcc1ced635fbf..08eef2a73f68f 100644 --- a/src/test/incremental/change_private_fn_cc/auxiliary/point.rs +++ b/src/test/incremental/change_private_fn_cc/auxiliary/point.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + pub struct Point { pub x: f32, pub y: f32, diff --git a/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs b/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs index 8df1cf54da2b9..e69dc51119e92 100644 --- a/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs +++ b/src/test/incremental/change_private_impl_method_cc/auxiliary/point.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + pub struct Point { pub x: f32, pub y: f32, diff --git a/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs b/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs index 4d84e844dedbb..39547fb7359f5 100644 --- a/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs +++ b/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + #![allow(warnings)] #![crate_name = "a"] #![crate_type = "rlib"] diff --git a/src/test/incremental/rlib_cross_crate/auxiliary/a.rs b/src/test/incremental/rlib_cross_crate/auxiliary/a.rs index ff5fd63471449..3ecd9aff3f8cd 100644 --- a/src/test/incremental/rlib_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/rlib_cross_crate/auxiliary/a.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc // no-prefer-dynamic #![crate_type="rlib"] diff --git a/src/test/incremental/struct_change_field_type_cross_crate/auxiliary/a.rs b/src/test/incremental/struct_change_field_type_cross_crate/auxiliary/a.rs index 2ddcaf157210d..d14ebf78d8222 100644 --- a/src/test/incremental/struct_change_field_type_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/struct_change_field_type_cross_crate/auxiliary/a.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + #![crate_type="rlib"] #[cfg(rpass1)] diff --git a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs index e1dba1317703d..0393bcda99156 100644 --- a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs +++ b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z incremental-cc + #![crate_type="rlib"] #[cfg(rpass1)] diff --git a/src/test/parse-fail/bounds-lifetime-1.rs b/src/test/parse-fail/bounds-lifetime-1.rs new file mode 100644 index 0000000000000..824d243d5f846 --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime-1.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. + +// compile-flags: -Z parse-only + +type A = for<'a 'b> fn(); //~ ERROR expected one of `,`, `:`, or `>`, found `'b` + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-2.rs b/src/test/parse-fail/bounds-lifetime-2.rs new file mode 100644 index 0000000000000..3c67dda70f562 --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime-2.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. + +// compile-flags: -Z parse-only + +type A = for<'a + 'b> fn(); //~ ERROR expected one of `,`, `:`, or `>`, found `+` + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-where-1.rs b/src/test/parse-fail/bounds-lifetime-where-1.rs new file mode 100644 index 0000000000000..aae9d72998750 --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime-where-1.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. + +// compile-flags: -Z parse-only + +type A where 'a; //~ ERROR expected `:`, found `;` + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime-where.rs b/src/test/parse-fail/bounds-lifetime-where.rs new file mode 100644 index 0000000000000..0a30818bc96ae --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime-where.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. + +// compile-flags: -Z parse-only + +type A where 'a: 'b + 'c = u8; // OK +type A where 'a: 'b, = u8; // OK +type A where 'a: = u8; // OK +type A where 'a:, = u8; // OK +type A where 'a: 'b + 'c = u8; // OK +type A where = u8; // OK +type A where 'a: 'b + = u8; // OK +type A where , = u8; //~ ERROR expected one of `=`, lifetime, or type, found `,` + +fn main() {} diff --git a/src/test/parse-fail/bounds-lifetime.rs b/src/test/parse-fail/bounds-lifetime.rs new file mode 100644 index 0000000000000..5113a6b4803fc --- /dev/null +++ b/src/test/parse-fail/bounds-lifetime.rs @@ -0,0 +1,24 @@ +// 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 + +type A = for<'a: 'b + 'c> fn(); // OK +type A = for<'a: 'b,> fn(); // OK +type A = for<'a:> fn(); // OK +type A = for<'a:,> fn(); // OK +type A = for<'a> fn(); // OK +type A = for<> fn(); // OK +type A = for<'a: 'b +> fn(); // OK + +type A = for<'a, T> fn(); //~ ERROR only lifetime parameters can be used in this context +type A = for<,> fn(); //~ ERROR expected one of `>`, identifier, or lifetime, found `,` + +fn main() {} diff --git a/src/test/parse-fail/bounds-type-where.rs b/src/test/parse-fail/bounds-type-where.rs new file mode 100644 index 0000000000000..9dc5d8277446d --- /dev/null +++ b/src/test/parse-fail/bounds-type-where.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. + +// compile-flags: -Z parse-only + +type A where for<'a> for<'b> Trait1 + ?Trait2: 'a + Trait = u8; // OK +type A where T: Trait, = u8; // OK +type A where T: = u8; // OK +type A where T:, = u8; // OK +type A where T: Trait + Trait = u8; // OK +type A where = u8; // OK +type A where T: Trait + = u8; // OK +type A where T, = u8; +//~^ ERROR expected one of `!`, `(`, `+`, `::`, `:`, `<`, `==`, or `=`, found `,` + +fn main() {} diff --git a/src/test/parse-fail/bounds-type.rs b/src/test/parse-fail/bounds-type.rs new file mode 100644 index 0000000000000..c224b44a14bf1 --- /dev/null +++ b/src/test/parse-fail/bounds-type.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. + +// compile-flags: -Z parse-only -Z continue-parse-after-error + +struct S< + T: 'a + Tr, // OK + T: Tr + 'a, // OK + T: 'a, // OK + T:, // OK + T: ?for<'a: 'b + 'c> Trait, // OK + T: Tr +, // OK + T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds +>; + +fn main() {} diff --git a/src/test/parse-fail/issue-14303-path.rs b/src/test/parse-fail/issue-14303-path.rs index 431a917c2d9f4..f0d1feffec80b 100644 --- a/src/test/parse-fail/issue-14303-path.rs +++ b/src/test/parse-fail/issue-14303-path.rs @@ -12,4 +12,3 @@ fn bar<'a, T>(x: mymodule::X<'a, T, 'b, 'c>) {} //~^ ERROR lifetime parameters must be declared prior to type parameters -//~^^ ERROR expected pattern, found `'c` diff --git a/src/test/parse-fail/generic-non-trailing-defaults.rs b/src/test/parse-fail/issue-17904-2.rs similarity index 74% rename from src/test/parse-fail/generic-non-trailing-defaults.rs rename to src/test/parse-fail/issue-17904-2.rs index 2bb593258ae4b..3f41c0edd2e6f 100644 --- a/src/test/parse-fail/generic-non-trailing-defaults.rs +++ b/src/test/parse-fail/issue-17904-2.rs @@ -10,10 +10,6 @@ // compile-flags: -Z parse-only -Z continue-parse-after-error -struct Heap; - -struct Vec; //~ ERROR type parameters with a default must be trailing - -struct Foo, C>; //~ ERROR type parameters with a default must be trailing +struct Bar { x: T } where T: Copy //~ ERROR expected item, found `where` fn main() {} diff --git a/src/test/parse-fail/issue-17904.rs b/src/test/parse-fail/issue-17904.rs index de5aeb02ab788..ae28ac76acb98 100644 --- a/src/test/parse-fail/issue-17904.rs +++ b/src/test/parse-fail/issue-17904.rs @@ -13,7 +13,6 @@ struct Baz where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax. struct Baz where U: Eq(U) -> R; // Notice this parses as well. struct Baz(U) where U: Eq; // This rightfully signals no error as well. -struct Foo where T: Copy, (T); //~ ERROR unexpected token in `where` clause -struct Bar { x: T } where T: Copy //~ ERROR expected item, found `where` +struct Foo where T: Copy, (T); //~ ERROR expected one of `+`, `:`, `==`, or `=`, found `;` fn main() {} diff --git a/src/test/parse-fail/issue-32214.rs b/src/test/parse-fail/issue-32214.rs index 3ba59c8ee946b..9e20009409368 100644 --- a/src/test/parse-fail/issue-32214.rs +++ b/src/test/parse-fail/issue-32214.rs @@ -10,8 +10,7 @@ // compile-flags: -Z parse-only -Z continue-parse-after-error -pub fn test >() { - //~^ ERROR expected `=`, found `>` -} +pub fn test >() {} +//~^ ERROR type parameters must be declared prior to associated type bindings fn main() { } diff --git a/src/test/parse-fail/issue-39018.stderr b/src/test/parse-fail/issue-39018.stderr new file mode 100644 index 0000000000000..ee1a32c4c16cf --- /dev/null +++ b/src/test/parse-fail/issue-39018.stderr @@ -0,0 +1,28 @@ +error[E0369]: binary operation `+` cannot be applied to type `&'static str` + --> src/test/ui/span/issue-39018.rs:2:13 + | +2 | let x = "Hello " + "World!"; + | ^^^^^^^^ + | +note: `+` can't be used to concatenate two `&str` strings + --> src/test/ui/span/issue-39018.rs:2:13 + | +2 | let x = "Hello " + "World!"; + | ^^^^^^^^ +help: to_owned() can be used to create an owned `String` from a string reference. This allows concatenation since the `String` is owned. + | let x = "Hello ".to_owned() + "World!"; + +error[E0369]: binary operation `+` cannot be applied to type `World` + --> src/test/ui/span/issue-39018.rs:7:13 + | +7 | let y = World::Hello + World::Goodbye; + | ^^^^^^^^^^^^ + | +note: an implementation of `std::ops::Add` might be missing for `World` + --> src/test/ui/span/issue-39018.rs:7:13 + | +7 | let y = World::Hello + World::Goodbye; + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/parse-fail/lifetime-semicolon.rs b/src/test/parse-fail/lifetime-semicolon.rs index 7010d0e7debf2..e1975952fca3e 100644 --- a/src/test/parse-fail/lifetime-semicolon.rs +++ b/src/test/parse-fail/lifetime-semicolon.rs @@ -15,5 +15,4 @@ struct Foo<'a, 'b> { } fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {} -//~^ ERROR expected `,` or `>` after lifetime name, found `;` -//~^^ NOTE did you mean a single argument type &'a Type, or did you mean the comma-separated +//~^ ERROR expected one of `,` or `>`, found `;` diff --git a/src/test/parse-fail/tuple-float-index.rs b/src/test/parse-fail/tuple-float-index.rs index f3f5e35634682..57ad89ad37404 100644 --- a/src/test/parse-fail/tuple-float-index.rs +++ b/src/test/parse-fail/tuple-float-index.rs @@ -12,5 +12,6 @@ fn main () { (1, (2, 3)).1.1; //~ ERROR unexpected token - //~^ HELP try parenthesizing the first index; e.g., `(foo.1).1` + //~^ HELP try parenthesizing the first index + //~| SUGGESTION ((1, (2, 3)).1).1 } diff --git a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs index 78d9745408735..cf67b518fff91 100644 --- a/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs +++ b/src/test/parse-fail/where-clauses-no-bounds-or-predicates.rs @@ -10,13 +10,13 @@ // compile-flags: -Z parse-only -Z continue-parse-after-error +// Empty predicate list is OK fn equal1(_: &T, _: &T) -> bool where { -//~^ ERROR a `where` clause must have at least one predicate in it true } +// Empty bound list is OK fn equal2(_: &T, _: &T) -> bool where T: { -//~^ ERROR each predicate in a `where` clause must have at least one bound true } diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index 29cc6b7db9474..aa2f1626a6a86 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -38,15 +38,12 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_macro("identity", expand_identity); reg.register_syntax_extension( Symbol::intern("into_multi_foo"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiModifier(Box::new(expand_into_foo_multi))); reg.register_syntax_extension( Symbol::intern("duplicate"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiDecorator(Box::new(expand_duplicate))); reg.register_syntax_extension( Symbol::intern("caller"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiDecorator(Box::new(expand_caller))); } diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs index ba2af77cdb297..3c8868f1664e8 100644 --- a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs +++ b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs @@ -48,6 +48,5 @@ impl TTMacroExpander for Expander { pub fn plugin_registrar(reg: &mut Registry) { let args = reg.args().to_owned(); reg.register_syntax_extension(Symbol::intern("plugin_args"), - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. NormalTT(Box::new(Expander { args: args, }), None, false)); } diff --git a/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs b/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs index 328cc134f3b1f..1573b0807173f 100644 --- a/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs +++ b/src/test/run-pass-fulldeps/deriving-encodable-decodable-box.rs @@ -24,7 +24,6 @@ struct A { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let obj = A { foo: Box::new([true, false]) }; let s = json::encode(&obj).unwrap(); let obj2: A = json::decode(&s).unwrap(); diff --git a/src/test/run-pass-valgrind/dst-dtor-1.rs b/src/test/run-pass-valgrind/dst-dtor-1.rs index 995da8c73fab8..4af642a106c15 100644 --- a/src/test/run-pass-valgrind/dst-dtor-1.rs +++ b/src/test/run-pass-valgrind/dst-dtor-1.rs @@ -28,7 +28,6 @@ struct Fat { pub fn main() { { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let _x: Box> = Box::>::new(Fat { f: Foo }); } unsafe { diff --git a/src/test/run-pass-valgrind/dst-dtor-2.rs b/src/test/run-pass-valgrind/dst-dtor-2.rs index 471169340d793..283b8202b35d0 100644 --- a/src/test/run-pass-valgrind/dst-dtor-2.rs +++ b/src/test/run-pass-valgrind/dst-dtor-2.rs @@ -25,7 +25,6 @@ struct Fat { pub fn main() { { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let _x: Box> = Box::>::new(Fat { f: [Foo, Foo, Foo] }); } unsafe { diff --git a/src/test/run-pass/associated-types-doubleendediterator-object.rs b/src/test/run-pass/associated-types-doubleendediterator-object.rs index dd194447740b7..0a6135080bb6e 100644 --- a/src/test/run-pass/associated-types-doubleendediterator-object.rs +++ b/src/test/run-pass/associated-types-doubleendediterator-object.rs @@ -26,7 +26,6 @@ fn pairwise_sub(mut t: Box>) -> isize { fn main() { let v = vec![1, 2, 3, 4, 5, 6]; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let r = pairwise_sub(Box::new(v.into_iter())); assert_eq!(r, 9); } diff --git a/src/test/run-pass/auxiliary/issue13507.rs b/src/test/run-pass/auxiliary/issue13507.rs index ba50aed42c36f..ee7d45b77bf4d 100644 --- a/src/test/run-pass/auxiliary/issue13507.rs +++ b/src/test/run-pass/auxiliary/issue13507.rs @@ -58,7 +58,7 @@ pub mod testtypes { // Tests TySlice pub type FooSlice = [u8]; - // Tests TyBox (of u8) + // Tests Box (of u8) pub type FooBox = Box; // Tests TyRawPtr diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 72cf109fd5974..626eccfc9ec86 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -37,7 +37,6 @@ macro_rules! dump_and_die { target_os = "ios", target_os = "android", all(target_os = "linux", target_arch = "arm"), - target_os = "windows", target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", @@ -173,4 +172,3 @@ fn main() { run_test(&args[0]); } } - diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 75c665b04a123..834ce984e6632 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -104,10 +104,6 @@ fn runtest(me: &str) { } fn main() { - if cfg!(windows) && cfg!(target_env = "gnu") { - return - } - let args: Vec = env::args().collect(); if args.len() >= 2 && args[1] == "fail" { foo(); diff --git a/src/test/run-pass/coerce-expect-unsized.rs b/src/test/run-pass/coerce-expect-unsized.rs index e4792e7936bc4..a074aea9caa5c 100644 --- a/src/test/run-pass/coerce-expect-unsized.rs +++ b/src/test/run-pass/coerce-expect-unsized.rs @@ -19,15 +19,6 @@ use std::rc::Rc; // rvalue expressions to be unsized. See #20169 for more information. pub fn main() { - // FIXME #22405: We cannot infer the type `Box<[isize; k]>` for - // the r-value expression from the context `Box<[isize]>`, and - // therefore the `box EXPR` desugaring breaks down. - // - // One could reasonably claim that the `box EXPR` desugaring is - // effectively regressing half of Issue #20169. Hopefully we will - // eventually fix that, at which point the `Box::new` calls below - // should be replaced wth uses of `box`. - let _: Box<[isize]> = Box::new({ [1, 2, 3] }); let _: Box<[isize]> = Box::new(if true { [1, 2, 3] } else { [1, 3, 4] }); let _: Box<[isize]> = Box::new(match true { true => [1, 2, 3], false => [1, 3, 4] }); diff --git a/src/test/run-pass/deriving-default-box.rs b/src/test/run-pass/deriving-default-box.rs index dc31e71aad873..c9e5b014da37a 100644 --- a/src/test/run-pass/deriving-default-box.rs +++ b/src/test/run-pass/deriving-default-box.rs @@ -21,7 +21,6 @@ struct A { pub fn main() { let a: A = Default::default(); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let b: Box<[_]> = Box::<[bool; 0]>::new([]); assert_eq!(a.foo, b); } diff --git a/src/test/run-pass/deriving-eq-ord-boxed-slice.rs b/src/test/run-pass/deriving-eq-ord-boxed-slice.rs index f490cca6a699d..16c49065008aa 100644 --- a/src/test/run-pass/deriving-eq-ord-boxed-slice.rs +++ b/src/test/run-pass/deriving-eq-ord-boxed-slice.rs @@ -12,7 +12,6 @@ struct Foo(Box<[u8]>); pub fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let a = Foo(Box::new([0, 1, 2])); let b = Foo(Box::new([0, 1, 2])); assert_eq!(a, b); diff --git a/src/test/run-pass/dst-deref-mut.rs b/src/test/run-pass/dst-deref-mut.rs index 0666e41738e3c..9fb4635765ca0 100644 --- a/src/test/run-pass/dst-deref-mut.rs +++ b/src/test/run-pass/dst-deref-mut.rs @@ -39,7 +39,6 @@ pub fn foo(arr: &mut Arr) { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let mut a = Arr { ptr: Box::new([1, 2, 3]) }; foo(&mut a); } diff --git a/src/test/run-pass/dst-deref.rs b/src/test/run-pass/dst-deref.rs index 957ed13a3d817..4a143873e6e13 100644 --- a/src/test/run-pass/dst-deref.rs +++ b/src/test/run-pass/dst-deref.rs @@ -34,7 +34,6 @@ pub fn foo(arr: &Arr) { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let a = Arr { ptr: Box::new([1, 2, 3]) }; foo(&a); } diff --git a/src/test/run-pass/dst-struct.rs b/src/test/run-pass/dst-struct.rs index 94efa7a256b4d..56199c1aa61fa 100644 --- a/src/test/run-pass/dst-struct.rs +++ b/src/test/run-pass/dst-struct.rs @@ -127,7 +127,6 @@ pub fn main() { let f2 : Box> = f1; foo(&*f2); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let f3 : Box> = Box::>::new(Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }); foo(&*f3); diff --git a/src/test/run-pass/dst-trait.rs b/src/test/run-pass/dst-trait.rs index 9d12a4a34b7d4..d8d7d9a28bfbd 100644 --- a/src/test/run-pass/dst-trait.rs +++ b/src/test/run-pass/dst-trait.rs @@ -97,7 +97,6 @@ pub fn main() { // &* // - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let f7: Box = Box::new(Bar1 {f :42}); bar(&*f7); diff --git a/src/test/run-pass/empty-allocation-non-null.rs b/src/test/run-pass/empty-allocation-non-null.rs index af6e321e40aa6..3dbe7da6ac704 100644 --- a/src/test/run-pass/empty-allocation-non-null.rs +++ b/src/test/run-pass/empty-allocation-non-null.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - - pub fn main() { assert!(Some(Box::new(())).is_some()); diff --git a/src/test/run-pass/extern_fat_drop.rs b/src/test/run-pass/extern_fat_drop.rs index deb7e6bd53986..8ce1f744dee17 100644 --- a/src/test/run-pass/extern_fat_drop.rs +++ b/src/test/run-pass/extern_fat_drop.rs @@ -10,8 +10,6 @@ // aux-build:fat_drop.rs -#![feature(drop_in_place)] - extern crate fat_drop; fn main() { diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index 2306fa9afa2ef..bd90ce683c452 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -62,7 +62,6 @@ mod map_reduce { } let ctrl_clone = ctrl.clone(); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. ::map(input, Box::new(|a,b| emit(&mut intermediates, ctrl.clone(), a, b))); ctrl_clone.send(ctrl_proto::mapper_done).unwrap(); } diff --git a/src/test/run-pass/hrtb-precedence-of-plus.rs b/src/test/run-pass/hrtb-precedence-of-plus.rs index d93e52a8f5fbb..516278df178eb 100644 --- a/src/test/run-pass/hrtb-precedence-of-plus.rs +++ b/src/test/run-pass/hrtb-precedence-of-plus.rs @@ -17,7 +17,6 @@ // cause a compilation error. Issue #18772. fn adder(y: isize) -> Box isize + 'static> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Box::new(move |x| y + x) } diff --git a/src/test/run-pass/issue-11205.rs b/src/test/run-pass/issue-11205.rs index 679d494a47302..25c66bf8d485f 100644 --- a/src/test/run-pass/issue-11205.rs +++ b/src/test/run-pass/issue-11205.rs @@ -12,8 +12,6 @@ #![allow(dead_code)] -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - trait Foo { fn dummy(&self) { } } impl Foo for isize {} fn foo(_: [&Foo; 2]) {} diff --git a/src/test/run-pass/issue-11677.rs b/src/test/run-pass/issue-11677.rs index d4244d44439b0..62da3b1467559 100644 --- a/src/test/run-pass/issue-11677.rs +++ b/src/test/run-pass/issue-11677.rs @@ -27,6 +27,5 @@ impl X for F { } fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. S {f: Box::new(F), g: Box::new(F) }; } diff --git a/src/test/run-pass/issue-12744.rs b/src/test/run-pass/issue-12744.rs index 56d1d3599c7fd..aec45216b1b73 100644 --- a/src/test/run-pass/issue-12744.rs +++ b/src/test/run-pass/issue-12744.rs @@ -9,7 +9,6 @@ // except according to those terms. fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. fn test() -> Box { Box::new(1) } println!("{:?}", test()) } diff --git a/src/test/run-pass/issue-13808.rs b/src/test/run-pass/issue-13808.rs index c85c0117581a5..ccdfa0646c6aa 100644 --- a/src/test/run-pass/issue-13808.rs +++ b/src/test/run-pass/issue-13808.rs @@ -16,7 +16,6 @@ struct Foo<'a> { impl<'a> Foo<'a> { fn new(listener: F) -> Foo<'a> where F: FnMut() + 'a { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Foo { listener: Box::new(listener) } } } diff --git a/src/test/run-pass/issue-14589.rs b/src/test/run-pass/issue-14589.rs index b0893e21af7e9..8aaa24e991ea1 100644 --- a/src/test/run-pass/issue-14589.rs +++ b/src/test/run-pass/issue-14589.rs @@ -11,8 +11,6 @@ // All 3 expressions should work in that the argument gets // coerced to a trait object -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - // pretty-expanded FIXME #23616 fn main() { diff --git a/src/test/run-pass/issue-14919.rs b/src/test/run-pass/issue-14919.rs index d3c9fe9161ccb..df5d62e7699bb 100644 --- a/src/test/run-pass/issue-14919.rs +++ b/src/test/run-pass/issue-14919.rs @@ -31,7 +31,6 @@ trait IntoMatcher<'a, T> { impl<'a, 'b, F> IntoMatcher<'a, CharPredMatcher<'a, 'b>> for F where F: FnMut(char) -> bool + 'b { fn into_matcher(self, s: &'a str) -> CharPredMatcher<'a, 'b> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. CharPredMatcher { str: s, pred: Box::new(self), diff --git a/src/test/run-pass/issue-16668.rs b/src/test/run-pass/issue-16668.rs index 18861feb1997a..5613211b31df4 100644 --- a/src/test/run-pass/issue-16668.rs +++ b/src/test/run-pass/issue-16668.rs @@ -16,7 +16,6 @@ struct Parser<'a, I, O> { impl<'a, I: 'a, O: 'a> Parser<'a, I, O> { fn compose(mut self, mut rhs: Parser<'a, O, K>) -> Parser<'a, I, K> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Parser { parse: Box::new(move |x: I| { match (self.parse)(x) { diff --git a/src/test/run-pass/issue-17734.rs b/src/test/run-pass/issue-17734.rs index 0fc8eea778da9..8178c1fd7c885 100644 --- a/src/test/run-pass/issue-17734.rs +++ b/src/test/run-pass/issue-17734.rs @@ -17,8 +17,6 @@ fn f(s: Box) -> Box { fn main() { // There is currently no safe way to construct a `Box`, so improvise - // - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let box_arr: Box<[u8]> = Box::new(['h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8]); let box_str: Box = unsafe { std::mem::transmute(box_arr) }; assert_eq!(&*box_str, "hello"); diff --git a/src/test/run-pass/issue-20575.rs b/src/test/run-pass/issue-20575.rs index e73492e7a7ee5..7db7e3b28e8e6 100644 --- a/src/test/run-pass/issue-20575.rs +++ b/src/test/run-pass/issue-20575.rs @@ -13,7 +13,6 @@ // pretty-expanded FIXME #23616 fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; let _: Option> = functions.iter().map(|f| (*f)()).collect(); diff --git a/src/test/run-pass/issue-3052.rs b/src/test/run-pass/issue-3052.rs index 8f013ee4f3a0f..3b56b2e28ff22 100644 --- a/src/test/run-pass/issue-3052.rs +++ b/src/test/run-pass/issue-3052.rs @@ -13,7 +13,6 @@ type Connection = Box) + 'static>; fn f() -> Option { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let mock_connection: Connection = Box::new(|_| {}); Some(mock_connection) } diff --git a/src/test/run-pass/issue-3609.rs b/src/test/run-pass/issue-3609.rs index 61de3c6385e7b..d1bf7e066cb5a 100644 --- a/src/test/run-pass/issue-3609.rs +++ b/src/test/run-pass/issue-3609.rs @@ -26,7 +26,6 @@ fn foo(name: String, samples_chan: Sender) { thread::spawn(move|| { let mut samples_chan = samples_chan; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let callback: SamplesFn = Box::new(move |buffer| { for i in 0..buffer.len() { println!("{}: {}", i, buffer[i]) diff --git a/src/test/run-pass/match-arm-statics.rs b/src/test/run-pass/match-arm-statics.rs index 9700ed247959b..78a37f5183786 100644 --- a/src/test/run-pass/match-arm-statics.rs +++ b/src/test/run-pass/match-arm-statics.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -g #[derive(PartialEq, Eq)] struct NewBool(bool); diff --git a/src/test/run-pass/newlambdas-ret-infer.rs b/src/test/run-pass/newlambdas-ret-infer.rs index 543dbb36b2850..428eed0787a83 100644 --- a/src/test/run-pass/newlambdas-ret-infer.rs +++ b/src/test/run-pass/newlambdas-ret-infer.rs @@ -11,7 +11,6 @@ // Test that the lambda kind is inferred correctly as a return // expression -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. // pretty-expanded FIXME #23616 fn unique() -> Box { return Box::new(|| ()); } diff --git a/src/test/run-pass/newlambdas-ret-infer2.rs b/src/test/run-pass/newlambdas-ret-infer2.rs index e8297173a5834..439ea3f2b579c 100644 --- a/src/test/run-pass/newlambdas-ret-infer2.rs +++ b/src/test/run-pass/newlambdas-ret-infer2.rs @@ -11,7 +11,6 @@ // Test that the lambda kind is inferred correctly as a return // expression -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. // pretty-expanded FIXME #23616 fn unique() -> Box { Box::new(|| ()) } diff --git a/src/test/run-pass/object-lifetime-default-from-ref-struct.rs b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs index 910d933d46f08..6aaf892097136 100644 --- a/src/test/run-pass/object-lifetime-default-from-ref-struct.rs +++ b/src/test/run-pass/object-lifetime-default-from-ref-struct.rs @@ -15,6 +15,8 @@ #![allow(dead_code)] +use std::fmt::Display; + trait Test { fn foo(&self) { } } @@ -23,6 +25,11 @@ struct Ref<'a,T:'a+?Sized> { r: &'a T } +struct Ref2<'a,'b,T:'a+'b+?Sized> { + a: &'a T, + b: &'b T +} + struct SomeStruct<'a> { t: Ref<'a,Test>, u: Ref<'a,Test+'a>, @@ -44,6 +51,17 @@ fn d<'a>(t: Ref<'a,Test+'a>, mut ss: SomeStruct<'a>) { ss.u = t; } +fn e<'a>(_: Ref<'a, Display+'static>) {} +fn g<'a, 'b>(_: Ref2<'a, 'b, Display+'static>) {} + fn main() { + // Inside a function body, we can just infer all + // lifetimes, to allow Ref<'tmp, Display+'static> + // and Ref2<'tmp, 'tmp, Display+'static>. + let x = &0 as &(Display+'static); + let r: Ref = Ref { r: x }; + let r2: Ref2 = Ref2 { a: x, b: x }; + e(r); + g(r2); } diff --git a/src/test/run-pass/object-lifetime-default-from-rptr.rs b/src/test/run-pass/object-lifetime-default-from-rptr.rs index d9e0b22fbfa4b..cbff0d4dbaa3c 100644 --- a/src/test/run-pass/object-lifetime-default-from-rptr.rs +++ b/src/test/run-pass/object-lifetime-default-from-rptr.rs @@ -15,6 +15,8 @@ #![allow(dead_code)] +use std::fmt::Display; + trait Test { fn foo(&self) { } } @@ -40,6 +42,10 @@ fn d<'a>(t: &'a (Test+'a), mut ss: SomeStruct<'a>) { ss.u = t; } +fn e<'a>(_: &'a (Display+'static)) {} fn main() { + // Inside a function body, we can just infer both + // lifetimes, to allow &'tmp (Display+'static). + e(&0 as &Display); } diff --git a/src/test/run-pass/regions-fn-subtyping.rs b/src/test/run-pass/regions-fn-subtyping.rs index fc42fbc714c09..c7a4accff85e1 100644 --- a/src/test/run-pass/regions-fn-subtyping.rs +++ b/src/test/run-pass/regions-fn-subtyping.rs @@ -16,8 +16,6 @@ #![allow(unused_variables)] #![allow(unknown_features)] -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - // Should pass region checking. fn ok(f: Box) { // Here, g is a function that can accept a usize pointer with diff --git a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs index 8eee54b3fec66..ae4adbfb1f497 100644 --- a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs +++ b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs @@ -31,7 +31,6 @@ struct Foo<'a,'tcx:'a> { impl<'a,'tcx> Foo<'a,'tcx> { fn bother(&mut self) -> isize { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. self.elaborate_bounds(Box::new(|this| { // (*) Here: type of `this` is `&'f0 Foo<&'f1, '_2>`, // where `'f0` and `'f1` are fresh, free regions that diff --git a/src/test/run-pass/show-boxed-slice.rs b/src/test/run-pass/show-boxed-slice.rs index 03971668182ac..47d0737dfc451 100644 --- a/src/test/run-pass/show-boxed-slice.rs +++ b/src/test/run-pass/show-boxed-slice.rs @@ -12,6 +12,5 @@ struct Foo(Box<[u8]>); pub fn main() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. println!("{:?}", Foo(Box::new([0, 1, 2]))); } diff --git a/src/test/run-pass/struct-path-associated-type.rs b/src/test/run-pass/struct-path-associated-type.rs index 292761dfd005f..b033ed5c80210 100644 --- a/src/test/run-pass/struct-path-associated-type.rs +++ b/src/test/run-pass/struct-path-associated-type.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(more_struct_aliases)] - struct S { a: T, b: U, diff --git a/src/test/run-pass/struct-path-self.rs b/src/test/run-pass/struct-path-self.rs index b569ab62c1bfa..c7a282c2a2fa0 100644 --- a/src/test/run-pass/struct-path-self.rs +++ b/src/test/run-pass/struct-path-self.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(more_struct_aliases)] - use std::ops::Add; struct S { diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 9877dffe9df02..c58442aa58f33 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -105,7 +105,6 @@ fn check_legs(arc: Arc>>) { } fn check_names(arc: Arc>>) { for pet in arc.iter() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. pet.name(Box::new(|name| { assert!(name.as_bytes()[0] == 'a' as u8 && name.as_bytes()[1] == 'l' as u8); })) diff --git a/src/test/run-pass/trait-coercion-generic.rs b/src/test/run-pass/trait-coercion-generic.rs index f9a22d5ccec6d..40453262ddf3a 100644 --- a/src/test/run-pass/trait-coercion-generic.rs +++ b/src/test/run-pass/trait-coercion-generic.rs @@ -26,7 +26,6 @@ impl Trait<&'static str> for Struct { pub fn main() { let a = Struct { x: 1, y: 2 }; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let b: Box> = Box::new(a); b.f("Mary"); let c: &Trait<&'static str> = &a; diff --git a/src/test/run-pass/trait-coercion.rs b/src/test/run-pass/trait-coercion.rs index d40d9c89f89df..130c6ee7521b4 100644 --- a/src/test/run-pass/trait-coercion.rs +++ b/src/test/run-pass/trait-coercion.rs @@ -30,8 +30,6 @@ impl Trait for Struct { fn foo(mut a: Box) {} -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - pub fn main() { let a = Struct { x: 1, y: 2 }; let b: Box = Box::new(a); diff --git a/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs index a92fb05306f48..789d2237c543c 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs @@ -15,7 +15,6 @@ use std::ops::FnMut; fn make_adder(x: isize) -> Boxisize + 'static> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Box::new(move |y| { x + y }) } diff --git a/src/test/run-pass/unboxed-closures-call-sugar-object.rs b/src/test/run-pass/unboxed-closures-call-sugar-object.rs index 5dd2343cfd1dd..e730771547170 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-object.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-object.rs @@ -13,7 +13,6 @@ use std::ops::FnMut; fn make_adder(x: isize) -> Boxisize + 'static> { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. Box::new(move |y| { x + y }) } diff --git a/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs b/src/test/ui/did_you_mean/issue-38147-1.rs similarity index 56% rename from src/test/ui/lifetimes/consider-using-explicit-lifetime.rs rename to src/test/ui/did_you_mean/issue-38147-1.rs index 603f55af465f4..136921dd0a569 100644 --- a/src/test/ui/lifetimes/consider-using-explicit-lifetime.rs +++ b/src/test/ui/did_you_mean/issue-38147-1.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,21 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::str::FromStr; - -pub struct Foo<'a> { - field: &'a str, +struct Pass<'a> { + s: &'a mut String } -impl<'a> Foo<'a> { - fn bar(path: &str) -> Result { - Ok(Foo { field: path }) +impl<'a> Pass<'a> { + fn f(&mut self) { + self.s.push('x'); } } -impl<'a> FromStr for Foo<'a> { - type Err = (); - fn from_str(path: &str) -> Result { - Ok(Foo { field: path }) +struct Foo<'a> { + s: &'a mut String +} + +impl<'a> Foo<'a> { + fn f(&self) { + self.s.push('x'); } } + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-38147-1.stderr b/src/test/ui/did_you_mean/issue-38147-1.stderr new file mode 100644 index 0000000000000..e9f2b1dad806d --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-1.stderr @@ -0,0 +1,10 @@ +error[E0389]: cannot borrow data mutably in a `&` reference + --> $DIR/issue-38147-1.rs:27:9 + | +26 | fn f(&self) { + | ----- use `&mut self` here to make mutable +27 | self.s.push('x'); + | ^^^^^^ assignment into an immutable reference + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-38147-2.rs b/src/test/ui/did_you_mean/issue-38147-2.rs new file mode 100644 index 0000000000000..a5d533edf75ec --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-2.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. + +struct Bar<'a> { + s: &'a String +} + +impl<'a> Bar<'a> { + fn f(&mut self) { + self.s.push('x'); + } +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr new file mode 100644 index 0000000000000..fdaf0cd44d9d4 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-2.stderr @@ -0,0 +1,11 @@ +error: cannot borrow immutable borrowed content `*self.s` as mutable + --> $DIR/issue-38147-2.rs:17:9 + | +12 | s: &'a String + | ------------- use `&'a mut String` here to make mutable +... +17 | self.s.push('x'); + | ^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-38147-3.rs b/src/test/ui/did_you_mean/issue-38147-3.rs new file mode 100644 index 0000000000000..5e8f2d3eaefaa --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-3.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. + +struct Qux<'a> { + s: &'a String +} + +impl<'a> Qux<'a> { + fn f(&self) { + self.s.push('x'); + } +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr new file mode 100644 index 0000000000000..d2280fa561bde --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-3.stderr @@ -0,0 +1,13 @@ +error: cannot borrow immutable borrowed content `*self.s` as mutable + --> $DIR/issue-38147-3.rs:17:9 + | +12 | s: &'a String + | ------------- use `&'a mut String` here to make mutable +... +16 | fn f(&self) { + | ----- use `&mut self` here to make mutable +17 | self.s.push('x'); + | ^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + diff --git a/src/test/ui/did_you_mean/issue-38147-4.rs b/src/test/ui/did_you_mean/issue-38147-4.rs new file mode 100644 index 0000000000000..4eb20ceeed48e --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-4.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo<'a> { + s: &'a mut String +} + +fn f(x: usize, f: &Foo) { + f.s.push('x'); +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-38147-4.stderr b/src/test/ui/did_you_mean/issue-38147-4.stderr new file mode 100644 index 0000000000000..9a8853f4fbbdb --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-4.stderr @@ -0,0 +1,10 @@ +error[E0389]: cannot borrow data mutably in a `&` reference + --> $DIR/issue-38147-4.rs:16:5 + | +15 | fn f(x: usize, f: &Foo) { + | ---- use `&mut Foo` here to make mutable +16 | f.s.push('x'); + | ^^^ assignment into an immutable reference + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr b/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr deleted file mode 100644 index 153aaa07833a8..0000000000000 --- a/src/test/ui/lifetimes/consider-using-explicit-lifetime.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error: main function not found - -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/consider-using-explicit-lifetime.rs:19:12 - | -19 | Ok(Foo { field: path }) - | ^^^ - -error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/consider-using-explicit-lifetime.rs:26:12 - | -26 | Ok(Foo { field: path }) - | ^^^ - | -help: consider using an explicit lifetime parameter as shown: fn from_str(path: &'a str) -> Result - --> $DIR/consider-using-explicit-lifetime.rs:25:5 - | -25 | fn from_str(path: &str) -> Result { - | _____^ starting here... -26 | | Ok(Foo { field: path }) -27 | | } - | |_____^ ...ending here - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr index c47975b01355d..ccc9fb56772f5 100644 --- a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr +++ b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types 24 | a(x); //~ ERROR mismatched types [E0308] | ^ expected trait `Foo + std::marker::Send`, found trait `Foo` | - = note: expected type `Box` - found type `Box` + = note: expected type `std::boxed::Box` + found type `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/compile-fail/uninhabited-reference-type-feature-gated.rs b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs similarity index 75% rename from src/test/compile-fail/uninhabited-reference-type-feature-gated.rs rename to src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs index 8f246eddbcde4..f190f5dd0534d 100644 --- a/src/test/compile-fail/uninhabited-reference-type-feature-gated.rs +++ b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs @@ -8,12 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum Void {} +#![feature(pub_restricted)] -fn main() { - let x: Result = Ok(23); - let _ = match x { //~ ERROR non-exhaustive - Ok(n) => n, - }; +pub mod m { + pub struct S(u8); + + pub mod n { + pub(m) struct Z(pub(m::n) u8); + } } +pub use m::S; diff --git a/src/test/ui/resolve/privacy-struct-ctor.rs b/src/test/ui/resolve/privacy-struct-ctor.rs new file mode 100644 index 0000000000000..3d0c76c740ad6 --- /dev/null +++ b/src/test/ui/resolve/privacy-struct-ctor.rs @@ -0,0 +1,48 @@ +// 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. + +// aux-build:privacy-struct-ctor.rs + +#![feature(pub_restricted)] + +extern crate privacy_struct_ctor as xcrate; + +mod m { + pub struct S(u8); + + pub mod n { + pub(m) struct Z(pub(m::n) u8); + } + + use m::n::Z; // OK, only the type is imported + + fn f() { + n::Z; //~ ERROR tuple struct `Z` is private + Z; + //~^ ERROR expected value, found struct `Z` + //~| NOTE tuple struct constructors with private fields are invisible outside of their mod + } +} + +use m::S; // OK, only the type is imported + +fn main() { + m::S; //~ ERROR tuple struct `S` is private + S; + //~^ ERROR expected value, found struct `S` + //~| NOTE constructor is not visible here due to private fields + m::n::Z; //~ ERROR tuple struct `Z` is private + + xcrate::m::S; //~ ERROR tuple struct `S` is private + xcrate::S; + //~^ ERROR expected value, found struct `xcrate::S` + //~| NOTE constructor is not visible here due to private fields + xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private +} diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr new file mode 100644 index 0000000000000..30fdbb02cc715 --- /dev/null +++ b/src/test/ui/resolve/privacy-struct-ctor.stderr @@ -0,0 +1,68 @@ +error[E0423]: expected value, found struct `Z` + --> $DIR/privacy-struct-ctor.rs:28:9 + | +28 | Z; + | ^ + | | + | did you mean `Z { /* fields */ }`? + | constructor is not visible here due to private fields + | + = help: possible better candidate is found in another module, you can import it into scope: + `use m::n::Z;` + +error[E0423]: expected value, found struct `S` + --> $DIR/privacy-struct-ctor.rs:38:5 + | +38 | S; + | ^ + | | + | did you mean `S { /* fields */ }`? + | constructor is not visible here due to private fields + | + = help: possible better candidate is found in another module, you can import it into scope: + `use m::S;` + +error[E0423]: expected value, found struct `xcrate::S` + --> $DIR/privacy-struct-ctor.rs:44:5 + | +44 | xcrate::S; + | ^^^^^^^^^ + | | + | did you mean `xcrate::S { /* fields */ }`? + | constructor is not visible here due to private fields + | + = help: possible better candidate is found in another module, you can import it into scope: + `use m::S;` + +error: tuple struct `Z` is private + --> $DIR/privacy-struct-ctor.rs:27:9 + | +27 | n::Z; //~ ERROR tuple struct `Z` is private + | ^^^^ + +error: tuple struct `S` is private + --> $DIR/privacy-struct-ctor.rs:37:5 + | +37 | m::S; //~ ERROR tuple struct `S` is private + | ^^^^ + +error: tuple struct `Z` is private + --> $DIR/privacy-struct-ctor.rs:41:5 + | +41 | m::n::Z; //~ ERROR tuple struct `Z` is private + | ^^^^^^^ + +error: tuple struct `S` is private + --> $DIR/privacy-struct-ctor.rs:43:5 + | +43 | xcrate::m::S; //~ ERROR tuple struct `S` is private + | ^^^^^^^^^^^^ + +error: tuple struct `Z` is private + --> $DIR/privacy-struct-ctor.rs:47:5 + | +47 | xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private + | ^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr index 1109351bff839..b83a6aaebf323 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr @@ -12,7 +12,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 74 | fn deref_extend_mut_field1(x: &Own) -> &mut isize { | ----------- use `&mut Own` here to make mutable 75 | &mut x.y //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error[E0499]: cannot borrow `*x` as mutable more than once at a time --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:19 @@ -38,7 +38,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 101 | fn assign_field2<'a>(x: &'a Own) { | -------------- use `&'a mut Own` here to make mutable 102 | x.y = 3; //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error[E0499]: cannot borrow `*x` as mutable more than once at a time --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:111:5 @@ -64,7 +64,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 130 | fn deref_extend_mut_method1(x: &Own) -> &mut isize { | ----------- use `&mut Own` here to make mutable 131 | x.y_mut() //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6 @@ -80,7 +80,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 142 | fn assign_method2<'a>(x: &'a Own) { | -------------- use `&'a mut Own` here to make mutable 143 | *x.y_mut() = 3; //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error: aborting due to 10 previous errors diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr index a5b7045916141..af954a4d7924f 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr @@ -12,7 +12,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 50 | fn deref_extend_mut1<'a>(x: &'a Own) -> &'a mut isize { | -------------- use `&'a mut Own` here to make mutable 51 | &mut **x //~ ERROR cannot borrow - | ^^ + | ^^ cannot borrow as mutable error: cannot borrow immutable argument `x` as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6 @@ -28,7 +28,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 62 | fn assign2<'a>(x: &'a Own) { | -------------- use `&'a mut Own` here to make mutable 63 | **x = 3; //~ ERROR cannot borrow - | ^^ + | ^^ cannot borrow as mutable error: aborting due to 4 previous errors diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs index ba1ae64ec330a..6264d11186452 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs @@ -18,7 +18,6 @@ struct Test<'a> { f: Box } -// FIXME (#22405): Replace `Box::new` with `box` here when/if possible. fn call(mut f: F) where F: FnMut(Fn) { f(Box::new(|| { //~^ ERROR: cannot borrow `f` as mutable more than once @@ -58,7 +57,6 @@ fn test6() { fn test7() { fn foo(_: F) where F: FnMut(Box, isize) {} let mut f = |g: Box, b: isize| {}; - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. f(Box::new(|a| { foo(f); //~^ ERROR cannot move `f` into closure because it is borrowed diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 16bb60013674f..58b3f205fe352 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -1,42 +1,44 @@ error[E0499]: cannot borrow `f` as mutable more than once at a time - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:23:16 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:22:16 | -23 | f(Box::new(|| { +22 | f(Box::new(|| { | - ^^ second mutable borrow occurs here | | | first mutable borrow occurs here -24 | //~^ ERROR: cannot borrow `f` as mutable more than once -25 | f((Box::new(|| {}))) +23 | //~^ ERROR: cannot borrow `f` as mutable more than once +24 | f((Box::new(|| {}))) | - borrow occurs due to use of `f` in closure -26 | })); +25 | })); | - first borrow ends here error: cannot borrow immutable borrowed content `*f` as mutable - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:36:5 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:35:5 | -35 | fn test2(f: &F) where F: FnMut() { +34 | fn test2(f: &F) where F: FnMut() { | -- use `&mut F` here to make mutable -36 | (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable - | ^^^^ +35 | (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable + | ^^^^ cannot borrow as mutable error: cannot borrow immutable `Box` content `*f.f` as mutable - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:43:5 | -44 | f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable - | ^^^ +42 | fn test4(f: &Test) { + | ----- use `&mut Test` here to make mutable +43 | f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable + | ^^^ cannot borrow as mutable error[E0504]: cannot move `f` into closure because it is borrowed - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:61:13 | -62 | f(Box::new(|a| { +60 | f(Box::new(|a| { | - borrow of `f` occurs here -63 | foo(f); +61 | foo(f); | ^ move into closure occurs here error[E0507]: cannot move out of captured outer variable in an `FnMut` closure - --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13 + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:61:13 | -63 | foo(f); +61 | foo(f); | ^ cannot move out of captured outer variable in an `FnMut` closure error: aborting due to 5 previous errors diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr index a1af1ca7408a2..2349bfaf75e6f 100644 --- a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr +++ b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr @@ -5,7 +5,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable | ---- use `&mut Foo` here to make mutable 26 | x.f(); 27 | x.h(); //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-fn-in-const-b.stderr b/src/test/ui/span/borrowck-fn-in-const-b.stderr index 41f549c708a29..251a9e4aa5755 100644 --- a/src/test/ui/span/borrowck-fn-in-const-b.stderr +++ b/src/test/ui/span/borrowck-fn-in-const-b.stderr @@ -4,7 +4,7 @@ error: cannot borrow immutable borrowed content `*x` as mutable 16 | fn broken(x: &Vec) { | ------------ use `&mut Vec` here to make mutable 17 | x.push(format!("this is broken")); - | ^ + | ^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr index 32e4da18056ff..4ef1cb9c239e4 100644 --- a/src/test/ui/span/borrowck-object-mutability.stderr +++ b/src/test/ui/span/borrowck-object-mutability.stderr @@ -5,13 +5,13 @@ error: cannot borrow immutable borrowed content `*x` as mutable | ---- use `&mut Foo` here to make mutable 18 | x.borrowed(); 19 | x.borrowed_mut(); //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error: cannot borrow immutable `Box` content `*x` as mutable --> $DIR/borrowck-object-mutability.rs:29:5 | 29 | x.borrowed_mut(); //~ ERROR cannot borrow - | ^ + | ^ cannot borrow as mutable error: aborting due to 2 previous errors diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index c32fefcd0d6a9..6a70b8ff851d7 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -49,7 +49,7 @@ error[E0308]: mismatched types | ^^^^^ cyclic type of infinite size | = note: expected type `_` - found type `Box<_>` + found type `std::boxed::Box<_>` error: aborting due to 5 previous errors diff --git a/src/test/ui/span/issue-39018.rs b/src/test/ui/span/issue-39018.rs new file mode 100644 index 0000000000000..1cbc5ff1d2ab5 --- /dev/null +++ b/src/test/ui/span/issue-39018.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. + +pub fn main() { + let x = "Hello " + "World!"; + + // Make sure that the span outputs a warning + // for not having an implementation for std::ops::Add + // that won't output for the above string concatenation + let y = World::Hello + World::Goodbye; +} + +enum World { + Hello, + Goodbye, +} diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr new file mode 100644 index 0000000000000..a8cc74056ca2c --- /dev/null +++ b/src/test/ui/span/issue-39018.stderr @@ -0,0 +1,28 @@ +error[E0369]: binary operation `+` cannot be applied to type `&'static str` + --> $DIR/issue-39018.rs:12:13 + | +12 | let x = "Hello " + "World!"; + | ^^^^^^^^ + | +note: `+` can't be used to concatenate two `&str` strings + --> $DIR/issue-39018.rs:12:13 + | +12 | let x = "Hello " + "World!"; + | ^^^^^^^^ +help: to_owned() can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left. + | let x = "Hello ".to_owned() + "World!"; + +error[E0369]: binary operation `+` cannot be applied to type `World` + --> $DIR/issue-39018.rs:17:13 + | +17 | let y = World::Hello + World::Goodbye; + | ^^^^^^^^^^^^ + | +note: an implementation of `std::ops::Add` might be missing for `World` + --> $DIR/issue-39018.rs:17:13 + | +17 | let y = World::Hello + World::Goodbye; + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr index 58f66c1358437..e4ed062214715 100644 --- a/src/test/ui/span/mut-arg-hint.stderr +++ b/src/test/ui/span/mut-arg-hint.stderr @@ -4,7 +4,7 @@ error: cannot borrow immutable borrowed content `*a` as mutable 17 | pub fn foo<'a>(mut a: &'a String) { | ---------- use `&'a mut String` here to make mutable 18 | a.push_str("foo"); - | ^ + | ^ cannot borrow as mutable error: cannot borrow immutable borrowed content `*a` as mutable --> $DIR/mut-arg-hint.rs:13:9 @@ -12,7 +12,7 @@ error: cannot borrow immutable borrowed content `*a` as mutable 12 | fn foo(mut a: &String) { | ------- use `&mut String` here to make mutable 13 | a.push_str("bar"); - | ^ + | ^ cannot borrow as mutable error: cannot borrow immutable borrowed content `*a` as mutable --> $DIR/mut-arg-hint.rs:25:9 @@ -20,7 +20,7 @@ error: cannot borrow immutable borrowed content `*a` as mutable 24 | pub fn foo(mut a: &String) { | ------- use `&mut String` here to make mutable 25 | a.push_str("foo"); - | ^ + | ^ cannot borrow as mutable error: aborting due to 3 previous errors diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml new file mode 100644 index 0000000000000..4b876753b1fea --- /dev/null +++ b/src/tools/build-manifest/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "build-manifest" +version = "0.1.0" +authors = ["Alex Crichton "] + +[dependencies] +toml = "0.1" +rustc-serialize = "0.3" diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs new file mode 100644 index 0000000000000..8c15a6630a33c --- /dev/null +++ b/src/tools/build-manifest/src/main.rs @@ -0,0 +1,404 @@ +// 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. + +extern crate toml; +extern crate rustc_serialize; + +use std::collections::HashMap; +use std::env; +use std::fs::File; +use std::io::{self, Read, Write}; +use std::path::{PathBuf, Path}; +use std::process::{Command, Stdio}; + +static HOSTS: &'static [&'static str] = &[ + "aarch64-unknown-linux-gnu", + "arm-unknown-linux-gnueabi", + "arm-unknown-linux-gnueabihf", + "armv7-unknown-linux-gnueabihf", + "i686-apple-darwin", + "i686-pc-windows-gnu", + "i686-pc-windows-msvc", + "i686-unknown-linux-gnu", + "mips-unknown-linux-gnu", + "mips64-unknown-linux-gnuabi64", + "mips64el-unknown-linux-gnuabi64", + "mipsel-unknown-linux-gnu", + "powerpc-unknown-linux-gnu", + "powerpc64-unknown-linux-gnu", + "powerpc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-netbsd", +]; + +static TARGETS: &'static [&'static str] = &[ + "aarch64-apple-ios", + "aarch64-linux-android", + "aarch64-unknown-linux-gnu", + "arm-linux-androideabi", + "arm-unknown-linux-gnueabi", + "arm-unknown-linux-gnueabihf", + "arm-unknown-linux-musleabi", + "arm-unknown-linux-musleabihf", + "armv7-apple-ios", + "armv7-linux-androideabi", + "armv7-unknown-linux-gnueabihf", + "armv7-unknown-linux-musleabihf", + "armv7s-apple-ios", + "asmjs-unknown-emscripten", + "i386-apple-ios", + "i586-pc-windows-msvc", + "i586-unknown-linux-gnu", + "i686-apple-darwin", + "i686-linux-android", + "i686-pc-windows-gnu", + "i686-pc-windows-msvc", + "i686-unknown-freebsd", + "i686-unknown-linux-gnu", + "i686-unknown-linux-musl", + "mips-unknown-linux-gnu", + "mips-unknown-linux-musl", + "mips64-unknown-linux-gnuabi64", + "mips64el-unknown-linux-gnuabi64", + "mipsel-unknown-linux-gnu", + "mipsel-unknown-linux-musl", + "powerpc-unknown-linux-gnu", + "powerpc64-unknown-linux-gnu", + "powerpc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "wasm32-unknown-emscripten", + "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-rumprun-netbsd", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "x86_64-unknown-netbsd", +]; + +static MINGW: &'static [&'static str] = &[ + "i686-pc-windows-gnu", + "x86_64-pc-windows-gnu", +]; + +#[derive(RustcEncodable)] +struct Manifest { + manifest_version: String, + date: String, + pkg: HashMap, +} + +#[derive(RustcEncodable)] +struct Package { + version: String, + target: HashMap, +} + +#[derive(RustcEncodable)] +struct Target { + available: bool, + url: Option, + hash: Option, + components: Option>, + extensions: Option>, +} + +#[derive(RustcEncodable)] +struct Component { + pkg: String, + target: String, +} + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +struct Builder { + channel: String, + input: PathBuf, + output: PathBuf, + gpg_passphrase: String, + digests: HashMap, + s3_address: String, + date: String, + rust_version: String, + cargo_version: String, +} + +fn main() { + let mut args = env::args().skip(1); + let input = PathBuf::from(args.next().unwrap()); + let output = PathBuf::from(args.next().unwrap()); + let date = args.next().unwrap(); + let channel = args.next().unwrap(); + let s3_address = args.next().unwrap(); + let mut passphrase = String::new(); + t!(io::stdin().read_to_string(&mut passphrase)); + + Builder { + channel: channel, + input: input, + output: output, + gpg_passphrase: passphrase, + digests: HashMap::new(), + s3_address: s3_address, + date: date, + rust_version: String::new(), + cargo_version: String::new(), + }.build(); +} + +impl Builder { + fn build(&mut self) { + self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu"); + self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu"); + + self.digest_and_sign(); + let manifest = self.build_manifest(); + let manifest = toml::encode(&manifest).to_string(); + + let filename = format!("channel-rust-{}.toml", self.channel); + self.write_manifest(&manifest, &filename); + + if self.channel != "beta" && self.channel != "nightly" { + self.write_manifest(&manifest, "channel-rust-stable.toml"); + } + } + + fn digest_and_sign(&mut self) { + for file in t!(self.input.read_dir()).map(|e| t!(e).path()) { + let filename = file.file_name().unwrap().to_str().unwrap(); + let digest = self.hash(&file); + self.sign(&file); + assert!(self.digests.insert(filename.to_string(), digest).is_none()); + } + } + + fn build_manifest(&mut self) -> Manifest { + let mut manifest = Manifest { + manifest_version: "2".to_string(), + date: self.date.to_string(), + pkg: HashMap::new(), + }; + + self.package("rustc", &mut manifest.pkg, HOSTS); + self.package("cargo", &mut manifest.pkg, HOSTS); + self.package("rust-mingw", &mut manifest.pkg, MINGW); + self.package("rust-std", &mut manifest.pkg, TARGETS); + self.package("rust-docs", &mut manifest.pkg, TARGETS); + self.package("rust-src", &mut manifest.pkg, &["*"]); + + let mut pkg = Package { + version: self.cached_version("rust").to_string(), + target: HashMap::new(), + }; + for host in HOSTS { + let filename = self.filename("rust", host); + let digest = match self.digests.remove(&filename) { + Some(digest) => digest, + None => { + pkg.target.insert(host.to_string(), Target { + available: false, + url: None, + hash: None, + components: None, + extensions: None, + }); + continue + } + }; + let mut components = Vec::new(); + let mut extensions = Vec::new(); + + // rustc/rust-std/cargo are all required, and so is rust-mingw if it's + // available for the target. + components.extend(vec![ + Component { pkg: "rustc".to_string(), target: host.to_string() }, + Component { pkg: "rust-std".to_string(), target: host.to_string() }, + Component { pkg: "cargo".to_string(), target: host.to_string() }, + ]); + if host.contains("pc-windows-gnu") { + components.push(Component { + pkg: "rust-mingw".to_string(), + target: host.to_string(), + }); + } + + // Docs, other standard libraries, and the source package are all + // optional. + extensions.push(Component { + pkg: "rust-docs".to_string(), + target: host.to_string(), + }); + for target in TARGETS { + if target != host { + extensions.push(Component { + pkg: "rust-std".to_string(), + target: target.to_string(), + }); + } + } + extensions.push(Component { + pkg: "rust-src".to_string(), + target: "*".to_string(), + }); + + pkg.target.insert(host.to_string(), Target { + available: true, + url: Some(self.url("rust", host)), + hash: Some(to_hex(digest.as_ref())), + components: Some(components), + extensions: Some(extensions), + }); + } + manifest.pkg.insert("rust".to_string(), pkg); + + return manifest + } + + fn package(&mut self, + pkgname: &str, + dst: &mut HashMap, + targets: &[&str]) { + let targets = targets.iter().map(|name| { + let filename = self.filename(pkgname, name); + let digest = match self.digests.remove(&filename) { + Some(digest) => digest, + None => { + return (name.to_string(), Target { + available: false, + url: None, + hash: None, + components: None, + extensions: None, + }) + } + }; + + (name.to_string(), Target { + available: true, + url: Some(self.url(pkgname, name)), + hash: Some(digest), + components: None, + extensions: None, + }) + }).collect(); + + dst.insert(pkgname.to_string(), Package { + version: self.cached_version(pkgname).to_string(), + target: targets, + }); + } + + fn url(&self, component: &str, target: &str) -> String { + format!("{}/{}/{}", + self.s3_address, + self.date, + self.filename(component, target)) + } + + fn filename(&self, component: &str, target: &str) -> String { + if component == "rust-src" { + format!("rust-src-{}.tar.gz", self.channel) + } else { + format!("{}-{}-{}.tar.gz", component, self.channel, target) + } + } + + fn cached_version(&self, component: &str) -> &str { + if component == "cargo" { + &self.cargo_version + } else { + &self.rust_version + } + } + + fn version(&self, component: &str, target: &str) -> String { + let mut cmd = Command::new("tar"); + let filename = self.filename(component, target); + cmd.arg("xf") + .arg(self.input.join(&filename)) + .arg(format!("{}/version", filename.replace(".tar.gz", ""))) + .arg("-O"); + let version = t!(cmd.output()); + if !version.status.success() { + panic!("failed to learn version:\n\n{:?}\n\n{}\n\n{}", + cmd, + String::from_utf8_lossy(&version.stdout), + String::from_utf8_lossy(&version.stderr)); + } + String::from_utf8_lossy(&version.stdout).trim().to_string() + } + + fn hash(&self, path: &Path) -> String { + let sha = t!(Command::new("shasum") + .arg("-a").arg("256") + .arg(path) + .output()); + assert!(sha.status.success()); + + let filename = path.file_name().unwrap().to_str().unwrap(); + let sha256 = self.output.join(format!("{}.sha256", filename)); + t!(t!(File::create(&sha256)).write_all(&sha.stdout)); + + let stdout = String::from_utf8_lossy(&sha.stdout); + stdout.split_whitespace().next().unwrap().to_string() + } + + fn sign(&self, path: &Path) { + let filename = path.file_name().unwrap().to_str().unwrap(); + let asc = self.output.join(format!("{}.asc", filename)); + println!("signing: {:?}", path); + let mut cmd = Command::new("gpg"); + cmd.arg("--no-tty") + .arg("--yes") + .arg("--passphrase-fd").arg("0") + .arg("--armor") + .arg("--output").arg(&asc) + .arg("--detach-sign").arg(path) + .stdin(Stdio::piped()); + let mut child = t!(cmd.spawn()); + t!(child.stdin.take().unwrap().write_all(self.gpg_passphrase.as_bytes())); + assert!(t!(child.wait()).success()); + } + + fn write_manifest(&self, manifest: &str, name: &str) { + let dst = self.output.join(name); + t!(t!(File::create(&dst)).write_all(manifest.as_bytes())); + self.hash(&dst); + self.sign(&dst); + } +} + +fn to_hex(digest: &[u8]) -> String { + let mut ret = String::new(); + for byte in digest { + ret.push(hex((byte & 0xf0) >> 4)); + ret.push(hex(byte & 0xf)); + } + return ret; + + fn hex(b: u8) -> char { + match b { + 0...9 => (b'0' + b) as char, + _ => (b'a' + b - 10) as char, + } + } +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 05d6e21e9aaea..86fa5e70c9c28 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2175,6 +2175,10 @@ actual:\n\ .env("LLVM_COMPONENTS", &self.config.llvm_components) .env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags); + // We don't want RUSTFLAGS set from the outside to interfere with + // compiler flags set in the test cases: + cmd.env_remove("RUSTFLAGS"); + if self.config.target.contains("msvc") { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 154ebd3649bcd..2c3e57c833262 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -166,8 +166,7 @@ pub fn check(path: &Path, bad: &mut bool) { // FIXME get this whitelist empty. let whitelist = vec![ - "abi_ptx", "simd", "macro_reexport", - "static_recursion", "quote", + "abi_ptx", "simd", "static_recursion", "cfg_target_has_atomic", "staged_api", "const_indexing", "unboxed_closures", "stmt_expr_attributes", "cfg_target_thread_local", "unwind_attributes",