diff --git a/.gitattributes b/.gitattributes index 0319b4d2f2a9..1d4c6252f2c7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,3 +7,4 @@ src/etc/pkg/rust-logo.ico binary src/etc/pkg/rust-logo.png binary *.woff binary +src/vendor/* binary diff --git a/.gitignore b/.gitignore index 6de43f471d88..bf66eabc1c80 100644 --- a/.gitignore +++ b/.gitignore @@ -98,3 +98,4 @@ tmp.*.rs version.md version.ml version.texi +.cargo diff --git a/.travis.yml b/.travis.yml index 0bc9a4ad4198..144329caa71a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ before_install: script: - docker run -v `pwd`:/build rust sh -c " - ./configure --enable-rustbuild --llvm-root=/usr/lib/llvm-3.7 --enable-quiet-tests && + ./configure --enable-vendor --enable-rustbuild --llvm-root=/usr/lib/llvm-3.7 --enable-quiet-tests && make tidy && make check -j4 " diff --git a/README.md b/README.md index b79c9703f44e..7360651095bb 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ ones from MSYS if you have it installed). You'll also need Visual Studio 2013 or newer with the C++ tools. Then all you need to do is to kick off rustbuild. ``` -python .\src\bootstrap\bootstrap.py +python x.py build ``` Currently rustbuild only works with some known versions of Visual Studio. If you @@ -137,7 +137,7 @@ by manually calling the appropriate vcvars file before running the bootstrap. ``` CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" -python .\src\bootstrap\bootstrap.py +python x.py build ``` ## Building Documentation diff --git a/RELEASES.md b/RELEASES.md index e6f18f9f7ba5..222ad3aa112a 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,30 @@ +Version 1.12.1 (2016-10-20) +=========================== + +Regression Fixes +---------------- + +* [ICE: 'rustc' panicked at 'assertion failed: concrete_substs.is_normalized_for_trans()' #36381][36381] +* [Confusion with double negation and booleans][36856] +* [rustc 1.12.0 fails with SIGSEGV in release mode (syn crate 0.8.0)][36875] +* [Rustc 1.12.0 Windows build of `ethcore` crate fails with LLVM error][36924] +* [1.12.0: High memory usage when linking in release mode with debug info][36926] +* [Corrupted memory after updated to 1.12][36936] +* ["Let NullaryConstructor = something;" causes internal compiler error: "tried to overwrite interned AdtDef"][37026] +* [Fix ICE: inject bitcast if types mismatch for invokes/calls/stores][37112] +* [debuginfo: Handle spread_arg case in MIR-trans in a more stable way.][37153] + +[36381]: https://github.com/rust-lang/rust/issues/36381 +[36856]: https://github.com/rust-lang/rust/issues/36856 +[36875]: https://github.com/rust-lang/rust/issues/36875 +[36924]: https://github.com/rust-lang/rust/issues/36924 +[36926]: https://github.com/rust-lang/rust/issues/36926 +[36936]: https://github.com/rust-lang/rust/issues/36936 +[37026]: https://github.com/rust-lang/rust/issues/37026 +[37112]: https://github.com/rust-lang/rust/issues/37112 +[37153]: https://github.com/rust-lang/rust/issues/37153 + + Version 1.12.0 (2016-09-29) =========================== diff --git a/configure b/configure index cd22229b7993..9c055e7217aa 100755 --- a/configure +++ b/configure @@ -634,6 +634,7 @@ opt rustbuild 0 "use the rust and cargo based build system" opt codegen-tests 1 "run the src/test/codegen tests" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" +opt vendor 0 "enable usage of vendored Rust crates" # Optimization and debugging options. These may be overridden by the release channel, etc. opt_nosave optimize 1 "build optimized rust code" @@ -868,13 +869,6 @@ then fi fi -if [ -n "$CFG_GDB" ] -then - # Store GDB's version - CFG_GDB_VERSION=$($CFG_GDB --version 2>/dev/null | head -1) - putvar CFG_GDB_VERSION -fi - if [ -n "$CFG_LLDB" ] then # Store LLDB's version diff --git a/mk/dist.mk b/mk/dist.mk index cb0bca01e6c4..238ba8acee42 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -65,7 +65,8 @@ PKG_FILES := \ stage0.txt \ rust-installer \ tools \ - test) \ + test \ + vendor) \ $(PKG_GITMODULES) \ $(filter-out config.stamp, \ $(MKFILES_FOR_TARBALL)) diff --git a/mk/main.mk b/mk/main.mk index a5e376412200..2fa8ccf3621e 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -372,7 +372,7 @@ CFG_INFO := $(info cfg: disabling unstable features (CFG_DISABLE_UNSTABLE_FEATUR # Turn on feature-staging export CFG_DISABLE_UNSTABLE_FEATURES # Subvert unstable feature lints to do the self-build -export RUSTC_BOOTSTRAP +export RUSTC_BOOTSTRAP=1 endif ifdef CFG_MUSL_ROOT export CFG_MUSL_ROOT diff --git a/mk/tests.mk b/mk/tests.mk index 1957c989eb0d..f3d8f0387bbd 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -648,7 +648,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) = \ --host $(3) \ --docck-python $$(CFG_PYTHON) \ --lldb-python $$(CFG_LLDB_PYTHON) \ - --gdb-version="$(CFG_GDB_VERSION)" \ + --gdb="$(CFG_GDB)" \ --lldb-version="$(CFG_LLDB_VERSION)" \ --llvm-version="$$(LLVM_VERSION_$(3))" \ --android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \ diff --git a/src/Cargo.lock b/src/Cargo.lock index 5826995cc3cf..d3517175d4ce 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -40,17 +40,15 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.38 (git+https://github.com/alexcrichton/gcc-rs)", + "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "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)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -63,7 +61,7 @@ version = "0.1.0" [[package]] name = "cmake" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", @@ -131,11 +129,6 @@ dependencies = [ name = "fmt_macros" version = "0.0.0" -[[package]] -name = "gcc" -version = "0.3.38" -source = "git+https://github.com/alexcrichton/gcc-rs#be620ac6d3ddb498cd0c700d5312c6a4c3c19597" - [[package]] name = "gcc" version = "0.3.38" @@ -154,25 +147,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "graphviz" version = "0.0.0" -[[package]] -name = "idna" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "libc" version = "0.0.0" @@ -188,9 +162,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "linkchecker" version = "0.1.0" -dependencies = [ - "url 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "log" @@ -201,11 +172,6 @@ name = "log" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "matches" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "md5" version = "0.1.1" @@ -710,56 +676,15 @@ dependencies = [ "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "unicode-bidi" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "url" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] -"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978" +"checksum cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum gcc 0.3.38 (git+https://github.com/alexcrichton/gcc-rs)" = "" "checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8" "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" -"checksum matches 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc3ad8109fa4b522f9b0cd81440422781f564aaf8c195de6b9d6642177ad0dd" "checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" "checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796" -"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f" -"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172" -"checksum url 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ba5a45db1d2e0effb7a1c00cc73ffc63a973da8c7d1fcd5b46f24285ade6c54" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index c96690754387..4c9b578c1349 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -27,10 +27,6 @@ num_cpus = "0.2" toml = "0.1" getopts = "0.2" rustc-serialize = "0.3" -gcc = { git = "https://github.com/alexcrichton/gcc-rs" } +gcc = "0.3.38" libc = "0.2" md5 = "0.1" - -[target.'cfg(windows)'.dependencies] -winapi = "0.2" -kernel32-sys = "0.2" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 57d644d635cf..f73f41ffae29 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -10,8 +10,64 @@ system. ## Using rustbuild -When configuring Rust via `./configure`, pass the following to enable building -via this build system: +The rustbuild build system has a primary entry point, a top level `x.py` script: + +``` +python ./x.py build +``` + +Note that if you're on Unix you should be able to execute the script directly: + +``` +./x.py build +``` + +The script accepts commands, flags, and filters to determine what to do: + +* `build` - a general purpose command for compiling code. Alone `build` will + bootstrap the entire compiler, and otherwise arguments passed indicate what to + build. For example: + + ``` + # build the whole compiler + ./x.py build + + # build the stage1 compier + ./x.py build --stage 1 + + # build stage0 libstd + ./x.py build --stage 0 src/libstd + + # build a particular crate in stage0 + ./x.py build --stage 0 src/libtest + ``` + +* `test` - a command for executing unit tests. Like the `build` command this + will execute the entire test suite by default, and otherwise it can be used to + select which test suite is run: + + ``` + # run all unit tests + ./x.py test + + # execute the run-pass test suite + ./x.py test src/test/run-pass + + # execute only some tests in the run-pass test suite + ./x.py test src/test/run-pass --filter my-filter + + # execute tests in the standard library in stage0 + ./x.py test --stage 0 src/libstd + + # execute all doc tests + ./x.py test src/doc + ``` + +* `doc` - a command for building documentation. Like above can take arguments + for what to document. + +If you're more used to `./configure` and `make`, however, then you can also +configure the build system to use rustbuild instead of the old makefiles: ``` ./configure --enable-rustbuild @@ -19,15 +75,7 @@ make ``` Afterwards the `Makefile` which is generated will have a few commands like -`make check`, `make tidy`, etc. For finer-grained control, the -`bootstrap.py` entry point can be used: - -``` -python src/bootstrap/bootstrap.py -``` - -This accepts a number of options like `--stage` and `--step` which can configure -what's actually being done. +`make check`, `make tidy`, etc. ## Configuring rustbuild @@ -47,7 +95,7 @@ being invoked manually (via the python script). The rustbuild build system goes through a few phases to actually build the compiler. What actually happens when you invoke rustbuild is: -1. The entry point script, `src/bootstrap/bootstrap.py` is run. This script is +1. The entry point script, `x.py` is run. This script is responsible for downloading the stage0 compiler/Cargo binaries, and it then compiles the build system itself (this folder). Finally, it then invokes the actual `bootstrap` binary build system. diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 2c2260a8e60c..08a8ca5a6313 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -259,9 +259,11 @@ class RustBuild(object): env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] - self.run([self.cargo(), "build", "--manifest-path", - os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")], - env) + args = [self.cargo(), "build", "--manifest-path", + os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")] + if self.use_vendored_sources: + args.append("--frozen") + self.run(args, env) def run(self, args, env): proc = subprocess.Popen(args, env=env) @@ -344,6 +346,22 @@ class RustBuild(object): ostype += 'eabihf' elif cputype == 'aarch64': cputype = 'aarch64' + elif cputype == 'mips': + if sys.byteorder == 'big': + cputype = 'mips' + elif sys.byteorder == 'little': + cputype = 'mipsel' + else: + raise ValueError('unknown byteorder: ' + sys.byteorder) + elif cputype == 'mips64': + if sys.byteorder == 'big': + cputype = 'mips64' + elif sys.byteorder == 'little': + cputype = 'mips64el' + else: + raise ValueError('unknown byteorder: ' + sys.byteorder) + # only the n64 ABI is supported, indicate it + ostype += 'abi64' elif cputype in {'powerpc', 'ppc', 'ppc64'}: cputype = 'powerpc' elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}: @@ -384,6 +402,25 @@ def main(): except: pass + rb.use_vendored_sources = '\nvendor = true' in rb.config_toml or \ + 'CFG_ENABLE_VENDOR' in rb.config_mk + + if rb.use_vendored_sources: + if not os.path.exists('.cargo'): + os.makedirs('.cargo') + f = open('.cargo/config','w') + f.write(""" + [source.crates-io] + replace-with = 'vendored-sources' + registry = 'https://example.com' + + [source.vendored-sources] + directory = '{}/src/vendor' + """.format(rb.rust_root)) + f.close() + else: + if os.path.exists('.cargo'): + shutil.rmtree('.cargo') data = stage0_data(rb.rust_root) rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1) rb._cargo_channel, rb._cargo_date = data['cargo'].split('-', 1) @@ -399,12 +436,10 @@ def main(): # Run the bootstrap args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")] - args.append('--src') - args.append(rb.rust_root) - args.append('--build') - args.append(rb.build) args.extend(sys.argv[1:]) env = os.environ.copy() + env["BUILD"] = rb.build + env["SRC"] = rb.rust_root env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) rb.run(args, env) diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 0a281b89c571..f27f9641036c 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -13,44 +13,19 @@ //! This file implements the various regression test suites that we execute on //! our CI. -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use std::env; use std::fs; use std::path::{PathBuf, Path}; use std::process::Command; use build_helper::output; -use rustc_serialize::json; use {Build, Compiler, Mode}; use util::{self, dylib_path, dylib_path_var}; const ADB_TEST_DIR: &'static str = "/data/tmp"; -#[derive(RustcDecodable)] -struct Output { - packages: Vec, - resolve: Resolve, -} - -#[derive(RustcDecodable)] -struct Package { - id: String, - name: String, - source: Option, -} - -#[derive(RustcDecodable)] -struct Resolve { - nodes: Vec, -} - -#[derive(RustcDecodable)] -struct ResolveNode { - id: String, - dependencies: Vec, -} - /// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler. /// /// This tool in `src/tools` will verify the validity of all our links in the @@ -168,8 +143,8 @@ pub fn compiletest(build: &Build, cmd.arg("--lldb-python").arg(python_default); } - if let Some(ref vers) = build.gdb_version { - cmd.arg("--gdb-version").arg(vers); + if let Some(ref gdb) = build.config.gdb { + cmd.arg("--gdb").arg(gdb); } if let Some(ref vers) = build.lldb_version { cmd.arg("--lldb-version").arg(vers); @@ -181,7 +156,7 @@ pub fn compiletest(build: &Build, let llvm_version = output(Command::new(&llvm_config).arg("--version")); cmd.arg("--llvm-version").arg(llvm_version); - cmd.args(&build.flags.args); + cmd.args(&build.flags.cmd.test_args()); if build.config.verbose || build.flags.verbose { cmd.arg("--verbose"); @@ -267,7 +242,9 @@ pub fn docs(build: &Build, compiler: &Compiler) { pub fn error_index(build: &Build, compiler: &Compiler) { println!("Testing error-index stage{}", compiler.stage); - let output = testdir(build, compiler.host).join("error-index.md"); + let dir = testdir(build, compiler.host); + t!(fs::create_dir_all(&dir)); + let output = dir.join("error-index.md"); build.run(build.tool_cmd(compiler, "error_index_generator") .arg("markdown") .arg(&output) @@ -282,7 +259,7 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { cmd.arg("--test"); cmd.arg(markdown); - let mut test_args = build.flags.args.join(" "); + let mut test_args = build.flags.cmd.test_args().join(" "); if build.config.quiet_tests { test_args.push_str(" --quiet"); } @@ -302,7 +279,8 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) { pub fn krate(build: &Build, compiler: &Compiler, target: &str, - mode: Mode) { + mode: Mode, + krate: Option<&str>) { let (name, path, features, root) = match mode { Mode::Libstd => { ("libstd", "src/rustc/std_shim", build.std_features(), "std_shim") @@ -318,24 +296,6 @@ pub fn krate(build: &Build, println!("Testing {} stage{} ({} -> {})", name, compiler.stage, compiler.host, target); - // Run `cargo metadata` to figure out what crates we're testing. - // - // Down below we're going to call `cargo test`, but to test the right set - // of packages we're going to have to know what `-p` arguments to pass it - // to know what crates to test. Here we run `cargo metadata` to learn about - // the dependency graph and what `-p` arguments there are. - let mut cargo = Command::new(&build.cargo); - cargo.arg("metadata") - .arg("--manifest-path").arg(build.src.join(path).join("Cargo.toml")); - let output = output(&mut cargo); - let output: Output = json::decode(&output).unwrap(); - let id2pkg = output.packages.iter() - .map(|pkg| (&pkg.id, pkg)) - .collect::>(); - let id2deps = output.resolve.nodes.iter() - .map(|node| (&node.id, &node.dependencies)) - .collect::>(); - // Build up the base `cargo test` command. // // Pass in some standard flags then iterate over the graph we've discovered @@ -346,24 +306,25 @@ pub fn krate(build: &Build, .arg(build.src.join(path).join("Cargo.toml")) .arg("--features").arg(features); - let mut visited = HashSet::new(); - let root_pkg = output.packages.iter().find(|p| p.name == root).unwrap(); - let mut next = vec![&root_pkg.id]; - while let Some(id) = next.pop() { - // Skip any packages with sources listed, as these come from crates.io - // and we shouldn't be testing them. - if id2pkg[id].source.is_some() { - continue + match krate { + Some(krate) => { + cargo.arg("-p").arg(krate); } - // Right now jemalloc is our only target-specific crate in the sense - // that it's not present on all platforms. Custom skip it here for now, - // but if we add more this probably wants to get more generalized. - if !id.contains("jemalloc") { - cargo.arg("-p").arg(&id2pkg[id].name); - } - for dep in id2deps[id] { - if visited.insert(dep) { - next.push(dep); + None => { + let mut visited = HashSet::new(); + let mut next = vec![root]; + while let Some(name) = next.pop() { + // Right now jemalloc is our only target-specific crate in the sense + // that it's not present on all platforms. Custom skip it here for now, + // but if we add more this probably wants to get more generalized. + if !name.contains("jemalloc") { + cargo.arg("-p").arg(name); + } + for dep in build.crates[name].deps.iter() { + if visited.insert(dep) { + next.push(dep); + } + } } } } @@ -389,7 +350,7 @@ pub fn krate(build: &Build, build.run(cargo.arg("--no-run")); krate_emscripten(build, compiler, target, mode); } else { - cargo.args(&build.flags.args); + cargo.args(&build.flags.cmd.test_args()); build.run(&mut cargo); } } @@ -421,7 +382,7 @@ fn krate_android(build: &Build, target = target, test = test_file_name, log = log, - args = build.flags.args.join(" ")); + args = build.flags.cmd.test_args().join(" ")); let output = output(Command::new("adb").arg("shell").arg(&program)); println!("{}", output); diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index a1e286e162ff..75bcbfee6ee0 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -16,6 +16,7 @@ //! directory as we want that cached between builds. use std::fs; +use std::io::{self, ErrorKind}; use std::path::Path; use Build; @@ -25,24 +26,58 @@ pub fn clean(build: &Build) { rm_rf(build, &build.out.join("tmp")); for host in build.config.host.iter() { + let entries = match build.out.join(host).read_dir() { + Ok(iter) => iter, + Err(_) => continue, + }; - let out = build.out.join(host); - - rm_rf(build, &out.join("doc")); - - for stage in 0..4 { - rm_rf(build, &out.join(format!("stage{}", stage))); - rm_rf(build, &out.join(format!("stage{}-std", stage))); - rm_rf(build, &out.join(format!("stage{}-rustc", stage))); - rm_rf(build, &out.join(format!("stage{}-tools", stage))); - rm_rf(build, &out.join(format!("stage{}-test", stage))); + for entry in entries { + let entry = t!(entry); + if entry.file_name().to_str() == Some("llvm") { + continue + } + let path = t!(entry.path().canonicalize()); + rm_rf(build, &path); } } } fn rm_rf(build: &Build, path: &Path) { - if path.exists() { - build.verbose(&format!("removing `{}`", path.display())); - t!(fs::remove_dir_all(path)); + if !path.exists() { + return + } + + for file in t!(fs::read_dir(path)) { + let file = t!(file).path(); + + if file.is_dir() { + rm_rf(build, &file); + } else { + // On windows we can't remove a readonly file, and git will + // often clone files as readonly. As a result, we have some + // special logic to remove readonly files on windows. + do_op(&file, "remove file", |p| fs::remove_file(p)); + } + } + do_op(path, "remove dir", |p| fs::remove_dir(p)); +} + +fn do_op(path: &Path, desc: &str, mut f: F) + where F: FnMut(&Path) -> io::Result<()> +{ + match f(path) { + Ok(()) => {} + Err(ref e) if cfg!(windows) && + e.kind() == ErrorKind::PermissionDenied => { + let mut p = t!(path.metadata()).permissions(); + p.set_readonly(false); + t!(fs::set_permissions(path, p)); + f(path).unwrap_or_else(|e| { + panic!("failed to {} {}: {}", desc, path.display(), e); + }) + } + Err(e) => { + panic!("failed to {} {}: {}", desc, path.display(), e); + } } } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index ff8e4757bd1f..5fc4f006729d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -64,8 +64,8 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { } build.run(&mut cargo); - update_mtime(&libstd_stamp(build, compiler, target)); - std_link(build, target, compiler, compiler.host); + update_mtime(&libstd_stamp(build, &compiler, target)); + std_link(build, target, compiler.stage, compiler.host); } /// Link all libstd rlibs/dylibs into the sysroot location. @@ -74,11 +74,12 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { /// by `compiler` into `host`'s sysroot. pub fn std_link(build: &Build, target: &str, - compiler: &Compiler, + stage: u32, host: &str) { + let compiler = Compiler::new(stage, &build.config.build); let target_compiler = Compiler::new(compiler.stage, host); let libdir = build.sysroot_libdir(&target_compiler, target); - let out_dir = build.cargo_out(compiler, Mode::Libstd, target); + let out_dir = build.cargo_out(&compiler, Mode::Libstd, target); // If we're linking one compiler host's output into another, then we weren't // called from the `std` method above. In that case we clean out what's @@ -146,7 +147,7 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { .arg(build.src.join("src/rustc/test_shim/Cargo.toml")); build.run(&mut cargo); update_mtime(&libtest_stamp(build, compiler, target)); - test_link(build, target, compiler, compiler.host); + test_link(build, target, compiler.stage, compiler.host); } /// Link all libtest rlibs/dylibs into the sysroot location. @@ -155,11 +156,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { /// by `compiler` into `host`'s sysroot. pub fn test_link(build: &Build, target: &str, - compiler: &Compiler, + stage: u32, host: &str) { + let compiler = Compiler::new(stage, &build.config.build); let target_compiler = Compiler::new(compiler.stage, host); let libdir = build.sysroot_libdir(&target_compiler, target); - let out_dir = build.cargo_out(compiler, Mode::Libtest, target); + let out_dir = build.cargo_out(&compiler, Mode::Libtest, target); add_to_sysroot(&out_dir, &libdir); } @@ -218,7 +220,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { } build.run(&mut cargo); - rustc_link(build, target, compiler, compiler.host); + rustc_link(build, target, compiler.stage, compiler.host); } /// Link all librustc rlibs/dylibs into the sysroot location. @@ -227,11 +229,12 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { /// by `compiler` into `host`'s sysroot. pub fn rustc_link(build: &Build, target: &str, - compiler: &Compiler, + stage: u32, host: &str) { + let compiler = Compiler::new(stage, &build.config.build); let target_compiler = Compiler::new(compiler.stage, host); let libdir = build.sysroot_libdir(&target_compiler, target); - let out_dir = build.cargo_out(compiler, Mode::Librustc, target); + let out_dir = build.cargo_out(&compiler, Mode::Librustc, target); add_to_sysroot(&out_dir, &libdir); } @@ -259,7 +262,10 @@ fn compiler_file(compiler: &Path, file: &str) -> PathBuf { /// must have been previously produced by the `stage - 1` build.config.build /// compiler. pub fn assemble_rustc(build: &Build, stage: u32, host: &str) { - assert!(stage > 0, "the stage0 compiler isn't assembled, it's downloaded"); + // nothing to do in stage0 + if stage == 0 { + return + } // The compiler that we're assembling let target_compiler = Compiler::new(stage, host); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index abaa9389d809..9a939fee43e8 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -23,6 +23,7 @@ use std::process; use num_cpus; use rustc_serialize::Decodable; use toml::{Parser, Decoder, Value}; +use util::push_exe_path; /// Global configuration for the entire build and/or bootstrap. /// @@ -43,6 +44,7 @@ pub struct Config { pub submodules: bool, pub compiler_docs: bool, pub docs: bool, + pub vendor: bool, pub target_config: HashMap, // llvm codegen options @@ -86,6 +88,7 @@ pub struct Config { pub mandir: Option, pub codegen_tests: bool, pub nodejs: Option, + pub gdb: Option, } /// Per-target configuration stored in the global configuration structure. @@ -123,6 +126,8 @@ struct Build { compiler_docs: Option, docs: Option, submodules: Option, + gdb: Option, + vendor: Option, } /// TOML representation of how the LLVM build is configured. @@ -227,9 +232,11 @@ impl Config { } config.rustc = build.rustc.map(PathBuf::from); config.cargo = build.cargo.map(PathBuf::from); + config.gdb = build.gdb.map(PathBuf::from); set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.docs, build.docs); set(&mut config.submodules, build.submodules); + set(&mut config.vendor, build.vendor); if let Some(ref llvm) = toml.llvm { set(&mut config.ccache, llvm.ccache); @@ -343,6 +350,7 @@ impl Config { ("LOCAL_REBUILD", self.local_rebuild), ("NINJA", self.ninja), ("CODEGEN_TESTS", self.codegen_tests), + ("VENDOR", self.vendor), } match key { @@ -356,37 +364,37 @@ impl Config { .collect(); } "CFG_MUSL_ROOT" if value.len() > 0 => { - self.musl_root = Some(PathBuf::from(value)); + self.musl_root = Some(parse_configure_path(value)); } "CFG_MUSL_ROOT_X86_64" if value.len() > 0 => { let target = "x86_64-unknown-linux-musl".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.musl_root = Some(PathBuf::from(value)); + target.musl_root = Some(parse_configure_path(value)); } "CFG_MUSL_ROOT_I686" if value.len() > 0 => { let target = "i686-unknown-linux-musl".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.musl_root = Some(PathBuf::from(value)); + target.musl_root = Some(parse_configure_path(value)); } "CFG_MUSL_ROOT_ARM" if value.len() > 0 => { let target = "arm-unknown-linux-musleabi".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.musl_root = Some(PathBuf::from(value)); + target.musl_root = Some(parse_configure_path(value)); } "CFG_MUSL_ROOT_ARMHF" if value.len() > 0 => { let target = "arm-unknown-linux-musleabihf".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.musl_root = Some(PathBuf::from(value)); + target.musl_root = Some(parse_configure_path(value)); } "CFG_MUSL_ROOT_ARMV7" if value.len() > 0 => { let target = "armv7-unknown-linux-musleabihf".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.musl_root = Some(PathBuf::from(value)); + target.musl_root = Some(parse_configure_path(value)); } "CFG_DEFAULT_AR" if value.len() > 0 => { self.rustc_default_ar = Some(value.to_string()); @@ -394,6 +402,9 @@ impl Config { "CFG_DEFAULT_LINKER" if value.len() > 0 => { self.rustc_default_linker = Some(value.to_string()); } + "CFG_GDB" if value.len() > 0 => { + self.gdb = Some(parse_configure_path(value)); + } "CFG_RELEASE_CHANNEL" => { self.channel = value.to_string(); } @@ -412,41 +423,42 @@ impl Config { "CFG_LLVM_ROOT" if value.len() > 0 => { let target = self.target_config.entry(self.build.clone()) .or_insert(Target::default()); - let root = PathBuf::from(value); - target.llvm_config = Some(root.join("bin/llvm-config")); + let root = parse_configure_path(value); + target.llvm_config = Some(push_exe_path(root, &["bin", "llvm-config"])); } "CFG_JEMALLOC_ROOT" if value.len() > 0 => { let target = self.target_config.entry(self.build.clone()) .or_insert(Target::default()); - target.jemalloc = Some(PathBuf::from(value)); + target.jemalloc = Some(parse_configure_path(value)); } "CFG_ARM_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => { let target = "arm-linux-androideabi".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.ndk = Some(PathBuf::from(value)); + target.ndk = Some(parse_configure_path(value)); } "CFG_ARMV7_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => { let target = "armv7-linux-androideabi".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.ndk = Some(PathBuf::from(value)); + target.ndk = Some(parse_configure_path(value)); } "CFG_I686_LINUX_ANDROID_NDK" if value.len() > 0 => { let target = "i686-linux-android".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.ndk = Some(PathBuf::from(value)); + target.ndk = Some(parse_configure_path(value)); } "CFG_AARCH64_LINUX_ANDROID_NDK" if value.len() > 0 => { let target = "aarch64-linux-android".to_string(); let target = self.target_config.entry(target) .or_insert(Target::default()); - target.ndk = Some(PathBuf::from(value)); + target.ndk = Some(parse_configure_path(value)); } "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => { - self.rustc = Some(PathBuf::from(value).join("bin/rustc")); - self.cargo = Some(PathBuf::from(value).join("bin/cargo")); + let path = parse_configure_path(value); + self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"])); + self.cargo = Some(push_exe_path(path, &["bin", "cargo"])); } _ => {} } @@ -454,6 +466,30 @@ impl Config { } } +#[cfg(not(windows))] +fn parse_configure_path(path: &str) -> PathBuf { + path.into() +} + +#[cfg(windows)] +fn parse_configure_path(path: &str) -> PathBuf { + // on windows, configure produces unix style paths e.g. /c/some/path but we + // only want real windows paths + + use std::process::Command; + use build_helper; + + // '/' is invalid in windows paths, so we can detect unix paths by the presence of it + if !path.contains('/') { + return path.into(); + } + + let win_path = build_helper::output(Command::new("cygpath").arg("-w").arg(path)); + let win_path = win_path.trim(); + + win_path.into() +} + fn set(field: &mut T, val: Option) { if let Some(v) = val { *field = v; diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index b4730c003d64..306708f9e4b6 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -79,6 +79,12 @@ # Indicate whether submodules are managed and updated automatically. #submodules = true +# The path to (or name of) the GDB executable to use +#gdb = "gdb" + +# Indicate whether the vendored sources are used for Rust dependencies or not +#vendor = false + # ============================================================================= # Options for compiling Rust code itself # ============================================================================= diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index c2636384dbb2..30c7fefad874 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -19,7 +19,6 @@ use std::fs::{self, File}; use std::io::prelude::*; -use std::path::Path; use std::process::Command; use {Build, Compiler, Mode}; @@ -30,8 +29,9 @@ use util::{up_to_date, cp_r}; /// /// This will not actually generate any documentation if the documentation has /// already been generated. -pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path) { - t!(fs::create_dir_all(out)); +pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str) { + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let out = out.join(name); let compiler = Compiler::new(stage, &build.config.build); @@ -57,9 +57,10 @@ pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path) /// `STAMP` alongw ith providing the various header/footer HTML we've cutomized. /// /// In the end, this is just a glorified wrapper around rustdoc! -pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) { +pub fn standalone(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} standalone ({})", stage, target); - t!(fs::create_dir_all(out)); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let compiler = Compiler::new(stage, &build.config.build); @@ -109,7 +110,7 @@ pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) { .arg("--html-in-header").arg(&favicon) .arg("--markdown-playground-url") .arg("https://play.rust-lang.org/") - .arg("-o").arg(out) + .arg("-o").arg(&out) .arg(&path); if filename == "reference.md" { @@ -131,9 +132,10 @@ pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) { /// /// This will generate all documentation for the standard library and its /// dependencies. This is largely just a wrapper around `cargo doc`. -pub fn std(build: &Build, stage: u32, target: &str, out: &Path) { +pub fn std(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} std ({})", stage, target); - t!(fs::create_dir_all(out)); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let compiler = Compiler::new(stage, &build.config.build); let out_dir = build.stage_out(&compiler, Mode::Libstd) .join(target).join("doc"); @@ -146,16 +148,17 @@ pub fn std(build: &Build, stage: u32, target: &str, out: &Path) { .arg(build.src.join("src/rustc/std_shim/Cargo.toml")) .arg("--features").arg(build.std_features()); build.run(&mut cargo); - cp_r(&out_dir, out) + cp_r(&out_dir, &out) } /// Compile all libtest documentation. /// /// This will generate all documentation for libtest and its dependencies. This /// is largely just a wrapper around `cargo doc`. -pub fn test(build: &Build, stage: u32, target: &str, out: &Path) { +pub fn test(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} test ({})", stage, target); - t!(fs::create_dir_all(out)); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let compiler = Compiler::new(stage, &build.config.build); let out_dir = build.stage_out(&compiler, Mode::Libtest) .join(target).join("doc"); @@ -167,16 +170,17 @@ pub fn test(build: &Build, stage: u32, target: &str, out: &Path) { cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/test_shim/Cargo.toml")); build.run(&mut cargo); - cp_r(&out_dir, out) + cp_r(&out_dir, &out) } /// Generate all compiler documentation. /// /// This will generate all documentation for the compiler libraries and their /// dependencies. This is largely just a wrapper around `cargo doc`. -pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) { +pub fn rustc(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} compiler ({})", stage, target); - t!(fs::create_dir_all(out)); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let compiler = Compiler::new(stage, &build.config.build); let out_dir = build.stage_out(&compiler, Mode::Librustc) .join(target).join("doc"); @@ -189,14 +193,15 @@ pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) { .arg(build.src.join("src/rustc/Cargo.toml")) .arg("--features").arg(build.rustc_features()); build.run(&mut cargo); - cp_r(&out_dir, out) + cp_r(&out_dir, &out) } /// Generates the HTML rendered error-index by running the /// `error_index_generator` tool. -pub fn error_index(build: &Build, stage: u32, target: &str, out: &Path) { +pub fn error_index(build: &Build, stage: u32, target: &str) { println!("Documenting stage{} error index ({})", stage, target); - t!(fs::create_dir_all(out)); + let out = build.doc_out(target); + t!(fs::create_dir_all(&out)); let compiler = Compiler::new(stage, &build.config.build); let mut index = build.tool_cmd(&compiler, "error_index_generator"); index.arg("html"); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index d925997f36c2..d7516954f12d 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -13,30 +13,46 @@ //! This module implements the command-line parsing of the build system which //! has various flags to configure how it's run. +use std::env; use std::fs; use std::path::PathBuf; use std::process; -use std::slice; -use getopts::Options; +use getopts::{Matches, Options}; + +use Build; +use config::Config; +use metadata; +use step; /// Deserialized version of all flags for this compile. pub struct Flags { pub verbose: bool, pub stage: Option, pub build: String, - pub host: Filter, - pub target: Filter, - pub step: Vec, + pub host: Vec, + pub target: Vec, pub config: Option, pub src: Option, pub jobs: Option, - pub args: Vec, - pub clean: bool, + pub cmd: Subcommand, } -pub struct Filter { - values: Vec, +pub enum Subcommand { + Build { + paths: Vec, + }, + Doc { + paths: Vec, + }, + Test { + paths: Vec, + test_args: Vec, + }, + Clean, + Dist { + install: bool, + }, } impl Flags { @@ -44,29 +60,177 @@ impl Flags { let mut opts = Options::new(); opts.optflag("v", "verbose", "use verbose output"); opts.optopt("", "config", "TOML configuration file for build", "FILE"); + opts.optopt("", "build", "build target of the stage0 compiler", "BUILD"); opts.optmulti("", "host", "host targets to build", "HOST"); - opts.reqopt("", "build", "build target of the stage0 compiler", "BUILD"); - opts.optmulti("", "target", "targets to build", "TARGET"); - opts.optmulti("s", "step", "build step to execute", "STEP"); + opts.optmulti("", "target", "target targets to build", "TARGET"); opts.optopt("", "stage", "stage to build", "N"); - opts.optopt("", "src", "path to repo root", "DIR"); + opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); - opts.optflag("", "clean", "clean output directory"); opts.optflag("h", "help", "print this help message"); - let usage = |n| -> ! { - let brief = format!("Usage: rust.py [options]"); - print!("{}", opts.usage(&brief)); + let usage = |n, opts: &Options| -> ! { + let command = args.get(0).map(|s| &**s); + let brief = format!("Usage: x.py {} [options] [...]", + command.unwrap_or("")); + + println!("{}", opts.usage(&brief)); + match command { + Some("build") => { + println!("\ +Arguments: + This subcommand accepts a number of positional arguments of directories to + the crates and/or artifacts to compile. For example: + + ./x.py build src/libcore + ./x.py build src/libproc_macro + ./x.py build src/libstd --stage 1 + + If no arguments are passed then the complete artifacts for that stage are + also compiled. + + ./x.py build + ./x.py build --stage 1 + + For a quick build with a usable compile, you can pass: + + ./x.py build --stage 1 src/libtest +"); + } + + Some("test") => { + println!("\ +Arguments: + This subcommand accepts a number of positional arguments of directories to + tests that should be compiled and run. For example: + + ./x.py test src/test/run-pass + ./x.py test src/test/run-pass/assert-* + ./x.py test src/libstd --test-args hash_map + ./x.py test src/libstd --stage 0 + + If no arguments are passed then the complete artifacts for that stage are + compiled and tested. + + ./x.py test + ./x.py test --stage 1 +"); + } + + Some("doc") => { + println!("\ +Arguments: + This subcommand accepts a number of positional arguments of directories of + documentation to build. For example: + + ./x.py doc src/doc/book + ./x.py doc src/doc/nomicon + ./x.py doc src/libstd + + If no arguments are passed then everything is documented: + + ./x.py doc + ./x.py doc --stage 1 +"); + } + + _ => {} + } + + if let Some(command) = command { + if command == "build" || + command == "dist" || + command == "doc" || + command == "test" || + command == "clean" { + println!("Available invocations:"); + if args.iter().any(|a| a == "-v") { + let flags = Flags::parse(&["build".to_string()]); + let mut config = Config::default(); + config.build = flags.build.clone(); + let mut build = Build::new(flags, config); + metadata::build(&mut build); + step::build_rules(&build).print_help(command); + } else { + println!(" ... elided, run `./x.py {} -h -v` to see", + command); + } + + println!(""); + } + } + +println!("\ +Subcommands: + build Compile either the compiler or libraries + test Build and run some test suites + doc Build documentation + clean Clean out build directories + dist Build and/or install distribution artifacts + +To learn more about a subcommand, run `./x.py -h` +"); + process::exit(n); }; - - let m = opts.parse(args).unwrap_or_else(|e| { - println!("failed to parse options: {}", e); - usage(1); - }); - if m.opt_present("h") { - usage(0); + if args.len() == 0 { + println!("a command must be passed"); + usage(1, &opts); } + let parse = |opts: &Options| { + let m = opts.parse(&args[1..]).unwrap_or_else(|e| { + println!("failed to parse options: {}", e); + usage(1, opts); + }); + if m.opt_present("h") { + usage(0, opts); + } + return m + }; + + let cwd = t!(env::current_dir()); + let remaining_as_path = |m: &Matches| { + m.free.iter().map(|p| cwd.join(p)).collect::>() + }; + + let m: Matches; + let cmd = match &args[0][..] { + "build" => { + m = parse(&opts); + Subcommand::Build { paths: remaining_as_path(&m) } + } + "doc" => { + m = parse(&opts); + Subcommand::Doc { paths: remaining_as_path(&m) } + } + "test" => { + opts.optmulti("", "test-args", "extra arguments", "ARGS"); + m = parse(&opts); + Subcommand::Test { + paths: remaining_as_path(&m), + test_args: m.opt_strs("test-args"), + } + } + "clean" => { + m = parse(&opts); + if m.free.len() > 0 { + println!("clean takes no arguments"); + usage(1, &opts); + } + Subcommand::Clean + } + "dist" => { + opts.optflag("", "install", "run installer as well"); + m = parse(&opts); + Subcommand::Dist { + install: m.opt_present("install"), + } + } + cmd => { + println!("unknown command: {}", cmd); + usage(1, &opts); + } + }; + let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { @@ -78,26 +242,27 @@ impl Flags { Flags { verbose: m.opt_present("v"), - clean: m.opt_present("clean"), stage: m.opt_str("stage").map(|j| j.parse().unwrap()), - build: m.opt_str("build").unwrap(), - host: Filter { values: m.opt_strs("host") }, - target: Filter { values: m.opt_strs("target") }, - step: m.opt_strs("step"), + build: m.opt_str("build").unwrap_or_else(|| { + env::var("BUILD").unwrap() + }), + host: m.opt_strs("host"), + target: m.opt_strs("target"), config: cfg_file, src: m.opt_str("src").map(PathBuf::from), jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()), - args: m.free.clone(), + cmd: cmd, } } } -impl Filter { - pub fn contains(&self, name: &str) -> bool { - self.values.len() == 0 || self.values.iter().any(|s| s == name) - } - - pub fn iter(&self) -> slice::Iter { - self.values.iter() +impl Subcommand { + pub fn test_args(&self) -> Vec<&str> { + match *self { + Subcommand::Test { ref test_args, .. } => { + test_args.iter().flat_map(|s| s.split_whitespace()).collect() + } + _ => Vec::new(), + } } } diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs index 4558e6f04943..b4d7aff97da6 100644 --- a/src/bootstrap/job.rs +++ b/src/bootstrap/job.rs @@ -37,15 +37,82 @@ //! Note that this module has a #[cfg(windows)] above it as none of this logic //! is required on Unix. -extern crate kernel32; -extern crate winapi; +#![allow(bad_style, dead_code)] use std::env; use std::io; use std::mem; -use self::winapi::*; -use self::kernel32::*; +type HANDLE = *mut u8; +type BOOL = i32; +type DWORD = u32; +type LPHANDLE = *mut HANDLE; +type LPVOID = *mut u8; +type JOBOBJECTINFOCLASS = i32; +type SIZE_T = usize; +type LARGE_INTEGER = i64; +type ULONG_PTR = usize; +type ULONGLONG = u64; + +const FALSE: BOOL = 0; +const DUPLICATE_SAME_ACCESS: DWORD = 0x2; +const PROCESS_DUP_HANDLE: DWORD = 0x40; +const JobObjectExtendedLimitInformation: JOBOBJECTINFOCLASS = 9; +const JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: DWORD = 0x2000; + +extern "system" { + fn CreateJobObjectW(lpJobAttributes: *mut u8, lpName: *const u8) -> HANDLE; + fn CloseHandle(hObject: HANDLE) -> BOOL; + fn GetCurrentProcess() -> HANDLE; + fn OpenProcess(dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwProcessId: DWORD) -> HANDLE; + fn DuplicateHandle(hSourceProcessHandle: HANDLE, + hSourceHandle: HANDLE, + hTargetProcessHandle: HANDLE, + lpTargetHandle: LPHANDLE, + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwOptions: DWORD) -> BOOL; + fn AssignProcessToJobObject(hJob: HANDLE, hProcess: HANDLE) -> BOOL; + fn SetInformationJobObject(hJob: HANDLE, + JobObjectInformationClass: JOBOBJECTINFOCLASS, + lpJobObjectInformation: LPVOID, + cbJobObjectInformationLength: DWORD) -> BOOL; +} + +#[repr(C)] +struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { + BasicLimitInformation: JOBOBJECT_BASIC_LIMIT_INFORMATION, + IoInfo: IO_COUNTERS, + ProcessMemoryLimit: SIZE_T, + JobMemoryLimit: SIZE_T, + PeakProcessMemoryUsed: SIZE_T, + PeakJobMemoryUsed: SIZE_T, +} + +#[repr(C)] +struct IO_COUNTERS { + ReadOperationCount: ULONGLONG, + WriteOperationCount: ULONGLONG, + OtherOperationCount: ULONGLONG, + ReadTransferCount: ULONGLONG, + WriteTransferCount: ULONGLONG, + OtherTransferCount: ULONGLONG, +} + +#[repr(C)] +struct JOBOBJECT_BASIC_LIMIT_INFORMATION { + PerProcessUserTimeLimit: LARGE_INTEGER, + PerJobUserTimeLimit: LARGE_INTEGER, + LimitFlags: DWORD, + MinimumWorkingsetSize: SIZE_T, + MaximumWorkingsetSize: SIZE_T, + ActiveProcessLimit: DWORD, + Affinity: ULONG_PTR, + PriorityClass: DWORD, + SchedulingClass: DWORD, +} pub unsafe fn setup() { // Create a new job object for us to use diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 7c5a0c7373f8..e6b88ea58c9b 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -57,6 +57,7 @@ mod channel; mod check; mod clean; mod compile; +mod metadata; mod config; mod dist; mod doc; @@ -76,7 +77,7 @@ mod job { } pub use config::Config; -pub use flags::Flags; +pub use flags::{Flags, Subcommand}; /// A structure representing a Rust compiler. /// @@ -123,13 +124,23 @@ pub struct Build { bootstrap_key_stage0: String, // Probed tools at runtime - gdb_version: Option, lldb_version: Option, lldb_python_dir: Option, // Runtime state filled in later on cc: HashMap)>, cxx: HashMap, + crates: HashMap, +} + +#[derive(Debug)] +struct Crate { + name: String, + deps: Vec, + path: PathBuf, + doc_step: String, + build_step: String, + test_step: String, } /// The various "modes" of invoking Cargo. @@ -162,7 +173,9 @@ impl Build { /// By default all build output will be placed in the current directory. pub fn new(flags: Flags, config: Config) -> Build { let cwd = t!(env::current_dir()); - let src = flags.src.clone().unwrap_or(cwd.clone()); + let src = flags.src.clone().or_else(|| { + env::var_os("SRC").map(|x| x.into()) + }).unwrap_or(cwd.clone()); let out = cwd.join("build"); let stage0_root = out.join(&config.build).join("stage0/bin"); @@ -196,7 +209,7 @@ impl Build { package_vers: String::new(), cc: HashMap::new(), cxx: HashMap::new(), - gdb_version: None, + crates: HashMap::new(), lldb_version: None, lldb_python_dir: None, } @@ -204,13 +217,11 @@ impl Build { /// Executes the entire build, as configured by the flags and configuration. pub fn build(&mut self) { - use step::Source::*; - unsafe { job::setup(); } - if self.flags.clean { + if let Subcommand::Clean = self.flags.cmd { return clean::clean(self); } @@ -232,247 +243,10 @@ impl Build { } self.verbose("updating submodules"); self.update_submodules(); + self.verbose("learning about cargo"); + metadata::build(self); - // The main loop of the build system. - // - // The `step::all` function returns a topographically sorted list of all - // steps that need to be executed as part of this build. Each step has a - // corresponding entry in `step.rs` and indicates some unit of work that - // needs to be done as part of the build. - // - // Almost all of these are simple one-liners that shell out to the - // corresponding functionality in the extra modules, where more - // documentation can be found. - let steps = step::all(self); - - self.verbose("bootstrap build plan:"); - for step in &steps { - self.verbose(&format!("{:?}", step)); - } - - for target in steps { - let doc_out = self.out.join(&target.target).join("doc"); - match target.src { - Llvm { _dummy } => { - native::llvm(self, target.target); - } - TestHelpers { _dummy } => { - native::test_helpers(self, target.target); - } - Libstd { compiler } => { - compile::std(self, target.target, &compiler); - } - Libtest { compiler } => { - compile::test(self, target.target, &compiler); - } - Librustc { compiler } => { - compile::rustc(self, target.target, &compiler); - } - LibstdLink { compiler, host } => { - compile::std_link(self, target.target, &compiler, host); - } - LibtestLink { compiler, host } => { - compile::test_link(self, target.target, &compiler, host); - } - LibrustcLink { compiler, host } => { - compile::rustc_link(self, target.target, &compiler, host); - } - Rustc { stage: 0 } => { - // nothing to do... - } - Rustc { stage } => { - compile::assemble_rustc(self, stage, target.target); - } - ToolLinkchecker { stage } => { - compile::tool(self, stage, target.target, "linkchecker"); - } - ToolRustbook { stage } => { - compile::tool(self, stage, target.target, "rustbook"); - } - ToolErrorIndex { stage } => { - compile::tool(self, stage, target.target, - "error_index_generator"); - } - ToolCargoTest { stage } => { - compile::tool(self, stage, target.target, "cargotest"); - } - ToolTidy { stage } => { - compile::tool(self, stage, target.target, "tidy"); - } - ToolCompiletest { stage } => { - compile::tool(self, stage, target.target, "compiletest"); - } - DocBook { stage } => { - doc::rustbook(self, stage, target.target, "book", &doc_out); - } - DocNomicon { stage } => { - doc::rustbook(self, stage, target.target, "nomicon", - &doc_out); - } - DocStandalone { stage } => { - doc::standalone(self, stage, target.target, &doc_out); - } - DocStd { stage } => { - doc::std(self, stage, target.target, &doc_out); - } - DocTest { stage } => { - doc::test(self, stage, target.target, &doc_out); - } - DocRustc { stage } => { - doc::rustc(self, stage, target.target, &doc_out); - } - DocErrorIndex { stage } => { - doc::error_index(self, stage, target.target, &doc_out); - } - - CheckLinkcheck { stage } => { - check::linkcheck(self, stage, target.target); - } - CheckCargoTest { stage } => { - check::cargotest(self, stage, target.target); - } - CheckTidy { stage } => { - check::tidy(self, stage, target.target); - } - CheckRPass { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-pass", "run-pass"); - } - CheckRPassFull { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-pass", "run-pass-fulldeps"); - } - CheckCFail { compiler } => { - check::compiletest(self, &compiler, target.target, - "compile-fail", "compile-fail"); - } - CheckCFailFull { compiler } => { - check::compiletest(self, &compiler, target.target, - "compile-fail", "compile-fail-fulldeps") - } - CheckPFail { compiler } => { - check::compiletest(self, &compiler, target.target, - "parse-fail", "parse-fail"); - } - CheckRFail { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-fail", "run-fail"); - } - CheckRFailFull { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-fail", "run-fail-fulldeps"); - } - CheckPretty { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "pretty"); - } - CheckPrettyRPass { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "run-pass"); - } - CheckPrettyRPassFull { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "run-pass-fulldeps"); - } - CheckPrettyRFail { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "run-fail"); - } - CheckPrettyRFailFull { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "run-fail-fulldeps"); - } - CheckPrettyRPassValgrind { compiler } => { - check::compiletest(self, &compiler, target.target, - "pretty", "run-pass-valgrind"); - } - CheckMirOpt { compiler } => { - check::compiletest(self, &compiler, target.target, - "mir-opt", "mir-opt"); - } - CheckCodegen { compiler } => { - if self.config.codegen_tests { - check::compiletest(self, &compiler, target.target, - "codegen", "codegen"); - } - } - CheckCodegenUnits { compiler } => { - check::compiletest(self, &compiler, target.target, - "codegen-units", "codegen-units"); - } - CheckIncremental { compiler } => { - check::compiletest(self, &compiler, target.target, - "incremental", "incremental"); - } - CheckUi { compiler } => { - check::compiletest(self, &compiler, target.target, - "ui", "ui"); - } - CheckDebuginfo { compiler } => { - if target.target.contains("msvc") { - // nothing to do - } else if target.target.contains("apple") { - check::compiletest(self, &compiler, target.target, - "debuginfo-lldb", "debuginfo"); - } else { - check::compiletest(self, &compiler, target.target, - "debuginfo-gdb", "debuginfo"); - } - } - CheckRustdoc { compiler } => { - check::compiletest(self, &compiler, target.target, - "rustdoc", "rustdoc"); - } - CheckRPassValgrind { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-pass-valgrind", "run-pass-valgrind"); - } - CheckDocs { compiler } => { - check::docs(self, &compiler); - } - CheckErrorIndex { compiler } => { - check::error_index(self, &compiler); - } - CheckRMake { compiler } => { - check::compiletest(self, &compiler, target.target, - "run-make", "run-make") - } - CheckCrateStd { compiler } => { - check::krate(self, &compiler, target.target, Mode::Libstd) - } - CheckCrateTest { compiler } => { - check::krate(self, &compiler, target.target, Mode::Libtest) - } - CheckCrateRustc { compiler } => { - check::krate(self, &compiler, target.target, Mode::Librustc) - } - - DistDocs { stage } => dist::docs(self, stage, target.target), - DistMingw { _dummy } => dist::mingw(self, target.target), - DistRustc { stage } => dist::rustc(self, stage, target.target), - DistStd { compiler } => dist::std(self, &compiler, target.target), - DistSrc { _dummy } => dist::rust_src(self), - - Install { stage } => install::install(self, stage, target.target), - - DebuggerScripts { stage } => { - let compiler = Compiler::new(stage, target.target); - dist::debugger_scripts(self, - &self.sysroot(&compiler), - target.target); - } - - AndroidCopyLibs { compiler } => { - check::android_copy_libs(self, &compiler, target.target); - } - - // pseudo-steps - Dist { .. } | - Doc { .. } | - CheckTarget { .. } | - Check { .. } => {} - } - } + step::run(self); } /// Updates all git submodules that we have. @@ -686,6 +460,9 @@ impl Build { if self.config.rust_optimize { cargo.arg("--release"); } + if self.config.vendor { + cargo.arg("--frozen"); + } return cargo } @@ -812,6 +589,11 @@ impl Build { self.out.join(target).join("llvm") } + /// Output directory for all documentation for a target + fn doc_out(&self, target: &str) -> PathBuf { + self.out.join(target).join("doc") + } + /// Returns true if no custom `llvm-config` is set for the specified target. /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. @@ -873,7 +655,7 @@ impl Build { /// Adds the compiler's bootstrap key to the environment of `cmd`. fn add_bootstrap_key(&self, cmd: &mut Command) { - cmd.env("RUSTC_BOOTSTRAP", ""); + cmd.env("RUSTC_BOOTSTRAP", "1"); // FIXME: Transitionary measure to bootstrap using the old bootstrap logic. // Remove this once the bootstrap compiler uses the new login in Issue #36548. cmd.env("RUSTC_BOOTSTRAP_KEY", "62b3e239"); diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs new file mode 100644 index 000000000000..bf5cc6a4ad83 --- /dev/null +++ b/src/bootstrap/metadata.rs @@ -0,0 +1,95 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashMap; +use std::process::Command; +use std::path::PathBuf; + +use build_helper::output; +use rustc_serialize::json; + +use {Build, Crate}; + +#[derive(RustcDecodable)] +struct Output { + packages: Vec, + resolve: Resolve, +} + +#[derive(RustcDecodable)] +struct Package { + id: String, + name: String, + source: Option, + manifest_path: String, +} + +#[derive(RustcDecodable)] +struct Resolve { + nodes: Vec, +} + +#[derive(RustcDecodable)] +struct ResolveNode { + id: String, + dependencies: Vec, +} + +pub fn build(build: &mut Build) { + build_krate(build, "src/rustc/std_shim"); + build_krate(build, "src/rustc/test_shim"); + build_krate(build, "src/rustc"); +} + +fn build_krate(build: &mut Build, krate: &str) { + // Run `cargo metadata` to figure out what crates we're testing. + // + // Down below we're going to call `cargo test`, but to test the right set + // of packages we're going to have to know what `-p` arguments to pass it + // to know what crates to test. Here we run `cargo metadata` to learn about + // the dependency graph and what `-p` arguments there are. + let mut cargo = Command::new(&build.cargo); + cargo.arg("metadata") + .arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml")); + let output = output(&mut cargo); + let output: Output = json::decode(&output).unwrap(); + let mut id2name = HashMap::new(); + for package in output.packages { + if package.source.is_none() { + id2name.insert(package.id, package.name.clone()); + let mut path = PathBuf::from(package.manifest_path); + path.pop(); + build.crates.insert(package.name.clone(), Crate { + build_step: format!("build-crate-{}", package.name), + doc_step: format!("doc-crate-{}", package.name), + test_step: format!("test-crate-{}", package.name), + name: package.name, + deps: Vec::new(), + path: path, + }); + } + } + + for node in output.resolve.nodes { + let name = match id2name.get(&node.id) { + Some(name) => name, + None => continue, + }; + + let krate = build.crates.get_mut(name).unwrap(); + for dep in node.dependencies.iter() { + let dep = match id2name.get(dep) { + Some(dep) => dep, + None => continue, + }; + krate.deps.push(dep.clone()); + } + } +} diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 0762ed98472b..d4031077639c 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -17,47 +17,46 @@ else BOOTSTRAP_ARGS := endif -BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_ARGS) +BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py all: - $(Q)$(BOOTSTRAP) + $(Q)$(BOOTSTRAP) build $(BOOTSTRAP_ARGS) + $(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS) # Don’t use $(Q) here, always show how to invoke the bootstrap script directly help: $(BOOTSTRAP) --help clean: - $(Q)$(BOOTSTRAP) --clean + $(Q)$(BOOTSTRAP) clean $(BOOTSTRAP_ARGS) rustc-stage1: - $(Q)$(BOOTSTRAP) --step libtest --stage 1 + $(Q)$(BOOTSTRAP) build --stage 1 src/libtest $(BOOTSTRAP_ARGS) rustc-stage2: - $(Q)$(BOOTSTRAP) --step libtest --stage 2 + $(Q)$(BOOTSTRAP) build --stage 2 src/libtest $(BOOTSTRAP_ARGS) docs: doc doc: - $(Q)$(BOOTSTRAP) --step doc -style: - $(Q)$(BOOTSTRAP) --step doc-style + $(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS) nomicon: - $(Q)$(BOOTSTRAP) --step doc-nomicon + $(Q)$(BOOTSTRAP) doc src/doc/nomicon $(BOOTSTRAP_ARGS) book: - $(Q)$(BOOTSTRAP) --step doc-book + $(Q)$(BOOTSTRAP) doc src/doc/book $(BOOTSTRAP_ARGS) standalone-docs: - $(Q)$(BOOTSTRAP) --step doc-standalone + $(Q)$(BOOTSTRAP) doc src/doc $(BOOTSTRAP_ARGS) check: - $(Q)$(BOOTSTRAP) --step check + $(Q)$(BOOTSTRAP) test $(BOOTSTRAP_ARGS) check-cargotest: - $(Q)$(BOOTSTRAP) --step check-cargotest + $(Q)$(BOOTSTRAP) test src/tools/cargotest $(BOOTSTRAP_ARGS) dist: - $(Q)$(BOOTSTRAP) --step dist + $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) install: ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) $(Q)echo "'sudo make install' is not supported currently." else - $(Q)$(BOOTSTRAP) --step install + $(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS) endif tidy: - $(Q)$(BOOTSTRAP) --step check-tidy --stage 0 + $(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS) .PHONY: dist diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 969cd70fd57e..cc1b7136d475 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -92,6 +92,12 @@ pub fn check(build: &mut Build) { need_cmd(s.as_ref()); } + if let Some(ref gdb) = build.config.gdb { + need_cmd(gdb.as_ref()); + } else { + build.config.gdb = have_cmd("gdb".as_ref()); + } + // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. for target in build.config.target.iter() { @@ -198,7 +204,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake .to_string() }) }; - build.gdb_version = run(Command::new("gdb").arg("--version")).ok(); build.lldb_version = run(Command::new("lldb").arg("--version")).ok(); if build.lldb_version.is_some() { build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok(); diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 3bf0f2119214..6f616434b10c 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -8,600 +8,691 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Major workhorse of rustbuild, definition and dependencies between stages of -//! the copmile. -//! -//! The primary purpose of this module is to define the various `Step`s of -//! execution of the build. Each `Step` has a corresponding `Source` indicating -//! what it's actually doing along with a number of dependencies which must be -//! executed first. -//! -//! This module will take the CLI as input and calculate the steps required for -//! the build requested, ensuring that all intermediate pieces are in place. -//! Essentially this module is a `make`-replacement, but not as good. +use std::collections::{HashMap, HashSet}; +use std::mem; -use std::collections::HashSet; +use check; +use compile; +use dist; +use doc; +use flags::Subcommand; +use install; +use native; +use {Compiler, Build, Mode}; -use {Build, Compiler}; - -#[derive(Hash, Eq, PartialEq, Clone, Debug)] -pub struct Step<'a> { - pub src: Source<'a>, - pub target: &'a str, -} - -/// Macro used to iterate over all targets that are recognized by the build -/// system. -/// -/// Whenever a new step is added it will involve adding an entry here, updating -/// the dependencies section below, and then adding an implementation of the -/// step in `build/mod.rs`. -/// -/// This macro takes another macro as an argument and then calls that macro with -/// all steps that the build system knows about. -macro_rules! targets { - ($m:ident) => { - $m! { - // Step representing building the stageN compiler. This is just the - // compiler executable itself, not any of the support libraries - (rustc, Rustc { stage: u32 }), - - // Steps for the two main cargo builds. These are parameterized over - // the compiler which is producing the artifact. - (libstd, Libstd { compiler: Compiler<'a> }), - (libtest, Libtest { compiler: Compiler<'a> }), - (librustc, Librustc { compiler: Compiler<'a> }), - - // Links the target produced by the compiler provided into the - // host's directory also provided. - (libstd_link, LibstdLink { - compiler: Compiler<'a>, - host: &'a str - }), - (libtest_link, LibtestLink { - compiler: Compiler<'a>, - host: &'a str - }), - (librustc_link, LibrustcLink { - compiler: Compiler<'a>, - host: &'a str - }), - - // Various tools that we can build as part of the build. - (tool_linkchecker, ToolLinkchecker { stage: u32 }), - (tool_rustbook, ToolRustbook { stage: u32 }), - (tool_error_index, ToolErrorIndex { stage: u32 }), - (tool_cargotest, ToolCargoTest { stage: u32 }), - (tool_tidy, ToolTidy { stage: u32 }), - (tool_compiletest, ToolCompiletest { stage: u32 }), - - // Steps for long-running native builds. Ideally these wouldn't - // actually exist and would be part of build scripts, but for now - // these are here. - // - // There aren't really any parameters to this, but empty structs - // with braces are unstable so we just pick something that works. - (llvm, Llvm { _dummy: () }), - (test_helpers, TestHelpers { _dummy: () }), - (debugger_scripts, DebuggerScripts { stage: u32 }), - - // Steps for various pieces of documentation that we can generate, - // the 'doc' step is just a pseudo target to depend on a bunch of - // others. - (doc, Doc { stage: u32 }), - (doc_book, DocBook { stage: u32 }), - (doc_nomicon, DocNomicon { stage: u32 }), - (doc_standalone, DocStandalone { stage: u32 }), - (doc_std, DocStd { stage: u32 }), - (doc_test, DocTest { stage: u32 }), - (doc_rustc, DocRustc { stage: u32 }), - (doc_error_index, DocErrorIndex { stage: u32 }), - - // Steps for running tests. The 'check' target is just a pseudo - // target to depend on a bunch of others. - (check, Check { stage: u32, compiler: Compiler<'a> }), - (check_target, CheckTarget { stage: u32, compiler: Compiler<'a> }), - (check_linkcheck, CheckLinkcheck { stage: u32 }), - (check_cargotest, CheckCargoTest { stage: u32 }), - (check_tidy, CheckTidy { stage: u32 }), - (check_rpass, CheckRPass { compiler: Compiler<'a> }), - (check_rpass_full, CheckRPassFull { compiler: Compiler<'a> }), - (check_rpass_valgrind, CheckRPassValgrind { compiler: Compiler<'a> }), - (check_rfail, CheckRFail { compiler: Compiler<'a> }), - (check_rfail_full, CheckRFailFull { compiler: Compiler<'a> }), - (check_cfail, CheckCFail { compiler: Compiler<'a> }), - (check_cfail_full, CheckCFailFull { compiler: Compiler<'a> }), - (check_pfail, CheckPFail { compiler: Compiler<'a> }), - (check_pretty, CheckPretty { compiler: Compiler<'a> }), - (check_pretty_rpass, CheckPrettyRPass { compiler: Compiler<'a> }), - (check_pretty_rpass_full, CheckPrettyRPassFull { compiler: Compiler<'a> }), - (check_pretty_rfail, CheckPrettyRFail { compiler: Compiler<'a> }), - (check_pretty_rfail_full, CheckPrettyRFailFull { compiler: Compiler<'a> }), - (check_pretty_rpass_valgrind, CheckPrettyRPassValgrind { compiler: Compiler<'a> }), - (check_codegen, CheckCodegen { compiler: Compiler<'a> }), - (check_codegen_units, CheckCodegenUnits { compiler: Compiler<'a> }), - (check_incremental, CheckIncremental { compiler: Compiler<'a> }), - (check_ui, CheckUi { compiler: Compiler<'a> }), - (check_mir_opt, CheckMirOpt { compiler: Compiler<'a> }), - (check_debuginfo, CheckDebuginfo { compiler: Compiler<'a> }), - (check_rustdoc, CheckRustdoc { compiler: Compiler<'a> }), - (check_docs, CheckDocs { compiler: Compiler<'a> }), - (check_error_index, CheckErrorIndex { compiler: Compiler<'a> }), - (check_rmake, CheckRMake { compiler: Compiler<'a> }), - (check_crate_std, CheckCrateStd { compiler: Compiler<'a> }), - (check_crate_test, CheckCrateTest { compiler: Compiler<'a> }), - (check_crate_rustc, CheckCrateRustc { compiler: Compiler<'a> }), - - // Distribution targets, creating tarballs - (dist, Dist { stage: u32 }), - (dist_docs, DistDocs { stage: u32 }), - (dist_mingw, DistMingw { _dummy: () }), - (dist_rustc, DistRustc { stage: u32 }), - (dist_std, DistStd { compiler: Compiler<'a> }), - (dist_src, DistSrc { _dummy: () }), - - // install target - (install, Install { stage: u32 }), - - // Misc targets - (android_copy_libs, AndroidCopyLibs { compiler: Compiler<'a> }), - } - } -} - -// Define the `Source` enum by iterating over all the steps and peeling out just -// the types that we want to define. - -macro_rules! item { ($a:item) => ($a) } - -macro_rules! define_source { - ($(($short:ident, $name:ident { $($args:tt)* }),)*) => { - item! { - #[derive(Hash, Eq, PartialEq, Clone, Debug)] - pub enum Source<'a> { - $($name { $($args)* }),* - } - } - } -} - -targets!(define_source); - -/// Calculate a list of all steps described by `build`. -/// -/// This will inspect the flags passed in on the command line and use that to -/// build up a list of steps to execute. These steps will then be transformed -/// into a topologically sorted list which when executed left-to-right will -/// correctly sequence the entire build. -pub fn all(build: &Build) -> Vec { - build.verbose("inferred build steps:"); - - let mut ret = Vec::new(); - let mut all = HashSet::new(); - for target in top_level(build) { - fill(build, &target, &mut ret, &mut all); - } - return ret; - - fn fill<'a>(build: &'a Build, - target: &Step<'a>, - ret: &mut Vec>, - set: &mut HashSet>) { - if set.insert(target.clone()) { - for dep in target.deps(build) { - build.verbose(&format!("{:?}\n -> {:?}", target, dep)); - fill(build, &dep, ret, set); - } - ret.push(target.clone()); - } - } -} - -/// Determines what top-level targets are requested as part of this build, -/// returning them as a list. -fn top_level(build: &Build) -> Vec { - let mut targets = Vec::new(); - let stage = build.flags.stage.unwrap_or(2); - - let host = Step { - src: Source::Llvm { _dummy: () }, - target: build.flags.host.iter().next() - .unwrap_or(&build.config.build), - }; - let target = Step { - src: Source::Llvm { _dummy: () }, - target: build.flags.target.iter().next().map(|x| &x[..]) - .unwrap_or(host.target) - }; - - // First, try to find steps on the command line. - add_steps(build, stage, &host, &target, &mut targets); - - // If none are specified, then build everything. - if targets.len() == 0 { - let t = Step { - src: Source::Llvm { _dummy: () }, - target: &build.config.build, - }; - if build.config.docs { - targets.push(t.doc(stage)); - } - for host in build.config.host.iter() { - if !build.flags.host.contains(host) { - continue - } - let host = t.target(host); - if host.target == build.config.build { - targets.push(host.librustc(host.compiler(stage))); - } else { - targets.push(host.librustc_link(t.compiler(stage), host.target)); - } - for target in build.config.target.iter() { - if !build.flags.target.contains(target) { - continue - } - - if host.target == build.config.build { - targets.push(host.target(target) - .libtest(host.compiler(stage))); - } else { - targets.push(host.target(target) - .libtest_link(t.compiler(stage), host.target)); - } - } - } - } - - targets -} - -fn add_steps<'a>(build: &'a Build, - stage: u32, - host: &Step<'a>, - target: &Step<'a>, - targets: &mut Vec>) { - struct Context<'a> { - stage: u32, - compiler: Compiler<'a>, - _dummy: (), - host: &'a str, - } - for step in build.flags.step.iter() { - - // The macro below insists on hygienic access to all local variables, so - // we shove them all in a struct and subvert hygiene by accessing struct - // fields instead, - let cx = Context { - stage: stage, - compiler: host.target(&build.config.build).compiler(stage), - _dummy: (), - host: host.target, - }; - macro_rules! add_step { - ($(($short:ident, $name:ident { $($arg:ident: $t:ty),* }),)*) => ({$( - let name = stringify!($short).replace("_", "-"); - if &step[..] == &name[..] { - targets.push(target.$short($(cx.$arg),*)); - continue - } - drop(name); - )*}) - } - - targets!(add_step); - - panic!("unknown step: {}", step); - } -} - -macro_rules! constructors { - ($(($short:ident, $name:ident { $($arg:ident: $t:ty),* }),)*) => {$( - fn $short(&self, $($arg: $t),*) -> Step<'a> { - Step { - src: Source::$name { $($arg: $arg),* }, - target: self.target, - } - } - )*} +#[derive(PartialEq, Eq, Hash, Clone, Debug)] +struct Step<'a> { + name: &'a str, + stage: u32, + host: &'a str, + target: &'a str, } impl<'a> Step<'a> { - fn compiler(&self, stage: u32) -> Compiler<'a> { - Compiler::new(stage, self.target) + fn name(&self, name: &'a str) -> Step<'a> { + Step { name: name, ..*self } + } + + fn stage(&self, stage: u32) -> Step<'a> { + Step { stage: stage, ..*self } + } + + fn host(&self, host: &'a str) -> Step<'a> { + Step { host: host, ..*self } } fn target(&self, target: &'a str) -> Step<'a> { - Step { target: target, src: self.src.clone() } + Step { target: target, ..*self } } - // Define ergonomic constructors for each step defined above so they can be - // easily constructed. - targets!(constructors); + fn compiler(&self) -> Compiler<'a> { + Compiler::new(self.stage, self.host) + } +} - /// Mapping of all dependencies for rustbuild. - /// - /// This function receives a step, the build that we're building for, and - /// then returns a list of all the dependencies of that step. - pub fn deps(&self, build: &'a Build) -> Vec> { - match self.src { - Source::Rustc { stage: 0 } => { - Vec::new() - } - Source::Rustc { stage } => { - let compiler = Compiler::new(stage - 1, &build.config.build); - vec![self.librustc(compiler)] - } - Source::Librustc { compiler } => { - vec![self.libtest(compiler), self.llvm(())] - } - Source::Libtest { compiler } => { - vec![self.libstd(compiler)] - } - Source::Libstd { compiler } => { - vec![self.rustc(compiler.stage).target(compiler.host)] - } - Source::LibrustcLink { compiler, host } => { - vec![self.librustc(compiler), - self.libtest_link(compiler, host)] - } - Source::LibtestLink { compiler, host } => { - vec![self.libtest(compiler), self.libstd_link(compiler, host)] - } - Source::LibstdLink { compiler, host } => { - vec![self.libstd(compiler), - self.target(host).rustc(compiler.stage)] - } - Source::Llvm { _dummy } => Vec::new(), - Source::TestHelpers { _dummy } => Vec::new(), - Source::DebuggerScripts { stage: _ } => Vec::new(), +pub fn run(build: &Build) { + let rules = build_rules(build); + let steps = rules.plan(); + rules.run(&steps); +} - // Note that all doc targets depend on artifacts from the build - // architecture, not the target (which is where we're generating - // docs into). - Source::DocStd { stage } => { - let compiler = self.target(&build.config.build).compiler(stage); - vec![self.libstd(compiler)] - } - Source::DocTest { stage } => { - let compiler = self.target(&build.config.build).compiler(stage); - vec![self.libtest(compiler)] - } - Source::DocBook { stage } | - Source::DocNomicon { stage } => { - vec![self.target(&build.config.build).tool_rustbook(stage)] - } - Source::DocErrorIndex { stage } => { - vec![self.target(&build.config.build).tool_error_index(stage)] - } - Source::DocStandalone { stage } => { - vec![self.target(&build.config.build).rustc(stage)] - } - Source::DocRustc { stage } => { - vec![self.doc_test(stage)] - } - Source::Doc { stage } => { - let mut deps = vec![ - self.doc_book(stage), self.doc_nomicon(stage), - self.doc_standalone(stage), self.doc_std(stage), - self.doc_error_index(stage), - ]; +pub fn build_rules(build: &Build) -> Rules { + let mut rules: Rules = Rules::new(build); + // dummy rule to do nothing, useful when a dep maps to no deps + rules.build("dummy", "path/to/nowhere"); + fn dummy<'a>(s: &Step<'a>, build: &'a Build) -> Step<'a> { + s.name("dummy").stage(0) + .target(&build.config.build) + .host(&build.config.build) + } - if build.config.compiler_docs { - deps.push(self.doc_rustc(stage)); - } - - deps - } - Source::Check { stage, compiler } => { - // Check is just a pseudo step which means check all targets, - // so just depend on checking all targets. - build.config.target.iter().map(|t| { - self.target(t).check_target(stage, compiler) - }).collect() - } - Source::CheckTarget { stage, compiler } => { - // CheckTarget here means run all possible test suites for this - // target. Most of the time, however, we can't actually run - // anything if we're not the build triple as we could be cross - // compiling. - // - // As a result, the base set of targets here is quite stripped - // down from the standard set of targets. These suites have - // their own internal logic to run in cross-compiled situations - // if they'll run at all. For example compiletest knows that - // when testing Android targets we ship artifacts to the - // emulator. - // - // When in doubt the rule of thumb for adding to this list is - // "should this test suite run on the android bot?" - let mut base = vec![ - self.check_rpass(compiler), - self.check_rfail(compiler), - self.check_crate_std(compiler), - self.check_crate_test(compiler), - self.check_debuginfo(compiler), - ]; - - // If we're testing the build triple, then we know we can - // actually run binaries and such, so we run all possible tests - // that we know about. - if self.target == build.config.build { - base.extend(vec![ - // docs-related - self.check_docs(compiler), - self.check_error_index(compiler), - self.check_rustdoc(compiler), - - // UI-related - self.check_cfail(compiler), - self.check_pfail(compiler), - self.check_ui(compiler), - - // codegen-related - self.check_incremental(compiler), - self.check_codegen(compiler), - self.check_codegen_units(compiler), - - // misc compiletest-test suites - self.check_rpass_full(compiler), - self.check_rfail_full(compiler), - self.check_cfail_full(compiler), - self.check_pretty_rpass_full(compiler), - self.check_pretty_rfail_full(compiler), - self.check_rpass_valgrind(compiler), - self.check_rmake(compiler), - self.check_mir_opt(compiler), - - // crates - self.check_crate_rustc(compiler), - - // pretty - self.check_pretty(compiler), - self.check_pretty_rpass(compiler), - self.check_pretty_rfail(compiler), - self.check_pretty_rpass_valgrind(compiler), - - // misc - self.check_linkcheck(stage), - self.check_tidy(stage), - - // can we make the distributables? - self.dist(stage), - ]); - } - base - } - Source::CheckLinkcheck { stage } => { - vec![self.tool_linkchecker(stage), self.doc(stage)] - } - Source::CheckCargoTest { stage } => { - vec![self.tool_cargotest(stage), - self.librustc(self.compiler(stage))] - } - Source::CheckTidy { stage } => { - vec![self.tool_tidy(stage)] - } - Source::CheckMirOpt { compiler} | - Source::CheckPrettyRPass { compiler } | - Source::CheckPrettyRFail { compiler } | - Source::CheckRFail { compiler } | - Source::CheckPFail { compiler } | - Source::CheckCodegen { compiler } | - Source::CheckCodegenUnits { compiler } | - Source::CheckIncremental { compiler } | - Source::CheckUi { compiler } | - Source::CheckPretty { compiler } | - Source::CheckCFail { compiler } | - Source::CheckRPassValgrind { compiler } | - Source::CheckRPass { compiler } => { - let mut base = vec![ - self.libtest(compiler), - self.target(compiler.host).tool_compiletest(compiler.stage), - self.test_helpers(()), - ]; - if self.target.contains("android") { - base.push(self.android_copy_libs(compiler)); - } - base - } - Source::CheckDebuginfo { compiler } => { - vec![ - self.libtest(compiler), - self.target(compiler.host).tool_compiletest(compiler.stage), - self.test_helpers(()), - self.debugger_scripts(compiler.stage), - ] - } - Source::CheckRustdoc { compiler } | - Source::CheckRPassFull { compiler } | - Source::CheckRFailFull { compiler } | - Source::CheckCFailFull { compiler } | - Source::CheckPrettyRPassFull { compiler } | - Source::CheckPrettyRFailFull { compiler } | - Source::CheckPrettyRPassValgrind { compiler } | - Source::CheckRMake { compiler } => { - vec![self.librustc(compiler), - self.target(compiler.host).tool_compiletest(compiler.stage)] - } - Source::CheckDocs { compiler } => { - vec![self.libtest(compiler)] - } - Source::CheckErrorIndex { compiler } => { - vec![self.libstd(compiler), - self.target(compiler.host).tool_error_index(compiler.stage)] - } - Source::CheckCrateStd { compiler } => { - vec![self.libtest(compiler)] - } - Source::CheckCrateTest { compiler } => { - vec![self.libtest(compiler)] - } - Source::CheckCrateRustc { compiler } => { - vec![self.libtest(compiler)] - } - - Source::ToolLinkchecker { stage } | - Source::ToolTidy { stage } => { - vec![self.libstd(self.compiler(stage))] - } - Source::ToolErrorIndex { stage } | - Source::ToolRustbook { stage } => { - vec![self.librustc(self.compiler(stage))] - } - Source::ToolCargoTest { stage } => { - vec![self.libstd(self.compiler(stage))] - } - Source::ToolCompiletest { stage } => { - vec![self.libtest(self.compiler(stage))] - } - - Source::DistDocs { stage } => vec![self.doc(stage)], - Source::DistMingw { _dummy: _ } => Vec::new(), - Source::DistRustc { stage } => { - vec![self.rustc(stage)] - } - Source::DistStd { compiler } => { - // We want to package up as many target libraries as possible - // for the `rust-std` package, so if this is a host target we - // depend on librustc and otherwise we just depend on libtest. - if build.config.host.iter().any(|t| t == self.target) { - vec![self.librustc(compiler)] - } else { - vec![self.libtest(compiler)] + // Helper for loading an entire DAG of crates, rooted at `name` + let krates = |name: &str| { + let mut ret = Vec::new(); + let mut list = vec![name]; + let mut visited = HashSet::new(); + while let Some(krate) = list.pop() { + let default = krate == name; + let krate = &build.crates[krate]; + let path = krate.path.strip_prefix(&build.src).unwrap(); + ret.push((krate, path.to_str().unwrap(), default)); + for dep in krate.deps.iter() { + if visited.insert(dep) && dep != "build_helper" { + list.push(dep); } } - Source::DistSrc { _dummy: _ } => Vec::new(), + } + return ret + }; - Source::Dist { stage } => { - let mut base = Vec::new(); + rules.build("rustc", "path/to/nowhere") + .dep(move |s| { + if s.stage == 0 { + dummy(s, build) + } else { + s.name("librustc") + .host(&build.config.build) + .stage(s.stage - 1) + } + }) + .run(move |s| compile::assemble_rustc(build, s.stage, s.target)); + rules.build("llvm", "src/llvm") + .host(true) + .run(move |s| native::llvm(build, s.target)); - for host in build.config.host.iter() { - let host = self.target(host); - base.push(host.dist_src(())); - base.push(host.dist_rustc(stage)); - if host.target.contains("windows-gnu") { - base.push(host.dist_mingw(())); - } + // ======================================================================== + // Crate compilations + // + // Tools used during the build system but not shipped + rules.build("libstd", "src/libstd") + .dep(|s| s.name("build-crate-std_shim")); + rules.build("libtest", "src/libtest") + .dep(|s| s.name("build-crate-test_shim")); + rules.build("librustc", "src/librustc") + .dep(|s| s.name("build-crate-rustc-main")); + for (krate, path, _default) in krates("std_shim") { + rules.build(&krate.build_step, path) + .dep(move |s| s.name("rustc").host(&build.config.build).target(s.host)) + .dep(move |s| { + if s.host == build.config.build { + dummy(s, build) + } else { + s.host(&build.config.build) + } + }) + .run(move |s| { + if s.host == build.config.build { + compile::std(build, s.target, &s.compiler()) + } else { + compile::std_link(build, s.target, s.stage, s.host) + } + }); + } + for (krate, path, default) in krates("test_shim") { + rules.build(&krate.build_step, path) + .dep(|s| s.name("libstd")) + .dep(move |s| { + if s.host == build.config.build { + dummy(s, build) + } else { + s.host(&build.config.build) + } + }) + .default(default) + .run(move |s| { + if s.host == build.config.build { + compile::test(build, s.target, &s.compiler()) + } else { + compile::test_link(build, s.target, s.stage, s.host) + } + }); + } + for (krate, path, default) in krates("rustc-main") { + rules.build(&krate.build_step, path) + .dep(|s| s.name("libtest")) + .dep(move |s| s.name("llvm").host(&build.config.build).stage(0)) + .dep(move |s| { + if s.host == build.config.build { + dummy(s, build) + } else { + s.host(&build.config.build) + } + }) + .host(true) + .default(default) + .run(move |s| { + if s.host == build.config.build { + compile::rustc(build, s.target, &s.compiler()) + } else { + compile::rustc_link(build, s.target, s.stage, s.host) + } + }); + } - let compiler = self.compiler(stage); - for target in build.config.target.iter() { - let target = self.target(target); - if build.config.docs { - base.push(target.dist_docs(stage)); - } - base.push(target.dist_std(compiler)); - } - } - base - } + // ======================================================================== + // Test targets + // + // Various unit tests and tests suites we can run + { + let mut suite = |name, path, dir, mode| { + rules.test(name, path) + .dep(|s| s.name("libtest")) + .dep(|s| s.name("tool-compiletest").target(s.host)) + .dep(|s| s.name("test-helpers")) + .dep(move |s| { + if s.target.contains("android") { + s.name("android-copy-libs") + } else { + dummy(s, build) + } + }) + .default(true) + .run(move |s| { + check::compiletest(build, &s.compiler(), s.target, dir, mode) + }); + }; - Source::Install { stage } => { - vec![self.dist(stage)] - } + suite("check-rpass", "src/test/run-pass", "run-pass", "run-pass"); + suite("check-cfail", "src/test/compile-fail", "compile-fail", "compile-fail"); + suite("check-pfail", "src/test/parse-fail", "parse-fail", "parse-fail"); + suite("check-rfail", "src/test/run-fail", "run-fail", "run-fail"); + suite("check-rpass-valgrind", "src/test/run-pass-valgrind", + "run-pass-valgrind", "run-pass-valgrind"); + suite("check-mir-opt", "src/test/mir-opt", "mir-opt", "mir-opt"); + if build.config.codegen_tests { + suite("check-codegen", "src/test/codegen", "codegen", "codegen"); + } + suite("check-codegen-units", "src/test/codegen-units", "codegen-units", + "codegen-units"); + suite("check-incremental", "src/test/incremental", "incremental", + "incremental"); + suite("check-ui", "src/test/ui", "ui", "ui"); + suite("check-pretty", "src/test/pretty", "pretty", "pretty"); + suite("check-pretty-rpass", "src/test/run-pass/pretty", "pretty", + "run-pass"); + suite("check-pretty-rfail", "src/test/run-pass/pretty", "pretty", + "run-fail"); + suite("check-pretty-valgrind", "src/test/run-pass-valgrind", "pretty", + "run-pass-valgrind"); + } - Source::AndroidCopyLibs { compiler } => { - vec![self.libtest(compiler)] - } + if build.config.build.contains("msvc") { + // nothing to do for debuginfo tests + } else if build.config.build.contains("apple") { + rules.test("check-debuginfo", "src/test/debuginfo") + .dep(|s| s.name("libtest")) + .dep(|s| s.name("tool-compiletest").host(s.host)) + .dep(|s| s.name("test-helpers")) + .dep(|s| s.name("debugger-scripts")) + .run(move |s| check::compiletest(build, &s.compiler(), s.target, + "debuginfo-lldb", "debuginfo")); + } else { + rules.test("check-debuginfo", "src/test/debuginfo") + .dep(|s| s.name("libtest")) + .dep(|s| s.name("tool-compiletest").host(s.host)) + .dep(|s| s.name("test-helpers")) + .dep(|s| s.name("debugger-scripts")) + .run(move |s| check::compiletest(build, &s.compiler(), s.target, + "debuginfo-gdb", "debuginfo")); + } + + rules.test("debugger-scripts", "src/etc/lldb_batchmode.py") + .run(move |s| dist::debugger_scripts(build, &build.sysroot(&s.compiler()), + s.target)); + + { + let mut suite = |name, path, dir, mode| { + rules.test(name, path) + .dep(|s| s.name("librustc")) + .dep(|s| s.name("tool-compiletest").target(s.host)) + .default(true) + .host(true) + .run(move |s| { + check::compiletest(build, &s.compiler(), s.target, dir, mode) + }); + }; + + suite("check-rpass-full", "src/test/run-pass-fulldeps", + "run-pass", "run-pass-fulldeps"); + suite("check-cfail-full", "src/test/compile-fail-fulldeps", + "compile-fail", "compile-fail-fulldeps"); + suite("check-rmake", "src/test/run-make", "run-make", "run-make"); + suite("check-rustdoc", "src/test/rustdoc", "rustdoc", "rustdoc"); + suite("check-pretty-rpass-full", "src/test/run-pass-fulldeps", + "pretty", "run-pass-fulldeps"); + suite("check-pretty-rfail-full", "src/test/run-fail-fulldeps", + "pretty", "run-fail-fulldeps"); + } + + for (krate, path, _default) in krates("std_shim") { + rules.test(&krate.test_step, path) + .dep(|s| s.name("libtest")) + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Libstd, Some(&krate.name))); + } + rules.test("check-std-all", "path/to/nowhere") + .dep(|s| s.name("libtest")) + .default(true) + .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libstd, + None)); + for (krate, path, _default) in krates("test_shim") { + rules.test(&krate.test_step, path) + .dep(|s| s.name("libtest")) + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Libtest, Some(&krate.name))); + } + rules.test("check-test-all", "path/to/nowhere") + .dep(|s| s.name("libtest")) + .default(true) + .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libtest, + None)); + for (krate, path, _default) in krates("rustc-main") { + rules.test(&krate.test_step, path) + .dep(|s| s.name("librustc")) + .host(true) + .run(move |s| check::krate(build, &s.compiler(), s.target, + Mode::Librustc, Some(&krate.name))); + } + rules.test("check-rustc-all", "path/to/nowhere") + .dep(|s| s.name("librustc")) + .default(true) + .host(true) + .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Librustc, + None)); + + rules.test("check-linkchecker", "src/tools/linkchecker") + .dep(|s| s.name("tool-linkchecker")) + .dep(|s| s.name("default:doc")) + .default(true) + .host(true) + .run(move |s| check::linkcheck(build, s.stage, s.target)); + rules.test("check-cargotest", "src/tools/cargotest") + .dep(|s| s.name("tool-cargotest")) + .dep(|s| s.name("librustc")) + .host(true) + .run(move |s| check::cargotest(build, s.stage, s.target)); + rules.test("check-tidy", "src/tools/tidy") + .dep(|s| s.name("tool-tidy")) + .default(true) + .host(true) + .run(move |s| check::tidy(build, s.stage, s.target)); + rules.test("check-error-index", "src/tools/error_index_generator") + .dep(|s| s.name("libstd")) + .dep(|s| s.name("tool-error-index").host(s.host)) + .default(true) + .host(true) + .run(move |s| check::error_index(build, &s.compiler())); + rules.test("check-docs", "src/doc") + .dep(|s| s.name("libtest")) + .default(true) + .host(true) + .run(move |s| check::docs(build, &s.compiler())); + + rules.build("test-helpers", "src/rt/rust_test_helpers.c") + .run(move |s| native::test_helpers(build, s.target)); + rules.test("android-copy-libs", "path/to/nowhere") + .dep(|s| s.name("libtest")) + .run(move |s| check::android_copy_libs(build, &s.compiler(), s.target)); + + // ======================================================================== + // Build tools + // + // Tools used during the build system but not shipped + rules.build("tool-rustbook", "src/tools/rustbook") + .dep(|s| s.name("librustc")) + .run(move |s| compile::tool(build, s.stage, s.target, "rustbook")); + rules.build("tool-error-index", "src/tools/error_index_generator") + .dep(|s| s.name("librustc")) + .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator")); + rules.build("tool-tidy", "src/tools/tidy") + .dep(|s| s.name("libstd")) + .run(move |s| compile::tool(build, s.stage, s.target, "tidy")); + rules.build("tool-linkchecker", "src/tools/linkchecker") + .dep(|s| s.name("libstd")) + .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker")); + rules.build("tool-cargotest", "src/tools/cargotest") + .dep(|s| s.name("libstd")) + .run(move |s| compile::tool(build, s.stage, s.target, "cargotest")); + rules.build("tool-compiletest", "src/tools/compiletest") + .dep(|s| s.name("libtest")) + .run(move |s| compile::tool(build, s.stage, s.target, "compiletest")); + + // ======================================================================== + // Documentation targets + rules.doc("doc-book", "src/doc/book") + .dep(move |s| s.name("tool-rustbook").target(&build.config.build)) + .default(build.config.docs) + .run(move |s| doc::rustbook(build, s.stage, s.target, "book")); + rules.doc("doc-nomicon", "src/doc/nomicon") + .dep(move |s| s.name("tool-rustbook").target(&build.config.build)) + .default(build.config.docs) + .run(move |s| doc::rustbook(build, s.stage, s.target, "nomicon")); + rules.doc("doc-standalone", "src/doc") + .dep(move |s| s.name("rustc").host(&build.config.build).target(&build.config.build)) + .default(build.config.docs) + .run(move |s| doc::standalone(build, s.stage, s.target)); + rules.doc("doc-error-index", "src/tools/error_index_generator") + .dep(move |s| s.name("tool-error-index").target(&build.config.build)) + .dep(move |s| s.name("librustc")) + .default(build.config.docs) + .host(true) + .run(move |s| doc::error_index(build, s.stage, s.target)); + for (krate, path, default) in krates("std_shim") { + rules.doc(&krate.doc_step, path) + .dep(|s| s.name("libstd")) + .default(default && build.config.docs) + .run(move |s| doc::std(build, s.stage, s.target)); + } + for (krate, path, default) in krates("test_shim") { + rules.doc(&krate.doc_step, path) + .dep(|s| s.name("libtest")) + .default(default && build.config.docs) + .run(move |s| doc::test(build, s.stage, s.target)); + } + for (krate, path, default) in krates("rustc-main") { + rules.doc(&krate.doc_step, path) + .dep(|s| s.name("librustc")) + .host(true) + .default(default && build.config.compiler_docs) + .run(move |s| doc::rustc(build, s.stage, s.target)); + } + + // ======================================================================== + // Distribution targets + rules.dist("dist-rustc", "src/librustc") + .dep(move |s| s.name("rustc").host(&build.config.build)) + .host(true) + .default(true) + .run(move |s| dist::rustc(build, s.stage, s.target)); + rules.dist("dist-std", "src/libstd") + .dep(move |s| { + // We want to package up as many target libraries as possible + // for the `rust-std` package, so if this is a host target we + // depend on librustc and otherwise we just depend on libtest. + if build.config.host.iter().any(|t| t == s.target) { + s.name("librustc") + } else { + s.name("libtest") + } + }) + .default(true) + .run(move |s| dist::std(build, &s.compiler(), s.target)); + rules.dist("dist-mingw", "path/to/nowhere") + .run(move |s| dist::mingw(build, s.target)); + rules.dist("dist-src", "src") + .default(true) + .host(true) + .run(move |_| dist::rust_src(build)); + rules.dist("dist-docs", "src/doc") + .dep(|s| s.name("default:doc")) + .run(move |s| dist::docs(build, s.stage, s.target)); + rules.dist("install", "src") + .dep(|s| s.name("default:dist")) + .run(move |s| install::install(build, s.stage, s.target)); + + rules.verify(); + return rules +} + +struct Rule<'a> { + name: &'a str, + path: &'a str, + kind: Kind, + deps: Vec) -> Step<'a> + 'a>>, + run: Box) + 'a>, + default: bool, + host: bool, +} + +#[derive(PartialEq)] +enum Kind { + Build, + Test, + Dist, + Doc, +} + +impl<'a> Rule<'a> { + fn new(name: &'a str, path: &'a str, kind: Kind) -> Rule<'a> { + Rule { + name: name, + deps: Vec::new(), + run: Box::new(|_| ()), + path: path, + kind: kind, + default: false, + host: false, } } } + +struct RuleBuilder<'a: 'b, 'b> { + rules: &'b mut Rules<'a>, + rule: Rule<'a>, +} + +impl<'a, 'b> RuleBuilder<'a, 'b> { + fn dep(&mut self, f: F) -> &mut Self + where F: Fn(&Step<'a>) -> Step<'a> + 'a, + { + self.rule.deps.push(Box::new(f)); + self + } + + fn run(&mut self, f: F) -> &mut Self + where F: Fn(&Step<'a>) + 'a, + { + self.rule.run = Box::new(f); + self + } + + fn default(&mut self, default: bool) -> &mut Self { + self.rule.default = default; + self + } + + fn host(&mut self, host: bool) -> &mut Self { + self.rule.host = host; + self + } +} + +impl<'a, 'b> Drop for RuleBuilder<'a, 'b> { + fn drop(&mut self) { + let rule = mem::replace(&mut self.rule, Rule::new("", "", Kind::Build)); + let prev = self.rules.rules.insert(rule.name, rule); + if let Some(prev) = prev { + panic!("duplicate rule named: {}", prev.name); + } + } +} + +pub struct Rules<'a> { + build: &'a Build, + sbuild: Step<'a>, + rules: HashMap<&'a str, Rule<'a>>, +} + +impl<'a> Rules<'a> { + fn new(build: &'a Build) -> Rules<'a> { + Rules { + build: build, + sbuild: Step { + stage: build.flags.stage.unwrap_or(2), + target: &build.config.build, + host: &build.config.build, + name: "", + }, + rules: HashMap::new(), + } + } + + fn build<'b>(&'b mut self, name: &'a str, path: &'a str) + -> RuleBuilder<'a, 'b> { + self.rule(name, path, Kind::Build) + } + + fn test<'b>(&'b mut self, name: &'a str, path: &'a str) + -> RuleBuilder<'a, 'b> { + self.rule(name, path, Kind::Test) + } + + fn doc<'b>(&'b mut self, name: &'a str, path: &'a str) + -> RuleBuilder<'a, 'b> { + self.rule(name, path, Kind::Doc) + } + + fn dist<'b>(&'b mut self, name: &'a str, path: &'a str) + -> RuleBuilder<'a, 'b> { + self.rule(name, path, Kind::Dist) + } + + fn rule<'b>(&'b mut self, + name: &'a str, + path: &'a str, + kind: Kind) -> RuleBuilder<'a, 'b> { + RuleBuilder { + rules: self, + rule: Rule::new(name, path, kind), + } + } + + /// Verify the dependency graph defined by all our rules are correct, e.g. + /// everything points to a valid something else. + fn verify(&self) { + for rule in self.rules.values() { + for dep in rule.deps.iter() { + let dep = dep(&self.sbuild.name(rule.name)); + if self.rules.contains_key(&dep.name) || dep.name.starts_with("default:") { + continue } + panic!("\ + +invalid rule dependency graph detected, was a rule added and maybe typo'd? + + `{}` depends on `{}` which does not exist + +", rule.name, dep.name); + } + } + } + + pub fn print_help(&self, command: &str) { + let kind = match command { + "build" => Kind::Build, + "doc" => Kind::Doc, + "test" => Kind::Test, + "dist" => Kind::Dist, + _ => return, + }; + let rules = self.rules.values().filter(|r| r.kind == kind); + let rules = rules.filter(|r| !r.path.contains("nowhere")); + let mut rules = rules.collect::>(); + rules.sort_by_key(|r| r.path); + + println!("Available paths:\n"); + for rule in rules { + print!(" ./x.py {} {}", command, rule.path); + + println!(""); + } + } + + /// Construct the top-level build steps that we're going to be executing, + /// given the subcommand that our build is performing. + fn plan(&self) -> Vec> { + let (kind, paths) = match self.build.flags.cmd { + Subcommand::Build { ref paths } => (Kind::Build, &paths[..]), + Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), + Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]), + Subcommand::Dist { install } => { + if install { + return vec![self.sbuild.name("install")] + } else { + (Kind::Dist, &[][..]) + } + } + Subcommand::Clean => panic!(), + }; + + self.rules.values().filter(|rule| rule.kind == kind).filter(|rule| { + (paths.len() == 0 && rule.default) || paths.iter().any(|path| { + path.ends_with(rule.path) + }) + }).flat_map(|rule| { + let hosts = if self.build.flags.host.len() > 0 { + &self.build.flags.host + } else { + &self.build.config.host + }; + let targets = if self.build.flags.target.len() > 0 { + &self.build.flags.target + } else { + &self.build.config.target + }; + let arr = if rule.host {hosts} else {targets}; + + hosts.iter().flat_map(move |host| { + arr.iter().map(move |target| { + self.sbuild.name(rule.name).target(target).host(host) + }) + }) + }).collect() + } + + /// Execute all top-level targets indicated by `steps`. + /// + /// This will take the list returned by `plan` and then execute each step + /// along with all required dependencies as it goes up the chain. + fn run(&self, steps: &[Step<'a>]) { + self.build.verbose("bootstrap top targets:"); + for step in steps.iter() { + self.build.verbose(&format!("\t{:?}", step)); + } + + // Using `steps` as the top-level targets, make a topological ordering + // of what we need to do. + let mut order = Vec::new(); + let mut added = HashSet::new(); + for step in steps.iter().cloned() { + self.fill(step, &mut order, &mut added); + } + + // Print out what we're doing for debugging + self.build.verbose("bootstrap build plan:"); + for step in order.iter() { + self.build.verbose(&format!("\t{:?}", step)); + } + + // And finally, iterate over everything and execute it. + for step in order.iter() { + self.build.verbose(&format!("executing step {:?}", step)); + (self.rules[step.name].run)(step); + } + } + + fn fill(&self, + step: Step<'a>, + order: &mut Vec>, + added: &mut HashSet>) { + if !added.insert(step.clone()) { + return + } + for dep in self.rules[step.name].deps.iter() { + let dep = dep(&step); + if dep.name.starts_with("default:") { + let kind = match &dep.name[8..] { + "doc" => Kind::Doc, + "dist" => Kind::Dist, + kind => panic!("unknown kind: `{}`", kind), + }; + let rules = self.rules.values().filter(|r| r.default); + for rule in rules.filter(|r| r.kind == kind) { + self.fill(dep.name(rule.name), order, added); + } + } else { + self.fill(dep, order, added); + } + } + order.push(step); + } +} diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 6c0a32a54d91..e028c5223666 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -57,8 +57,7 @@ pub fn cp_r(src: &Path, dst: &Path) { let name = path.file_name().unwrap(); let dst = dst.join(name); if t!(f.file_type()).is_dir() { - let _ = fs::remove_dir_all(&dst); - t!(fs::create_dir(&dst)); + t!(fs::create_dir_all(&dst)); cp_r(&path, &dst); } else { let _ = fs::remove_file(&dst); @@ -172,3 +171,21 @@ pub fn dylib_path() -> Vec { env::split_paths(&env::var_os(dylib_path_var()).unwrap_or(OsString::new())) .collect() } + +/// `push` all components to `buf`. On windows, append `.exe` to the last component. +pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf { + let (&file, components) = components.split_last().expect("at least one component required"); + let mut file = file.to_owned(); + + if cfg!(windows) { + file.push_str(".exe"); + } + + for c in components { + buf.push(c); + } + + buf.push(file); + + buf +} diff --git a/src/compiler-rt b/src/compiler-rt index f03ba5a4e8bf..ecd2b1f6d689 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit f03ba5a4e8bf16dcf42dd742a4ce255c36321356 +Subproject commit ecd2b1f6d689d5afbf5debe8afb3739337323852 diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index b7b67a9f1d09..fa9f66d43baa 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -327,7 +327,7 @@ that takes a reference like so: fn call_with_ref(some_closure:F) -> i32 where F: Fn(&i32) -> i32 { - let mut value = 0; + let value = 0; some_closure(&value) } ``` @@ -340,14 +340,15 @@ fn call_with_ref<'a, F>(some_closure:F) -> i32 where F: Fn(&'a i32) -> i32 { ``` -However this presents a problem in our case. When you specify the explicit -lifetime on a function it binds that lifetime to the *entire* scope of the function -instead of just the invocation scope of our closure. This means that the borrow checker -will see a mutable reference in the same lifetime as our immutable reference and fail -to compile. +However, this presents a problem in our case. When a function has an explicit +lifetime parameter, that lifetime must be at least as long as the *entire* +call to that function. The borrow checker will complain that `value` doesn't +live long enough, because it is only in scope after its declaration inside the +function body. -In order to say that we only need the lifetime to be valid for the invocation scope -of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: +What we need is a closure that can borrow its argument only for its own +invocation scope, not for the outer function's scope. In order to say that, +we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: ```ignore fn call_with_ref(some_closure:F) -> i32 @@ -362,7 +363,7 @@ expect. fn call_with_ref(some_closure:F) -> i32 where F: for<'a> Fn(&'a i32) -> i32 { - let mut value = 0; + let value = 0; some_closure(&value) } ``` diff --git a/src/doc/book/getting-started.md b/src/doc/book/getting-started.md index 5add23592827..2eab449dbd42 100644 --- a/src/doc/book/getting-started.md +++ b/src/doc/book/getting-started.md @@ -4,112 +4,25 @@ This first chapter of the book will get us going with Rust and its tooling. First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally, we’ll talk about Cargo, Rust’s build system and package manager. -# Installing Rust - -The first step to using Rust is to install it. Generally speaking, you’ll need -an Internet connection to run the commands in this section, as we’ll be -downloading Rust from the Internet. - We’ll be showing off a number of commands using a terminal, and those lines all start with `$`. You don't need to type in the `$`s, they are there to indicate the start of each command. We’ll see many tutorials and examples around the web that follow this convention: `$` for commands run as our regular user, and `#` for commands we should be running as an administrator. -## Platform support +# Installing Rust -The Rust compiler runs on, and compiles to, a great number of platforms, though -not all platforms are equally supported. Rust's support levels are organized -into three tiers, each with a different set of guarantees. +The first step to using Rust is to install it. Generally speaking, you’ll need +an Internet connection to run the commands in this section, as we’ll be +downloading Rust from the Internet. -Platforms are identified by their "target triple" which is the string to inform -the compiler what kind of output should be produced. The columns below indicate -whether the corresponding component works on the specified platform. +The Rust compiler runs on, and compiles to, a great number of platforms, but is +best supported on Linux, Mac, and Windows, on the x86 and x86-64 CPU +architecture. There are official builds of the Rust compiler and standard +library for these platforms and more. [For full details on Rust platform support +see the website][platform-support]. -### Tier 1 - -Tier 1 platforms can be thought of as "guaranteed to build and work". -Specifically they will each satisfy the following requirements: - -* Automated testing is set up to run tests for the platform. -* Landing changes to the `rust-lang/rust` repository's master branch is gated on - tests passing. -* Official release artifacts are provided for the platform. -* Documentation for how to use and how to build the platform is available. - -| Target | std |rustc|cargo| notes | -|-------------------------------|-----|-----|-----|----------------------------| -| `i686-apple-darwin` | ✓ | ✓ | ✓ | 32-bit OSX (10.7+, Lion+) | -| `i686-pc-windows-gnu` | ✓ | ✓ | ✓ | 32-bit MinGW (Windows 7+) | -| `i686-pc-windows-msvc` | ✓ | ✓ | ✓ | 32-bit MSVC (Windows 7+) | -| `i686-unknown-linux-gnu` | ✓ | ✓ | ✓ | 32-bit Linux (2.6.18+) | -| `x86_64-apple-darwin` | ✓ | ✓ | ✓ | 64-bit OSX (10.7+, Lion+) | -| `x86_64-pc-windows-gnu` | ✓ | ✓ | ✓ | 64-bit MinGW (Windows 7+) | -| `x86_64-pc-windows-msvc` | ✓ | ✓ | ✓ | 64-bit MSVC (Windows 7+) | -| `x86_64-unknown-linux-gnu` | ✓ | ✓ | ✓ | 64-bit Linux (2.6.18+) | - -### Tier 2 - -Tier 2 platforms can be thought of as "guaranteed to build". Automated tests -are not run so it's not guaranteed to produce a working build, but platforms -often work to quite a good degree and patches are always welcome! Specifically, -these platforms are required to have each of the following: - -* Automated building is set up, but may not be running tests. -* Landing changes to the `rust-lang/rust` repository's master branch is gated on - platforms **building**. Note that this means for some platforms only the - standard library is compiled, but for others the full bootstrap is run. -* Official release artifacts are provided for the platform. - -| Target | std |rustc|cargo| notes | -|-------------------------------|-----|-----|-----|----------------------------| -| `aarch64-apple-ios` | ✓ | | | ARM64 iOS | -| `aarch64-unknown-linux-gnu` | ✓ | ✓ | ✓ | ARM64 Linux (2.6.18+) | -| `arm-linux-androideabi` | ✓ | | | ARM Android | -| `arm-unknown-linux-gnueabi` | ✓ | ✓ | ✓ | ARM Linux (2.6.18+) | -| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | ✓ | ARM Linux (2.6.18+) | -| `armv7-apple-ios` | ✓ | | | ARM iOS | -|`armv7-unknown-linux-gnueabihf`| ✓ | ✓ | ✓ | ARMv7 Linux (2.6.18+) | -| `armv7s-apple-ios` | ✓ | | | ARM iOS | -| `i386-apple-ios` | ✓ | | | 32-bit x86 iOS | -| `i586-pc-windows-msvc` | ✓ | | | 32-bit Windows w/o SSE | -| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) | -| `mips-unknown-linux-musl` | ✓ | | | MIPS Linux with MUSL | -| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) | -| `mipsel-unknown-linux-musl` | ✓ | | | MIPS (LE) Linux with MUSL | -| `powerpc-unknown-linux-gnu` | ✓ | | | PowerPC Linux (2.6.18+) | -| `powerpc64-unknown-linux-gnu` | ✓ | | | PPC64 Linux (2.6.18+) | -|`powerpc64le-unknown-linux-gnu`| ✓ | | | PPC64LE Linux (2.6.18+) | -| `x86_64-apple-ios` | ✓ | | | 64-bit x86 iOS | -| `x86_64-rumprun-netbsd` | ✓ | | | 64-bit NetBSD Rump Kernel | -| `x86_64-unknown-freebsd` | ✓ | ✓ | ✓ | 64-bit FreeBSD | -| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL | -| `x86_64-unknown-netbsd` | ✓ | ✓ | ✓ | 64-bit NetBSD | - -### Tier 3 - -Tier 3 platforms are those which Rust has support for, but landing changes is -not gated on the platform either building or passing tests. Working builds for -these platforms may be spotty as their reliability is often defined in terms of -community contributions. Additionally, release artifacts and installers are not -provided, but there may be community infrastructure producing these in -unofficial locations. - -| Target | std |rustc|cargo| notes | -|-------------------------------|-----|-----|-----|----------------------------| -| `aarch64-linux-android` | ✓ | | | ARM64 Android | -| `armv7-linux-androideabi` | ✓ | | | ARM-v7a Android | -| `i686-linux-android` | ✓ | | | 32-bit x86 Android | -| `i686-pc-windows-msvc` (XP) | ✓ | | | Windows XP support | -| `i686-unknown-freebsd` | ✓ | ✓ | ✓ | 32-bit FreeBSD | -| `x86_64-pc-windows-msvc` (XP) | ✓ | | | Windows XP support | -| `x86_64-sun-solaris` | ✓ | ✓ | | 64-bit Solaris/SunOS | -| `x86_64-unknown-bitrig` | ✓ | ✓ | | 64-bit Bitrig | -| `x86_64-unknown-dragonfly` | ✓ | ✓ | | 64-bit DragonFlyBSD | -| `x86_64-unknown-openbsd` | ✓ | ✓ | | 64-bit OpenBSD | - -Note that this table can be expanded over time, this isn't the exhaustive set of -tier 3 platforms that will ever be! +[platform-support]: https://forge.rust-lang.org/platform-support.html ## Installing on Linux or Mac diff --git a/src/doc/book/guessing-game.md b/src/doc/book/guessing-game.md index a3ab4803bc4d..e2a23979a819 100644 --- a/src/doc/book/guessing-game.md +++ b/src/doc/book/guessing-game.md @@ -19,6 +19,7 @@ has a command that does that for us. Let’s give it a shot: ```bash $ cd ~/projects $ cargo new guessing_game --bin + Created binary (application) `guessing_game` project $ cd guessing_game ``` @@ -51,6 +52,7 @@ Let’s try compiling what Cargo gave us: ```{bash} $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.53 secs ``` Excellent! Open up your `src/main.rs` again. We’ll be writing all of @@ -61,6 +63,7 @@ Remember the `run` command from last chapter? Try it out again here: ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/guessing_game` Hello, world! ``` @@ -282,10 +285,13 @@ we’ll get a warning: ```bash $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) -src/main.rs:10:5: 10:39 warning: unused result which must be used, -#[warn(unused_must_use)] on by default -src/main.rs:10 io::stdin().read_line(&mut guess); - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +warning: unused result which must be used, #[warn(unused_must_use)] on by default + --> src/main.rs:10:5 + | +10 | io::stdin().read_line(&mut guess); + | ^ + + Finished debug [unoptimized + debuginfo] target(s) in 0.42 secs ``` Rust warns us that we haven’t used the `Result` value. This warning comes from @@ -321,6 +327,7 @@ Anyway, that’s the tour. We can run what we have with `cargo run`: ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.44 secs Running `target/debug/guessing_game` Guess the number! Please input your guess. @@ -373,11 +380,12 @@ Now, without changing any of our code, let’s build our project: ```bash $ cargo build Updating registry `https://github.com/rust-lang/crates.io-index` - Downloading rand v0.3.8 - Downloading libc v0.1.6 - Compiling libc v0.1.6 - Compiling rand v0.3.8 + Downloading rand v0.3.14 + Downloading libc v0.2.17 + Compiling libc v0.2.17 + Compiling rand v0.3.14 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 5.88 secs ``` (You may see different versions, of course.) @@ -399,22 +407,24 @@ If we run `cargo build` again, we’ll get different output: ```bash $ cargo build + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs ``` -That’s right, no output! Cargo knows that our project has been built, and that +That’s right, nothing was done! Cargo knows that our project has been built, and that all of its dependencies are built, and so there’s no reason to do all that stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again, -make a trivial change, and then save it again, we’ll only see one line: +make a trivial change, and then save it again, we’ll only see two lines: ```bash $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.45 secs ``` So, we told Cargo we wanted any `0.3.x` version of `rand`, and so it fetched the latest -version at the time this was written, `v0.3.8`. But what happens when next -week, version `v0.3.9` comes out, with an important bugfix? While getting -bugfixes is important, what if `0.3.9` contains a regression that breaks our +version at the time this was written, `v0.3.14`. But what happens when next +week, version `v0.3.15` comes out, with an important bugfix? While getting +bugfixes is important, what if `0.3.15` contains a regression that breaks our code? The answer to this problem is the `Cargo.lock` file you’ll now find in your @@ -423,11 +433,11 @@ figures out all of the versions that fit your criteria, and then writes them to the `Cargo.lock` file. When you build your project in the future, Cargo will see that the `Cargo.lock` file exists, and then use that specific version rather than do all the work of figuring out versions again. This lets you -have a repeatable build automatically. In other words, we’ll stay at `0.3.8` +have a repeatable build automatically. In other words, we’ll stay at `0.3.14` until we explicitly upgrade, and so will anyone who we share our code with, thanks to the lock file. -What about when we _do_ want to use `v0.3.9`? Cargo has another command, +What about when we _do_ want to use `v0.3.15`? Cargo has another command, `update`, which says ‘ignore the lock, figure out all the latest versions that fit what we’ve specified. If that works, write those versions out to the lock file’. But, by default, Cargo will only look for versions larger than `0.3.0` @@ -510,6 +520,7 @@ Try running our new program a few times: ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.55 secs Running `target/debug/guessing_game` Guess the number! The secret number is: 7 @@ -517,6 +528,7 @@ Please input your guess. 4 You guessed: 4 $ cargo run + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/guessing_game` Guess the number! The secret number is: 83 @@ -618,15 +630,20 @@ I did mention that this won’t quite compile yet, though. Let’s try it: ```bash $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) -src/main.rs:28:21: 28:35 error: mismatched types: - expected `&collections::string::String`, - found `&_` -(expected struct `collections::string::String`, - found integral variable) [E0308] -src/main.rs:28 match guess.cmp(&secret_number) { - ^~~~~~~~~~~~~~ +error[E0308]: mismatched types + --> src/main.rs:23:21 + | +23 | match guess.cmp(&secret_number) { + | ^^^^^^^^^^^^^^ expected struct `std::string::String`, found integral variable + | + = note: expected type `&std::string::String` + = note: found type `&{integer}` + error: aborting due to previous error -Could not compile `guessing_game`. + +error: Could not compile `guessing_game`. + +To learn more, run the command again with --verbose. ``` Whew! This is a big error. The core of it is that we have ‘mismatched types’. @@ -722,6 +739,7 @@ Let’s try our program out! ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs Running `target/guessing_game` Guess the number! The secret number is: 58 @@ -785,6 +803,7 @@ and quit. Observe: ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.58 secs Running `target/guessing_game` Guess the number! The secret number is: 59 @@ -919,6 +938,7 @@ Now we should be good! Let’s try: ```bash $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs Running `target/guessing_game` Guess the number! The secret number is: 61 diff --git a/src/doc/book/structs.md b/src/doc/book/structs.md index 328db25b819d..d6960b10b080 100644 --- a/src/doc/book/structs.md +++ b/src/doc/book/structs.md @@ -61,7 +61,7 @@ write something like this: ```rust,ignore struct Point { - mut x: i32, + mut x: i32, // This causes an error. y: i32, } ``` diff --git a/src/doc/book/syntax-index.md b/src/doc/book/syntax-index.md index 1e05b01d30d4..28403711cd70 100644 --- a/src/doc/book/syntax-index.md +++ b/src/doc/book/syntax-index.md @@ -94,6 +94,7 @@ * `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`). * `||` (`expr || expr`): logical or. * `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]). +* `?` (`expr?`): Error propagation. Returns early when `Err(_)` is encountered, unwraps otherwise. Similar to the [`try!` macro]. ## Other Syntax @@ -210,6 +211,7 @@ [Functions]: functions.html [Generics]: generics.html [Iterators]: iterators.html +[`try!` macro]: error-handling.html#the-try-macro [Lifetimes]: lifetimes.html [Loops (`for`)]: loops.html#for [Loops (`loop`)]: loops.html#loop diff --git a/src/doc/reference.md b/src/doc/reference.md index 4838ecd2d42e..0596e476d5f6 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -21,6 +21,11 @@ separately by extracting documentation attributes from their source code. Many of the features that one might expect to be language features are library features in Rust, so what you're looking for may be there, not here. +Finally, this document is not normative. It may include details that are +specific to `rustc` itself, and should not be taken as a specification for +the Rust language. We intend to produce such a document someday, but this +is what we have for now. + You may also be interested in the [grammar]. [book]: book/index.html @@ -2479,8 +2484,6 @@ The currently implemented features of the reference compiler are: * - `abi_vectorcall` - Allows the usage of the vectorcall calling convention (e.g. `extern "vectorcall" func fn_();`) -* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns. - * - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention (e.g. `extern "sysv64" func fn_();`) @@ -2860,8 +2863,8 @@ assert_eq!(x, y); ### Unary operator expressions -Rust defines the following unary operators. They are all written as prefix operators, -before the expression they apply to. +Rust defines the following unary operators. With the exception of `?`, they are +all written as prefix operators, before the expression they apply to. * `-` : Negation. Signed integer types and floating-point types support negation. It @@ -2890,6 +2893,10 @@ before the expression they apply to. If the `&` or `&mut` operators are applied to an rvalue, a temporary value is created; the lifetime of this temporary value is defined by [syntactic rules](#temporary-lifetimes). +* `?` + : Propagating errors if applied to `Err(_)` and unwrapping if + applied to `Ok(_)`. Only works on the `Result` type, + and written in postfix notation. ### Binary operator expressions @@ -3755,6 +3762,21 @@ The special type `Self` has a meaning within traits and impls. In a trait defini to an implicit type parameter representing the "implementing" type. In an impl, it is an alias for the implementing type. For example, in: +``` +pub trait From { + fn from(T) -> Self; +} + +impl From for String { + fn from(x: i32) -> Self { + x.to_string() + } +} +``` + +The notation `Self` in the impl refers to the implementing type: `String`. In another +example: + ``` trait Printable { fn make_string(&self) -> String; diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 7a07e007ce1c..3a7da18c8deb 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -36,6 +36,10 @@ use core::{isize, usize}; use core::convert::From; use heap::deallocate; +/// A soft limit on the amount of references that may be made to an `Arc`. +/// +/// Going above this limit will abort your program (although not +/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// A thread-safe reference-counting pointer. @@ -270,6 +274,68 @@ impl Arc { Ok(elem) } } + + /// Consumes the `Arc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Arc` using + /// [`Arc::from_raw`][from_raw]. + /// + /// [from_raw]: struct.Arc.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_raw)] + /// + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let x_ptr = Arc::into_raw(x); + /// assert_eq!(unsafe { *x_ptr }, 10); + /// ``` + #[unstable(feature = "rc_raw", issue = "37197")] + pub fn into_raw(this: Self) -> *mut T { + let ptr = unsafe { &mut (**this.ptr).data as *mut _ }; + mem::forget(this); + ptr + } + + /// Constructs an `Arc` from a raw pointer. + /// + /// The raw pointer must have been previously returned by a call to a + /// [`Arc::into_raw`][into_raw]. + /// + /// This function is unsafe because improper use may lead to memory problems. For example, a + /// double-free may occur if the function is called twice on the same raw pointer. + /// + /// [into_raw]: struct.Arc.html#method.into_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_raw)] + /// + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let x_ptr = Arc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Arc` to prevent leak. + /// let x = Arc::from_raw(x_ptr); + /// assert_eq!(*x, 10); + /// + /// // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + #[unstable(feature = "rc_raw", issue = "37197")] + pub unsafe fn from_raw(ptr: *mut T) -> Self { + // To find the corresponding pointer to the `ArcInner` we need to subtract the offset of the + // `data` field from the pointer. + Arc { ptr: Shared::new((ptr as *mut u8).offset(-offset_of!(ArcInner, data)) as *mut _) } + } } impl Arc { @@ -315,11 +381,14 @@ impl Arc { /// Gets the number of [`Weak`][weak] pointers to this value. /// - /// Be careful how you use this information, because another thread - /// may change the weak count at any time. - /// /// [weak]: struct.Weak.html /// + /// # Safety + /// + /// This method by itself is safe, but using it correctly requires extra care. + /// Another thread can change the weak count at any time, + /// including potentially between calling this method and acting on the result. + /// /// # Examples /// /// ``` @@ -343,8 +412,11 @@ impl Arc { /// Gets the number of strong (`Arc`) pointers to this value. /// - /// Be careful how you use this information, because another thread - /// may change the strong count at any time. + /// # Safety + /// + /// This method by itself is safe, but using it correctly requires extra care. + /// Another thread can change the strong count at any time, + /// including potentially between calling this method and acting on the result. /// /// # Examples /// @@ -1179,6 +1251,23 @@ mod tests { assert_eq!(Arc::try_unwrap(x), Ok(5)); } + #[test] + fn into_from_raw() { + let x = Arc::new(box "hello"); + let y = x.clone(); + + let x_ptr = Arc::into_raw(x); + drop(y); + unsafe { + assert_eq!(**x_ptr, "hello"); + + let x = Arc::from_raw(x_ptr); + assert_eq!(**x, "hello"); + + assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); + } + } + #[test] fn test_cowarc_clone_make_mut() { let mut cow0 = Arc::new(75); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 31491106d97e..0d450184ed87 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -99,6 +99,10 @@ #[macro_use] extern crate std; +// Module with internal macros used by other modules (needs to be included before other modules). +#[macro_use] +mod macros; + // Heaps provided for low-level allocation strategies pub mod heap; diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs new file mode 100644 index 000000000000..7da91c87e967 --- /dev/null +++ b/src/liballoc/macros.rs @@ -0,0 +1,28 @@ +// Copyright 2013-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. + +// Private macro to get the offset of a struct field in bytes from the address of the struct. +macro_rules! offset_of { + ($container:path, $field:ident) => {{ + // Make sure the field actually exists. This line ensures that a compile-time error is + // generated if $field is accessed through a Deref impl. + let $container { $field : _, .. }; + + // Create an (invalid) instance of the container and calculate the offset to its + // field. Using a null pointer might be UB if `&(*(0 as *const T)).field` is interpreted to + // be nullptr deref. + let invalid: $container = ::core::mem::uninitialized(); + let offset = &invalid.$field as *const _ as usize - &invalid as *const _ as usize; + + // Do not run destructors on the made up invalid instance. + ::core::mem::forget(invalid); + offset as isize + }}; +} diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 740d13c47622..8d863d7d9e91 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -364,6 +364,68 @@ impl Rc { pub fn would_unwrap(this: &Self) -> bool { Rc::strong_count(&this) == 1 } + + /// Consumes the `Rc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Rc` using + /// [`Rc::from_raw`][from_raw]. + /// + /// [from_raw]: struct.Rc.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_raw)] + /// + /// use std::rc::Rc; + /// + /// let x = Rc::new(10); + /// let x_ptr = Rc::into_raw(x); + /// assert_eq!(unsafe { *x_ptr }, 10); + /// ``` + #[unstable(feature = "rc_raw", issue = "37197")] + pub fn into_raw(this: Self) -> *mut T { + let ptr = unsafe { &mut (**this.ptr).value as *mut _ }; + mem::forget(this); + ptr + } + + /// Constructs an `Rc` from a raw pointer. + /// + /// The raw pointer must have been previously returned by a call to a + /// [`Rc::into_raw`][into_raw]. + /// + /// This function is unsafe because improper use may lead to memory problems. For example, a + /// double-free may occur if the function is called twice on the same raw pointer. + /// + /// [into_raw]: struct.Rc.html#method.into_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_raw)] + /// + /// use std::rc::Rc; + /// + /// let x = Rc::new(10); + /// let x_ptr = Rc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Rc` to prevent leak. + /// let x = Rc::from_raw(x_ptr); + /// assert_eq!(*x, 10); + /// + /// // Further calls to `Rc::from_raw(x_ptr)` would be memory unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + #[unstable(feature = "rc_raw", issue = "37197")] + pub unsafe fn from_raw(ptr: *mut T) -> Self { + // To find the corresponding pointer to the `RcBox` we need to subtract the offset of the + // `value` field from the pointer. + Rc { ptr: Shared::new((ptr as *mut u8).offset(-offset_of!(RcBox, value)) as *mut _) } + } } impl Rc { @@ -1287,6 +1349,23 @@ mod tests { assert_eq!(Rc::try_unwrap(x), Ok(5)); } + #[test] + fn into_from_raw() { + let x = Rc::new(box "hello"); + let y = x.clone(); + + let x_ptr = Rc::into_raw(x); + drop(y); + unsafe { + assert_eq!(**x_ptr, "hello"); + + let x = Rc::from_raw(x_ptr); + assert_eq!(**x, "hello"); + + assert_eq!(Rc::try_unwrap(x).map(|x| *x), Ok("hello")); + } + } + #[test] fn get_mut() { let mut x = Rc::new(3); diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 8f9c35783379..37618b7600a0 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -17,6 +17,7 @@ use core::hash::{Hash, Hasher}; use core::ops::{Add, AddAssign, Deref}; use fmt; +use string::String; use self::Cow::*; @@ -159,7 +160,10 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned { match *self { Borrowed(borrowed) => { *self = Owned(borrowed.to_owned()); - self.to_mut() + match *self { + Borrowed(..) => unreachable!(), + Owned(ref mut owned) => owned, + } } Owned(ref mut owned) => owned, } @@ -284,48 +288,60 @@ impl<'a, T: ?Sized + ToOwned> AsRef for Cow<'a, T> { } } -#[stable(feature = "cow_add", since = "1.13.0")] +#[stable(feature = "cow_add", since = "1.14.0")] impl<'a> Add<&'a str> for Cow<'a, str> { type Output = Cow<'a, str>; - fn add(self, rhs: &'a str) -> Self { - if self == "" { - Cow::Borrowed(rhs) - } else if rhs == "" { - self - } else { - Cow::Owned(self.into_owned() + rhs) - } + #[inline] + fn add(mut self, rhs: &'a str) -> Self::Output { + self += rhs; + self } } -#[stable(feature = "cow_add", since = "1.13.0")] +#[stable(feature = "cow_add", since = "1.14.0")] impl<'a> Add> for Cow<'a, str> { type Output = Cow<'a, str>; - fn add(self, rhs: Cow<'a, str>) -> Self { - if self == "" { - rhs - } else if rhs == "" { - self + #[inline] + fn add(mut self, rhs: Cow<'a, str>) -> Self::Output { + self += rhs; + self + } +} + +#[stable(feature = "cow_add", since = "1.14.0")] +impl<'a> AddAssign<&'a str> for Cow<'a, str> { + fn add_assign(&mut self, rhs: &'a str) { + if self.is_empty() { + *self = Cow::Borrowed(rhs) + } else if rhs.is_empty() { + return; } else { - Cow::Owned(self.into_owned() + rhs.borrow()) + if let Cow::Borrowed(lhs) = *self { + let mut s = String::with_capacity(lhs.len() + rhs.len()); + s.push_str(lhs); + *self = Cow::Owned(s); + } + self.to_mut().push_str(rhs); } } } -#[stable(feature = "cow_add", since = "1.13.0")] -impl<'a> AddAssign<&'a str> for Cow<'a, str> { - fn add_assign(&mut self, rhs: &'a str) { - if rhs == "" { return; } - self.to_mut().push_str(rhs); - } -} - -#[stable(feature = "cow_add", since = "1.13.0")] +#[stable(feature = "cow_add", since = "1.14.0")] impl<'a> AddAssign> for Cow<'a, str> { fn add_assign(&mut self, rhs: Cow<'a, str>) { - if rhs == "" { return; } - self.to_mut().push_str(rhs.borrow()); + if self.is_empty() { + *self = rhs + } else if rhs.is_empty() { + return; + } else { + if let Cow::Borrowed(lhs) = *self { + let mut s = String::with_capacity(lhs.len() + rhs.len()); + s.push_str(lhs); + *self = Cow::Owned(s); + } + self.to_mut().push_str(&rhs); + } } } diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 990de541b678..23d6edd6d794 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -50,6 +50,7 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(step_by)] +#![feature(trusted_len)] #![feature(unicode)] #![feature(unique)] #![cfg_attr(test, feature(rand, test))] diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 286f06b6fe32..348eb6fb5ffa 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1904,10 +1904,10 @@ impl<'a> FromIterator for Cow<'a, str> { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Into> for String { - fn into(self) -> Vec { - self.into_bytes() +#[stable(feature = "from_string_for_vec_u8", since = "1.14.0")] +impl From for Vec { + fn from(string : String) -> Vec { + string.into_bytes() } } diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index d94a27917e86..71c49ee616cb 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -75,7 +75,7 @@ use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; use core::intrinsics::{arith_offset, assume}; -use core::iter::{FromIterator, FusedIterator}; +use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::mem; use core::ops::{Index, IndexMut}; use core::ops; @@ -83,7 +83,6 @@ use core::ptr; use core::ptr::Shared; use core::slice; -use super::SpecExtend; use super::range::RangeArgument; /// A contiguous growable array type, written `Vec` but pronounced 'vector'. @@ -1245,26 +1244,7 @@ impl Vec { /// ``` #[stable(feature = "vec_extend_from_slice", since = "1.6.0")] pub fn extend_from_slice(&mut self, other: &[T]) { - self.reserve(other.len()); - - // Unsafe code so this can be optimised to a memcpy (or something - // similarly fast) when T is Copy. LLVM is easily confused, so any - // extra operations during the loop can prevent this optimisation. - unsafe { - let len = self.len(); - let ptr = self.get_unchecked_mut(len) as *mut T; - // Use SetLenOnDrop to work around bug where compiler - // may not realize the store through `ptr` trough self.set_len() - // don't alias. - let mut local_len = SetLenOnDrop::new(&mut self.len); - - for i in 0..other.len() { - ptr::write(ptr.offset(i as isize), other.get_unchecked(i).clone()); - local_len.increment_len(1); - } - - // len set by scope guard - } + self.extend(other.iter().cloned()) } } @@ -1606,19 +1586,25 @@ impl<'a, T> IntoIterator for &'a mut Vec { impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { - >::spec_extend(self, iter); - } -} - -impl SpecExtend for Vec { - default fn spec_extend(&mut self, iter: I) { self.extend_desugared(iter.into_iter()) } } -impl SpecExtend> for Vec { - fn spec_extend(&mut self, ref mut other: Vec) { - self.append(other); +trait IsTrustedLen : Iterator { + fn trusted_len(&self) -> Option { None } +} +impl IsTrustedLen for I where I: Iterator { } + +impl IsTrustedLen for I where I: TrustedLen +{ + fn trusted_len(&self) -> Option { + let (low, high) = self.size_hint(); + if let Some(high_value) = high { + debug_assert_eq!(low, high_value, + "TrustedLen iterator's size hint is not exact: {:?}", + (low, high)); + } + high } } @@ -1629,16 +1615,30 @@ impl Vec { // for item in iterator { // self.push(item); // } - while let Some(element) = iterator.next() { - let len = self.len(); - if len == self.capacity() { - let (lower, _) = iterator.size_hint(); - self.reserve(lower.saturating_add(1)); - } + if let Some(additional) = iterator.trusted_len() { + self.reserve(additional); unsafe { - ptr::write(self.get_unchecked_mut(len), element); - // NB can't overflow since we would have had to alloc the address space - self.set_len(len + 1); + let mut ptr = self.as_mut_ptr().offset(self.len() as isize); + let mut local_len = SetLenOnDrop::new(&mut self.len); + for element in iterator { + ptr::write(ptr, element); + ptr = ptr.offset(1); + // NB can't overflow since we would have had to alloc the address space + local_len.increment_len(1); + } + } + } else { + while let Some(element) = iterator.next() { + let len = self.len(); + if len == self.capacity() { + let (lower, _) = iterator.size_hint(); + self.reserve(lower.saturating_add(1)); + } + unsafe { + ptr::write(self.get_unchecked_mut(len), element); + // NB can't overflow since we would have had to alloc the address space + self.set_len(len + 1); + } } } } @@ -1647,24 +1647,7 @@ impl Vec { #[stable(feature = "extend_ref", since = "1.2.0")] impl<'a, T: 'a + Copy> Extend<&'a T> for Vec { fn extend>(&mut self, iter: I) { - >::extend_vec(iter, self); - } -} - -// helper trait for specialization of Vec's Extend impl -trait SpecExtendVec { - fn extend_vec(self, vec: &mut Vec); -} - -impl <'a, T: 'a + Copy, I: IntoIterator> SpecExtendVec for I { - default fn extend_vec(self, vec: &mut Vec) { - vec.extend(self.into_iter().cloned()); - } -} - -impl<'a, T: Copy> SpecExtendVec for &'a [T] { - fn extend_vec(self, vec: &mut Vec) { - vec.extend_from_slice(self); + self.extend(iter.into_iter().map(|&x| x)) } } @@ -1988,6 +1971,9 @@ impl ExactSizeIterator for IntoIter {} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IntoIter {} + #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] impl Clone for IntoIter { fn clone(&self) -> IntoIter { diff --git a/src/libcollectionstest/cow_str.rs b/src/libcollectionstest/cow_str.rs index 82533ba07754..b29245121daa 100644 --- a/src/libcollectionstest/cow_str.rs +++ b/src/libcollectionstest/cow_str.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2013-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -12,54 +12,130 @@ use std::borrow::Cow; // check that Cow<'a, str> implements addition #[test] -fn check_cow_add() { - borrowed1 = Cow::Borrowed("Hello, "); - borrowed2 = Cow::Borrowed("World!"); - borrow_empty = Cow::Borrowed(""); +fn check_cow_add_cow() { + let borrowed1 = Cow::Borrowed("Hello, "); + let borrowed2 = Cow::Borrowed("World!"); + let borrow_empty = Cow::Borrowed(""); - owned1 = Cow::Owned("Hi, ".into()); - owned2 = Cow::Owned("Rustaceans!".into()); - owned_empty = Cow::Owned("".into()); + let owned1: Cow = Cow::Owned(String::from("Hi, ")); + let owned2: Cow = Cow::Owned(String::from("Rustaceans!")); + let owned_empty: Cow = Cow::Owned(String::new()); - assert_eq!("Hello, World!", borrowed1 + borrowed2); - assert_eq!("Hello, Rustaceans!", borrowed1 + owned2); + assert_eq!("Hello, World!", borrowed1.clone() + borrowed2.clone()); + assert_eq!("Hello, Rustaceans!", borrowed1.clone() + owned2.clone()); - assert_eq!("Hello, World!", owned1 + borrowed2); - assert_eq!("Hello, Rustaceans!", owned1 + owned2); + assert_eq!("Hi, World!", owned1.clone() + borrowed2.clone()); + assert_eq!("Hi, Rustaceans!", owned1.clone() + owned2.clone()); - if let Cow::Owned(_) = borrowed1 + borrow_empty { + if let Cow::Owned(_) = borrowed1.clone() + borrow_empty.clone() { panic!("Adding empty strings to a borrow should note allocate"); } - if let Cow::Owned(_) = borrow_empty + borrowed1 { + if let Cow::Owned(_) = borrow_empty.clone() + borrowed1.clone() { panic!("Adding empty strings to a borrow should note allocate"); } - if let Cow::Owned(_) = borrowed1 + owned_empty { + if let Cow::Owned(_) = borrowed1.clone() + owned_empty.clone() { panic!("Adding empty strings to a borrow should note allocate"); } - if let Cow::Owned(_) = owned_empty + borrowed1 { + if let Cow::Owned(_) = owned_empty.clone() + borrowed1.clone() { panic!("Adding empty strings to a borrow should note allocate"); } } -fn check_cow_add_assign() { - borrowed1 = Cow::Borrowed("Hello, "); - borrowed2 = Cow::Borrowed("World!"); - borrow_empty = Cow::Borrowed(""); +#[test] +fn check_cow_add_str() { + let borrowed = Cow::Borrowed("Hello, "); + let borrow_empty = Cow::Borrowed(""); - owned1 = Cow::Owned("Hi, ".into()); - owned2 = Cow::Owned("Rustaceans!".into()); - owned_empty = Cow::Owned("".into()); + let owned: Cow = Cow::Owned(String::from("Hi, ")); + let owned_empty: Cow = Cow::Owned(String::new()); - let borrowed1clone = borrowed1.clone(); - borrowed1clone += borrow_empty; - assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr()); + assert_eq!("Hello, World!", borrowed.clone() + "World!"); - borrowed1clone += owned_empty; - assert_eq!((&borrowed1clone).as_ptr(), (&borrowed1).as_ptr()); + assert_eq!("Hi, World!", owned.clone() + "World!"); + + if let Cow::Owned(_) = borrowed.clone() + "" { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = borrow_empty.clone() + "Hello, " { + panic!("Adding empty strings to a borrow should note allocate"); + } + if let Cow::Owned(_) = owned_empty.clone() + "Hello, " { + panic!("Adding empty strings to a borrow should note allocate"); + } +} + +#[test] +fn check_cow_add_assign_cow() { + let mut borrowed1 = Cow::Borrowed("Hello, "); + let borrowed2 = Cow::Borrowed("World!"); + let borrow_empty = Cow::Borrowed(""); + + let mut owned1: Cow = Cow::Owned(String::from("Hi, ")); + let owned2: Cow = Cow::Owned(String::from("Rustaceans!")); + let owned_empty: Cow = Cow::Owned(String::new()); + + let mut s = borrowed1.clone(); + s += borrow_empty.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrow_empty.clone(); + s += borrowed1.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrowed1.clone(); + s += owned_empty.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = owned_empty.clone(); + s += borrowed1.clone(); + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } owned1 += borrowed2; borrowed1 += owned2; - assert_eq!("Hello, World!", owned1); + assert_eq!("Hi, World!", owned1); assert_eq!("Hello, Rustaceans!", borrowed1); } + +#[test] +fn check_cow_add_assign_str() { + let mut borrowed = Cow::Borrowed("Hello, "); + let borrow_empty = Cow::Borrowed(""); + + let mut owned: Cow = Cow::Owned(String::from("Hi, ")); + let owned_empty: Cow = Cow::Owned(String::new()); + + let mut s = borrowed.clone(); + s += ""; + assert_eq!("Hello, ", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = borrow_empty.clone(); + s += "World!"; + assert_eq!("World!", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = owned_empty.clone(); + s += "World!"; + assert_eq!("World!", s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + + owned += "World!"; + borrowed += "World!"; + + assert_eq!("Hi, World!", owned); + assert_eq!("Hello, World!", borrowed); +} diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 5d3e03c2dee3..14ec8d58bef6 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -42,6 +42,7 @@ mod bench; mod binary_heap; mod btree; +mod cow_str; mod enum_set; mod fmt; mod linked_list; diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 6b3ab64dfd88..5f5d07b66823 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -24,7 +24,8 @@ use mem; /// /// See: https://131002.net/siphash/ #[unstable(feature = "sip_hash_13", issue = "34767")] -#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] +#[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] pub struct SipHasher13 { hasher: Hasher, @@ -34,7 +35,8 @@ pub struct SipHasher13 { /// /// See: https://131002.net/siphash/ #[unstable(feature = "sip_hash_13", issue = "34767")] -#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] +#[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] pub struct SipHasher24 { hasher: Hasher, @@ -53,7 +55,8 @@ pub struct SipHasher24 { /// it is not intended for cryptographic purposes. As such, all /// cryptographic uses of this implementation are _strongly discouraged_. #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] +#[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] #[derive(Debug, Clone, Default)] pub struct SipHasher(SipHasher24); @@ -140,7 +143,8 @@ impl SipHasher { /// Creates a new `SipHasher` with the two initial keys set to 0. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher { SipHasher::new_with_keys(0, 0) } @@ -148,7 +152,8 @@ impl SipHasher { /// Creates a `SipHasher` that is keyed off the provided keys. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { SipHasher(SipHasher24::new_with_keys(key0, key1)) } @@ -158,7 +163,8 @@ impl SipHasher13 { /// Creates a new `SipHasher13` with the two initial keys set to 0. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher13 { SipHasher13::new_with_keys(0, 0) } @@ -166,7 +172,8 @@ impl SipHasher13 { /// Creates a `SipHasher13` that is keyed off the provided keys. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) @@ -178,7 +185,8 @@ impl SipHasher24 { /// Creates a new `SipHasher24` with the two initial keys set to 0. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new() -> SipHasher24 { SipHasher24::new_with_keys(0, 0) } @@ -186,7 +194,8 @@ impl SipHasher24 { /// Creates a `SipHasher24` that is keyed off the provided keys. #[inline] #[unstable(feature = "sip_hash_13", issue = "34767")] - #[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")] + #[rustc_deprecated(since = "1.13.0", + reason = "use `std::collections::hash_map::DefaultHasher` instead")] pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 { SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs new file mode 100644 index 000000000000..f2cdc9d6a98c --- /dev/null +++ b/src/libcore/internal_macros.rs @@ -0,0 +1,62 @@ +// 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. + + +// implements the unary operator "op &T" +// based on "op T" where T is expected to be `Copy`able +macro_rules! forward_ref_unop { + (impl $imp:ident, $method:ident for $t:ty) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a> $imp for &'a $t { + type Output = <$t as $imp>::Output; + + #[inline] + fn $method(self) -> <$t as $imp>::Output { + $imp::$method(*self) + } + } + } +} + +// implements binary operators "&T op U", "T op &U", "&T op &U" +// based on "T op U" where T and U are expected to be `Copy`able +macro_rules! forward_ref_binop { + (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a> $imp<$u> for &'a $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: $u) -> <$t as $imp<$u>>::Output { + $imp::$method(*self, other) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a> $imp<&'a $u> for $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { + $imp::$method(self, *other) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b> $imp<&'a $u> for &'b $t { + type Output = <$t as $imp<$u>>::Output; + + #[inline] + fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { + $imp::$method(*self, *other) + } + } + } +} diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 5a12f5db19dd..f6b74a91c193 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -35,11 +35,14 @@ pub trait Iterator { /// Advances the iterator and returns the next value. /// - /// Returns `None` when iteration is finished. Individual iterator + /// Returns [`None`] when iteration is finished. Individual iterator /// implementations may choose to resume iteration, and so calling `next()` - /// again may or may not eventually start returning `Some(Item)` again at some + /// again may or may not eventually start returning [`Some(Item)`] again at some /// point. /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`Some(Item)`]: ../../std/option/enum.Option.html#variant.Some + /// /// # Examples /// /// Basic usage: @@ -69,9 +72,9 @@ pub trait Iterator { /// Specifically, `size_hint()` returns a tuple where the first element /// is the lower bound, and the second element is the upper bound. /// - /// The second half of the tuple that is returned is an `Option`. A - /// `None` here means that either there is no known upper bound, or the - /// upper bound is larger than `usize`. + /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`. + /// A [`None`] here means that either there is no known upper bound, or the + /// upper bound is larger than [`usize`]. /// /// # Implementation notes /// @@ -91,6 +94,10 @@ pub trait Iterator { /// The default implementation returns `(0, None)` which is correct for any /// iterator. /// + /// [`usize`]: ../../std/primitive.usize.html + /// [`Option`]: ../../std/option/enum.Option.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// Basic usage: @@ -134,23 +141,26 @@ pub trait Iterator { /// Consumes the iterator, counting the number of iterations and returning it. /// /// This method will evaluate the iterator until its [`next()`] returns - /// `None`. Once `None` is encountered, `count()` returns the number of + /// [`None`]. Once [`None`] is encountered, `count()` returns the number of /// times it called [`next()`]. /// /// [`next()`]: #tymethod.next + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Overflow Behavior /// /// The method does no guarding against overflows, so counting elements of - /// an iterator with more than `usize::MAX` elements either produces the + /// an iterator with more than [`usize::MAX`] elements either produces the /// wrong result or panics. If debug assertions are enabled, a panic is /// guaranteed. /// /// # Panics /// - /// This function might panic if the iterator has more than `usize::MAX` + /// This function might panic if the iterator has more than [`usize::MAX`] /// elements. /// + /// [`usize::MAX`]: ../../std/isize/constant.MAX.html + /// /// # Examples /// /// Basic usage: @@ -172,10 +182,12 @@ pub trait Iterator { /// Consumes the iterator, returning the last element. /// - /// This method will evaluate the iterator until it returns `None`. While - /// doing so, it keeps track of the current element. After `None` is + /// This method will evaluate the iterator until it returns [`None`]. While + /// doing so, it keeps track of the current element. After [`None`] is /// returned, `last()` will then return the last element it saw. /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// Basic usage: @@ -202,9 +214,11 @@ pub trait Iterator { /// Like most indexing operations, the count starts from zero, so `nth(0)` /// returns the first value, `nth(1)` the second, and so on. /// - /// `nth()` will return `None` if `n` is greater than or equal to the length of the + /// `nth()` will return [`None`] if `n` is greater than or equal to the length of the /// iterator. /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// Basic usage: @@ -306,8 +320,8 @@ pub trait Iterator { /// /// In other words, it zips two iterators together, into a single one. /// - /// When either iterator returns `None`, all further calls to `next()` - /// will return `None`. + /// When either iterator returns [`None`], all further calls to [`next()`] + /// will return [`None`]. /// /// # Examples /// @@ -346,7 +360,7 @@ pub trait Iterator { /// ``` /// /// `zip()` is often used to zip an infinite iterator to a finite one. - /// This works because the finite iterator will eventually return `None`, + /// This works because the finite iterator will eventually return [`None`], /// ending the zipper. Zipping with `(0..)` can look a lot like [`enumerate()`]: /// /// ``` @@ -365,6 +379,8 @@ pub trait Iterator { /// ``` /// /// [`enumerate()`]: trait.Iterator.html#method.enumerate + /// [`next()`]: ../../std/iter/trait.Iterator.html#tymethod.next + /// [`None`]: ../../std/option/enum.Option.html#variant.None #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn zip(self, other: U) -> Zip where @@ -501,11 +517,9 @@ pub trait Iterator { /// /// The closure must return an [`Option`]. `filter_map()` creates an /// iterator which calls this closure on each element. If the closure - /// returns `Some(element)`, then that element is returned. If the - /// closure returns `None`, it will try again, and call the closure on the - /// next element, seeing if it will return `Some`. - /// - /// [`Option`]: ../../std/option/enum.Option.html + /// returns [`Some(element)`][`Some`], then that element is returned. If the + /// closure returns [`None`], it will try again, and call the closure on the + /// next element, seeing if it will return [`Some`]. /// /// Why `filter_map()` and not just [`filter()`].[`map()`]? The key is in this /// part: @@ -513,11 +527,11 @@ pub trait Iterator { /// [`filter()`]: #method.filter /// [`map()`]: #method.map /// - /// > If the closure returns `Some(element)`, then that element is returned. + /// > If the closure returns [`Some(element)`][`Some`], then that element is returned. /// /// In other words, it removes the [`Option`] layer automatically. If your /// mapping is already returning an [`Option`] and you want to skip over - /// `None`s, then `filter_map()` is much, much nicer to use. + /// [`None`]s, then `filter_map()` is much, much nicer to use. /// /// # Examples /// @@ -547,7 +561,11 @@ pub trait Iterator { /// assert_eq!(iter.next(), None); /// ``` /// - /// There's an extra layer of `Some` in there. + /// There's an extra layer of [`Some`] in there. + /// + /// [`Option`]: ../../std/option/enum.Option.html + /// [`Some`]: ../../std/option/enum.Option.html#variant.Some + /// [`None`]: ../../std/option/enum.Option.html#variant.None #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn filter_map(self, f: F) -> FilterMap where @@ -567,21 +585,20 @@ pub trait Iterator { /// different sized integer, the [`zip()`] function provides similar /// functionality. /// - /// [`usize`]: ../../std/primitive.usize.html - /// [`zip()`]: #method.zip - /// /// # Overflow Behavior /// /// The method does no guarding against overflows, so enumerating more than /// [`usize::MAX`] elements either produces the wrong result or panics. If /// debug assertions are enabled, a panic is guaranteed. /// - /// [`usize::MAX`]: ../../std/usize/constant.MAX.html - /// /// # Panics /// /// The returned iterator might panic if the to-be-returned index would - /// overflow a `usize`. + /// overflow a [`usize`]. + /// + /// [`usize::MAX`]: ../../std/usize/constant.MAX.html + /// [`usize`]: ../../std/primitive.usize.html + /// [`zip()`]: #method.zip /// /// # Examples /// @@ -607,12 +624,13 @@ pub trait Iterator { /// Adds a [`peek()`] method to an iterator. See its documentation for /// more information. /// - /// Note that the underlying iterator is still advanced when `peek` is + /// Note that the underlying iterator is still advanced when [`peek()`] is /// called for the first time: In order to retrieve the next element, - /// `next` is called on the underlying iterator, hence any side effects of - /// the `next` method will occur. + /// [`next()`] is called on the underlying iterator, hence any side effects of + /// the [`next()`] method will occur. /// /// [`peek()`]: struct.Peekable.html#method.peek + /// [`next()`]: ../../std/iter/trait.Iterator.html#tymethod.next /// /// # Examples /// @@ -894,12 +912,12 @@ pub trait Iterator { /// an extra layer of indirection. `flat_map()` will remove this extra layer /// on its own. /// - /// [`map()`]: #method.map - /// /// Another way of thinking about `flat_map()`: [`map()`]'s closure returns /// one item for each element, and `flat_map()`'s closure returns an /// iterator for each element. /// + /// [`map()`]: #method.map + /// /// # Examples /// /// Basic usage: @@ -921,11 +939,14 @@ pub trait Iterator { FlatMap{iter: self, f: f, frontiter: None, backiter: None } } - /// Creates an iterator which ends after the first `None`. + /// Creates an iterator which ends after the first [`None`]. /// - /// After an iterator returns `None`, future calls may or may not yield - /// `Some(T)` again. `fuse()` adapts an iterator, ensuring that after a - /// `None` is given, it will always return `None` forever. + /// After an iterator returns [`None`], future calls may or may not yield + /// [`Some(T)`] again. `fuse()` adapts an iterator, ensuring that after a + /// [`None`] is given, it will always return [`None`] forever. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`Some(T)`]: ../../std/option/enum.Option.html#variant.Some /// /// # Examples /// @@ -1082,19 +1103,15 @@ pub trait Iterator { /// library, used in a variety of contexts. /// /// The most basic pattern in which `collect()` is used is to turn one - /// collection into another. You take a collection, call `iter()` on it, + /// collection into another. You take a collection, call [`iter()`] on it, /// do a bunch of transformations, and then `collect()` at the end. /// /// 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 + /// be thought of as single [`Result`]`, E>`. See the examples /// below for more. /// - /// [`String`]: ../../std/string/struct.String.html - /// [`Result`]: ../../std/result/enum.Result.html - /// [`char`]: ../../std/primitive.char.html - /// /// Because `collect()` is so general, it can cause problems with type /// inference. As such, `collect()` is one of the few times you'll see /// the syntax affectionately known as the 'turbofish': `::<>`. This @@ -1172,7 +1189,7 @@ pub trait Iterator { /// assert_eq!("hello", hello); /// ``` /// - /// If you have a list of [`Result`]s, you can use `collect()` to + /// If you have a list of [`Result`][`Result`]s, you can use `collect()` to /// see if any of them failed: /// /// ``` @@ -1190,6 +1207,11 @@ pub trait Iterator { /// // gives us the list of answers /// assert_eq!(Ok(vec![1, 3]), result); /// ``` + /// + /// [`iter()`]: ../../std/iter/trait.Iterator.html#tymethod.next + /// [`String`]: ../../std/string/struct.String.html + /// [`char`]: ../../std/primitive.char.html + /// [`Result`]: ../../std/result/enum.Result.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn collect>(self) -> B where Self: Sized { @@ -1281,6 +1303,8 @@ pub trait Iterator { /// use a `for` loop with a list of things to build up a result. Those /// can be turned into `fold()`s: /// + /// [`for`]: ../../book/loops.html#for + /// /// ``` /// let numbers = [1, 2, 3, 4, 5]; /// @@ -1414,8 +1438,8 @@ pub trait Iterator { /// /// `find()` takes a closure that returns `true` or `false`. It applies /// this closure to each element of the iterator, and if any of them return - /// `true`, then `find()` returns `Some(element)`. If they all return - /// `false`, it returns `None`. + /// `true`, then `find()` returns [`Some(element)`]. If they all return + /// `false`, it returns [`None`]. /// /// `find()` is short-circuiting; in other words, it will stop processing /// as soon as the closure returns `true`. @@ -1425,6 +1449,9 @@ pub trait Iterator { /// argument is a double reference. You can see this effect in the /// examples below, with `&&x`. /// + /// [`Some(element)`]: ../../std/option/enum.Option.html#variant.Some + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// Basic usage: @@ -1465,8 +1492,8 @@ pub trait Iterator { /// /// `position()` takes a closure that returns `true` or `false`. It applies /// this closure to each element of the iterator, and if one of them - /// returns `true`, then `position()` returns `Some(index)`. If all of - /// them return `false`, it returns `None`. + /// returns `true`, then `position()` returns [`Some(index)`]. If all of + /// them return `false`, it returns [`None`]. /// /// `position()` is short-circuiting; in other words, it will stop /// processing as soon as it finds a `true`. @@ -1474,7 +1501,7 @@ pub trait Iterator { /// # Overflow Behavior /// /// The method does no guarding against overflows, so if there are more - /// than `usize::MAX` non-matching elements, it either produces the wrong + /// than [`usize::MAX`] non-matching elements, it either produces the wrong /// result or panics. If debug assertions are enabled, a panic is /// guaranteed. /// @@ -1483,6 +1510,10 @@ pub trait Iterator { /// This function might panic if the iterator has more than `usize::MAX` /// non-matching elements. /// + /// [`Some(index)`]: ../../std/option/enum.Option.html#variant.Some + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`usize::MAX`]: ../../std/usize/constant.MAX.html + /// /// # Examples /// /// Basic usage: @@ -1528,11 +1559,14 @@ pub trait Iterator { /// `rposition()` takes a closure that returns `true` or `false`. It applies /// this closure to each element of the iterator, starting from the end, /// and if one of them returns `true`, then `rposition()` returns - /// `Some(index)`. If all of them return `false`, it returns `None`. + /// [`Some(index)`]. If all of them return `false`, it returns [`None`]. /// /// `rposition()` is short-circuiting; in other words, it will stop /// processing as soon as it finds a `true`. /// + /// [`Some(index)`]: ../../std/option/enum.Option.html#variant.Some + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// Basic usage: @@ -1798,11 +1832,13 @@ pub trait Iterator { (ts, us) } - /// Creates an iterator which `clone()`s all of its elements. + /// Creates an iterator which [`clone()`]s all of its elements. /// /// This is useful when you have an iterator over `&T`, but you need an /// iterator over `T`. /// + /// [`clone()`]: ../../std/clone/trait.Clone.html#tymethod.clone + /// /// # Examples /// /// Basic usage: @@ -1827,10 +1863,12 @@ pub trait Iterator { /// Repeats an iterator endlessly. /// - /// Instead of stopping at `None`, the iterator will instead start again, + /// Instead of stopping at [`None`], the iterator will instead start again, /// from the beginning. After iterating again, it will start at the /// beginning again. And again. And again. Forever. /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// Basic usage: @@ -1862,7 +1900,7 @@ pub trait Iterator { /// /// # Panics /// - /// When calling `sum` and a primitive integer type is being returned, this + /// When calling `sum()` and a primitive integer type is being returned, this /// method will panic if the computation overflows and debug assertions are /// enabled. /// @@ -1890,7 +1928,7 @@ pub trait Iterator { /// /// # Panics /// - /// When calling `product` and a primitive integer type is being returned, + /// When calling `product()` and a primitive integer type is being returned, /// method will panic if the computation overflows and debug assertions are /// enabled. /// diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index df4f5e5c5764..cd2e0cb11d35 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -328,6 +328,8 @@ pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend}; pub use self::traits::{ExactSizeIterator, Sum, Product}; #[unstable(feature = "fused", issue = "35602")] pub use self::traits::FusedIterator; +#[unstable(feature = "trusted_len", issue = "37572")] +pub use self::traits::TrustedLen; mod iterator; mod range; @@ -372,6 +374,10 @@ impl ExactSizeIterator for Rev impl FusedIterator for Rev where I: FusedIterator + DoubleEndedIterator {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Rev + where I: TrustedLen + DoubleEndedIterator {} + /// An iterator that clones the elements of an underlying iterator. /// /// This `struct` is created by the [`cloned()`] method on [`Iterator`]. See its @@ -438,6 +444,12 @@ unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned fn may_have_side_effect() -> bool { true } } +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, I, T: 'a> TrustedLen for Cloned + where I: TrustedLen, + T: Clone +{} + /// An iterator that repeats endlessly. /// /// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its @@ -667,6 +679,11 @@ impl FusedIterator for Chain B: FusedIterator, {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Chain + where A: TrustedLen, B: TrustedLen, +{} + /// An iterator that iterates two other iterators simultaneously. /// /// This `struct` is created by the [`zip()`] method on [`Iterator`]. See its @@ -884,6 +901,11 @@ unsafe impl TrustedRandomAccess for Zip impl FusedIterator for Zip where A: FusedIterator, B: FusedIterator, {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Zip + where A: TrustedLen, B: TrustedLen, +{} + /// An iterator that maps the values of `iter` with `f`. /// /// This `struct` is created by the [`map()`] method on [`Iterator`]. See its @@ -991,6 +1013,11 @@ impl ExactSizeIterator for Map impl FusedIterator for Map where F: FnMut(I::Item) -> B {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Map + where I: TrustedLen, + F: FnMut(I::Item) -> B {} + #[doc(hidden)] unsafe impl TrustedRandomAccess for Map where I: TrustedRandomAccess, @@ -1227,6 +1254,12 @@ unsafe impl TrustedRandomAccess for Enumerate #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for Enumerate where I: FusedIterator {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Enumerate + where I: TrustedLen, +{} + + /// An iterator with a `peek()` that returns an optional reference to the next /// element. /// @@ -1341,10 +1374,7 @@ impl Peekable { if self.peeked.is_none() { self.peeked = self.iter.next(); } - match self.peeked { - Some(ref value) => Some(value), - None => None, - } + self.peeked.as_ref() } } diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index eaa3d50c88ad..e6f21d6c17ae 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -12,7 +12,7 @@ use mem; use ops::{self, Add, Sub}; use usize; -use super::FusedIterator; +use super::{FusedIterator, TrustedLen}; /// Objects that can be stepped over in both directions. /// @@ -96,12 +96,12 @@ macro_rules! step_impl_unsigned { #[inline] fn add_one(&self) -> Self { - *self + 1 + Add::add(*self, 1) } #[inline] fn sub_one(&self) -> Self { - *self - 1 + Sub::sub(*self, 1) } #[inline] @@ -167,12 +167,12 @@ macro_rules! step_impl_signed { #[inline] fn add_one(&self) -> Self { - *self + 1 + Add::add(*self, 1) } #[inline] fn sub_one(&self) -> Self { - *self - 1 + Sub::sub(*self, 1) } #[inline] @@ -216,12 +216,12 @@ macro_rules! step_impl_no_between { #[inline] fn add_one(&self) -> Self { - *self + 1 + Add::add(*self, 1) } #[inline] fn sub_one(&self) -> Self { - *self - 1 + Sub::sub(*self, 1) } #[inline] @@ -480,6 +480,22 @@ macro_rules! range_incl_exact_iter_impl { )*) } +macro_rules! range_trusted_len_impl { + ($($t:ty)*) => ($( + #[unstable(feature = "trusted_len", issue = "37572")] + unsafe impl TrustedLen for ops::Range<$t> { } + )*) +} + +macro_rules! range_incl_trusted_len_impl { + ($($t:ty)*) => ($( + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + unsafe impl TrustedLen for ops::RangeInclusive<$t> { } + )*) +} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for ops::Range where for<'a> &'a A: Add<&'a A, Output = A> @@ -513,6 +529,13 @@ impl Iterator for ops::Range where range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32); range_incl_exact_iter_impl!(u8 u16 i8 i16); +// These macros generate `TrustedLen` impls. +// +// They need to guarantee that .size_hint() is either exact, or that +// the upper bound is None when it does not fit the type limits. +range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64); +range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64); + #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for ops::Range where for<'a> &'a A: Add<&'a A, Output = A>, diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index b55d6f96af9b..9d402971d18d 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use ops::{Mul, Add}; +use num::Wrapping; /// Conversion from an `Iterator`. /// @@ -555,10 +556,14 @@ impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for &'a mut I {} /// Trait to represent types that can be created by summing up an iterator. /// -/// This trait is used to implement the `sum` method on iterators. Types which -/// implement the trait can be generated by the `sum` method. Like -/// `FromIterator` this trait should rarely be called directly and instead -/// interacted with through `Iterator::sum`. +/// This trait is used to implement the [`sum()`] method on iterators. Types which +/// implement the trait can be generated by the [`sum()`] method. Like +/// [`FromIterator`] this trait should rarely be called directly and instead +/// interacted with through [`Iterator::sum()`]. +/// +/// [`sum()`]: ../../std/iter/trait.Sum.html#tymethod.sum +/// [`FromIterator`]: ../../std/iter/trait.FromIterator.html +/// [`Iterator::sum()`]: ../../std/iter/trait.Iterator.html#method.sum #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Sum: Sized { /// Method which takes an iterator and generates `Self` from the elements by @@ -570,10 +575,14 @@ pub trait Sum: Sized { /// Trait to represent types that can be created by multiplying elements of an /// iterator. /// -/// This trait is used to implement the `product` method on iterators. Types -/// which implement the trait can be generated by the `product` method. Like -/// `FromIterator` this trait should rarely be called directly and instead -/// interacted with through `Iterator::product`. +/// This trait is used to implement the [`product()`] method on iterators. Types +/// which implement the trait can be generated by the [`product()`] method. Like +/// [`FromIterator`] this trait should rarely be called directly and instead +/// interacted with through [`Iterator::product()`]. +/// +/// [`product()`]: ../../std/iter/trait.Product.html#tymethod.product +/// [`FromIterator`]: ../../std/iter/trait.FromIterator.html +/// [`Iterator::product()`]: ../../std/iter/trait.Iterator.html#method.product #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Product: Sized { /// Method which takes an iterator and generates `Self` from the elements by @@ -584,35 +593,39 @@ pub trait Product: Sized { // NB: explicitly use Add and Mul here to inherit overflow checks macro_rules! integer_sum_product { - ($($a:ident)*) => ($( + (@impls $zero:expr, $one:expr, $($a:ty)*) => ($( #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { fn sum>(iter: I) -> $a { - iter.fold(0, Add::add) + iter.fold($zero, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Product for $a { fn product>(iter: I) -> $a { - iter.fold(1, Mul::mul) + iter.fold($one, Mul::mul) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Sum<&'a $a> for $a { fn sum>(iter: I) -> $a { - iter.cloned().fold(0, Add::add) + iter.fold($zero, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Product<&'a $a> for $a { fn product>(iter: I) -> $a { - iter.cloned().fold(1, Mul::mul) + iter.fold($one, Mul::mul) } } - )*) + )*); + ($($a:ty)*) => ( + integer_sum_product!(@impls 0, 1, $($a)+); + integer_sum_product!(@impls Wrapping(0), Wrapping(1), $(Wrapping<$a>)+); + ); } macro_rules! float_sum_product { @@ -665,3 +678,22 @@ pub trait FusedIterator: Iterator {} #[unstable(feature = "fused", issue = "35602")] impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {} + +/// An iterator that reports an accurate length using size_hint. +/// +/// The iterator reports a size hint where it is either exact +/// (lower bound is equal to upper bound), or the upper bound is `None`. +/// The upper bound must only be `None` if the actual iterator length is +/// larger than `usize::MAX`. +/// +/// The iterator must produce exactly the number of elements it reported. +/// +/// # Safety +/// +/// This trait must only be implemented when the contract is upheld. +/// Consumers of this trait must inspect `.size_hint()`’s upper bound. +#[unstable(feature = "trusted_len", issue = "37572")] +pub unsafe trait TrustedLen : Iterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, I: TrustedLen + ?Sized> TrustedLen for &'a mut I {} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 28101d21fc25..07f5e725e200 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -100,6 +100,9 @@ use prelude::v1::*; #[macro_use] mod macros; +#[macro_use] +mod internal_macros; + #[path = "num/float_macros.rs"] #[macro_use] mod float_macros; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index cae46a0dd0fe..3cf32d1a5591 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -350,6 +350,21 @@ macro_rules! try { /// /// assert_eq!(w, b"testformatted arguments"); /// ``` +/// +/// A module can import both `std::fmt::Write` and `std::io::Write` and call `write!` on objects +/// implementing either, as objects do not typically implement both. However, the module must +/// import the traits qualified so their names do not conflict: +/// +/// ``` +/// use std::fmt::Write as FmtWrite; +/// use std::io::Write as IoWrite; +/// +/// let mut s = String::new(); +/// let mut v = Vec::new(); +/// write!(&mut s, "{} {}", "abc", 123).unwrap(); // uses fmt::Write::write_fmt +/// write!(&mut v, "s = {:?}", s).unwrap(); // uses io::Write::write_fmt +/// assert_eq!(v, b"s = \"abc 123\""); +/// ``` #[macro_export] #[stable(feature = "core", since = "1.6.0")] macro_rules! write { @@ -394,6 +409,21 @@ macro_rules! write { /// /// assert_eq!(&w[..], "test\nformatted arguments\n".as_bytes()); /// ``` +/// +/// A module can import both `std::fmt::Write` and `std::io::Write` and call `write!` on objects +/// implementing either, as objects do not typically implement both. However, the module must +/// import the traits qualified so their names do not conflict: +/// +/// ``` +/// use std::fmt::Write as FmtWrite; +/// use std::io::Write as IoWrite; +/// +/// let mut s = String::new(); +/// let mut v = Vec::new(); +/// writeln!(&mut s, "{} {}", "abc", 123).unwrap(); // uses fmt::Write::write_fmt +/// writeln!(&mut v, "s = {:?}", s).unwrap(); // uses io::Write::write_fmt +/// assert_eq!(v, b"s = \"abc 123\\n\"\n"); +/// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! writeln { diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index d35c451ac260..50d64838a5c0 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -131,6 +131,7 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_add(other.0)) } } + forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl AddAssign for Wrapping<$t> { @@ -149,6 +150,7 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_sub(other.0)) } } + forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl SubAssign for Wrapping<$t> { @@ -167,6 +169,7 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_mul(other.0)) } } + forward_ref_binop! { impl Mul, mul for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl MulAssign for Wrapping<$t> { @@ -185,6 +188,7 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_div(other.0)) } } + forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl DivAssign for Wrapping<$t> { @@ -203,6 +207,7 @@ macro_rules! wrapping_impl { Wrapping(self.0.wrapping_rem(other.0)) } } + forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl RemAssign for Wrapping<$t> { @@ -221,6 +226,7 @@ macro_rules! wrapping_impl { Wrapping(!self.0) } } + forward_ref_unop! { impl Not, not for Wrapping<$t> } #[stable(feature = "rust1", since = "1.0.0")] impl BitXor for Wrapping<$t> { @@ -231,6 +237,7 @@ macro_rules! wrapping_impl { Wrapping(self.0 ^ other.0) } } + forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl BitXorAssign for Wrapping<$t> { @@ -249,6 +256,7 @@ macro_rules! wrapping_impl { Wrapping(self.0 | other.0) } } + forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl BitOrAssign for Wrapping<$t> { @@ -267,6 +275,7 @@ macro_rules! wrapping_impl { Wrapping(self.0 & other.0) } } + forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t> } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl BitAndAssign for Wrapping<$t> { @@ -284,6 +293,7 @@ macro_rules! wrapping_impl { Wrapping(0) - self } } + forward_ref_unop! { impl Neg, neg for Wrapping<$t> } )*) } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 06838ee89bd3..07ae5b920b27 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -196,58 +196,6 @@ pub trait Drop { fn drop(&mut self); } -// implements the unary operator "op &T" -// based on "op T" where T is expected to be `Copy`able -macro_rules! forward_ref_unop { - (impl $imp:ident, $method:ident for $t:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a> $imp for &'a $t { - type Output = <$t as $imp>::Output; - - #[inline] - fn $method(self) -> <$t as $imp>::Output { - $imp::$method(*self) - } - } - } -} - -// implements binary operators "&T op U", "T op &U", "&T op &U" -// based on "T op U" where T and U are expected to be `Copy`able -macro_rules! forward_ref_binop { - (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a> $imp<$u> for &'a $t { - type Output = <$t as $imp<$u>>::Output; - - #[inline] - fn $method(self, other: $u) -> <$t as $imp<$u>>::Output { - $imp::$method(*self, other) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a> $imp<&'a $u> for $t { - type Output = <$t as $imp<$u>>::Output; - - #[inline] - fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { - $imp::$method(self, *other) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, 'b> $imp<&'a $u> for &'b $t { - type Output = <$t as $imp<$u>>::Output; - - #[inline] - fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { - $imp::$method(*self, *other) - } - } - } -} - /// The `Add` trait is used to specify the functionality of `+`. /// /// # Examples diff --git a/src/libcore/option.rs b/src/libcore/option.rs index a74979911d34..607e16887a83 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -145,7 +145,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use iter::{FromIterator, FusedIterator}; +use iter::{FromIterator, FusedIterator, TrustedLen}; use mem; // Note that this is not a lang item per se, but it has a hidden dependency on @@ -803,6 +803,7 @@ impl DoubleEndedIterator for Item { impl ExactSizeIterator for Item {} impl FusedIterator for Item {} +unsafe impl TrustedLen for Item {} /// An iterator over a reference of the contained item in an [`Option`]. /// @@ -833,6 +834,9 @@ impl<'a, A> ExactSizeIterator for Iter<'a, A> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, A> FusedIterator for Iter<'a, A> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, A> TrustedLen for Iter<'a, A> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, A> Clone for Iter<'a, A> { fn clone(&self) -> Iter<'a, A> { @@ -868,6 +872,8 @@ impl<'a, A> ExactSizeIterator for IterMut<'a, A> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, A> FusedIterator for IterMut<'a, A> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} /// An iterator over the item contained inside an [`Option`]. /// @@ -898,6 +904,9 @@ impl ExactSizeIterator for IntoIter {} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IntoIter {} + ///////////////////////////////////////////////////////////////////////////// // FromIterator ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f0510422a07d..2ad38de72b1b 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -344,6 +344,46 @@ impl *const T { pub unsafe fn offset(self, count: isize) -> *const T where T: Sized { intrinsics::offset(self, count) } + + /// Calculates the offset from a pointer using wrapping arithmetic. + /// `count` is in units of T; e.g. a `count` of 3 represents a pointer + /// offset of `3 * sizeof::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// Always use `.offset(count)` instead when possible, because `offset` + /// allows the compiler to optimize better. + /// + /// # Examples + /// + /// 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(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_offset(6); + /// + /// // This loop prints "1, 3, 5, " + /// while ptr != end_rounded_up { + /// unsafe { + /// print!("{}, ", *ptr); + /// } + /// ptr = ptr.wrapping_offset(step); + /// } + /// ``` + #[unstable(feature = "ptr_wrapping_offset", issue = "37570")] + #[inline] + pub fn wrapping_offset(self, count: isize) -> *const T where T: Sized { + unsafe { + intrinsics::arith_offset(self, count) + } + } } #[lang = "mut_ptr"] @@ -429,6 +469,46 @@ impl *mut T { intrinsics::offset(self, count) as *mut T } + /// Calculates the offset from a pointer using wrapping arithmetic. + /// `count` is in units of T; e.g. a `count` of 3 represents a pointer + /// offset of `3 * sizeof::()` bytes. + /// + /// # Safety + /// + /// The resulting pointer does not need to be in bounds, but it is + /// potentially hazardous to dereference (which requires `unsafe`). + /// + /// Always use `.offset(count)` instead when possible, because `offset` + /// allows the compiler to optimize better. + /// + /// # Examples + /// + /// 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(); + /// let step = 2; + /// let end_rounded_up = ptr.wrapping_offset(6); + /// + /// while ptr != end_rounded_up { + /// unsafe { + /// *ptr = 0; + /// } + /// ptr = ptr.wrapping_offset(step); + /// } + /// assert_eq!(&data, &[0, 2, 0, 4, 0]); + /// ``` + #[unstable(feature = "ptr_wrapping_offset", issue = "37570")] + #[inline] + pub fn wrapping_offset(self, count: isize) -> *mut T where T: Sized { + unsafe { + intrinsics::arith_offset(self, count) as *mut T + } + } + /// Returns `None` if the pointer is null, or else returns a mutable /// reference to the value wrapped in `Some`. /// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 9ba5ff7c3a46..afed99d265f1 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -249,7 +249,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use fmt; -use iter::{FromIterator, FusedIterator}; +use iter::{FromIterator, FusedIterator, TrustedLen}; /// `Result` is a type that represents either success (`Ok`) or failure (`Err`). /// @@ -924,6 +924,9 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for Iter<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, A> TrustedLen for Iter<'a, A> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } } @@ -962,6 +965,9 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} + /// An iterator over the value in a [`Ok`] variant of a [`Result`]. This struct is /// created by the [`into_iter`] method on [`Result`][`Result`] (provided by /// the [`IntoIterator`] trait). @@ -999,6 +1005,9 @@ impl ExactSizeIterator for IntoIter {} #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for IntoIter {} + ///////////////////////////////////////////////////////////////////////////// // FromIterator ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 31be404ba905..871b63145ca6 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -988,6 +988,9 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for Iter<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for Iter<'a, T> {} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, _marker: self._marker } } @@ -1109,6 +1112,9 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} + /// An internal abstraction over the splitting iterators, so that /// splitn, splitn_mut etc can be implemented once. #[doc(hidden)] diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 26bc46931bd5..8f85bfe2c638 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -53,7 +53,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8), // now hopefully. #[no_mangle] pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { - return abort(); + abort(); #[cfg(unix)] unsafe fn abort() -> ! { diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index f0f19be3366b..73264fab69c2 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -124,7 +124,7 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 -#[cfg(any(target_arch = "mips", target_arch = "mipsel", target_arch = "mips64"))] +#[cfg(any(target_arch = "mips", target_arch = "mips64"))] const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 1d2c64d6d938..5ee9fecfb21b 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -95,7 +95,8 @@ pub mod __internal { pub trait Registry { fn register_custom_derive(&mut self, trait_name: &str, - expand: fn(TokenStream) -> TokenStream); + expand: fn(TokenStream) -> TokenStream, + attributes: &[&'static str]); } // Emulate scoped_thread_local!() here essentially diff --git a/src/libproc_macro_tokens/parse.rs b/src/libproc_macro_tokens/parse.rs index 9af8a68cdcf4..5ab4fcd5dab2 100644 --- a/src/libproc_macro_tokens/parse.rs +++ b/src/libproc_macro_tokens/parse.rs @@ -15,12 +15,12 @@ extern crate syntax; use syntax::parse::{ParseSess, filemap_to_tts}; use syntax::tokenstream::TokenStream; -/// Map a string to tts, using a made-up filename. For example, `lex(15)` will return a +/// Map a string to tts, using a made-up filename. For example, `lex("15")` will return a /// TokenStream containing the literal 15. pub fn lex(source_str: &str) -> TokenStream { let ps = ParseSess::new(); TokenStream::from_tts(filemap_to_tts(&ps, - ps.codemap().new_filemap("procmacro_lex".to_string(), + ps.codemap().new_filemap("".to_string(), None, source_str.to_owned()))) } diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 1b2976b7435d..22c7d14be29d 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -33,16 +33,16 @@ struct LoopScope { } pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - blk: &hir::Block) -> CFG { + body: &hir::Expr) -> CFG { let mut graph = graph::Graph::new(); let entry = graph.add_node(CFGNodeData::Entry); // `fn_exit` is target of return exprs, which lies somewhere - // outside input `blk`. (Distinguishing `fn_exit` and `block_exit` + // outside input `body`. (Distinguishing `fn_exit` and `body_exit` // also resolves chicken-and-egg problem that arises if you try to - // have return exprs jump to `block_exit` during construction.) + // have return exprs jump to `body_exit` during construction.) let fn_exit = graph.add_node(CFGNodeData::Exit); - let block_exit; + let body_exit; let mut cfg_builder = CFGBuilder { graph: graph, @@ -50,8 +50,8 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: tcx, loop_scopes: Vec::new() }; - block_exit = cfg_builder.block(blk, entry); - cfg_builder.add_contained_edge(block_exit, fn_exit); + body_exit = cfg_builder.expr(body, entry); + cfg_builder.add_contained_edge(body_exit, fn_exit); let CFGBuilder {graph, ..} = cfg_builder; CFG {graph: graph, entry: entry, @@ -311,11 +311,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } hir::ExprIndex(ref l, ref r) | - hir::ExprBinary(_, ref l, ref r) if self.tcx.is_method_call(expr.id) => { + hir::ExprBinary(_, ref l, ref r) if self.tcx.tables().is_method_call(expr.id) => { self.call(expr, pred, &l, Some(&**r).into_iter()) } - hir::ExprUnary(_, ref e) if self.tcx.is_method_call(expr.id) => { + hir::ExprUnary(_, ref e) if self.tcx.tables().is_method_call(expr.id) => { self.call(expr, pred, &e, None::.iter()) } @@ -372,9 +372,9 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { func_or_rcvr: &hir::Expr, args: I) -> CFGIndex { let method_call = ty::MethodCall::expr(call_expr.id); - let fn_ty = match self.tcx.tables.borrow().method_map.get(&method_call) { + let fn_ty = match self.tcx.tables().method_map.get(&method_call) { Some(method) => method.ty, - None => self.tcx.expr_ty_adjusted(func_or_rcvr) + None => self.tcx.tables().expr_ty_adjusted(func_or_rcvr) }; let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index d06f51073df0..43434b884c8d 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -59,8 +59,8 @@ pub type CFGEdge = graph::Edge; impl CFG { pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - blk: &hir::Block) -> CFG { - construct::construct(tcx, blk) + body: &hir::Expr) -> CFG { + construct::construct(tcx, body) } pub fn node_is_reachable(&self, id: ast::NodeId) -> bool { diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e99ffa95ed63..351feaba0346 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -103,11 +103,11 @@ pub enum DepNode { // nodes. Often we map multiple tables to the same node if there // is no point in distinguishing them (e.g., both the type and // predicates for an item wind up in `ItemSignature`). - ImplOrTraitItems(D), + AssociatedItems(D), ItemSignature(D), FieldTy(D), SizedConstraint(D), - ImplOrTraitItemDefIds(D), + AssociatedItemDefIds(D), InherentImpls(D), // The set of impls for a given trait. Ultimately, it would be @@ -153,10 +153,10 @@ impl DepNode { TransCrateItem, TypeckItemType, TypeckItemBody, - ImplOrTraitItems, + AssociatedItems, ItemSignature, FieldTy, - ImplOrTraitItemDefIds, + AssociatedItemDefIds, InherentImpls, TraitImpls, ReprHints, @@ -219,11 +219,11 @@ impl DepNode { RvalueCheck(ref d) => op(d).map(RvalueCheck), TransCrateItem(ref d) => op(d).map(TransCrateItem), TransInlinedItem(ref d) => op(d).map(TransInlinedItem), - ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems), + AssociatedItems(ref d) => op(d).map(AssociatedItems), ItemSignature(ref d) => op(d).map(ItemSignature), FieldTy(ref d) => op(d).map(FieldTy), SizedConstraint(ref d) => op(d).map(SizedConstraint), - ImplOrTraitItemDefIds(ref d) => op(d).map(ImplOrTraitItemDefIds), + AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds), InherentImpls(ref d) => op(d).map(InherentImpls), TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 51f7890c7a2f..50a478fcc2fd 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -9,7 +9,7 @@ // except according to those terms. use hir::def_id::DefId; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use std::cell::RefCell; use std::ops::Index; use std::hash::Hash; @@ -24,7 +24,7 @@ use super::{DepNode, DepGraph}; pub struct DepTrackingMap { phantom: PhantomData, graph: DepGraph, - map: FnvHashMap, + map: FxHashMap, } pub trait DepTrackingMapConfig { @@ -38,7 +38,7 @@ impl DepTrackingMap { DepTrackingMap { phantom: PhantomData, graph: graph, - map: FnvHashMap() + map: FxHashMap() } } diff --git a/src/librustc/dep_graph/edges.rs b/src/librustc/dep_graph/edges.rs index 10f3d21f2af6..8657a3e5a587 100644 --- a/src/librustc/dep_graph/edges.rs +++ b/src/librustc/dep_graph/edges.rs @@ -8,15 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::fmt::Debug; use std::hash::Hash; use super::{DepGraphQuery, DepNode}; pub struct DepGraphEdges { nodes: Vec>, - indices: FnvHashMap, IdIndex>, - edges: FnvHashSet<(IdIndex, IdIndex)>, + indices: FxHashMap, IdIndex>, + edges: FxHashSet<(IdIndex, IdIndex)>, open_nodes: Vec, } @@ -46,8 +46,8 @@ impl DepGraphEdges { pub fn new() -> DepGraphEdges { DepGraphEdges { nodes: vec![], - indices: FnvHashMap(), - edges: FnvHashSet(), + indices: FxHashMap(), + edges: FxHashSet(), open_nodes: Vec::new() } } diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index fac3586afc7b..2637d34c5c56 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -9,7 +9,7 @@ // except according to those terms. use hir::def_id::DefId; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use session::config::OutputType; use std::cell::{Ref, RefCell}; use std::rc::Rc; @@ -34,10 +34,10 @@ struct DepGraphData { /// things available to us. If we find that they are not dirty, we /// load the path to the file storing those work-products here into /// this map. We can later look for and extract that data. - previous_work_products: RefCell, WorkProduct>>, + previous_work_products: RefCell, WorkProduct>>, /// Work-products that we generate in this run. - work_products: RefCell, WorkProduct>>, + work_products: RefCell, WorkProduct>>, } impl DepGraph { @@ -45,8 +45,8 @@ impl DepGraph { DepGraph { data: Rc::new(DepGraphData { thread: DepGraphThreadData::new(enabled), - previous_work_products: RefCell::new(FnvHashMap()), - work_products: RefCell::new(FnvHashMap()), + previous_work_products: RefCell::new(FxHashMap()), + work_products: RefCell::new(FxHashMap()), }) } } @@ -117,7 +117,7 @@ impl DepGraph { /// Access the map of work-products created during this run. Only /// used during saving of the dep-graph. - pub fn work_products(&self) -> Ref, WorkProduct>> { + pub fn work_products(&self) -> Ref, WorkProduct>> { self.data.work_products.borrow() } } diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs index 7a780c1d4ae2..4c791f965534 100644 --- a/src/librustc/dep_graph/query.rs +++ b/src/librustc/dep_graph/query.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::{Direction, INCOMING, Graph, NodeIndex, OUTGOING}; use std::fmt::Debug; use std::hash::Hash; @@ -17,7 +17,7 @@ use super::DepNode; pub struct DepGraphQuery { pub graph: Graph, ()>, - pub indices: FnvHashMap, NodeIndex>, + pub indices: FxHashMap, NodeIndex>, } impl DepGraphQuery { @@ -25,7 +25,7 @@ impl DepGraphQuery { edges: &[(DepNode, DepNode)]) -> DepGraphQuery { let mut graph = Graph::new(); - let mut indices = FnvHashMap(); + let mut indices = FxHashMap(); for node in nodes { indices.insert(node.clone(), graph.next_node_index()); graph.add_node(node.clone()); diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 465a09505e4a..ec09877ae121 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -672,120 +672,6 @@ extern "C" { ``` "##, -E0269: r##" -A returned value was expected but not all control paths return one. - -Erroneous code example: - -```compile_fail,E0269 -fn abracada_FAIL() -> String { - "this won't work".to_string(); - // error: not all control paths return a value -} -``` - -In the previous code, the function is supposed to return a `String`, however, -the code returns nothing (because of the ';'). Another erroneous code would be: - -```compile_fail -fn abracada_FAIL(b: bool) -> u32 { - if b { - 0 - } else { - "a" // It fails because an `u32` was expected and something else is - // returned. - } -} -``` - -It is advisable to find out what the unhandled cases are and check for them, -returning an appropriate value or panicking if necessary. Check if you need -to remove a semicolon from the last expression, like in the first erroneous -code example. -"##, - -E0270: r##" -Rust lets you define functions which are known to never return, i.e. are -'diverging', by marking its return type as `!`. - -For example, the following functions never return: - -```no_run -fn foo() -> ! { - loop {} -} - -fn bar() -> ! { - foo() // foo() is diverging, so this will diverge too -} - -fn baz() -> ! { - panic!(); // this macro internally expands to a call to a diverging function -} -``` - -Such functions can be used in a place where a value is expected without -returning a value of that type, for instance: - -```no_run -fn foo() -> ! { - loop {} -} - -let x = 3; - -let y = match x { - 1 => 1, - 2 => 4, - _ => foo() // diverging function called here -}; - -println!("{}", y) -``` - -If the third arm of the match block is reached, since `foo()` doesn't ever -return control to the match block, it is fine to use it in a place where an -integer was expected. The `match` block will never finish executing, and any -point where `y` (like the print statement) is needed will not be reached. - -However, if we had a diverging function that actually does finish execution: - -```ignore -fn foo() -> ! { - loop {break;} -} -``` - -Then we would have an unknown value for `y` in the following code: - -```no_run -fn foo() -> ! { - loop {} -} - -let x = 3; - -let y = match x { - 1 => 1, - 2 => 4, - _ => foo() -}; - -println!("{}", y); -``` - -In the previous example, the print statement was never reached when the -wildcard match arm was hit, so we were okay with `foo()` not returning an -integer that we could set to `y`. But in this example, `foo()` actually does -return control, so the print statement will be executed with an uninitialized -value. - -Obviously we cannot have functions which are allowed to be used in such -positions and yet can return control. So, if you are defining a function that -returns `!`, make sure that there is no way for it to actually finish -executing. -"##, - E0271: r##" This is because of a type mismatch between the associated type of some trait (e.g. `T::Bar`, where `T` implements `trait Quux { type Bar; }`) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 8b9cee1d2f6d..044e36e5c9cd 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -52,6 +52,9 @@ pub enum Def { ast::NodeId), // expr node that creates the closure Label(ast::NodeId), + // Macro namespace + Macro(DefId), + // Both namespaces Err, } @@ -133,7 +136,7 @@ impl Def { Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | - Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) => { + Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id) => { id } @@ -173,6 +176,7 @@ impl Def { Def::Upvar(..) => "closure capture", Def::Label(..) => "label", Def::SelfTy(..) => "self type", + Def::Macro(..) => "macro", Def::Err => "unresolved item", } } diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 399243551d65..d3771b1755b1 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -34,6 +34,10 @@ impl Idx for CrateNum { /// LOCAL_CRATE in their DefId. pub const LOCAL_CRATE: CrateNum = CrateNum(0); +/// Virtual crate for builtin macros +// FIXME(jseyfried): this is also used for custom derives until proc-macro crates get `CrateNum`s. +pub const BUILTIN_MACROS_CRATE: CrateNum = CrateNum(!0); + impl CrateNum { pub fn new(x: usize) -> CrateNum { assert!(x < (u32::MAX as usize)); diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index b1771f52da2c..9932e5fe6862 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -138,7 +138,7 @@ pub trait Visitor<'v> : Sized { fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) { walk_where_predicate(self, predicate) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, id: NodeId) { + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Expr, s: Span, id: NodeId) { walk_fn(self, fk, fd, b, s, id) } fn visit_trait_item(&mut self, ti: &'v TraitItem) { @@ -635,13 +635,13 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<' pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>, function_declaration: &'v FnDecl, - function_body: &'v Block, + function_body: &'v Expr, _span: Span, id: NodeId) { visitor.visit_id(id); walk_fn_decl(visitor, function_declaration); walk_fn_kind(visitor, function_kind); - visitor.visit_block(function_body) + visitor.visit_expr(function_body) } pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) { @@ -925,7 +925,7 @@ impl<'v> Visitor<'v> for IdRangeComputingVisitor { /// Computes the id range for a single fn body, ignoring nested items. pub fn compute_id_range_for_fn_body(fk: FnKind, decl: &FnDecl, - body: &Block, + body: &Expr, sp: Span, id: NodeId) -> IdRange { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 620ee30c9562..b985298e47cc 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -595,12 +595,13 @@ impl<'a> LoweringContext<'a> { hir::ItemConst(self.lower_ty(t), self.lower_expr(e)) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { + let body = self.lower_block(body); hir::ItemFn(self.lower_fn_decl(decl), self.lower_unsafety(unsafety), self.lower_constness(constness), abi, self.lower_generics(generics), - self.lower_block(body)) + self.expr_block(body, ThinVec::new())) } ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), @@ -665,7 +666,10 @@ impl<'a> LoweringContext<'a> { } TraitItemKind::Method(ref sig, ref body) => { hir::MethodTraitItem(this.lower_method_sig(sig), - body.as_ref().map(|x| this.lower_block(x))) + body.as_ref().map(|x| { + let body = this.lower_block(x); + this.expr_block(body, ThinVec::new()) + })) } TraitItemKind::Type(ref bounds, ref default) => { hir::TypeTraitItem(this.lower_bounds(bounds), @@ -691,8 +695,9 @@ impl<'a> LoweringContext<'a> { hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr)) } ImplItemKind::Method(ref sig, ref body) => { + let body = this.lower_block(body); hir::ImplItemKind::Method(this.lower_method_sig(sig), - this.lower_block(body)) + this.expr_block(body, ThinVec::new())) } ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)), ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), @@ -1110,7 +1115,7 @@ impl<'a> LoweringContext<'a> { self.with_parent_def(e.id, |this| { hir::ExprClosure(this.lower_capture_clause(capture_clause), this.lower_fn_decl(decl), - this.lower_block(body), + this.lower_expr(body), fn_decl_span) }) } @@ -1208,38 +1213,32 @@ impl<'a> LoweringContext<'a> { ExprKind::Break(opt_ident) => hir::ExprBreak(self.lower_opt_sp_ident(opt_ident)), ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_opt_sp_ident(opt_ident)), ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| self.lower_expr(x))), - ExprKind::InlineAsm(InlineAsm { - ref inputs, - ref outputs, - ref asm, - asm_str_style, - ref clobbers, - volatile, - alignstack, - dialect, - expn_id, - }) => hir::ExprInlineAsm(P(hir::InlineAsm { - inputs: inputs.iter().map(|&(ref c, _)| c.clone()).collect(), - outputs: outputs.iter() - .map(|out| { - hir::InlineAsmOutput { - constraint: out.constraint.clone(), - is_rw: out.is_rw, - is_indirect: out.is_indirect, - } - }) - .collect(), - asm: asm.clone(), - asm_str_style: asm_str_style, - clobbers: clobbers.clone().into(), - volatile: volatile, - alignstack: alignstack, - dialect: dialect, - expn_id: expn_id, - }), outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(), - inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect()), + ExprKind::InlineAsm(ref asm) => { + let hir_asm = hir::InlineAsm { + inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(), + outputs: asm.outputs.iter().map(|out| { + hir::InlineAsmOutput { + constraint: out.constraint.clone(), + is_rw: out.is_rw, + is_indirect: out.is_indirect, + } + }).collect(), + asm: asm.asm.clone(), + asm_str_style: asm.asm_str_style, + clobbers: asm.clobbers.clone().into(), + volatile: asm.volatile, + alignstack: asm.alignstack, + dialect: asm.dialect, + expn_id: asm.expn_id, + }; + let outputs = + asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); + let inputs = + asm.inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect(); + hir::ExprInlineAsm(P(hir_asm), outputs, inputs) + } ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { - hir::ExprStruct(self.lower_path(path), + hir::ExprStruct(P(self.lower_path(path)), fields.iter().map(|x| self.lower_field(x)).collect(), maybe_expr.as_ref().map(|x| self.lower_expr(x))) } @@ -1743,7 +1742,7 @@ impl<'a> LoweringContext<'a> { e: Option>, attrs: ThinVec) -> P { let def = self.resolver.resolve_generated_global_path(&path, false); - let expr = self.expr(sp, hir::ExprStruct(path, fields, e), attrs); + let expr = self.expr(sp, hir::ExprStruct(P(path), fields, e), attrs); self.resolver.record_resolution(expr.id, def); expr } diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 448723488569..325a90ea91e0 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -21,11 +21,9 @@ //! nested within a uniquely determined `FnLike`), and users can ask //! for the `Code` associated with a particular NodeId. -pub use self::Code::*; - use hir as ast; use hir::map::{self, Node}; -use hir::{Block, FnDecl}; +use hir::{Expr, FnDecl}; use hir::intravisit::FnKind; use syntax::abi; use syntax::ast::{Attribute, Name, NodeId}; @@ -50,7 +48,7 @@ pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; } /// Components shared by fn-like things (fn items, methods, closures). pub struct FnParts<'a> { pub decl: &'a FnDecl, - pub body: &'a Block, + pub body: &'a Expr, pub kind: FnKind<'a>, pub span: Span, pub id: NodeId, @@ -77,29 +75,32 @@ impl MaybeFnLike for ast::Expr { } } -/// Carries either an FnLikeNode or a Block, as these are the two +/// Carries either an FnLikeNode or a Expr, as these are the two /// constructs that correspond to "code" (as in, something from which /// we can construct a control-flow graph). #[derive(Copy, Clone)] pub enum Code<'a> { - FnLikeCode(FnLikeNode<'a>), - BlockCode(&'a Block), + FnLike(FnLikeNode<'a>), + Expr(&'a Expr), } impl<'a> Code<'a> { pub fn id(&self) -> NodeId { match *self { - FnLikeCode(node) => node.id(), - BlockCode(block) => block.id, + Code::FnLike(node) => node.id(), + Code::Expr(block) => block.id, } } - /// Attempts to construct a Code from presumed FnLike or Block node input. - pub fn from_node(node: Node) -> Option { - if let map::NodeBlock(block) = node { - Some(BlockCode(block)) - } else { - FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like)) + /// Attempts to construct a Code from presumed FnLike or Expr node input. + pub fn from_node(map: &map::Map<'a>, id: NodeId) -> Option> { + match map.get(id) { + map::NodeBlock(_) => { + // Use the parent, hopefully an expression node. + Code::from_node(map, map.get_parent_node(id)) + } + map::NodeExpr(expr) => Some(Code::Expr(expr)), + node => FnLikeNode::from_node(node).map(Code::FnLike) } } } @@ -114,7 +115,7 @@ struct ItemFnParts<'a> { abi: abi::Abi, vis: &'a ast::Visibility, generics: &'a ast::Generics, - body: &'a Block, + body: &'a Expr, id: NodeId, span: Span, attrs: &'a [Attribute], @@ -124,14 +125,14 @@ struct ItemFnParts<'a> { /// for use when implementing FnLikeNode operations. struct ClosureParts<'a> { decl: &'a FnDecl, - body: &'a Block, + body: &'a Expr, id: NodeId, span: Span, attrs: &'a [Attribute], } impl<'a> ClosureParts<'a> { - fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self { + fn new(d: &'a FnDecl, b: &'a Expr, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self { ClosureParts { decl: d, body: b, @@ -171,9 +172,9 @@ impl<'a> FnLikeNode<'a> { } } - pub fn body(self) -> &'a Block { + pub fn body(self) -> &'a Expr { self.handle(|i: ItemFnParts<'a>| &*i.body, - |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _, _| body, + |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Expr, _, _| body, |c: ClosureParts<'a>| c.body) } @@ -214,7 +215,7 @@ impl<'a> FnLikeNode<'a> { Name, &'a ast::MethodSig, Option<&'a ast::Visibility>, - &'a ast::Block, + &'a ast::Expr, Span, &'a [Attribute]) -> A, diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 3d9031a136e2..04fcf7e84508 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -211,7 +211,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { } fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl, - b: &'ast Block, s: Span, id: NodeId) { + b: &'ast Expr, s: Span, id: NodeId) { assert_eq!(self.parent_node, id); intravisit::walk_fn(self, fk, fd, b, s, id); } @@ -226,4 +226,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) { self.insert(lifetime.id, NodeLifetime(lifetime)); } + + fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { + self.insert_entry(macro_def.id, NotPresent); + } } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index e8b3714bbe3b..38157c7e5656 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -9,7 +9,7 @@ // except according to those terms. use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use std::fmt::Write; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; @@ -22,7 +22,7 @@ use util::nodemap::NodeMap; #[derive(Clone)] pub struct Definitions { data: Vec, - key_map: FnvHashMap, + key_map: FxHashMap, node_map: NodeMap, } @@ -219,7 +219,7 @@ impl Definitions { pub fn new() -> Definitions { Definitions { data: vec![], - key_map: FnvHashMap(), + key_map: FxHashMap(), node_map: NodeMap(), } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c451a789193a..6b5b8101a146 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -33,7 +33,7 @@ pub use self::PathParameters::*; use hir::def::Def; use hir::def_id::DefId; -use util::nodemap::{NodeMap, FnvHashSet}; +use util::nodemap::{NodeMap, FxHashSet}; use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP}; use syntax::codemap::{self, respan, Spanned}; @@ -840,8 +840,8 @@ pub enum UnsafeSource { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Expr { pub id: NodeId, - pub node: Expr_, pub span: Span, + pub node: Expr_, pub attrs: ThinVec, } @@ -904,7 +904,7 @@ pub enum Expr_ { /// A closure (for example, `move |a, b, c| {a + b + c}`). /// /// The final span is the span of the argument block `|...|` - ExprClosure(CaptureClause, P, P, Span), + ExprClosure(CaptureClause, P, P, Span), /// A block (`{ ... }`) ExprBlock(P), @@ -946,7 +946,7 @@ pub enum Expr_ { /// /// For example, `Foo {x: 1, y: 2}`, or /// `Foo {x: 1, .. base}`, where `base` is the `Option`. - ExprStruct(Path, HirVec, Option>), + ExprStruct(P, HirVec, Option>), /// An array literal constructed from one repeated element. /// @@ -1035,7 +1035,7 @@ pub enum TraitItem_ { /// must contain a value) ConstTraitItem(P, Option>), /// A method with an optional body - MethodTraitItem(MethodSig, Option>), + MethodTraitItem(MethodSig, Option>), /// An associated type with (possibly empty) bounds and optional concrete /// type TypeTraitItem(TyParamBounds, Option>), @@ -1060,7 +1060,7 @@ pub enum ImplItemKind { /// of the expression Const(P, P), /// A method implementation with the given signature and body - Method(MethodSig, P), + Method(MethodSig, P), /// An associated type Type(P), } @@ -1501,7 +1501,7 @@ pub enum Item_ { /// A `const` item ItemConst(P, P), /// A function declaration - ItemFn(P, Unsafety, Constness, Abi, Generics, P), + ItemFn(P, Unsafety, Constness, Abi, Generics, P), /// A module ItemMod(Mod), /// An external module @@ -1605,4 +1605,4 @@ pub type TraitMap = NodeMap>; // Map from the NodeId of a glob import to a list of items which are actually // imported. -pub type GlobMap = NodeMap>; +pub type GlobMap = NodeMap>; diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 657c10bab12e..2c4ffb853c1f 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -713,7 +713,9 @@ impl<'a> State<'a> { typarams, &item.vis)?; word(&mut self.s, " ")?; - self.print_block_with_attrs(&body, &item.attrs)?; + self.end()?; // need to close a box + self.end()?; // need to close a box + self.print_expr(&body)?; } hir::ItemMod(ref _mod) => { self.head(&visibility_qualified(&item.vis, "mod"))?; @@ -1002,7 +1004,9 @@ impl<'a> State<'a> { self.print_method_sig(ti.name, sig, &hir::Inherited)?; if let Some(ref body) = *body { self.nbsp()?; - self.print_block_with_attrs(body, &ti.attrs)?; + self.end()?; // need to close a box + self.end()?; // need to close a box + self.print_expr(body)?; } else { word(&mut self.s, ";")?; } @@ -1034,7 +1038,9 @@ impl<'a> State<'a> { self.head("")?; self.print_method_sig(ii.name, sig, &ii.vis)?; self.nbsp()?; - self.print_block_with_attrs(body, &ii.attrs)?; + self.end()?; // need to close a box + self.end()?; // need to close a box + self.print_expr(body)?; } hir::ImplItemKind::Type(ref ty) => { self.print_associated_type(ii.name, None, Some(ty))?; @@ -1402,26 +1408,10 @@ impl<'a> State<'a> { self.print_fn_block_args(&decl)?; space(&mut self.s)?; - let default_return = match decl.output { - hir::DefaultReturn(..) => true, - _ => false, - }; + // this is a bare expression + self.print_expr(body)?; + self.end()?; // need to close a box - if !default_return || !body.stmts.is_empty() || body.expr.is_none() { - self.print_block_unclosed(&body)?; - } else { - // we extract the block, so as not to create another set of boxes - match body.expr.as_ref().unwrap().node { - hir::ExprBlock(ref blk) => { - self.print_block_unclosed(&blk)?; - } - _ => { - // this is a bare expression - self.print_expr(body.expr.as_ref().map(|e| &**e).unwrap())?; - self.end()?; // need to close a box - } - } - } // a box will be closed by print_expr, but we didn't want an overall // wrapper so we closed the corresponding opening. so create an // empty box to satisfy the close. diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 5e3925b0b3c9..47c0bc5fd60c 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -245,6 +245,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("report_region_errors: {} errors after preprocessing", errors.len()); for error in errors { + debug!("report_region_errors: error = {:?}", error); match error.clone() { ConcreteFailure(origin, sub, sup) => { self.report_concrete_failure(origin, sub, sup).emit(); @@ -299,44 +300,64 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut bound_failures = Vec::new(); for error in errors { + // Check whether we can process this error into some other + // form; if not, fall through. match *error { ConcreteFailure(ref origin, sub, sup) => { debug!("processing ConcreteFailure"); - match free_regions_from_same_fn(self.tcx, sub, sup) { - Some(ref same_frs) => { - origins.push( - ProcessedErrorOrigin::ConcreteFailure( - origin.clone(), - sub, - sup)); - append_to_same_regions(&mut same_regions, same_frs); - } - _ => { - other_errors.push(error.clone()); - } + if let SubregionOrigin::CompareImplMethodObligation { .. } = *origin { + // When comparing an impl method against a + // trait method, it is not helpful to suggest + // changes to the impl method. This is + // because the impl method signature is being + // checked using the trait's environment, so + // usually the changes we suggest would + // actually have to be applied to the *trait* + // method (and it's not clear that the trait + // method is even under the user's control). + } else if let Some(same_frs) = free_regions_from_same_fn(self.tcx, sub, sup) { + origins.push( + ProcessedErrorOrigin::ConcreteFailure( + origin.clone(), + sub, + sup)); + append_to_same_regions(&mut same_regions, &same_frs); + continue; } } - SubSupConflict(ref var_origin, _, sub_r, _, sup_r) => { - debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub_r, sup_r); - match free_regions_from_same_fn(self.tcx, sub_r, sup_r) { - Some(ref same_frs) => { - origins.push( - ProcessedErrorOrigin::VariableFailure( - var_origin.clone())); - append_to_same_regions(&mut same_regions, same_frs); + SubSupConflict(ref var_origin, ref sub_origin, sub, ref sup_origin, sup) => { + debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub, sup); + match (sub_origin, sup_origin) { + (&SubregionOrigin::CompareImplMethodObligation { .. }, _) => { + // As above, when comparing an impl method + // against a trait method, it is not helpful + // to suggest changes to the impl method. } - None => { - other_errors.push(error.clone()); + (_, &SubregionOrigin::CompareImplMethodObligation { .. }) => { + // See above. + } + _ => { + if let Some(same_frs) = free_regions_from_same_fn(self.tcx, sub, sup) { + origins.push( + ProcessedErrorOrigin::VariableFailure( + var_origin.clone())); + append_to_same_regions(&mut same_regions, &same_frs); + continue; + } } } } GenericBoundFailure(ref origin, ref kind, region) => { bound_failures.push((origin.clone(), kind.clone(), region)); + continue; } ProcessedErrors(..) => { bug!("should not encounter a `ProcessedErrors` yet: {:?}", error) } } + + // No changes to this error. + other_errors.push(error.clone()); } // ok, let's pull together the errors, sorted in an order that @@ -630,6 +651,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { format!("the associated type `{}`", p), }; + if let SubregionOrigin::CompareImplMethodObligation { + span, item_name, impl_item_def_id, trait_item_def_id, lint_id + } = origin { + self.report_extra_impl_obligation(span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", bound_kind, sub), + lint_id) + .emit(); + return; + } + let mut err = match *sub { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { // Does the required lifetime have a nice name we can print? @@ -947,6 +981,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ""); err } + infer::CompareImplMethodObligation { span, + item_name, + impl_item_def_id, + trait_item_def_id, + lint_id } => { + self.report_extra_impl_obligation(span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}: {}`", sup, sub), + lint_id) + } } } @@ -1792,6 +1838,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "...so that references are valid when the destructor \ runs"); } + infer::CompareImplMethodObligation { span, .. } => { + err.span_note( + span, + "...so that the definition in impl matches the definition from the trait"); + } } } } diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 828f9f32baac..30e18a4c569b 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -32,7 +32,7 @@ use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::fold::TypeFolder; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use std::collections::hash_map::Entry; use super::InferCtxt; @@ -41,7 +41,7 @@ use super::unify_key::ToType; pub struct TypeFreshener<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, freshen_count: u32, - freshen_map: FnvHashMap>, + freshen_map: FxHashMap>, } impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { @@ -50,7 +50,7 @@ impl<'a, 'gcx, 'tcx> TypeFreshener<'a, 'gcx, 'tcx> { TypeFreshener { infcx: infcx, freshen_count: 0, - freshen_map: FnvHashMap(), + freshen_map: FxHashMap(), } } diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 25b899b3c56c..737ce8bdf681 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -24,7 +24,7 @@ use ty::{self, TyCtxt, Binder, TypeFoldable}; use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; use syntax_pos::Span; -use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::nodemap::{FxHashMap, FxHashSet}; pub struct HrMatchResult { pub value: U, @@ -135,7 +135,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Map each skolemized region to a vector of other regions that it // must be equated with. (Note that this vector may include other // skolemized regions from `skol_map`.) - let skol_resolution_map: FnvHashMap<_, _> = + let skol_resolution_map: FxHashMap<_, _> = skol_map .iter() .map(|(&br, &skol)| { @@ -158,7 +158,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // `skol_map`. There should always be a representative if things // are properly well-formed. let mut unconstrained_regions = vec![]; - let skol_representatives: FnvHashMap<_, _> = + let skol_representatives: FxHashMap<_, _> = skol_resolution_map .iter() .map(|(&skol, &(br, ref regions))| { @@ -268,7 +268,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &FnvHashMap, + a_map: &FxHashMap, r0: &'tcx ty::Region) -> &'tcx ty::Region { // Regions that pre-dated the LUB computation stay as they are. @@ -364,8 +364,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &FnvHashMap, + a_map: &FxHashMap, a_vars: &[ty::RegionVid], b_vars: &[ty::RegionVid], r0: &'tcx ty::Region) @@ -434,7 +433,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span, - a_map: &FnvHashMap, + a_map: &FxHashMap, r: &'tcx ty::Region) -> &'tcx ty::Region { for (a_br, a_r) in a_map { @@ -457,7 +456,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, - map: &FnvHashMap) + map: &FxHashMap) -> Vec { map.iter() .map(|(_, &r)| match *r { @@ -504,7 +503,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, r: &'tcx ty::Region, directions: TaintDirections) - -> FnvHashSet<&'tcx ty::Region> { + -> FxHashSet<&'tcx ty::Region> { self.region_vars.tainted(&snapshot.region_vars_snapshot, r, directions) } @@ -568,7 +567,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let escaping_types = self.type_variables.borrow_mut().types_escaping_snapshot(&snapshot.type_snapshot); - let mut escaping_region_vars = FnvHashSet(); + let mut escaping_region_vars = FxHashSet(); for ty in &escaping_types { self.tcx.collect_regions(ty, &mut escaping_region_vars); } @@ -764,7 +763,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // region back to the `ty::BoundRegion` that it originally // represented. Because `leak_check` passed, we know that // these taint sets are mutually disjoint. - let inv_skol_map: FnvHashMap<&'tcx ty::Region, ty::BoundRegion> = + let inv_skol_map: FxHashMap<&'tcx ty::Region, ty::BoundRegion> = skol_map .iter() .flat_map(|(&skol_br, &skol)| { @@ -837,7 +836,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot) { debug!("pop_skolemized({:?})", skol_map); - let skol_regions: FnvHashSet<_> = skol_map.values().cloned().collect(); + let skol_regions: FxHashSet<_> = skol_map.values().cloned().collect(); self.region_vars.pop_skolemized(&skol_regions, &snapshot.region_vars_snapshot); if !skol_map.is_empty() { self.projection_cache.borrow_mut().rollback_skolemized( diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 4c097965bb06..ebafd206e26e 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -39,7 +39,7 @@ use std::fmt; use syntax::ast; use errors::DiagnosticBuilder; use syntax_pos::{self, Span, DUMMY_SP}; -use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap}; +use util::nodemap::{FxHashMap, FxHashSet, NodeMap}; use self::combine::CombineFields; use self::higher_ranked::HrMatchResult; @@ -134,7 +134,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // the set of predicates on which errors have been reported, to // avoid reporting the same error twice. - pub reported_trait_errors: RefCell>>, + pub reported_trait_errors: RefCell>>, // Sadly, the behavior of projection varies a bit depending on the // stage of compilation. The specifics are given in the @@ -170,7 +170,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// region that each late-bound region was replaced with. -pub type SkolemizationMap<'tcx> = FnvHashMap; +pub type SkolemizationMap<'tcx> = FxHashMap; /// Why did we require that the two types be related? /// @@ -355,6 +355,19 @@ pub enum SubregionOrigin<'tcx> { // Region constraint arriving from destructor safety SafeDestructor(Span), + + // Comparing the signature and requirements of an impl method against + // the containing trait. + CompareImplMethodObligation { + span: Span, + item_name: ast::Name, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + + // this is `Some(_)` if this error arises from the bug fix for + // #18937. This is a temporary measure. + lint_id: Option, + }, } /// Places that type/region parameters can appear. @@ -479,7 +492,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), projection_cache: RefCell::new(traits::ProjectionCache::new()), - reported_trait_errors: RefCell::new(FnvHashSet()), + reported_trait_errors: RefCell::new(FxHashSet()), projection_mode: Reveal::NotSpecializable, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), @@ -518,7 +531,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { parameter_environment: param_env, selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), - reported_trait_errors: RefCell::new(FnvHashSet()), + reported_trait_errors: RefCell::new(FxHashSet()), projection_mode: projection_mode, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), @@ -1056,7 +1069,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.probe(|_| { let origin = TypeOrigin::Misc(syntax_pos::DUMMY_SP); let trace = TypeTrace::types(origin, true, a, b); - self.sub(true, trace, &a, &b).map(|_| ()) + self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }) }) } @@ -1147,16 +1163,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn region_outlives_predicate(&self, - span: Span, + cause: &traits::ObligationCause<'tcx>, predicate: &ty::PolyRegionOutlivesPredicate<'tcx>) -> UnitResult<'tcx> { self.commit_if_ok(|snapshot| { let (ty::OutlivesPredicate(r_a, r_b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); - let origin = RelateRegionParamBound(span); + let origin = + SubregionOrigin::from_obligation_cause(cause, + || RelateRegionParamBound(cause.span)); self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` - self.leak_check(false, span, &skol_map, snapshot)?; + self.leak_check(false, cause.span, &skol_map, snapshot)?; Ok(self.pop_skolemized(skol_map, snapshot)) }) } @@ -1251,26 +1269,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.region_vars.new_bound(debruijn) } - /// Apply `adjustment` to the type of `expr` - pub fn adjust_expr_ty(&self, - expr: &hir::Expr, - adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) - -> Ty<'tcx> - { - let raw_ty = self.expr_ty(expr); - let raw_ty = self.shallow_resolve(raw_ty); - let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty); - raw_ty.adjust(self.tcx, - expr.span, - expr.id, - adjustment, - |method_call| self.tables - .borrow() - .method_map - .get(&method_call) - .map(|method| resolve_ty(method.ty))) - } - /// True if errors have been reported since this infcx was /// created. This is sometimes used as a heuristic to skip /// reporting errors that often occur as a result of earlier @@ -1532,7 +1530,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, lbrct: LateBoundRegionConversionTime, value: &ty::Binder) - -> (T, FnvHashMap) + -> (T, FxHashMap) where T : TypeFoldable<'tcx> { self.tcx.replace_late_bound_regions( @@ -1597,8 +1595,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // anyhow. We should make this typetrace stuff more // generic so we don't have to do anything quite this // terrible. - self.equate(true, TypeTrace::dummy(self.tcx), a, b) - }).map(|_| ()) + let trace = TypeTrace::dummy(self.tcx); + self.equate(true, trace, a, b).map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }) + }) } pub fn node_ty(&self, id: ast::NodeId) -> McResult> { @@ -1607,7 +1609,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { - let ty = self.adjust_expr_ty(expr, self.tables.borrow().adjustments.get(&expr.id)); + let ty = self.tables.borrow().expr_ty_adjusted(expr); self.resolve_type_vars_or_error(&ty) } @@ -1651,9 +1653,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .map(|method| method.def_id) } - pub fn adjustments(&self) -> Ref>> { + pub fn adjustments(&self) -> Ref>> { fn project_adjustments<'a, 'tcx>(tables: &'a ty::Tables<'tcx>) - -> &'a NodeMap> { + -> &'a NodeMap> { &tables.adjustments } @@ -1786,6 +1788,32 @@ impl<'tcx> SubregionOrigin<'tcx> { AddrOf(a) => a, AutoBorrow(a) => a, SafeDestructor(a) => a, + CompareImplMethodObligation { span, .. } => span, + } + } + + pub fn from_obligation_cause(cause: &traits::ObligationCause<'tcx>, + default: F) + -> Self + where F: FnOnce() -> Self + { + match cause.code { + traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => + SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span), + + traits::ObligationCauseCode::CompareImplMethodObligation { item_name, + impl_item_def_id, + trait_item_def_id, + lint_id } => + SubregionOrigin::CompareImplMethodObligation { + span: cause.span, + item_name: item_name, + impl_item_def_id: impl_item_def_id, + trait_item_def_id: trait_item_def_id, + lint_id: lint_id, + }, + + _ => default(), } } } diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index 289f7d6c7380..95ce8d39ff48 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -23,7 +23,7 @@ use middle::region::CodeExtent; use super::Constraint; use infer::SubregionOrigin; use infer::region_inference::RegionVarBindings; -use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::nodemap::{FxHashMap, FxHashSet}; use std::borrow::Cow; use std::collections::hash_map::Entry::Vacant; @@ -122,8 +122,8 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, graph_name: String, - map: &'a FnvHashMap, SubregionOrigin<'tcx>>, - node_ids: FnvHashMap, + map: &'a FxHashMap, SubregionOrigin<'tcx>>, + node_ids: FxHashMap, } #[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)] @@ -145,7 +145,7 @@ impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> { map: &'a ConstraintMap<'tcx>) -> ConstraintGraph<'a, 'gcx, 'tcx> { let mut i = 0; - let mut node_ids = FnvHashMap(); + let mut node_ids = FxHashMap(); { let mut add_node = |node| { if let Vacant(e) = node_ids.entry(node) { @@ -235,7 +235,7 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { type Node = Node; type Edge = Edge<'tcx>; fn nodes(&self) -> dot::Nodes { - let mut set = FnvHashSet(); + let mut set = FxHashSet(); for node in self.node_ids.keys() { set.insert(*node); } @@ -261,7 +261,7 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { } } -pub type ConstraintMap<'tcx> = FnvHashMap, SubregionOrigin<'tcx>>; +pub type ConstraintMap<'tcx> = FxHashMap, SubregionOrigin<'tcx>>; fn dump_region_constraints_to<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, map: &ConstraintMap<'tcx>, diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index ef36ffa83192..af6f2c50e72f 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -19,7 +19,7 @@ pub use self::VarValue::*; use super::{RegionVariableOrigin, SubregionOrigin, MiscVariable}; use super::unify_key; -use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING}; use rustc_data_structures::unify::{self, UnificationTable}; use middle::free_region::FreeRegionMap; @@ -213,7 +213,7 @@ impl SameRegions { } } -pub type CombineMap<'tcx> = FnvHashMap, RegionVid>; +pub type CombineMap<'tcx> = FxHashMap, RegionVid>; pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, @@ -222,7 +222,7 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // Constraints of the form `A <= B` introduced by the region // checker. Here at least one of `A` and `B` must be a region // variable. - constraints: RefCell, SubregionOrigin<'tcx>>>, + constraints: RefCell, SubregionOrigin<'tcx>>>, // A "verify" is something that we need to verify after inference is // done, but which does not directly affect inference in any way. @@ -248,7 +248,7 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // record the fact that `'a <= 'b` is implied by the fn signature, // and then ignore the constraint when solving equations. This is // a bit of a hack but seems to work. - givens: RefCell>, + givens: RefCell>, lubs: RefCell>, glbs: RefCell>, @@ -305,14 +305,14 @@ impl TaintDirections { struct TaintSet<'tcx> { directions: TaintDirections, - regions: FnvHashSet<&'tcx ty::Region> + regions: FxHashSet<&'tcx ty::Region> } impl<'a, 'gcx, 'tcx> TaintSet<'tcx> { fn new(directions: TaintDirections, initial_region: &'tcx ty::Region) -> Self { - let mut regions = FnvHashSet(); + let mut regions = FxHashSet(); regions.insert(initial_region); TaintSet { directions: directions, regions: regions } } @@ -362,7 +362,7 @@ impl<'a, 'gcx, 'tcx> TaintSet<'tcx> { } } - fn into_set(self) -> FnvHashSet<&'tcx ty::Region> { + fn into_set(self) -> FxHashSet<&'tcx ty::Region> { self.regions } @@ -393,11 +393,11 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { tcx: tcx, var_origins: RefCell::new(Vec::new()), values: RefCell::new(None), - constraints: RefCell::new(FnvHashMap()), + constraints: RefCell::new(FxHashMap()), verifys: RefCell::new(Vec::new()), - givens: RefCell::new(FnvHashSet()), - lubs: RefCell::new(FnvHashMap()), - glbs: RefCell::new(FnvHashMap()), + givens: RefCell::new(FxHashSet()), + lubs: RefCell::new(FxHashMap()), + glbs: RefCell::new(FxHashMap()), skolemization_count: Cell::new(0), bound_count: Cell::new(0), undo_log: RefCell::new(Vec::new()), @@ -547,7 +547,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// completes to remove all trace of the skolemized regions /// created in that time. pub fn pop_skolemized(&self, - skols: &FnvHashSet<&'tcx ty::Region>, + skols: &FxHashSet<&'tcx ty::Region>, snapshot: &RegionSnapshot) { debug!("pop_skolemized_regions(skols={:?})", skols); @@ -601,7 +601,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { self.skolemization_count.set(snapshot.skolemization_count); return; - fn kill_constraint<'tcx>(skols: &FnvHashSet<&'tcx ty::Region>, + fn kill_constraint<'tcx>(skols: &FxHashSet<&'tcx ty::Region>, undo_entry: &UndoLogEntry<'tcx>) -> bool { match undo_entry { @@ -905,7 +905,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { mark: &RegionSnapshot, r0: &'tcx Region, directions: TaintDirections) - -> FnvHashSet<&'tcx ty::Region> { + -> FxHashSet<&'tcx ty::Region> { debug!("tainted(mark={:?}, r0={:?}, directions={:?})", mark, r0, directions); @@ -1414,13 +1414,13 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { dup_vec: &mut [u32]) -> (Vec>, bool) { struct WalkState<'tcx> { - set: FnvHashSet, + set: FxHashSet, stack: Vec, result: Vec>, dup_found: bool, } let mut state = WalkState { - set: FnvHashSet(), + set: FxHashSet(), stack: vec![orig_node_idx], result: Vec::new(), dup_found: false, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d17402d21342..fa49e5c72895 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -31,7 +31,7 @@ #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(enumset)] #![feature(libc)] #![feature(nonzero)] diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 3472c77cf422..82a46f76401d 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -198,6 +198,12 @@ declare_lint! { "patterns in functions without body were erroneously allowed" } +declare_lint! { + pub EXTRA_REQUIREMENT_IN_IMPL, + Warn, + "detects extra requirements in impls that were erroneously allowed" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -235,7 +241,8 @@ impl LintPass for HardwiredLints { HR_LIFETIME_IN_ASSOC_TYPE, LIFETIME_UNDERSCORE, SAFE_EXTERN_STATICS, - PATTERNS_IN_FNS_WITHOUT_BODY + PATTERNS_IN_FNS_WITHOUT_BODY, + EXTRA_REQUIREMENT_IN_IMPL ) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 20463f42d3b1..f44f82860077 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -33,16 +33,17 @@ use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource}; use lint::{EarlyLintPassObject, LateLintPassObject}; use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}; use lint::builtin; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use std::cmp; use std::default::Default as StdDefault; use std::mem; +use std::fmt; use syntax::attr; use syntax::parse::token::InternedString; use syntax::ast; -use syntax_pos::Span; -use errors::DiagnosticBuilder; +use syntax_pos::{MultiSpan, Span}; +use errors::{self, Diagnostic, DiagnosticBuilder}; use hir; use hir::intravisit as hir_visit; use syntax::visit as ast_visit; @@ -63,23 +64,63 @@ pub struct LintStore { late_passes: Option>, /// Lints indexed by name. - by_name: FnvHashMap, + by_name: FxHashMap, /// Current levels of each lint, and where they were set. - levels: FnvHashMap, + levels: FxHashMap, /// Map of registered lint groups to what lints they expand to. The bool /// is true if the lint group was added by a plugin. - lint_groups: FnvHashMap<&'static str, (Vec, bool)>, + lint_groups: FxHashMap<&'static str, (Vec, bool)>, /// Extra info for future incompatibility lints, descibing the /// issue or RFC that caused the incompatibility. - future_incompatible: FnvHashMap, + future_incompatible: FxHashMap, /// Maximum level a lint can be lint_cap: Option, } +/// When you call `add_lint` on the session, you wind up storing one +/// of these, which records a "potential lint" at a particular point. +#[derive(PartialEq)] +pub struct EarlyLint { + /// what lint is this? (e.g., `dead_code`) + pub id: LintId, + + /// the main message + pub diagnostic: Diagnostic, +} + +impl fmt::Debug for EarlyLint { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("EarlyLint") + .field("id", &self.id) + .field("span", &self.diagnostic.span) + .field("diagnostic", &self.diagnostic) + .finish() + } +} + +pub trait IntoEarlyLint { + fn into_early_lint(self, id: LintId) -> EarlyLint; +} + +impl<'a> IntoEarlyLint for (Span, &'a str) { + fn into_early_lint(self, id: LintId) -> EarlyLint { + let (span, msg) = self; + let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg); + diagnostic.set_span(span); + EarlyLint { id: id, diagnostic: diagnostic } + } +} + +impl IntoEarlyLint for Diagnostic { + fn into_early_lint(self, id: LintId) -> EarlyLint { + EarlyLint { id: id, diagnostic: self } + } +} + /// Extra information for a future incompatibility lint. See the call /// to `register_future_incompatible` in `librustc_lint/lib.rs` for /// guidelines. @@ -130,10 +171,10 @@ impl LintStore { lints: vec![], early_passes: Some(vec![]), late_passes: Some(vec![]), - by_name: FnvHashMap(), - levels: FnvHashMap(), - future_incompatible: FnvHashMap(), - lint_groups: FnvHashMap(), + by_name: FxHashMap(), + levels: FxHashMap(), + future_incompatible: FxHashMap(), + lint_groups: FxHashMap(), lint_cap: None, } } @@ -263,8 +304,8 @@ impl LintStore { Err(FindLintError::Removed) => { } Err(_) => { match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone())) - .collect::>>() + .collect::>>() .get(&lint_name[..]) { Some(v) => { v.iter() @@ -388,22 +429,24 @@ pub fn gather_attr(attr: &ast::Attribute) /// in trans that run after the main lint pass is finished. Most /// lints elsewhere in the compiler should call /// `Session::add_lint()` instead. -pub fn raw_emit_lint(sess: &Session, - lints: &LintStore, - lint: &'static Lint, - lvlsrc: LevelSource, - span: Option, - msg: &str) { +pub fn raw_emit_lint>(sess: &Session, + lints: &LintStore, + lint: &'static Lint, + lvlsrc: LevelSource, + span: Option, + msg: &str) { raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit(); } -pub fn raw_struct_lint<'a>(sess: &'a Session, - lints: &LintStore, - lint: &'static Lint, - lvlsrc: LevelSource, - span: Option, - msg: &str) - -> DiagnosticBuilder<'a> { +pub fn raw_struct_lint<'a, S>(sess: &'a Session, + lints: &LintStore, + lint: &'static Lint, + lvlsrc: LevelSource, + span: Option, + msg: &str) + -> DiagnosticBuilder<'a> + where S: Into +{ let (mut level, source) = lvlsrc; if level == Allow { return sess.diagnostic().struct_dummy(); @@ -496,11 +539,11 @@ pub trait LintContext: Sized { raw_emit_lint(&self.sess(), self.lints(), lint, (level, src), span, msg); } - fn lookup(&self, - lint: &'static Lint, - span: Option, - msg: &str) - -> DiagnosticBuilder { + fn lookup>(&self, + lint: &'static Lint, + span: Option, + msg: &str) + -> DiagnosticBuilder { let (level, src) = match self.level_src(lint) { None => return self.sess().diagnostic().struct_dummy(), Some(pair) => pair, @@ -514,11 +557,20 @@ pub trait LintContext: Sized { self.lookup_and_emit(lint, Some(span), msg); } - fn struct_span_lint(&self, - lint: &'static Lint, - span: Span, - msg: &str) - -> DiagnosticBuilder { + fn early_lint(&self, early_lint: EarlyLint) { + let span = early_lint.diagnostic.span.primary_span().expect("early lint w/o primary span"); + let mut err = self.struct_span_lint(early_lint.id.lint, + span, + &early_lint.diagnostic.message); + err.copy_details_not_message(&early_lint.diagnostic); + err.emit(); + } + + fn struct_span_lint>(&self, + lint: &'static Lint, + span: S, + msg: &str) + -> DiagnosticBuilder { self.lookup(lint, Some(span), msg) } @@ -786,7 +838,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { } fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl, - body: &'v hir::Block, span: Span, id: ast::NodeId) { + body: &'v hir::Expr, span: Span, id: ast::NodeId) { run_lints!(self, check_fn, late_passes, fk, decl, body, span, id); hir_visit::walk_fn(self, fk, decl, body, span, id); run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id); @@ -942,10 +994,10 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { } fn visit_fn(&mut self, fk: ast_visit::FnKind, decl: &ast::FnDecl, - body: &ast::Block, span: Span, id: ast::NodeId) { - run_lints!(self, check_fn, early_passes, fk, decl, body, span, id); - ast_visit::walk_fn(self, fk, decl, body, span); - run_lints!(self, check_fn_post, early_passes, fk, decl, body, span, id); + span: Span, id: ast::NodeId) { + run_lints!(self, check_fn, early_passes, fk, decl, span, id); + ast_visit::walk_fn(self, fk, decl, span); + run_lints!(self, check_fn_post, early_passes, fk, decl, span, id); } fn visit_variant_data(&mut self, @@ -1065,8 +1117,8 @@ impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> { fn visit_id(&mut self, id: ast::NodeId) { if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) { debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints); - for (lint_id, span, msg) in lints { - self.cx.span_lint(lint_id.lint, span, &msg[..]) + for early_lint in lints { + self.cx.early_lint(early_lint); } } } @@ -1211,10 +1263,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // If we missed any lints added to the session, then there's a bug somewhere // in the iteration code. for (id, v) in tcx.sess.lints.borrow().iter() { - for &(lint, span, ref msg) in v { - span_bug!(span, - "unprocessed lint {} at {}: {}", - lint.to_string(), tcx.map.node_to_string(*id), *msg) + for early_lint in v { + span_bug!(early_lint.diagnostic.span.clone(), + "unprocessed lint {:?} at {}", + early_lint, tcx.map.node_to_string(*id)); } } @@ -1229,8 +1281,8 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { cx.with_lint_attrs(&krate.attrs, |cx| { // Lints may be assigned to the whole crate. if let Some(lints) = cx.sess.lints.borrow_mut().remove(&ast::CRATE_NODE_ID) { - for (lint_id, span, msg) in lints { - cx.span_lint(lint_id.lint, span, &msg[..]) + for early_lint in lints { + cx.early_lint(early_lint); } } @@ -1249,8 +1301,8 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { // If we missed any lints added to the session, then there's a bug somewhere // in the iteration code. for (_, v) in sess.lints.borrow().iter() { - for &(lint, span, ref msg) in v { - span_bug!(span, "unprocessed lint {}: {}", lint.to_string(), *msg) + for early_lint in v { + span_bug!(early_lint.diagnostic.span.clone(), "unprocessed lint {:?}", early_lint); } } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 7eea6a2fcf27..6f7102229f8d 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -41,7 +41,7 @@ use hir; pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, raw_emit_lint, check_crate, check_ast_crate, gather_attrs, - raw_struct_lint, FutureIncompatibleInfo}; + raw_struct_lint, FutureIncompatibleInfo, EarlyLint, IntoEarlyLint}; /// Specification of a single lint. #[derive(Copy, Clone, Debug)] @@ -151,9 +151,9 @@ pub trait LateLintPass: LintPass { fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { } fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { } fn check_fn(&mut self, _: &LateContext, - _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { } + _: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { } fn check_fn_post(&mut self, _: &LateContext, - _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { } + _: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { } fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { } fn check_trait_item_post(&mut self, _: &LateContext, _: &hir::TraitItem) { } fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { } @@ -200,9 +200,9 @@ pub trait EarlyLintPass: LintPass { fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { } fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { } fn check_fn(&mut self, _: &EarlyContext, - _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { } + _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { } fn check_fn_post(&mut self, _: &EarlyContext, - _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { } + _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { } fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { } fn check_trait_item_post(&mut self, _: &EarlyContext, _: &ast::TraitItem) { } fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 59a5147ed1c1..3583ccdb97ba 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -34,6 +34,7 @@ use session::Session; use session::search_paths::PathKind; use util::nodemap::{NodeSet, DefIdMap}; use std::path::PathBuf; +use std::rc::Rc; use syntax::ast; use syntax::attr; use syntax::ext::base::SyntaxExtension; @@ -61,7 +62,18 @@ pub struct LinkMeta { pub struct CrateSource { pub dylib: Option<(PathBuf, PathKind)>, pub rlib: Option<(PathBuf, PathKind)>, - pub cnum: CrateNum, +} + +#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] +pub enum DepKind { + /// A dependency that is only used for its macros. + MacrosOnly, + /// A dependency that is always injected into the dependency list and so + /// doesn't need to be linked to an rlib, e.g. the injected allocator. + Implicit, + /// A dependency that is required by an rlib version of this crate. + /// Ordinary `extern crate`s result in `Explicit` dependencies. + Explicit, } #[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)] @@ -95,6 +107,11 @@ pub enum InlinedItemRef<'a> { ImplItem(DefId, &'a hir::ImplItem) } +pub enum LoadedMacro { + MacroRules(ast::MacroDef), + ProcMacro(Rc), +} + #[derive(Copy, Clone, Debug)] pub struct ExternCrate { /// def_id of an `extern crate` in the current crate that caused @@ -147,7 +164,7 @@ pub trait CrateStore<'tcx> { fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info - fn impl_or_trait_items(&self, def_id: DefId) -> Vec; + fn associated_item_def_ids(&self, def_id: DefId) -> Vec; fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option>; fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity; @@ -157,8 +174,8 @@ pub trait CrateStore<'tcx> { // trait/impl-item info fn trait_of_item(&self, def_id: DefId) -> Option; - fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option>; + fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> Option; // flags fn is_const_fn(&self, did: DefId) -> bool; @@ -170,10 +187,10 @@ pub trait CrateStore<'tcx> { // crate metadata fn dylib_dependency_formats(&self, cnum: CrateNum) -> Vec<(CrateNum, LinkagePreference)>; + fn dep_kind(&self, cnum: CrateNum) -> DepKind; fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>; fn missing_lang_items(&self, cnum: CrateNum) -> Vec; fn is_staged_api(&self, cnum: CrateNum) -> bool; - fn is_explicitly_linked(&self, cnum: CrateNum) -> bool; fn is_allocator(&self, cnum: CrateNum) -> bool; fn is_panic_runtime(&self, cnum: CrateNum) -> bool; fn is_compiler_builtins(&self, cnum: CrateNum) -> bool; @@ -200,6 +217,7 @@ pub trait CrateStore<'tcx> { fn relative_def_path(&self, def: DefId) -> Option; fn struct_field_names(&self, def: DefId) -> Vec; fn item_children(&self, did: DefId) -> Vec; + fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro; // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -311,8 +329,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { } // impl info - fn impl_or_trait_items(&self, def_id: DefId) -> Vec - { bug!("impl_or_trait_items") } + fn associated_item_def_ids(&self, def_id: DefId) -> Vec + { bug!("associated_items") } fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { bug!("impl_trait_ref") } fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") } @@ -323,8 +341,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // trait/impl-item info fn trait_of_item(&self, def_id: DefId) -> Option { bug!("trait_of_item") } - fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option> { bug!("impl_or_trait_item") } + fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> Option { bug!("associated_item") } // flags fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") } @@ -342,7 +360,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn missing_lang_items(&self, cnum: CrateNum) -> Vec { bug!("missing_lang_items") } fn is_staged_api(&self, cnum: CrateNum) -> bool { bug!("is_staged_api") } - fn is_explicitly_linked(&self, cnum: CrateNum) -> bool { bug!("is_explicitly_linked") } + fn dep_kind(&self, cnum: CrateNum) -> DepKind { bug!("is_explicitly_linked") } fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") } fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") } fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") } @@ -371,6 +389,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } + fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") } // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -410,22 +429,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } -pub enum LoadedMacros { - MacroRules(Vec), - ProcMacros(Vec<(ast::Name, SyntaxExtension)>), -} - -impl LoadedMacros { - pub fn is_proc_macros(&self) -> bool { - match *self { - LoadedMacros::ProcMacros(_) => true, - _ => false, - } - } -} - pub trait CrateLoader { - fn process_item(&mut self, item: &ast::Item, defs: &Definitions, load_macros: bool) - -> Option; + fn process_item(&mut self, item: &ast::Item, defs: &Definitions); fn postprocess(&mut self, krate: &ast::Crate); } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 7f3a58808c22..1ec3d0db8e0a 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -498,7 +498,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { // ^^^^^^^^^^^^^ only needed for pretty printing - pub fn propagate(&mut self, cfg: &cfg::CFG, blk: &hir::Block) { + pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Expr) { //! Performs the data flow analysis. if self.bits_per_id == 0 { @@ -524,17 +524,17 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { debug!("Dataflow result for {}:", self.analysis_name); debug!("{}", { let mut v = Vec::new(); - self.pretty_print_to(box &mut v, blk).unwrap(); + self.pretty_print_to(box &mut v, body).unwrap(); String::from_utf8(v).unwrap() }); } fn pretty_print_to<'b>(&self, wr: Box, - blk: &hir::Block) -> io::Result<()> { + body: &hir::Expr) -> io::Result<()> { let mut ps = pprust::rust_printer_annotated(wr, self, None); ps.cbox(pprust::indent_unit)?; ps.ibox(0)?; - ps.print_block(blk)?; + ps.print_expr(body)?; pp::eof(&mut ps.s) } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index dc634b08784a..23fc5911259d 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -22,7 +22,7 @@ use ty::{self, TyCtxt}; use hir::def::Def; use hir::def_id::{DefId}; use lint; -use util::nodemap::FnvHashSet; +use util::nodemap::FxHashSet; use syntax::{ast, codemap}; use syntax::attr; @@ -48,7 +48,7 @@ fn should_explore<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, struct MarkSymbolVisitor<'a, 'tcx: 'a> { worklist: Vec, tcx: TyCtxt<'a, 'tcx, 'tcx>, - live_symbols: Box>, + live_symbols: Box>, struct_has_extern_repr: bool, ignore_non_const_paths: bool, inherited_pub_visibility: bool, @@ -61,7 +61,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { MarkSymbolVisitor { worklist: worklist, tcx: tcx, - live_symbols: box FnvHashSet(), + live_symbols: box FxHashSet(), struct_has_extern_repr: false, ignore_non_const_paths: false, inherited_pub_visibility: false, @@ -92,7 +92,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { match def { Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_) if self.tcx.trait_of_item(def.def_id()).is_some() => { - if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { + if let Some(substs) = self.tcx.tables().item_substs.get(&id) { if let ty::TyAdt(tyid, _) = substs.substs.type_at(0).sty { self.check_def_id(tyid.did); } @@ -123,12 +123,12 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn lookup_and_handle_method(&mut self, id: ast::NodeId) { let method_call = ty::MethodCall::expr(id); - let method = self.tcx.tables.borrow().method_map[&method_call]; + let method = self.tcx.tables().method_map[&method_call]; self.check_def_id(method.def_id); } fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { - match self.tcx.expr_ty_adjusted(lhs).sty { + match self.tcx.tables().expr_ty_adjusted(lhs).sty { ty::TyAdt(def, _) => { self.insert_def_id(def.struct_variant().field_named(name).did); } @@ -137,7 +137,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) { - match self.tcx.expr_ty_adjusted(lhs).sty { + match self.tcx.tables().expr_ty_adjusted(lhs).sty { ty::TyAdt(def, _) => { self.insert_def_id(def.struct_variant().fields[idx].did); } @@ -148,7 +148,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, pats: &[codemap::Spanned]) { - let variant = match self.tcx.node_id_to_type(lhs.id).sty { + let variant = match self.tcx.tables().node_id_to_type(lhs.id).sty { ty::TyAdt(adt, _) => { adt.variant_of_def(self.tcx.expect_def(lhs.id)) } @@ -163,7 +163,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn mark_live_symbols(&mut self) { - let mut scanned = FnvHashSet(); + let mut scanned = FxHashSet(); while !self.worklist.is_empty() { let id = self.worklist.pop().unwrap(); if scanned.contains(&id) { @@ -396,7 +396,7 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &privacy::AccessLevels, krate: &hir::Crate) - -> Box> { + -> Box> { let worklist = create_and_seed_worklist(tcx, access_levels, krate); let mut symbol_visitor = MarkSymbolVisitor::new(tcx, worklist); symbol_visitor.mark_live_symbols(); @@ -414,7 +414,7 @@ fn get_struct_ctor_id(item: &hir::Item) -> Option { struct DeadVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - live_symbols: Box>, + live_symbols: Box>, } impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { @@ -433,7 +433,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool { - let field_type = self.tcx.node_id_to_type(field.id); + let field_type = self.tcx.tables().node_id_to_type(field.id); let is_marker_field = match field_type.ty_to_def_id() { Some(def_id) => self.tcx.lang_items.items().iter().any(|item| *item == Some(def_id)), _ => false @@ -471,11 +471,10 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { // This is done to handle the case where, for example, the static // method of a private type is used, but the type itself is never // called directly. - let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow(); if let Some(impl_list) = self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) { - for impl_did in impl_list.iter() { - for &item_did in &impl_items[impl_did][..] { + for &impl_did in impl_list.iter() { + for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] { if let Some(item_node_id) = self.tcx.map.as_local_node_id(item_did) { if self.live_symbols.contains(&item_node_id) { return true; @@ -567,7 +566,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { self.warn_dead_code(impl_item.id, impl_item.span, impl_item.name, "method"); } - intravisit::walk_block(self, body) + intravisit::walk_expr(self, body) } hir::ImplItemKind::Type(..) => {} } @@ -576,11 +575,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { // Overwrite so that we don't warn the trait item itself. fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { match trait_item.node { - hir::ConstTraitItem(_, Some(ref expr)) => { - intravisit::walk_expr(self, expr) - } + hir::ConstTraitItem(_, Some(ref body))| hir::MethodTraitItem(_, Some(ref body)) => { - intravisit::walk_block(self, body) + intravisit::walk_expr(self, body) } hir::ConstTraitItem(_, None) | hir::MethodTraitItem(_, None) | diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 656d3146fe5d..92d1ab85c5a0 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -65,8 +65,9 @@ use hir::def_id::CrateNum; use session; use session::config; +use middle::cstore::DepKind; use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic}; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use rustc_back::PanicStrategy; /// A list of dependencies for a certain crate type. @@ -80,7 +81,7 @@ pub type DependencyList = Vec; /// A mapping of all required dependencies for a particular flavor of output. /// /// This is local to the tcx, and is generally relevant to one session. -pub type Dependencies = FnvHashMap; +pub type Dependencies = FxHashMap; #[derive(Copy, Clone, PartialEq, Debug)] pub enum Linkage { @@ -123,6 +124,7 @@ fn calculate_type(sess: &session::Session, return v; } for cnum in sess.cstore.crates() { + if sess.cstore.dep_kind(cnum) == DepKind::MacrosOnly { continue } let src = sess.cstore.used_crate_source(cnum); if src.rlib.is_some() { continue } sess.err(&format!("dependency `{}` not found in rlib format", @@ -149,12 +151,13 @@ fn calculate_type(sess: &session::Session, config::CrateTypeProcMacro => {}, } - let mut formats = FnvHashMap(); + let mut formats = FxHashMap(); // Sweep all crates for found dylibs. Add all dylibs, as well as their // dependencies, ensuring there are no conflicts. The only valid case for a // dependency to be relied upon twice is for both cases to rely on a dylib. for cnum in sess.cstore.crates() { + if sess.cstore.dep_kind(cnum) == DepKind::MacrosOnly { continue } let name = sess.cstore.crate_name(cnum); let src = sess.cstore.used_crate_source(cnum); if src.dylib.is_some() { @@ -188,7 +191,7 @@ fn calculate_type(sess: &session::Session, let src = sess.cstore.used_crate_source(cnum); if src.dylib.is_none() && !formats.contains_key(&cnum) && - sess.cstore.is_explicitly_linked(cnum) { + sess.cstore.dep_kind(cnum) == DepKind::Explicit { assert!(src.rlib.is_some()); info!("adding staticlib: {}", sess.cstore.crate_name(cnum)); add_library(sess, cnum, RequireStatic, &mut formats); @@ -240,7 +243,7 @@ fn calculate_type(sess: &session::Session, fn add_library(sess: &session::Session, cnum: CrateNum, link: LinkagePreference, - m: &mut FnvHashMap) { + m: &mut FxHashMap) { match m.get(&cnum) { Some(&link2) => { // If the linkages differ, then we'd have two copies of the library @@ -272,7 +275,7 @@ fn attempt_static(sess: &session::Session) -> Option { // everything in explicitly so long as it's actually required. let last_crate = sess.cstore.crates().len(); let mut ret = (1..last_crate+1).map(|cnum| { - if sess.cstore.is_explicitly_linked(CrateNum::new(cnum)) { + if sess.cstore.dep_kind(CrateNum::new(cnum)) == DepKind::Explicit { Linkage::Static } else { Linkage::NotLinked diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 2a75b6620fd6..5634e2012c97 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_fn(&mut self, fn_kind: FnKind<'v>, fn_decl: &'v hir::FnDecl, - block: &'v hir::Block, span: Span, id: ast::NodeId) { + block: &'v hir::Expr, span: Span, id: ast::NodeId) { let (is_item_fn, is_unsafe_fn) = match fn_kind { FnKind::ItemFn(_, _, unsafety, ..) => @@ -159,7 +159,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { match expr.node { hir::ExprMethodCall(..) => { let method_call = MethodCall::expr(expr.id); - let base_type = self.tcx.tables.borrow().method_map[&method_call].ty; + let base_type = self.tcx.tables().method_map[&method_call].ty; debug!("effect: method call case, base type is {:?}", base_type); if type_is_unsafe_function(base_type) { @@ -168,7 +168,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprCall(ref base, _) => { - let base_type = self.tcx.expr_ty_adjusted(base); + let base_type = self.tcx.tables().expr_ty_adjusted(base); debug!("effect: call case, base type is {:?}", base_type); if type_is_unsafe_function(base_type) { @@ -176,7 +176,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprUnary(hir::UnDeref, ref base) => { - let base_type = self.tcx.expr_ty_adjusted(base); + let base_type = self.tcx.tables().expr_ty_adjusted(base); debug!("effect: unary case, base type is {:?}", base_type); if let ty::TyRawPtr(_) = base_type.sty { @@ -200,7 +200,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprField(ref base_expr, field) => { - if let ty::TyAdt(adt, ..) = self.tcx.expr_ty_adjusted(base_expr).sty { + if let ty::TyAdt(adt, ..) = self.tcx.tables().expr_ty_adjusted(base_expr).sty { if adt.is_union() { self.require_unsafe(field.span, "access to union field"); } @@ -214,7 +214,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_pat(&mut self, pat: &hir::Pat) { if let PatKind::Struct(_, ref fields, _) = pat.node { - if let ty::TyAdt(adt, ..) = self.tcx.pat_ty(pat).sty { + if let ty::TyAdt(adt, ..) = self.tcx.tables().pat_ty(pat).sty { if adt.is_union() { for field in fields { self.require_unsafe(field.span, "matching on union field"); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index c37b6df369df..231da576f2b9 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -227,8 +227,8 @@ impl OverloadedCallType { } fn from_method_id(tcx: TyCtxt, method_id: DefId) -> OverloadedCallType { - let method = tcx.impl_or_trait_item(method_id); - OverloadedCallType::from_trait_id(tcx, method.container().id()) + let method = tcx.associated_item(method_id); + OverloadedCallType::from_trait_id(tcx, method.container.id()) } } @@ -290,14 +290,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn walk_fn(&mut self, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { self.walk_arg_patterns(decl, body); - self.walk_block(body); + self.consume_expr(body); } fn walk_arg_patterns(&mut self, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { for arg in &decl.inputs { let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); @@ -720,11 +720,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { //NOTE(@jroesch): mixed RefCell borrow causes crash let adj = infcx.adjustments().get(&expr.id).map(|x| x.clone()); if let Some(adjustment) = adj { - match adjustment { - adjustment::AdjustNeverToAny(..) | - adjustment::AdjustReifyFnPointer | - adjustment::AdjustUnsafeFnPointer | - adjustment::AdjustMutToConstPointer => { + match adjustment.kind { + adjustment::Adjust::NeverToAny | + adjustment::Adjust::ReifyFnPointer | + adjustment::Adjust::UnsafeFnPointer | + adjustment::Adjust::MutToConstPointer => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. debug!("walk_adjustment: trivial adjustment"); @@ -732,8 +732,21 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { return_if_err!(self.mc.cat_expr_unadjusted(expr)); self.delegate_consume(expr.id, expr.span, cmt_unadjusted); } - adjustment::AdjustDerefRef(ref adj) => { - self.walk_autoderefref(expr, adj); + adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { + debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); + + self.walk_autoderefs(expr, autoderefs); + + let cmt_derefd = + return_if_err!(self.mc.cat_expr_autoderefd(expr, autoderefs)); + + let cmt_refd = + self.walk_autoref(expr, cmt_derefd, autoref); + + if unsize { + // Unsizing consumes the thin pointer and produces a fat one. + self.delegate_consume(expr.id, expr.span, cmt_refd); + } } } } @@ -770,28 +783,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } - fn walk_autoderefref(&mut self, - expr: &hir::Expr, - adj: &adjustment::AutoDerefRef<'tcx>) { - debug!("walk_autoderefref expr={:?} adj={:?}", - expr, - adj); - - self.walk_autoderefs(expr, adj.autoderefs); - - let cmt_derefd = - return_if_err!(self.mc.cat_expr_autoderefd(expr, adj.autoderefs)); - - let cmt_refd = - self.walk_autoref(expr, cmt_derefd, adj.autoref); - - if adj.unsize.is_some() { - // Unsizing consumes the thin pointer and produces a fat one. - self.delegate_consume(expr.id, expr.span, cmt_refd); - } - } - - /// Walks the autoref `opt_autoref` applied to the autoderef'd /// `expr`. `cmt_derefd` is the mem-categorized form of `expr` /// after all relevant autoderefs have occurred. Because AutoRefs @@ -803,7 +794,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn walk_autoref(&mut self, expr: &hir::Expr, cmt_base: mc::cmt<'tcx>, - opt_autoref: Option>) + opt_autoref: Option>) -> mc::cmt<'tcx> { debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})", @@ -822,7 +813,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { }; match *autoref { - adjustment::AutoPtr(r, m) => { + adjustment::AutoBorrow::Ref(r, m) => { self.delegate.borrow(expr.id, expr.span, cmt_base, @@ -831,7 +822,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { AutoRef); } - adjustment::AutoUnsafe(m) => { + adjustment::AutoBorrow::RawPtr(m) => { debug!("walk_autoref: expr.id={} cmt_base={:?}", expr.id, cmt_base); diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 1acd0fb0f79c..7dbf9aa74144 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, id: ast::NodeId) { + b: &'v hir::Expr, s: Span, id: ast::NodeId) { if let FnKind::Closure(..) = fk { span_bug!(s, "intrinsicck: closure outside of function") } @@ -163,7 +163,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> { if let hir::ExprPath(..) = expr.node { match self.infcx.tcx.expect_def(expr.id) { Def::Fn(did) if self.def_id_is_transmute(did) => { - let typ = self.infcx.tcx.node_id_to_type(expr.id); + let typ = self.infcx.tcx.tables().node_id_to_type(expr.id); match typ.sty { ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { let from = bare_fn_ty.sig.0.inputs[0]; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 3175230ab6a5..3e7de79246b6 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -27,7 +27,7 @@ use session::Session; use hir::def_id::DefId; use ty; use middle::weak_lang_items; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use syntax::ast; use syntax::parse::token::InternedString; @@ -146,7 +146,7 @@ struct LanguageItemCollector<'a, 'tcx: 'a> { session: &'a Session, - item_refs: FnvHashMap<&'static str, usize>, + item_refs: FxHashMap<&'static str, usize>, } impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> { @@ -169,7 +169,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> { impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { pub fn new(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>) -> LanguageItemCollector<'a, 'tcx> { - let mut item_refs = FnvHashMap(); + let mut item_refs = FxHashMap(); $( item_refs.insert($name, $variant as usize); )* diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 79396b9ca4da..a654d65bc679 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -123,10 +123,9 @@ use std::io::prelude::*; use std::io; use std::rc::Rc; use syntax::ast::{self, NodeId}; -use syntax::codemap::original_sp; use syntax::parse::token::keywords; use syntax::ptr::P; -use syntax_pos::{BytePos, Span}; +use syntax_pos::Span; use hir::Expr; use hir; @@ -187,7 +186,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt) -> String { impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> { fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, id: NodeId) { + b: &'v hir::Expr, s: Span, id: NodeId) { visit_fn(self, fk, fd, b, s, id); } fn visit_local(&mut self, l: &hir::Local) { visit_local(self, l); } @@ -352,9 +351,9 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { } impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> { - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, n: NodeId) { - check_fn(self, fk, fd, b, s, n); + fn visit_fn(&mut self, _: FnKind<'v>, _: &'v hir::FnDecl, + _: &'v hir::Expr, _: Span, _: NodeId) { + // do not check contents of nested fns } fn visit_local(&mut self, l: &hir::Local) { check_local(self, l); @@ -370,7 +369,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> { fn visit_fn(ir: &mut IrMaps, fk: FnKind, decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId) { debug!("visit_fn"); @@ -405,10 +404,10 @@ fn visit_fn(ir: &mut IrMaps, // compute liveness let mut lsets = Liveness::new(&mut fn_maps, specials); - let entry_ln = lsets.compute(decl, body); + let entry_ln = lsets.compute(body); // check for various error conditions - lsets.visit_block(body); + lsets.visit_expr(body); lsets.check_ret(id, sp, fk, entry_ln, body); lsets.warn_about_unused_args(decl, entry_ln); } @@ -821,17 +820,23 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // _______________________________________________________________________ - fn compute(&mut self, decl: &hir::FnDecl, body: &hir::Block) -> LiveNode { + fn compute(&mut self, body: &hir::Expr) -> LiveNode { // if there is a `break` or `again` at the top level, then it's // effectively a return---this only occurs in `for` loops, // where the body is really a closure. - debug!("compute: using id for block, {}", block_to_string(body)); + debug!("compute: using id for body, {}", expr_to_string(body)); let exit_ln = self.s.exit_ln; - let entry_ln: LiveNode = - self.with_loop_nodes(body.id, exit_ln, exit_ln, - |this| this.propagate_through_fn_block(decl, body)); + let entry_ln: LiveNode = self.with_loop_nodes(body.id, exit_ln, exit_ln, |this| { + // the fallthrough exit is only for those cases where we do not + // explicitly return: + let s = this.s; + this.init_from_succ(s.fallthrough_ln, s.exit_ln); + this.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ); + + this.propagate_through_expr(body, s.fallthrough_ln) + }); // hack to skip the loop unless debug! is enabled: debug!("^^ liveness computation results for body {} (entry={:?})", @@ -846,20 +851,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { entry_ln } - fn propagate_through_fn_block(&mut self, _: &hir::FnDecl, blk: &hir::Block) - -> LiveNode { - // the fallthrough exit is only for those cases where we do not - // explicitly return: - let s = self.s; - self.init_from_succ(s.fallthrough_ln, s.exit_ln); - if blk.expr.is_none() { - self.acc(s.fallthrough_ln, s.no_ret_var, ACC_READ) - } - self.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ); - - self.propagate_through_block(blk, s.fallthrough_ln) - } - fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode) -> LiveNode { let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ); @@ -1081,7 +1072,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprAssignOp(_, ref l, ref r) => { // an overloaded assign op is like a method call - if self.ir.tcx.is_method_call(expr.id) { + if self.ir.tcx.tables().is_method_call(expr.id) { let succ = self.propagate_through_expr(&l, succ); self.propagate_through_expr(&r, succ) } else { @@ -1113,8 +1104,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprCall(ref f, ref args) => { // FIXME(canndrew): This is_never should really be an is_uninhabited - let diverges = !self.ir.tcx.is_method_call(expr.id) && - self.ir.tcx.expr_ty_adjusted(&f).fn_ret().0.is_never(); + let diverges = !self.ir.tcx.tables().is_method_call(expr.id) && + self.ir.tcx.tables().expr_ty_adjusted(&f).fn_ret().0.is_never(); let succ = if diverges { self.s.exit_ln } else { @@ -1126,7 +1117,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprMethodCall(.., ref args) => { let method_call = ty::MethodCall::expr(expr.id); - let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty; + let method_ty = self.ir.tcx.tables().method_map[&method_call].ty; // FIXME(canndrew): This is_never should really be an is_uninhabited let succ = if method_ty.fn_ret().0.is_never() { self.s.exit_ln @@ -1409,7 +1400,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { } hir::ExprAssignOp(_, ref l, _) => { - if !this.ir.tcx.is_method_call(expr.id) { + if !this.ir.tcx.tables().is_method_call(expr.id) { this.check_lvalue(&l); } @@ -1448,18 +1439,9 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { } } -fn check_fn(_v: &Liveness, - _fk: FnKind, - _decl: &hir::FnDecl, - _body: &hir::Block, - _sp: Span, - _id: NodeId) { - // do not check contents of nested fns -} - impl<'a, 'tcx> Liveness<'a, 'tcx> { fn fn_ret(&self, id: NodeId) -> ty::Binder> { - let fn_ty = self.ir.tcx.node_id_to_type(id); + let fn_ty = self.ir.tcx.tables().node_id_to_type(id); match fn_ty.sty { ty::TyClosure(closure_def_id, substs) => self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), @@ -1472,7 +1454,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { sp: Span, _fk: FnKind, entry_ln: LiveNode, - body: &hir::Block) + body: &hir::Expr) { // within the fn body, late-bound regions are liberated // and must outlive the *call-site* of the function. @@ -1481,13 +1463,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.ir.tcx.region_maps.call_site_extent(id, body.id), &self.fn_ret(id)); - if fn_ret.is_never() { - // FIXME(durka) this rejects code like `fn foo(x: !) -> ! { x }` - if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() { - span_err!(self.ir.tcx.sess, sp, E0270, - "computation may converge in a function marked as diverging"); - } - } else if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { + if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { let param_env = ParameterEnvironment::for_item(self.ir.tcx, id); let t_ret_subst = fn_ret.subst(self.ir.tcx, ¶m_env.free_substs); let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env), @@ -1498,32 +1474,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // for nil return types, it is ok to not return a value expl. if !is_nil { - let ends_with_stmt = match body.expr { - None if !body.stmts.is_empty() => - match body.stmts.last().unwrap().node { - hir::StmtSemi(ref e, _) => { - self.ir.tcx.expr_ty(&e) == fn_ret - }, - _ => false - }, - _ => false - }; - let mut err = struct_span_err!(self.ir.tcx.sess, - sp, - E0269, - "not all control paths return a value"); - if ends_with_stmt { - let last_stmt = body.stmts.last().unwrap(); - let original_span = original_sp(self.ir.tcx.sess.codemap(), - last_stmt.span, sp); - let span_semicolon = Span { - lo: original_span.hi - BytePos(1), - hi: original_span.hi, - expn_id: original_span.expn_id - }; - err.span_help(span_semicolon, "consider removing this semicolon:"); - } - err.emit(); + span_bug!(sp, "not all control paths return a value"); } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 9214138d2107..e3ed13e1e401 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -354,11 +354,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { - let unadjusted_ty = self.expr_ty(expr)?; - Ok(unadjusted_ty.adjust( - self.tcx(), expr.span, expr.id, - self.infcx.adjustments().get(&expr.id), - |method_call| self.infcx.node_method_ty(method_call))) + self.infcx.expr_ty_adjusted(expr) } fn node_ty(&self, id: ast::NodeId) -> McResult> { @@ -396,19 +392,21 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Some(adjustment) => { - match *adjustment { - adjustment::AdjustDerefRef( - adjustment::AutoDerefRef { - autoref: None, unsize: None, autoderefs, ..}) => { + match adjustment.kind { + adjustment::Adjust::DerefRef { + autoderefs, + autoref: None, + unsize: false + } => { // Equivalent to *expr or something similar. self.cat_expr_autoderefd(expr, autoderefs) } - adjustment::AdjustNeverToAny(..) | - adjustment::AdjustReifyFnPointer | - adjustment::AdjustUnsafeFnPointer | - adjustment::AdjustMutToConstPointer | - adjustment::AdjustDerefRef(_) => { + adjustment::Adjust::NeverToAny | + adjustment::Adjust::ReifyFnPointer | + adjustment::Adjust::UnsafeFnPointer | + adjustment::Adjust::MutToConstPointer | + adjustment::Adjust::DerefRef {..} => { debug!("cat_expr({:?}): {:?}", adjustment, expr); diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 189150d42646..1376886968f7 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -12,7 +12,7 @@ //! outside their scopes. This pass will also generate a set of exported items //! which are available for use externally when compiled as a library. -use util::nodemap::{DefIdSet, FnvHashMap}; +use util::nodemap::{DefIdSet, FxHashMap}; use std::hash::Hash; use std::fmt; @@ -35,7 +35,7 @@ pub enum AccessLevel { // Accessibility levels for reachable HIR nodes #[derive(Clone)] pub struct AccessLevels { - pub map: FnvHashMap + pub map: FxHashMap } impl AccessLevels { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index a476d0f6f30a..7868e700f270 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -22,7 +22,7 @@ use hir::def_id::DefId; use ty::{self, TyCtxt}; use middle::privacy; use session::config; -use util::nodemap::{NodeSet, FnvHashSet}; +use util::nodemap::{NodeSet, FxHashSet}; use syntax::abi::Abi; use syntax::ast; @@ -116,7 +116,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { } hir::ExprMethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); - let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id; + let def_id = self.tcx.tables().method_map[&method_call].def_id; // Mark the trait item (and, possibly, its default impl) as reachable // Or mark inherent impl item as reachable @@ -204,7 +204,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Step 2: Mark all symbols that the symbols on the worklist touch. fn propagate(&mut self) { - let mut scanned = FnvHashSet(); + let mut scanned = FxHashSet(); loop { let search_item = match self.worklist.pop() { Some(item) => item, @@ -248,9 +248,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match *node { ast_map::NodeItem(item) => { match item.node { - hir::ItemFn(.., ref search_block) => { + hir::ItemFn(.., ref body) => { if item_might_be_inlined(&item) { - intravisit::walk_block(self, &search_block) + self.visit_expr(body); } } @@ -278,11 +278,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::MethodTraitItem(_, None) => { // Keep going, nothing to get exported } - hir::ConstTraitItem(_, Some(ref expr)) => { - self.visit_expr(&expr); - } + hir::ConstTraitItem(_, Some(ref body)) | hir::MethodTraitItem(_, Some(ref body)) => { - intravisit::walk_block(self, body); + self.visit_expr(body); } hir::TypeTraitItem(..) => {} } @@ -295,7 +293,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ImplItemKind::Method(ref sig, ref body) => { let did = self.tcx.map.get_parent_did(search_item); if method_might_be_inlined(self.tcx, sig, impl_item, did) { - intravisit::walk_block(self, body) + self.visit_expr(body) } } hir::ImplItemKind::Type(_) => {} diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 30b735b9c24e..34a6a547d944 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -19,7 +19,7 @@ use dep_graph::DepNode; use hir::map as ast_map; use session::Session; -use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; +use util::nodemap::{FxHashMap, NodeMap, NodeSet}; use ty; use std::cell::RefCell; @@ -251,7 +251,7 @@ impl CodeExtent { /// The region maps encode information about region relationships. pub struct RegionMaps { code_extents: RefCell>, - code_extent_interner: RefCell>, + code_extent_interner: RefCell>, /// `scope_map` maps from a scope id to the enclosing scope id; /// this is usually corresponding to the lexical nesting, though /// in the case of closures the parent scope is the innermost @@ -490,12 +490,7 @@ impl RegionMaps { // if there's one. Static items, for instance, won't // have an enclosing scope, hence no scope will be // returned. - let expr_extent = self.node_extent(expr_id); - // For some reason, the expr's scope itself is skipped here. - let mut id = match scope_map[expr_extent.0 as usize].into_option() { - Some(i) => i, - _ => return None - }; + let mut id = self.node_extent(expr_id); while let Some(p) = scope_map[id.0 as usize].into_option() { match code_extents[p.0 as usize] { @@ -1086,7 +1081,7 @@ fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &hir::Item) { fn resolve_fn(visitor: &mut RegionResolutionVisitor, kind: FnKind, decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId) { debug!("region::resolve_fn(id={:?}, \ @@ -1128,7 +1123,7 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, parent: fn_decl_scope, var_parent: fn_decl_scope }; - visitor.visit_block(body); + visitor.visit_expr(body); // Restore context we had at the start. visitor.cx = outer_cx; @@ -1191,7 +1186,7 @@ impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, - b: &'v Block, s: Span, n: NodeId) { + b: &'v Expr, s: Span, n: NodeId) { resolve_fn(self, fk, fd, b, s, n); } fn visit_arm(&mut self, a: &Arm) { @@ -1217,7 +1212,7 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps { let maps = RegionMaps { code_extents: RefCell::new(vec![]), - code_extent_interner: RefCell::new(FnvHashMap()), + code_extent_interner: RefCell::new(FxHashMap()), scope_map: RefCell::new(vec![]), var_map: RefCell::new(NodeMap()), rvalue_scopes: RefCell::new(NodeMap()), diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 2d93c33afb40..292d9592ceb0 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -31,7 +31,7 @@ use syntax::parse::token::keywords; use syntax_pos::Span; use util::nodemap::NodeMap; -use rustc_data_structures::fnv::FnvHashSet; +use rustc_data_structures::fx::FxHashSet; use hir; use hir::print::lifetime_to_string; use hir::intravisit::{self, Visitor, FnKind}; @@ -202,7 +202,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, fn_id: ast::NodeId) { + b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { match fk { FnKind::ItemFn(_, generics, ..) => { self.visit_early_late(fn_id,decl, generics, |this| { @@ -403,7 +403,7 @@ 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::Block) { +fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) { struct GatherLabels<'a> { sess: &'a Session, scope: Scope<'a>, @@ -415,7 +415,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) { scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn, }; - gather.visit_block(b); + gather.visit_expr(b); return; impl<'v, 'a> Visitor<'v> for GatherLabels<'a> { @@ -493,7 +493,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn add_scope_and_walk_fn<'b>(&mut self, fk: FnKind, fd: &hir::FnDecl, - fb: &'b hir::Block, + fb: &'b hir::Expr, _span: Span, fn_id: ast::NodeId) { @@ -516,7 +516,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { extract_labels(self, fb); self.with(FnScope { fn_id: fn_id, body_id: fb.id, s: self.scope }, - |_old_scope, this| this.visit_block(fb)) + |_old_scope, this| this.visit_expr(fb)) } fn with(&mut self, wrap_scope: ScopeChain, f: F) where @@ -847,13 +847,13 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, generics: &hir::Generics) { debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics); - let mut constrained_by_input = ConstrainedCollector { regions: FnvHashSet() }; + let mut constrained_by_input = ConstrainedCollector { regions: FxHashSet() }; for arg in &decl.inputs { constrained_by_input.visit_ty(&arg.ty); } let mut appears_in_output = AllCollector { - regions: FnvHashSet(), + regions: FxHashSet(), impl_trait: false }; intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); @@ -866,7 +866,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, // Subtle point: because we disallow nested bindings, we can just // ignore binders here and scrape up all names we see. let mut appears_in_where_clause = AllCollector { - regions: FnvHashSet(), + regions: FxHashSet(), impl_trait: false }; for ty_param in generics.ty_params.iter() { @@ -926,7 +926,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, return; struct ConstrainedCollector { - regions: FnvHashSet, + regions: FxHashSet, } impl<'v> Visitor<'v> for ConstrainedCollector { @@ -961,7 +961,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, } struct AllCollector { - regions: FnvHashSet, + regions: FxHashSet, impl_trait: bool } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 5192575972b0..d79833998d6c 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -27,7 +27,7 @@ use syntax::ast; use syntax::ast::{NodeId, Attribute}; use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version}; use syntax::attr::{self, Stability, Deprecation}; -use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap}; +use util::nodemap::{DefIdMap, FxHashSet, FxHashMap}; use hir; use hir::{Item, Generics, StructField, Variant, PatKind}; @@ -102,7 +102,7 @@ pub struct Index<'tcx> { depr_map: DefIdMap>, /// Maps for each crate whether it is part of the staged API. - staged_api: FnvHashMap + staged_api: FxHashMap } // A private tree-walker for producing an Index. @@ -343,7 +343,7 @@ impl<'a, 'tcx> Index<'tcx> { } } - let mut staged_api = FnvHashMap(); + let mut staged_api = FxHashMap(); staged_api.insert(LOCAL_CRATE, is_staged_api); Index { staged_api: staged_api, @@ -357,7 +357,7 @@ impl<'a, 'tcx> Index<'tcx> { /// features and possibly prints errors. Returns a list of all /// features used. pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> FnvHashMap { + -> FxHashMap { let _task = tcx.dep_graph.in_task(DepNode::StabilityCheck); let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features; @@ -367,7 +367,7 @@ pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) let mut checker = Checker { tcx: tcx, active_features: active_features, - used_features: FnvHashMap(), + used_features: FxHashMap(), in_skip_block: 0, }; intravisit::walk_crate(&mut checker, tcx.map.krate()); @@ -377,8 +377,8 @@ pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) struct Checker<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - active_features: FnvHashSet, - used_features: FnvHashMap, + active_features: FxHashSet, + used_features: FxHashMap, // Within a block where feature gate checking can be skipped. in_skip_block: u32, } @@ -529,14 +529,11 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // items. hir::ItemImpl(.., Some(ref t), _, ref impl_items) => { let trait_did = tcx.expect_def(t.ref_id).def_id(); - let trait_items = tcx.trait_items(trait_did); - for impl_item in impl_items { - let item = trait_items.iter().find(|item| { - item.name() == impl_item.name - }).unwrap(); + let item = tcx.associated_items(trait_did) + .find(|item| item.name == impl_item.name).unwrap(); if warn_about_defns { - maybe_do_stability_check(tcx, item.def_id(), impl_item.span, cb); + maybe_do_stability_check(tcx, item.def_id, impl_item.span, cb); } } } @@ -555,11 +552,11 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, hir::ExprMethodCall(i, ..) => { span = i.span; let method_call = ty::MethodCall::expr(e.id); - tcx.tables.borrow().method_map[&method_call].def_id + tcx.tables().method_map[&method_call].def_id } hir::ExprField(ref base_e, ref field) => { span = field.span; - match tcx.expr_ty_adjusted(base_e).sty { + match tcx.tables().expr_ty_adjusted(base_e).sty { ty::TyAdt(def, _) => { def.struct_variant().field_named(field.node).did } @@ -569,7 +566,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, } hir::ExprTupField(ref base_e, ref field) => { span = field.span; - match tcx.expr_ty_adjusted(base_e).sty { + match tcx.tables().expr_ty_adjusted(base_e).sty { ty::TyAdt(def, _) => { def.struct_variant().fields[field.node].did } @@ -580,7 +577,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, } } hir::ExprStruct(_, ref expr_fields, _) => { - match tcx.expr_ty(e).sty { + match tcx.tables().expr_ty(e).sty { ty::TyAdt(adt, ..) => match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { // check the stability of each field that appears @@ -637,7 +634,7 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } - let v = match tcx.pat_ty_opt(pat).map(|ty| &ty.sty) { + let v = match tcx.tables().pat_ty_opt(pat).map(|ty| &ty.sty) { Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => adt.struct_variant(), _ => return, }; @@ -685,15 +682,8 @@ fn is_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span) -> bool { } fn is_staged_api<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> bool { - match tcx.trait_item_of_item(id) { - Some(trait_method_id) if trait_method_id != id => { - is_staged_api(tcx, trait_method_id) - } - _ => { - *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with( - || tcx.sess.cstore.is_staged_api(id.krate)) - } - } + *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with( + || tcx.sess.cstore.is_staged_api(id.krate)) } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { @@ -746,10 +736,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. pub fn check_unused_or_stable_features(sess: &Session, - lib_features_used: &FnvHashMap) { + lib_features_used: &FxHashMap) { let ref declared_lib_features = sess.features.borrow().declared_lib_features; - let mut remaining_lib_features: FnvHashMap + let mut remaining_lib_features: FxHashMap = declared_lib_features.clone().into_iter().collect(); fn format_stable_since_msg(version: &str) -> String { diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index db7267ca0d4b..b5da304a1098 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -157,14 +157,14 @@ macro_rules! make_mir_visitor { fn visit_projection(&mut self, lvalue: & $($mutability)* LvalueProjection<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { self.super_projection(lvalue, context, location); } fn visit_projection_elem(&mut self, lvalue: & $($mutability)* LvalueElem<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { self.super_projection_elem(lvalue, context, location); } @@ -579,7 +579,7 @@ macro_rules! make_mir_visitor { fn super_projection(&mut self, proj: & $($mutability)* LvalueProjection<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { let Projection { ref $($mutability)* base, @@ -596,7 +596,7 @@ macro_rules! make_mir_visitor { fn super_projection_elem(&mut self, proj: & $($mutability)* LvalueElem<'tcx>, - _context: LvalueContext, + _context: LvalueContext<'tcx>, location: Location) { match *proj { ProjectionElem::Deref => { @@ -739,7 +739,7 @@ macro_rules! make_mir_visitor { make_mir_visitor!(Visitor,); make_mir_visitor!(MutVisitor,mut); -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LvalueContext<'tcx> { // Appears as LHS of an assignment Store, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 87a5c6410a84..16522a73f56a 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -793,7 +793,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, remark: Passes = (SomePasses(Vec::new()), parse_passes, [UNTRACKED], "print remarks for these optimization passes (space separated, or \"all\")"), no_stack_check: bool = (false, parse_bool, [UNTRACKED], - "disable checks for stack exhaustion (a memory-safety hazard!)"), + "the --no-stack-check flag is deprecated and does nothing"), debuginfo: Option = (None, parse_opt_uint, [TRACKED], "debug info emission level, 0 = no debug info, 1 = line tables only, \ 2 = full debug info with variable and type information"), @@ -918,6 +918,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "the directory the MIR is dumped into"), perf_stats: bool = (false, parse_bool, [UNTRACKED], "print some performance-related statistics"), + hir_stats: bool = (false, parse_bool, [UNTRACKED], + "print some statistics about AST and HIR"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1ce5b223fbef..724b32d2cd71 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -17,7 +17,7 @@ use middle::dependency_format; use session::search_paths::PathKind; use session::config::DebugInfoLevel; use ty::tls; -use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; +use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; use util::common::duration_to_secs_str; use mir::transform as mir_pass; @@ -74,11 +74,11 @@ pub struct Session { pub local_crate_source_file: Option, pub working_dir: PathBuf, pub lint_store: RefCell, - pub lints: RefCell>>, + pub lints: RefCell>>, /// Set of (LintId, span, message) tuples tracking lint (sub)diagnostics /// that have been set once, but should not be set again, in order to avoid /// redundantly verbose output (Issue #24690). - pub one_time_diagnostics: RefCell>, + pub one_time_diagnostics: RefCell>, pub plugin_llvm_passes: RefCell>, pub mir_passes: RefCell, pub plugin_attributes: RefCell>, @@ -262,17 +262,26 @@ impl Session { lint: &'static lint::Lint, id: ast::NodeId, sp: Span, - msg: String) { + msg: String) + { + self.add_lint_diagnostic(lint, id, (sp, &msg[..])) + } + pub fn add_lint_diagnostic(&self, + lint: &'static lint::Lint, + id: ast::NodeId, + msg: M) + where M: lint::IntoEarlyLint, + { let lint_id = lint::LintId::of(lint); let mut lints = self.lints.borrow_mut(); + let early_lint = msg.into_early_lint(lint_id); if let Some(arr) = lints.get_mut(&id) { - let tuple = (lint_id, sp, msg); - if !arr.contains(&tuple) { - arr.push(tuple); + if !arr.contains(&early_lint) { + arr.push(early_lint); } return; } - lints.insert(id, vec![(lint_id, sp, msg)]); + lints.insert(id, vec![early_lint]); } pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId { let id = self.next_node_id.get(); @@ -594,12 +603,12 @@ pub fn build_session_(sopts: config::Options, working_dir: env::current_dir().unwrap(), lint_store: RefCell::new(lint::LintStore::new()), lints: RefCell::new(NodeMap()), - one_time_diagnostics: RefCell::new(FnvHashSet()), + one_time_diagnostics: RefCell::new(FxHashSet()), plugin_llvm_passes: RefCell::new(Vec::new()), mir_passes: RefCell::new(mir_pass::Passes::new()), plugin_attributes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), - dependency_formats: RefCell::new(FnvHashMap()), + dependency_formats: RefCell::new(FxHashMap()), crate_disambiguator: RefCell::new(token::intern("").as_str()), features: RefCell::new(feature_gate::Features::new()), recursion_limit: Cell::new(64), diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 68c88249ec0c..1ccd048cedca 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -14,7 +14,7 @@ use super::{SelectionContext, Obligation, ObligationCause}; use hir::def_id::{DefId, LOCAL_CRATE}; use ty::{self, Ty, TyCtxt}; -use infer::{InferCtxt, TypeOrigin}; +use infer::{InferCtxt, InferOk, TypeOrigin}; use syntax_pos::DUMMY_SP; #[derive(Copy, Clone)] @@ -55,11 +55,13 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, debug!("overlap: b_impl_header={:?}", b_impl_header); // Do `a` and `b` unify? If not, no overlap. - if let Err(_) = selcx.infcx().eq_impl_headers(true, - TypeOrigin::Misc(DUMMY_SP), - &a_impl_header, - &b_impl_header) { - return None; + match selcx.infcx().eq_impl_headers(true, TypeOrigin::Misc(DUMMY_SP), &a_impl_header, + &b_impl_header) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + } + Err(_) => return None } debug!("overlap: unification check succeeded"); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 9435f96c08a2..7e70fdb92e68 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -27,15 +27,17 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; use infer::{self, InferCtxt, TypeOrigin}; +use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; use ty::subst::Subst; -use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::nodemap::{FxHashMap, FxHashSet}; use std::cmp; use std::fmt; +use syntax::ast; use syntax_pos::Span; use errors::DiagnosticBuilder; @@ -250,7 +252,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let generic_map = def.generics.types.iter().map(|param| { (param.name.as_str().to_string(), trait_ref.substs.type_for_def(param).to_string()) - }).collect::>(); + }).collect::>(); let parser = Parser::new(&istring); let mut errored = false; let err: String = parser.filter_map(|p| { @@ -417,6 +419,45 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.report_overflow_error(&cycle[0], false); } + pub fn report_extra_impl_obligation(&self, + error_span: Span, + item_name: ast::Name, + _impl_item_def_id: DefId, + trait_item_def_id: DefId, + requirement: &fmt::Display, + lint_id: Option) // (*) + -> DiagnosticBuilder<'tcx> + { + // (*) This parameter is temporary and used only for phasing + // in the bug fix to #18937. If it is `Some`, it has a kind of + // weird effect -- the diagnostic is reported as a lint, and + // the builder which is returned is marked as canceled. + + let mut err = + struct_span_err!(self.tcx.sess, + error_span, + E0276, + "impl has stricter requirements than trait"); + + if let Some(trait_item_span) = self.tcx.map.span_if_local(trait_item_def_id) { + err.span_label(trait_item_span, + &format!("definition of `{}` from trait", item_name)); + } + + err.span_label( + error_span, + &format!("impl has extra requirement {}", requirement)); + + if let Some(node_id) = lint_id { + self.tcx.sess.add_lint_diagnostic(EXTRA_REQUIREMENT_IN_IMPL, + node_id, + (*err).clone()); + err.cancel(); + } + + err + } + pub fn report_selection_error(&self, obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>) @@ -424,12 +465,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let span = obligation.cause.span; let mut err = match *error { SelectionError::Unimplemented => { - if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code { - span_err!( - self.tcx.sess, span, E0276, - "the requirement `{}` appears on the impl \ - method but not on the corresponding trait method", - obligation.predicate); + if let ObligationCauseCode::CompareImplMethodObligation { + item_name, impl_item_def_id, trait_item_def_id, lint_id + } = obligation.cause.code { + self.report_extra_impl_obligation( + span, + item_name, + impl_item_def_id, + trait_item_def_id, + &format!("`{}`", obligation.predicate), + lint_id) + .emit(); return; } else { match obligation.predicate { @@ -492,7 +538,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::RegionOutlives(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); - let err = self.region_outlives_predicate(span, + let err = self.region_outlives_predicate(&obligation.cause, &predicate).err().unwrap(); struct_span_err!(self.tcx.sess, span, E0279, "the requirement `{}` is not satisfied (`{}`)", @@ -601,7 +647,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { "the trait `{}` cannot be made into an object", trait_str )); - let mut reported_violations = FnvHashSet(); + let mut reported_violations = FxHashSet(); for violation in violations { if !reported_violations.insert(violation.clone()) { continue; @@ -617,25 +663,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { in the supertrait listing" } - ObjectSafetyViolation::Method(method, + ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) => { - buf = format!("method `{}` has no receiver", - method.name); + buf = format!("method `{}` has no receiver", name); &buf } - ObjectSafetyViolation::Method(method, + ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) => { buf = format!("method `{}` references the `Self` type \ in its arguments or return type", - method.name); + name); &buf } - ObjectSafetyViolation::Method(method, + ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => { - buf = format!("method `{}` has generic type parameters", - method.name); + buf = format!("method `{}` has generic type parameters", name); &buf } }; @@ -740,7 +784,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn predicate_can_apply(&self, pred: ty::PolyTraitRef<'tcx>) -> bool { struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - var_map: FnvHashMap, Ty<'tcx>> + var_map: FxHashMap, Ty<'tcx>> } impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ParamToVarFolder<'a, 'gcx, 'tcx> { @@ -761,7 +805,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let cleaned_pred = pred.fold_with(&mut ParamToVarFolder { infcx: self, - var_map: FnvHashMap() + var_map: FxHashMap() }); let cleaned_pred = super::project::normalize( @@ -822,6 +866,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.note(&format!("required so that reference `{}` does not outlive its referent", ref_ty)); } + ObligationCauseCode::ObjectTypeBound(object_ty, region) => { + err.note(&format!("required so that the lifetime bound of `{}` for `{}` \ + is satisfied", + region, object_ty)); + } ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = tcx.item_path_str(item_def_id); err.note(&format!("required by `{}`", item_name)); @@ -886,7 +935,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &parent_predicate, &data.parent_code); } - ObligationCauseCode::CompareImplMethodObligation => { + ObligationCauseCode::CompareImplMethodObligation { .. } => { err.note( &format!("the requirement `{}` appears on the impl method \ but not on the corresponding trait method", diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index ded2fdc58b42..6de93adce3f8 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -18,7 +18,7 @@ use std::marker::PhantomData; use std::mem; use syntax::ast; use util::common::ErrorReported; -use util::nodemap::{FnvHashSet, NodeMap}; +use util::nodemap::{FxHashSet, NodeMap}; use super::CodeAmbiguity; use super::CodeProjectionError; @@ -37,7 +37,7 @@ impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { } pub struct GlobalFulfilledPredicates<'tcx> { - set: FnvHashSet>, + set: FxHashSet>, dep_graph: DepGraph, } @@ -526,7 +526,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } ty::Predicate::RegionOutlives(ref binder) => { - match selcx.infcx().region_outlives_predicate(obligation.cause.span, binder) { + match selcx.infcx().region_outlives_predicate(&obligation.cause, binder) { Ok(()) => Ok(Some(Vec::new())), Err(_) => Err(CodeSelectionError(Unimplemented)), } @@ -673,7 +673,7 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> { pub fn new(dep_graph: DepGraph) -> GlobalFulfilledPredicates<'gcx> { GlobalFulfilledPredicates { - set: FnvHashSet(), + set: FxHashSet(), dep_graph: dep_graph, } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 7ba10d9c0a58..36405df6325a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -111,6 +111,9 @@ pub enum ObligationCauseCode<'tcx> { /// A type like `&'a T` is WF only if `T: 'a`. ReferenceOutlivesReferent(Ty<'tcx>), + /// A type like `Box + 'b>` is WF only if `'b: 'a`. + ObjectTypeBound(Ty<'tcx>, &'tcx ty::Region), + /// Obligation incurred due to an object cast. ObjectCastObligation(/* Object type */ Ty<'tcx>), @@ -138,7 +141,13 @@ pub enum ObligationCauseCode<'tcx> { ImplDerivedObligation(DerivedObligationCause<'tcx>), - CompareImplMethodObligation, + // error derived when matching traits/impls; see ObligationCause for more details + CompareImplMethodObligation { + item_name: ast::Name, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + lint_id: Option, + }, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -569,18 +578,14 @@ pub fn get_vtable_methods<'a, 'tcx>( supertraits(tcx, trait_ref).flat_map(move |trait_ref| { tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id()); - let trait_item_def_ids = tcx.impl_or_trait_items(trait_ref.def_id()); - let trait_methods = (0..trait_item_def_ids.len()).filter_map(move |i| { - match tcx.impl_or_trait_item(trait_item_def_ids[i]) { - ty::MethodTraitItem(m) => Some(m), - _ => None - } - }); + let trait_methods = tcx.associated_items(trait_ref.def_id()) + .filter(|item| item.kind == ty::AssociatedKind::Method); // Now list each method's DefId and Substs (for within its trait). // If the method can never be called from this object, produce None. trait_methods.map(move |trait_method| { debug!("get_vtable_methods: trait_method={:?}", trait_method); + let def_id = trait_method.def_id; // Some methods cannot be called on an object; skip those. if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) { @@ -590,21 +595,21 @@ pub fn get_vtable_methods<'a, 'tcx>( // the method may have some early-bound lifetimes, add // regions for those - let substs = Substs::for_item(tcx, trait_method.def_id, - |_, _| tcx.mk_region(ty::ReErased), - |def, _| trait_ref.substs().type_for_def(def)); + let substs = Substs::for_item(tcx, def_id, + |_, _| tcx.mk_region(ty::ReErased), + |def, _| trait_ref.substs().type_for_def(def)); // It's possible that the method relies on where clauses that // do not hold for this particular set of type parameters. // Note that this method could then never be called, so we // do not want to try and trans it, in that case (see #23435). - let predicates = trait_method.predicates.instantiate_own(tcx, substs); + let predicates = tcx.lookup_predicates(def_id).instantiate_own(tcx, substs); if !normalize_and_test_predicates(tcx, predicates.predicates) { debug!("get_vtable_methods: predicates do not hold"); return None; } - Some((trait_method.def_id, substs)) + Some((def_id, substs)) }) }) } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 5f7b71518291..c783bd561bb1 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -22,11 +22,10 @@ use super::elaborate_predicates; use hir::def_id::DefId; use traits; use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; -use std::rc::Rc; use syntax::ast; #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum ObjectSafetyViolation<'tcx> { +pub enum ObjectSafetyViolation { /// Self : Sized declared on the trait SizedSelf, @@ -35,7 +34,7 @@ pub enum ObjectSafetyViolation<'tcx> { SupertraitSelf, /// Method has something illegal - Method(Rc>, MethodViolationCode), + Method(ast::Name, MethodViolationCode), } /// Reasons a method might not be object-safe. @@ -77,7 +76,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// because `object_safety_violations` can't be used during /// type collection. pub fn astconv_object_safety_violations(self, trait_def_id: DefId) - -> Vec> + -> Vec { let mut violations = vec![]; @@ -93,7 +92,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn object_safety_violations(self, trait_def_id: DefId) - -> Vec> + -> Vec { traits::supertrait_def_ids(self, trait_def_id) .flat_map(|def_id| self.object_safety_violations_for_trait(def_id)) @@ -101,21 +100,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } fn object_safety_violations_for_trait(self, trait_def_id: DefId) - -> Vec> + -> Vec { // Check methods for violations. - let mut violations: Vec<_> = - self.trait_items(trait_def_id).iter() + let mut violations: Vec<_> = self.associated_items(trait_def_id) + .filter(|item| item.kind == ty::AssociatedKind::Method) .filter_map(|item| { - match *item { - ty::MethodTraitItem(ref m) => { - self.object_safety_violation_for_method(trait_def_id, &m) - .map(|code| ObjectSafetyViolation::Method(m.clone(), code)) - } - _ => None, - } - }) - .collect(); + self.object_safety_violation_for_method(trait_def_id, &item) + .map(|code| ObjectSafetyViolation::Method(item.name, code)) + }).collect(); // Check the trait itself. if self.trait_has_sized_self(trait_def_id) { @@ -198,7 +191,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns `Some(_)` if this method makes the containing trait not object safe. fn object_safety_violation_for_method(self, trait_def_id: DefId, - method: &ty::Method<'gcx>) + method: &ty::AssociatedItem) -> Option { // Any method that has a `Self : Sized` requisite is otherwise @@ -216,7 +209,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// otherwise ensure that they cannot be used when `Self=Trait`. pub fn is_vtable_safe_method(self, trait_def_id: DefId, - method: &ty::Method<'gcx>) + method: &ty::AssociatedItem) -> bool { // Any method that has a `Self : Sized` requisite can't be called. @@ -233,26 +226,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// `Self:Sized`. fn virtual_call_violation_for_method(self, trait_def_id: DefId, - method: &ty::Method<'tcx>) + method: &ty::AssociatedItem) -> Option { // The method's first parameter must be something that derefs (or // autorefs) to `&self`. For now, we only accept `self`, `&self` // and `Box`. - match method.explicit_self { - ty::ExplicitSelfCategory::Static => { - return Some(MethodViolationCode::StaticMethod); - } - - ty::ExplicitSelfCategory::ByValue | - ty::ExplicitSelfCategory::ByReference(..) | - ty::ExplicitSelfCategory::ByBox => { - } + if !method.method_has_self_argument { + return Some(MethodViolationCode::StaticMethod); } // The `Self` type is erased, so it should not appear in list of // arguments or return type apart from the receiver. - let ref sig = method.fty.sig; + let ref sig = self.lookup_item_type(method.def_id).ty.fn_sig(); for &input_ty in &sig.0.inputs[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); @@ -263,7 +249,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We can't monomorphize things like `fn foo(...)`. - if !method.generics.types.is_empty() { + if !self.lookup_generics(method.def_id).types.is_empty() { return Some(MethodViolationCode::Generic); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index ce882c48377f..b1ab61b09757 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,8 +33,6 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; -use std::rc::Rc; - /// Depending on the stage of compilation, we want projection to be /// more or less conservative. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -945,7 +943,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // an error when we confirm the candidate // (which will ultimately lead to `normalize_to_error` // being invoked). - node_item.item.ty.is_some() + node_item.item.has_value } else { node_item.item.defaultness.is_default() }; @@ -1305,7 +1303,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( match assoc_ty { Some(node_item) => { - let ty = node_item.item.ty.unwrap_or_else(|| { + let ty = if !node_item.item.has_value { // This means that the impl is missing a definition for the // associated type. This error will be reported by the type // checker method `check_impl_items_against_trait`, so here we @@ -1314,7 +1312,9 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( node_item.item.name, obligation.predicate.trait_ref); tcx.types.err - }); + } else { + tcx.lookup_item_type(node_item.item.def_id).ty + }; let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); Progress { ty: ty.subst(tcx, substs), @@ -1339,27 +1339,25 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( selcx: &SelectionContext<'cx, 'gcx, 'tcx>, impl_def_id: DefId, assoc_ty_name: ast::Name) - -> Option>>> + -> Option> { let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id; if selcx.projection_mode() == Reveal::ExactMatch { let impl_node = specialization_graph::Node::Impl(impl_def_id); for item in impl_node.items(selcx.tcx()) { - if let ty::TypeTraitItem(assoc_ty) = item { - if assoc_ty.name == assoc_ty_name { - return Some(specialization_graph::NodeItem { - node: specialization_graph::Node::Impl(impl_def_id), - item: assoc_ty, - }); - } + if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name { + return Some(specialization_graph::NodeItem { + node: specialization_graph::Node::Impl(impl_def_id), + item: item, + }); } } None } else { selcx.tcx().lookup_trait_def(trait_def_id) .ancestors(impl_def_id) - .type_defs(selcx.tcx(), assoc_ty_name) + .defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type) .next() } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index e75c8bd43340..5e3f78b1208d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -51,7 +51,7 @@ use std::mem; use std::rc::Rc; use syntax::abi::Abi; use hir; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; struct InferredObligationsSnapshotVecDelegate<'tcx> { phantom: PhantomData<&'tcx i32>, @@ -104,8 +104,8 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { #[derive(Clone)] pub struct SelectionCache<'tcx> { - hashmap: RefCell, - SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, + hashmap: RefCell, + SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, } pub enum MethodMatchResult { @@ -306,7 +306,7 @@ enum EvaluationResult { #[derive(Clone)] pub struct EvaluationCache<'tcx> { - hashmap: RefCell, EvaluationResult>> + hashmap: RefCell, EvaluationResult>> } impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { @@ -2937,7 +2937,7 @@ impl<'tcx> TraitObligation<'tcx> { impl<'tcx> SelectionCache<'tcx> { pub fn new() -> SelectionCache<'tcx> { SelectionCache { - hashmap: RefCell::new(FnvHashMap()) + hashmap: RefCell::new(FxHashMap()) } } } @@ -2945,7 +2945,7 @@ impl<'tcx> SelectionCache<'tcx> { impl<'tcx> EvaluationCache<'tcx> { pub fn new() -> EvaluationCache<'tcx> { EvaluationCache { - hashmap: RefCell::new(FnvHashMap()) + hashmap: RefCell::new(FxHashMap()) } } } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 24cafa7f7253..91c40a5cc851 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -20,9 +20,9 @@ use super::{SelectionContext, FulfillmentContext}; use super::util::impl_trait_ref_and_oblig; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use hir::def_id::DefId; -use infer::{InferCtxt, TypeOrigin}; +use infer::{InferCtxt, InferOk, TypeOrigin}; use middle::region; use ty::subst::{Subst, Substs}; use traits::{self, Reveal, ObligationCause}; @@ -120,7 +120,8 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); let trait_def = tcx.lookup_trait_def(trait_def_id); - match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() { + let ancestors = trait_def.ancestors(impl_data.impl_def_id); + match ancestors.defs(tcx, name, ty::AssociatedKind::Method).next() { Some(node_item) => { let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); @@ -222,14 +223,18 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, target_substs); // do the impls unify? If not, no specialization. - if let Err(_) = infcx.eq_trait_refs(true, - TypeOrigin::Misc(DUMMY_SP), - source_trait_ref, - target_trait_ref) { - debug!("fulfill_implication: {:?} does not unify with {:?}", - source_trait_ref, - target_trait_ref); - return Err(()); + match infcx.eq_trait_refs(true, TypeOrigin::Misc(DUMMY_SP), source_trait_ref, + target_trait_ref) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()) + } + Err(_) => { + debug!("fulfill_implication: {:?} does not unify with {:?}", + source_trait_ref, + target_trait_ref); + return Err(()); + } } // attempt to prove all of the predicates for impl2 given those for impl1 @@ -266,13 +271,13 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } pub struct SpecializesCache { - map: FnvHashMap<(DefId, DefId), bool> + map: FxHashMap<(DefId, DefId), bool> } impl SpecializesCache { pub fn new() -> Self { SpecializesCache { - map: FnvHashMap() + map: FxHashMap() } } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 1374719ef49c..5a6809f1fad6 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -8,16 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::rc::Rc; - use super::{OverlapError, specializes}; use hir::def_id::DefId; use traits::{self, Reveal}; -use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable}; +use ty::{self, TyCtxt, TraitDef, TypeFoldable}; use ty::fast_reject::{self, SimplifiedType}; use syntax::ast::Name; -use util::nodemap::{DefIdMap, FnvHashMap}; +use util::nodemap::{DefIdMap, FxHashMap}; /// A per-trait graph of impls in specialization order. At the moment, this /// graph forms a tree rooted with the trait itself, with all other nodes @@ -57,7 +55,7 @@ struct Children { // the specialization graph. /// Impls of the trait. - nonblanket_impls: FnvHashMap>, + nonblanket_impls: FxHashMap>, /// Blanket impls associated with the trait. blanket_impls: Vec, @@ -78,7 +76,7 @@ enum Inserted { impl<'a, 'gcx, 'tcx> Children { fn new() -> Children { Children { - nonblanket_impls: FnvHashMap(), + nonblanket_impls: FxHashMap(), blanket_impls: vec![], } } @@ -285,12 +283,10 @@ impl<'a, 'gcx, 'tcx> Node { } /// Iterate over the items defined directly by the given (impl or trait) node. - pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> NodeItems<'a, 'gcx> { - NodeItems { - tcx: tcx.global_tcx(), - items: tcx.impl_or_trait_items(self.def_id()), - idx: 0, - } + #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. + pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) + -> impl Iterator + 'a { + tcx.associated_items(self.def_id()) } pub fn def_id(&self) -> DefId { @@ -301,28 +297,6 @@ impl<'a, 'gcx, 'tcx> Node { } } -/// An iterator over the items defined within a trait or impl. -pub struct NodeItems<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - items: Rc>, - idx: usize -} - -impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> { - type Item = ImplOrTraitItem<'tcx>; - fn next(&mut self) -> Option> { - if self.idx < self.items.len() { - let item_def_id = self.items[self.idx]; - let items_table = self.tcx.impl_or_trait_items.borrow(); - let item = items_table[&item_def_id].clone(); - self.idx += 1; - Some(item) - } else { - None - } - } -} - pub struct Ancestors<'a, 'tcx: 'a> { trait_def: &'a TraitDef<'tcx>, current_source: Option, @@ -358,104 +332,16 @@ impl NodeItem { } } -pub struct TypeDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for TypeDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - -pub struct FnDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for FnDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - -pub struct ConstDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for ConstDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - impl<'a, 'gcx, 'tcx> Ancestors<'a, 'tcx> { - /// Search the items from the given ancestors, returning each type definition - /// with the given name. - pub fn type_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> TypeDefs<'a, 'gcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::TypeTraitItem(assoc_ty) = item { - if assoc_ty.name == name { - return Some(NodeItem { - node: node, - item: assoc_ty, - }); - } - } - None - }) - - }); - TypeDefs { iter: Box::new(iter) } - } - - /// Search the items from the given ancestors, returning each fn definition - /// with the given name. - pub fn fn_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> FnDefs<'a, 'gcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::MethodTraitItem(method) = item { - if method.name == name { - return Some(NodeItem { - node: node, - item: method, - }); - } - } - None - }) - - }); - FnDefs { iter: Box::new(iter) } - } - - /// Search the items from the given ancestors, returning each const - /// definition with the given name. - pub fn const_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> ConstDefs<'a, 'gcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::ConstTraitItem(konst) = item { - if konst.name == name { - return Some(NodeItem { - node: node, - item: konst, - }); - } - } - None - }) - - }); - ConstDefs { iter: Box::new(iter) } + /// Search the items from the given ancestors, returning each definition + /// with the given name and the given kind. + #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. + pub fn defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name, kind: ty::AssociatedKind) + -> impl Iterator> + 'a { + self.flat_map(move |node| { + node.items(tcx).filter(move |item| item.kind == kind && item.name == name) + .map(move |item| NodeItem { node: node, item: item }) + }) } } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 022566642f64..d33e8b5675f5 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -175,6 +175,13 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::ReferenceOutlivesReferent(ty) => { tcx.lift(&ty).map(super::ReferenceOutlivesReferent) } + super::ObjectTypeBound(ty, r) => { + tcx.lift(&ty).and_then(|ty| { + tcx.lift(&r).and_then(|r| { + Some(super::ObjectTypeBound(ty, r)) + }) + }) + } super::ObjectCastObligation(ty) => { tcx.lift(&ty).map(super::ObjectCastObligation) } @@ -195,8 +202,16 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::ImplDerivedObligation(ref cause) => { tcx.lift(cause).map(super::ImplDerivedObligation) } - super::CompareImplMethodObligation => { - Some(super::CompareImplMethodObligation) + super::CompareImplMethodObligation { item_name, + impl_item_def_id, + trait_item_def_id, + lint_id } => { + Some(super::CompareImplMethodObligation { + item_name: item_name, + impl_item_def_id: impl_item_def_id, + trait_item_def_id: trait_item_def_id, + lint_id: lint_id, + }) } } } @@ -459,12 +474,15 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::FieldSized | super::ConstSized | super::SharedStatic | - super::CompareImplMethodObligation => self.clone(), + super::CompareImplMethodObligation { .. } => self.clone(), super::ProjectionWf(proj) => super::ProjectionWf(proj.fold_with(folder)), super::ReferenceOutlivesReferent(ty) => { super::ReferenceOutlivesReferent(ty.fold_with(folder)) } + super::ObjectTypeBound(ty, r) => { + super::ObjectTypeBound(ty.fold_with(folder), r.fold_with(folder)) + } super::ObjectCastObligation(ty) => { super::ObjectCastObligation(ty.fold_with(folder)) } @@ -492,10 +510,11 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::FieldSized | super::ConstSized | super::SharedStatic | - super::CompareImplMethodObligation => false, + super::CompareImplMethodObligation { .. } => false, super::ProjectionWf(proj) => proj.visit_with(visitor), super::ReferenceOutlivesReferent(ty) => ty.visit_with(visitor), + super::ObjectTypeBound(ty, r) => ty.visit_with(visitor) || r.visit_with(visitor), super::ObjectCastObligation(ty) => ty.visit_with(visitor), super::BuiltinDerivedObligation(ref cause) => cause.visit_with(visitor), super::ImplDerivedObligation(ref cause) => cause.visit_with(visitor) diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index a0792dcf4dd5..9346bbd30f9c 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -11,8 +11,9 @@ use hir::def_id::DefId; use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; +use ty::outlives::Component; use util::common::ErrorReported; -use util::nodemap::FnvHashSet; +use util::nodemap::FxHashSet; use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; @@ -49,12 +50,12 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, struct PredicateSet<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, - set: FnvHashSet>, + set: FxHashSet>, } impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> { fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> PredicateSet<'a, 'gcx, 'tcx> { - PredicateSet { tcx: tcx, set: FnvHashSet() } + PredicateSet { tcx: tcx, set: FxHashSet() } } fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { @@ -166,27 +167,63 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { ty::Predicate::ClosureKind(..) => { // Nothing to elaborate when waiting for a closure's kind to be inferred. } - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) => { - // Currently, we do not "elaborate" predicates like - // `'a : 'b` or `T : 'a`. We could conceivably do - // more here. For example, + + ty::Predicate::RegionOutlives(..) => { + // Nothing to elaborate from `'a: 'b`. + } + + ty::Predicate::TypeOutlives(ref data) => { + // We know that `T: 'a` for some type `T`. We can + // often elaborate this. For example, if we know that + // `[U]: 'a`, that implies that `U: 'a`. Similarly, if + // we know `&'a U: 'b`, then we know that `'a: 'b` and + // `U: 'b`. // - // &'a int : 'b - // - // implies that - // - // 'a : 'b - // - // and we could get even more if we took WF - // constraints into account. For example, - // - // &'a &'b int : 'c - // - // implies that - // - // 'b : 'a - // 'a : 'c + // We can basically ignore bound regions here. So for + // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to + // `'a: 'b`. + + // Ignore `for<'a> T: 'a` -- we might in the future + // consider this as evidence that `T: 'static`, but + // I'm a bit wary of such constructions and so for now + // I want to be conservative. --nmatsakis + let ty_max = data.skip_binder().0; + let r_min = data.skip_binder().1; + if r_min.is_bound() { + return; + } + + let visited = &mut self.visited; + self.stack.extend( + tcx.outlives_components(ty_max) + .into_iter() + .filter_map(|component| match component { + Component::Region(r) => if r.is_bound() { + None + } else { + Some(ty::Predicate::RegionOutlives( + ty::Binder(ty::OutlivesPredicate(r, r_min)))) + }, + + Component::Param(p) => { + let ty = tcx.mk_param(p.idx, p.name); + Some(ty::Predicate::TypeOutlives( + ty::Binder(ty::OutlivesPredicate(ty, r_min)))) + }, + + Component::UnresolvedInferenceVariable(_) => { + None + }, + + Component::Projection(_) | + Component::EscapingProjection(_) => { + // We can probably do more here. This + // corresponds to a case like `>::U: 'b`. + None + }, + }) + .filter(|p| visited.insert(p))); } } } @@ -235,7 +272,7 @@ pub fn transitive_bounds<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>, pub struct SupertraitDefIds<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, stack: Vec, - visited: FnvHashSet, + visited: FxHashSet, } pub fn supertrait_def_ids<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>, @@ -440,8 +477,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let mut entries = 0; // Count number of methods and add them to the total offset. // Skip over associated types and constants. - for trait_item in &self.trait_items(trait_ref.def_id())[..] { - if let ty::MethodTraitItem(_) = *trait_item { + for trait_item in self.associated_items(trait_ref.def_id()) { + if trait_item.kind == ty::AssociatedKind::Method { entries += 1; } } @@ -458,17 +495,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // add them to the total offset. // Skip over associated types and constants. let mut entries = object.vtable_base; - for trait_item in &self.trait_items(object.upcast_trait_ref.def_id())[..] { - if trait_item.def_id() == method_def_id { + for trait_item in self.associated_items(object.upcast_trait_ref.def_id()) { + if trait_item.def_id == method_def_id { // The item with the ID we were given really ought to be a method. - assert!(match *trait_item { - ty::MethodTraitItem(_) => true, - _ => false - }); - + assert_eq!(trait_item.kind, ty::AssociatedKind::Method); return entries; } - if let ty::MethodTraitItem(_) = *trait_item { + if trait_item.kind == ty::AssociatedKind::Method { entries += 1; } } diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index cfe370343ae4..333a5c74cb45 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::AutoAdjustment::*; -pub use self::AutoRef::*; - -use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFoldable}; +use ty::{self, Ty, TyCtxt, TypeAndMut}; use ty::LvaluePreference::{NoPreference}; use syntax::ast; @@ -20,116 +17,122 @@ use syntax_pos::Span; use hir; #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub enum AutoAdjustment<'tcx> { - AdjustNeverToAny(Ty<'tcx>), // go from ! to any type - AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type - AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer - AdjustMutToConstPointer, // go from a mut raw pointer to a const raw pointer - AdjustDerefRef(AutoDerefRef<'tcx>), +pub struct Adjustment<'tcx> { + pub kind: Adjust<'tcx>, + pub target: Ty<'tcx> } -/// Represents coercing a pointer to a different kind of pointer - where 'kind' -/// here means either or both of raw vs borrowed vs unique and fat vs thin. -/// -/// We transform pointers by following the following steps in order: -/// 1. Deref the pointer `self.autoderefs` times (may be 0). -/// 2. If `autoref` is `Some(_)`, then take the address and produce either a -/// `&` or `*` pointer. -/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, -/// which will do things like convert thin pointers to fat -/// pointers, or convert structs containing thin pointers to -/// structs containing fat pointers, or convert between fat -/// pointers. We don't store the details of how the transform is -/// done (in fact, we don't know that, because it might depend on -/// the precise type parameters). We just store the target -/// type. Trans figures out what has to be done at monomorphization -/// time based on the precise source/target type at hand. -/// -/// To make that more concrete, here are some common scenarios: -/// -/// 1. The simplest cases are where the pointer is not adjusted fat vs thin. -/// Here the pointer will be dereferenced N times (where a dereference can -/// happen to raw or borrowed pointers or any smart pointer which implements -/// Deref, including Box<_>). The number of dereferences is given by -/// `autoderefs`. It can then be auto-referenced zero or one times, indicated -/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is -/// None. -/// -/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start -/// with a thin pointer, deref a number of times, unsize the underlying data, -/// then autoref. The 'unsize' phase may change a fixed length array to a -/// dynamically sized one, a concrete object to a trait object, or statically -/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is -/// represented by: -/// -/// ``` -/// AutoDerefRef { -/// autoderefs: 1, // &[i32; 4] -> [i32; 4] -/// autoref: Some(AutoPtr), // [i32] -> &[i32] -/// unsize: Some([i32]), // [i32; 4] -> [i32] -/// } -/// ``` -/// -/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. -/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> -/// The autoderef and -ref are the same as in the above example, but the type -/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about -/// the underlying conversions from `[i32; 4]` to `[i32]`. -/// -/// 3. Coercing a `Box` to `Box` is an interesting special case. In -/// that case, we have the pointer we need coming in, so there are no -/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. -/// At some point, of course, `Box` should move out of the compiler, in which -/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> -/// Box<[i32]> is represented by: -/// -/// ``` -/// AutoDerefRef { -/// autoderefs: 0, -/// autoref: None, -/// unsize: Some(Box<[i32]>), -/// } -/// ``` -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub struct AutoDerefRef<'tcx> { - /// Step 1. Apply a number of dereferences, producing an lvalue. - pub autoderefs: usize, +#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] +pub enum Adjust<'tcx> { + /// Go from ! to any type. + NeverToAny, - /// Step 2. Optionally produce a pointer/reference from the value. - pub autoref: Option>, + /// Go from a fn-item type to a fn-pointer type. + ReifyFnPointer, - /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to - /// `&[T]`. The stored type is the target pointer type. Note that - /// the source could be a thin or fat pointer. - pub unsize: Option>, + /// Go from a safe fn pointer to an unsafe fn pointer. + UnsafeFnPointer, + + /// Go from a mut raw pointer to a const raw pointer. + MutToConstPointer, + + /// Represents coercing a pointer to a different kind of pointer - where 'kind' + /// here means either or both of raw vs borrowed vs unique and fat vs thin. + /// + /// We transform pointers by following the following steps in order: + /// 1. Deref the pointer `self.autoderefs` times (may be 0). + /// 2. If `autoref` is `Some(_)`, then take the address and produce either a + /// `&` or `*` pointer. + /// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, + /// which will do things like convert thin pointers to fat + /// pointers, or convert structs containing thin pointers to + /// structs containing fat pointers, or convert between fat + /// pointers. We don't store the details of how the transform is + /// done (in fact, we don't know that, because it might depend on + /// the precise type parameters). We just store the target + /// type. Trans figures out what has to be done at monomorphization + /// time based on the precise source/target type at hand. + /// + /// To make that more concrete, here are some common scenarios: + /// + /// 1. The simplest cases are where the pointer is not adjusted fat vs thin. + /// Here the pointer will be dereferenced N times (where a dereference can + /// happen to raw or borrowed pointers or any smart pointer which implements + /// Deref, including Box<_>). The number of dereferences is given by + /// `autoderefs`. It can then be auto-referenced zero or one times, indicated + /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is + /// None. + /// + /// 2. A thin-to-fat coercon involves unsizing the underlying data. We start + /// with a thin pointer, deref a number of times, unsize the underlying data, + /// then autoref. The 'unsize' phase may change a fixed length array to a + /// dynamically sized one, a concrete object to a trait object, or statically + /// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is + /// represented by: + /// + /// ``` + /// Adjust::DerefRef { + /// autoderefs: 1, // &[i32; 4] -> [i32; 4] + /// autoref: Some(AutoBorrow::Ref), // [i32] -> &[i32] + /// unsize: Some([i32]), // [i32; 4] -> [i32] + /// } + /// ``` + /// + /// Note that for a struct, the 'deep' unsizing of the struct is not recorded. + /// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> + /// The autoderef and -ref are the same as in the above example, but the type + /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about + /// the underlying conversions from `[i32; 4]` to `[i32]`. + /// + /// 3. Coercing a `Box` to `Box` is an interesting special case. In + /// that case, we have the pointer we need coming in, so there are no + /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. + /// At some point, of course, `Box` should move out of the compiler, in which + /// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> + /// Box<[i32]> is represented by: + /// + /// ``` + /// Adjust::DerefRef { + /// autoderefs: 0, + /// autoref: None, + /// unsize: Some(Box<[i32]>), + /// } + /// ``` + DerefRef { + /// Step 1. Apply a number of dereferences, producing an lvalue. + autoderefs: usize, + + /// Step 2. Optionally produce a pointer/reference from the value. + autoref: Option>, + + /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. Note that the source could be a thin or fat pointer. + unsize: bool, + } } -impl<'tcx> AutoAdjustment<'tcx> { +impl<'tcx> Adjustment<'tcx> { pub fn is_identity(&self) -> bool { - match *self { - AdjustNeverToAny(ty) => ty.is_never(), - AdjustReifyFnPointer | - AdjustUnsafeFnPointer | - AdjustMutToConstPointer => false, - AdjustDerefRef(ref r) => r.is_identity(), + match self.kind { + Adjust::NeverToAny => self.target.is_never(), + + Adjust::DerefRef { autoderefs: 0, autoref: None, unsize: false } => true, + + Adjust::ReifyFnPointer | + Adjust::UnsafeFnPointer | + Adjust::MutToConstPointer | + Adjust::DerefRef {..} => false, } } } -impl<'tcx> AutoDerefRef<'tcx> { - pub fn is_identity(&self) -> bool { - self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() - } -} - #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)] -pub enum AutoRef<'tcx> { +pub enum AutoBorrow<'tcx> { /// Convert from T to &T. - AutoPtr(&'tcx ty::Region, hir::Mutability), + Ref(&'tcx ty::Region, hir::Mutability), /// Convert from T to *T. - /// Value to thin pointer. - AutoUnsafe(hir::Mutability), + RawPtr(hir::Mutability), } #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] @@ -139,84 +142,6 @@ pub enum CustomCoerceUnsized { } impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> { - /// See `expr_ty_adjusted` - pub fn adjust(&'tcx self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - span: Span, - expr_id: ast::NodeId, - adjustment: Option<&AutoAdjustment<'tcx>>, - mut method_type: F) - -> Ty<'tcx> where - F: FnMut(ty::MethodCall) -> Option>, - { - if let ty::TyError = self.sty { - return self; - } - - return match adjustment { - Some(adjustment) => { - match *adjustment { - AdjustNeverToAny(ref ty) => ty, - - AdjustReifyFnPointer => { - match self.sty { - ty::TyFnDef(.., f) => tcx.mk_fn_ptr(f), - _ => { - bug!("AdjustReifyFnPointer adjustment on non-fn-item: {:?}", - self); - } - } - } - - AdjustUnsafeFnPointer => { - match self.sty { - ty::TyFnPtr(b) => tcx.safe_to_unsafe_fn_ty(b), - ref b => { - bug!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: {:?}", - b); - } - } - } - - AdjustMutToConstPointer => { - match self.sty { - ty::TyRawPtr(mt) => tcx.mk_ptr(ty::TypeAndMut { - ty: mt.ty, - mutbl: hir::MutImmutable - }), - ref b => { - bug!("AdjustMutToConstPointer on non-raw-ptr: {:?}", - b); - } - } - } - - AdjustDerefRef(ref adj) => { - let mut adjusted_ty = self; - - if !adjusted_ty.references_error() { - for i in 0..adj.autoderefs { - adjusted_ty = - adjusted_ty.adjust_for_autoderef(tcx, - expr_id, - span, - i as u32, - &mut method_type); - } - } - - if let Some(target) = adj.unsize { - target - } else { - adjusted_ty.adjust_for_autoref(tcx, adj.autoref) - } - } - } - } - None => self - }; - } - pub fn adjust_for_autoderef(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>, expr_id: ast::NodeId, @@ -247,14 +172,14 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> { } pub fn adjust_for_autoref(&'tcx self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - autoref: Option>) + autoref: Option>) -> Ty<'tcx> { match autoref { None => self, - Some(AutoPtr(r, m)) => { + Some(AutoBorrow::Ref(r, m)) => { tcx.mk_ref(r, TypeAndMut { ty: self, mutbl: m }) } - Some(AutoUnsafe(m)) => { + Some(AutoBorrow::RawPtr(m)) => { tcx.mk_ptr(TypeAndMut { ty: self, mutbl: m }) } } diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index b499e1346e73..7ed4de38be97 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -11,7 +11,7 @@ use hir::def_id::{DefId}; use ty::{self, Ty, TyCtxt}; use util::common::MemoizationMap; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use std::fmt; use std::ops; @@ -141,11 +141,11 @@ impl fmt::Debug for TypeContents { impl<'a, 'tcx> ty::TyS<'tcx> { pub fn type_contents(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> TypeContents { - return tcx.tc_cache.memoize(self, || tc_ty(tcx, self, &mut FnvHashMap())); + return tcx.tc_cache.memoize(self, || tc_ty(tcx, self, &mut FxHashMap())); fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, - cache: &mut FnvHashMap, TypeContents>) -> TypeContents + cache: &mut FxHashMap, TypeContents>) -> TypeContents { // Subtle: Note that we are *not* using tcx.tc_cache here but rather a // private cache for this walk. This is needed in the case of cyclic diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 62cc78141db4..60a48ba580a0 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -36,12 +36,12 @@ use ty::layout::{Layout, TargetDataLayout}; use ty::maps; use util::common::MemoizationMap; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; -use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; use arena::TypedArena; use std::borrow::Borrow; -use std::cell::{Cell, RefCell, Ref}; +use std::cell::{Cell, RefCell}; use std::hash::{Hash, Hasher}; use std::mem; use std::ops::Deref; @@ -96,26 +96,26 @@ pub struct CtxtInterners<'tcx> { /// Specifically use a speedy hash algorithm for these hash sets, /// they're accessed quite often. - type_: RefCell>>>, - type_list: RefCell>>>>, - substs: RefCell>>>, - bare_fn: RefCell>>>, - region: RefCell>>, - stability: RefCell>, - layout: RefCell>, + type_: RefCell>>>, + type_list: RefCell>>>>, + substs: RefCell>>>, + bare_fn: RefCell>>>, + region: RefCell>>, + stability: RefCell>, + layout: RefCell>, } impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { fn new(arenas: &'tcx CtxtArenas<'tcx>) -> CtxtInterners<'tcx> { CtxtInterners { arenas: arenas, - type_: RefCell::new(FnvHashSet()), - type_list: RefCell::new(FnvHashSet()), - substs: RefCell::new(FnvHashSet()), - bare_fn: RefCell::new(FnvHashSet()), - region: RefCell::new(FnvHashSet()), - stability: RefCell::new(FnvHashSet()), - layout: RefCell::new(FnvHashSet()) + type_: RefCell::new(FxHashSet()), + type_list: RefCell::new(FxHashSet()), + substs: RefCell::new(FxHashSet()), + bare_fn: RefCell::new(FxHashSet()), + region: RefCell::new(FxHashSet()), + stability: RefCell::new(FxHashSet()), + layout: RefCell::new(FxHashSet()) } } @@ -212,7 +212,7 @@ pub struct Tables<'tcx> { /// other items. pub item_substs: NodeMap>, - pub adjustments: NodeMap>, + pub adjustments: NodeMap>, pub method_map: ty::MethodMap<'tcx>, @@ -244,17 +244,87 @@ pub struct Tables<'tcx> { impl<'a, 'gcx, 'tcx> Tables<'tcx> { pub fn empty() -> Tables<'tcx> { Tables { - node_types: FnvHashMap(), + node_types: FxHashMap(), item_substs: NodeMap(), adjustments: NodeMap(), - method_map: FnvHashMap(), - upvar_capture_map: FnvHashMap(), + method_map: FxHashMap(), + upvar_capture_map: FxHashMap(), closure_tys: DefIdMap(), closure_kinds: DefIdMap(), liberated_fn_sigs: NodeMap(), fru_field_types: NodeMap() } } + + pub fn node_id_to_type(&self, id: NodeId) -> Ty<'tcx> { + match self.node_id_to_type_opt(id) { + Some(ty) => ty, + None => { + bug!("node_id_to_type: no type for node `{}`", + tls::with(|tcx| tcx.map.node_to_string(id))) + } + } + } + + pub fn node_id_to_type_opt(&self, id: NodeId) -> Option> { + self.node_types.get(&id).cloned() + } + + pub fn node_id_item_substs(&self, id: NodeId) -> Option<&'tcx Substs<'tcx>> { + self.item_substs.get(&id).map(|ts| ts.substs) + } + + // Returns the type of a pattern as a monotype. Like @expr_ty, this function + // doesn't provide type parameter substitutions. + pub fn pat_ty(&self, pat: &hir::Pat) -> Ty<'tcx> { + self.node_id_to_type(pat.id) + } + + pub fn pat_ty_opt(&self, pat: &hir::Pat) -> Option> { + self.node_id_to_type_opt(pat.id) + } + + // Returns the type of an expression as a monotype. + // + // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in + // some cases, we insert `Adjustment` annotations such as auto-deref or + // auto-ref. The type returned by this function does not consider such + // adjustments. See `expr_ty_adjusted()` instead. + // + // NB (2): This type doesn't provide type parameter substitutions; e.g. if you + // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" + // instead of "fn(ty) -> T with T = isize". + pub fn expr_ty(&self, expr: &hir::Expr) -> Ty<'tcx> { + self.node_id_to_type(expr.id) + } + + pub fn expr_ty_opt(&self, expr: &hir::Expr) -> Option> { + self.node_id_to_type_opt(expr.id) + } + + /// Returns the type of `expr`, considering any `Adjustment` + /// entry recorded for that expression. + pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> Ty<'tcx> { + self.adjustments.get(&expr.id) + .map_or_else(|| self.expr_ty(expr), |adj| adj.target) + } + + pub fn expr_ty_adjusted_opt(&self, expr: &hir::Expr) -> Option> { + self.adjustments.get(&expr.id) + .map(|adj| adj.target).or_else(|| self.expr_ty_opt(expr)) + } + + pub fn is_method_call(&self, expr_id: NodeId) -> bool { + self.method_map.contains_key(&ty::MethodCall::expr(expr_id)) + } + + pub fn is_overloaded_autoderef(&self, expr_id: NodeId, autoderefs: u32) -> bool { + self.method_map.contains_key(&ty::MethodCall::autoderef(expr_id, autoderefs)) + } + + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { + Some(self.upvar_capture_map.get(&upvar_id).unwrap().clone()) + } } impl<'tcx> CommonTypes<'tcx> { @@ -333,14 +403,10 @@ pub struct GlobalCtxt<'tcx> { pub tables: RefCell>, /// Maps from a trait item to the trait item "descriptor" - pub impl_or_trait_items: RefCell>>, + pub associated_items: RefCell>>, /// Maps from an impl/trait def-id to a list of the def-ids of its items - pub impl_or_trait_item_def_ids: RefCell>>, - - /// A cache for the trait_items() routine; note that the routine - /// itself pushes the `TraitItems` dependency node. - trait_items_cache: RefCell>>, + pub associated_item_def_ids: RefCell>>, pub impl_trait_refs: RefCell>>, pub trait_defs: RefCell>>, @@ -381,16 +447,16 @@ pub struct GlobalCtxt<'tcx> { pub tcache: RefCell>>, // Internal cache for metadata decoding. No need to track deps on this. - pub rcache: RefCell>>, + pub rcache: RefCell>>, // Cache for the type-contents routine. FIXME -- track deps? - pub tc_cache: RefCell, ty::contents::TypeContents>>, + pub tc_cache: RefCell, ty::contents::TypeContents>>, // FIXME no dep tracking, but we should be able to remove this pub ty_param_defs: RefCell>>, // FIXME dep tracking -- should be harmless enough - pub normalized_cache: RefCell, Ty<'tcx>>>, + pub normalized_cache: RefCell, Ty<'tcx>>>, pub lang_items: middle::lang_items::LanguageItems, @@ -501,7 +567,7 @@ pub struct GlobalCtxt<'tcx> { pub data_layout: TargetDataLayout, /// Cache for layouts computed from types. - pub layout_cache: RefCell, &'tcx Layout>>, + pub layout_cache: RefCell, &'tcx Layout>>, /// Used to prevent layout from recursing too deeply. pub layout_depth: Cell, @@ -599,14 +665,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.ty_param_defs.borrow().get(&node_id).unwrap().clone() } - pub fn node_types(self) -> Ref<'a, NodeMap>> { - fn projection<'a, 'tcx>(tables: &'a Tables<'tcx>) -> &'a NodeMap> { - &tables.node_types - } - - Ref::map(self.tables.borrow(), projection) - } - pub fn node_type_insert(self, id: NodeId, ty: Ty<'gcx>) { self.tables.borrow_mut().node_types.insert(id, ty); } @@ -739,7 +797,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { types: common_types, named_region_map: named_region_map, region_maps: region_maps, - free_region_maps: RefCell::new(FnvHashMap()), + free_region_maps: RefCell::new(FxHashMap()), item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())), variance_computed: Cell::new(false), sess: s, @@ -758,13 +816,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { freevars: RefCell::new(freevars), maybe_unused_trait_imports: maybe_unused_trait_imports, tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - rcache: RefCell::new(FnvHashMap()), - tc_cache: RefCell::new(FnvHashMap()), - impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - impl_or_trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - trait_items_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + rcache: RefCell::new(FxHashMap()), + tc_cache: RefCell::new(FxHashMap()), + associated_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + associated_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), ty_param_defs: RefCell::new(NodeMap()), - normalized_cache: RefCell::new(FnvHashMap()), + normalized_cache: RefCell::new(FxHashMap()), lang_items: lang_items, inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())), used_unsafe: RefCell::new(NodeSet()), @@ -784,7 +841,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { fragment_infos: RefCell::new(DefIdMap()), crate_name: token::intern_and_get_ident(crate_name), data_layout: data_layout, - layout_cache: RefCell::new(FnvHashMap()), + layout_cache: RefCell::new(FxHashMap()), layout_depth: Cell::new(0), derive_macros: RefCell::new(NodeMap()), }, f) @@ -1477,15 +1534,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from)) } - pub fn trait_items(self, trait_did: DefId) -> Rc>> { - self.trait_items_cache.memoize(trait_did, || { - let def_ids = self.impl_or_trait_items(trait_did); - Rc::new(def_ids.iter() - .map(|&def_id| self.impl_or_trait_item(def_id)) - .collect()) - }) - } - /// Obtain the representation annotation for a struct definition. pub fn lookup_repr_hints(self, did: DefId) -> Rc> { self.repr_hint_cache.memoize(did, || { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index ae0a4a0e6bd1..354658ec4397 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -45,7 +45,7 @@ use ty::adjustment; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use std::fmt; -use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::nodemap::{FxHashMap, FxHashSet}; /// The TypeFoldable trait is implemented for every type that can be folded. /// Basically, every type that has a corresponding method in TypeFolder. @@ -176,8 +176,8 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { r.super_fold_with(self) } - fn fold_autoref(&mut self, ar: &adjustment::AutoRef<'tcx>) - -> adjustment::AutoRef<'tcx> { + fn fold_autoref(&mut self, ar: &adjustment::AutoBorrow<'tcx>) + -> adjustment::AutoBorrow<'tcx> { ar.super_fold_with(self) } } @@ -225,7 +225,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// whether any late-bound regions were skipped pub fn collect_regions(self, value: &T, - region_set: &mut FnvHashSet<&'tcx ty::Region>) + region_set: &mut FxHashSet<&'tcx ty::Region>) -> bool where T : TypeFoldable<'tcx> { @@ -319,14 +319,14 @@ struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, current_depth: u32, fld_r: &'a mut (FnMut(ty::BoundRegion) -> &'tcx ty::Region + 'a), - map: FnvHashMap + map: FxHashMap } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn replace_late_bound_regions(self, value: &Binder, mut f: F) - -> (T, FnvHashMap) + -> (T, FxHashMap) where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region, T : TypeFoldable<'tcx>, { @@ -390,7 +390,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// variables and equate `value` with something else, those /// variables will also be equated. pub fn collect_constrained_late_bound_regions(&self, value: &Binder) - -> FnvHashSet + -> FxHashSet where T : TypeFoldable<'tcx> { self.collect_late_bound_regions(value, true) @@ -398,14 +398,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns a set of all late-bound regions that appear in `value` anywhere. pub fn collect_referenced_late_bound_regions(&self, value: &Binder) - -> FnvHashSet + -> FxHashSet where T : TypeFoldable<'tcx> { self.collect_late_bound_regions(value, false) } fn collect_late_bound_regions(&self, value: &Binder, just_constraint: bool) - -> FnvHashSet + -> FxHashSet where T : TypeFoldable<'tcx> { let mut collector = LateBoundRegionsCollector::new(just_constraint); @@ -450,7 +450,7 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { tcx: tcx, current_depth: 1, fld_r: fld_r, - map: FnvHashMap() + map: FxHashMap() } } } @@ -650,7 +650,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { /// Collects all the late-bound regions it finds into a hash set. struct LateBoundRegionsCollector { current_depth: u32, - regions: FnvHashSet, + regions: FxHashSet, just_constrained: bool, } @@ -658,7 +658,7 @@ impl LateBoundRegionsCollector { fn new(just_constrained: bool) -> Self { LateBoundRegionsCollector { current_depth: 1, - regions: FnvHashSet(), + regions: FxHashSet(), just_constrained: just_constrained, } } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index cad87081a93b..43abb61e7fcd 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -16,7 +16,7 @@ use ty::{self, Ty}; use std::cell::RefCell; use std::marker::PhantomData; use std::rc::Rc; -use syntax::{attr, ast}; +use syntax::attr; macro_rules! dep_map_ty { ($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => { @@ -32,18 +32,16 @@ macro_rules! dep_map_ty { } } -dep_map_ty! { ImplOrTraitItems: ImplOrTraitItems(DefId) -> ty::ImplOrTraitItem<'tcx> } +dep_map_ty! { AssociatedItems: AssociatedItems(DefId) -> ty::AssociatedItem } dep_map_ty! { Tcache: ItemSignature(DefId) -> Ty<'tcx> } dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> } dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } -dep_map_ty! { ImplOrTraitItemDefIds: ImplOrTraitItemDefIds(DefId) -> Rc> } +dep_map_ty! { AssociatedItemDefIds: AssociatedItemDefIds(DefId) -> Rc> } dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option> } dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> } dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> } dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc> } dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec } -dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc> } -dep_map_ty! { InlinedClosures: Hir(DefId) -> ast::NodeId } dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 588857e557c2..1d260fd65fef 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -10,9 +10,8 @@ pub use self::Variance::*; pub use self::DtorKind::*; -pub use self::ImplOrTraitItemContainer::*; +pub use self::AssociatedItemContainer::*; pub use self::BorrowKind::*; -pub use self::ImplOrTraitItem::*; pub use self::IntVarValue::*; pub use self::LvaluePreference::*; pub use self::fold::TypeFoldable; @@ -31,7 +30,7 @@ use ty::subst::{Subst, Substs}; use ty::walk::TypeWalker; use util::common::MemoizationMap; use util::nodemap::NodeSet; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use serialize::{self, Encodable, Encoder}; use std::borrow::Cow; @@ -135,12 +134,12 @@ impl DtorKind { } #[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum ImplOrTraitItemContainer { +pub enum AssociatedItemContainer { TraitContainer(DefId), ImplContainer(DefId), } -impl ImplOrTraitItemContainer { +impl AssociatedItemContainer { pub fn id(&self) -> DefId { match *self { TraitContainer(id) => id, @@ -183,58 +182,34 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> { } } -#[derive(Clone)] -pub enum ImplOrTraitItem<'tcx> { - ConstTraitItem(Rc>), - MethodTraitItem(Rc>), - TypeTraitItem(Rc>), +#[derive(Copy, Clone, Debug)] +pub struct AssociatedItem { + pub def_id: DefId, + pub name: Name, + pub kind: AssociatedKind, + pub vis: Visibility, + pub defaultness: hir::Defaultness, + pub has_value: bool, + pub container: AssociatedItemContainer, + + /// Whether this is a method with an explicit self + /// as its first argument, allowing method calls. + pub method_has_self_argument: bool, } -impl<'tcx> ImplOrTraitItem<'tcx> { +#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] +pub enum AssociatedKind { + Const, + Method, + Type +} + +impl AssociatedItem { pub fn def(&self) -> Def { - match *self { - ConstTraitItem(ref associated_const) => Def::AssociatedConst(associated_const.def_id), - MethodTraitItem(ref method) => Def::Method(method.def_id), - TypeTraitItem(ref ty) => Def::AssociatedTy(ty.def_id), - } - } - - pub fn def_id(&self) -> DefId { - match *self { - ConstTraitItem(ref associated_const) => associated_const.def_id, - MethodTraitItem(ref method) => method.def_id, - TypeTraitItem(ref associated_type) => associated_type.def_id, - } - } - - pub fn name(&self) -> Name { - match *self { - ConstTraitItem(ref associated_const) => associated_const.name, - MethodTraitItem(ref method) => method.name, - TypeTraitItem(ref associated_type) => associated_type.name, - } - } - - pub fn vis(&self) -> Visibility { - match *self { - ConstTraitItem(ref associated_const) => associated_const.vis, - MethodTraitItem(ref method) => method.vis, - TypeTraitItem(ref associated_type) => associated_type.vis, - } - } - - pub fn container(&self) -> ImplOrTraitItemContainer { - match *self { - ConstTraitItem(ref associated_const) => associated_const.container, - MethodTraitItem(ref method) => method.container, - TypeTraitItem(ref associated_type) => associated_type.container, - } - } - - pub fn as_opt_method(&self) -> Option>> { - match *self { - MethodTraitItem(ref m) => Some((*m).clone()), - _ => None, + match self.kind { + AssociatedKind::Const => Def::AssociatedConst(self.def_id), + AssociatedKind::Method => Def::Method(self.def_id), + AssociatedKind::Type => Def::AssociatedTy(self.def_id), } } } @@ -308,64 +283,6 @@ impl Visibility { } } -#[derive(Clone, Debug)] -pub struct Method<'tcx> { - pub name: Name, - pub generics: &'tcx Generics<'tcx>, - pub predicates: GenericPredicates<'tcx>, - pub fty: &'tcx BareFnTy<'tcx>, - pub explicit_self: ExplicitSelfCategory<'tcx>, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub has_body: bool, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, -} - -impl<'tcx> Method<'tcx> { - pub fn container_id(&self) -> DefId { - match self.container { - TraitContainer(id) => id, - ImplContainer(id) => id, - } - } -} - -impl<'tcx> PartialEq for Method<'tcx> { - #[inline] - fn eq(&self, other: &Self) -> bool { self.def_id == other.def_id } -} - -impl<'tcx> Eq for Method<'tcx> {} - -impl<'tcx> Hash for Method<'tcx> { - #[inline] - fn hash(&self, s: &mut H) { - self.def_id.hash(s) - } -} - -#[derive(Clone, Copy, Debug)] -pub struct AssociatedConst<'tcx> { - pub name: Name, - pub ty: Ty<'tcx>, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, - pub has_value: bool -} - -#[derive(Clone, Copy, Debug)] -pub struct AssociatedType<'tcx> { - pub name: Name, - pub ty: Option>, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, -} - #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type @@ -418,7 +335,7 @@ impl MethodCall { // maps from an expression id that corresponds to a method call to the details // of the method to be invoked -pub type MethodMap<'tcx> = FnvHashMap>; +pub type MethodMap<'tcx> = FxHashMap>; // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. @@ -650,7 +567,7 @@ pub struct UpvarBorrow<'tcx> { pub region: &'tcx ty::Region, } -pub type UpvarCaptureMap<'tcx> = FnvHashMap>; +pub type UpvarCaptureMap<'tcx> = FxHashMap>; #[derive(Copy, Clone)] pub struct ClosureUpvar<'tcx> { @@ -1251,10 +1168,10 @@ pub struct ParameterEnvironment<'tcx> { pub free_id_outlive: CodeExtent, /// A cache for `moves_by_default`. - pub is_copy_cache: RefCell, bool>>, + pub is_copy_cache: RefCell, bool>>, /// A cache for `type_is_sized` - pub is_sized_cache: RefCell, bool>>, + pub is_sized_cache: RefCell, bool>>, } impl<'a, 'tcx> ParameterEnvironment<'tcx> { @@ -1267,8 +1184,8 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { implicit_region_bound: self.implicit_region_bound, caller_bounds: caller_bounds, free_id_outlive: self.free_id_outlive, - is_copy_cache: RefCell::new(FnvHashMap()), - is_sized_cache: RefCell::new(FnvHashMap()), + is_copy_cache: RefCell::new(FxHashMap()), + is_sized_cache: RefCell::new(FxHashMap()), } } @@ -1288,19 +1205,10 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { tcx.region_maps.item_extent(id)) } hir::ImplItemKind::Method(_, ref body) => { - let method_def_id = tcx.map.local_def_id(id); - match tcx.impl_or_trait_item(method_def_id) { - MethodTraitItem(ref method_ty) => { - tcx.construct_parameter_environment( - impl_item.span, - method_ty.def_id, - tcx.region_maps.call_site_extent(id, body.id)) - } - _ => { - bug!("ParameterEnvironment::for_item(): \ - got non-method item from impl method?!") - } - } + tcx.construct_parameter_environment( + impl_item.span, + tcx.map.local_def_id(id), + tcx.region_maps.call_site_extent(id, body.id)) } } } @@ -1319,27 +1227,17 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { // Use call-site for extent (unless this is a // trait method with no default; then fallback // to the method id). - let method_def_id = tcx.map.local_def_id(id); - match tcx.impl_or_trait_item(method_def_id) { - MethodTraitItem(ref method_ty) => { - let extent = if let Some(ref body) = *body { - // default impl: use call_site extent as free_id_outlive bound. - tcx.region_maps.call_site_extent(id, body.id) - } else { - // no default impl: use item extent as free_id_outlive bound. - tcx.region_maps.item_extent(id) - }; - tcx.construct_parameter_environment( - trait_item.span, - method_ty.def_id, - extent) - } - _ => { - bug!("ParameterEnvironment::for_item(): \ - got non-method item from provided \ - method?!") - } - } + let extent = if let Some(ref body) = *body { + // default impl: use call_site extent as free_id_outlive bound. + tcx.region_maps.call_site_extent(id, body.id) + } else { + // no default impl: use item extent as free_id_outlive bound. + tcx.region_maps.item_extent(id) + }; + tcx.construct_parameter_environment( + trait_item.span, + tcx.map.local_def_id(id), + extent) } } } @@ -2065,7 +1963,7 @@ impl LvaluePreference { } /// Helper for looking things up in the various maps that are populated during -/// typeck::collect (e.g., `tcx.impl_or_trait_items`, `tcx.tcache`, etc). All of +/// typeck::collect (e.g., `tcx.associated_items`, `tcx.tcache`, etc). All of /// these share the pattern that if the id is local, it should have been loaded /// into the map by the `typeck::collect` phase. If the def-id is external, /// then we have to go consult the crate loading code (and cache the result for @@ -2120,80 +2018,8 @@ impl BorrowKind { } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - pub fn node_id_to_type(self, id: NodeId) -> Ty<'gcx> { - match self.node_id_to_type_opt(id) { - Some(ty) => ty, - None => bug!("node_id_to_type: no type for node `{}`", - self.map.node_to_string(id)) - } - } - - pub fn node_id_to_type_opt(self, id: NodeId) -> Option> { - self.tables.borrow().node_types.get(&id).cloned() - } - - pub fn node_id_item_substs(self, id: NodeId) -> ItemSubsts<'gcx> { - match self.tables.borrow().item_substs.get(&id) { - None => ItemSubsts { - substs: self.global_tcx().intern_substs(&[]) - }, - Some(ts) => ts.clone(), - } - } - - // Returns the type of a pattern as a monotype. Like @expr_ty, this function - // doesn't provide type parameter substitutions. - pub fn pat_ty(self, pat: &hir::Pat) -> Ty<'gcx> { - self.node_id_to_type(pat.id) - } - pub fn pat_ty_opt(self, pat: &hir::Pat) -> Option> { - self.node_id_to_type_opt(pat.id) - } - - // Returns the type of an expression as a monotype. - // - // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in - // some cases, we insert `AutoAdjustment` annotations such as auto-deref or - // auto-ref. The type returned by this function does not consider such - // adjustments. See `expr_ty_adjusted()` instead. - // - // NB (2): This type doesn't provide type parameter substitutions; e.g. if you - // ask for the type of "id" in "id(3)", it will return "fn(&isize) -> isize" - // instead of "fn(ty) -> T with T = isize". - pub fn expr_ty(self, expr: &hir::Expr) -> Ty<'gcx> { - self.node_id_to_type(expr.id) - } - - pub fn expr_ty_opt(self, expr: &hir::Expr) -> Option> { - self.node_id_to_type_opt(expr.id) - } - - /// Returns the type of `expr`, considering any `AutoAdjustment` - /// entry recorded for that expression. - /// - /// It would almost certainly be better to store the adjusted ty in with - /// the `AutoAdjustment`, but I opted not to do this because it would - /// require serializing and deserializing the type and, although that's not - /// hard to do, I just hate that code so much I didn't want to touch it - /// unless it was to fix it properly, which seemed a distraction from the - /// thread at hand! -nmatsakis - pub fn expr_ty_adjusted(self, expr: &hir::Expr) -> Ty<'gcx> { - self.expr_ty(expr) - .adjust(self.global_tcx(), expr.span, expr.id, - self.tables.borrow().adjustments.get(&expr.id), - |method_call| { - self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) - }) - } - - pub fn expr_ty_adjusted_opt(self, expr: &hir::Expr) -> Option> { - self.expr_ty_opt(expr).map(|t| t.adjust(self.global_tcx(), - expr.span, - expr.id, - self.tables.borrow().adjustments.get(&expr.id), - |method_call| { - self.tables.borrow().method_map.get(&method_call).map(|method| method.ty) - })) + pub fn tables(self) -> Ref<'a, Tables<'gcx>> { + self.tables.borrow() } pub fn expr_span(self, id: NodeId) -> Span { @@ -2276,13 +2102,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn provided_trait_methods(self, id: DefId) -> Vec>> { - self.impl_or_trait_items(id).iter().filter_map(|&def_id| { - match self.impl_or_trait_item(def_id) { - MethodTraitItem(ref m) if m.has_body => Some(m.clone()), - _ => None - } - }).collect() + pub fn provided_trait_methods(self, id: DefId) -> Vec { + self.associated_items(id) + .filter(|item| item.kind == AssociatedKind::Method && item.has_value) + .collect() } pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity { @@ -2315,17 +2138,105 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } - pub fn impl_or_trait_item(self, id: DefId) -> ImplOrTraitItem<'gcx> { - lookup_locally_or_in_crate_store( - "impl_or_trait_items", id, &self.impl_or_trait_items, - || self.sess.cstore.impl_or_trait_item(self.global_tcx(), id) - .expect("missing ImplOrTraitItem in metadata")) + pub fn associated_item(self, def_id: DefId) -> AssociatedItem { + self.associated_items.memoize(def_id, || { + if !def_id.is_local() { + return self.sess.cstore.associated_item(self.global_tcx(), def_id) + .expect("missing AssociatedItem in metadata"); + } + + let id = self.map.as_local_node_id(def_id).unwrap(); + let parent_id = self.map.get_parent(id); + let parent_def_id = self.map.local_def_id(parent_id); + match self.map.get(id) { + ast_map::NodeTraitItem(trait_item) => { + let (kind, has_self, has_value) = match trait_item.node { + hir::MethodTraitItem(ref sig, ref body) => { + (AssociatedKind::Method, sig.decl.get_self().is_some(), + body.is_some()) + } + hir::ConstTraitItem(_, ref value) => { + (AssociatedKind::Const, false, value.is_some()) + } + hir::TypeTraitItem(_, ref ty) => { + (AssociatedKind::Type, false, ty.is_some()) + } + }; + + AssociatedItem { + name: trait_item.name, + kind: kind, + vis: Visibility::from_hir(&hir::Inherited, id, self), + defaultness: hir::Defaultness::Default, + has_value: has_value, + def_id: def_id, + container: TraitContainer(parent_def_id), + method_has_self_argument: has_self + } + } + ast_map::NodeImplItem(impl_item) => { + let (kind, has_self) = match impl_item.node { + hir::ImplItemKind::Method(ref sig, _) => { + (AssociatedKind::Method, sig.decl.get_self().is_some()) + } + hir::ImplItemKind::Const(..) => (AssociatedKind::Const, false), + hir::ImplItemKind::Type(..) => (AssociatedKind::Type, false) + }; + + // Trait impl items are always public. + let public = hir::Public; + let parent_item = self.map.expect_item(parent_id); + let vis = if let hir::ItemImpl(.., Some(_), _, _) = parent_item.node { + &public + } else { + &impl_item.vis + }; + + AssociatedItem { + name: impl_item.name, + kind: kind, + vis: Visibility::from_hir(vis, id, self), + defaultness: impl_item.defaultness, + has_value: true, + def_id: def_id, + container: ImplContainer(parent_def_id), + method_has_self_argument: has_self + } + } + item => bug!("associated_item: {:?} not an associated item", item) + } + }) } - pub fn impl_or_trait_items(self, id: DefId) -> Rc> { - lookup_locally_or_in_crate_store( - "impl_or_trait_items", id, &self.impl_or_trait_item_def_ids, - || Rc::new(self.sess.cstore.impl_or_trait_items(id))) + pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { + self.associated_item_def_ids.memoize(def_id, || { + if !def_id.is_local() { + return Rc::new(self.sess.cstore.associated_item_def_ids(def_id)); + } + + let id = self.map.as_local_node_id(def_id).unwrap(); + let item = self.map.expect_item(id); + match item.node { + hir::ItemTrait(.., ref trait_items) => { + Rc::new(trait_items.iter().map(|trait_item| { + self.map.local_def_id(trait_item.id) + }).collect()) + } + hir::ItemImpl(.., ref impl_items) => { + Rc::new(impl_items.iter().map(|impl_item| { + self.map.local_def_id(impl_item.id) + }).collect()) + } + _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") + } + }) + } + + #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. + pub fn associated_items(self, def_id: DefId) + -> impl Iterator + 'a { + let def_ids = self.associated_item_def_ids(def_id); + (0..def_ids.len()).map(move |i| self.associated_item(def_ids[i])) } /// Returns the trait-ref corresponding to a given impl, or None if it is @@ -2611,31 +2522,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL) } - /// Load primitive inherent implementations if necessary - pub fn populate_implementations_for_primitive_if_necessary(self, - primitive_def_id: DefId) { - if primitive_def_id.is_local() { - return - } - - // The primitive is not local, hence we are reading this out - // of metadata. - let _ignore = self.dep_graph.in_ignore(); - - if self.populated_external_primitive_impls.borrow().contains(&primitive_def_id) { - return - } - - debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", - primitive_def_id); - - let impl_items = self.sess.cstore.impl_or_trait_items(primitive_def_id); - - // Store the implementation info. - self.impl_or_trait_item_def_ids.borrow_mut().insert(primitive_def_id, Rc::new(impl_items)); - self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); - } - /// Populates the type context with all the inherent implementations for /// the given type if necessary. pub fn populate_inherent_implementations_for_type_if_necessary(self, @@ -2656,11 +2542,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { type_id); let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id); - for &impl_def_id in &inherent_impls { - // Store the implementation info. - let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id); - self.impl_or_trait_item_def_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); - } self.inherent_impls.borrow_mut().insert(type_id, inherent_impls); self.populated_external_types.borrow_mut().insert(type_id); @@ -2689,23 +2570,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) { - let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id); let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); // Record the trait->implementation mapping. let parent = self.sess.cstore.impl_parent(impl_def_id).unwrap_or(trait_id); def.record_remote_impl(self, impl_def_id, trait_ref, parent); - - // For any methods that use a default implementation, add them to - // the map. This is a bit unfortunate. - for &impl_item_def_id in &impl_items { - // load impl items eagerly for convenience - // FIXME: we may want to load these lazily - self.impl_or_trait_item(impl_item_def_id); - } - - // Store the implementation info. - self.impl_or_trait_item_def_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); } def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); @@ -2751,17 +2620,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// ID of the impl that the method belongs to. Otherwise, return `None`. pub fn impl_of_method(self, def_id: DefId) -> Option { if def_id.krate != LOCAL_CRATE { - return self.sess.cstore.impl_or_trait_item(self.global_tcx(), def_id) + return self.sess.cstore.associated_item(self.global_tcx(), def_id) .and_then(|item| { - match item.container() { + match item.container { TraitContainer(_) => None, ImplContainer(def_id) => Some(def_id), } }); } - match self.impl_or_trait_items.borrow().get(&def_id).cloned() { + match self.associated_items.borrow().get(&def_id).cloned() { Some(trait_item) => { - match trait_item.container() { + match trait_item.container { TraitContainer(_) => None, ImplContainer(def_id) => Some(def_id), } @@ -2777,9 +2646,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if def_id.krate != LOCAL_CRATE { return self.sess.cstore.trait_of_item(def_id); } - match self.impl_or_trait_items.borrow().get(&def_id) { - Some(impl_or_trait_item) => { - match impl_or_trait_item.container() { + match self.associated_items.borrow().get(&def_id) { + Some(associated_item) => { + match associated_item.container { TraitContainer(def_id) => Some(def_id), ImplContainer(_) => None } @@ -2788,30 +2657,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// If the given def ID describes an item belonging to a trait, (either a - /// default method or an implementation of a trait method), return the ID of - /// the method inside trait definition (this means that if the given def ID - /// is already that of the original trait method, then the return value is - /// the same). - /// Otherwise, return `None`. - pub fn trait_item_of_item(self, def_id: DefId) -> Option { - let impl_or_trait_item = match self.impl_or_trait_items.borrow().get(&def_id) { - Some(m) => m.clone(), - None => return None, - }; - match impl_or_trait_item.container() { - TraitContainer(_) => Some(impl_or_trait_item.def_id()), - ImplContainer(def_id) => { - self.trait_id_of_impl(def_id).and_then(|trait_did| { - let name = impl_or_trait_item.name(); - self.trait_items(trait_did).iter() - .find(|item| item.name() == name) - .map(|item| item.def_id()) - }) - } - } - } - /// Construct a parameter environment suitable for static contexts or other contexts where there /// are no free type/lifetime parameters in scope. pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> { @@ -2824,8 +2669,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { caller_bounds: Vec::new(), implicit_region_bound: self.mk_region(ty::ReEmpty), free_id_outlive: free_id_outlive, - is_copy_cache: RefCell::new(FnvHashMap()), - is_sized_cache: RefCell::new(FnvHashMap()), + is_copy_cache: RefCell::new(FxHashMap()), + is_sized_cache: RefCell::new(FxHashMap()), } } @@ -2896,8 +2741,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { implicit_region_bound: tcx.mk_region(ty::ReScope(free_id_outlive)), caller_bounds: predicates, free_id_outlive: free_id_outlive, - is_copy_cache: RefCell::new(FnvHashMap()), - is_sized_cache: RefCell::new(FnvHashMap()), + is_copy_cache: RefCell::new(FxHashMap()), + is_sized_cache: RefCell::new(FxHashMap()), }; let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps)); @@ -2908,19 +2753,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_region(ty::ReScope(self.region_maps.node_extent(id))) } - pub fn is_method_call(self, expr_id: NodeId) -> bool { - self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id)) - } - - pub fn is_overloaded_autoderef(self, expr_id: NodeId, autoderefs: u32) -> bool { - self.tables.borrow().method_map.contains_key(&MethodCall::autoderef(expr_id, - autoderefs)) - } - - pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option> { - Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) - } - pub fn visit_all_items_in_krate(self, dep_node_fn: F, visitor: &mut V) @@ -2941,15 +2773,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } -/// The category of explicit self. -#[derive(Clone, Copy, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)] -pub enum ExplicitSelfCategory<'tcx> { - Static, - ByValue, - ByReference(&'tcx Region, hir::Mutability), - ByBox, -} - impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn with_freevars(self, fid: NodeId, f: F) -> T where F: FnOnce(&[hir::Freevar]) -> T, diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index a4edd3b93c94..51feab9d40c9 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -12,8 +12,7 @@ // refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that // RFC for reference. -use infer::InferCtxt; -use ty::{self, Ty, TypeFoldable}; +use ty::{self, Ty, TyCtxt, TypeFoldable}; #[derive(Debug)] pub enum Component<'tcx> { @@ -55,9 +54,9 @@ pub enum Component<'tcx> { EscapingProjection(Vec>), } -impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns all the things that must outlive `'a` for the condition - /// `ty0: 'a` to hold. + /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. pub fn outlives_components(&self, ty0: Ty<'tcx>) -> Vec> { let mut components = vec![]; @@ -148,16 +147,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - // If we encounter an inference variable, try to resolve it - // and proceed with resolved version. If we cannot resolve it, - // then record the unresolved variable as a component. - ty::TyInfer(_) => { - let ty = self.resolve_type_vars_if_possible(&ty); - if let ty::TyInfer(infer_ty) = ty.sty { - out.push(Component::UnresolvedInferenceVariable(infer_ty)); - } else { - self.compute_components(ty, out); - } + // We assume that inference variables are fully resolved. + // So, if we encounter an inference variable, just record + // the unresolved variable as a component. + ty::TyInfer(infer_ty) => { + out.push(Component::UnresolvedInferenceVariable(infer_ty)); } // Most types do not introduce any region binders, nor diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 3165edebf1a4..9ca911837b51 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -218,15 +218,15 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ItemSubsts<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoRef<'a> { - type Lifted = ty::adjustment::AutoRef<'tcx>; +impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { + type Lifted = ty::adjustment::AutoBorrow<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { match *self { - ty::adjustment::AutoPtr(r, m) => { - tcx.lift(&r).map(|r| ty::adjustment::AutoPtr(r, m)) + ty::adjustment::AutoBorrow::Ref(r, m) => { + tcx.lift(&r).map(|r| ty::adjustment::AutoBorrow::Ref(r, m)) } - ty::adjustment::AutoUnsafe(m) => { - Some(ty::adjustment::AutoUnsafe(m)) + ty::adjustment::AutoBorrow::RawPtr(m) => { + Some(ty::adjustment::AutoBorrow::RawPtr(m)) } } } @@ -676,13 +676,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ItemSubsts<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { - ty::adjustment::AutoPtr(ref r, m) => { - ty::adjustment::AutoPtr(r.fold_with(folder), m) + ty::adjustment::AutoBorrow::Ref(ref r, m) => { + ty::adjustment::AutoBorrow::Ref(r.fold_with(folder), m) } - ty::adjustment::AutoUnsafe(m) => ty::adjustment::AutoUnsafe(m) + ty::adjustment::AutoBorrow::RawPtr(m) => ty::adjustment::AutoBorrow::RawPtr(m) } } @@ -692,8 +692,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoRef<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { - ty::adjustment::AutoPtr(r, _m) => r.visit_with(visitor), - ty::adjustment::AutoUnsafe(_m) => false, + ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor), + ty::adjustment::AutoBorrow::RawPtr(_m) => false, } } } diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 3ff2ed76e571..fc3202994838 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -16,7 +16,7 @@ use ty::fast_reject; use ty::{Ty, TyCtxt, TraitRef}; use std::cell::{Cell, RefCell}; use hir; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; /// As `TypeScheme` but for a trait ref. pub struct TraitDef<'tcx> { @@ -55,7 +55,7 @@ pub struct TraitDef<'tcx> { /// Impls of the trait. nonblanket_impls: RefCell< - FnvHashMap> + FxHashMap> >, /// Blanket impls associated with the trait. @@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { unsafety: unsafety, generics: generics, trait_ref: trait_ref, - nonblanket_impls: RefCell::new(FnvHashMap()), + nonblanket_impls: RefCell::new(FxHashMap()), blanket_impls: RefCell::new(vec![]), flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS), specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()), diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index cca4069ba5a1..b1aeaeb48d14 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -20,7 +20,7 @@ use ty::{Disr, ParameterEnvironment}; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; use ty::TypeVariants::*; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; @@ -594,7 +594,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: &ParameterEnvironment<'tcx>, bound: ty::BuiltinBound, - cache: &RefCell, bool>>, + cache: &RefCell, bool>>, span: Span) -> bool { if self.has_param_types() || self.has_self_ty() { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 1135199d2254..155fa4989ea3 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -178,7 +178,8 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( match infcx.tcx.no_late_bound_regions(data) { None => vec![], Some(ty::OutlivesPredicate(ty_a, r_b)) => { - let components = infcx.outlives_components(ty_a); + let ty_a = infcx.resolve_type_vars_if_possible(&ty_a); + let components = infcx.tcx.outlives_components(ty_a); implied_bounds_from_components(r_b, components) } }, @@ -497,7 +498,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let explicit_bound = data.region_bound; for implicit_bound in implicit_bounds { - let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); + let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound)); self.out.push(traits::Obligation::new(cause, outlives.to_predicate())); } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 78f20b77f318..7cd5fd78df52 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -75,6 +75,26 @@ pub fn duration_to_secs_str(dur: Duration) -> String { format!("{:.3}", secs) } +pub fn to_readable_str(mut val: usize) -> String { + let mut groups = vec![]; + loop { + let group = val % 1000; + + val /= 1000; + + if val == 0 { + groups.push(format!("{}", group)); + break + } else { + groups.push(format!("{:03}", group)); + } + } + + groups.reverse(); + + groups.join("_") +} + pub fn record_time(accu: &Cell, f: F) -> T where F: FnOnce() -> T, { @@ -264,3 +284,17 @@ pub fn path2cstr(p: &Path) -> CString { pub fn path2cstr(p: &Path) -> CString { CString::new(p.to_str().unwrap()).unwrap() } + + +#[test] +fn test_to_readable_str() { + assert_eq!("0", to_readable_str(0)); + assert_eq!("1", to_readable_str(1)); + assert_eq!("99", to_readable_str(99)); + assert_eq!("999", to_readable_str(999)); + assert_eq!("1_000", to_readable_str(1_000)); + assert_eq!("1_001", to_readable_str(1_001)); + assert_eq!("999_999", to_readable_str(999_999)); + assert_eq!("1_000_000", to_readable_str(1_000_000)); + assert_eq!("1_234_567", to_readable_str(1_234_567)); +} diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs index 69bcc9cbfffe..b03011fcb216 100644 --- a/src/librustc/util/nodemap.rs +++ b/src/librustc/util/nodemap.rs @@ -15,17 +15,17 @@ use hir::def_id::DefId; use syntax::ast; -pub use rustc_data_structures::fnv::FnvHashMap; -pub use rustc_data_structures::fnv::FnvHashSet; +pub use rustc_data_structures::fx::FxHashMap; +pub use rustc_data_structures::fx::FxHashSet; -pub type NodeMap = FnvHashMap; -pub type DefIdMap = FnvHashMap; +pub type NodeMap = FxHashMap; +pub type DefIdMap = FxHashMap; -pub type NodeSet = FnvHashSet; -pub type DefIdSet = FnvHashSet; +pub type NodeSet = FxHashSet; +pub type DefIdSet = FxHashSet; -pub fn NodeMap() -> NodeMap { FnvHashMap() } -pub fn DefIdMap() -> DefIdMap { FnvHashMap() } -pub fn NodeSet() -> NodeSet { FnvHashSet() } -pub fn DefIdSet() -> DefIdSet { FnvHashSet() } +pub fn NodeMap() -> NodeMap { FxHashMap() } +pub fn DefIdMap() -> DefIdMap { FxHashMap() } +pub fn NodeSet() -> NodeSet { FxHashSet() } +pub fn DefIdSet() -> DefIdSet { FxHashSet() } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 954e3b1fc13c..01b44ced8e08 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -447,32 +447,9 @@ impl<'tcx, 'container> fmt::Debug for ty::AdtDefData<'tcx, 'container> { } } -impl<'tcx> fmt::Debug for ty::adjustment::AutoAdjustment<'tcx> { +impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ty::adjustment::AdjustNeverToAny(ref target) => { - write!(f, "AdjustNeverToAny({:?})", target) - } - ty::adjustment::AdjustReifyFnPointer => { - write!(f, "AdjustReifyFnPointer") - } - ty::adjustment::AdjustUnsafeFnPointer => { - write!(f, "AdjustUnsafeFnPointer") - } - ty::adjustment::AdjustMutToConstPointer => { - write!(f, "AdjustMutToConstPointer") - } - ty::adjustment::AdjustDerefRef(ref data) => { - write!(f, "{:?}", data) - } - } - } -} - -impl<'tcx> fmt::Debug for ty::adjustment::AutoDerefRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "AutoDerefRef({}, unsize={:?}, {:?})", - self.autoderefs, self.unsize, self.autoref) + write!(f, "{:?} -> {}", self.kind, self.target) } } @@ -693,18 +670,6 @@ impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ImplOrTraitItem<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ImplOrTraitItem(")?; - match *self { - ty::ImplOrTraitItem::MethodTraitItem(ref i) => write!(f, "{:?}", i), - ty::ImplOrTraitItem::ConstTraitItem(ref i) => write!(f, "{:?}", i), - ty::ImplOrTraitItem::TypeTraitItem(ref i) => write!(f, "{:?}", i), - }?; - write!(f, ")") - } -} - impl<'tcx> fmt::Display for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "fn")?; @@ -1018,20 +983,6 @@ impl fmt::Display for ty::InferTy { } } -impl<'tcx> fmt::Display for ty::ExplicitSelfCategory<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match *self { - ty::ExplicitSelfCategory::Static => "static", - ty::ExplicitSelfCategory::ByValue => "self", - ty::ExplicitSelfCategory::ByReference(_, hir::MutMutable) => { - "&mut self" - } - ty::ExplicitSelfCategory::ByReference(_, hir::MutImmutable) => "&self", - ty::ExplicitSelfCategory::ByBox => "Box", - }) - } -} - impl fmt::Display for ty::ParamTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.name) diff --git a/src/librustc_back/target/aarch64_unknown_fuchsia.rs b/src/librustc_back/target/aarch64_unknown_fuchsia.rs index a93a46d14023..6ba1732e67f7 100644 --- a/src/librustc_back/target/aarch64_unknown_fuchsia.rs +++ b/src/librustc_back/target/aarch64_unknown_fuchsia.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{Target, TargetResult}; +use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::fuchsia_base::opts(); @@ -23,6 +23,9 @@ pub fn target() -> TargetResult { target_os: "fuchsia".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), - options: base, + options: TargetOptions { + abi_blacklist: super::arm_base::abi_blacklist(), + .. base + }, }) } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index b2032e6a1bf9..5ed628d7dcae 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -190,7 +190,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, all_loans: &[Loan<'tcx>], fn_id: ast::NodeId, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { debug!("check_loans(body id={})", body.id); let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id); diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 9bdc6887f6d0..51574868f9bf 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -37,7 +37,7 @@ pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, decl_id: ast::NodeId, _decl_span: Span, var_id: ast::NodeId) { - let ty = bccx.tcx.node_id_to_type(var_id); + let ty = bccx.tcx.tables().node_id_to_type(var_id); let loan_path = Rc::new(LoanPath::new(LpVar(var_id), ty)); move_data.add_move(bccx.tcx, loan_path, decl_id, Declared); } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 763c012a8f8a..8f2afa7f8082 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -42,7 +42,7 @@ mod move_error; pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, fn_id: NodeId, decl: &hir::FnDecl, - body: &hir::Block) + body: &hir::Expr) -> (Vec>, move_data::MoveData<'tcx>) { let mut glcx = GatherLoanCtxt { diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 191cd981b61e..be85069db313 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -21,7 +21,7 @@ use rustc::mir::*; use rustc::mir::transform::{Pass, MirPass, MirSource}; use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; -use rustc::util::nodemap::FnvHashMap; +use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; @@ -63,7 +63,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { env: &env, flow_inits: flow_inits, flow_uninits: flow_uninits, - drop_flags: FnvHashMap(), + drop_flags: FxHashMap(), patch: MirPatch::new(mir), }.elaborate() }; @@ -118,7 +118,7 @@ struct ElaborateDropsCtxt<'a, 'tcx: 'a> { env: &'a MoveDataParamEnv<'tcx>, flow_inits: DataflowResults>, flow_uninits: DataflowResults>, - drop_flags: FnvHashMap, + drop_flags: FxHashMap, patch: MirPatch<'tcx>, } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 1dc5769e63cf..02064b52cb1f 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -11,7 +11,7 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment}; use rustc::mir::*; -use rustc::util::nodemap::FnvHashMap; +use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_vec::{IndexVec}; use syntax::codemap::DUMMY_SP; @@ -181,7 +181,7 @@ pub struct MovePathLookup<'tcx> { /// subsequent search so that it is solely relative to that /// base-lvalue). For the remaining lookup, we map the projection /// elem to the associated MovePathIndex. - projections: FnvHashMap<(MovePathIndex, AbstractElem<'tcx>), MovePathIndex> + projections: FxHashMap<(MovePathIndex, AbstractElem<'tcx>), MovePathIndex> } struct MoveDataBuilder<'a, 'tcx: 'a> { @@ -215,7 +215,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { locals: mir.local_decls.indices().map(Lvalue::Local).map(|v| { Self::new_move_path(&mut move_paths, &mut path_map, None, v) }).collect(), - projections: FnvHashMap(), + projections: FxHashMap(), }, move_paths: move_paths, path_map: path_map, diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index cea9170da9ff..836832de5b9c 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -58,7 +58,7 @@ pub struct MoveDataParamEnv<'tcx> { pub fn borrowck_mir(bcx: &mut BorrowckCtxt, fk: FnKind, _decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, _sp: Span, id: ast::NodeId, attributes: &[ast::Attribute]) { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 2f74ea3e475b..fb842f70a54a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -47,9 +47,7 @@ use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use rustc::hir; -use rustc::hir::{FnDecl, Block}; -use rustc::hir::intravisit; -use rustc::hir::intravisit::{Visitor, FnKind}; +use rustc::hir::intravisit::{self, Visitor, FnKind}; pub mod check_loans; @@ -65,8 +63,8 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> { - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, - b: &'v Block, s: Span, id: ast::NodeId) { + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, + b: &'v hir::Expr, s: Span, id: ast::NodeId) { match fk { FnKind::ItemFn(..) | FnKind::Method(..) => { @@ -159,7 +157,7 @@ pub struct AnalysisData<'a, 'tcx: 'a> { fn borrowck_fn(this: &mut BorrowckCtxt, fk: FnKind, decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId, attributes: &[ast::Attribute]) { @@ -200,7 +198,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, fk: FnKind, decl: &hir::FnDecl, cfg: &cfg::CFG, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId) -> AnalysisData<'a, 'tcx> diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index ba036f1a8b15..32bda5e11620 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -23,7 +23,7 @@ use rustc::middle::expr_use_visitor as euv; use rustc::middle::expr_use_visitor::MutateMode; use rustc::middle::mem_categorization as mc; use rustc::ty::{self, TyCtxt}; -use rustc::util::nodemap::{FnvHashMap, NodeSet}; +use rustc::util::nodemap::{FxHashMap, NodeSet}; use std::cell::RefCell; use std::rc::Rc; @@ -41,7 +41,7 @@ pub struct MoveData<'tcx> { pub paths: RefCell>>, /// Cache of loan path to move path index, for easy lookup. - pub path_map: RefCell>, MovePathIndex>>, + pub path_map: RefCell>, MovePathIndex>>, /// Each move or uninitialized variable gets an entry here. pub moves: RefCell>, @@ -217,7 +217,7 @@ impl<'a, 'tcx> MoveData<'tcx> { pub fn new() -> MoveData<'tcx> { MoveData { paths: RefCell::new(Vec::new()), - path_map: RefCell::new(FnvHashMap()), + path_map: RefCell::new(FxHashMap()), moves: RefCell::new(Vec::new()), path_assignments: RefCell::new(Vec::new()), var_assignments: RefCell::new(Vec::new()), @@ -656,7 +656,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { cfg: &cfg::CFG, id_range: IdRange, decl: &hir::FnDecl, - body: &hir::Block) + body: &hir::Expr) -> FlowedMoveData<'a, 'tcx> { let mut dfcx_moves = DataFlowContext::new(tcx, diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index da899714e935..2cd709dbd36e 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -19,7 +19,7 @@ #![allow(non_camel_case_types)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 7f5eb31612cb..c48811cb295b 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -17,7 +17,7 @@ use eval::{compare_const_vals}; use rustc_const_math::ConstInt; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use pattern::{FieldPattern, Pattern, PatternKind}; @@ -39,7 +39,7 @@ use syntax_pos::{Span, DUMMY_SP}; use arena::TypedArena; -use std::cmp::Ordering; +use std::cmp::{self, Ordering}; use std::fmt; use std::iter::{FromIterator, IntoIterator, repeat}; @@ -160,7 +160,7 @@ pub struct MatchCheckCtxt<'a, 'tcx: 'a> { /// associated types to get field types. pub wild_pattern: &'a Pattern<'tcx>, pub pattern_arena: &'a TypedArena>, - pub byte_array_map: FnvHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>, + pub byte_array_map: FxHashMap<*const Pattern<'tcx>, Vec<&'a Pattern<'tcx>>>, } impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { @@ -181,7 +181,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { tcx: tcx, wild_pattern: &wild_pattern, pattern_arena: &pattern_arena, - byte_array_map: FnvHashMap(), + byte_array_map: FxHashMap(), }) } @@ -419,6 +419,99 @@ fn all_constructors(_cx: &mut MatchCheckCtxt, pcx: PatternContext) -> Vec( + _cx: &mut MatchCheckCtxt<'a, 'tcx>, + patterns: I) -> usize + where I: Iterator> +{ + // The exhaustiveness-checking paper does not include any details on + // checking variable-length slice patterns. However, they are matched + // by an infinite collection of fixed-length array patterns. + // + // Checking the infinite set directly would take an infinite amount + // of time. However, it turns out that for each finite set of + // patterns `P`, all sufficiently large array lengths are equivalent: + // + // Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies + // to exactly the subset `Pₜ` of `P` can be transformed to a slice + // `sₘ` for each sufficiently-large length `m` that applies to exactly + // the same subset of `P`. + // + // Because of that, each witness for reachability-checking from one + // of the sufficiently-large lengths can be transformed to an + // equally-valid witness from any other length, so we only have + // to check slice lengths from the "minimal sufficiently-large length" + // and below. + // + // Note that the fact that there is a *single* `sₘ` for each `m` + // not depending on the specific pattern in `P` is important: if + // you look at the pair of patterns + // `[true, ..]` + // `[.., false]` + // Then any slice of length ≥1 that matches one of these two + // patterns can be be trivially turned to a slice of any + // other length ≥1 that matches them and vice-versa - for + // but the slice from length 2 `[false, true]` that matches neither + // of these patterns can't be turned to a slice from length 1 that + // matches neither of these patterns, so we have to consider + // slices from length 2 there. + // + // Now, to see that that length exists and find it, observe that slice + // patterns are either "fixed-length" patterns (`[_, _, _]`) or + // "variable-length" patterns (`[_, .., _]`). + // + // For fixed-length patterns, all slices with lengths *longer* than + // the pattern's length have the same outcome (of not matching), so + // as long as `L` is greater than the pattern's length we can pick + // any `sₘ` from that length and get the same result. + // + // For variable-length patterns, the situation is more complicated, + // because as seen above the precise value of `sₘ` matters. + // + // However, for each variable-length pattern `p` with a prefix of length + // `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last + // `slₚ` elements are examined. + // + // Therefore, as long as `L` is positive (to avoid concerns about empty + // types), all elements after the maximum prefix length and before + // the maximum suffix length are not examined by any variable-length + // pattern, and therefore can be added/removed without affecting + // them - creating equivalent patterns from any sufficiently-large + // length. + // + // Of course, if fixed-length patterns exist, we must be sure + // that our length is large enough to miss them all, so + // we can pick `L = max(FIXED_LEN+1 ∪ {max(PREFIX_LEN) + max(SUFFIX_LEN)})` + // + // for example, with the above pair of patterns, all elements + // but the first and last can be added/removed, so any + // witness of length ≥2 (say, `[false, false, true]`) can be + // turned to a witness from any other length ≥2. + + let mut max_prefix_len = 0; + let mut max_suffix_len = 0; + let mut max_fixed_len = 0; + + for row in patterns { + match *row.kind { + PatternKind::Constant { value: ConstVal::ByteStr(ref data) } => { + max_fixed_len = cmp::max(max_fixed_len, data.len()); + } + PatternKind::Slice { ref prefix, slice: None, ref suffix } => { + let fixed_len = prefix.len() + suffix.len(); + max_fixed_len = cmp::max(max_fixed_len, fixed_len); + } + PatternKind::Slice { ref prefix, slice: Some(_), ref suffix } => { + max_prefix_len = cmp::max(max_prefix_len, prefix.len()); + max_suffix_len = cmp::max(max_suffix_len, suffix.len()); + } + _ => {} + } + } + + cmp::max(max_fixed_len + 1, max_prefix_len + max_suffix_len) +} + /// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html /// /// Whether a vector `v` of patterns is 'useful' in relation to a set of such @@ -453,16 +546,12 @@ pub fn is_useful<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, let &Matrix(ref rows) = matrix; assert!(rows.iter().all(|r| r.len() == v.len())); + + let pcx = PatternContext { ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error()) .unwrap_or(v[0].ty), - max_slice_length: rows.iter().filter_map(|row| match *row[0].kind { - PatternKind::Slice { ref prefix, slice: _, ref suffix } => - Some(prefix.len() + suffix.len()), - PatternKind::Constant { value: ConstVal::ByteStr(ref data) } => - Some(data.len()), - _ => None - }).max().map_or(0, |v| v + 1) + max_slice_length: max_slice_length(cx, rows.iter().map(|r| r[0]).chain(Some(v[0]))) }; debug!("is_useful_expand_first_col: pcx={:?}, expanding {:?}", pcx, v[0]); diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 9aa1ac62f552..e0e8a2159192 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -65,7 +65,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, id: ast::NodeId) { + b: &'v hir::Expr, s: Span, id: ast::NodeId) { if let FnKind::Closure(..) = fk { span_bug!(s, "check_match: closure outside of function") } @@ -113,7 +113,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, n: ast::NodeId) { + b: &'v hir::Expr, s: Span, n: ast::NodeId) { intravisit::walk_fn(self, fk, fd, b, s, n); for input in &fd.inputs { @@ -201,7 +201,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { // Finally, check if the whole match expression is exhaustive. // Check for empty enum, because is_useful only works on inhabited types. - let pat_ty = self.tcx.node_id_to_type(scrut.id); + let pat_ty = self.tcx.tables().node_id_to_type(scrut.id); if inlined_arms.is_empty() { if !pat_ty.is_uninhabited(self.tcx) { // We know the type is inhabited, so this must be wrong @@ -262,7 +262,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) { pat.walk(|p| { if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), name, None) = p.node { - let pat_ty = cx.tcx.pat_ty(p); + let pat_ty = cx.tcx.tables().pat_ty(p); if let ty::TyAdt(edef, _) = pat_ty.sty { if edef.is_enum() { if let Def::Local(..) = cx.tcx.expect_def(p.id) { @@ -486,7 +486,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, for pat in pats { pat.walk(|p| { if let PatKind::Binding(hir::BindByValue(..), _, ref sub) = p.node { - let pat_ty = cx.tcx.node_id_to_type(p.id); + let pat_ty = cx.tcx.tables().node_id_to_type(p.id); if pat_ty.moves_by_default(cx.tcx, cx.param_env, pat.span) { check_move(p, sub.as_ref().map(|p| &**p)); } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c02cca0da722..5f0c94744a11 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -27,7 +27,7 @@ use rustc::ty::util::IntTypeExt; use rustc::ty::subst::Substs; use rustc::traits::Reveal; use rustc::util::common::ErrorReported; -use rustc::util::nodemap::NodeMap; +use rustc::util::nodemap::DefIdMap; use rustc::lint; use graphviz::IntoCow; @@ -246,7 +246,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat_id: ast::NodeId, span: Span) -> Result, DefId> { - let pat_ty = tcx.expr_ty(expr); + let pat_ty = tcx.tables().expr_ty(expr); debug!("expr={:?} pat_ty={:?} pat_id={}", expr, pat_ty, pat_id); match pat_ty.sty { ty::TyFloat(_) => { @@ -314,7 +314,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }, })) .collect::>()?; - PatKind::Struct(path.clone(), field_pats, false) + PatKind::Struct((**path).clone(), field_pats, false) } hir::ExprArray(ref exprs) => { @@ -329,7 +329,8 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Def::StructCtor(_, CtorKind::Const) | Def::VariantCtor(_, CtorKind::Const) => PatKind::Path(None, path.clone()), Def::Const(def_id) | Def::AssociatedConst(def_id) => { - let substs = Some(tcx.node_id_item_substs(expr.id).substs); + let substs = Some(tcx.tables().node_id_item_substs(expr.id) + .unwrap_or_else(|| tcx.intern_substs(&[]))); let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap(); return const_expr_to_pat(tcx, expr, pat_id, span); }, @@ -413,7 +414,7 @@ pub fn eval_const_expr_checked<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, eval_const_expr_partial(tcx, e, ExprTypeChecked, None) } -pub type FnArgMap<'a> = Option<&'a NodeMap>; +pub type FnArgMap<'a> = Option<&'a DefIdMap>; #[derive(Clone, Debug)] pub struct ConstEvalErr { @@ -606,7 +607,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let ety = match ty_hint { ExprTypeChecked => { // After type-checking, expr_ty is guaranteed to succeed. - Some(tcx.expr_ty(e)) + Some(tcx.tables().expr_ty(e)) } UncheckedExprHint(ty) => { // Use the type hint; it's not guaranteed to be right, but it's @@ -617,7 +618,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // This expression might not be type-checked, and we have no hint. // Try to query the context for a type anyway; we might get lucky // (for example, if the expression was imported from another crate). - tcx.expr_ty_opt(e) + tcx.tables().expr_ty_opt(e) } }; let result = match e.node { @@ -759,7 +760,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let base_hint = if let ExprTypeChecked = ty_hint { ExprTypeChecked } else { - match tcx.expr_ty_opt(&base) { + match tcx.tables().expr_ty_opt(&base) { Some(t) => UncheckedExprHint(t), None => ty_hint } @@ -798,7 +799,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = if let ExprTypeChecked = ty_hint { - Some(tcx.node_id_item_substs(e.id).substs) + Some(tcx.tables().node_id_item_substs(e.id) + .unwrap_or_else(|| tcx.intern_substs(&[]))) } else { None }; @@ -835,9 +837,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ConstVal::Struct(e.id) } Def::Local(def_id) => { - let id = tcx.map.as_local_node_id(def_id).unwrap(); - debug!("Def::Local({:?}): {:?}", id, fn_args); - if let Some(val) = fn_args.and_then(|args| args.get(&id)) { + debug!("Def::Local({:?}): {:?}", def_id, fn_args); + if let Some(val) = fn_args.and_then(|args| args.get(&def_id)) { val.clone() } else { signal!(e, NonConstPath); @@ -856,14 +857,13 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callee => signal!(e, CallOn(callee)), }; let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) { - (fn_like.decl(), &fn_like.body().expr) + (fn_like.decl(), fn_like.body()) } else { signal!(e, NonConstPath) }; - let result = result.as_ref().expect("const fn has no result expression"); assert_eq!(decl.inputs.len(), args.len()); - let mut call_args = NodeMap(); + let mut call_args = DefIdMap(); for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) { let arg_hint = ty_hint.erase_hint(); let arg_val = eval_const_expr_partial( @@ -873,7 +873,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_args )?; debug!("const call arg: {:?}", arg); - let old = call_args.insert(arg.pat.id, arg_val); + let old = call_args.insert(tcx.expect_def(arg.pat.id).def_id(), arg_val); assert!(old.is_none()); } debug!("const call({:?})", call_args); @@ -1090,13 +1090,8 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // when constructing the inference context above. match selection { traits::VtableImpl(ref impl_data) => { - let ac = tcx.impl_or_trait_items(impl_data.impl_def_id) - .iter().filter_map(|&def_id| { - match tcx.impl_or_trait_item(def_id) { - ty::ConstTraitItem(ic) => Some(ic), - _ => None - } - }).find(|ic| ic.name == ti.name); + let ac = tcx.associated_items(impl_data.impl_def_id) + .find(|item| item.kind == ty::AssociatedKind::Const && item.name == ti.name); match ac { Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), None => match ti.node { diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 1a07ece044ff..3fa60f86c98c 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -22,7 +22,7 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_private)] #![feature(staged_api)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 946a39747476..241920f2949f 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -128,7 +128,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { } pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> { - let mut ty = self.tcx.node_id_to_type(pat.id); + let mut ty = self.tcx.tables().node_id_to_type(pat.id); let kind = match pat.node { PatKind::Wild => PatternKind::Wild, @@ -167,8 +167,9 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { match self.tcx.expect_def(pat.id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let tcx = self.tcx.global_tcx(); - let substs = Some(self.tcx.node_id_item_substs(pat.id).substs); - match eval::lookup_const_by_id(tcx, def_id, substs) { + let substs = tcx.tables().node_id_item_substs(pat.id) + .unwrap_or_else(|| tcx.intern_substs(&[])); + match eval::lookup_const_by_id(tcx, def_id, Some(substs)) { Some((const_expr, _const_ty)) => { match eval::const_expr_to_pat( tcx, const_expr, pat.id, pat.span) @@ -197,7 +198,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { } PatKind::Slice(ref prefix, ref slice, ref suffix) => { - let ty = self.tcx.node_id_to_type(pat.id); + let ty = self.tcx.tables().node_id_to_type(pat.id); match ty.sty { ty::TyRef(_, mt) => PatternKind::Deref { @@ -222,7 +223,8 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { } PatKind::Tuple(ref subpatterns, ddpos) => { - match self.tcx.node_id_to_type(pat.id).sty { + let ty = self.tcx.tables().node_id_to_type(pat.id); + match ty.sty { ty::TyTuple(ref tys) => { let subpatterns = subpatterns.iter() @@ -243,7 +245,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { PatKind::Binding(bm, ref ident, ref sub) => { let def_id = self.tcx.expect_def(pat.id).def_id(); let id = self.tcx.map.as_local_node_id(def_id).unwrap(); - let var_ty = self.tcx.node_id_to_type(pat.id); + let var_ty = self.tcx.tables().node_id_to_type(pat.id); let region = match var_ty.sty { ty::TyRef(r, _) => Some(r), _ => None, @@ -280,7 +282,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { } PatKind::TupleStruct(_, ref subpatterns, ddpos) => { - let pat_ty = self.tcx.node_id_to_type(pat.id); + let pat_ty = self.tcx.tables().node_id_to_type(pat.id); let adt_def = match pat_ty.sty { ty::TyAdt(adt_def, _) => adt_def, _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"), @@ -299,7 +301,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { } PatKind::Struct(_, ref fields, _) => { - let pat_ty = self.tcx.node_id_to_type(pat.id); + let pat_ty = self.tcx.tables().node_id_to_type(pat.id); let adt_def = match pat_ty.sty { ty::TyAdt(adt_def, _) => adt_def, _ => { diff --git a/src/librustc_data_structures/fx.rs b/src/librustc_data_structures/fx.rs new file mode 100644 index 000000000000..1fb7673521d8 --- /dev/null +++ b/src/librustc_data_structures/fx.rs @@ -0,0 +1,115 @@ +// 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. + +use std::collections::{HashMap, HashSet}; +use std::default::Default; +use std::hash::{Hasher, Hash, BuildHasherDefault}; +use std::ops::BitXor; + +pub type FxHashMap = HashMap>; +pub type FxHashSet = HashSet>; + +#[allow(non_snake_case)] +pub fn FxHashMap() -> FxHashMap { + HashMap::default() +} + +#[allow(non_snake_case)] +pub fn FxHashSet() -> FxHashSet { + HashSet::default() +} + +/// A speedy hash algorithm for use within rustc. The hashmap in libcollections +/// by default uses SipHash which isn't quite as speedy as we want. In the +/// compiler we're not really worried about DOS attempts, so we use a fast +/// non-cryptographic hash. +/// +/// This is the same as the algorithm used by Firefox -- which is a homespun +/// one not based on any widely-known algorithm -- though modified to produce +/// 64-bit hash values instead of 32-bit hash values. It consistently +/// out-performs an FNV-based hash within rustc itself -- the collision rate is +/// similar or slightly worse than FNV, but the speed of the hash function +/// itself is much higher because it works on up to 8 bytes at a time. +pub struct FxHasher { + hash: usize +} + +#[cfg(target_pointer_width = "32")] +const K: usize = 0x9e3779b9; +#[cfg(target_pointer_width = "64")] +const K: usize = 0x517cc1b727220a95; + +impl Default for FxHasher { + #[inline] + fn default() -> FxHasher { + FxHasher { hash: 0 } + } +} + +impl FxHasher { + #[inline] + fn add_to_hash(&mut self, i: usize) { + self.hash = self.hash.rotate_left(5).bitxor(i).wrapping_mul(K); + } +} + +impl Hasher for FxHasher { + #[inline] + fn write(&mut self, bytes: &[u8]) { + for byte in bytes { + let i = *byte; + self.add_to_hash(i as usize); + } + } + + #[inline] + fn write_u8(&mut self, i: u8) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_u16(&mut self, i: u16) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.add_to_hash(i as usize); + } + + #[cfg(target_pointer_width = "32")] + #[inline] + fn write_u64(&mut self, i: u64) { + self.add_to_hash(i as usize); + self.add_to_hash((i >> 32) as usize); + } + + #[cfg(target_pointer_width = "64")] + #[inline] + fn write_u64(&mut self, i: u64) { + self.add_to_hash(i as usize); + } + + #[inline] + fn write_usize(&mut self, i: usize) { + self.add_to_hash(i); + } + + #[inline] + fn finish(&self) -> u64 { + self.hash as u64 + } +} + +pub fn hash(v: &T) -> u64 { + let mut state = FxHasher::default(); + v.hash(&mut state); + state.finish() +} diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 912346314993..00cea9cbdf6b 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -149,6 +149,21 @@ impl IndexVec { pub fn last(&self) -> Option { self.len().checked_sub(1).map(I::new) } + + #[inline] + pub fn shrink_to_fit(&mut self) { + self.raw.shrink_to_fit() + } + + #[inline] + pub fn swap(&mut self, a: usize, b: usize) { + self.raw.swap(a, b) + } + + #[inline] + pub fn truncate(&mut self, a: usize) { + self.raw.truncate(a) + } } impl Index for IndexVec { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index fc963dac9495..fdcbec6bac11 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -60,6 +60,7 @@ pub mod snapshot_vec; pub mod transitive_relation; pub mod unify; pub mod fnv; +pub mod fx; pub mod tuple_slice; pub mod veccell; pub mod control_flow_graph; diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index a2bfa784e8ae..a46238309bb4 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -15,7 +15,7 @@ //! in the first place). See README.md for a general overview of how //! to use this class. -use fnv::{FnvHashMap, FnvHashSet}; +use fx::{FxHashMap, FxHashSet}; use std::cell::Cell; use std::collections::hash_map::Entry; @@ -68,9 +68,9 @@ pub struct ObligationForest { /// backtrace iterator (which uses `split_at`). nodes: Vec>, /// A cache of predicates that have been successfully completed. - done_cache: FnvHashSet, + done_cache: FxHashSet, /// An cache of the nodes in `nodes`, indexed by predicate. - waiting_cache: FnvHashMap, + waiting_cache: FxHashMap, /// A list of the obligations added in snapshots, to allow /// for their removal. cache_list: Vec, @@ -158,8 +158,8 @@ impl ObligationForest { ObligationForest { nodes: vec![], snapshots: vec![], - done_cache: FnvHashSet(), - waiting_cache: FnvHashMap(), + done_cache: FxHashSet(), + waiting_cache: FxHashMap(), cache_list: vec![], scratch: Some(vec![]), } diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index a4e6166032d8..cd7143ad3ce8 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use fnv::FnvHashMap; +use fx::FxHashMap; use std::hash::Hash; use std::ops; use std::mem; @@ -19,7 +19,7 @@ mod test; pub struct SnapshotMap where K: Hash + Clone + Eq { - map: FnvHashMap, + map: FxHashMap, undo_log: Vec>, } @@ -40,7 +40,7 @@ impl SnapshotMap { pub fn new() -> Self { SnapshotMap { - map: FnvHashMap(), + map: FxHashMap(), undo_log: vec![], } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index da1d5ad2c4a9..d83918495676 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -37,7 +37,8 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, static_recursion}; +use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, + static_recursion, hir_stats}; use rustc_const_eval::check_match; use super::Compilation; @@ -513,6 +514,10 @@ pub fn phase_1_parse_input<'a>(sess: &'a Session, input: &Input) -> PResult<'a, syntax::show_span::run(sess.diagnostic(), s, &krate); } + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS"); + } + Ok(krate) } @@ -718,6 +723,10 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, println!("Post-expansion node count: {}", count_nodes(&krate)); } + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_ast_stats(&krate, "POST EXPANSION AST STATS"); + } + if sess.opts.debugging_opts.ast_json { println!("{}", json::as_json(&krate)); } @@ -758,7 +767,13 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, // Lower ast -> hir. let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || { - hir_map::Forest::new(lower_crate(sess, &krate, &mut resolver), &sess.dep_graph) + let hir_crate = lower_crate(sess, &krate, &mut resolver); + + if sess.opts.debugging_opts.hir_stats { + hir_stats::print_hir_stats(&hir_crate); + } + + hir_map::Forest::new(hir_crate, &sess.dep_graph) }); // Discard hygiene data, which isn't required past lowering to HIR. @@ -917,17 +932,19 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "MIR dump", || mir::mir_map::build_mir_for_crate(tcx)); - time(time_passes, "MIR passes", || { + time(time_passes, "MIR cleanup and validation", || { let mut passes = sess.mir_passes.borrow_mut(); - // Push all the built-in passes. + // Push all the built-in validation passes. + // NB: if you’re adding an *optimisation* it ought to go to another set of passes + // in stage 4 below. passes.push_hook(box mir::transform::dump_mir::DumpMir); - passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("initial")); + passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial")); passes.push_pass( box mir::transform::qualify_consts::QualifyAndPromoteConstants::default()); passes.push_pass(box mir::transform::type_check::TypeckMir); passes.push_pass( box mir::transform::simplify_branches::SimplifyBranches::new("initial")); - passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("qualify-consts")); + passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts")); // And run everything. passes.run_passes(tcx); }); @@ -989,13 +1006,13 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "resolving dependency formats", || dependency_format::calculate(&tcx.sess)); - // Run the passes that transform the MIR into a more suitable for translation - // to LLVM code. - time(time_passes, "Prepare MIR codegen passes", || { + // Run the passes that transform the MIR into a more suitable form for translation to LLVM + // code. + time(time_passes, "MIR optimisations", || { let mut passes = ::rustc::mir::transform::Passes::new(); passes.push_hook(box mir::transform::dump_mir::DumpMir); passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); - passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("no-landing-pads")); + passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("no-landing-pads")); // From here on out, regions are gone. passes.push_pass(box mir::transform::erase_regions::EraseRegions); @@ -1003,13 +1020,14 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); passes.push_pass(box borrowck::ElaborateDrops); passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); - passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops")); + passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops")); // No lifetime analysis based on borrowing can be done from here on out. passes.push_pass(box mir::transform::instcombine::InstCombine::new()); passes.push_pass(box mir::transform::deaggregator::Deaggregator); passes.push_pass(box mir::transform::copy_prop::CopyPropagation); + passes.push_pass(box mir::transform::simplify::SimplifyLocals); passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans")); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index cb78baa12a6a..7e60c40220f8 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -24,7 +24,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(box_syntax)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] @@ -75,7 +75,7 @@ use rustc::dep_graph::DepGraph; use rustc::session::{self, config, Session, build_session, CompileResult}; use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType}; use rustc::session::config::nightly_options; -use rustc::session::early_error; +use rustc::session::{early_error, early_warn}; use rustc::lint::Lint; use rustc::lint; use rustc_metadata::locator; @@ -455,8 +455,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { 1 => panic!("make_input should have provided valid inputs"), _ => early_error(sopts.error_format, "multiple input filenames provided"), } - - None } fn late_callback(&mut self, @@ -1011,6 +1009,11 @@ pub fn handle_options(args: &[String]) -> Option { return None; } + if cg_flags.iter().any(|x| *x == "no-stack-check") { + early_warn(ErrorOutputType::default(), + "the --no-stack-check flag is deprecated and does nothing"); + } + if cg_flags.contains(&"passes=list".to_string()) { unsafe { ::llvm::LLVMRustPrintPasses(); diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 289a7348cc8d..ecbf28c1082f 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -501,7 +501,7 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { pp::space(&mut s.s)?; pp::word(&mut s.s, "as")?; pp::space(&mut s.s)?; - pp::word(&mut s.s, &self.tcx.expr_ty(expr).to_string())?; + pp::word(&mut s.s, &self.tcx.tables().expr_ty(expr).to_string())?; s.pclose() } _ => Ok(()), @@ -701,8 +701,8 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, mut out: W) -> io::Result<()> { let cfg = match code { - blocks::BlockCode(block) => cfg::CFG::new(tcx, &block), - blocks::FnLikeCode(fn_like) => cfg::CFG::new(tcx, &fn_like.body()), + blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr), + blocks::Code::FnLike(fn_like) => cfg::CFG::new(tcx, fn_like.body()), }; let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; let lcfg = LabelledCFG { @@ -717,12 +717,12 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, let r = dot::render(&lcfg, &mut out); return expand_err_details(r); } - blocks::BlockCode(_) => { + blocks::Code::Expr(_) => { tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \ fn-like node id."); return Ok(()); } - blocks::FnLikeCode(fn_like) => { + blocks::Code::FnLike(fn_like) => { let (bccx, analysis_data) = borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.to_fn_parts(), &cfg); @@ -990,8 +990,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) }); - let code = blocks::Code::from_node(node); - match code { + match blocks::Code::from_node(&tcx.map, nodeid) { Some(code) => { let variants = gather_flowgraph_variants(tcx.sess); diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index 128c270eb359..c92e4d8f5aba 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -11,4 +11,4 @@ crate-type = ["dylib"] [dependencies] log = { path = "../liblog" } serialize = { path = "../libserialize" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs new file mode 100644 index 000000000000..730ca8f9e2e4 --- /dev/null +++ b/src/librustc_errors/diagnostic.rs @@ -0,0 +1,202 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use CodeSuggestion; +use Level; +use RenderSpan; +use RenderSpan::Suggestion; +use std::fmt; +use syntax_pos::{MultiSpan, Span}; + +#[must_use] +#[derive(Clone, Debug, PartialEq)] +pub struct Diagnostic { + pub level: Level, + pub message: String, + pub code: Option, + pub span: MultiSpan, + pub children: Vec, +} + +/// For example a note attached to an error. +#[derive(Clone, Debug, PartialEq)] +pub struct SubDiagnostic { + pub level: Level, + pub message: String, + pub span: MultiSpan, + pub render_span: Option, +} + +impl Diagnostic { + pub fn new(level: Level, message: &str) -> Self { + Diagnostic::new_with_code(level, None, message) + } + + pub fn new_with_code(level: Level, code: Option, message: &str) -> Self { + Diagnostic { + level: level, + message: message.to_owned(), + code: code, + span: MultiSpan::new(), + children: vec![], + } + } + + /// Cancel the diagnostic (a structured diagnostic must either be emitted or + /// cancelled or it will panic when dropped). + /// BEWARE: if this DiagnosticBuilder is an error, then creating it will + /// bump the error count on the Handler and cancelling it won't undo that. + /// If you want to decrement the error count you should use `Handler::cancel`. + pub fn cancel(&mut self) { + self.level = Level::Cancelled; + } + + pub fn cancelled(&self) -> bool { + self.level == Level::Cancelled + } + + pub fn is_fatal(&self) -> bool { + self.level == Level::Fatal + } + + /// Add a span/label to be included in the resulting snippet. + /// This is pushed onto the `MultiSpan` that was created when the + /// diagnostic was first built. If you don't call this function at + /// all, and you just supplied a `Span` to create the diagnostic, + /// then the snippet will just include that `Span`, which is + /// called the primary span. + pub fn span_label(&mut self, span: Span, label: &fmt::Display) + -> &mut Self { + self.span.push_span_label(span, format!("{}", label)); + self + } + + pub fn note_expected_found(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display) + -> &mut Self + { + self.note_expected_found_extra(label, expected, found, &"", &"") + } + + pub fn note_expected_found_extra(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display, + expected_extra: &fmt::Display, + found_extra: &fmt::Display) + -> &mut Self + { + // For now, just attach these as notes + self.note(&format!("expected {} `{}`{}", label, expected, expected_extra)); + self.note(&format!(" found {} `{}`{}", label, found, found_extra)); + self + } + + pub fn note(&mut self, msg: &str) -> &mut Self { + self.sub(Level::Note, msg, MultiSpan::new(), None); + self + } + + pub fn span_note>(&mut self, + sp: S, + msg: &str) + -> &mut Self { + self.sub(Level::Note, msg, sp.into(), None); + self + } + + pub fn warn(&mut self, msg: &str) -> &mut Self { + self.sub(Level::Warning, msg, MultiSpan::new(), None); + self + } + + pub fn span_warn>(&mut self, + sp: S, + msg: &str) + -> &mut Self { + self.sub(Level::Warning, msg, sp.into(), None); + self + } + + pub fn help(&mut self , msg: &str) -> &mut Self { + self.sub(Level::Help, msg, MultiSpan::new(), None); + self + } + + pub fn span_help>(&mut self, + sp: S, + msg: &str) + -> &mut Self { + self.sub(Level::Help, msg, sp.into(), None); + self + } + + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion>(&mut self, + sp: S, + msg: &str, + suggestion: String) + -> &mut Self { + self.sub(Level::Help, + msg, + MultiSpan::new(), + Some(Suggestion(CodeSuggestion { + msp: sp.into(), + substitutes: vec![suggestion], + }))); + self + } + + pub fn set_span>(&mut self, sp: S) -> &mut Self { + self.span = sp.into(); + self + } + + pub fn code(&mut self, s: String) -> &mut Self { + self.code = Some(s); + self + } + + pub fn message(&self) -> &str { + &self.message + } + + pub fn level(&self) -> Level { + self.level + } + + /// Used by a lint. Copies over all details *but* the "main + /// message". + pub fn copy_details_not_message(&mut self, from: &Diagnostic) { + self.span = from.span.clone(); + self.code = from.code.clone(); + self.children.extend(from.children.iter().cloned()) + } + + /// Convenience function for internal use, clients should use one of the + /// public methods above. + fn sub(&mut self, + level: Level, + message: &str, + span: MultiSpan, + render_span: Option) { + let sub = SubDiagnostic { + level: level, + message: message.to_owned(), + span: span, + render_span: render_span, + }; + self.children.push(sub); + } +} diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs new file mode 100644 index 000000000000..7dfea6b8951b --- /dev/null +++ b/src/librustc_errors/diagnostic_builder.rs @@ -0,0 +1,196 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use Diagnostic; +use Level; +use Handler; +use std::fmt::{self, Debug}; +use std::ops::{Deref, DerefMut}; +use std::thread::panicking; +use syntax_pos::{MultiSpan, Span}; + +/// Used for emitting structured error messages and other diagnostic information. +#[must_use] +#[derive(Clone)] +pub struct DiagnosticBuilder<'a> { + handler: &'a Handler, + diagnostic: Diagnostic, +} + +/// In general, the `DiagnosticBuilder` uses deref to allow access to +/// the fields and methods of the embedded `diagnostic` in a +/// transparent way. *However,* many of the methods are intended to +/// be used in a chained way, and hence ought to return `self`. In +/// that case, we can't just naively forward to the method on the +/// `diagnostic`, because the return type would be a `&Diagnostic` +/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes +/// it easy to declare such methods on the builder. +macro_rules! forward { + // Forward pattern for &self -> &Self + (pub fn $n:ident(&self, $($name:ident: $ty:ty),*) -> &Self) => { + pub fn $n(&self, $($name: $ty),*) -> &Self { + self.diagnostic.$n($($name),*); + self + } + }; + + // Forward pattern for &mut self -> &mut Self + (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => { + pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { + self.diagnostic.$n($($name),*); + self + } + }; + + // Forward pattern for &mut self -> &mut Self, with S: Into + // type parameter. No obvious way to make this more generic. + (pub fn $n:ident>(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => { + pub fn $n>(&mut self, $($name: $ty),*) -> &mut Self { + self.diagnostic.$n($($name),*); + self + } + }; +} + +impl<'a> Deref for DiagnosticBuilder<'a> { + type Target = Diagnostic; + + fn deref(&self) -> &Diagnostic { + &self.diagnostic + } +} + +impl<'a> DerefMut for DiagnosticBuilder<'a> { + fn deref_mut(&mut self) -> &mut Diagnostic { + &mut self.diagnostic + } +} + +impl<'a> DiagnosticBuilder<'a> { + /// Emit the diagnostic. + pub fn emit(&mut self) { + if self.cancelled() { + return; + } + + match self.level { + Level::Bug | + Level::Fatal | + Level::PhaseFatal | + Level::Error => { + self.handler.bump_err_count(); + } + + Level::Warning | + Level::Note | + Level::Help | + Level::Cancelled => { + } + } + + self.handler.emitter.borrow_mut().emit(&self); + self.cancel(); + self.handler.panic_if_treat_err_as_bug(); + + // if self.is_fatal() { + // panic!(FatalError); + // } + } + + /// Add a span/label to be included in the resulting snippet. + /// This is pushed onto the `MultiSpan` that was created when the + /// diagnostic was first built. If you don't call this function at + /// all, and you just supplied a `Span` to create the diagnostic, + /// then the snippet will just include that `Span`, which is + /// called the primary span. + forward!(pub fn span_label(&mut self, span: Span, label: &fmt::Display) + -> &mut Self); + + forward!(pub fn note_expected_found(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display) + -> &mut Self); + + forward!(pub fn note_expected_found_extra(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display, + expected_extra: &fmt::Display, + found_extra: &fmt::Display) + -> &mut Self); + + forward!(pub fn note(&mut self, msg: &str) -> &mut Self); + forward!(pub fn span_note>(&mut self, + sp: S, + msg: &str) + -> &mut Self); + forward!(pub fn warn(&mut self, msg: &str) -> &mut Self); + forward!(pub fn span_warn>(&mut self, sp: S, msg: &str) -> &mut Self); + forward!(pub fn help(&mut self , msg: &str) -> &mut Self); + forward!(pub fn span_help>(&mut self, + sp: S, + msg: &str) + -> &mut Self); + forward!(pub fn span_suggestion>(&mut self, + sp: S, + msg: &str, + suggestion: String) + -> &mut Self); + forward!(pub fn set_span>(&mut self, sp: S) -> &mut Self); + forward!(pub fn code(&mut self, s: String) -> &mut Self); + + /// Convenience function for internal use, clients should use one of the + /// struct_* methods on Handler. + pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { + DiagnosticBuilder::new_with_code(handler, level, None, message) + } + + /// Convenience function for internal use, clients should use one of the + /// struct_* methods on Handler. + pub fn new_with_code(handler: &'a Handler, + level: Level, + code: Option, + message: &str) + -> DiagnosticBuilder<'a> { + DiagnosticBuilder { + handler: handler, + diagnostic: Diagnostic::new_with_code(level, code, message) + } + } + + pub fn into_diagnostic(mut self) -> Diagnostic { + // annoyingly, the Drop impl means we can't actually move + let result = self.diagnostic.clone(); + self.cancel(); + result + } +} + +impl<'a> Debug for DiagnosticBuilder<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.diagnostic.fmt(f) + } +} + +/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or +/// we emit a bug. +impl<'a> Drop for DiagnosticBuilder<'a> { + fn drop(&mut self) { + if !panicking() && !self.cancelled() { + let mut db = DiagnosticBuilder::new(self.handler, + Level::Bug, + "Error constructed but not emitted"); + db.emit(); + panic!(); + } + } +} + diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 25b314256b09..badee66b83de 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -39,15 +39,15 @@ extern crate syntax_pos; pub use emitter::ColorConfig; use self::Level::*; -use self::RenderSpan::*; use emitter::{Emitter, EmitterWriter}; use std::cell::{RefCell, Cell}; use std::{error, fmt}; use std::rc::Rc; -use std::thread::panicking; +pub mod diagnostic; +pub mod diagnostic_builder; pub mod emitter; pub mod snippet; pub mod registry; @@ -57,7 +57,7 @@ mod lock; use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION}; use syntax_pos::MacroBacktrace; -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub enum RenderSpan { /// A FullSpan renders with both with an initial line for the /// message, prefixed by file:linenum, followed by a summary of @@ -71,7 +71,7 @@ pub enum RenderSpan { Suggestion(CodeSuggestion), } -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct CodeSuggestion { pub msp: MultiSpan, pub substitutes: Vec, @@ -211,219 +211,8 @@ impl error::Error for ExplicitBug { } } -/// Used for emitting structured error messages and other diagnostic information. -#[must_use] -#[derive(Clone)] -pub struct DiagnosticBuilder<'a> { - handler: &'a Handler, - pub level: Level, - pub message: String, - pub code: Option, - pub span: MultiSpan, - pub children: Vec, -} - -/// For example a note attached to an error. -#[derive(Clone)] -pub struct SubDiagnostic { - pub level: Level, - pub message: String, - pub span: MultiSpan, - pub render_span: Option, -} - -impl<'a> DiagnosticBuilder<'a> { - /// Emit the diagnostic. - pub fn emit(&mut self) { - if self.cancelled() { - return; - } - - self.handler.emitter.borrow_mut().emit(&self); - self.cancel(); - self.handler.panic_if_treat_err_as_bug(); - - // if self.is_fatal() { - // panic!(FatalError); - // } - } - - /// Cancel the diagnostic (a structured diagnostic must either be emitted or - /// cancelled or it will panic when dropped). - /// BEWARE: if this DiagnosticBuilder is an error, then creating it will - /// bump the error count on the Handler and cancelling it won't undo that. - /// If you want to decrement the error count you should use `Handler::cancel`. - pub fn cancel(&mut self) { - self.level = Level::Cancelled; - } - - pub fn cancelled(&self) -> bool { - self.level == Level::Cancelled - } - - pub fn is_fatal(&self) -> bool { - self.level == Level::Fatal - } - - /// Add a span/label to be included in the resulting snippet. - /// This is pushed onto the `MultiSpan` that was created when the - /// diagnostic was first built. If you don't call this function at - /// all, and you just supplied a `Span` to create the diagnostic, - /// then the snippet will just include that `Span`, which is - /// called the primary span. - pub fn span_label(&mut self, span: Span, label: &fmt::Display) -> &mut DiagnosticBuilder<'a> { - self.span.push_span_label(span, format!("{}", label)); - self - } - - pub fn note_expected_found(&mut self, - label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) - -> &mut DiagnosticBuilder<'a> { - self.note_expected_found_extra(label, expected, found, &"", &"") - } - - pub fn note_expected_found_extra(&mut self, - label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, - expected_extra: &fmt::Display, - found_extra: &fmt::Display) - -> &mut DiagnosticBuilder<'a> { - // For now, just attach these as notes - self.note(&format!("expected {} `{}`{}", label, expected, expected_extra)); - self.note(&format!(" found {} `{}`{}", label, found, found_extra)); - self - } - - pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, MultiSpan::new(), None); - self - } - pub fn span_note>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, sp.into(), None); - self - } - pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, MultiSpan::new(), None); - self - } - pub fn span_warn>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, sp.into(), None); - self - } - pub fn help(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, MultiSpan::new(), None); - self - } - pub fn span_help>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, sp.into(), None); - self - } - /// Prints out a message with a suggested edit of the code. - /// - /// See `diagnostic::RenderSpan::Suggestion` for more information. - pub fn span_suggestion>(&mut self, - sp: S, - msg: &str, - suggestion: String) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, - msg, - MultiSpan::new(), - Some(Suggestion(CodeSuggestion { - msp: sp.into(), - substitutes: vec![suggestion], - }))); - self - } - - pub fn set_span>(&mut self, sp: S) -> &mut Self { - self.span = sp.into(); - self - } - - pub fn code(&mut self, s: String) -> &mut Self { - self.code = Some(s); - self - } - - pub fn message(&self) -> &str { - &self.message - } - - pub fn level(&self) -> Level { - self.level - } - - /// Convenience function for internal use, clients should use one of the - /// struct_* methods on Handler. - fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { - DiagnosticBuilder::new_with_code(handler, level, None, message) - } - - /// Convenience function for internal use, clients should use one of the - /// struct_* methods on Handler. - fn new_with_code(handler: &'a Handler, - level: Level, - code: Option, - message: &str) - -> DiagnosticBuilder<'a> { - DiagnosticBuilder { - handler: handler, - level: level, - message: message.to_owned(), - code: code, - span: MultiSpan::new(), - children: vec![], - } - } - - /// Convenience function for internal use, clients should use one of the - /// public methods above. - fn sub(&mut self, - level: Level, - message: &str, - span: MultiSpan, - render_span: Option) { - let sub = SubDiagnostic { - level: level, - message: message.to_owned(), - span: span, - render_span: render_span, - }; - self.children.push(sub); - } -} - -impl<'a> fmt::Debug for DiagnosticBuilder<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.message.fmt(f) - } -} - -/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or -/// we emit a bug. -impl<'a> Drop for DiagnosticBuilder<'a> { - fn drop(&mut self) { - if !panicking() && !self.cancelled() { - let mut db = - DiagnosticBuilder::new(self.handler, Bug, "Error constructed but not emitted"); - db.emit(); - panic!(); - } - } -} +pub use diagnostic::{Diagnostic, SubDiagnostic}; +pub use diagnostic_builder::DiagnosticBuilder; /// A handler deals with errors; certain errors /// (fatal, bug, unimpl) may cause immediate exit, @@ -504,7 +293,6 @@ impl Handler { sp: S, msg: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); let mut result = DiagnosticBuilder::new(self, Level::Error, msg); result.set_span(sp); result @@ -514,21 +302,18 @@ impl Handler { msg: &str, code: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); let mut result = DiagnosticBuilder::new(self, Level::Error, msg); result.set_span(sp); result.code(code.to_owned()); result } pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); DiagnosticBuilder::new(self, Level::Error, msg) } pub fn struct_span_fatal<'a, S: Into>(&'a self, sp: S, msg: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); result.set_span(sp); result @@ -538,24 +323,16 @@ impl Handler { msg: &str, code: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); result.set_span(sp); result.code(code.to_owned()); result } pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { - self.bump_err_count(); DiagnosticBuilder::new(self, Level::Fatal, msg) } pub fn cancel(&self, err: &mut DiagnosticBuilder) { - if err.level == Level::Error || err.level == Level::Fatal { - self.err_count.set(self.err_count - .get() - .checked_sub(1) - .expect("cancelled an error but err_count is 0")); - } err.cancel(); } @@ -567,7 +344,6 @@ impl Handler { pub fn span_fatal>(&self, sp: S, msg: &str) -> FatalError { self.emit(&sp.into(), msg, Fatal); - self.bump_err_count(); self.panic_if_treat_err_as_bug(); return FatalError; } @@ -577,13 +353,11 @@ impl Handler { code: &str) -> FatalError { self.emit_with_code(&sp.into(), msg, code, Fatal); - self.bump_err_count(); self.panic_if_treat_err_as_bug(); return FatalError; } pub fn span_err>(&self, sp: S, msg: &str) { self.emit(&sp.into(), msg, Error); - self.bump_err_count(); self.panic_if_treat_err_as_bug(); } pub fn mut_span_err<'a, S: Into>(&'a self, @@ -592,12 +366,10 @@ impl Handler { -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(self, Level::Error, msg); result.set_span(sp); - self.bump_err_count(); result } pub fn span_err_with_code>(&self, sp: S, msg: &str, code: &str) { self.emit_with_code(&sp.into(), msg, code, Error); - self.bump_err_count(); self.panic_if_treat_err_as_bug(); } pub fn span_warn>(&self, sp: S, msg: &str) { @@ -616,7 +388,6 @@ impl Handler { } pub fn span_bug_no_panic>(&self, sp: S, msg: &str) { self.emit(&sp.into(), msg, Bug); - self.bump_err_count(); } pub fn span_note_without_error>(&self, sp: S, msg: &str) { self.emit(&sp.into(), msg, Note); @@ -630,7 +401,6 @@ impl Handler { } let mut db = DiagnosticBuilder::new(self, Fatal, msg); db.emit(); - self.bump_err_count(); FatalError } pub fn err(&self, msg: &str) { @@ -639,7 +409,6 @@ impl Handler { } let mut db = DiagnosticBuilder::new(self, Error, msg); db.emit(); - self.bump_err_count(); } pub fn warn(&self, msg: &str) { let mut db = DiagnosticBuilder::new(self, Warning, msg); diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 28aab1fdd416..37477da755c9 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -48,7 +48,7 @@ use rustc::dep_graph::{DepGraphQuery, DepNode}; use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; use rustc::hir::def_id::DefId; use rustc::ty::TyCtxt; -use rustc_data_structures::fnv::FnvHashSet; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex}; use rustc::hir; use rustc::hir::intravisit::Visitor; @@ -244,7 +244,7 @@ fn dump_graph(tcx: TyCtxt) { } } -pub struct GraphvizDepGraph<'q>(FnvHashSet<&'q DepNode>, +pub struct GraphvizDepGraph<'q>(FxHashSet<&'q DepNode>, Vec<(&'q DepNode, &'q DepNode)>); impl<'a, 'tcx, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> { @@ -288,7 +288,7 @@ impl<'a, 'tcx, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> { // filter) or the set of nodes whose labels contain all of those // substrings. fn node_set<'q>(query: &'q DepGraphQuery, filter: &DepNodeFilter) - -> Option>> + -> Option>> { debug!("node_set(filter={:?})", filter); @@ -300,9 +300,9 @@ fn node_set<'q>(query: &'q DepGraphQuery, filter: &DepNodeFilter) } fn filter_nodes<'q>(query: &'q DepGraphQuery, - sources: &Option>>, - targets: &Option>>) - -> FnvHashSet<&'q DepNode> + sources: &Option>>, + targets: &Option>>) + -> FxHashSet<&'q DepNode> { if let &Some(ref sources) = sources { if let &Some(ref targets) = targets { @@ -318,11 +318,11 @@ fn filter_nodes<'q>(query: &'q DepGraphQuery, } fn walk_nodes<'q>(query: &'q DepGraphQuery, - starts: &FnvHashSet<&'q DepNode>, + starts: &FxHashSet<&'q DepNode>, direction: Direction) - -> FnvHashSet<&'q DepNode> + -> FxHashSet<&'q DepNode> { - let mut set = FnvHashSet(); + let mut set = FxHashSet(); for &start in starts { debug!("walk_nodes: start={:?} outgoing?={:?}", start, direction == OUTGOING); if set.insert(start) { @@ -342,9 +342,9 @@ fn walk_nodes<'q>(query: &'q DepGraphQuery, } fn walk_between<'q>(query: &'q DepGraphQuery, - sources: &FnvHashSet<&'q DepNode>, - targets: &FnvHashSet<&'q DepNode>) - -> FnvHashSet<&'q DepNode> + sources: &FxHashSet<&'q DepNode>, + targets: &FxHashSet<&'q DepNode>) + -> FxHashSet<&'q DepNode> { // This is a bit tricky. We want to include a node only if it is: // (a) reachable from a source and (b) will reach a target. And we @@ -410,7 +410,7 @@ fn walk_between<'q>(query: &'q DepGraphQuery, } fn filter_edges<'q>(query: &'q DepGraphQuery, - nodes: &FnvHashSet<&'q DepNode>) + nodes: &FxHashSet<&'q DepNode>) -> Vec<(&'q DepNode, &'q DepNode)> { query.edges() diff --git a/src/librustc_incremental/calculate_svh/hasher.rs b/src/librustc_incremental/calculate_svh/hasher.rs index 49683a81227b..d7d9c231a91f 100644 --- a/src/librustc_incremental/calculate_svh/hasher.rs +++ b/src/librustc_incremental/calculate_svh/hasher.rs @@ -9,13 +9,16 @@ // except according to those terms. use std::mem; +use std::hash::Hasher; use rustc_data_structures::blake2b::Blake2bHasher; use rustc::ty::util::ArchIndependentHasher; use ich::Fingerprint; +use rustc_serialize::leb128::write_unsigned_leb128; #[derive(Debug)] pub struct IchHasher { state: ArchIndependentHasher, + leb128_helper: Vec, bytes_hashed: u64, } @@ -24,6 +27,7 @@ impl IchHasher { let hash_size = mem::size_of::(); IchHasher { state: ArchIndependentHasher::new(Blake2bHasher::new(hash_size, &[])), + leb128_helper: vec![], bytes_hashed: 0 } } @@ -37,9 +41,19 @@ impl IchHasher { fingerprint.0.copy_from_slice(self.state.into_inner().finalize()); fingerprint } + + #[inline] + fn write_uleb128(&mut self, value: u64) { + let len = write_unsigned_leb128(&mut self.leb128_helper, 0, value); + self.state.write(&self.leb128_helper[0..len]); + self.bytes_hashed += len as u64; + } } -impl ::std::hash::Hasher for IchHasher { +// For the non-u8 integer cases we leb128 encode them first. Because small +// integers dominate, this significantly and cheaply reduces the number of +// bytes hashed, which is good because blake2b is expensive. +impl Hasher for IchHasher { fn finish(&self) -> u64 { bug!("Use other finish() implementation to get the full 128-bit hash."); } @@ -49,4 +63,26 @@ impl ::std::hash::Hasher for IchHasher { self.state.write(bytes); self.bytes_hashed += bytes.len() as u64; } + + // There is no need to leb128-encode u8 values. + + #[inline] + fn write_u16(&mut self, i: u16) { + self.write_uleb128(i as u64); + } + + #[inline] + fn write_u32(&mut self, i: u32) { + self.write_uleb128(i as u64); + } + + #[inline] + fn write_u64(&mut self, i: u64) { + self.write_uleb128(i); + } + + #[inline] + fn write_usize(&mut self, i: usize) { + self.write_uleb128(i as u64); + } } diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 3b0b37bb01ce..58a215299741 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -35,7 +35,7 @@ use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc::util::common::record_time; use rustc::session::config::DebugInfoLevel::NoDebugInfo; @@ -51,21 +51,21 @@ mod caching_codemap_view; pub mod hasher; pub struct IncrementalHashesMap { - hashes: FnvHashMap, Fingerprint>, + hashes: FxHashMap, Fingerprint>, // These are the metadata hashes for the current crate as they were stored // during the last compilation session. They are only loaded if // -Z query-dep-graph was specified and are needed for auto-tests using // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to // check whether some metadata hash has changed in between two revisions. - pub prev_metadata_hashes: RefCell>, + pub prev_metadata_hashes: RefCell>, } impl IncrementalHashesMap { pub fn new() -> IncrementalHashesMap { IncrementalHashesMap { - hashes: FnvHashMap(), - prev_metadata_hashes: RefCell::new(FnvHashMap()), + hashes: FxHashMap(), + prev_metadata_hashes: RefCell::new(FxHashMap()), } } diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 80c41f855ba5..0b0dd596784e 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -88,6 +88,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { // within the CodeMap. // Also note that we are hashing byte offsets for the column, not unicode // codepoint offsets. For the purpose of the hash that's sufficient. + // Also, hashing filenames is expensive so we avoid doing it twice when the + // span starts and ends in the same file, which is almost always the case. fn hash_span(&mut self, span: Span) { debug!("hash_span: st={:?}", self.st); @@ -103,21 +105,35 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { span.hi }; - let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); - let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi); - - let expansion_kind = match span.expn_id { + let expn_kind = match span.expn_id { NO_EXPANSION => SawSpanExpnKind::NoExpansion, COMMAND_LINE_EXPN => SawSpanExpnKind::CommandLine, _ => SawSpanExpnKind::SomeExpansion, }; - SawSpan(loc1.as_ref().map(|&(ref fm, line, col)| (&fm.name[..], line, col)), - loc2.as_ref().map(|&(ref fm, line, col)| (&fm.name[..], line, col)), - expansion_kind) - .hash(self.st); + let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); + let loc1 = loc1.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col)) + .unwrap_or(("???", 0, BytePos(0))); - if expansion_kind == SawSpanExpnKind::SomeExpansion { + let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi); + let loc2 = loc2.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col)) + .unwrap_or(("???", 0, BytePos(0))); + + let saw = if loc1.0 == loc2.0 { + SawSpan(loc1.0, + loc1.1, loc1.2, + loc2.1, loc2.2, + expn_kind) + } else { + SawSpanTwoFiles(loc1.0, loc1.1, loc1.2, + loc2.0, loc2.1, loc2.2, + expn_kind) + }; + saw.hash(self.st); + + if expn_kind == SawSpanExpnKind::SomeExpansion { let call_site = self.codemap.codemap().source_callsite(span); self.hash_span(call_site); } @@ -189,9 +205,13 @@ enum SawAbiComponent<'a> { SawAssocTypeBinding, SawAttribute(ast::AttrStyle), SawMacroDef, - SawSpan(Option<(&'a str, usize, BytePos)>, - Option<(&'a str, usize, BytePos)>, + SawSpan(&'a str, + usize, BytePos, + usize, BytePos, SawSpanExpnKind), + SawSpanTwoFiles(&'a str, usize, BytePos, + &'a str, usize, BytePos, + SawSpanExpnKind), } /// SawExprComponent carries all of the information that we want @@ -814,7 +834,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { Def::Const(..) | Def::AssociatedConst(..) | Def::Local(..) | - Def::Upvar(..) => { + Def::Upvar(..) | + Def::Macro(..) => { DefHash::SawDefId.hash(self.st); self.hash_def_id(def.def_id()); } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 577e50699bff..4a5a6b9bea90 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -19,7 +19,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![cfg_attr(stage0, feature(question_mark))] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 734ffe6a9441..f0e4f4f99ef0 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -13,7 +13,7 @@ use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId}; use rustc::hir::def_id::DefIndex; use std::sync::Arc; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use ich::Fingerprint; use super::directory::DefPathIndex; @@ -106,7 +106,7 @@ pub struct SerializedMetadataHashes { /// is only populated if -Z query-dep-graph is specified. It will be /// empty otherwise. Importing crates are perfectly happy with just having /// the DefIndex. - pub index_map: FnvHashMap + pub index_map: FxHashMap } /// The hash for some metadata that (when saving) will be exported diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 94478f6603a6..69b9be12de46 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -47,7 +47,7 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::Visitor; use syntax::ast::{self, Attribute, NestedMetaItem}; -use rustc_data_structures::fnv::{FnvHashSet, FnvHashMap}; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use syntax::parse::token::InternedString; use syntax_pos::Span; use rustc::ty::TyCtxt; @@ -67,7 +67,7 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let _ignore = tcx.dep_graph.in_ignore(); - let dirty_inputs: FnvHashSet> = + let dirty_inputs: FxHashSet> = dirty_inputs.iter() .filter_map(|d| retraced.map(d)) .collect(); @@ -84,7 +84,7 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct DirtyCleanVisitor<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, query: &'a DepGraphQuery, - dirty_inputs: FnvHashSet>, + dirty_inputs: FxHashSet>, } impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { @@ -187,8 +187,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> { } pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prev_metadata_hashes: &FnvHashMap, - current_metadata_hashes: &FnvHashMap) { + prev_metadata_hashes: &FxHashMap, + current_metadata_hashes: &FxHashMap) { if !tcx.sess.opts.debugging_opts.query_dep_graph { return; } @@ -205,8 +205,8 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - prev_metadata_hashes: &'m FnvHashMap, - current_metadata_hashes: &'m FnvHashMap, + prev_metadata_hashes: &'m FxHashMap, + current_metadata_hashes: &'m FxHashMap, } impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> { diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index ff7c3d0512e4..ca9c11920232 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -120,7 +120,7 @@ use rustc::session::Session; use rustc::ty::TyCtxt; use rustc::util::fs as fs_util; use rustc_data_structures::flock; -use rustc_data_structures::fnv::{FnvHashSet, FnvHashMap}; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use std::ffi::OsString; use std::fs as std_fs; @@ -195,7 +195,7 @@ pub fn prepare_session_directory(tcx: TyCtxt) -> Result { debug!("crate-dir: {}", crate_dir.display()); try!(create_dir(tcx.sess, &crate_dir, "crate")); - let mut source_directories_already_tried = FnvHashSet(); + let mut source_directories_already_tried = FxHashSet(); loop { // Generate a session directory of the form: @@ -490,7 +490,7 @@ fn delete_session_dir_lock_file(sess: &Session, /// Find the most recent published session directory that is not in the /// ignore-list. fn find_source_directory(crate_dir: &Path, - source_directories_already_tried: &FnvHashSet) + source_directories_already_tried: &FxHashSet) -> Option { let iter = crate_dir.read_dir() .unwrap() // FIXME @@ -500,7 +500,7 @@ fn find_source_directory(crate_dir: &Path, } fn find_source_directory_in_iter(iter: I, - source_directories_already_tried: &FnvHashSet) + source_directories_already_tried: &FxHashSet) -> Option where I: Iterator { @@ -704,8 +704,8 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { // First do a pass over the crate directory, collecting lock files and // session directories - let mut session_directories = FnvHashSet(); - let mut lock_files = FnvHashSet(); + let mut session_directories = FxHashSet(); + let mut lock_files = FxHashSet(); for dir_entry in try!(crate_directory.read_dir()) { let dir_entry = match dir_entry { @@ -731,7 +731,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { } // Now map from lock files to session directories - let lock_file_to_session_dir: FnvHashMap> = + let lock_file_to_session_dir: FxHashMap> = lock_files.into_iter() .map(|lock_file_name| { assert!(lock_file_name.ends_with(LOCK_FILE_EXT)); @@ -774,7 +774,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { } // Filter out `None` directories - let lock_file_to_session_dir: FnvHashMap = + let lock_file_to_session_dir: FxHashMap = lock_file_to_session_dir.into_iter() .filter_map(|(lock_file_name, directory_name)| { directory_name.map(|n| (lock_file_name, n)) @@ -898,7 +898,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> { } fn all_except_most_recent(deletion_candidates: Vec<(SystemTime, PathBuf, Option)>) - -> FnvHashMap> { + -> FxHashMap> { let most_recent = deletion_candidates.iter() .map(|&(timestamp, ..)| timestamp) .max(); @@ -909,7 +909,7 @@ fn all_except_most_recent(deletion_candidates: Vec<(SystemTime, PathBuf, Option< .map(|(_, path, lock)| (path, lock)) .collect() } else { - FnvHashMap() + FxHashMap() } } @@ -946,19 +946,19 @@ fn test_all_except_most_recent() { (UNIX_EPOCH + Duration::new(5, 0), PathBuf::from("5"), None), (UNIX_EPOCH + Duration::new(3, 0), PathBuf::from("3"), None), (UNIX_EPOCH + Duration::new(2, 0), PathBuf::from("2"), None), - ]).keys().cloned().collect::>(), + ]).keys().cloned().collect::>(), vec![ PathBuf::from("1"), PathBuf::from("2"), PathBuf::from("3"), PathBuf::from("4"), - ].into_iter().collect::>() + ].into_iter().collect::>() ); assert_eq!(all_except_most_recent( vec![ - ]).keys().cloned().collect::>(), - FnvHashSet() + ]).keys().cloned().collect::>(), + FxHashSet() ); } @@ -973,7 +973,7 @@ fn test_timestamp_serialization() { #[test] fn test_find_source_directory_in_iter() { - let already_visited = FnvHashSet(); + let already_visited = FxHashSet(); // Find newest assert_eq!(find_source_directory_in_iter( diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index e365cbbd3a9a..73311ee96c53 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -12,7 +12,7 @@ use rustc::dep_graph::DepNode; use rustc::hir::def_id::{CrateNum, DefId}; use rustc::hir::svh::Svh; use rustc::ty::TyCtxt; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::flock; use rustc_serialize::Decodable; use rustc_serialize::opaque::Decoder; @@ -26,8 +26,8 @@ use super::file_format; pub struct HashContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &'a IncrementalHashesMap, - item_metadata_hashes: FnvHashMap, - crate_hashes: FnvHashMap, + item_metadata_hashes: FxHashMap, + crate_hashes: FxHashMap, } impl<'a, 'tcx> HashContext<'a, 'tcx> { @@ -37,8 +37,8 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { HashContext { tcx: tcx, incremental_hashes_map: incremental_hashes_map, - item_metadata_hashes: FnvHashMap(), - crate_hashes: FnvHashMap(), + item_metadata_hashes: FxHashMap(), + crate_hashes: FxHashMap(), } } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 7cef246b6cb2..12bf74c95116 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -15,7 +15,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; use rustc::session::Session; use rustc::ty::TyCtxt; -use rustc_data_structures::fnv::{FnvHashSet, FnvHashMap}; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_serialize::Decodable as RustcDecodable; use rustc_serialize::opaque::Decoder; use std::fs; @@ -30,7 +30,7 @@ use super::hash::*; use super::fs::*; use super::file_format; -pub type DirtyNodes = FnvHashSet>; +pub type DirtyNodes = FxHashSet>; /// If we are in incremental mode, and a previous dep-graph exists, /// then load up those nodes/edges that are still valid into the @@ -183,7 +183,7 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Compute which work-products have an input that has changed or // been removed. Put the dirty ones into a set. - let mut dirty_target_nodes = FnvHashSet(); + let mut dirty_target_nodes = FxHashSet(); for &(raw_source_node, ref target_node) in &retraced_edges { if dirty_raw_source_nodes.contains(raw_source_node) { if !dirty_target_nodes.contains(target_node) { @@ -239,7 +239,7 @@ fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, retraced: &RetracedDefIdDirectory) -> DirtyNodes { let mut hcx = HashContext::new(tcx, incremental_hashes_map); - let mut dirty_nodes = FnvHashSet(); + let mut dirty_nodes = FxHashSet(); for hash in serialized_hashes { if let Some(dep_node) = retraced.map(&hash.dep_node) { @@ -270,7 +270,7 @@ fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// otherwise no longer applicable. fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, work_products: Vec, - dirty_target_nodes: &FnvHashSet>) { + dirty_target_nodes: &FxHashSet>) { debug!("reconcile_work_products({:?})", work_products); for swp in work_products { if dirty_target_nodes.contains(&DepNode::WorkProduct(swp.id.clone())) { @@ -314,7 +314,7 @@ fn delete_dirty_work_product(tcx: TyCtxt, fn load_prev_metadata_hashes(tcx: TyCtxt, retraced: &RetracedDefIdDirectory, - output: &mut FnvHashMap) { + output: &mut FxHashMap) { if !tcx.sess.opts.debugging_opts.query_dep_graph { return } diff --git a/src/librustc_incremental/persist/preds.rs b/src/librustc_incremental/persist/preds.rs index fe1d627253f2..e1968ce8d7b6 100644 --- a/src/librustc_incremental/persist/preds.rs +++ b/src/librustc_incremental/persist/preds.rs @@ -10,7 +10,7 @@ use rustc::dep_graph::{DepGraphQuery, DepNode}; use rustc::hir::def_id::DefId; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::{DepthFirstTraversal, INCOMING, NodeIndex}; use super::hash::*; @@ -23,11 +23,11 @@ pub struct Predecessors<'query> { // nodes. // - Values: transitive predecessors of the key that are hashable // (e.g., HIR nodes, input meta-data nodes) - pub inputs: FnvHashMap<&'query DepNode, Vec<&'query DepNode>>, + pub inputs: FxHashMap<&'query DepNode, Vec<&'query DepNode>>, // - Keys: some hashable node // - Values: the hash thereof - pub hashes: FnvHashMap<&'query DepNode, Fingerprint>, + pub hashes: FxHashMap<&'query DepNode, Fingerprint>, } impl<'q> Predecessors<'q> { @@ -37,7 +37,7 @@ impl<'q> Predecessors<'q> { let all_nodes = query.graph.all_nodes(); let tcx = hcx.tcx; - let inputs: FnvHashMap<_, _> = all_nodes.iter() + let inputs: FxHashMap<_, _> = all_nodes.iter() .enumerate() .filter(|&(_, node)| match node.data { DepNode::WorkProduct(_) => true, @@ -60,7 +60,7 @@ impl<'q> Predecessors<'q> { }) .collect(); - let mut hashes = FnvHashMap(); + let mut hashes = FxHashMap(); for input in inputs.values().flat_map(|v| v.iter().cloned()) { hashes.entry(input) .or_insert_with(|| hcx.hash(input).unwrap()); diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index bc156b0e8913..289eebb21620 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -13,7 +13,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; use rustc::session::Session; use rustc::ty::TyCtxt; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_serialize::Encodable as RustcEncodable; use rustc_serialize::opaque::Encoder; use std::hash::Hash; @@ -46,7 +46,7 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let query = tcx.dep_graph.query(); let mut hcx = HashContext::new(tcx, incremental_hashes_map); let preds = Predecessors::new(&query, &mut hcx); - let mut current_metadata_hashes = FnvHashMap(); + 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 @@ -186,7 +186,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, svh: Svh, preds: &Predecessors, builder: &mut DefIdDirectoryBuilder, - current_metadata_hashes: &mut FnvHashMap, + current_metadata_hashes: &mut FxHashMap, encoder: &mut Encoder) -> io::Result<()> { // For each `MetaData(X)` node where `X` is local, accumulate a @@ -198,10 +198,10 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, // (I initially wrote this with an iterator, but it seemed harder to read.) let mut serialized_hashes = SerializedMetadataHashes { hashes: vec![], - index_map: FnvHashMap() + index_map: FxHashMap() }; - let mut def_id_hashes = FnvHashMap(); + let mut def_id_hashes = FxHashMap(); for (&target, sources) in &preds.inputs { let def_id = match *target { diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index fea3de59520c..6320a923d690 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -29,10 +29,10 @@ pub enum MethodLateContext { pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext { let def_id = cx.tcx.map.local_def_id(id); - match cx.tcx.impl_or_trait_items.borrow().get(&def_id) { + match cx.tcx.associated_items.borrow().get(&def_id) { None => span_bug!(span, "missing method descriptor?!"), Some(item) => { - match item.container() { + match item.container { ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl, ty::ImplContainer(cid) => { match cx.tcx.impl_trait_ref(cid) { @@ -250,7 +250,7 @@ impl LateLintPass for NonSnakeCase { cx: &LateContext, fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, + _: &hir::Expr, span: Span, id: ast::NodeId) { match fk { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index a28109c14719..c19b3c40f65c 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -34,7 +34,6 @@ use middle::stability; use rustc::cfg; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::adjustment; use rustc::traits::{self, Reveal}; use rustc::hir::map as hir_map; use util::nodemap::NodeSet; @@ -118,7 +117,9 @@ impl LateLintPass for BoxPointers { hir::ItemTy(..) | hir::ItemEnum(..) | hir::ItemStruct(..) | - hir::ItemUnion(..) => self.check_heap_type(cx, it.span, cx.tcx.node_id_to_type(it.id)), + hir::ItemUnion(..) => { + self.check_heap_type(cx, it.span, cx.tcx.tables().node_id_to_type(it.id)) + } _ => (), } @@ -129,7 +130,7 @@ impl LateLintPass for BoxPointers { for struct_field in struct_def.fields() { self.check_heap_type(cx, struct_field.span, - cx.tcx.node_id_to_type(struct_field.id)); + cx.tcx.tables().node_id_to_type(struct_field.id)); } } _ => (), @@ -137,7 +138,7 @@ impl LateLintPass for BoxPointers { } fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { - let ty = cx.tcx.node_id_to_type(e.id); + let ty = cx.tcx.tables().node_id_to_type(e.id); self.check_heap_type(cx, e.span, ty); } } @@ -221,7 +222,7 @@ impl LateLintPass for UnsafeCode { cx: &LateContext, fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, + _: &hir::Expr, span: Span, _: ast::NodeId) { match fk { @@ -585,7 +586,7 @@ impl LateLintPass for MissingDebugImplementations { let mut impls = NodeSet(); debug_def.for_each_impl(cx.tcx, |d| { if let Some(n) = cx.tcx.map.as_local_node_id(d) { - if let Some(ty_def) = cx.tcx.node_id_to_type(n).ty_to_def_id() { + if let Some(ty_def) = cx.tcx.tables().node_id_to_type(n).ty_to_def_id() { if let Some(node_id) = cx.tcx.map.as_local_node_id(ty_def) { impls.insert(node_id); } @@ -811,13 +812,13 @@ impl LateLintPass for UnconditionalRecursion { cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl, - blk: &hir::Block, + blk: &hir::Expr, sp: Span, id: ast::NodeId) { let method = match fn_kind { FnKind::ItemFn(..) => None, FnKind::Method(..) => { - cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method() + Some(cx.tcx.associated_item(cx.tcx.map.local_def_id(id))) } // closures can't recur, so they don't matter. FnKind::Closure(_) => return, @@ -936,11 +937,13 @@ impl LateLintPass for UnconditionalRecursion { // Check if the expression `id` performs a call to `method`. fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - method: &ty::Method, + method: &ty::AssociatedItem, id: ast::NodeId) -> bool { + use rustc::ty::adjustment::*; + // Check for method calls and overloaded operators. - let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned(); + let opt_m = tcx.tables().method_map.get(&ty::MethodCall::expr(id)).cloned(); if let Some(m) = opt_m { if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) { return true; @@ -948,15 +951,12 @@ impl LateLintPass for UnconditionalRecursion { } // Check for overloaded autoderef method calls. - let opt_adj = tcx.tables.borrow().adjustments.get(&id).cloned(); - if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj { - for i in 0..adj.autoderefs { + let opt_adj = tcx.tables().adjustments.get(&id).cloned(); + if let Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) = opt_adj { + for i in 0..autoderefs { let method_call = ty::MethodCall::autoderef(id, i as u32); - if let Some(m) = tcx.tables - .borrow() - .method_map - .get(&method_call) - .cloned() { + if let Some(m) = tcx.tables().method_map.get(&method_call) + .cloned() { if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) { return true; } @@ -971,12 +971,10 @@ impl LateLintPass for UnconditionalRecursion { // it doesn't necessarily have a definition. match tcx.expect_def_or_none(callee.id) { Some(Def::Method(def_id)) => { - let item_substs = tcx.node_id_item_substs(callee.id); - method_call_refers_to_method(tcx, - method, - def_id, - &item_substs.substs, - id) + let substs = tcx.tables().node_id_item_substs(callee.id) + .unwrap_or_else(|| tcx.intern_substs(&[])); + method_call_refers_to_method( + tcx, method, def_id, substs, id) } _ => false, } @@ -988,14 +986,14 @@ impl LateLintPass for UnconditionalRecursion { // Check if the method call to the method with the ID `callee_id` // and instantiated with `callee_substs` refers to method `method`. fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - method: &ty::Method, + method: &ty::AssociatedItem, callee_id: DefId, callee_substs: &Substs<'tcx>, expr_id: ast::NodeId) -> bool { - let callee_item = tcx.impl_or_trait_item(callee_id); + let callee_item = tcx.associated_item(callee_id); - match callee_item.container() { + match callee_item.container { // This is an inherent method, so the `def_id` refers // directly to the method definition. ty::ImplContainer(_) => callee_id == method.def_id, @@ -1036,7 +1034,7 @@ impl LateLintPass for UnconditionalRecursion { let container = ty::ImplContainer(vtable_impl.impl_def_id); // It matches if it comes from the same impl, // and has the same method name. - container == method.container && callee_item.name() == method.name + container == method.container && callee_item.name == method.name } // There's no way to know if this call is @@ -1213,7 +1211,7 @@ impl LateLintPass for MutableTransmutes { if !def_id_is_transmute(cx, did) { return None; } - let typ = cx.tcx.node_id_to_type(expr.id); + let typ = cx.tcx.tables().node_id_to_type(expr.id); match typ.sty { ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => { let from = bare_fn.sig.0.inputs[0]; @@ -1284,7 +1282,7 @@ impl LateLintPass for UnionsWithDropFields { if let hir::ItemUnion(ref vdata, _) = item.node { let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id); for field in vdata.fields() { - let field_ty = ctx.tcx.node_id_to_type(field.id); + let field_ty = ctx.tcx.tables().node_id_to_type(field.id); if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) { ctx.span_lint(UNIONS_WITH_DROP_FIELDS, field.span, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 6f114e09a6c7..114c0ea556ef 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -31,13 +31,12 @@ #![cfg_attr(test, feature(test))] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(staged_api)] -#![feature(dotdot_in_tuple_patterns)] #[macro_use] extern crate syntax; @@ -229,6 +228,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY), reference: "issue #35203 ", }, + FutureIncompatibleInfo { + id: LintId::of(EXTRA_REQUIREMENT_IN_IMPL), + reference: "issue #37166 ", + }, ]); // Register renamed and removed lints diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 9464bf30b693..48471282672a 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -18,7 +18,7 @@ use rustc::traits::Reveal; use middle::const_val::ConstVal; use rustc_const_eval::eval_const_expr_partial; use rustc_const_eval::EvalHint::ExprTypeChecked; -use util::nodemap::FnvHashSet; +use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -113,14 +113,14 @@ impl LateLintPass for TypeLimits { forbid_unsigned_negation(cx, e.span); } ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { - if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty { + if let ty::TyUint(_) = cx.tcx.tables().node_id_to_type(e.id).sty { forbid_unsigned_negation(cx, e.span); } } _ => (), } } else { - let t = cx.tcx.node_id_to_type(expr.id); + let t = cx.tcx.tables().node_id_to_type(expr.id); if let ty::TyUint(_) = t.sty { forbid_unsigned_negation(cx, e.span); } @@ -138,7 +138,7 @@ impl LateLintPass for TypeLimits { } if binop.node.is_shift() { - let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty { + let opt_ty_bits = match cx.tcx.tables().node_id_to_type(l.id).sty { ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)), ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)), _ => None, @@ -171,7 +171,7 @@ impl LateLintPass for TypeLimits { } } hir::ExprLit(ref lit) => { - match cx.tcx.node_id_to_type(e.id).sty { + match cx.tcx.tables().node_id_to_type(e.id).sty { ty::TyInt(t) => { match lit.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | @@ -324,7 +324,7 @@ impl LateLintPass for TypeLimits { // Normalize the binop so that the literal is always on the RHS in // the comparison let norm_binop = if swap { rev_binop(binop) } else { binop }; - match tcx.node_id_to_type(expr.id).sty { + match tcx.tables().node_id_to_type(expr.id).sty { ty::TyInt(int_ty) => { let (min, max) = int_ty_range(int_ty); let lit_val: i64 = match lit.node { @@ -428,7 +428,7 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the given type is "ffi-safe" (has a stable, well-defined /// representation which can be exported to C code). - fn check_type_for_ffi(&self, cache: &mut FnvHashSet>, ty: Ty<'tcx>) -> FfiResult { + fn check_type_for_ffi(&self, cache: &mut FxHashSet>, ty: Ty<'tcx>) -> FfiResult { use self::FfiResult::*; let cx = self.cx.tcx; @@ -639,7 +639,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // any generic types right now: let ty = self.cx.tcx.normalize_associated_type(&ty); - match self.check_type_for_ffi(&mut FnvHashSet(), ty) { + match self.check_type_for_ffi(&mut FxHashSet(), ty) { FfiResult::FfiSafe => {} FfiResult::FfiUnsafe(s) => { self.cx.span_lint(IMPROPER_CTYPES, sp, s); @@ -740,7 +740,7 @@ impl LateLintPass for VariantSizeDifferences { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types - let t = cx.tcx.node_id_to_type(it.id); + let t = cx.tcx.tables().node_id_to_type(it.id); let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let ty = cx.tcx.erase_regions(&t); ty.layout(&infcx) diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index a29ff18ab531..0668d362037d 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -11,7 +11,7 @@ use rustc::hir::pat_util; use rustc::ty; use rustc::ty::adjustment; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use lint::{LateContext, EarlyContext, LintContext, LintArray}; use lint::{LintPass, EarlyLintPass, LateLintPass}; @@ -19,7 +19,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::ast; use syntax::attr; -use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; +use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType}; use syntax::parse::token::keywords; use syntax::ptr::P; use syntax_pos::Span; @@ -42,7 +42,7 @@ impl UnusedMut { // collect all mutable pattern and group their NodeIDs by their Identifier to // avoid false warnings in match arms with multiple patterns - let mut mutables = FnvHashMap(); + let mut mutables = FxHashMap(); for p in pats { pat_util::pat_bindings(p, |mode, id, _, path1| { let name = path1.node; @@ -99,7 +99,7 @@ impl LateLintPass for UnusedMut { cx: &LateContext, _: FnKind, decl: &hir::FnDecl, - _: &hir::Block, + _: &hir::Expr, _: Span, _: ast::NodeId) { for a in &decl.inputs { @@ -140,7 +140,7 @@ impl LateLintPass for UnusedResults { return; } - let t = cx.tcx.expr_ty(&expr); + let t = cx.tcx.tables().expr_ty(&expr); let warned = match t.sty { ty::TyTuple(ref tys) if tys.is_empty() => return, ty::TyNever => return, @@ -245,7 +245,7 @@ impl LateLintPass for UnusedAttributes { debug!("checking attribute: {:?}", attr); // Note that check_name() marks the attribute as used if it matches. - for &(ref name, ty, _) in KNOWN_ATTRIBUTES { + for &(ref name, ty, _) in BUILTIN_ATTRIBUTES { match ty { AttributeType::Whitelisted if attr.check_name(name) => { debug!("{:?} is Whitelisted", name); @@ -267,7 +267,7 @@ impl LateLintPass for UnusedAttributes { debug!("Emitting warning for: {:?}", attr); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); // Is it a builtin attribute that must be used at the crate level? - let known_crate = KNOWN_ATTRIBUTES.iter() + let known_crate = BUILTIN_ATTRIBUTES.iter() .find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel) .is_some(); @@ -441,16 +441,15 @@ impl LateLintPass for UnusedAllocation { _ => return, } - if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) { - if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { ref autoref, .. }) = - *adjustment { + if let Some(adjustment) = cx.tcx.tables().adjustments.get(&e.id) { + if let adjustment::Adjust::DerefRef { autoref, .. } = adjustment.kind { match autoref { - &Some(adjustment::AutoPtr(_, hir::MutImmutable)) => { + Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => { cx.span_lint(UNUSED_ALLOCATION, e.span, "unnecessary allocation, use & instead"); } - &Some(adjustment::AutoPtr(_, hir::MutMutable)) => { + Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => { cx.span_lint(UNUSED_ALLOCATION, e.span, "unnecessary allocation, use &mut instead"); diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 35140d5ab4ae..8656bb8bf003 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -128,6 +128,19 @@ fn main() { // of llvm-config, not the target that we're attempting to link. let mut cmd = Command::new(&llvm_config); cmd.arg("--libs"); + + // Force static linking with "--link-static" if available. + let mut version_cmd = Command::new(&llvm_config); + version_cmd.arg("--version"); + let version_output = output(&mut version_cmd); + let mut parts = version_output.split('.'); + if let (Some(major), Some(minor)) = (parts.next().and_then(|s| s.parse::().ok()), + parts.next().and_then(|s| s.parse::().ok())) { + if major > 3 || (major == 3 && minor >= 9) { + cmd.arg("--link-static"); + } + } + if !is_crossed { cmd.arg("--system-libs"); } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index da09bfa66d28..07b87072c435 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -29,6 +29,7 @@ #![feature(staged_api)] #![feature(linked_from)] #![feature(concat_idents)] +#![cfg_attr(not(stage0), feature(rustc_private))] extern crate libc; #[macro_use] diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index f001f8513197..e009955b92ee 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -38,7 +38,7 @@ enum TableEntry<'tcx> { Def(Def), NodeType(Ty<'tcx>), ItemSubsts(ty::ItemSubsts<'tcx>), - Adjustment(ty::adjustment::AutoAdjustment<'tcx>), + Adjustment(ty::adjustment::Adjustment<'tcx>), ConstQualif(ConstQualif), } @@ -94,9 +94,9 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> }; encode(tcx.expect_def_or_none(id).map(TableEntry::Def)); - encode(tcx.node_types().get(&id).cloned().map(TableEntry::NodeType)); - encode(tcx.tables.borrow().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts)); - encode(tcx.tables.borrow().adjustments.get(&id).cloned().map(TableEntry::Adjustment)); + encode(tcx.tables().node_types.get(&id).cloned().map(TableEntry::NodeType)); + encode(tcx.tables().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts)); + encode(tcx.tables().adjustments.get(&id).cloned().map(TableEntry::Adjustment)); encode(tcx.const_qualif_map.borrow().get(&id).cloned().map(TableEntry::ConstQualif)); } } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index e72ac8419941..75944122f5c1 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -16,28 +16,27 @@ use schema::CrateRoot; use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::svh::Svh; -use rustc::middle::cstore::LoadedMacros; +use rustc::middle::cstore::DepKind; use rustc::session::{config, Session}; use rustc_back::PanicStrategy; use rustc::session::search_paths::PathKind; use rustc::middle; use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; -use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc::hir::map::Definitions; use std::cell::{RefCell, Cell}; use std::ops::Deref; use std::path::PathBuf; use std::rc::Rc; -use std::fs; +use std::{cmp, fs}; use syntax::ast; use syntax::abi::Abi; -use syntax::parse; use syntax::attr; use syntax::ext::base::SyntaxExtension; use syntax::parse::token::{InternedString, intern}; -use syntax_pos::{self, Span, mk_sp}; +use syntax_pos::{Span, DUMMY_SP}; use log; pub struct Library { @@ -50,35 +49,29 @@ pub struct CrateLoader<'a> { pub sess: &'a Session, cstore: &'a CStore, next_crate_num: CrateNum, - foreign_item_map: FnvHashMap>, + foreign_item_map: FxHashMap>, local_crate_name: String, } fn dump_crates(cstore: &CStore) { info!("resolved crates:"); - cstore.iter_crate_data_origins(|_, data, opt_source| { + cstore.iter_crate_data(|_, data| { info!(" name: {}", data.name()); info!(" cnum: {}", data.cnum); info!(" hash: {}", data.hash()); - info!(" reqd: {}", data.explicitly_linked.get()); - opt_source.map(|cs| { - let CrateSource { dylib, rlib, cnum: _ } = cs; - dylib.map(|dl| info!(" dylib: {}", dl.0.display())); - rlib.map(|rl| info!(" rlib: {}", rl.0.display())); - }); + info!(" reqd: {:?}", data.dep_kind.get()); + let CrateSource { dylib, rlib } = data.source.clone(); + dylib.map(|dl| info!(" dylib: {}", dl.0.display())); + rlib.map(|rl| info!(" rlib: {}", rl.0.display())); }) } -fn should_link(i: &ast::Item) -> bool { - !attr::contains_name(&i.attrs, "no_link") -} - #[derive(Debug)] struct ExternCrateInfo { ident: String, name: String, id: ast::NodeId, - should_link: bool, + dep_kind: DepKind, } fn register_native_lib(sess: &Session, @@ -148,7 +141,7 @@ impl<'a> CrateLoader<'a> { sess: sess, cstore: cstore, next_crate_num: cstore.next_crate_num(), - foreign_item_map: FnvHashMap(), + foreign_item_map: FxHashMap(), local_crate_name: local_crate_name.to_owned(), } } @@ -170,7 +163,11 @@ impl<'a> CrateLoader<'a> { ident: i.ident.to_string(), name: name, id: i.id, - should_link: should_link(i), + dep_kind: if attr::contains_name(&i.attrs, "no_link") { + DepKind::MacrosOnly + } else { + DepKind::Explicit + }, }) } _ => None @@ -260,9 +257,8 @@ impl<'a> CrateLoader<'a> { name: &str, span: Span, lib: Library, - explicitly_linked: bool) - -> (CrateNum, Rc, - cstore::CrateSource) { + dep_kind: DepKind) + -> (CrateNum, Rc) { info!("register crate `extern crate {} as {}`", name, ident); let crate_root = lib.metadata.get_root(); self.verify_no_symbol_conflicts(span, &crate_root); @@ -286,34 +282,29 @@ impl<'a> CrateLoader<'a> { let Library { dylib, rlib, metadata } = lib; - let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span); - - if crate_root.macro_derive_registrar.is_some() { - self.sess.span_err(span, "crates of the `proc-macro` crate type \ - cannot be linked at runtime"); - } + let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind); let cmeta = Rc::new(cstore::CrateMetadata { name: name.to_string(), extern_crate: Cell::new(None), key_map: metadata.load_key_map(crate_root.index), + proc_macros: crate_root.macro_derive_registrar.map(|_| { + self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span) + }), root: crate_root, blob: metadata, cnum_map: RefCell::new(cnum_map), cnum: cnum, codemap_import_info: RefCell::new(vec![]), - explicitly_linked: Cell::new(explicitly_linked), + dep_kind: Cell::new(dep_kind), + source: cstore::CrateSource { + dylib: dylib, + rlib: rlib, + }, }); - let source = cstore::CrateSource { - dylib: dylib, - rlib: rlib, - cnum: cnum, - }; - self.cstore.set_crate_data(cnum, cmeta.clone()); - self.cstore.add_used_crate_source(source.clone()); - (cnum, cmeta, source) + (cnum, cmeta) } fn resolve_crate(&mut self, @@ -323,47 +314,58 @@ impl<'a> CrateLoader<'a> { hash: Option<&Svh>, span: Span, kind: PathKind, - explicitly_linked: bool) - -> (CrateNum, Rc, cstore::CrateSource) { + mut dep_kind: DepKind) + -> (CrateNum, Rc) { info!("resolving crate `extern crate {} as {}`", name, ident); - let result = match self.existing_match(name, hash, kind) { - Some(cnum) => LoadResult::Previous(cnum), - None => { - info!("falling back to a load"); - let mut locate_ctxt = locator::Context { - sess: self.sess, - span: span, - ident: ident, - crate_name: name, - hash: hash.map(|a| &*a), - filesearch: self.sess.target_filesearch(kind), - target: &self.sess.target.target, - triple: &self.sess.opts.target_triple, - root: root, + let result = if let Some(cnum) = self.existing_match(name, hash, kind) { + LoadResult::Previous(cnum) + } else { + info!("falling back to a load"); + let mut locate_ctxt = locator::Context { + sess: self.sess, + span: span, + ident: ident, + crate_name: name, + hash: hash.map(|a| &*a), + filesearch: self.sess.target_filesearch(kind), + target: &self.sess.target.target, + triple: &self.sess.opts.target_triple, + root: root, + rejected_via_hash: vec![], + rejected_via_triple: vec![], + rejected_via_kind: vec![], + rejected_via_version: vec![], + should_match_name: true, + is_proc_macro: Some(false), + }; + + self.load(&mut locate_ctxt).or_else(|| { + dep_kind = DepKind::MacrosOnly; + + let mut proc_macro_locator = locator::Context { + target: &self.sess.host, + triple: config::host_triple(), + filesearch: self.sess.host_filesearch(PathKind::Crate), rejected_via_hash: vec![], rejected_via_triple: vec![], rejected_via_kind: vec![], rejected_via_version: vec![], - should_match_name: true, + is_proc_macro: Some(true), + ..locate_ctxt }; - match self.load(&mut locate_ctxt) { - Some(result) => result, - None => locate_ctxt.report_errs(), - } - } + + self.load(&mut proc_macro_locator) + }).unwrap_or_else(|| locate_ctxt.report_errs()) }; match result { LoadResult::Previous(cnum) => { let data = self.cstore.get_crate_data(cnum); - if explicitly_linked && !data.explicitly_linked.get() { - data.explicitly_linked.set(explicitly_linked); - } - (cnum, data, self.cstore.used_crate_source(cnum)) + data.dep_kind.set(cmp::max(data.dep_kind.get(), dep_kind)); + (cnum, data) } LoadResult::Loaded(library) => { - self.register_crate(root, ident, name, span, library, - explicitly_linked) + self.register_crate(root, ident, name, span, library, dep_kind) } } } @@ -401,7 +403,7 @@ impl<'a> CrateLoader<'a> { fn update_extern_crate(&mut self, cnum: CrateNum, mut extern_crate: ExternCrate, - visited: &mut FnvHashSet<(CrateNum, bool)>) + visited: &mut FxHashSet<(CrateNum, bool)>) { if !visited.insert((cnum, extern_crate.direct)) { return } @@ -436,21 +438,27 @@ impl<'a> CrateLoader<'a> { crate_root: &CrateRoot, metadata: &MetadataBlob, krate: CrateNum, - span: Span) + span: Span, + dep_kind: DepKind) -> cstore::CrateNumMap { debug!("resolving deps of external crate"); + if crate_root.macro_derive_registrar.is_some() { + return cstore::CrateNumMap::new(); + } + // The map from crate numbers in the crate we're resolving to local crate // numbers let deps = crate_root.crate_deps.decode(metadata); - let map: FnvHashMap<_, _> = deps.enumerate().map(|(crate_num, dep)| { + let map: FxHashMap<_, _> = deps.enumerate().map(|(crate_num, dep)| { debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); - let (local_cnum, ..) = self.resolve_crate(root, - &dep.name.as_str(), - &dep.name.as_str(), - Some(&dep.hash), - span, - PathKind::Dependency, - dep.explicitly_linked); + let dep_name = &dep.name.as_str(); + let dep_kind = match dep_kind { + DepKind::MacrosOnly => DepKind::MacrosOnly, + _ => dep.kind, + }; + let (local_cnum, ..) = self.resolve_crate( + root, dep_name, dep_name, Some(&dep.hash), span, PathKind::Dependency, dep_kind, + ); (CrateNum::new(crate_num + 1), local_cnum) }).collect(); @@ -464,8 +472,8 @@ impl<'a> CrateLoader<'a> { } fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate { - info!("read extension crate {} `extern crate {} as {}` linked={}", - info.id, info.name, info.ident, info.should_link); + info!("read extension crate {} `extern crate {} as {}` dep_kind={:?}", + info.id, info.name, info.ident, info.dep_kind); let target_triple = &self.sess.opts.target_triple[..]; let is_cross = target_triple != config::host_triple(); let mut target_only = false; @@ -486,6 +494,7 @@ impl<'a> CrateLoader<'a> { rejected_via_kind: vec![], rejected_via_version: vec![], should_match_name: true, + is_proc_macro: None, }; let library = self.load(&mut locate_ctxt).or_else(|| { if !is_cross { @@ -508,9 +517,8 @@ impl<'a> CrateLoader<'a> { let (dylib, metadata) = match library { LoadResult::Previous(cnum) => { - let dylib = self.cstore.opt_used_crate_source(cnum).unwrap().dylib; let data = self.cstore.get_crate_data(cnum); - (dylib, PMDSource::Registered(data)) + (data.source.dylib.clone(), PMDSource::Registered(data)) } LoadResult::Loaded(library) => { let dylib = library.dylib.clone(); @@ -526,68 +534,6 @@ impl<'a> CrateLoader<'a> { } } - fn read_macros(&mut self, item: &ast::Item, ekrate: &ExtensionCrate) -> LoadedMacros { - let root = ekrate.metadata.get_root(); - let source_name = format!("<{} macros>", item.ident); - let mut macro_rules = Vec::new(); - - for def in root.macro_defs.decode(&*ekrate.metadata) { - // NB: Don't use parse::parse_tts_from_source_str because it parses with - // quote_depth > 0. - let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, - source_name.clone(), - def.body); - let lo = p.span.lo; - let body = match p.parse_all_token_trees() { - Ok(body) => body, - Err(mut err) => { - err.emit(); - self.sess.abort_if_errors(); - unreachable!(); - } - }; - let local_span = mk_sp(lo, p.prev_span.hi); - - // Mark the attrs as used - for attr in &def.attrs { - attr::mark_used(attr); - } - - macro_rules.push(ast::MacroDef { - ident: ast::Ident::with_empty_ctxt(def.name), - id: ast::DUMMY_NODE_ID, - span: local_span, - imported_from: Some(item.ident), - allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"), - attrs: def.attrs, - body: body, - }); - self.sess.imported_macro_spans.borrow_mut() - .insert(local_span, (def.name.as_str().to_string(), def.span)); - } - - if let Some(id) = root.macro_derive_registrar { - let dylib = match ekrate.dylib.clone() { - Some(dylib) => dylib, - None => span_bug!(item.span, "proc-macro crate not dylib"), - }; - if ekrate.target_only { - let message = format!("proc-macro crate is not available for \ - triple `{}` (only found {})", - config::host_triple(), - self.sess.opts.target_triple); - self.sess.span_fatal(item.span, &message); - } - - // custom derive crates currently should not have any macro_rules! - // exported macros, enforced elsewhere - assert_eq!(macro_rules.len(), 0); - LoadedMacros::ProcMacros(self.load_derive_macros(item, id, root.hash, dylib)) - } else { - LoadedMacros::MacroRules(macro_rules) - } - } - /// Load custom derive macros. /// /// Note that this is intentionally similar to how we load plugins today, @@ -595,38 +541,47 @@ impl<'a> CrateLoader<'a> { /// implemented as dynamic libraries, but we have a possible future where /// custom derive (and other macro-1.1 style features) are implemented via /// executables and custom IPC. - fn load_derive_macros(&mut self, item: &ast::Item, index: DefIndex, svh: Svh, path: PathBuf) - -> Vec<(ast::Name, SyntaxExtension)> { + fn load_derive_macros(&mut self, root: &CrateRoot, dylib: Option, span: Span) + -> Vec<(ast::Name, Rc)> { use std::{env, mem}; use proc_macro::TokenStream; use proc_macro::__internal::Registry; use rustc_back::dynamic_lib::DynamicLibrary; use syntax_ext::deriving::custom::CustomDerive; + let path = match dylib { + Some(dylib) => dylib, + None => span_bug!(span, "proc-macro crate not dylib"), + }; // Make sure the path contains a / or the linker will search for it. let path = env::current_dir().unwrap().join(path); let lib = match DynamicLibrary::open(Some(&path)) { Ok(lib) => lib, - Err(err) => self.sess.span_fatal(item.span, &err), + Err(err) => self.sess.span_fatal(span, &err), }; - let sym = self.sess.generate_derive_registrar_symbol(&svh, index); + let sym = self.sess.generate_derive_registrar_symbol(&root.hash, + root.macro_derive_registrar.unwrap()); let registrar = unsafe { let sym = match lib.symbol(&sym) { Ok(f) => f, - Err(err) => self.sess.span_fatal(item.span, &err), + Err(err) => self.sess.span_fatal(span, &err), }; mem::transmute::<*mut u8, fn(&mut Registry)>(sym) }; - struct MyRegistrar(Vec<(ast::Name, SyntaxExtension)>); + struct MyRegistrar(Vec<(ast::Name, Rc)>); impl Registry for MyRegistrar { fn register_custom_derive(&mut self, trait_name: &str, - expand: fn(TokenStream) -> TokenStream) { - let derive = SyntaxExtension::CustomDerive(Box::new(CustomDerive::new(expand))); - self.0.push((intern(trait_name), derive)); + expand: fn(TokenStream) -> TokenStream, + attributes: &[&'static str]) { + let attrs = attributes.iter().map(|s| InternedString::new(s)).collect(); + let derive = SyntaxExtension::CustomDerive( + Box::new(CustomDerive::new(expand, attrs)) + ); + self.0.push((intern(trait_name), Rc::new(derive))); } } @@ -647,7 +602,7 @@ impl<'a> CrateLoader<'a> { name: name.to_string(), ident: name.to_string(), id: ast::DUMMY_NODE_ID, - should_link: false, + dep_kind: DepKind::MacrosOnly, }); if ekrate.target_only { @@ -721,7 +676,7 @@ impl<'a> CrateLoader<'a> { // #![panic_runtime] crate. self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime()); - runtime_found = runtime_found || data.explicitly_linked.get(); + runtime_found = runtime_found || data.dep_kind.get() == DepKind::Explicit; } }); @@ -750,9 +705,9 @@ impl<'a> CrateLoader<'a> { }; info!("panic runtime not found -- loading {}", name); - let (cnum, data, _) = self.resolve_crate(&None, name, name, None, - syntax_pos::DUMMY_SP, - PathKind::Crate, false); + let dep_kind = DepKind::Implicit; + let (cnum, data) = + self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind); // Sanity check the loaded crate to ensure it is indeed a panic runtime // and the panic strategy is indeed what we thought it was. @@ -786,7 +741,7 @@ impl<'a> CrateLoader<'a> { self.inject_dependency_if(cnum, "an allocator", &|data| data.needs_allocator()); found_required_allocator = found_required_allocator || - data.explicitly_linked.get(); + data.dep_kind.get() == DepKind::Explicit; } }); if !needs_allocator || found_required_allocator { return } @@ -832,9 +787,9 @@ impl<'a> CrateLoader<'a> { } else { &self.sess.target.target.options.exe_allocation_crate }; - let (cnum, data, _) = self.resolve_crate(&None, name, name, None, - syntax_pos::DUMMY_SP, - PathKind::Crate, false); + let dep_kind = DepKind::Implicit; + let (cnum, data) = + self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind); // Sanity check the crate we loaded to ensure that it is indeed an // allocator. @@ -974,46 +929,16 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { self.register_statically_included_foreign_items(); } - fn process_item(&mut self, item: &ast::Item, definitions: &Definitions, load_macros: bool) - -> Option { + fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) { match item.node { ast::ItemKind::ExternCrate(_) => {} - ast::ItemKind::ForeignMod(ref fm) => { - self.process_foreign_mod(item, fm); - return None; - } - _ => return None, + ast::ItemKind::ForeignMod(ref fm) => return self.process_foreign_mod(item, fm), + _ => return, } let info = self.extract_crate_info(item).unwrap(); - let loaded_macros = if load_macros { - let ekrate = self.read_extension_crate(item.span, &info); - let loaded_macros = self.read_macros(item, &ekrate); - - // If this is a proc-macro crate or `#[no_link]` crate, it is only used at compile time, - // so we return here to avoid registering the crate. - if loaded_macros.is_proc_macros() || !info.should_link { - return Some(loaded_macros); - } - - // Register crate now to avoid double-reading metadata - if let PMDSource::Owned(lib) = ekrate.metadata { - if ekrate.target_only || config::host_triple() == self.sess.opts.target_triple { - let ExternCrateInfo { ref ident, ref name, .. } = info; - self.register_crate(&None, ident, name, item.span, lib, true); - } - } - - Some(loaded_macros) - } else { - if !info.should_link { - return None; - } - None - }; - let (cnum, ..) = self.resolve_crate( - &None, &info.ident, &info.name, None, item.span, PathKind::Crate, true, + &None, &info.ident, &info.name, None, item.span, PathKind::Crate, info.dep_kind, ); let def_id = definitions.opt_local_def_id(item.id).unwrap(); @@ -1021,9 +946,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { let extern_crate = ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len }; - self.update_extern_crate(cnum, extern_crate, &mut FnvHashSet()); + self.update_extern_crate(cnum, extern_crate, &mut FxHashSet()); self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); - - loaded_macros } } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 58c70f959b7c..8c95e4aec0a0 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -18,16 +18,17 @@ use rustc::dep_graph::DepGraph; use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId}; use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; -use rustc::middle::cstore::ExternCrate; +use rustc::middle::cstore::{DepKind, ExternCrate}; use rustc_back::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; -use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; +use rustc::util::nodemap::{FxHashMap, NodeMap, NodeSet, DefIdMap}; use std::cell::{RefCell, Cell}; use std::rc::Rc; use std::path::PathBuf; use flate::Bytes; use syntax::{ast, attr}; +use syntax::ext::base::SyntaxExtension; use syntax_pos; pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference}; @@ -76,13 +77,12 @@ pub struct CrateMetadata { /// hashmap, which gives the reverse mapping. This allows us to /// quickly retrace a `DefPath`, which is needed for incremental /// compilation support. - pub key_map: FnvHashMap, + pub key_map: FxHashMap, - /// Flag if this crate is required by an rlib version of this crate, or in - /// other words whether it was explicitly linked to. An example of a crate - /// where this is false is when an allocator crate is injected into the - /// dependency list, and therefore isn't actually needed to link an rlib. - pub explicitly_linked: Cell, + pub dep_kind: Cell, + pub source: CrateSource, + + pub proc_macros: Option)>>, } pub struct CachedInlinedItem { @@ -94,10 +94,9 @@ pub struct CachedInlinedItem { pub struct CStore { pub dep_graph: DepGraph, - metas: RefCell>>, + metas: RefCell>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: RefCell>, - used_crate_sources: RefCell>, used_libraries: RefCell>, used_link_args: RefCell>, statically_included_foreign_items: RefCell, @@ -110,15 +109,14 @@ impl CStore { pub fn new(dep_graph: &DepGraph) -> CStore { CStore { dep_graph: dep_graph.clone(), - metas: RefCell::new(FnvHashMap()), - extern_mod_crate_map: RefCell::new(FnvHashMap()), - used_crate_sources: RefCell::new(Vec::new()), + metas: RefCell::new(FxHashMap()), + extern_mod_crate_map: RefCell::new(FxHashMap()), used_libraries: RefCell::new(Vec::new()), used_link_args: RefCell::new(Vec::new()), statically_included_foreign_items: RefCell::new(NodeSet()), - visible_parent_map: RefCell::new(FnvHashMap()), - inlined_item_cache: RefCell::new(FnvHashMap()), - defid_for_inlined_node: RefCell::new(FnvHashMap()), + visible_parent_map: RefCell::new(FxHashMap()), + inlined_item_cache: RefCell::new(FxHashMap()), + defid_for_inlined_node: RefCell::new(FxHashMap()), } } @@ -146,38 +144,9 @@ impl CStore { } } - /// Like `iter_crate_data`, but passes source paths (if available) as well. - pub fn iter_crate_data_origins(&self, mut i: I) - where I: FnMut(CrateNum, &CrateMetadata, Option) - { - for (&k, v) in self.metas.borrow().iter() { - let origin = self.opt_used_crate_source(k); - origin.as_ref().map(|cs| { - assert!(k == cs.cnum); - }); - i(k, &v, origin); - } - } - - pub fn add_used_crate_source(&self, src: CrateSource) { - let mut used_crate_sources = self.used_crate_sources.borrow_mut(); - if !used_crate_sources.contains(&src) { - used_crate_sources.push(src); - } - } - - pub fn opt_used_crate_source(&self, cnum: CrateNum) -> Option { - self.used_crate_sources - .borrow_mut() - .iter() - .find(|source| source.cnum == cnum) - .cloned() - } - pub fn reset(&self) { self.metas.borrow_mut().clear(); self.extern_mod_crate_map.borrow_mut().clear(); - self.used_crate_sources.borrow_mut().clear(); self.used_libraries.borrow_mut().clear(); self.used_link_args.borrow_mut().clear(); self.statically_included_foreign_items.borrow_mut().clear(); @@ -223,15 +192,16 @@ impl CStore { } info!("topological ordering: {:?}", ordering); ordering.reverse(); - let mut libs = self.used_crate_sources + let mut libs = self.metas .borrow() .iter() - .map(|src| { - (src.cnum, - match prefer { - LinkagePreference::RequireDynamic => src.dylib.clone().map(|p| p.0), - LinkagePreference::RequireStatic => src.rlib.clone().map(|p| p.0), - }) + .filter_map(|(&cnum, data)| { + if data.dep_kind.get() == DepKind::MacrosOnly { return None; } + let path = match prefer { + LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0), + LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0), + }; + Some((cnum, path)) }) .collect::>(); libs.sort_by(|&(a, _), &(b, _)| { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index a618c98ff774..83de8acdb605 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -13,10 +13,11 @@ use encoder; use locator; use schema; -use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, ExternCrate}; -use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; +use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate}; +use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference, LoadedMacro}; use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; +use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; @@ -30,7 +31,8 @@ use rustc_back::PanicStrategy; use std::path::PathBuf; use syntax::ast; use syntax::attr; -use syntax::parse::token; +use syntax::parse::{token, new_parser_from_source_str}; +use syntax_pos::mk_sp; use rustc::hir::svh::Svh; use rustc_back::target::Target; use rustc::hir; @@ -144,7 +146,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn impl_or_trait_items(&self, def_id: DefId) -> Vec { + fn associated_item_def_ids(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; self.get_crate_data(def_id.krate) @@ -182,11 +184,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index) } - fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option> + fn associated_item<'a>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> Option { self.dep_graph.read(DepNode::MetaData(def)); - self.get_crate_data(def.krate).get_impl_or_trait_item(def.index, tcx) + self.get_crate_data(def.krate).get_associated_item(def.index) } fn is_const_fn(&self, did: DefId) -> bool @@ -221,6 +223,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(cnum).get_dylib_dependency_formats() } + fn dep_kind(&self, cnum: CrateNum) -> DepKind + { + self.get_crate_data(cnum).dep_kind.get() + } + fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)> { self.get_crate_data(cnum).get_lang_items() @@ -237,11 +244,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(cnum).is_staged_api() } - fn is_explicitly_linked(&self, cnum: CrateNum) -> bool - { - self.get_crate_data(cnum).explicitly_linked.get() - } - fn is_allocator(&self, cnum: CrateNum) -> bool { self.get_crate_data(cnum).is_allocator() @@ -351,6 +353,48 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } + fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro { + let data = self.get_crate_data(id.krate); + if let Some(ref proc_macros) = data.proc_macros { + return LoadedMacro::ProcMacro(proc_macros[id.index.as_usize()].1.clone()); + } + + let (name, def) = data.get_macro(id.index); + let source_name = format!("<{} macros>", name); + + // NB: Don't use parse_tts_from_source_str because it parses with quote_depth > 0. + let mut parser = new_parser_from_source_str(&sess.parse_sess, source_name, def.body); + + let lo = parser.span.lo; + let body = match parser.parse_all_token_trees() { + Ok(body) => body, + Err(mut err) => { + err.emit(); + sess.abort_if_errors(); + unreachable!(); + } + }; + let local_span = mk_sp(lo, parser.prev_span.hi); + + // Mark the attrs as used + for attr in &def.attrs { + attr::mark_used(attr); + } + + sess.imported_macro_spans.borrow_mut() + .insert(local_span, (def.name.as_str().to_string(), def.span)); + + LoadedMacro::MacroRules(ast::MacroDef { + ident: ast::Ident::with_empty_ctxt(def.name), + id: ast::DUMMY_NODE_ID, + span: local_span, + imported_from: None, // FIXME + allow_internal_unstable: attr::contains_name(&def.attrs, "allow_internal_unstable"), + attrs: def.attrs, + body: body, + }) + } + fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) @@ -427,9 +471,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { // the logic to do that already exists in `middle`. In order to // reuse that code, it needs to be able to look up the traits for // inlined items. - let ty_trait_item = tcx.impl_or_trait_item(def_id).clone(); + let ty_trait_item = tcx.associated_item(def_id).clone(); let trait_item_def_id = tcx.map.local_def_id(trait_item.id); - tcx.impl_or_trait_items.borrow_mut() + tcx.associated_items.borrow_mut() .insert(trait_item_def_id, ty_trait_item); } Some(&InlinedItem::ImplItem(_, ref impl_item)) => { @@ -507,7 +551,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { - self.opt_used_crate_source(cnum).unwrap() + self.get_crate_data(cnum).source.clone() } fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ccd497860de8..78cde4c2fcb7 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -17,11 +17,11 @@ use schema::*; use rustc::hir::map as hir_map; use rustc::hir::map::{DefKey, DefPathData}; -use rustc::util::nodemap::FnvHashMap; +use rustc::util::nodemap::FxHashMap; use rustc::hir; use rustc::hir::intravisit::IdRange; -use rustc::middle::cstore::{InlinedItem, LinkagePreference}; +use rustc::middle::cstore::{DepKind, InlinedItem, LinkagePreference}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc::middle::lang_items; @@ -36,7 +36,6 @@ use std::borrow::Cow; use std::cell::Ref; use std::io; use std::mem; -use std::rc::Rc; use std::str; use std::u32; @@ -432,7 +431,7 @@ impl<'a, 'tcx> MetadataBlob { /// Go through each item in the metadata and create a map from that /// item's def-key to the item's DefIndex. - pub fn load_key_map(&self, index: LazySeq) -> FnvHashMap { + pub fn load_key_map(&self, index: LazySeq) -> FxHashMap { index.iter_enumerated(self.raw_bytes()) .map(|(index, item)| (item.decode(self).def_key.decode(self), index)) .collect() @@ -469,6 +468,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Variant(_) => Def::Variant(did), EntryKind::Trait(_) => Def::Trait(did), EntryKind::Enum => Def::Enum(did), + EntryKind::MacroDef(_) => Def::Macro(did), EntryKind::ForeignMod | EntryKind::Impl(_) | @@ -691,6 +691,16 @@ impl<'a, 'tcx> CrateMetadata { pub fn each_child_of_item(&self, id: DefIndex, mut callback: F) where F: FnMut(def::Export) { + if let Some(ref proc_macros) = self.proc_macros { + for (id, &(name, _)) in proc_macros.iter().enumerate() { + callback(def::Export { + name: name, + def: Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id), }), + }) + } + return + } + // Find the item. let item = match self.maybe_entry(id) { None => return, @@ -698,10 +708,21 @@ impl<'a, 'tcx> CrateMetadata { }; // Iterate over all children. + let macros_only = self.dep_kind.get() == DepKind::MacrosOnly; for child_index in item.children.decode(self) { + if macros_only { + continue + } + // Get the item. if let Some(child) = self.maybe_entry(child_index) { let child = child.decode(self); + match child.kind { + EntryKind::MacroDef(..) => {} + _ if macros_only => continue, + _ => {} + } + // Hand off the item to the callback. match child.kind { // FIXME(eddyb) Don't encode these in children. @@ -760,6 +781,11 @@ impl<'a, 'tcx> CrateMetadata { if let EntryKind::Mod(data) = item.kind { for exp in data.decode(self).reexports.decode(self) { + match exp.def { + Def::Macro(..) => {} + _ if macros_only => continue, + _ => {} + } callback(exp); } } @@ -792,10 +818,7 @@ impl<'a, 'tcx> CrateMetadata { self.entry(id).mir.map(|mir| mir.decode((self, tcx))) } - pub fn get_impl_or_trait_item(&self, - id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Option> { + pub fn get_associated_item(&self, id: DefIndex) -> Option { let item = self.entry(id); let parent_and_name = || { let def_key = item.def_key.decode(self); @@ -806,52 +829,43 @@ impl<'a, 'tcx> CrateMetadata { Some(match item.kind { EntryKind::AssociatedConst(container) => { let (parent, name) = parent_and_name(); - ty::ConstTraitItem(Rc::new(ty::AssociatedConst { + ty::AssociatedItem { name: name, - ty: item.ty.unwrap().decode((self, tcx)), + kind: ty::AssociatedKind::Const, vis: item.visibility, defaultness: container.defaultness(), + has_value: container.has_value(), def_id: self.local_def_id(id), container: container.with_def_id(parent), - has_value: container.has_body(), - })) + method_has_self_argument: false + } } EntryKind::Method(data) => { let (parent, name) = parent_and_name(); - let ity = item.ty.unwrap().decode((self, tcx)); - let fty = match ity.sty { - ty::TyFnDef(.., fty) => fty, - _ => { - bug!("the type {:?} of the method {:?} is not a function?", - ity, - name) - } - }; - let data = data.decode(self); - ty::MethodTraitItem(Rc::new(ty::Method { + ty::AssociatedItem { name: name, - generics: tcx.lookup_generics(self.local_def_id(id)), - predicates: item.predicates.unwrap().decode((self, tcx)), - fty: fty, - explicit_self: data.explicit_self.decode((self, tcx)), + kind: ty::AssociatedKind::Method, vis: item.visibility, defaultness: data.container.defaultness(), - has_body: data.container.has_body(), + has_value: data.container.has_value(), def_id: self.local_def_id(id), container: data.container.with_def_id(parent), - })) + method_has_self_argument: data.has_self + } } EntryKind::AssociatedType(container) => { let (parent, name) = parent_and_name(); - ty::TypeTraitItem(Rc::new(ty::AssociatedType { + ty::AssociatedItem { name: name, - ty: item.ty.map(|ty| ty.decode((self, tcx))), + kind: ty::AssociatedKind::Type, vis: item.visibility, defaultness: container.defaultness(), + has_value: container.has_value(), def_id: self.local_def_id(id), container: container.with_def_id(parent), - })) + method_has_self_argument: false + } } _ => return None, }) @@ -1000,6 +1014,14 @@ impl<'a, 'tcx> CrateMetadata { self.root.reachable_ids.decode(self).map(|index| self.local_def_id(index)).collect() } + pub fn get_macro(&self, id: DefIndex) -> (ast::Name, MacroDef) { + let entry = self.entry(id); + match entry.kind { + EntryKind::MacroDef(macro_def) => (self.item_name(&entry), macro_def.decode(self)), + _ => bug!(), + } + } + pub fn is_const_fn(&self, id: DefIndex) -> bool { let constness = match self.entry(id).kind { EntryKind::Method(data) => data.decode(self).fn_data.constness, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index e8734e427571..ac1f2afcb2ad 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -23,7 +23,7 @@ use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; use rustc::session::config::{self, CrateTypeProcMacro}; -use rustc::util::nodemap::{FnvHashMap, NodeSet}; +use rustc::util::nodemap::{FxHashMap, NodeSet}; use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; use std::hash::Hash; @@ -52,8 +52,8 @@ pub struct EncodeContext<'a, 'tcx: 'a> { reachable: &'a NodeSet, lazy_state: LazyState, - type_shorthands: FnvHashMap, usize>, - predicate_shorthands: FnvHashMap, usize>, + type_shorthands: FxHashMap, usize>, + predicate_shorthands: FxHashMap, usize>, } macro_rules! encoder_methods { @@ -200,7 +200,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { variant: &U, map: M) -> Result<(), ::Error> - where M: for<'b> Fn(&'b mut Self) -> &'b mut FnvHashMap, + where M: for<'b> Fn(&'b mut Self) -> &'b mut FxHashMap, T: Clone + Eq + Hash, U: Encodable { @@ -457,19 +457,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let node_id = tcx.map.as_local_node_id(def_id).unwrap(); let ast_item = tcx.map.expect_trait_item(node_id); - let trait_item = tcx.impl_or_trait_item(def_id); + let trait_item = tcx.associated_item(def_id); - let container = |has_body| if has_body { + let container = if trait_item.has_value { AssociatedContainer::TraitWithDefault } else { AssociatedContainer::TraitRequired }; - let kind = match trait_item { - ty::ConstTraitItem(ref associated_const) => { - EntryKind::AssociatedConst(container(associated_const.has_value)) - } - ty::MethodTraitItem(ref method_ty) => { + let kind = match trait_item.kind { + ty::AssociatedKind::Const => EntryKind::AssociatedConst(container), + ty::AssociatedKind::Method => { let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node { FnData { constness: hir::Constness::NotConst, @@ -478,30 +476,35 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { bug!() }; - let data = MethodData { + EntryKind::Method(self.lazy(&MethodData { fn_data: fn_data, - container: container(method_ty.has_body), - explicit_self: self.lazy(&method_ty.explicit_self), - }; - EntryKind::Method(self.lazy(&data)) + container: container, + has_self: trait_item.method_has_self_argument, + })) } - ty::TypeTraitItem(_) => EntryKind::AssociatedType(container(false)), + ty::AssociatedKind::Type => EntryKind::AssociatedType(container), }; Entry { kind: kind, - visibility: trait_item.vis().simplify(), + visibility: trait_item.vis.simplify(), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&ast_item.attrs), children: LazySeq::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), - ty: match trait_item { - ty::ConstTraitItem(_) | - ty::MethodTraitItem(_) => Some(self.encode_item_type(def_id)), - ty::TypeTraitItem(ref associated_type) => { - associated_type.ty.map(|ty| self.lazy(&ty)) + ty: match trait_item.kind { + ty::AssociatedKind::Const | + ty::AssociatedKind::Method => { + Some(self.encode_item_type(def_id)) + } + ty::AssociatedKind::Type => { + if trait_item.has_value { + Some(self.encode_item_type(def_id)) + } else { + None + } } }, inherent_impls: LazySeq::empty(), @@ -509,8 +512,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: if let ty::ConstTraitItem(_) = trait_item { - let trait_def_id = trait_item.container().id(); + ast: if trait_item.kind == ty::AssociatedKind::Const { + let trait_def_id = trait_item.container.id(); Some(self.encode_inlined_item(InlinedItemRef::TraitItem(trait_def_id, ast_item))) } else { None @@ -522,17 +525,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { let node_id = self.tcx.map.as_local_node_id(def_id).unwrap(); let ast_item = self.tcx.map.expect_impl_item(node_id); - let impl_item = self.tcx.impl_or_trait_item(def_id); - let impl_def_id = impl_item.container().id(); + let impl_item = self.tcx.associated_item(def_id); + let impl_def_id = impl_item.container.id(); - let container = match ast_item.defaultness { + let container = match impl_item.defaultness { hir::Defaultness::Default => AssociatedContainer::ImplDefault, hir::Defaultness::Final => AssociatedContainer::ImplFinal, }; - let kind = match impl_item { - ty::ConstTraitItem(_) => EntryKind::AssociatedConst(container), - ty::MethodTraitItem(ref method_ty) => { + let kind = match impl_item.kind { + ty::AssociatedKind::Const => EntryKind::AssociatedConst(container), + ty::AssociatedKind::Method => { let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { FnData { constness: sig.constness, @@ -541,17 +544,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { bug!() }; - let data = MethodData { + EntryKind::Method(self.lazy(&MethodData { fn_data: fn_data, container: container, - explicit_self: self.lazy(&method_ty.explicit_self), - }; - EntryKind::Method(self.lazy(&data)) + has_self: impl_item.method_has_self_argument, + })) } - ty::TypeTraitItem(_) => EntryKind::AssociatedType(container), + ty::AssociatedKind::Type => EntryKind::AssociatedType(container) }; - let (ast, mir) = if let ty::ConstTraitItem(_) = impl_item { + let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const { (true, true) } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { let generics = self.tcx.lookup_generics(def_id); @@ -565,20 +567,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: kind, - visibility: impl_item.vis().simplify(), + visibility: impl_item.vis.simplify(), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&ast_item.attrs), children: LazySeq::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), - ty: match impl_item { - ty::ConstTraitItem(_) | - ty::MethodTraitItem(_) => Some(self.encode_item_type(def_id)), - ty::TypeTraitItem(ref associated_type) => { - associated_type.ty.map(|ty| self.lazy(&ty)) - } - }, + ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), variances: LazySeq::empty(), generics: Some(self.encode_generics(def_id)), @@ -758,7 +754,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemImpl(..) | hir::ItemTrait(..) => { - self.lazy_seq(tcx.impl_or_trait_items(def_id).iter().map(|&def_id| { + self.lazy_seq(tcx.associated_item_def_ids(def_id).iter().map(|&def_id| { assert!(def_id.is_local()); def_id.index })) @@ -834,6 +830,34 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }, } } + + /// Serialize the text of exported macros + fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx> { + let def_id = self.tcx.map.local_def_id(macro_def.id); + let macro_def = MacroDef { + name: macro_def.name, + attrs: macro_def.attrs.to_vec(), + span: macro_def.span, + body: ::syntax::print::pprust::tts_to_string(¯o_def.body) + }; + Entry { + kind: EntryKind::MacroDef(self.lazy(¯o_def)), + visibility: ty::Visibility::Public, + def_key: self.encode_def_key(def_id), + + attributes: LazySeq::empty(), + children: LazySeq::empty(), + stability: None, + deprecation: None, + ty: None, + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: None, + predicates: None, + ast: None, + mir: None, + } + } } impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { @@ -880,14 +904,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { self.encode_fields(def_id); } hir::ItemImpl(..) => { - for &trait_item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] { + for &trait_item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { self.record(trait_item_def_id, EncodeContext::encode_info_for_impl_item, trait_item_def_id); } } hir::ItemTrait(..) => { - for &item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] { + for &item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { self.record(item_def_id, EncodeContext::encode_info_for_trait_item, item_def_id); @@ -968,6 +992,10 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { intravisit::walk_ty(self, ty); self.index.encode_info_for_ty(ty); } + fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef) { + let def_id = self.index.tcx.map.local_def_id(macro_def.id); + self.index.record(def_id, EncodeContext::encode_info_for_macro_def, macro_def); + } } impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { @@ -1016,7 +1044,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = ClosureData { kind: tcx.closure_kind(def_id), - ty: self.lazy(&tcx.tables.borrow().closure_tys[&def_id]), + ty: self.lazy(&tcx.tables().closure_tys[&def_id]), }; Entry { @@ -1047,6 +1075,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); let mut visitor = EncodeVisitor { index: index }; krate.visit_all_items(&mut visitor); + for macro_def in &krate.exported_macros { + visitor.visit_macro_def(macro_def); + } visitor.index.into_items() } @@ -1084,7 +1115,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { CrateDep { name: syntax::parse::token::intern(dep.name()), hash: dep.hash(), - explicitly_linked: dep.explicitly_linked.get(), + kind: dep.dep_kind.get(), } })) } @@ -1126,24 +1157,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }) .map(|filemap| &**filemap)) } - - /// Serialize the text of the exported macros - fn encode_macro_defs(&mut self) -> LazySeq { - let tcx = self.tcx; - self.lazy_seq(tcx.map.krate().exported_macros.iter().map(|def| { - MacroDef { - name: def.name, - attrs: def.attrs.to_vec(), - span: def.span, - body: ::syntax::print::pprust::tts_to_string(&def.body), - } - })) - } } struct ImplVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - impls: FnvHashMap>, + impls: FxHashMap>, } impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { @@ -1165,7 +1183,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_impls(&mut self) -> LazySeq { let mut visitor = ImplVisitor { tcx: self.tcx, - impls: FnvHashMap(), + impls: FxHashMap(), }; self.tcx.map.krate().visit_all_items(&mut visitor); @@ -1232,11 +1250,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let codemap = self.encode_codemap(); let codemap_bytes = self.position() - i; - // Encode macro definitions - i = self.position(); - let macro_defs = self.encode_macro_defs(); - let macro_defs_bytes = self.position() - i; - // Encode the def IDs of impls, for coherence checking. i = self.position(); let impls = self.encode_impls(); @@ -1283,7 +1296,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { lang_items_missing: lang_items_missing, native_libraries: native_libraries, codemap: codemap, - macro_defs: macro_defs, impls: impls, reachable_ids: reachable_ids, index: index, @@ -1304,7 +1316,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { println!(" lang item bytes: {}", lang_item_bytes); println!(" native bytes: {}", native_lib_bytes); println!(" codemap bytes: {}", codemap_bytes); - println!(" macro def bytes: {}", macro_defs_bytes); println!(" impl bytes: {}", impl_bytes); println!(" reachable bytes: {}", reachable_bytes); println!(" item bytes: {}", item_bytes); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 9938e20d1861..1a74a9254547 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -195,6 +195,7 @@ read_hir!(hir::Item); read_hir!(hir::ImplItem); read_hir!(hir::TraitItem); read_hir!(hir::ForeignItem); +read_hir!(hir::MacroDef); /// Leaks access to a value of type T without any tracking. This is /// suitable for ambiguous types like `usize`, which *could* represent diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index ef81dbd7f29e..2fd40181d7c7 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -20,7 +20,7 @@ #![feature(box_patterns)] #![feature(conservative_impl_trait)] #![feature(core_intrinsics)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(proc_macro_internals)] #![feature(proc_macro_lib)] #![cfg_attr(stage0, feature(question_mark))] diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 0461d7ec061d..b6b347fff5f2 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -221,7 +221,7 @@ use rustc::session::Session; use rustc::session::filesearch::{FileSearch, FileMatches, FileDoesntMatch}; use rustc::session::search_paths::PathKind; use rustc::util::common; -use rustc::util::nodemap::FnvHashMap; +use rustc::util::nodemap::FxHashMap; use rustc_llvm as llvm; use rustc_llvm::{False, ObjectFile, mk_section_iter}; @@ -262,6 +262,7 @@ pub struct Context<'a> { pub rejected_via_kind: Vec, pub rejected_via_version: Vec, pub should_match_name: bool, + pub is_proc_macro: Option, } pub struct ArchiveMetadata { @@ -430,7 +431,7 @@ impl<'a> Context<'a> { let rlib_prefix = format!("lib{}", self.crate_name); let staticlib_prefix = format!("{}{}", staticpair.0, self.crate_name); - let mut candidates = FnvHashMap(); + let mut candidates = FxHashMap(); let mut staticlibs = vec![]; // First, find all possible candidate rlibs and dylibs purely based on @@ -469,7 +470,7 @@ impl<'a> Context<'a> { let hash_str = hash.to_string(); let slot = candidates.entry(hash_str) - .or_insert_with(|| (FnvHashMap(), FnvHashMap())); + .or_insert_with(|| (FxHashMap(), FxHashMap())); let (ref mut rlibs, ref mut dylibs) = *slot; fs::canonicalize(path) .map(|p| { @@ -492,7 +493,7 @@ impl<'a> Context<'a> { // A Library candidate is created if the metadata for the set of // libraries corresponds to the crate id and hash criteria that this // search is being performed for. - let mut libraries = FnvHashMap(); + let mut libraries = FxHashMap(); for (_hash, (rlibs, dylibs)) in candidates { let mut slot = None; let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot); @@ -544,7 +545,7 @@ impl<'a> Context<'a> { // be read, it is assumed that the file isn't a valid rust library (no // errors are emitted). fn extract_one(&mut self, - m: FnvHashMap, + m: FxHashMap, flavor: CrateFlavor, slot: &mut Option<(Svh, MetadataBlob)>) -> Option<(PathBuf, PathKind)> { @@ -623,6 +624,12 @@ impl<'a> Context<'a> { fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option { let root = metadata.get_root(); + if let Some(is_proc_macro) = self.is_proc_macro { + if root.macro_derive_registrar.is_some() != is_proc_macro { + return None; + } + } + let rustc_version = rustc_version(); if root.rustc_version != rustc_version { info!("Rejecting via version: expected {} got {}", @@ -690,8 +697,8 @@ impl<'a> Context<'a> { // rlibs/dylibs. let sess = self.sess; let dylibname = self.dylibname(); - let mut rlibs = FnvHashMap(); - let mut dylibs = FnvHashMap(); + let mut rlibs = FxHashMap(); + let mut dylibs = FxHashMap(); { let locs = locs.map(|l| PathBuf::from(l)).filter(|loc| { if !loc.exists() { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 3d1bd77d8bc2..d7a5f7ad7154 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -14,7 +14,7 @@ use index; use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId}; -use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind}; +use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibraryKind}; use rustc::middle::lang_items; use rustc::mir; use rustc::ty::{self, Ty}; @@ -177,7 +177,6 @@ pub struct CrateRoot { pub lang_items_missing: LazySeq, pub native_libraries: LazySeq<(NativeLibraryKind, String)>, pub codemap: LazySeq, - pub macro_defs: LazySeq, pub impls: LazySeq, pub reachable_ids: LazySeq, pub index: LazySeq, @@ -187,7 +186,7 @@ pub struct CrateRoot { pub struct CrateDep { pub name: ast::Name, pub hash: hir::svh::Svh, - pub explicitly_linked: bool, + pub kind: DepKind, } #[derive(RustcEncodable, RustcDecodable)] @@ -241,11 +240,12 @@ pub enum EntryKind<'tcx> { Fn(Lazy), ForeignFn(Lazy), Mod(Lazy), + MacroDef(Lazy), Closure(Lazy>), Trait(Lazy>), Impl(Lazy>), DefaultImpl(Lazy>), - Method(Lazy>), + Method(Lazy), AssociatedType(AssociatedContainer), AssociatedConst(AssociatedContainer), } @@ -300,7 +300,7 @@ pub enum AssociatedContainer { } impl AssociatedContainer { - pub fn with_def_id(&self, def_id: DefId) -> ty::ImplOrTraitItemContainer { + pub fn with_def_id(&self, def_id: DefId) -> ty::AssociatedItemContainer { match *self { AssociatedContainer::TraitRequired | AssociatedContainer::TraitWithDefault => ty::TraitContainer(def_id), @@ -310,7 +310,7 @@ impl AssociatedContainer { } } - pub fn has_body(&self) -> bool { + pub fn has_value(&self) -> bool { match *self { AssociatedContainer::TraitRequired => false, @@ -332,10 +332,10 @@ impl AssociatedContainer { } #[derive(RustcEncodable, RustcDecodable)] -pub struct MethodData<'tcx> { +pub struct MethodData { pub fn_data: FnData, pub container: AssociatedContainer, - pub explicit_self: Lazy>, + pub has_self: bool, } #[derive(RustcEncodable, RustcDecodable)] diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 490f675c3d5e..b75e52fd4b10 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -13,7 +13,7 @@ use std; use rustc_const_math::{ConstMathErr, Op}; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use build::{BlockAnd, BlockAndExtension, Builder}; @@ -190,7 +190,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // first process the set of fields that were provided // (evaluating them in order given by user) - let fields_map: FnvHashMap<_, _> = + let fields_map: FxHashMap<_, _> = fields.into_iter() .map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr)))) .collect(); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 727e634ef92d..786299c370d8 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -14,7 +14,7 @@ //! details. use build::{BlockAnd, BlockAndExtension, Builder}; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::bitvec::BitVector; use rustc::middle::const_val::ConstVal; use rustc::ty::{AdtDef, Ty}; @@ -309,7 +309,7 @@ enum TestKind<'tcx> { SwitchInt { switch_ty: Ty<'tcx>, options: Vec, - indices: FnvHashMap, + indices: FxHashMap, }, // test for equality diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 5984b0f7893c..948ba7338cdd 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -18,7 +18,7 @@ use build::Builder; use build::matches::{Candidate, MatchPair, Test, TestKind}; use hair::*; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::bitvec::BitVector; use rustc::middle::const_val::ConstVal; use rustc::ty::{self, Ty}; @@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // these maps are empty to start; cases are // added below in add_cases_to_switch options: vec![], - indices: FnvHashMap(), + indices: FxHashMap(), } } } @@ -110,7 +110,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, options: &mut Vec, - indices: &mut FnvHashMap) + indices: &mut FxHashMap) -> bool { let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index d6fcc79a9a21..902798ec9800 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -156,7 +156,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, fn_id: ast::NodeId, arguments: A, return_ty: Ty<'gcx>, - ast_block: &'gcx hir::Block) + ast_body: &'gcx hir::Expr) -> (Mir<'tcx>, ScopeAuxiliaryVec) where A: Iterator, Option<&'gcx hir::Pat>)> { @@ -166,7 +166,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let span = tcx.map.span(fn_id); let mut builder = Builder::new(hir, span, arguments.len(), return_ty); - let body_id = ast_block.id; + let body_id = ast_body.id; let call_site_extent = tcx.region_maps.lookup_code_extent( CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id }); @@ -176,7 +176,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let mut block = START_BLOCK; unpack!(block = builder.in_scope(call_site_extent, block, |builder| { unpack!(block = builder.in_scope(arg_extent, block, |builder| { - builder.args_and_body(block, return_ty, &arguments, arg_extent, ast_block) + builder.args_and_body(block, &arguments, arg_extent, ast_body) })); // Attribute epilogue to function's closing brace let fn_end = Span { lo: span.hi, ..span }; @@ -191,7 +191,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, assert_eq!(block, builder.return_block()); let mut spread_arg = None; - match tcx.node_id_to_type(fn_id).sty { + match tcx.tables().node_id_to_type(fn_id).sty { ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => { // RustCall pseudo-ABI untuples the last argument. spread_arg = Some(Local::new(arguments.len())); @@ -203,7 +203,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| { freevars.iter().map(|fv| { let var_id = tcx.map.as_local_node_id(fv.def.def_id()).unwrap(); - let by_ref = tcx.upvar_capture(ty::UpvarId { + let by_ref = tcx.tables().upvar_capture(ty::UpvarId { var_id: var_id, closure_expr_id: fn_id }).map_or(false, |capture| match capture { @@ -233,7 +233,7 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, ast_expr: &'tcx hir::Expr) -> (Mir<'tcx>, ScopeAuxiliaryVec) { let tcx = hir.tcx(); - let ty = tcx.expr_ty_adjusted(ast_expr); + let ty = tcx.tables().expr_ty_adjusted(ast_expr); let span = tcx.map.span(item_id); let mut builder = Builder::new(hir, span, 0, ty); @@ -310,10 +310,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn args_and_body(&mut self, mut block: BasicBlock, - return_ty: Ty<'tcx>, arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)], argument_extent: CodeExtent, - ast_block: &'gcx hir::Block) + ast_body: &'gcx hir::Expr) -> BlockAnd<()> { // Allocate locals for the function arguments @@ -342,12 +341,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(pattern) = pattern { let pattern = Pattern::from_hir(self.hir.tcx(), pattern); - scope = self.declare_bindings(scope, ast_block.span, &pattern); + scope = self.declare_bindings(scope, ast_body.span, &pattern); unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue)); } // Make sure we drop (parts of) the argument even when not matched on. - self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span), + self.schedule_drop(pattern.as_ref().map_or(ast_body.span, |pat| pat.span), argument_extent, &lvalue, ty); } @@ -357,13 +356,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.visibility_scope = visibility_scope; } - // FIXME(#32959): temporary hack for the issue at hand - let return_is_unit = return_ty.is_nil(); - // start the first basic block and translate the body - unpack!(block = self.ast_block(&Lvalue::Local(RETURN_POINTER), - return_is_unit, block, ast_block)); - - block.unit() + let body = self.hir.mirror(ast_body); + self.into(&Lvalue::Local(RETURN_POINTER), block, body) } fn get_unit_temp(&mut self) -> Lvalue<'tcx> { diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index af8170a1b8f5..b5343975a9cd 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -94,7 +94,7 @@ use rustc::ty::{Ty, TyCtxt}; use rustc::mir::*; use syntax_pos::Span; use rustc_data_structures::indexed_vec::Idx; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; pub struct Scope<'tcx> { /// the scope-id within the scope_auxiliary @@ -140,7 +140,7 @@ pub struct Scope<'tcx> { free: Option>, /// The cache for drop chain on “normal” exit into a particular BasicBlock. - cached_exits: FnvHashMap<(BasicBlock, CodeExtent), BasicBlock>, + cached_exits: FxHashMap<(BasicBlock, CodeExtent), BasicBlock>, } struct DropData<'tcx> { @@ -298,7 +298,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { needs_cleanup: false, drops: vec![], free: None, - cached_exits: FnvHashMap() + cached_exits: FxHashMap() }); self.scope_auxiliary.push(ScopeAuxiliary { extent: extent, diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index ec1136368c13..cb69de2cb3ca 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -77,7 +77,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, block: &'tcx hir::Block) -> ExprRef<'tcx> { - let block_ty = cx.tcx.node_id_to_type(block.id); + let block_ty = cx.tcx.tables().node_id_to_type(block.id); let temp_lifetime = cx.tcx.region_maps.temporary_scope(block.id); let expr = Expr { ty: block_ty, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 1b324ac3132f..ba0d3b49a6c1 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -35,15 +35,15 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); let mut expr = make_mirror_unadjusted(cx, self); + let adj = cx.tcx.tables().adjustments.get(&self.id).cloned(); debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}", - expr, cx.tcx.tables.borrow().adjustments.get(&self.id)); + expr, adj); // Now apply adjustments, if any. - match cx.tcx.tables.borrow().adjustments.get(&self.id) { + match adj.map(|adj| (adj.kind, adj.target)) { None => {} - Some(&ty::adjustment::AdjustReifyFnPointer) => { - let adjusted_ty = cx.tcx.expr_ty_adjusted(self); + Some((ty::adjustment::Adjust::ReifyFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -51,8 +51,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::ReifyFnPointer { source: expr.to_ref() }, }; } - Some(&ty::adjustment::AdjustUnsafeFnPointer) => { - let adjusted_ty = cx.tcx.expr_ty_adjusted(self); + Some((ty::adjustment::Adjust::UnsafeFnPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -60,7 +59,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() }, }; } - Some(&ty::adjustment::AdjustNeverToAny(adjusted_ty)) => { + Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -68,8 +67,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::NeverToAny { source: expr.to_ref() }, }; } - Some(&ty::adjustment::AdjustMutToConstPointer) => { - let adjusted_ty = cx.tcx.expr_ty_adjusted(self); + Some((ty::adjustment::Adjust::MutToConstPointer, adjusted_ty)) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -77,8 +75,9 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { kind: ExprKind::Cast { source: expr.to_ref() }, }; } - Some(&ty::adjustment::AdjustDerefRef(ref adj)) => { - for i in 0..adj.autoderefs { + Some((ty::adjustment::Adjust::DerefRef { autoderefs, autoref, unsize }, + adjusted_ty)) => { + for i in 0..autoderefs { let i = i as u32; let adjusted_ty = expr.ty.adjust_for_autoderef( @@ -86,11 +85,11 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { self.id, self.span, i, - |mc| cx.tcx.tables.borrow().method_map.get(&mc).map(|m| m.ty)); + |mc| cx.tcx.tables().method_map.get(&mc).map(|m| m.ty)); debug!("make_mirror: autoderef #{}, adjusted_ty={:?}", i, adjusted_ty); let method_key = ty::MethodCall::autoderef(self.id, i); let meth_ty = - cx.tcx.tables.borrow().method_map.get(&method_key).map(|m| m.ty); + cx.tcx.tables().method_map.get(&method_key).map(|m| m.ty); let kind = if let Some(meth_ty) = meth_ty { debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty); @@ -128,10 +127,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { }; } - if let Some(autoref) = adj.autoref { + if let Some(autoref) = autoref { let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref)); match autoref { - ty::adjustment::AutoPtr(r, m) => { + ty::adjustment::AutoBorrow::Ref(r, m) => { expr = Expr { temp_lifetime: temp_lifetime, ty: adjusted_ty, @@ -143,7 +142,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { }, }; } - ty::adjustment::AutoUnsafe(m) => { + ty::adjustment::AutoBorrow::RawPtr(m) => { // Convert this to a suitable `&foo` and // then an unsafe coercion. Limit the region to be just this // expression. @@ -169,10 +168,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { } } - if let Some(target) = adj.unsize { + if unsize { expr = Expr { temp_lifetime: temp_lifetime, - ty: target, + ty: adjusted_ty, span: self.span, kind: ExprKind::Unsize { source: expr.to_ref() }, }; @@ -212,7 +211,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr) -> Expr<'tcx> { - let expr_ty = cx.tcx.expr_ty(expr); + let expr_ty = cx.tcx.tables().expr_ty(expr); let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); let kind = match expr.node { @@ -231,7 +230,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprCall(ref fun, ref args) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { // The callee is something implementing Fn, FnMut, or FnOnce. // Find the actual method implementation being called and // build the appropriate UFCS call expression with the @@ -282,7 +281,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }) } else { None }; if let Some((adt_def, index)) = adt_data { - let substs = cx.tcx.node_id_item_substs(fun.id).substs; + let substs = cx.tcx.tables().node_id_item_substs(fun.id) + .unwrap_or_else(|| cx.tcx.intern_substs(&[])); let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef { name: Field::new(idx), expr: e.to_ref() @@ -296,7 +296,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } else { ExprKind::Call { - ty: cx.tcx.node_id_to_type(fun.id), + ty: cx.tcx.tables().node_id_to_type(fun.id), fun: fun.to_ref(), args: args.to_ref(), } @@ -328,7 +328,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprAssignOp(op, ref lhs, ref rhs) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { @@ -350,7 +350,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }, hir::ExprBinary(op, ref lhs, ref rhs) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { let pass_args = if op.node.is_by_value() { PassArgs::ByValue } else { @@ -406,7 +406,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprIndex(ref lhs, ref index) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, lhs.to_ref(), vec![index]) } else { @@ -418,7 +418,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { overloaded_lvalue(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, arg.to_ref(), vec![]) } else { @@ -427,7 +427,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnNot, ref arg) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, arg.to_ref(), vec![]) } else { @@ -439,7 +439,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => { - if cx.tcx.is_method_call(expr.id) { + if cx.tcx.tables().is_method_call(expr.id) { overloaded_operator(cx, expr, ty::MethodCall::expr(expr.id), PassArgs::ByValue, arg.to_ref(), vec![]) } else { @@ -470,10 +470,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, base: base.as_ref().map(|base| { FruInfo { base: base.to_ref(), - field_types: cx.tcx.tables - .borrow() - .fru_field_types[&expr.id] - .clone() + field_types: + cx.tcx.tables().fru_field_types[&expr.id].clone() } }) } @@ -512,7 +510,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprClosure(..) => { - let closure_ty = cx.tcx.expr_ty(expr); + let closure_ty = cx.tcx.tables().expr_ty(expr); let (def_id, substs) = match closure_ty.sty { ty::TyClosure(def_id, substs) => (def_id, substs), _ => { @@ -551,7 +549,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat { value: v.to_ref(), count: TypedConstVal { - ty: cx.tcx.expr_ty(c), + ty: cx.tcx.tables().expr_ty(c), span: c.span, value: match const_eval::eval_const_expr(cx.tcx.global_tcx(), c) { ConstVal::Integral(ConstInt::Usize(u)) => u, @@ -579,7 +577,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ExprKind::Loop { condition: None, body: block::to_expr_ref(cx, body) }, hir::ExprField(ref source, name) => { - let index = match cx.tcx.expr_ty_adjusted(source).sty { + let index = match cx.tcx.tables().expr_ty_adjusted(source).sty { ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node), ref ty => @@ -631,8 +629,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &hir::Expr, method_call: ty::MethodCall) -> Expr<'tcx> { - let tables = cx.tcx.tables.borrow(); - let callee = &tables.method_map[&method_call]; + let callee = cx.tcx.tables().method_map[&method_call]; let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); Expr { temp_lifetime: temp_lifetime, @@ -666,8 +663,8 @@ fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr) -> ExprKind<'tcx> { - let substs = cx.tcx.node_id_item_substs(expr.id).substs; - // Otherwise there may be def_map borrow conflicts + let substs = cx.tcx.tables().node_id_item_substs(expr.id) + .unwrap_or_else(|| cx.tcx.intern_substs(&[])); let def = cx.tcx.expect_def(expr.id); let def_id = match def { // A regular function, constructor function or a constant. @@ -677,18 +674,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::Const(def_id) | Def::AssociatedConst(def_id) => def_id, Def::StructCtor(def_id, CtorKind::Const) | - Def::VariantCtor(def_id, CtorKind::Const) => match cx.tcx.node_id_to_type(expr.id).sty { - // A unit struct/variant which is used as a value. - // We return a completely different ExprKind here to account for this special case. - ty::TyAdt(adt_def, substs) => return ExprKind::Adt { - adt_def: adt_def, - variant_index: adt_def.variant_index_with_id(def_id), - substs: substs, - fields: vec![], - base: None, - }, - ref sty => bug!("unexpected sty: {:?}", sty) - }, + Def::VariantCtor(def_id, CtorKind::Const) => { + match cx.tcx.tables().node_id_to_type(expr.id).sty { + // A unit struct/variant which is used as a value. + // We return a completely different ExprKind here to account for this special case. + ty::TyAdt(adt_def, substs) => return ExprKind::Adt { + adt_def: adt_def, + variant_index: adt_def.variant_index_with_id(def_id), + substs: substs, + fields: vec![], + base: None, + }, + ref sty => bug!("unexpected sty: {:?}", sty) + } + } Def::Static(node_id, _) => return ExprKind::StaticRef { id: node_id, @@ -720,7 +719,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::Upvar(def_id, index, closure_expr_id) => { let id_var = cx.tcx.map.as_local_node_id(def_id).unwrap(); debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id); - let var_ty = cx.tcx.node_id_to_type(id_var); + let var_ty = cx.tcx.tables().node_id_to_type(id_var); let body_id = match cx.tcx.map.find(closure_expr_id) { Some(map::NodeExpr(expr)) => { @@ -737,7 +736,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; // FIXME free regions in closures are not right - let closure_ty = cx.tcx.node_id_to_type(closure_expr_id); + let closure_ty = cx.tcx.tables().node_id_to_type(closure_expr_id); // FIXME we're just hard-coding the idea that the // signature will be &self or &mut self and hence will @@ -809,7 +808,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, var_id: id_var, closure_expr_id: closure_expr_id, }; - let upvar_capture = match cx.tcx.upvar_capture(upvar_id) { + let upvar_capture = match cx.tcx.tables().upvar_capture(upvar_id) { Some(c) => c, None => { span_bug!( @@ -893,7 +892,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, argrefs.extend( args.iter() .map(|arg| { - let arg_ty = cx.tcx.expr_ty_adjusted(arg); + let arg_ty = cx.tcx.tables().expr_ty_adjusted(arg); let adjusted_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: arg_ty, @@ -931,9 +930,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // line up (this is because `*x` and `x[y]` represent lvalues): // to find the type &T of the content returned by the method; - let tables = cx.tcx.tables.borrow(); - let callee = &tables.method_map[&method_call]; - let ref_ty = callee.ty.fn_ret(); + let ref_ty = cx.tcx.tables().method_map[&method_call].ty.fn_ret(); let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap(); // callees always have all late-bound regions fully instantiated, @@ -962,9 +959,9 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, var_id: id_var, closure_expr_id: closure_expr.id, }; - let upvar_capture = cx.tcx.upvar_capture(upvar_id).unwrap(); + let upvar_capture = cx.tcx.tables().upvar_capture(upvar_id).unwrap(); let temp_lifetime = cx.tcx.region_maps.temporary_scope(closure_expr.id); - let var_ty = cx.tcx.node_id_to_type(id_var); + let var_ty = cx.tcx.tables().node_id_to_type(id_var); let captured_var = Expr { temp_lifetime: temp_lifetime, ty: var_ty, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 678db1e544cb..ecc2d8fe050a 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -147,20 +147,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { -> (Ty<'tcx>, Literal<'tcx>) { let method_name = token::intern(method_name); let substs = self.tcx.mk_substs_trait(self_ty, params); - for trait_item in self.tcx.trait_items(trait_def_id).iter() { - match *trait_item { - ty::ImplOrTraitItem::MethodTraitItem(ref method) => { - if method.name == method_name { - let method_ty = self.tcx.lookup_item_type(method.def_id); - let method_ty = method_ty.ty.subst(self.tcx, substs); - return (method_ty, Literal::Item { - def_id: method.def_id, - substs: substs, - }); - } - } - ty::ImplOrTraitItem::ConstTraitItem(..) | - ty::ImplOrTraitItem::TypeTraitItem(..) => {} + for item in self.tcx.associated_items(trait_def_id) { + if item.kind == ty::AssociatedKind::Method && item.name == method_name { + let method_ty = self.tcx.lookup_item_type(item.def_id); + let method_ty = method_ty.ty.subst(self.tcx, substs); + return (method_ty, Literal::Item { + def_id: item.def_id, + substs: substs, + }); } } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 02f15602d708..aa56daf88894 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -22,7 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(associated_consts)] #![feature(box_patterns)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index b0e2d6e73d37..af2f9adfc9a8 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -209,12 +209,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block, + body: &'tcx hir::Expr, span: Span, id: ast::NodeId) { // fetch the fully liberated fn signature (that is, all bound // types/lifetimes replaced) - let fn_sig = match self.tcx.tables.borrow().liberated_fn_sigs.get(&id) { + let fn_sig = match self.tcx.tables().liberated_fn_sigs.get(&id) { Some(f) => f.clone(), None => { span_bug!(span, "no liberated fn sig for {:?}", id); @@ -248,7 +248,7 @@ fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, closure_expr_id: ast::NodeId, body_id: ast::NodeId) -> Ty<'tcx> { - let closure_ty = tcx.node_id_to_type(closure_expr_id); + let closure_ty = tcx.tables().node_id_to_type(closure_expr_id); // We're just hard-coding the idea that the signature will be // &self or &mut self and hence will have a bound region with diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index d2fc8aeaa2ee..d6f514cfb913 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::*; use rustc::mir::transform::MirSource; use rustc::ty::TyCtxt; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::{Idx}; use std::fmt::Display; use std::fs; @@ -122,10 +122,10 @@ enum Annotation { } fn scope_entry_exit_annotations(auxiliary: Option<&ScopeAuxiliaryVec>) - -> FnvHashMap> + -> FxHashMap> { // compute scope/entry exit annotations - let mut annotations = FnvHashMap(); + let mut annotations = FxHashMap(); if let Some(auxiliary) = auxiliary { for (scope_id, auxiliary) in auxiliary.iter_enumerated() { annotations.entry(auxiliary.dom) @@ -166,7 +166,7 @@ fn write_basic_block(tcx: TyCtxt, block: BasicBlock, mir: &Mir, w: &mut Write, - annotations: &FnvHashMap>) + annotations: &FxHashMap>) -> io::Result<()> { let data = &mir[block]; @@ -217,7 +217,7 @@ fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String { /// Returns the total number of variables printed. fn write_scope_tree(tcx: TyCtxt, mir: &Mir, - scope_tree: &FnvHashMap>, + scope_tree: &FxHashMap>, w: &mut Write, parent: VisibilityScope, depth: usize) @@ -283,7 +283,7 @@ fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, writeln!(w, " {{")?; // construct a scope tree and write it out - let mut scope_tree: FnvHashMap> = FnvHashMap(); + let mut scope_tree: FxHashMap> = FxHashMap(); for (index, scope_data) in mir.visibility_scopes.iter().enumerate() { if let Some(parent) = scope_data.parent_scope { scope_tree.entry(parent) diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index a01724d6d0e9..c4a8d34bda00 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -14,7 +14,7 @@ use rustc::mir::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue, Local}; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::ty::TyCtxt; -use rustc::util::nodemap::FnvHashSet; +use rustc::util::nodemap::FxHashSet; use rustc_data_structures::indexed_vec::Idx; use std::mem; @@ -107,5 +107,5 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { #[derive(Default)] struct OptimizationList { - and_stars: FnvHashSet, + and_stars: FxHashSet, } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 7bcb89b5895e..ae255f70fb78 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -9,7 +9,7 @@ // except according to those terms. pub mod simplify_branches; -pub mod simplify_cfg; +pub mod simplify; pub mod erase_regions; pub mod no_landing_pads; pub mod type_check; diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify.rs similarity index 65% rename from src/librustc_mir/transform/simplify_cfg.rs rename to src/librustc_mir/transform/simplify.rs index 1a8a5fa18cf5..d5fc90289e2c 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -8,35 +8,41 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A pass that removes various redundancies in the CFG. It should be -//! called after every significant CFG modification to tidy things -//! up. +//! A number of passes which remove various redundancies in the CFG. //! -//! This pass must also be run before any analysis passes because it removes -//! dead blocks, and some of these can be ill-typed. +//! The `SimplifyCfg` pass gets rid of unnecessary blocks in the CFG, whereas the `SimplifyLocals` +//! gets rid of all the unnecessary local variable declarations. //! -//! The cause of that is that typeck lets most blocks whose end is not -//! reachable have an arbitrary return type, rather than having the -//! usual () return type (as a note, typeck's notion of reachability -//! is in fact slightly weaker than MIR CFG reachability - see #31617). +//! The `SimplifyLocals` pass is kinda expensive and therefore not very suitable to be run often. +//! Most of the passes should not care or be impacted in meaningful ways due to extra locals +//! either, so running the pass once, right before translation, should suffice. +//! +//! On the other side of the spectrum, the `SimplifyCfg` pass is considerably cheap to run, thus +//! one should run it after every pass which may modify CFG in significant ways. This pass must +//! also be run before any analysis passes because it removes dead blocks, and some of these can be +//! ill-typed. +//! +//! The cause of this typing issue is typeck allowing most blocks whose end is not reachable have +//! an arbitrary return type, rather than having the usual () return type (as a note, typeck's +//! notion of reachability is in fact slightly weaker than MIR CFG reachability - see #31617). A +//! standard example of the situation is: //! -//! A standard example of the situation is: //! ```rust //! fn example() { //! let _a: char = { return; }; //! } //! ``` //! -//! Here the block (`{ return; }`) has the return type `char`, -//! rather than `()`, but the MIR we naively generate still contains -//! the `_a = ()` write in the unreachable block "after" the return. - +//! Here the block (`{ return; }`) has the return type `char`, rather than `()`, but the MIR we +//! naively generate still contains the `_a = ()` write in the unreachable block "after" the +//! return. use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::ty::TyCtxt; use rustc::mir::*; use rustc::mir::transform::{MirPass, MirSource, Pass}; +use rustc::mir::visit::{MutVisitor, Visitor, LvalueContext}; use std::fmt; pub struct SimplifyCfg<'a> { label: &'a str } @@ -257,3 +263,87 @@ fn remove_dead_blocks(mir: &mut Mir) { } } } + + +pub struct SimplifyLocals; + +impl Pass for SimplifyLocals { + fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyLocals".into() } +} + +impl<'tcx> MirPass<'tcx> for SimplifyLocals { + fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { + let mut marker = DeclMarker { locals: BitVector::new(mir.local_decls.len()) }; + marker.visit_mir(mir); + // Return pointer and arguments are always live + marker.locals.insert(0); + for idx in mir.args_iter() { + marker.locals.insert(idx.index()); + } + let map = make_local_map(&mut mir.local_decls, marker.locals); + // Update references to all vars and tmps now + LocalUpdater { map: map }.visit_mir(mir); + mir.local_decls.shrink_to_fit(); + } +} + +/// Construct the mapping while swapping out unused stuff out from the `vec`. +fn make_local_map<'tcx, I: Idx, V>(vec: &mut IndexVec, mask: BitVector) -> Vec { + let mut map: Vec = ::std::iter::repeat(!0).take(vec.len()).collect(); + let mut used = 0; + for alive_index in mask.iter() { + map[alive_index] = used; + if alive_index != used { + vec.swap(alive_index, used); + } + used += 1; + } + vec.truncate(used); + map +} + +struct DeclMarker { + pub locals: BitVector, +} + +impl<'tcx> Visitor<'tcx> for DeclMarker { + fn visit_lvalue(&mut self, lval: &Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) { + if ctx == LvalueContext::StorageLive || ctx == LvalueContext::StorageDead { + // ignore these altogether, they get removed along with their otherwise unused decls. + return; + } + if let Lvalue::Local(ref v) = *lval { + self.locals.insert(v.index()); + } + self.super_lvalue(lval, ctx, loc); + } +} + +struct LocalUpdater { + map: Vec, +} + +impl<'tcx> MutVisitor<'tcx> for LocalUpdater { + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { + // Remove unnecessary StorageLive and StorageDead annotations. + data.statements.retain(|stmt| { + match stmt.kind { + StatementKind::StorageLive(ref lval) | StatementKind::StorageDead(ref lval) => { + match *lval { + Lvalue::Local(l) => self.map[l.index()] != !0, + _ => true + } + } + _ => true + } + }); + self.super_basic_block_data(block, data); + } + fn visit_lvalue(&mut self, lval: &mut Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) { + match *lval { + Lvalue::Local(ref mut l) => *l = Local::new(self.map[l.index()]), + _ => (), + }; + self.super_lvalue(lval, ctx, loc); + } +} diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 8ad4d7f57a6f..02a0b3ab28d6 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -134,7 +134,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { fn fn_like(&mut self, fk: FnKind, fd: &hir::FnDecl, - b: &hir::Block, + b: &hir::Expr, s: Span, fn_id: ast::NodeId) -> ConstQualif { @@ -265,7 +265,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, + b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { self.fn_like(fk, fd, b, s, fn_id); @@ -319,7 +319,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { let mut outer = self.qualif; self.qualif = ConstQualif::empty(); - let node_ty = self.tcx.node_id_to_type(ex.id); + let node_ty = self.tcx.tables().node_id_to_type(ex.id); check_expr(self, ex, node_ty); check_adjustments(self, ex); @@ -449,14 +449,14 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node match e.node { hir::ExprUnary(..) | hir::ExprBinary(..) | - hir::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => { + hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => { v.add_qualif(ConstQualif::NOT_CONST); } hir::ExprBox(_) => { v.add_qualif(ConstQualif::NOT_CONST); } hir::ExprUnary(op, ref inner) => { - match v.tcx.node_id_to_type(inner.id).sty { + match v.tcx.tables().node_id_to_type(inner.id).sty { ty::TyRawPtr(_) => { assert!(op == hir::UnDeref); @@ -466,7 +466,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprBinary(op, ref lhs, _) => { - match v.tcx.node_id_to_type(lhs.id).sty { + match v.tcx.tables().node_id_to_type(lhs.id).sty { ty::TyRawPtr(_) => { assert!(op.node == hir::BiEq || op.node == hir::BiNe || op.node == hir::BiLe || op.node == hir::BiLt || @@ -503,7 +503,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } Def::Const(did) | Def::AssociatedConst(did) => { - let substs = Some(v.tcx.node_id_item_substs(e.id).substs); + let substs = Some(v.tcx.tables().node_id_item_substs(e.id) + .unwrap_or_else(|| v.tcx.intern_substs(&[]))); if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) { let inner = v.global_expr(Mode::Const, expr); v.add_qualif(inner); @@ -541,7 +542,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node v.handle_const_fn_call(e, did, node_ty) } Some(Def::Method(did)) => { - match v.tcx.impl_or_trait_item(did).container() { + match v.tcx.associated_item(did).container { ty::ImplContainer(_) => { v.handle_const_fn_call(e, did, node_ty) } @@ -555,8 +556,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprMethodCall(..) => { - let method = v.tcx.tables.borrow().method_map[&method_call]; - let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() { + let method = v.tcx.tables().method_map[&method_call]; + let is_const = match v.tcx.associated_item(method.def_id).container { ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty), ty::TraitContainer(_) => false }; @@ -565,7 +566,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } } hir::ExprStruct(..) => { - if let ty::TyAdt(adt, ..) = v.tcx.expr_ty(e).sty { + if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty { // unsafe_cell_type doesn't necessarily exist with no_core if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() { v.add_qualif(ConstQualif::MUTABLE_MEM); @@ -624,16 +625,18 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node /// Check the adjustments of an expression fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) { - match v.tcx.tables.borrow().adjustments.get(&e.id) { - None | - Some(&ty::adjustment::AdjustNeverToAny(..)) | - Some(&ty::adjustment::AdjustReifyFnPointer) | - Some(&ty::adjustment::AdjustUnsafeFnPointer) | - Some(&ty::adjustment::AdjustMutToConstPointer) => {} + use rustc::ty::adjustment::*; - Some(&ty::adjustment::AdjustDerefRef(ty::adjustment::AutoDerefRef { autoderefs, .. })) => { + match v.tcx.tables().adjustments.get(&e.id).map(|adj| adj.kind) { + None | + Some(Adjust::NeverToAny) | + Some(Adjust::ReifyFnPointer) | + Some(Adjust::UnsafeFnPointer) | + Some(Adjust::MutToConstPointer) => {} + + Some(Adjust::DerefRef { autoderefs, .. }) => { if (0..autoderefs as u32) - .any(|autoderef| v.tcx.is_overloaded_autoderef(e.id, autoderef)) { + .any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) { v.add_qualif(ConstQualif::NOT_CONST); } } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs new file mode 100644 index 000000000000..417987d9664e --- /dev/null +++ b/src/librustc_passes/hir_stats.rs @@ -0,0 +1,373 @@ +// 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. + +// The visitors in this module collect sizes and counts of the most important +// pieces of AST and HIR. The resulting numbers are good approximations but not +// completely accurate (some things might be counted twice, others missed). + +use rustc::hir; +use rustc::hir::intravisit as hir_visit; +use rustc::util::common::to_readable_str; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use syntax::ast::{self, NodeId, AttrId}; +use syntax::visit as ast_visit; +use syntax_pos::Span; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +enum Id { + Node(NodeId), + Attr(AttrId), + None, +} + +struct NodeData { + count: usize, + size: usize, +} + +struct StatCollector<'k> { + krate: Option<&'k hir::Crate>, + data: FxHashMap<&'static str, NodeData>, + seen: FxHashSet, +} + +pub fn print_hir_stats(krate: &hir::Crate) { + let mut collector = StatCollector { + krate: Some(krate), + data: FxHashMap(), + seen: FxHashSet(), + }; + hir_visit::walk_crate(&mut collector, krate); + collector.print("HIR STATS"); +} + +pub fn print_ast_stats(krate: &ast::Crate, title: &str) { + let mut collector = StatCollector { + krate: None, + data: FxHashMap(), + seen: FxHashSet(), + }; + ast_visit::walk_crate(&mut collector, krate); + collector.print(title); +} + +impl<'k> StatCollector<'k> { + + fn record(&mut self, label: &'static str, id: Id, node: &T) { + if id != Id::None { + if !self.seen.insert(id) { + return + } + } + + let entry = self.data.entry(label).or_insert(NodeData { + count: 0, + size: 0, + }); + + entry.count += 1; + entry.size = ::std::mem::size_of_val(node); + } + + fn print(&self, title: &str) { + let mut stats: Vec<_> = self.data.iter().collect(); + + stats.sort_by_key(|&(_, ref d)| d.count * d.size); + + let mut total_size = 0; + + println!("\n{}\n", title); + + println!("{:<18}{:>18}{:>14}{:>14}", + "Name", "Accumulated Size", "Count", "Item Size"); + println!("----------------------------------------------------------------"); + + for (label, data) in stats { + println!("{:<18}{:>18}{:>14}{:>14}", + label, + to_readable_str(data.count * data.size), + to_readable_str(data.count), + to_readable_str(data.size)); + + total_size += data.count * data.size; + } + println!("----------------------------------------------------------------"); + println!("{:<18}{:>18}\n", + "Total", + to_readable_str(total_size)); + } +} + +impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { + + fn visit_nested_item(&mut self, id: hir::ItemId) { + let nested_item = self.krate.unwrap().item(id.id); + self.visit_item(nested_item) + } + + fn visit_item(&mut self, i: &'v hir::Item) { + self.record("Item", Id::Node(i.id), i); + hir_visit::walk_item(self, i) + } + + /////////////////////////////////////////////////////////////////////////// + + fn visit_mod(&mut self, m: &'v hir::Mod, _s: Span, n: NodeId) { + self.record("Mod", Id::None, m); + hir_visit::walk_mod(self, m, n) + } + fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem) { + self.record("ForeignItem", Id::Node(i.id), i); + hir_visit::walk_foreign_item(self, i) + } + fn visit_local(&mut self, l: &'v hir::Local) { + self.record("Local", Id::Node(l.id), l); + hir_visit::walk_local(self, l) + } + fn visit_block(&mut self, b: &'v hir::Block) { + self.record("Block", Id::Node(b.id), b); + hir_visit::walk_block(self, b) + } + fn visit_stmt(&mut self, s: &'v hir::Stmt) { + self.record("Stmt", Id::Node(s.node.id()), s); + hir_visit::walk_stmt(self, s) + } + fn visit_arm(&mut self, a: &'v hir::Arm) { + self.record("Arm", Id::None, a); + hir_visit::walk_arm(self, a) + } + fn visit_pat(&mut self, p: &'v hir::Pat) { + self.record("Pat", Id::Node(p.id), p); + hir_visit::walk_pat(self, p) + } + fn visit_decl(&mut self, d: &'v hir::Decl) { + self.record("Decl", Id::None, d); + hir_visit::walk_decl(self, d) + } + fn visit_expr(&mut self, ex: &'v hir::Expr) { + self.record("Expr", Id::Node(ex.id), ex); + hir_visit::walk_expr(self, ex) + } + + fn visit_ty(&mut self, t: &'v hir::Ty) { + self.record("Ty", Id::Node(t.id), t); + hir_visit::walk_ty(self, t) + } + + fn visit_fn(&mut self, + fk: hir_visit::FnKind<'v>, + fd: &'v hir::FnDecl, + b: &'v hir::Expr, + s: Span, + id: NodeId) { + self.record("FnDecl", Id::None, fd); + hir_visit::walk_fn(self, fk, fd, b, s, id) + } + + fn visit_where_predicate(&mut self, predicate: &'v hir::WherePredicate) { + self.record("WherePredicate", Id::None, predicate); + hir_visit::walk_where_predicate(self, predicate) + } + + fn visit_trait_item(&mut self, ti: &'v hir::TraitItem) { + self.record("TraitItem", Id::Node(ti.id), ti); + hir_visit::walk_trait_item(self, ti) + } + fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { + self.record("ImplItem", Id::Node(ii.id), ii); + hir_visit::walk_impl_item(self, ii) + } + + fn visit_ty_param_bound(&mut self, bounds: &'v hir::TyParamBound) { + self.record("TyParamBound", Id::None, bounds); + hir_visit::walk_ty_param_bound(self, bounds) + } + + fn visit_struct_field(&mut self, s: &'v hir::StructField) { + self.record("StructField", Id::Node(s.id), s); + hir_visit::walk_struct_field(self, s) + } + + fn visit_variant(&mut self, + v: &'v hir::Variant, + g: &'v hir::Generics, + item_id: NodeId) { + self.record("Variant", Id::None, v); + hir_visit::walk_variant(self, v, g, item_id) + } + fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { + self.record("Lifetime", Id::Node(lifetime.id), lifetime); + hir_visit::walk_lifetime(self, lifetime) + } + fn visit_lifetime_def(&mut self, lifetime: &'v hir::LifetimeDef) { + self.record("LifetimeDef", Id::None, lifetime); + hir_visit::walk_lifetime_def(self, lifetime) + } + fn visit_path(&mut self, path: &'v hir::Path, _id: NodeId) { + self.record("Path", Id::None, path); + hir_visit::walk_path(self, path) + } + fn visit_path_list_item(&mut self, + prefix: &'v hir::Path, + item: &'v hir::PathListItem) { + self.record("PathListItem", Id::Node(item.node.id), item); + hir_visit::walk_path_list_item(self, prefix, item) + } + fn visit_path_segment(&mut self, + path_span: Span, + path_segment: &'v hir::PathSegment) { + self.record("PathSegment", Id::None, path_segment); + hir_visit::walk_path_segment(self, path_span, path_segment) + } + + fn visit_assoc_type_binding(&mut self, type_binding: &'v hir::TypeBinding) { + self.record("TypeBinding", Id::Node(type_binding.id), type_binding); + hir_visit::walk_assoc_type_binding(self, type_binding) + } + fn visit_attribute(&mut self, attr: &'v ast::Attribute) { + self.record("Attribute", Id::Attr(attr.node.id), attr); + } + fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef) { + self.record("MacroDef", Id::Node(macro_def.id), macro_def); + hir_visit::walk_macro_def(self, macro_def) + } +} + +impl<'v> ast_visit::Visitor for StatCollector<'v> { + + fn visit_mod(&mut self, m: &ast::Mod, _s: Span, _n: NodeId) { + self.record("Mod", Id::None, m); + ast_visit::walk_mod(self, m) + } + + fn visit_foreign_item(&mut self, i: &ast::ForeignItem) { + self.record("ForeignItem", Id::None, i); + ast_visit::walk_foreign_item(self, i) + } + + fn visit_item(&mut self, i: &ast::Item) { + self.record("Item", Id::None, i); + ast_visit::walk_item(self, i) + } + + fn visit_local(&mut self, l: &ast::Local) { + self.record("Local", Id::None, l); + ast_visit::walk_local(self, l) + } + + fn visit_block(&mut self, b: &ast::Block) { + self.record("Block", Id::None, b); + ast_visit::walk_block(self, b) + } + + fn visit_stmt(&mut self, s: &ast::Stmt) { + self.record("Stmt", Id::None, s); + ast_visit::walk_stmt(self, s) + } + + fn visit_arm(&mut self, a: &ast::Arm) { + self.record("Arm", Id::None, a); + ast_visit::walk_arm(self, a) + } + + fn visit_pat(&mut self, p: &ast::Pat) { + self.record("Pat", Id::None, p); + ast_visit::walk_pat(self, p) + } + + fn visit_expr(&mut self, ex: &ast::Expr) { + self.record("Expr", Id::None, ex); + ast_visit::walk_expr(self, ex) + } + + fn visit_ty(&mut self, t: &ast::Ty) { + self.record("Ty", Id::None, t); + ast_visit::walk_ty(self, t) + } + + fn visit_fn(&mut self, + fk: ast_visit::FnKind, + fd: &ast::FnDecl, + s: Span, + _: NodeId) { + self.record("FnDecl", Id::None, fd); + ast_visit::walk_fn(self, fk, fd, s) + } + + fn visit_trait_item(&mut self, ti: &ast::TraitItem) { + self.record("TraitItem", Id::None, ti); + ast_visit::walk_trait_item(self, ti) + } + + fn visit_impl_item(&mut self, ii: &ast::ImplItem) { + self.record("ImplItem", Id::None, ii); + ast_visit::walk_impl_item(self, ii) + } + + fn visit_ty_param_bound(&mut self, bounds: &ast::TyParamBound) { + self.record("TyParamBound", Id::None, bounds); + ast_visit::walk_ty_param_bound(self, bounds) + } + + fn visit_struct_field(&mut self, s: &ast::StructField) { + self.record("StructField", Id::None, s); + ast_visit::walk_struct_field(self, s) + } + + fn visit_variant(&mut self, + v: &ast::Variant, + g: &ast::Generics, + item_id: NodeId) { + self.record("Variant", Id::None, v); + ast_visit::walk_variant(self, v, g, item_id) + } + + fn visit_lifetime(&mut self, lifetime: &ast::Lifetime) { + self.record("Lifetime", Id::None, lifetime); + ast_visit::walk_lifetime(self, lifetime) + } + + fn visit_lifetime_def(&mut self, lifetime: &ast::LifetimeDef) { + self.record("LifetimeDef", Id::None, lifetime); + ast_visit::walk_lifetime_def(self, lifetime) + } + + fn visit_mac(&mut self, mac: &ast::Mac) { + self.record("Mac", Id::None, mac); + } + + fn visit_path_list_item(&mut self, + prefix: &ast::Path, + item: &ast::PathListItem) { + self.record("PathListItem", Id::None, item); + ast_visit::walk_path_list_item(self, prefix, item) + } + + fn visit_path_segment(&mut self, + path_span: Span, + path_segment: &ast::PathSegment) { + self.record("PathSegment", Id::None, path_segment); + ast_visit::walk_path_segment(self, path_span, path_segment) + } + + fn visit_assoc_type_binding(&mut self, type_binding: &ast::TypeBinding) { + self.record("TypeBinding", Id::None, type_binding); + ast_visit::walk_assoc_type_binding(self, type_binding) + } + + fn visit_attribute(&mut self, attr: &ast::Attribute) { + self.record("Attribute", Id::None, attr); + } + + fn visit_macro_def(&mut self, macro_def: &ast::MacroDef) { + self.record("MacroDef", Id::None, macro_def); + ast_visit::walk_macro_def(self, macro_def) + } +} diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index a4657251c9ce..039a76d25c7e 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -23,7 +23,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(staged_api)] #![feature(rustc_private)] @@ -45,6 +45,7 @@ pub mod diagnostics; pub mod ast_validation; pub mod consts; +pub mod hir_stats; pub mod loops; pub mod no_asm; pub mod rvalues; diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index e942707acd56..e58cd8938193 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -54,7 +54,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { self.with_context(Loop, |v| v.visit_block(&b)); } hir::ExprClosure(.., ref b, _) => { - self.with_context(Closure, |v| v.visit_block(&b)); + self.with_context(Closure, |v| v.visit_expr(&b)); } hir::ExprBreak(_) => self.require_loop("break", e.span), hir::ExprAgain(_) => self.require_loop("continue", e.span), diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index c3ef5a72a294..d55ce4c35638 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -35,7 +35,7 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> { fn visit_fn(&mut self, fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, + b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { // FIXME (@jroesch) change this to be an inference context diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 77b3e76fc541..dc7399e22890 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -17,7 +17,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] @@ -399,7 +399,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a method is in scope. fn check_method(&mut self, span: Span, method_def_id: DefId) { - match self.tcx.impl_or_trait_item(method_def_id).container() { + match self.tcx.associated_item(method_def_id).container { // Trait methods are always all public. The only controlling factor // is whether the trait itself is accessible or not. ty::TraitContainer(trait_def_id) if !self.item_is_accessible(trait_def_id) => { @@ -430,11 +430,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { match expr.node { hir::ExprMethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); - let method = self.tcx.tables.borrow().method_map[&method_call]; + let method = self.tcx.tables().method_map[&method_call]; self.check_method(expr.span, method.def_id); } hir::ExprStruct(_, ref expr_fields, _) => { - let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap(); + let adt = self.tcx.tables().expr_ty(expr).ty_adt_def().unwrap(); let variant = adt.variant_of_def(self.tcx.expect_def(expr.id)); // RFC 736: ensure all unmentioned fields are visible. // Rather than computing the set of unmentioned fields @@ -495,14 +495,14 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { match pattern.node { PatKind::Struct(_, ref fields, _) => { - let adt = self.tcx.pat_ty(pattern).ty_adt_def().unwrap(); + let adt = self.tcx.tables().pat_ty(pattern).ty_adt_def().unwrap(); let variant = adt.variant_of_def(self.tcx.expect_def(pattern.id)); for field in fields { self.check_field(field.span, adt, variant.field_named(field.node.name)); } } PatKind::TupleStruct(_, ref fields, ddpos) => { - match self.tcx.pat_ty(pattern).sty { + match self.tcx.tables().pat_ty(pattern).sty { // enum fields have no privacy at this time ty::TyAdt(def, _) if !def.is_enum() => { let expected_len = def.struct_variant().fields.len(); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index d90fe769caf6..99e7a9042c0c 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -14,18 +14,17 @@ //! any imports resolved. use macros::{InvocationData, LegacyScope}; +use resolve_imports::ImportDirective; use resolve_imports::ImportDirectiveSubclass::{self, GlobImport}; -use {Module, ModuleS, ModuleKind}; -use Namespace::{self, TypeNS, ValueNS}; -use {NameBinding, NameBindingKind, ToNameBinding}; -use Resolver; +use {Resolver, Module, ModuleS, ModuleKind, NameBinding, NameBindingKind, ToNameBinding}; +use Namespace::{self, TypeNS, ValueNS, MacroNS}; +use ResolveResult::Success; use {resolve_error, resolve_struct_error, ResolutionError}; -use rustc::middle::cstore::LoadedMacros; +use rustc::middle::cstore::{DepKind, LoadedMacro}; use rustc::hir::def::*; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::ty; -use rustc::util::nodemap::FnvHashMap; use std::cell::Cell; use std::rc::Rc; @@ -37,10 +36,9 @@ use syntax::parse::token; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; -use syntax::ext::base::{SyntaxExtension, Resolver as SyntaxResolver}; +use syntax::ext::base::SyntaxExtension; use syntax::ext::expand::mark_tts; use syntax::ext::hygiene::Mark; -use syntax::feature_gate::{self, emit_feature_err}; use syntax::ext::tt::macro_rules; use syntax::parse::token::keywords; use syntax::visit::{self, Visitor}; @@ -64,7 +62,6 @@ struct LegacyMacroImports { import_all: Option, imports: Vec<(Name, Span)>, reexports: Vec<(Name, Span)>, - no_link: bool, } impl<'b> Resolver<'b> { @@ -215,53 +212,26 @@ impl<'b> Resolver<'b> { } ItemKind::ExternCrate(_) => { - let legacy_imports = self.legacy_macro_imports(&item.attrs); - // `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root. - if self.current_module.parent.is_some() && { - legacy_imports.import_all.is_some() || !legacy_imports.imports.is_empty() || - !legacy_imports.reexports.is_empty() - } { - if self.current_module.parent.is_some() { - span_err!(self.session, item.span, E0468, - "an `extern crate` loading macros must be at the crate root"); - } - } - - let loaded_macros = if legacy_imports != LegacyMacroImports::default() { - self.crate_loader.process_item(item, &self.definitions, true) - } else { - self.crate_loader.process_item(item, &self.definitions, false) - }; + self.crate_loader.process_item(item, &self.definitions); // n.b. we don't need to look at the path option here, because cstore already did - let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id); - let module = if let Some(crate_id) = crate_id { - let def_id = DefId { - krate: crate_id, - index: CRATE_DEF_INDEX, - }; - let module = self.arenas.alloc_module(ModuleS { - extern_crate_id: Some(item.id), - populated: Cell::new(false), - ..ModuleS::new(Some(parent), ModuleKind::Def(Def::Mod(def_id), name)) - }); - self.define(parent, name, TypeNS, (module, sp, vis)); - self.populate_module_if_necessary(module); - module - } else { - // Define an empty module - let def = Def::Mod(self.definitions.local_def_id(item.id)); - let module = ModuleS::new(Some(parent), ModuleKind::Def(def, name)); - let module = self.arenas.alloc_module(module); - self.define(parent, name, TypeNS, (module, sp, vis)); - module - }; - - if let Some(loaded_macros) = loaded_macros { - self.import_extern_crate_macros( - item, module, loaded_macros, legacy_imports, expansion == Mark::root(), - ); - } + let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap(); + let module = self.get_extern_crate_root(crate_id); + let binding = (module, sp, ty::Visibility::Public).to_name_binding(); + let binding = self.arenas.alloc_name_binding(binding); + let directive = self.arenas.alloc_import_directive(ImportDirective { + id: item.id, + parent: parent, + imported_module: Cell::new(Some(module)), + subclass: ImportDirectiveSubclass::ExternCrate, + span: item.span, + module_path: Vec::new(), + vis: Cell::new(vis), + }); + let imported_binding = self.import(binding, directive); + self.define(parent, name, TypeNS, imported_binding); + self.populate_module_if_necessary(module); + self.process_legacy_macro_imports(item, module, expansion); } ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root @@ -282,9 +252,7 @@ impl<'b> Resolver<'b> { self.current_module = module; } - ItemKind::ForeignMod(..) => { - self.crate_loader.process_item(item, &self.definitions, false); - } + ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions), // These items live in the value namespace. ItemKind::Static(_, m, _) => { @@ -427,10 +395,10 @@ impl<'b> Resolver<'b> { let name = child.name; let def = child.def; let def_id = def.def_id(); - let vis = if parent.is_trait() { - ty::Visibility::Public - } else { - self.session.cstore.visibility(def_id) + let vis = match def { + Def::Macro(..) => ty::Visibility::Public, + _ if parent.is_trait() => ty::Visibility::Public, + _ => self.session.cstore.visibility(def_id), }; match def { @@ -456,7 +424,7 @@ impl<'b> Resolver<'b> { self.define(parent, name, TypeNS, (module, DUMMY_SP, vis)); // If this is a trait, add all the trait item names to the trait info. - let trait_item_def_ids = self.session.cstore.impl_or_trait_items(def_id); + let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id); for trait_item_def_id in trait_item_def_ids { let trait_item_name = self.session.cstore.def_key(trait_item_def_id) .disambiguated_data.data.get_opt_name() @@ -484,6 +452,9 @@ impl<'b> Resolver<'b> { let field_names = self.session.cstore.struct_field_names(def_id); self.insert_field_names(def_id, field_names); } + Def::Macro(..) => { + self.define(parent, name, MacroNS, (def, DUMMY_SP, vis)); + } Def::Local(..) | Def::PrimTy(..) | Def::TyParam(..) | @@ -496,6 +467,47 @@ impl<'b> Resolver<'b> { } } + fn get_extern_crate_root(&mut self, cnum: CrateNum) -> Module<'b> { + let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; + let macros_only = self.session.cstore.dep_kind(cnum) == DepKind::MacrosOnly; + let arenas = self.arenas; + *self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| { + arenas.alloc_module(ModuleS { + populated: Cell::new(false), + ..ModuleS::new(None, ModuleKind::Def(Def::Mod(def_id), keywords::Invalid.name())) + }) + }) + } + + pub fn get_macro(&mut self, def: Def) -> Rc { + let def_id = match def { + Def::Macro(def_id) => def_id, + _ => panic!("Expected Def::Macro(..)"), + }; + if let Some(ext) = self.macro_map.get(&def_id) { + return ext.clone(); + } + + let mut macro_rules = match self.session.cstore.load_macro(def_id, &self.session) { + LoadedMacro::MacroRules(macro_rules) => macro_rules, + LoadedMacro::ProcMacro(ext) => return ext, + }; + + let mark = Mark::fresh(); + let invocation = self.arenas.alloc_invocation_data(InvocationData { + module: Cell::new(self.get_extern_crate_root(def_id.krate)), + def_index: CRATE_DEF_INDEX, + const_integer: false, + legacy_scope: Cell::new(LegacyScope::Empty), + expansion: Cell::new(LegacyScope::Empty), + }); + self.invocations.insert(mark, invocation); + macro_rules.body = mark_tts(¯o_rules.body, mark); + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_rules)); + self.macro_map.insert(def_id, ext.clone()); + ext + } + /// Ensures that the reduced graph rooted at the given external module /// is built, building it if it is not. pub fn populate_module_if_necessary(&mut self, module: Module<'b>) { @@ -506,90 +518,55 @@ impl<'b> Resolver<'b> { module.populated.set(true) } - fn import_extern_crate_macros(&mut self, - extern_crate: &Item, - module: Module<'b>, - loaded_macros: LoadedMacros, - legacy_imports: LegacyMacroImports, - allow_shadowing: bool) { - let import_macro = |this: &mut Self, name, ext: Rc<_>, span| { - this.used_crates.insert(module.def_id().unwrap().krate); - if let SyntaxExtension::NormalTT(..) = *ext { - this.macro_names.insert(name); - } - if this.builtin_macros.insert(name, ext).is_some() && !allow_shadowing { - let msg = format!("`{}` is already in scope", name); - let note = - "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; - this.session.struct_span_err(span, &msg).note(note).emit(); - } - }; + fn legacy_import_macro(&mut self, name: Name, def: Def, span: Span, allow_shadowing: bool) { + self.used_crates.insert(def.def_id().krate); + self.macro_names.insert(name); + if self.builtin_macros.insert(name, def.def_id()).is_some() && !allow_shadowing { + let msg = format!("`{}` is already in scope", name); + let note = + "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)"; + self.session.struct_span_err(span, &msg).note(note).emit(); + } + } - match loaded_macros { - LoadedMacros::MacroRules(macros) => { - let mark = Mark::fresh(); - if !macros.is_empty() { - let invocation = self.arenas.alloc_invocation_data(InvocationData { - module: Cell::new(module), - def_index: CRATE_DEF_INDEX, - const_integer: false, - legacy_scope: Cell::new(LegacyScope::Empty), - expansion: Cell::new(LegacyScope::Empty), - }); - self.invocations.insert(mark, invocation); - } + fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'b>, expansion: Mark) { + let allow_shadowing = expansion == Mark::root(); + let legacy_imports = self.legacy_macro_imports(&item.attrs); + let cnum = module.def_id().unwrap().krate; - let mut macros: FnvHashMap<_, _> = macros.into_iter().map(|mut def| { - def.body = mark_tts(&def.body, mark); - let ext = macro_rules::compile(&self.session.parse_sess, &def); - (def.ident.name, (def, Rc::new(ext))) - }).collect(); + // `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root. + if self.current_module.parent.is_some() && legacy_imports != LegacyMacroImports::default() { + span_err!(self.session, item.span, E0468, + "an `extern crate` loading macros must be at the crate root"); + } else if self.session.cstore.dep_kind(cnum) == DepKind::MacrosOnly && + legacy_imports == LegacyMacroImports::default() { + let msg = "custom derive crates and `#[no_link]` crates have no effect without \ + `#[macro_use]`"; + self.session.span_warn(item.span, msg); + self.used_crates.insert(cnum); // Avoid the normal unused extern crate warning + } - if let Some(span) = legacy_imports.import_all { - for (&name, &(_, ref ext)) in macros.iter() { - import_macro(self, name, ext.clone(), span); - } + if let Some(span) = legacy_imports.import_all { + module.for_each_child(|name, ns, binding| if ns == MacroNS { + self.legacy_import_macro(name, binding.def(), span, allow_shadowing); + }); + } else { + for (name, span) in legacy_imports.imports { + let result = self.resolve_name_in_module(module, name, MacroNS, false, None); + if let Success(binding) = result { + self.legacy_import_macro(name, binding.def(), span, allow_shadowing); } else { - for (name, span) in legacy_imports.imports { - if let Some(&(_, ref ext)) = macros.get(&name) { - import_macro(self, name, ext.clone(), span); - } else { - span_err!(self.session, span, E0469, "imported macro not found"); - } - } - } - for (name, span) in legacy_imports.reexports { - if let Some((mut def, _)) = macros.remove(&name) { - def.id = self.next_node_id(); - self.exported_macros.push(def); - } else { - span_err!(self.session, span, E0470, "reexported macro not found"); - } + span_err!(self.session, span, E0469, "imported macro not found"); } } - - LoadedMacros::ProcMacros(macros) => { - if !self.session.features.borrow().proc_macro { - let sess = &self.session.parse_sess; - let issue = feature_gate::GateIssue::Language; - let msg = - "loading custom derive macro crates is experimentally supported"; - emit_feature_err(sess, "proc_macro", extern_crate.span, issue, msg); - } - if !legacy_imports.imports.is_empty() { - let msg = "`proc-macro` crates cannot be selectively imported from, \ - must use `#[macro_use]`"; - self.session.span_err(extern_crate.span, msg); - } - if !legacy_imports.reexports.is_empty() { - let msg = "`proc-macro` crates cannot be reexported from"; - self.session.span_err(extern_crate.span, msg); - } - if let Some(span) = legacy_imports.import_all { - for (name, ext) in macros { - import_macro(self, name, Rc::new(ext), span); - } - } + } + for (name, span) in legacy_imports.reexports { + self.used_crates.insert(module.def_id().unwrap().krate); + let result = self.resolve_name_in_module(module, name, MacroNS, false, None); + if let Success(binding) = result { + self.macro_exports.push(Export { name: name, def: binding.def() }); + } else { + span_err!(self.session, span, E0470, "reexported macro not found"); } } } @@ -647,8 +624,6 @@ impl<'b> Resolver<'b> { } else { bad_macro_reexport(self, attr.span()); } - } else if attr.check_name("no_link") { - imports.no_link = true; } } imports diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0b382fcbfdd5..fe90cd34687c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -19,7 +19,7 @@ #![feature(associated_consts)] #![feature(borrow_state)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] @@ -51,7 +51,7 @@ use rustc::hir::def::*; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; -use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; +use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet}; use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ast::{self, FloatTy}; @@ -76,7 +76,7 @@ use std::fmt; use std::mem::replace; use std::rc::Rc; -use resolve_imports::{ImportDirective, NameResolution}; +use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution}; use macros::{InvocationData, LegacyBinding, LegacyScope}; // NB: This module needs to be declared first so diagnostics are @@ -108,7 +108,7 @@ enum ResolutionError<'a> { /// error E0403: the name is already used for a type parameter in this type parameter list NameAlreadyUsedInTypeParameterList(Name, &'a Span), /// error E0404: is not a trait - IsNotATrait(&'a str), + IsNotATrait(&'a str, &'a str), /// error E0405: use of undeclared trait name UndeclaredTraitName(&'a str, SuggestedCandidates), /// error E0407: method is not a member of trait @@ -223,13 +223,13 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } - ResolutionError::IsNotATrait(name) => { + ResolutionError::IsNotATrait(name, kind_name) => { let mut err = struct_span_err!(resolver.session, span, E0404, "`{}` is not a trait", name); - err.span_label(span, &format!("not a trait")); + err.span_label(span, &format!("expected trait, found {}", kind_name)); err } ResolutionError::UndeclaredTraitName(name, candidates) => { @@ -498,7 +498,7 @@ struct BindingInfo { } // Map from the name in a pattern to its binding mode. -type BindingMap = FnvHashMap; +type BindingMap = FxHashMap; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum PatternSource { @@ -533,6 +533,7 @@ impl PatternSource { pub enum Namespace { TypeNS, ValueNS, + MacroNS, } impl<'a> Visitor for Resolver<'a> { @@ -555,7 +556,7 @@ impl<'a> Visitor for Resolver<'a> { self.resolve_type(ty); } fn visit_poly_trait_ref(&mut self, tref: &ast::PolyTraitRef, m: &ast::TraitBoundModifier) { - match self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0) { + match self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0, None) { Ok(def) => self.record_def(tref.trait_ref.ref_id, def), Err(_) => { // error already reported @@ -596,7 +597,6 @@ impl<'a> Visitor for Resolver<'a> { fn visit_fn(&mut self, function_kind: FnKind, declaration: &FnDecl, - block: &Block, _: Span, node_id: NodeId) { let rib_kind = match function_kind { @@ -604,13 +604,45 @@ impl<'a> Visitor for Resolver<'a> { self.visit_generics(generics); ItemRibKind } - FnKind::Method(_, sig, _) => { + FnKind::Method(_, sig, _, _) => { self.visit_generics(&sig.generics); MethodRibKind(!sig.decl.has_self()) } - FnKind::Closure => ClosureRibKind(node_id), + FnKind::Closure(_) => ClosureRibKind(node_id), }; - self.resolve_function(rib_kind, declaration, block); + + // Create a value rib for the function. + self.value_ribs.push(Rib::new(rib_kind)); + + // Create a label rib for the function. + self.label_ribs.push(Rib::new(rib_kind)); + + // Add each argument to the rib. + let mut bindings_list = FxHashMap(); + for argument in &declaration.inputs { + self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); + + self.visit_ty(&argument.ty); + + debug!("(resolving function) recorded argument"); + } + visit::walk_fn_ret_ty(self, &declaration.output); + + // Resolve the function body. + match function_kind { + FnKind::ItemFn(.., body) | + FnKind::Method(.., body) => { + self.visit_block(body); + } + FnKind::Closure(body) => { + self.visit_expr(body); + } + }; + + debug!("(resolving function) leaving function"); + + self.label_ribs.pop(); + self.value_ribs.pop(); } } @@ -703,14 +735,14 @@ enum ModulePrefixResult<'a> { /// One local scope. #[derive(Debug)] struct Rib<'a> { - bindings: FnvHashMap, + bindings: FxHashMap, kind: RibKind<'a>, } impl<'a> Rib<'a> { fn new(kind: RibKind<'a>) -> Rib<'a> { Rib { - bindings: FnvHashMap(), + bindings: FxHashMap(), kind: kind, } } @@ -765,11 +797,7 @@ pub struct ModuleS<'a> { // The node id of the closest normal module (`mod`) ancestor (including this module). normal_ancestor_id: Option, - // If the module is an extern crate, `def` is root of the external crate and `extern_crate_id` - // is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None). - extern_crate_id: Option, - - resolutions: RefCell>>>, + resolutions: RefCell>>>, no_implicit_prelude: bool, @@ -793,8 +821,7 @@ impl<'a> ModuleS<'a> { parent: parent, kind: kind, normal_ancestor_id: None, - extern_crate_id: None, - resolutions: RefCell::new(FnvHashMap()), + resolutions: RefCell::new(FxHashMap()), no_implicit_prelude: false, glob_importers: RefCell::new(Vec::new()), globs: RefCell::new((Vec::new())), @@ -922,7 +949,14 @@ impl<'a> NameBinding<'a> { } fn is_extern_crate(&self) -> bool { - self.module().ok().and_then(|module| module.extern_crate_id).is_some() + match self.kind { + NameBindingKind::Import { + directive: &ImportDirective { + subclass: ImportDirectiveSubclass::ExternCrate, .. + }, .. + } => true, + _ => false, + } } fn is_import(&self) -> bool { @@ -950,12 +984,12 @@ impl<'a> NameBinding<'a> { /// Interns the names of the primitive types. struct PrimitiveTypeTable { - primitive_types: FnvHashMap, + primitive_types: FxHashMap, } impl PrimitiveTypeTable { fn new() -> PrimitiveTypeTable { - let mut table = PrimitiveTypeTable { primitive_types: FnvHashMap() }; + let mut table = PrimitiveTypeTable { primitive_types: FxHashMap() }; table.intern("bool", TyBool); table.intern("char", TyChar); @@ -989,17 +1023,17 @@ pub struct Resolver<'a> { // Maps the node id of a statement to the expansions of the `macro_rules!`s // immediately above the statement (if appropriate). - macros_at_scope: FnvHashMap>, + macros_at_scope: FxHashMap>, graph_root: Module<'a>, prelude: Option>, - trait_item_map: FnvHashMap<(Name, DefId), bool /* is static method? */>, + trait_item_map: FxHashMap<(Name, DefId), bool /* is static method? */>, // Names of fields of an item `DefId` accessible with dot syntax. // Used for hints during error reporting. - field_names: FnvHashMap>, + field_names: FxHashMap>, // All imports known to succeed or fail. determined_imports: Vec<&'a ImportDirective<'a>>, @@ -1050,6 +1084,7 @@ pub struct Resolver<'a> { // There will be an anonymous module created around `g` with the ID of the // entry block for `f`. module_map: NodeMap>, + extern_crate_roots: FxHashMap<(CrateNum, bool /* MacrosOnly? */), Module<'a>>, // Whether or not to print error messages. Can be set to true // when getting additional info for error message suggestions, @@ -1061,13 +1096,13 @@ pub struct Resolver<'a> { // all imports, but only glob imports are actually interesting). pub glob_map: GlobMap, - used_imports: FnvHashSet<(NodeId, Namespace)>, - used_crates: FnvHashSet, + used_imports: FxHashSet<(NodeId, Namespace)>, + used_crates: FxHashSet, pub maybe_unused_trait_imports: NodeSet, privacy_errors: Vec>, ambiguity_errors: Vec>, - disallowed_shadowing: Vec<(Name, Span, LegacyScope<'a>)>, + disallowed_shadowing: Vec<&'a LegacyBinding<'a>>, arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, @@ -1075,11 +1110,14 @@ pub struct Resolver<'a> { pub exported_macros: Vec, crate_loader: &'a mut CrateLoader, - macro_names: FnvHashSet, - builtin_macros: FnvHashMap>, + macro_names: FxHashSet, + builtin_macros: FxHashMap, + lexical_macro_resolutions: Vec<(Name, LegacyScope<'a>)>, + macro_map: FxHashMap>, + macro_exports: Vec, // Maps the `Mark` of an expansion to its containing module or block. - invocations: FnvHashMap>, + invocations: FxHashMap>, } pub struct ResolverArenas<'a> { @@ -1205,7 +1243,7 @@ impl<'a> Resolver<'a> { let mut definitions = Definitions::new(); DefCollector::new(&mut definitions).collect_root(); - let mut invocations = FnvHashMap(); + let mut invocations = FxHashMap(); invocations.insert(Mark::root(), arenas.alloc_invocation_data(InvocationData::root(graph_root))); @@ -1213,15 +1251,15 @@ impl<'a> Resolver<'a> { session: session, definitions: definitions, - macros_at_scope: FnvHashMap(), + macros_at_scope: FxHashMap(), // The outermost module has def ID 0; this is not reflected in the // AST. graph_root: graph_root, prelude: None, - trait_item_map: FnvHashMap(), - field_names: FnvHashMap(), + trait_item_map: FxHashMap(), + field_names: FxHashMap(), determined_imports: Vec::new(), indeterminate_imports: Vec::new(), @@ -1242,13 +1280,14 @@ impl<'a> Resolver<'a> { export_map: NodeMap(), trait_map: NodeMap(), module_map: module_map, + extern_crate_roots: FxHashMap(), emit_errors: true, make_glob_map: make_glob_map == MakeGlobMap::Yes, glob_map: NodeMap(), - used_imports: FnvHashSet(), - used_crates: FnvHashSet(), + used_imports: FxHashSet(), + used_crates: FxHashSet(), maybe_unused_trait_imports: NodeSet(), privacy_errors: Vec::new(), @@ -1265,8 +1304,11 @@ impl<'a> Resolver<'a> { exported_macros: Vec::new(), crate_loader: crate_loader, - macro_names: FnvHashSet(), - builtin_macros: FnvHashMap(), + macro_names: FxHashSet(), + builtin_macros: FxHashMap(), + lexical_macro_resolutions: Vec::new(), + macro_map: FxHashMap(), + macro_exports: Vec::new(), invocations: invocations, } } @@ -1285,13 +1327,6 @@ impl<'a> Resolver<'a> { /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { - // Collect `DefId`s for exported macro defs. - for def in &krate.exported_macros { - DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { - collector.visit_macro_def(def) - }) - } - self.current_module = self.graph_root; visit::walk_crate(self, krate); @@ -1309,7 +1344,11 @@ impl<'a> Resolver<'a> { } fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec> { - match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs } + match ns { + ValueNS => &mut self.value_ribs, + TypeNS => &mut self.type_ribs, + MacroNS => panic!("The macro namespace has no ribs"), + } } fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) @@ -1338,7 +1377,7 @@ impl<'a> Resolver<'a> { fn add_to_glob_map(&mut self, id: NodeId, name: Name) { if self.make_glob_map { - self.glob_map.entry(id).or_insert_with(FnvHashSet).insert(name); + self.glob_map.entry(id).or_insert_with(FxHashSet).insert(name); } } @@ -1697,7 +1736,7 @@ impl<'a> Resolver<'a> { } ItemKind::DefaultImpl(_, ref trait_ref) => { - self.with_optional_trait_ref(Some(trait_ref), |_, _| {}); + self.with_optional_trait_ref(Some(trait_ref), |_, _| {}, None); } ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) => self.resolve_implementation(generics, @@ -1801,7 +1840,7 @@ impl<'a> Resolver<'a> { match type_parameters { HasTypeParameters(generics, rib_kind) => { let mut function_type_rib = Rib::new(rib_kind); - let mut seen_bindings = FnvHashMap(); + let mut seen_bindings = FxHashMap(); for type_parameter in &generics.ty_params { let name = type_parameter.ident.name; debug!("with_type_parameter_rib: {}", type_parameter.id); @@ -1854,40 +1893,11 @@ impl<'a> Resolver<'a> { self.value_ribs.pop(); } - fn resolve_function(&mut self, - rib_kind: RibKind<'a>, - declaration: &FnDecl, - block: &Block) { - // Create a value rib for the function. - self.value_ribs.push(Rib::new(rib_kind)); - - // Create a label rib for the function. - self.label_ribs.push(Rib::new(rib_kind)); - - // Add each argument to the rib. - let mut bindings_list = FnvHashMap(); - for argument in &declaration.inputs { - self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); - - self.visit_ty(&argument.ty); - - debug!("(resolving function) recorded argument"); - } - visit::walk_fn_ret_ty(self, &declaration.output); - - // Resolve the function body. - self.visit_block(block); - - debug!("(resolving function) leaving function"); - - self.label_ribs.pop(); - self.value_ribs.pop(); - } - fn resolve_trait_reference(&mut self, id: NodeId, trait_path: &Path, - path_depth: usize) + path_depth: usize, + generics: Option<&Generics>) -> Result { self.resolve_path(id, trait_path, path_depth, TypeNS).and_then(|path_res| { match path_res.base_def { @@ -1900,8 +1910,16 @@ impl<'a> Resolver<'a> { } let mut err = resolve_struct_error(self, trait_path.span, { - ResolutionError::IsNotATrait(&path_names_to_string(trait_path, path_depth)) + ResolutionError::IsNotATrait(&path_names_to_string(trait_path, path_depth), + path_res.base_def.kind_name()) }); + if let Some(generics) = generics { + if let Some(span) = generics.span_for_name( + &path_names_to_string(trait_path, path_depth)) { + + err.span_label(span, &"type parameter defined here"); + } + } // If it's a typedef, give a note if let Def::TyAlias(..) = path_res.base_def { @@ -1946,7 +1964,11 @@ impl<'a> Resolver<'a> { result } - fn with_optional_trait_ref(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T + fn with_optional_trait_ref(&mut self, + opt_trait_ref: Option<&TraitRef>, + f: F, + generics: Option<&Generics>) + -> T where F: FnOnce(&mut Resolver, Option) -> T { let mut new_val = None; @@ -1954,7 +1976,8 @@ impl<'a> Resolver<'a> { if let Some(trait_ref) = opt_trait_ref { if let Ok(path_res) = self.resolve_trait_reference(trait_ref.ref_id, &trait_ref.path, - 0) { + 0, + generics) { assert!(path_res.depth == 0); self.record_def(trait_ref.ref_id, path_res); new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); @@ -2042,7 +2065,7 @@ impl<'a> Resolver<'a> { } }); }); - }); + }, Some(&generics)); }); } @@ -2067,7 +2090,7 @@ impl<'a> Resolver<'a> { walk_list!(self, visit_expr, &local.init); // Resolve the pattern. - self.resolve_pattern(&local.pat, PatternSource::Let, &mut FnvHashMap()); + self.resolve_pattern(&local.pat, PatternSource::Let, &mut FxHashMap()); } // build a map from pattern identifiers to binding-info's. @@ -2075,7 +2098,7 @@ impl<'a> Resolver<'a> { // that expands into an or-pattern where one 'x' was from the // user and one 'x' came from the macro. fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap { - let mut binding_map = FnvHashMap(); + let mut binding_map = FxHashMap(); pat.walk(&mut |pat| { if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node { @@ -2135,7 +2158,7 @@ impl<'a> Resolver<'a> { fn resolve_arm(&mut self, arm: &Arm) { self.value_ribs.push(Rib::new(NormalRibKind)); - let mut bindings_list = FnvHashMap(); + let mut bindings_list = FxHashMap(); for pattern in &arm.pats { self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list); } @@ -2276,7 +2299,7 @@ impl<'a> Resolver<'a> { pat_id: NodeId, outer_pat_id: NodeId, pat_src: PatternSource, - bindings: &mut FnvHashMap) + bindings: &mut FxHashMap) -> PathResolution { // Add the binding to the local ribs, if it // doesn't already exist in the bindings map. (We @@ -2389,7 +2412,7 @@ impl<'a> Resolver<'a> { pat_src: PatternSource, // Maps idents to the node ID for the // outermost pattern that binds them. - bindings: &mut FnvHashMap) { + bindings: &mut FxHashMap) { // Visit all direct subpatterns of this pattern. let outer_pat_id = pat.id; pat.walk(&mut |pat| { @@ -2492,7 +2515,7 @@ impl<'a> Resolver<'a> { } max_assoc_types = path.segments.len() - qself.position; // Make sure the trait is valid. - let _ = self.resolve_trait_reference(id, path, max_assoc_types); + let _ = self.resolve_trait_reference(id, path, max_assoc_types, None); } None => { max_assoc_types = path.segments.len(); @@ -3046,7 +3069,7 @@ impl<'a> Resolver<'a> { self.visit_expr(subexpression); self.value_ribs.push(Rib::new(NormalRibKind)); - self.resolve_pattern(pattern, PatternSource::IfLet, &mut FnvHashMap()); + self.resolve_pattern(pattern, PatternSource::IfLet, &mut FxHashMap()); self.visit_block(if_block); self.value_ribs.pop(); @@ -3063,7 +3086,7 @@ impl<'a> Resolver<'a> { ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => { self.visit_expr(subexpression); self.value_ribs.push(Rib::new(NormalRibKind)); - self.resolve_pattern(pattern, PatternSource::WhileLet, &mut FnvHashMap()); + self.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap()); self.resolve_labeled_block(label, expr.id, block); @@ -3073,7 +3096,7 @@ impl<'a> Resolver<'a> { ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => { self.visit_expr(subexpression); self.value_ribs.push(Rib::new(NormalRibKind)); - self.resolve_pattern(pattern, PatternSource::For, &mut FnvHashMap()); + self.resolve_pattern(pattern, PatternSource::For, &mut FxHashMap()); self.resolve_labeled_block(label, expr.id, block); @@ -3216,7 +3239,7 @@ impl<'a> Resolver<'a> { in_module.for_each_child(|name, ns, name_binding| { // avoid imports entirely - if name_binding.is_import() { return; } + if name_binding.is_import() && !name_binding.is_extern_crate() { return; } // collect results based on the filter function if name == lookup_name && ns == namespace { @@ -3252,21 +3275,11 @@ impl<'a> Resolver<'a> { // collect submodules to explore if let Ok(module) = name_binding.module() { // form the path - let path_segments = match module.kind { - _ if module.parent.is_none() => path_segments.clone(), - ModuleKind::Def(_, name) => { - let mut paths = path_segments.clone(); - let ident = Ident::with_empty_ctxt(name); - let params = PathParameters::none(); - let segm = PathSegment { - identifier: ident, - parameters: params, - }; - paths.push(segm); - paths - } - _ => bug!(), - }; + let mut path_segments = path_segments.clone(); + path_segments.push(PathSegment { + identifier: Ident::with_empty_ctxt(name), + parameters: PathParameters::none(), + }); if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { // add the module to the lookup @@ -3335,7 +3348,7 @@ impl<'a> Resolver<'a> { fn report_errors(&mut self) { self.report_shadowing_errors(); - let mut reported_spans = FnvHashSet(); + let mut reported_spans = FxHashSet(); for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors { if !reported_spans.insert(span) { continue } @@ -3352,7 +3365,10 @@ impl<'a> Resolver<'a> { if !reported_spans.insert(span) { continue } if binding.is_extern_crate() { // Warn when using an inaccessible extern crate. - let node_id = binding.module().unwrap().extern_crate_id.unwrap(); + let node_id = match binding.kind { + NameBindingKind::Import { directive, .. } => directive.id, + _ => unreachable!(), + }; let msg = format!("extern crate `{}` is private", name); self.session.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, node_id, span, msg); } else { @@ -3363,12 +3379,16 @@ impl<'a> Resolver<'a> { } fn report_shadowing_errors(&mut self) { - let mut reported_errors = FnvHashSet(); - for (name, span, scope) in replace(&mut self.disallowed_shadowing, Vec::new()) { - if self.resolve_macro_name(scope, name, false).is_some() && - reported_errors.insert((name, span)) { - let msg = format!("`{}` is already in scope", name); - self.session.struct_span_err(span, &msg) + for (name, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) { + self.resolve_macro_name(scope, name); + } + + let mut reported_errors = FxHashSet(); + for binding in replace(&mut self.disallowed_shadowing, Vec::new()) { + if self.resolve_macro_name(binding.parent, binding.name).is_some() && + reported_errors.insert((binding.name, binding.span)) { + let msg = format!("`{}` is already in scope", binding.name); + self.session.struct_span_err(binding.span, &msg) .note("macro-expanded `macro_rules!`s may not shadow \ existing macros (see RFC 1560)") .emit(); @@ -3394,7 +3414,7 @@ impl<'a> Resolver<'a> { _ => "enum", }; - let (participle, noun) = match old_binding.is_import() || old_binding.is_extern_crate() { + let (participle, noun) = match old_binding.is_import() { true => ("imported", "import"), false => ("defined", "definition"), }; @@ -3403,7 +3423,8 @@ impl<'a> Resolver<'a> { let msg = { let kind = match (ns, old_binding.module()) { (ValueNS, _) => "a value", - (TypeNS, Ok(module)) if module.extern_crate_id.is_some() => "an extern crate", + (MacroNS, _) => "a macro", + (TypeNS, _) if old_binding.is_extern_crate() => "an extern crate", (TypeNS, Ok(module)) if module.is_normal() => "a module", (TypeNS, Ok(module)) if module.is_trait() => "a trait", (TypeNS, _) => "a type", @@ -3418,7 +3439,7 @@ impl<'a> Resolver<'a> { e.span_label(span, &format!("`{}` was already imported", name)); e }, - (true, _) | (_, true) if binding.is_import() || old_binding.is_import() => { + (true, _) | (_, true) if binding.is_import() && old_binding.is_import() => { let mut e = struct_span_err!(self.session, span, E0254, "{}", msg); e.span_label(span, &"already imported"); e diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index ed46c1d96ad1..f30c129c48fd 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use {Module, Resolver}; +use {Module, ModuleKind, Resolver}; use build_reduced_graph::BuildReducedGraphVisitor; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex}; +use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex}; +use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; use std::cell::Cell; use std::rc::Rc; @@ -21,8 +22,11 @@ use syntax::ext::base::{NormalTT, SyntaxExtension}; use syntax::ext::expand::Expansion; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; +use syntax::fold::Folder; use syntax::parse::token::intern; +use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; +use syntax::visit::Visitor; use syntax_pos::Span; #[derive(Clone)] @@ -73,10 +77,10 @@ impl<'a> LegacyScope<'a> { } pub struct LegacyBinding<'a> { - parent: LegacyScope<'a>, - name: ast::Name, + pub parent: LegacyScope<'a>, + pub name: ast::Name, ext: Rc, - span: Span, + pub span: Span, } impl<'a> base::Resolver for Resolver<'a> { @@ -97,6 +101,31 @@ impl<'a> base::Resolver for Resolver<'a> { mark } + fn eliminate_crate_var(&mut self, item: P) -> P { + struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>); + + impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> { + fn fold_path(&mut self, mut path: ast::Path) -> ast::Path { + let ident = path.segments[0].identifier; + if &ident.name.as_str() == "$crate" { + path.global = true; + let module = self.0.resolve_crate_var(ident.ctxt); + if module.is_local() { + path.segments.remove(0); + } else { + path.segments[0].identifier = match module.kind { + ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name), + _ => unreachable!(), + }; + } + } + path + } + } + + EliminateCrateVar(self).fold_item(item).expect_one("") + } + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { let invocation = self.invocations[&mark]; self.collect_def_ids(invocation, expansion); @@ -128,6 +157,13 @@ impl<'a> base::Resolver for Resolver<'a> { if export { def.id = self.next_node_id(); + DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { + collector.visit_macro_def(&def) + }); + self.macro_exports.push(Export { + name: def.ident.name, + def: Def::Macro(self.definitions.local_def_id(def.id)), + }); self.exported_macros.push(def); } } @@ -136,7 +172,12 @@ impl<'a> base::Resolver for Resolver<'a> { if let NormalTT(..) = *ext { self.macro_names.insert(ident.name); } - self.builtin_macros.insert(ident.name, ext); + let def_id = DefId { + krate: BUILTIN_MACROS_CRATE, + index: DefIndex::new(self.macro_map.len()), + }; + self.macro_map.insert(def_id, ext); + self.builtin_macros.insert(ident.name, def_id); } fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { @@ -147,7 +188,7 @@ impl<'a> base::Resolver for Resolver<'a> { for i in 0..attrs.len() { let name = intern(&attrs[i].name()); match self.builtin_macros.get(&name) { - Some(ext) => match **ext { + Some(&def_id) => match *self.get_macro(Def::Macro(def_id)) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) } @@ -171,7 +212,7 @@ impl<'a> base::Resolver for Resolver<'a> { if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() { invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent)); } - self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| { + self.resolve_macro_name(invocation.legacy_scope.get(), name).ok_or_else(|| { if force { let msg = format!("macro undefined: '{}!'", name); let mut err = self.session.struct_span_err(path.span, &msg); @@ -186,17 +227,18 @@ impl<'a> base::Resolver for Resolver<'a> { } impl<'a> Resolver<'a> { - pub fn resolve_macro_name(&mut self, - mut scope: LegacyScope<'a>, - name: ast::Name, - record_used: bool) + pub fn resolve_macro_name(&mut self, mut scope: LegacyScope<'a>, name: ast::Name) -> Option> { + let mut possible_time_travel = None; let mut relative_depth: u32 = 0; loop { scope = match scope { LegacyScope::Empty => break, LegacyScope::Expansion(invocation) => { if let LegacyScope::Empty = invocation.expansion.get() { + if possible_time_travel.is_none() { + possible_time_travel = Some(scope); + } invocation.legacy_scope.get() } else { relative_depth += 1; @@ -209,8 +251,11 @@ impl<'a> Resolver<'a> { } LegacyScope::Binding(binding) => { if binding.name == name { - if record_used && relative_depth > 0 { - self.disallowed_shadowing.push((name, binding.span, binding.parent)); + if let Some(scope) = possible_time_travel { + // Check for disallowed shadowing later + self.lexical_macro_resolutions.push((name, scope)); + } else if relative_depth > 0 { + self.disallowed_shadowing.push(binding); } return Some(binding.ext.clone()); } @@ -219,7 +264,10 @@ impl<'a> Resolver<'a> { }; } - self.builtin_macros.get(&name).cloned() + if let Some(scope) = possible_time_travel { + self.lexical_macro_resolutions.push((name, scope)); + } + self.builtin_macros.get(&name).cloned().map(|def_id| self.get_macro(Def::Macro(def_id))) } fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 2b3945bd0d92..5d66caec31b3 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -30,6 +30,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; use std::cell::{Cell, RefCell}; +use std::mem; impl<'a> Resolver<'a> { pub fn resolve_imports(&mut self) { @@ -51,6 +52,7 @@ pub enum ImportDirectiveSubclass<'a> { max_vis: Cell, // The visibility of the greatest reexport. // n.b. `max_vis` is only used in `finalize_import` to check for reexport errors. }, + ExternCrate, } impl<'a> ImportDirectiveSubclass<'a> { @@ -68,12 +70,12 @@ impl<'a> ImportDirectiveSubclass<'a> { #[derive(Debug,Clone)] pub struct ImportDirective<'a> { pub id: NodeId, - parent: Module<'a>, - module_path: Vec, - imported_module: Cell>>, // the resolution of `module_path` - subclass: ImportDirectiveSubclass<'a>, - span: Span, - vis: Cell, + pub parent: Module<'a>, + pub module_path: Vec, + pub imported_module: Cell>>, // the resolution of `module_path` + pub subclass: ImportDirectiveSubclass<'a>, + pub span: Span, + pub vis: Cell, } impl<'a> ImportDirective<'a> { @@ -169,7 +171,8 @@ impl<'a> Resolver<'a> { let new_import_semantics = self.new_import_semantics; let is_disallowed_private_import = |binding: &NameBinding| { !new_import_semantics && !allow_private_imports && // disallowed - binding.vis != ty::Visibility::Public && binding.is_import() // non-`pub` import + binding.vis != ty::Visibility::Public && binding.is_import() && // non-`pub` import + !binding.is_extern_crate() // not an `extern crate` }; if let Some(span) = record_used { @@ -237,7 +240,7 @@ impl<'a> Resolver<'a> { }; let name = match directive.subclass { SingleImport { source, .. } => source, - GlobImport { .. } => unreachable!(), + _ => unreachable!(), }; match self.resolve_name_in_module(module, name, ns, true, None) { Failed(_) => {} @@ -280,13 +283,14 @@ impl<'a> Resolver<'a> { // which are not relevant to import resolution. GlobImport { is_prelude: true, .. } => {} GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive), + _ => unreachable!(), } } // Given a binding and an import directive that resolves to it, // return the corresponding binding defined by the import directive. - fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>) - -> NameBinding<'a> { + pub fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>) + -> NameBinding<'a> { let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) || !directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC` directive.vis.get() @@ -529,6 +533,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.resolve_glob_import(directive); return Success(()); } + _ => unreachable!(), }; let mut indeterminate = false; @@ -616,6 +621,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } return Success(()); } + _ => unreachable!(), }; for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { @@ -767,6 +773,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { *module.globs.borrow_mut() = Vec::new(); let mut reexports = Vec::new(); + if module as *const _ == self.graph_root as *const _ { + reexports = mem::replace(&mut self.macro_exports, Vec::new()); + } + for (&(name, ns), resolution) in module.resolutions.borrow().iter() { let resolution = resolution.borrow(); let binding = match resolution.binding { @@ -831,5 +841,6 @@ fn import_directive_subclass_to_string(subclass: &ImportDirectiveSubclass) -> St match *subclass { SingleImport { source, .. } => source.to_string(), GlobImport { .. } => "*".to_string(), + ExternCrate => "".to_string(), } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 8a628289b7f9..e83c2359979c 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -32,7 +32,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir::map::{Node, NodeItem}; use rustc::session::Session; -use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer}; +use rustc::ty::{self, TyCtxt, AssociatedItemContainer}; use std::collections::HashSet; use std::collections::hash_map::DefaultHasher; @@ -341,6 +341,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::PrimTy(_) | + Def::Macro(_) | Def::Err => { span_bug!(span, "process_def_kind for unexpected item: {:?}", @@ -356,7 +357,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { collector.visit_pat(&arg.pat); let span_utils = self.span.clone(); for &(id, ref p, ..) in &collector.collected_paths { - let typ = self.tcx.node_types().get(&id).unwrap().to_string(); + let typ = self.tcx.tables().node_types.get(&id).unwrap().to_string(); // get the span only for the name of the variable (I hope the path is only ever a // variable name, but who knows?) let sub_span = span_utils.span_for_last_ident(p.span); @@ -402,19 +403,19 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // with the right name. if !self.span.filter_generated(Some(method_data.span), span) { let container = - self.tcx.impl_or_trait_item(self.tcx.map.local_def_id(id)).container(); + self.tcx.associated_item(self.tcx.map.local_def_id(id)).container; let mut trait_id; let mut decl_id = None; match container { - ImplOrTraitItemContainer::ImplContainer(id) => { + AssociatedItemContainer::ImplContainer(id) => { trait_id = self.tcx.trait_id_of_impl(id); match trait_id { Some(id) => { - for item in &**self.tcx.trait_items(id) { - if let &ImplOrTraitItem::MethodTraitItem(ref m) = item { - if m.name == name { - decl_id = Some(m.def_id); + for item in self.tcx.associated_items(id) { + if item.kind == ty::AssociatedKind::Method { + if item.name == name { + decl_id = Some(item.def_id); break; } } @@ -429,7 +430,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } } - ImplOrTraitItemContainer::TraitContainer(id) => { + AssociatedItemContainer::TraitContainer(id) => { trait_id = Some(id); } } @@ -916,11 +917,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // Modules or types in the path prefix. match self.tcx.expect_def(id) { Def::Method(did) => { - let ti = self.tcx.impl_or_trait_item(did); - if let ty::MethodTraitItem(m) = ti { - if m.explicit_self == ty::ExplicitSelfCategory::Static { - self.write_sub_path_trait_truncated(path); - } + let ti = self.tcx.associated_item(did); + if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument { + self.write_sub_path_trait_truncated(path); } } Def::Fn(..) | @@ -988,7 +987,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { match p.node { PatKind::Struct(ref path, ref fields, _) => { visit::walk_path(self, path); - let adt = self.tcx.node_id_to_type(p.id).ty_adt_def().unwrap(); + let adt = self.tcx.tables().node_id_to_type(p.id).ty_adt_def().unwrap(); let variant = adt.variant_of_def(self.tcx.expect_def(p.id)); for &Spanned { node: ref field, span } in fields { @@ -1023,8 +1022,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { ast::Mutability::Immutable => value.to_string(), _ => String::new(), }; - let types = self.tcx.node_types(); - let typ = match types.get(&id) { + let typ = match self.tcx.tables().node_types.get(&id) { Some(typ) => { let typ = typ.to_string(); if !value.is_empty() { @@ -1355,7 +1353,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } ast::ExprKind::Struct(ref path, ref fields, ref base) => { let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id); - let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap(); + let adt = self.tcx.tables().expr_ty(&hir_expr).ty_adt_def().unwrap(); let def = self.tcx.expect_def(hir_expr.id); self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base) } @@ -1381,7 +1379,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> return; } }; - let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; + let ty = &self.tcx.tables().expr_ty_adjusted(&hir_node).sty; match *ty { ty::TyAdt(def, _) => { let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); @@ -1415,7 +1413,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } // walk the body - self.nest(ex.id, |v| v.visit_block(&body)); + self.nest(ex.id, |v| v.visit_expr(body)); } ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) | ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => { @@ -1468,7 +1466,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } else { "".to_string() }; - let typ = self.tcx.node_types() + let typ = self.tcx.tables().node_types .get(&id).map(|t| t.to_string()).unwrap_or(String::new()); value.push_str(": "); value.push_str(&typ); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 15c74f2ed6ab..ab5bbea07a30 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -18,7 +18,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(custom_attribute)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![allow(unused_attributes)] #![feature(rustc_private)] #![feature(staged_api)] @@ -286,7 +286,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: NodeId) -> Option { if let Some(ident) = field.ident { let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident); - let typ = self.tcx.node_types().get(&field.id).unwrap().to_string(); + let typ = self.tcx.tables().node_types.get(&field.id).unwrap().to_string(); let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon); filter!(self.span_utils, sub_span, field.span, None); Some(VariableData { @@ -313,7 +313,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: ast::Name, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let (qualname, parent_scope, vis, docs) = + let (qualname, parent_scope, decl_id, vis, docs) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { Some(NodeItem(item)) => { @@ -323,12 +323,19 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push_str(&rustc::hir::print::ty_to_string(&ty)); let trait_id = self.tcx.trait_id_of_impl(impl_id); + let mut decl_id = None; if let Some(def_id) = trait_id { result.push_str(" as "); result.push_str(&self.tcx.item_path_str(def_id)); + self.tcx.associated_items(def_id) + .find(|item| item.name == name) + .map(|item| decl_id = Some(item.def_id)); } result.push_str(">"); - (result, trait_id, From::from(&item.vis), docs_for_attrs(&item.attrs)) + + (result, trait_id, decl_id, + From::from(&item.vis), + docs_for_attrs(&item.attrs)) } _ => { span_bug!(span, @@ -351,7 +358,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match self.tcx.map.get_if_local(def_id) { Some(NodeItem(item)) => { (format!("::{}", self.tcx.item_path_str(def_id)), - Some(def_id), + Some(def_id), None, From::from(&item.vis), docs_for_attrs(&item.attrs)) } @@ -373,15 +380,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let qualname = format!("{}::{}", qualname, name); - let def_id = self.tcx.map.local_def_id(id); - let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_def_id| { - if new_def_id != def_id { - Some(new_def_id) - } else { - None - } - }); - let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); filter!(self.span_utils, sub_span, span, None); Some(FunctionData { @@ -418,7 +416,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_expr_data(&self, expr: &ast::Expr) -> Option { let hir_node = self.tcx.map.expect_expr(expr.id); - let ty = self.tcx.expr_ty_adjusted_opt(&hir_node); + let ty = self.tcx.tables().expr_ty_adjusted_opt(&hir_node); if ty.is_none() || ty.unwrap().sty == ty::TyError { return None; } @@ -432,7 +430,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { return None; } }; - match self.tcx.expr_ty_adjusted(&hir_node).sty { + match self.tcx.tables().expr_ty_adjusted(&hir_node).sty { ty::TyAdt(def, _) if !def.is_enum() => { let f = def.struct_variant().field_named(ident.node.name); let sub_span = self.span_utils.span_for_last_ident(expr.span); @@ -451,7 +449,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } ast::ExprKind::Struct(ref path, ..) => { - match self.tcx.expr_ty_adjusted(&hir_node).sty { + match self.tcx.tables().expr_ty_adjusted(&hir_node).sty { ty::TyAdt(def, _) if !def.is_enum() => { let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); @@ -472,8 +470,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } ast::ExprKind::MethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); - let method_id = self.tcx.tables.borrow().method_map[&method_call].def_id; - let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() { + let method_id = self.tcx.tables().method_map[&method_call].def_id; + let (def_id, decl_id) = match self.tcx.associated_item(method_id).container { ty::ImplContainer(_) => (Some(method_id), None), ty::TraitContainer(_) => (None, Some(method_id)), }; @@ -535,21 +533,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_for_meth_name(path.span); filter!(self.span_utils, sub_span, path.span, None); let def_id = if decl_id.is_local() { - let ti = self.tcx.impl_or_trait_item(decl_id); - match ti.container() { - ty::TraitContainer(def_id) => { - self.tcx - .trait_items(def_id) - .iter() - .find(|mr| mr.name() == ti.name() && self.trait_method_has_body(mr)) - .map(|mr| mr.def_id()) - } - ty::ImplContainer(def_id) => { - Some(*self.tcx.impl_or_trait_items(def_id).iter().find(|&&mr| { - self.tcx.impl_or_trait_item(mr).name() == ti.name() - }).unwrap()) - } - } + let ti = self.tcx.associated_item(decl_id); + self.tcx.associated_items(ti.container.id()) + .find(|item| item.name == ti.name && item.has_value) + .map(|item| item.def_id) } else { None }; @@ -578,24 +565,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Def::PrimTy(..) | Def::SelfTy(..) | Def::Label(..) | + Def::Macro(..) | Def::Err => None, } } - fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool { - let def_id = mr.def_id(); - if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { - let trait_item = self.tcx.map.expect_trait_item(node_id); - if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node { - true - } else { - false - } - } else { - false - } - } - pub fn get_field_ref_data(&self, field_ref: &ast::Field, variant: ty::VariantDef, @@ -759,7 +733,11 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String { for attr in attrs { if attr.name() == doc { if let Some(ref val) = attr.value_str() { - result.push_str(&strip_doc_comment_decoration(val)); + if attr.node.is_sugared_doc { + result.push_str(&strip_doc_comment_decoration(val)); + } else { + result.push_str(val); + } result.push('\n'); } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index e46bdbb5ccf4..ad8e0c1ee59f 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -636,7 +636,7 @@ fn link_natively(sess: &Session, { let mut linker = trans.linker_info.to_linker(&mut cmd, &sess); link_args(&mut *linker, sess, crate_type, tmpdir, - objects, out_filename, outputs); + objects, out_filename, outputs, trans); } cmd.args(&sess.target.target.options.late_link_args); for obj in &sess.target.target.options.post_link_objects { @@ -711,7 +711,8 @@ fn link_args(cmd: &mut Linker, tmpdir: &Path, objects: &[PathBuf], out_filename: &Path, - outputs: &OutputFilenames) { + outputs: &OutputFilenames, + trans: &CrateTranslation) { // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. @@ -726,6 +727,13 @@ fn link_args(cmd: &mut Linker, } cmd.output_filename(out_filename); + if crate_type == config::CrateTypeExecutable && + sess.target.target.options.is_like_windows { + if let Some(ref s) = trans.windows_subsystem { + cmd.subsystem(s); + } + } + // If we're building a dynamic library then some platforms need to make sure // that all symbols are exported correctly from the dynamic library. if crate_type != config::CrateTypeExecutable { diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 3222571a76e1..860903d259fe 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -92,6 +92,7 @@ pub trait Linker { fn whole_archives(&mut self); fn no_whole_archives(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); + fn subsystem(&mut self, subsystem: &str); } pub struct GnuLinker<'a> { @@ -294,6 +295,10 @@ impl<'a> Linker for GnuLinker<'a> { self.cmd.arg(arg); } + + fn subsystem(&mut self, subsystem: &str) { + self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem)); + } } pub struct MsvcLinker<'a> { @@ -441,6 +446,30 @@ impl<'a> Linker for MsvcLinker<'a> { arg.push(path); self.cmd.arg(&arg); } + + fn subsystem(&mut self, subsystem: &str) { + // Note that previous passes of the compiler validated this subsystem, + // so we just blindly pass it to the linker. + self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem)); + + // Windows has two subsystems we're interested in right now, the console + // and windows subsystems. These both implicitly have different entry + // points (starting symbols). The console entry point starts with + // `mainCRTStartup` and the windows entry point starts with + // `WinMainCRTStartup`. These entry points, defined in system libraries, + // will then later probe for either `main` or `WinMain`, respectively to + // start the application. + // + // In Rust we just always generate a `main` function so we want control + // to always start there, so we force the entry point on the windows + // subsystem to be `mainCRTStartup` to get everything booted up + // correctly. + // + // For more information see RFC #1665 + if subsystem == "windows" { + self.cmd.arg("/ENTRY:mainCRTStartup"); + } + } } fn exported_symbols(scx: &SharedCrateContext, diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 977ababbf568..d50669272f72 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -79,7 +79,7 @@ use type_::Type; use type_of; use value::Value; use Disr; -use util::nodemap::{NodeSet, FnvHashMap, FnvHashSet}; +use util::nodemap::{NodeSet, FxHashMap, FxHashSet}; use arena::TypedArena; use libc::c_uint; @@ -1196,6 +1196,9 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) { } let llfn = declare::declare_cfn(ccx, "main", llfty); + // `main` should respect same config for frame pointer elimination as rest of code + attributes::set_frame_pointer_elimination(ccx, llfn); + let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llfn, "top\0".as_ptr() as *const _) }; @@ -1315,7 +1318,7 @@ fn write_metadata(cx: &SharedCrateContext, fn internalize_symbols<'a, 'tcx>(sess: &Session, ccxs: &CrateContextList<'a, 'tcx>, symbol_map: &SymbolMap<'tcx>, - reachable: &FnvHashSet<&str>) { + reachable: &FxHashSet<&str>) { let scx = ccxs.shared(); let tcx = scx.tcx(); @@ -1329,7 +1332,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, // 'unsafe' because we are holding on to CStr's from the LLVM module within // this block. unsafe { - let mut referenced_somewhere = FnvHashSet(); + let mut referenced_somewhere = FxHashSet(); // Collect all symbols that need to stay externally visible because they // are referenced via a declaration in some other codegen unit. @@ -1350,7 +1353,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, // Also collect all symbols for which we cannot adjust linkage, because // it is fixed by some directive in the source code (e.g. #[no_mangle]). - let linkage_fixed_explicitly: FnvHashSet<_> = scx + let linkage_fixed_explicitly: FxHashSet<_> = scx .translation_items() .borrow() .iter() @@ -1611,7 +1614,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata: metadata, reachable: vec![], no_builtins: no_builtins, - linker_info: linker_info + linker_info: linker_info, + windows_subsystem: None, }; } @@ -1747,6 +1751,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols); + let subsystem = attr::first_attr_value_str_by_name(&krate.attrs, + "windows_subsystem"); + let windows_subsystem = subsystem.map(|subsystem| { + if subsystem != "windows" && subsystem != "console" { + tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ + `windows` and `console` are allowed", + subsystem)); + } + subsystem.to_string() + }); + CrateTranslation { modules: modules, metadata_module: metadata_module, @@ -1754,7 +1769,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata: metadata, reachable: reachable_symbols, no_builtins: no_builtins, - linker_info: linker_info + linker_info: linker_info, + windows_subsystem: windows_subsystem, } } @@ -1846,7 +1862,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a } if scx.sess().opts.debugging_opts.print_trans_items.is_some() { - let mut item_to_cgus = FnvHashMap(); + let mut item_to_cgus = FxHashMap(); for cgu in &codegen_units { for (&trans_item, &linkage) in cgu.items() { diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 8556e95903c1..0480bb82a998 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -19,7 +19,7 @@ use common::*; use machine::llalign_of_pref; use type_::Type; use value::Value; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use libc::{c_uint, c_char}; use std::borrow::Cow; @@ -62,7 +62,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Build version of path with cycles removed. // Pass 1: scan table mapping str -> rightmost pos. - let mut mm = FnvHashMap(); + let mut mm = FxHashMap(); let len = v.len(); let mut i = 0; while i < len { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index cd81d114eb77..ffb13a833a58 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -74,7 +74,7 @@ impl<'tcx> Callee<'tcx> { pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>, method_call: ty::MethodCall) -> Callee<'tcx> { - let method = bcx.tcx().tables.borrow().method_map[&method_call]; + let method = bcx.tcx().tables().method_map[&method_call]; Callee::method(bcx, method) } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 8348da9f7b7b..2c0ba36f3b41 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -211,7 +211,7 @@ use context::SharedCrateContext; use common::{fulfill_obligation, type_is_sized}; use glue::{self, DropGlueKind}; use monomorphize::{self, Instance}; -use util::nodemap::{FnvHashSet, FnvHashMap, DefIdMap}; +use util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; use trans_item::{TransItem, type_to_string, def_id_to_string}; @@ -228,7 +228,7 @@ pub struct InliningMap<'tcx> { // that are potentially inlined by LLVM into the source. // The two numbers in the tuple are the start (inclusive) and // end index (exclusive) within the `targets` vecs. - index: FnvHashMap, (usize, usize)>, + index: FxHashMap, (usize, usize)>, targets: Vec>, } @@ -236,7 +236,7 @@ impl<'tcx> InliningMap<'tcx> { fn new() -> InliningMap<'tcx> { InliningMap { - index: FnvHashMap(), + index: FxHashMap(), targets: Vec::new(), } } @@ -269,7 +269,7 @@ impl<'tcx> InliningMap<'tcx> { pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, mode: TransItemCollectionMode) - -> (FnvHashSet>, + -> (FxHashSet>, InliningMap<'tcx>) { // We are not tracking dependencies of this pass as it has to be re-executed // every time no matter what. @@ -277,7 +277,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 't let roots = collect_roots(scx, mode); debug!("Building translation item graph, beginning at roots"); - let mut visited = FnvHashSet(); + let mut visited = FxHashSet(); let mut recursion_depths = DefIdMap(); let mut inlining_map = InliningMap::new(); @@ -318,7 +318,7 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // Collect all monomorphized translation items reachable from `starting_point` fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, starting_point: TransItem<'tcx>, - visited: &mut FnvHashSet>, + visited: &mut FxHashSet>, recursion_depths: &mut DefIdMap, inlining_map: &mut InliningMap<'tcx>) { if !visited.insert(starting_point.clone()) { @@ -844,17 +844,12 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, param_substs); if let Some(trait_def_id) = scx.tcx().trait_of_item(fn_def_id) { - match scx.tcx().impl_or_trait_item(fn_def_id) { - ty::MethodTraitItem(ref method) => { - debug!(" => trait method, attempting to find impl"); - do_static_trait_method_dispatch(scx, - method, - trait_def_id, - fn_substs, - param_substs) - } - _ => bug!() - } + debug!(" => trait method, attempting to find impl"); + do_static_trait_method_dispatch(scx, + &scx.tcx().associated_item(fn_def_id), + trait_def_id, + fn_substs, + param_substs) } else { debug!(" => regular function"); // The function is not part of an impl or trait, no dispatching @@ -866,7 +861,7 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // Given a trait-method and substitution information, find out the actual // implementation of the trait method. fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - trait_method: &ty::Method, + trait_method: &ty::AssociatedItem, trait_id: DefId, callee_substs: &'tcx Substs<'tcx>, param_substs: &'tcx Substs<'tcx>) @@ -1082,10 +1077,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) => { if !generics.is_parameterized() { - let ty = { - let tables = self.scx.tcx().tables.borrow(); - tables.node_types[&item.id] - }; + let ty = self.scx.tcx().tables().node_types[&item.id]; if self.mode == TransItemCollectionMode::Eager { debug!("RootCollector: ADT drop-glue for {}", @@ -1182,15 +1174,15 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { let callee_substs = tcx.erase_regions(&trait_ref.substs); - let overridden_methods: FnvHashSet<_> = items.iter() - .map(|item| item.name) - .collect(); + let overridden_methods: FxHashSet<_> = items.iter() + .map(|item| item.name) + .collect(); for method in tcx.provided_trait_methods(trait_ref.def_id) { if overridden_methods.contains(&method.name) { continue; } - if !method.generics.types.is_empty() { + if !tcx.lookup_generics(method.def_id).types.is_empty() { continue; } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index fc75b1018ec3..264d4940c17f 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -32,7 +32,7 @@ use session::config::NoDebugInfo; use session::Session; use session::config; use symbol_map::SymbolMap; -use util::nodemap::{NodeSet, DefIdMap, FnvHashMap, FnvHashSet}; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; @@ -52,7 +52,7 @@ pub struct Stats { pub n_inlines: Cell, pub n_closures: Cell, pub n_llvm_insns: Cell, - pub llvm_insns: RefCell>, + pub llvm_insns: RefCell>, // (ident, llvm-instructions) pub fn_stats: RefCell >, } @@ -74,7 +74,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { use_dll_storage_attrs: bool, - translation_items: RefCell>>, + translation_items: RefCell>>, trait_cache: RefCell>>, project_cache: RefCell>>, } @@ -89,15 +89,15 @@ pub struct LocalCrateContext<'tcx> { previous_work_product: Option, tn: TypeNames, // FIXME: This seems to be largely unused. codegen_unit: CodegenUnit<'tcx>, - needs_unwind_cleanup_cache: RefCell, bool>>, - fn_pointer_shims: RefCell, ValueRef>>, - drop_glues: RefCell, (ValueRef, FnType)>>, + needs_unwind_cleanup_cache: RefCell, bool>>, + fn_pointer_shims: RefCell, ValueRef>>, + drop_glues: RefCell, (ValueRef, FnType)>>, /// Cache instances of monomorphic and polymorphic items - instances: RefCell, ValueRef>>, + instances: RefCell, ValueRef>>, /// Cache generated vtables - vtables: RefCell, ValueRef>>, + vtables: RefCell, ValueRef>>, /// Cache of constant strings, - const_cstr_cache: RefCell>, + const_cstr_cache: RefCell>, /// Reverse-direction for const ptrs cast from globals. /// Key is a ValueRef holding a *T, @@ -107,24 +107,24 @@ pub struct LocalCrateContext<'tcx> { /// when we ptrcast, and we have to ptrcast during translation /// of a [T] const because we form a slice, a (*T,usize) pair, not /// a pointer to an LLVM array type. Similar for trait objects. - const_unsized: RefCell>, + const_unsized: RefCell>, /// Cache of emitted const globals (value -> global) - const_globals: RefCell>, + const_globals: RefCell>, /// Cache of emitted const values - const_values: RefCell), ValueRef>>, + const_values: RefCell), ValueRef>>, /// Cache of external const values extern_const_values: RefCell>, /// Mapping from static definitions to their DefId's. - statics: RefCell>, + statics: RefCell>, - impl_method_cache: RefCell>, + impl_method_cache: RefCell>, /// Cache of closure wrappers for bare fn's. - closure_bare_wrapper_cache: RefCell>, + closure_bare_wrapper_cache: RefCell>, /// List of globals for static variables which need to be passed to the /// LLVM function ReplaceAllUsesWith (RAUW) when translation is complete. @@ -132,15 +132,15 @@ pub struct LocalCrateContext<'tcx> { /// to constants.) statics_to_rauw: RefCell>, - lltypes: RefCell, Type>>, - llsizingtypes: RefCell, Type>>, - type_hashcodes: RefCell, String>>, + lltypes: RefCell, Type>>, + llsizingtypes: RefCell, Type>>, + type_hashcodes: RefCell, String>>, int_type: Type, opaque_vec_type: Type, builder: BuilderRef_res, /// Holds the LLVM values for closure IDs. - closure_vals: RefCell, ValueRef>>, + closure_vals: RefCell, ValueRef>>, dbg_cx: Option>, @@ -148,7 +148,7 @@ pub struct LocalCrateContext<'tcx> { eh_unwind_resume: Cell>, rust_try_fn: Cell>, - intrinsics: RefCell>, + intrinsics: RefCell>, /// Number of LLVM instructions translated into this `LocalCrateContext`. /// This is used to perform some basic load-balancing to keep all LLVM @@ -502,12 +502,12 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { n_inlines: Cell::new(0), n_closures: Cell::new(0), n_llvm_insns: Cell::new(0), - llvm_insns: RefCell::new(FnvHashMap()), + llvm_insns: RefCell::new(FxHashMap()), fn_stats: RefCell::new(Vec::new()), }, check_overflow: check_overflow, use_dll_storage_attrs: use_dll_storage_attrs, - translation_items: RefCell::new(FnvHashSet()), + translation_items: RefCell::new(FxHashSet()), trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), } @@ -557,7 +557,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { self.use_dll_storage_attrs } - pub fn translation_items(&self) -> &RefCell>> { + pub fn translation_items(&self) -> &RefCell>> { &self.translation_items } @@ -612,32 +612,32 @@ impl<'tcx> LocalCrateContext<'tcx> { previous_work_product: previous_work_product, codegen_unit: codegen_unit, tn: TypeNames::new(), - needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()), - fn_pointer_shims: RefCell::new(FnvHashMap()), - drop_glues: RefCell::new(FnvHashMap()), - instances: RefCell::new(FnvHashMap()), - vtables: RefCell::new(FnvHashMap()), - const_cstr_cache: RefCell::new(FnvHashMap()), - const_unsized: RefCell::new(FnvHashMap()), - const_globals: RefCell::new(FnvHashMap()), - const_values: RefCell::new(FnvHashMap()), + needs_unwind_cleanup_cache: RefCell::new(FxHashMap()), + fn_pointer_shims: RefCell::new(FxHashMap()), + drop_glues: RefCell::new(FxHashMap()), + instances: RefCell::new(FxHashMap()), + vtables: RefCell::new(FxHashMap()), + const_cstr_cache: RefCell::new(FxHashMap()), + const_unsized: RefCell::new(FxHashMap()), + const_globals: RefCell::new(FxHashMap()), + const_values: RefCell::new(FxHashMap()), extern_const_values: RefCell::new(DefIdMap()), - statics: RefCell::new(FnvHashMap()), - impl_method_cache: RefCell::new(FnvHashMap()), - closure_bare_wrapper_cache: RefCell::new(FnvHashMap()), + statics: RefCell::new(FxHashMap()), + impl_method_cache: RefCell::new(FxHashMap()), + closure_bare_wrapper_cache: RefCell::new(FxHashMap()), statics_to_rauw: RefCell::new(Vec::new()), - lltypes: RefCell::new(FnvHashMap()), - llsizingtypes: RefCell::new(FnvHashMap()), - type_hashcodes: RefCell::new(FnvHashMap()), + lltypes: RefCell::new(FxHashMap()), + llsizingtypes: RefCell::new(FxHashMap()), + type_hashcodes: RefCell::new(FxHashMap()), int_type: Type::from_ref(ptr::null_mut()), opaque_vec_type: Type::from_ref(ptr::null_mut()), builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), - closure_vals: RefCell::new(FnvHashMap()), + closure_vals: RefCell::new(FxHashMap()), dbg_cx: dbg_cx, eh_personality: Cell::new(None), eh_unwind_resume: Cell::new(None), rust_try_fn: Cell::new(None), - intrinsics: RefCell::new(FnvHashMap()), + intrinsics: RefCell::new(FxHashMap()), n_llvm_insns: Cell::new(0), type_of_depth: Cell::new(0), symbol_map: symbol_map, @@ -794,16 +794,16 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.shared.link_meta } - pub fn needs_unwind_cleanup_cache(&self) -> &RefCell, bool>> { + pub fn needs_unwind_cleanup_cache(&self) -> &RefCell, bool>> { &self.local().needs_unwind_cleanup_cache } - pub fn fn_pointer_shims(&self) -> &RefCell, ValueRef>> { + pub fn fn_pointer_shims(&self) -> &RefCell, ValueRef>> { &self.local().fn_pointer_shims } pub fn drop_glues<'a>(&'a self) - -> &'a RefCell, (ValueRef, FnType)>> { + -> &'a RefCell, (ValueRef, FnType)>> { &self.local().drop_glues } @@ -815,28 +815,28 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.sess().cstore.defid_for_inlined_node(node_id) } - pub fn instances<'a>(&'a self) -> &'a RefCell, ValueRef>> { + pub fn instances<'a>(&'a self) -> &'a RefCell, ValueRef>> { &self.local().instances } - pub fn vtables<'a>(&'a self) -> &'a RefCell, ValueRef>> { + pub fn vtables<'a>(&'a self) -> &'a RefCell, ValueRef>> { &self.local().vtables } - pub fn const_cstr_cache<'a>(&'a self) -> &'a RefCell> { + pub fn const_cstr_cache<'a>(&'a self) -> &'a RefCell> { &self.local().const_cstr_cache } - pub fn const_unsized<'a>(&'a self) -> &'a RefCell> { + pub fn const_unsized<'a>(&'a self) -> &'a RefCell> { &self.local().const_unsized } - pub fn const_globals<'a>(&'a self) -> &'a RefCell> { + pub fn const_globals<'a>(&'a self) -> &'a RefCell> { &self.local().const_globals } - pub fn const_values<'a>(&'a self) -> &'a RefCell), - ValueRef>> { + pub fn const_values<'a>(&'a self) -> &'a RefCell), + ValueRef>> { &self.local().const_values } @@ -844,16 +844,16 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().extern_const_values } - pub fn statics<'a>(&'a self) -> &'a RefCell> { + pub fn statics<'a>(&'a self) -> &'a RefCell> { &self.local().statics } pub fn impl_method_cache<'a>(&'a self) - -> &'a RefCell> { + -> &'a RefCell> { &self.local().impl_method_cache } - pub fn closure_bare_wrapper_cache<'a>(&'a self) -> &'a RefCell> { + pub fn closure_bare_wrapper_cache<'a>(&'a self) -> &'a RefCell> { &self.local().closure_bare_wrapper_cache } @@ -861,15 +861,15 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().statics_to_rauw } - pub fn lltypes<'a>(&'a self) -> &'a RefCell, Type>> { + pub fn lltypes<'a>(&'a self) -> &'a RefCell, Type>> { &self.local().lltypes } - pub fn llsizingtypes<'a>(&'a self) -> &'a RefCell, Type>> { + pub fn llsizingtypes<'a>(&'a self) -> &'a RefCell, Type>> { &self.local().llsizingtypes } - pub fn type_hashcodes<'a>(&'a self) -> &'a RefCell, String>> { + pub fn type_hashcodes<'a>(&'a self) -> &'a RefCell, String>> { &self.local().type_hashcodes } @@ -885,7 +885,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local().opaque_vec_type } - pub fn closure_vals<'a>(&'a self) -> &'a RefCell, ValueRef>> { + pub fn closure_vals<'a>(&'a self) -> &'a RefCell, ValueRef>> { &self.local().closure_vals } @@ -905,7 +905,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().rust_try_fn } - fn intrinsics<'a>(&'a self) -> &'a RefCell> { + fn intrinsics<'a>(&'a self) -> &'a RefCell> { &self.local().intrinsics } @@ -958,7 +958,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &*self.local().symbol_map } - pub fn translation_items(&self) -> &RefCell>> { + pub fn translation_items(&self) -> &RefCell>> { &self.shared.translation_items } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 863aecc82443..e81461b66217 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -36,7 +36,7 @@ use common::CrateContext; use type_::Type; use rustc::ty::{self, AdtKind, Ty, layout}; use session::config; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use util::common::path2cstr; use libc::{c_uint, c_longlong}; @@ -84,20 +84,20 @@ pub struct TypeMap<'tcx> { // The UniqueTypeIds created so far unique_id_interner: Interner, // A map from UniqueTypeId to debuginfo metadata for that type. This is a 1:1 mapping. - unique_id_to_metadata: FnvHashMap, + unique_id_to_metadata: FxHashMap, // A map from types to debuginfo metadata. This is a N:1 mapping. - type_to_metadata: FnvHashMap, DIType>, + type_to_metadata: FxHashMap, DIType>, // A map from types to UniqueTypeId. This is a N:1 mapping. - type_to_unique_id: FnvHashMap, UniqueTypeId> + type_to_unique_id: FxHashMap, UniqueTypeId> } impl<'tcx> TypeMap<'tcx> { pub fn new() -> TypeMap<'tcx> { TypeMap { unique_id_interner: Interner::new(), - type_to_metadata: FnvHashMap(), - unique_id_to_metadata: FnvHashMap(), - type_to_unique_id: FnvHashMap(), + type_to_metadata: FxHashMap(), + unique_id_to_metadata: FxHashMap(), + type_to_unique_id: FxHashMap(), } } @@ -1765,7 +1765,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, }; let is_local_to_unit = is_node_local_to_unit(cx, node_id); - let variable_type = tcx.erase_regions(&tcx.node_id_to_type(node_id)); + let variable_type = tcx.erase_regions(&tcx.tables().node_id_to_type(node_id)); let type_metadata = type_metadata(cx, variable_type, span); let var_name = tcx.item_name(node_def_id).to_string(); let linkage_name = mangled_name_of_item(cx, node_def_id, ""); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 3bc5f4f3dbc4..62fb40cc389c 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -34,7 +34,7 @@ use monomorphize::{self, Instance}; use rustc::ty::{self, Ty}; use rustc::mir; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; -use util::nodemap::{DefIdMap, FnvHashMap, FnvHashSet}; +use util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; use libc::c_uint; use std::cell::{Cell, RefCell}; @@ -68,15 +68,15 @@ pub struct CrateDebugContext<'tcx> { llcontext: ContextRef, builder: DIBuilderRef, current_debug_location: Cell, - created_files: RefCell>, - created_enum_disr_types: RefCell>, + created_files: RefCell>, + created_enum_disr_types: RefCell>, type_map: RefCell>, namespace_map: RefCell>, // This collection is used to assert that composite types (structs, enums, // ...) have their members only set once: - composite_types_completed: RefCell>, + composite_types_completed: RefCell>, } impl<'tcx> CrateDebugContext<'tcx> { @@ -89,11 +89,11 @@ impl<'tcx> CrateDebugContext<'tcx> { llcontext: llcontext, builder: builder, current_debug_location: Cell::new(InternalDebugLocation::UnknownLocation), - created_files: RefCell::new(FnvHashMap()), - created_enum_disr_types: RefCell::new(FnvHashMap()), + created_files: RefCell::new(FxHashMap()), + created_enum_disr_types: RefCell::new(FxHashMap()), type_map: RefCell::new(TypeMap::new()), namespace_map: RefCell::new(DefIdMap()), - composite_types_completed: RefCell::new(FnvHashSet()), + composite_types_completed: RefCell::new(FxHashSet()), }; } } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 07acc54962b8..8ef7f04d4ee1 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -28,7 +28,7 @@ #![feature(cell_extras)] #![feature(const_fn)] #![feature(custom_attribute)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![allow(unused_attributes)] #![feature(libc)] #![feature(quote)] @@ -169,6 +169,7 @@ pub struct CrateTranslation { pub metadata: Vec, pub reachable: Vec, pub no_builtins: bool, + pub windows_subsystem: Option, pub linker_info: back::linker::LinkerInfo } diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index a934da12b9e3..e4d0533ec878 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -42,12 +42,6 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>, common::type_is_fat_ptr(bcx.tcx(), ty)); } else if common::type_is_imm_pair(bcx.ccx(), ty) { // We allow pairs and uses of any of their 2 fields. - } else if !analyzer.seen_assigned.contains(index) { - // No assignment has been seen, which means that - // either the local has been marked as lvalue - // already, or there is no possible initialization - // for the local, making any reads invalid. - // This is useful in weeding out dead temps. } else { // These sorts of types require an alloca. Note that // type_is_immediate() may *still* be true, particularly diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 8bf27b4babfc..b22bcf9825a2 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -29,7 +29,7 @@ use type_of; use glue; use type_::Type; -use rustc_data_structures::fnv::FnvHashMap; +use rustc_data_structures::fx::FxHashMap; use syntax::parse::token; use super::{MirContext, LocalRef}; @@ -144,7 +144,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { adt::trans_get_discr(bcx, ty, discr_lvalue.llval, None, true) ); - let mut bb_hist = FnvHashMap(); + let mut bb_hist = FxHashMap(); for target in targets { *bb_hist.entry(target).or_insert(0) += 1; } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 3d0d88976094..b8d346b11c13 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -248,13 +248,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref); if let traits::VtableImpl(vtable_impl) = vtable { let name = ccx.tcx().item_name(instance.def); - let ac = ccx.tcx().impl_or_trait_items(vtable_impl.impl_def_id) - .iter().filter_map(|&def_id| { - match ccx.tcx().impl_or_trait_item(def_id) { - ty::ConstTraitItem(ac) => Some(ac), - _ => None - } - }).find(|ic| ic.name == name); + let ac = ccx.tcx().associated_items(vtable_impl.impl_def_id) + .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); if let Some(ac) = ac { instance = Instance::new(ac.def_id, vtable_impl.substs); } diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 625b43c7d179..c9c12fb6d453 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -134,7 +134,7 @@ use symbol_map::SymbolMap; use syntax::ast::NodeId; use syntax::parse::token::{self, InternedString}; use trans_item::TransItem; -use util::nodemap::{FnvHashMap, FnvHashSet}; +use util::nodemap::{FxHashMap, FxHashSet}; pub enum PartitioningStrategy { /// Generate one codegen unit per source-level module. @@ -151,12 +151,12 @@ pub struct CodegenUnit<'tcx> { /// as well as the crate name and disambiguator. name: InternedString, - items: FnvHashMap, llvm::Linkage>, + items: FxHashMap, llvm::Linkage>, } impl<'tcx> CodegenUnit<'tcx> { pub fn new(name: InternedString, - items: FnvHashMap, llvm::Linkage>) + items: FxHashMap, llvm::Linkage>) -> Self { CodegenUnit { name: name, @@ -165,7 +165,7 @@ impl<'tcx> CodegenUnit<'tcx> { } pub fn empty(name: InternedString) -> Self { - Self::new(name, FnvHashMap()) + Self::new(name, FxHashMap()) } pub fn contains_item(&self, item: &TransItem<'tcx>) -> bool { @@ -176,7 +176,7 @@ impl<'tcx> CodegenUnit<'tcx> { &self.name } - pub fn items(&self) -> &FnvHashMap, llvm::Linkage> { + pub fn items(&self) -> &FxHashMap, llvm::Linkage> { &self.items } @@ -297,7 +297,7 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, struct PreInliningPartitioning<'tcx> { codegen_units: Vec>, - roots: FnvHashSet>, + roots: FxHashSet>, } struct PostInliningPartitioning<'tcx>(Vec>); @@ -308,8 +308,8 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, where I: Iterator> { let tcx = scx.tcx(); - let mut roots = FnvHashSet(); - let mut codegen_units = FnvHashMap(); + let mut roots = FxHashSet(); + let mut codegen_units = FxHashMap(); for trans_item in trans_items { let is_root = !trans_item.is_instantiated_only_on_demand(tcx); @@ -419,7 +419,7 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit for codegen_unit in &initial_partitioning.codegen_units[..] { // Collect all items that need to be available in this codegen unit - let mut reachable = FnvHashSet(); + let mut reachable = FxHashSet(); for root in codegen_unit.items.keys() { follow_inlining(*root, inlining_map, &mut reachable); } @@ -465,7 +465,7 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit fn follow_inlining<'tcx>(trans_item: TransItem<'tcx>, inlining_map: &InliningMap<'tcx>, - visited: &mut FnvHashSet>) { + visited: &mut FxHashSet>) { if !visited.insert(trans_item) { return; } diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs index 3faaa085dce1..c3e0ac1fee51 100644 --- a/src/librustc_trans/symbol_map.rs +++ b/src/librustc_trans/symbol_map.rs @@ -14,7 +14,7 @@ use rustc::ty::TyCtxt; use std::borrow::Cow; use syntax::codemap::Span; use trans_item::TransItem; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; // In the SymbolMap we collect the symbol names of all translation items of // the current crate. This map exists as a performance optimization. Symbol @@ -22,7 +22,7 @@ use util::nodemap::FnvHashMap; // Thus they could also always be recomputed if needed. pub struct SymbolMap<'tcx> { - index: FnvHashMap, (usize, usize)>, + index: FxHashMap, (usize, usize)>, arena: String, } @@ -78,7 +78,7 @@ impl<'tcx> SymbolMap<'tcx> { } let mut symbol_map = SymbolMap { - index: FnvHashMap(), + index: FxHashMap(), arena: String::with_capacity(1024), }; diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index 03a71827b473..2a6f79d3ed57 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -15,7 +15,7 @@ use llvm::{TypeRef, Bool, False, True, TypeKind}; use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128}; use context::CrateContext; -use util::nodemap::FnvHashMap; +use util::nodemap::FxHashMap; use syntax::ast; use rustc::ty::layout; @@ -325,13 +325,13 @@ impl Type { /* Memory-managed object interface to type handles. */ pub struct TypeNames { - named_types: RefCell>, + named_types: RefCell>, } impl TypeNames { pub fn new() -> TypeNames { TypeNames { - named_types: RefCell::new(FnvHashMap()) + named_types: RefCell::new(FxHashMap()) } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1aa502fc443e..513b4860d5e8 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -66,7 +66,7 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ElisionFailureInfo, ElidedLifetime}; use rscope::{AnonTypeScope, MaybeWithAnonTypes}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; -use util::nodemap::{NodeMap, FnvHashSet}; +use util::nodemap::{NodeMap, FxHashSet}; use std::cell::RefCell; use syntax::{abi, ast}; @@ -107,11 +107,6 @@ pub trait AstConv<'gcx, 'tcx> { fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId) -> Result>, ErrorReported>; - /// Returns true if the trait with id `trait_def_id` defines an - /// associated type with the name `name`. - fn trait_defines_associated_type_named(&self, trait_def_id: DefId, name: ast::Name) - -> bool; - /// Return an (optional) substitution to convert bound type parameters that /// are in scope into free ones. This function should only return Some /// within a fn body. @@ -569,7 +564,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut possible_implied_output_region = None; for input_type in input_tys.iter() { - let mut regions = FnvHashSet(); + let mut regions = FxHashSet(); let have_bound_regions = tcx.collect_regions(input_type, &mut regions); debug!("find_implied_output_regions: collected {:?} from {:?} \ @@ -831,6 +826,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Some(self_ty)) } + fn trait_defines_associated_type_named(&self, + trait_def_id: DefId, + assoc_name: ast::Name) + -> bool + { + self.tcx().associated_items(trait_def_id).any(|item| { + item.kind == ty::AssociatedKind::Type && item.name == assoc_name + }) + } + fn ast_type_binding_to_poly_projection_predicate( &self, path_id: ast::NodeId, @@ -1142,22 +1147,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { return tcx.types.err; } - let mut associated_types = FnvHashSet::default(); + let mut associated_types = FxHashSet::default(); for tr in traits::supertraits(tcx, principal) { - if let Some(trait_id) = tcx.map.as_local_node_id(tr.def_id()) { - use collect::trait_associated_type_names; - - associated_types.extend(trait_associated_type_names(tcx, trait_id) - .map(|name| (tr.def_id(), name))) - } else { - let trait_items = tcx.impl_or_trait_items(tr.def_id()); - associated_types.extend(trait_items.iter().filter_map(|&def_id| { - match tcx.impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => Some(item.name), - _ => None - } - }).map(|name| (tr.def_id(), name))); - } + associated_types.extend(tcx.associated_items(tr.def_id()) + .filter(|item| item.kind == ty::AssociatedKind::Type) + .map(|item| (tr.def_id(), item.name))); } for projection_bound in &projection_bounds { @@ -1260,14 +1254,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if bounds.len() > 1 { let spans = bounds.iter().map(|b| { - self.tcx().impl_or_trait_items(b.def_id()).iter() - .find(|&&def_id| { - match self.tcx().impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => item.name.as_str() == assoc_name, - _ => false - } + self.tcx().associated_items(b.def_id()).find(|item| { + item.kind == ty::AssociatedKind::Type && item.name.as_str() == assoc_name }) - .and_then(|&def_id| self.tcx().map.as_local_node_id(def_id)) + .and_then(|item| self.tcx().map.as_local_node_id(item.def_id)) .and_then(|node_id| self.tcx().map.opt_span(node_id)) }); @@ -1383,25 +1373,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_did = bound.0.def_id; let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name); - let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) { - // `ty::trait_items` used below requires information generated - // by type collection, which may be in progress at this point. - match tcx.map.expect_item(trait_id).node { - hir::ItemTrait(.., ref trait_items) => { - let item = trait_items.iter() - .find(|i| i.name == assoc_name) - .expect("missing associated type"); - tcx.map.local_def_id(item.id) - } - _ => bug!() - } - } else { - let trait_items = tcx.trait_items(trait_did); - let item = trait_items.iter().find(|i| i.name() == assoc_name); - item.expect("missing associated type").def_id() - }; - - (ty, Def::AssociatedTy(item_did)) + let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name); + (ty, Def::AssociatedTy(item.expect("missing associated type").def_id)) } fn qpath_to_ty(&self, @@ -1549,7 +1522,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.prohibit_type_params(base_segments); let impl_id = tcx.map.as_local_node_id(def_id).unwrap(); - let ty = tcx.node_id_to_type(impl_id); + let ty = tcx.tables().node_id_to_type(impl_id); if let Some(free_substs) = self.get_free_substs() { ty.subst(tcx, free_substs) } else { @@ -1694,13 +1667,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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, - anon_scope, - anon_scope); + let bare_fn_ty = self.ty_of_method_or_bare_fn(bf.unsafety, + bf.abi, + None, + &bf.decl, + anon_scope, + anon_scope); // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not wellformed. @@ -1842,7 +1814,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { sig: &hir::MethodSig, untransformed_self_ty: Ty<'tcx>, anon_scope: Option) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) { + -> &'tcx ty::BareFnTy<'tcx> { self.ty_of_method_or_bare_fn(sig.unsafety, sig.abi, Some(untransformed_self_ty), @@ -1857,7 +1829,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { decl: &hir::FnDecl, anon_scope: Option) -> &'tcx ty::BareFnTy<'tcx> { - self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope).0 + self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope) } fn ty_of_method_or_bare_fn(&self, @@ -1867,7 +1839,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { decl: &hir::FnDecl, arg_anon_scope: Option, ret_anon_scope: Option) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) + -> &'tcx ty::BareFnTy<'tcx> { debug!("ty_of_method_or_bare_fn"); @@ -1880,13 +1852,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // 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. - let (self_ty, explicit_self_category) = match (opt_untransformed_self_ty, decl.get_self()) { + let (self_ty, explicit_self) = match (opt_untransformed_self_ty, decl.get_self()) { (Some(untransformed_self_ty), Some(explicit_self)) => { let self_type = self.determine_self_type(&rb, untransformed_self_ty, &explicit_self); - (Some(self_type.0), self_type.1) + (Some(self_type), Some(ExplicitSelf::determine(untransformed_self_ty, self_type))) } - _ => (None, ty::ExplicitSelfCategory::Static), + _ => (None, None), }; // HACK(eddyb) replace the fake self type in the AST with the actual type. @@ -1901,8 +1873,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // 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 implied_output_region = match explicit_self_category { - ty::ExplicitSelfCategory::ByReference(region, _) => Ok(*region), + let implied_output_region = match explicit_self { + Some(ExplicitSelf::ByReference(region, _)) => Ok(*region), _ => { // `pat_to_string` is expensive and // `find_implied_output_region` only needs its result when @@ -1928,7 +1900,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("ty_of_method_or_bare_fn: input_tys={:?}", input_tys); debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty); - (self.tcx().mk_bare_fn(ty::BareFnTy { + self.tcx().mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: ty::Binder(ty::FnSig { @@ -1936,95 +1908,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { output: output_ty, variadic: decl.variadic }), - }), explicit_self_category) + }) } fn determine_self_type<'a>(&self, rscope: &RegionScope, untransformed_self_ty: Ty<'tcx>, explicit_self: &hir::ExplicitSelf) - -> (Ty<'tcx>, ty::ExplicitSelfCategory<'tcx>) + -> Ty<'tcx> { - return match explicit_self.node { - SelfKind::Value(..) => { - (untransformed_self_ty, ty::ExplicitSelfCategory::ByValue) - } + match explicit_self.node { + SelfKind::Value(..) => untransformed_self_ty, SelfKind::Region(ref lifetime, mutability) => { let region = self.opt_ast_region_to_region( rscope, explicit_self.span, lifetime); - (self.tcx().mk_ref(region, + self.tcx().mk_ref(region, ty::TypeAndMut { ty: untransformed_self_ty, mutbl: mutability - }), - ty::ExplicitSelfCategory::ByReference(region, mutability)) - } - SelfKind::Explicit(ref ast_type, _) => { - let explicit_type = self.ast_ty_to_ty(rscope, &ast_type); - - // We wish to (for now) categorize an explicit self - // declaration like `self: SomeType` into either `self`, - // `&self`, `&mut self`, or `Box`. We do this here - // by some simple pattern matching. A more precise check - // is done later in `check_method_self_type()`. - // - // Examples: - // - // ``` - // impl Foo for &T { - // // Legal declarations: - // fn method1(self: &&T); // ExplicitSelfCategory::ByReference - // fn method2(self: &T); // ExplicitSelfCategory::ByValue - // fn method3(self: Box<&T>); // ExplicitSelfCategory::ByBox - // - // // Invalid cases will be caught later by `check_method_self_type`: - // fn method_err1(self: &mut T); // ExplicitSelfCategory::ByReference - // } - // ``` - // - // To do the check we just count the number of "modifiers" - // on each type and compare them. If they are the same or - // the impl has more, we call it "by value". Otherwise, we - // look at the outermost modifier on the method decl and - // call it by-ref, by-box as appropriate. For method1, for - // example, the impl type has one modifier, but the method - // type has two, so we end up with - // ExplicitSelfCategory::ByReference. - - let impl_modifiers = count_modifiers(untransformed_self_ty); - let method_modifiers = count_modifiers(explicit_type); - - debug!("determine_explicit_self_category(self_info.untransformed_self_ty={:?} \ - explicit_type={:?} \ - modifiers=({},{})", - untransformed_self_ty, - explicit_type, - impl_modifiers, - method_modifiers); - - let category = if impl_modifiers >= method_modifiers { - ty::ExplicitSelfCategory::ByValue - } else { - match explicit_type.sty { - ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(r, mt.mutbl), - ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox, - _ => ty::ExplicitSelfCategory::ByValue, - } - }; - - (explicit_type, category) - } - }; - - fn count_modifiers(ty: Ty) -> usize { - match ty.sty { - ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1, - ty::TyBox(t) => count_modifiers(t) + 1, - _ => 0, + }) } + SelfKind::Explicit(ref ast_type, _) => self.ast_ty_to_ty(rscope, &ast_type) } } @@ -2334,3 +2241,64 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { vec } } + +pub enum ExplicitSelf<'tcx> { + ByValue, + ByReference(&'tcx ty::Region, hir::Mutability), + ByBox +} + +impl<'tcx> ExplicitSelf<'tcx> { + /// We wish to (for now) categorize an explicit self + /// declaration like `self: SomeType` into either `self`, + /// `&self`, `&mut self`, or `Box`. We do this here + /// by some simple pattern matching. A more precise check + /// is done later in `check_method_self_type()`. + /// + /// Examples: + /// + /// ``` + /// impl Foo for &T { + /// // Legal declarations: + /// fn method1(self: &&T); // ExplicitSelf::ByReference + /// fn method2(self: &T); // ExplicitSelf::ByValue + /// fn method3(self: Box<&T>); // ExplicitSelf::ByBox + /// + /// // Invalid cases will be caught later by `check_method_self_type`: + /// fn method_err1(self: &mut T); // ExplicitSelf::ByReference + /// } + /// ``` + /// + /// To do the check we just count the number of "modifiers" + /// on each type and compare them. If they are the same or + /// the impl has more, we call it "by value". Otherwise, we + /// look at the outermost modifier on the method decl and + /// call it by-ref, by-box as appropriate. For method1, for + /// example, the impl type has one modifier, but the method + /// type has two, so we end up with + /// ExplicitSelf::ByReference. + pub fn determine(untransformed_self_ty: Ty<'tcx>, + self_arg_ty: Ty<'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, + _ => 0, + } + } + + let impl_modifiers = count_modifiers(untransformed_self_ty); + let method_modifiers = count_modifiers(self_arg_ty); + + if impl_modifiers >= method_modifiers { + ExplicitSelf::ByValue + } else { + match self_arg_ty.sty { + ty::TyRef(r, mt) => ExplicitSelf::ByReference(r, mt.mutbl), + ty::TyBox(_) => ExplicitSelf::ByBox, + _ => ExplicitSelf::ByValue, + } + } + } +} diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index c842514227ca..ca630624cdb3 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -13,8 +13,8 @@ use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; -use check::{FnCtxt, Expectation}; -use util::nodemap::FnvHashMap; +use check::{FnCtxt, Expectation, Diverges}; +use util::nodemap::FxHashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::cmp; @@ -360,9 +360,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } true } -} -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_match(&self, expr: &'gcx hir::Expr, discrim: &'gcx hir::Expr, @@ -390,14 +388,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { discrim_ty = self.next_ty_var(); self.check_expr_has_type(discrim, discrim_ty); }; + let discrim_diverges = self.diverges.get(); + self.diverges.set(Diverges::Maybe); // Typecheck the patterns first, so that we get types for all the // bindings. - for arm in arms { + let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| { + let mut all_pats_diverge = Diverges::WarnedAlways; for p in &arm.pats { + self.diverges.set(Diverges::Maybe); self.check_pat(&p, discrim_ty); + all_pats_diverge &= self.diverges.get(); } - } + all_pats_diverge + }).collect(); // Now typecheck the blocks. // @@ -410,6 +414,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // type in that case) let expected = expected.adjust_for_branches(self); let mut result_ty = self.next_diverging_ty_var(); + let mut all_arms_diverge = Diverges::WarnedAlways; let coerce_first = match expected { // We don't coerce to `()` so that if the match expression is a // statement it's branches can have any consistent type. That allows @@ -422,11 +427,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => result_ty }; - for (i, arm) in arms.iter().enumerate() { + for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { if let Some(ref e) = arm.guard { + self.diverges.set(pats_diverge); self.check_expr_has_type(e, tcx.types.bool); } + + self.diverges.set(pats_diverge); let arm_ty = self.check_expr_with_expectation(&arm.body, expected); + all_arms_diverge &= self.diverges.get(); if result_ty.references_error() || arm_ty.references_error() { result_ty = tcx.types.err; @@ -476,11 +485,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; } + // We won't diverge unless the discriminant or all arms diverge. + self.diverges.set(discrim_diverges | all_arms_diverge); + result_ty } -} -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_pat_struct(&self, pat: &'gcx hir::Pat, path: &hir::Path, @@ -633,10 +643,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_map = variant.fields .iter() .map(|field| (field.name, field)) - .collect::>(); + .collect::>(); // Keep track of which fields have already appeared in the pattern. - let mut used_fields = FnvHashMap(); + let mut used_fields = FxHashMap(); // Typecheck each field. for &Spanned { node: ref field, span } in fields { diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index c5a21d7dd91c..7606a5b7a4d4 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -13,6 +13,7 @@ use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag}; use CrateCtxt; use hir::def::Def; use hir::def_id::{DefId, LOCAL_CRATE}; +use hir::print; use rustc::{infer, traits}; use rustc::ty::{self, LvaluePreference, Ty}; use syntax::parse::token; @@ -103,7 +104,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If the callee is a bare function or a closure, then we're all set. match self.structurally_resolved_type(callee_expr.span, adjusted_ty).sty { ty::TyFnDef(..) | ty::TyFnPtr(_) => { - self.write_autoderef_adjustment(callee_expr.id, autoderefs); + self.write_autoderef_adjustment(callee_expr.id, autoderefs, adjusted_ty); return Some(CallStep::Builtin); } @@ -194,15 +195,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let error_fn_sig; let fn_sig = match callee_ty.sty { - ty::TyFnDef(.., &ty::BareFnTy { ref sig, .. }) | - ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => sig, - _ => { - let mut err = self.type_error_struct(call_expr.span, - |actual| { - format!("expected function, found `{}`", - actual) - }, - callee_ty); + ty::TyFnDef(.., &ty::BareFnTy {ref sig, ..}) | + ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => sig, + ref t => { + let mut unit_variant = None; + if let &ty::TyAdt(adt_def, ..) = t { + if adt_def.is_enum() { + if let hir::ExprCall(ref expr, _) = call_expr.node { + unit_variant = Some(print::expr_to_string(expr)) + } + } + } + let mut err = if let Some(path) = unit_variant { + let mut err = self.type_error_struct(call_expr.span, |_| { + format!("`{}` is being called, but it is not a function", path) + }, callee_ty); + err.help(&format!("did you mean to write `{}`?", path)); + err + } else { + self.type_error_struct(call_expr.span, |actual| { + format!("expected function, found `{}`", actual) + }, callee_ty) + }; if let hir::ExprCall(ref expr, _) = call_expr.node { let tcx = self.tcx; diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d478f1092bd8..af834f3f84d4 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &hir::Expr, _capture: hir::CaptureClause, decl: &'gcx hir::FnDecl, - body: &'gcx hir::Block, + body: &'gcx hir::Expr, expected: Expectation<'tcx>) -> Ty<'tcx> { debug!("check_expr_closure(expr={:?},expected={:?})", @@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &hir::Expr, opt_kind: Option, decl: &'gcx hir::FnDecl, - body: &'gcx hir::Block, + body: &'gcx hir::Expr, expected_sig: Option>) -> Ty<'tcx> { let expr_def_id = self.tcx.map.local_def_id(expr.id); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index ccc944813ff1..16493412d690 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -65,10 +65,7 @@ use check::FnCtxt; use rustc::hir; use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace}; use rustc::traits::{self, ObligationCause}; -use rustc::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef}; -use rustc::ty::adjustment::{AutoPtr, AutoUnsafe, AdjustReifyFnPointer}; -use rustc::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; -use rustc::ty::adjustment::AdjustNeverToAny; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty}; use rustc::ty::fold::TypeFoldable; use rustc::ty::error::TypeError; @@ -93,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { } } -type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, AutoAdjustment<'tcx>)>; +type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, Adjust<'tcx>)>; fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, to_mutbl: hir::Mutability) @@ -144,12 +141,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { /// Synthesize an identity adjustment. fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> { - Ok((ty, - AdjustDerefRef(AutoDerefRef { - autoderefs: 0, - autoref: None, - unsize: None, - }))) + Ok((ty, Adjust::DerefRef { + autoderefs: 0, + autoref: None, + unsize: false, + })) } fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> @@ -166,7 +162,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } if a.is_never() { - return Ok((b, AdjustNeverToAny(b))); + return Ok((b, Adjust::NeverToAny)); } // Consider coercing the subtype to a DST @@ -396,17 +392,16 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::TyRef(r_borrow, _) => r_borrow, _ => span_bug!(span, "expected a ref type, got {:?}", ty), }; - let autoref = Some(AutoPtr(r_borrow, mt_b.mutbl)); + let autoref = Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)); debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}", ty, autoderefs, autoref); - Ok((ty, - AdjustDerefRef(AutoDerefRef { - autoderefs: autoderefs, - autoref: autoref, - unsize: None, - }))) + Ok((ty, Adjust::DerefRef { + autoderefs: autoderefs, + autoref: autoref, + unsize: false, + })) } @@ -437,11 +432,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let coercion = Coercion(self.origin.span()); let r_borrow = self.next_region_var(coercion); - (mt_a.ty, Some(AutoPtr(r_borrow, mt_b.mutbl))) + (mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl))) } (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; - (mt_a.ty, Some(AutoUnsafe(mt_b.mutbl))) + (mt_a.ty, Some(AutoBorrow::RawPtr(mt_b.mutbl))) } _ => (source, None), }; @@ -497,13 +492,13 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { *self.unsizing_obligations.borrow_mut() = leftover_predicates; - let adjustment = AutoDerefRef { + let adjustment = Adjust::DerefRef { autoderefs: if reborrow.is_some() { 1 } else { 0 }, autoref: reborrow, - unsize: Some(target), + unsize: true, }; debug!("Success, coerced with {:?}", adjustment); - Ok((target, AdjustDerefRef(adjustment))) + Ok((target, adjustment)) } fn coerce_from_safe_fn(&self, @@ -516,7 +511,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); return self.unify_and_identity(unsafe_a, b) - .map(|(ty, _)| (ty, AdjustUnsafeFnPointer)); + .map(|(ty, _)| (ty, Adjust::UnsafeFnPointer)); } _ => {} } @@ -555,7 +550,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::TyFnPtr(_) => { let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b) - .map(|(ty, _)| (ty, AdjustReifyFnPointer)) + .map(|(ty, _)| (ty, Adjust::ReifyFnPointer)) } _ => self.unify_and_identity(a, b), } @@ -585,17 +580,17 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_mutbls(mt_a.mutbl, mutbl_b)?; // Although references and unsafe ptrs have the same - // representation, we still register an AutoDerefRef so that + // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. Ok((ty, if is_ref { - AdjustDerefRef(AutoDerefRef { + Adjust::DerefRef { autoderefs: 1, - autoref: Some(AutoUnsafe(mutbl_b)), - unsize: None, - }) + autoref: Some(AutoBorrow::RawPtr(mutbl_b)), + unsize: false, + } } else if mt_a.mutbl != mutbl_b { - AdjustMutToConstPointer + Adjust::MutToConstPointer } else { noop })) @@ -606,24 +601,25 @@ fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) - -> CoerceResult<'tcx> + -> RelateResult<'tcx, Adjustment<'tcx>> where E: Fn() -> I, I: IntoIterator { - let (ty, adjustment) = indent(|| coerce.coerce(exprs, a, b))?; + let (ty, adjust) = indent(|| coerce.coerce(exprs, a, b))?; let fcx = coerce.fcx; - if let AdjustDerefRef(auto) = adjustment { - if auto.unsize.is_some() { - let mut obligations = coerce.unsizing_obligations.borrow_mut(); - for obligation in obligations.drain(..) { - fcx.register_predicate(obligation); - } + if let Adjust::DerefRef { unsize: true, .. } = adjust { + let mut obligations = coerce.unsizing_obligations.borrow_mut(); + for obligation in obligations.drain(..) { + fcx.register_predicate(obligation); } } - Ok((ty, adjustment)) + Ok(Adjustment { + kind: adjust, + target: ty + }) } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -641,17 +637,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span)); self.commit_if_ok(|_| { - let (ty, adjustment) = apply(&mut coerce, &|| Some(expr), source, target)?; + let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?; if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); match self.tables.borrow().adjustments.get(&expr.id) { None | - Some(&AdjustNeverToAny(..)) => (), + Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => (), _ => bug!("expr already has an adjustment on it!"), }; self.write_adjustment(expr.id, adjustment); } - Ok(ty) + Ok(adjustment.target) }) } @@ -705,12 +701,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Reify both sides and return the reified fn pointer type. + let fn_ptr = self.tcx.mk_fn_ptr(fty); for expr in exprs().into_iter().chain(Some(new)) { // No adjustments can produce a fn item, so this should never trip. assert!(!self.tables.borrow().adjustments.contains_key(&expr.id)); - self.write_adjustment(expr.id, AdjustReifyFnPointer); + self.write_adjustment(expr.id, Adjustment { + kind: Adjust::ReifyFnPointer, + target: fn_ptr + }); } - return Ok(self.tcx.mk_fn_ptr(fty)); + return Ok(fn_ptr); } _ => {} } @@ -724,11 +724,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !self.tables.borrow().adjustments.contains_key(&new.id) { let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty)); match result { - Ok((ty, adjustment)) => { + Ok(adjustment) => { if !adjustment.is_identity() { self.write_adjustment(new.id, adjustment); } - return Ok(ty); + return Ok(adjustment.target); } Err(e) => first_error = Some(e), } @@ -738,10 +738,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // This requires ensuring there are no coercions applied to *any* of the // previous expressions, other than noop reborrows (ignoring lifetimes). for expr in exprs() { - let noop = match self.tables.borrow().adjustments.get(&expr.id) { - Some(&AdjustDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(AutoPtr(_, mutbl_adj)), - unsize: None })) => { + let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| adj.kind) { + Some(Adjust::DerefRef { + autoderefs: 1, + autoref: Some(AutoBorrow::Ref(_, mutbl_adj)), + unsize: false + }) => { match self.node_ty(expr.id).sty { ty::TyRef(_, mt_orig) => { // Reborrow that we can safely ignore. @@ -750,7 +752,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false, } } - Some(&AdjustNeverToAny(_)) => true, + Some(Adjust::NeverToAny) => true, Some(_) => false, None => true, }; @@ -783,18 +785,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) } } - Ok((ty, adjustment)) => { + Ok(adjustment) => { if !adjustment.is_identity() { + let mut tables = self.tables.borrow_mut(); for expr in exprs() { - let previous = self.tables.borrow().adjustments.get(&expr.id).cloned(); - if let Some(AdjustNeverToAny(_)) = previous { - self.write_adjustment(expr.id, AdjustNeverToAny(ty)); - } else { - self.write_adjustment(expr.id, adjustment); + if let Some(&mut Adjustment { + kind: Adjust::NeverToAny, + ref mut target + }) = tables.adjustments.get_mut(&expr.id) { + *target = adjustment.target; + continue; } + tables.adjustments.insert(expr.id, adjustment); } } - Ok(ty) + Ok(adjustment.target) } } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 25e9f1f522c9..ffde940b3f48 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -8,19 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::free_region::FreeRegionMap; +use rustc::hir; use rustc::infer::{self, InferOk, TypeOrigin}; +use rustc::middle::free_region::FreeRegionMap; use rustc::ty; use rustc::traits::{self, Reveal}; use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{Subst, Substs}; use rustc::hir::{ImplItemKind, TraitItem_, Ty_}; +use rustc::util::common::ErrorReported; use syntax::ast; use syntax_pos::Span; use CrateCtxt; use super::assoc; +use super::{Inherited, FnCtxt}; +use astconv::ExplicitSelf; /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. @@ -34,193 +38,62 @@ use super::assoc; /// - impl_trait_ref: the TraitRef corresponding to the trait implementation pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, impl_m_body_id: ast::NodeId, - trait_m: &ty::Method<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>, - trait_item_span: Option) { - debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); - - debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}", + trait_m: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>, + trait_item_span: Option, + old_broken_mode: bool) { + debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); + if let Err(ErrorReported) = compare_self_type(ccx, + impl_m, + impl_m_span, + trait_m, + impl_trait_ref) { + return; + } + + if let Err(ErrorReported) = compare_number_of_generics(ccx, + impl_m, + impl_m_span, + trait_m, + trait_item_span) { + return; + } + + if let Err(ErrorReported) = compare_number_of_method_arguments(ccx, + impl_m, + impl_m_span, + trait_m, + trait_item_span) { + return; + } + + if let Err(ErrorReported) = compare_predicate_entailment(ccx, + impl_m, + impl_m_span, + impl_m_body_id, + trait_m, + impl_trait_ref, + old_broken_mode) { + return; + } +} + +fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_m: &ty::AssociatedItem, + impl_m_span: Span, + impl_m_body_id: ast::NodeId, + trait_m: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>, + old_broken_mode: bool) + -> Result<(), ErrorReported> { let tcx = ccx.tcx; - let trait_to_impl_substs = &impl_trait_ref.substs; - - // Try to give more informative error messages about self typing - // mismatches. Note that any mismatch will also be detected - // below, where we construct a canonical function type that - // includes the self parameter as a normal parameter. It's just - // that the error messages you get out of this code are a bit more - // inscrutable, particularly for cases where one method has no - // self. - match (&trait_m.explicit_self, &impl_m.explicit_self) { - (&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {} - (&ty::ExplicitSelfCategory::Static, _) => { - let mut err = struct_span_err!(tcx.sess, - impl_m_span, - E0185, - "method `{}` has a `{}` declaration in the impl, but \ - not in the trait", - trait_m.name, - impl_m.explicit_self); - err.span_label(impl_m_span, - &format!("`{}` used in impl", impl_m.explicit_self)); - if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { - err.span_label(span, - &format!("trait declared without `{}`", impl_m.explicit_self)); - } - err.emit(); - return; - } - (_, &ty::ExplicitSelfCategory::Static) => { - let mut err = struct_span_err!(tcx.sess, - impl_m_span, - E0186, - "method `{}` has a `{}` declaration in the trait, but \ - not in the impl", - trait_m.name, - trait_m.explicit_self); - err.span_label(impl_m_span, - &format!("expected `{}` in impl", trait_m.explicit_self)); - if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { - err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self)); - } - err.emit(); - return; - } - _ => { - // Let the type checker catch other errors below - } - } - - let num_impl_m_type_params = impl_m.generics.types.len(); - let num_trait_m_type_params = trait_m.generics.types.len(); - if num_impl_m_type_params != num_trait_m_type_params { - let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); - let span = match tcx.map.expect_impl_item(impl_m_node_id).node { - ImplItemKind::Method(ref impl_m_sig, _) => { - if impl_m_sig.generics.is_parameterized() { - impl_m_sig.generics.span - } else { - impl_m_span - } - } - _ => bug!("{:?} is not a method", impl_m), - }; - - let mut err = struct_span_err!(tcx.sess, - span, - E0049, - "method `{}` has {} type parameter{} but its trait \ - declaration has {} type parameter{}", - trait_m.name, - num_impl_m_type_params, - if num_impl_m_type_params == 1 { "" } else { "s" }, - num_trait_m_type_params, - if num_trait_m_type_params == 1 { - "" - } else { - "s" - }); - - let mut suffix = None; - - if let Some(span) = trait_item_span { - err.span_label(span, - &format!("expected {}", - &if num_trait_m_type_params != 1 { - format!("{} type parameters", num_trait_m_type_params) - } else { - format!("{} type parameter", num_trait_m_type_params) - })); - } else { - suffix = Some(format!(", expected {}", num_trait_m_type_params)); - } - - err.span_label(span, - &format!("found {}{}", - &if num_impl_m_type_params != 1 { - format!("{} type parameters", num_impl_m_type_params) - } else { - format!("1 type parameter") - }, - suffix.as_ref().map(|s| &s[..]).unwrap_or(""))); - - err.emit(); - - return; - } - - if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() { - let trait_number_args = trait_m.fty.sig.0.inputs.len(); - let impl_number_args = impl_m.fty.sig.0.inputs.len(); - let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id); - let trait_span = if let Some(trait_id) = trait_m_node_id { - match tcx.map.expect_trait_item(trait_id).node { - TraitItem_::MethodTraitItem(ref trait_m_sig, _) => { - if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 { - trait_number_args - 1 - } else { - 0 - }) { - Some(arg.pat.span) - } else { - trait_item_span - } - } - _ => bug!("{:?} is not a method", impl_m), - } - } else { - trait_item_span - }; - let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); - let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node { - ImplItemKind::Method(ref impl_m_sig, _) => { - if let Some(arg) = impl_m_sig.decl.inputs.get(if impl_number_args > 0 { - impl_number_args - 1 - } else { - 0 - }) { - arg.pat.span - } else { - impl_m_span - } - } - _ => bug!("{:?} is not a method", impl_m), - }; - let mut err = struct_span_err!(tcx.sess, - impl_span, - E0050, - "method `{}` has {} parameter{} but the declaration in \ - trait `{}` has {}", - trait_m.name, - impl_number_args, - if impl_number_args == 1 { "" } else { "s" }, - tcx.item_path_str(trait_m.def_id), - trait_number_args); - if let Some(trait_span) = trait_span { - err.span_label(trait_span, - &format!("trait requires {}", - &if trait_number_args != 1 { - format!("{} parameters", trait_number_args) - } else { - format!("{} parameter", trait_number_args) - })); - } - err.span_label(impl_span, - &format!("expected {}, found {}", - &if trait_number_args != 1 { - format!("{} parameters", trait_number_args) - } else { - format!("{} parameter", trait_number_args) - }, - impl_number_args)); - err.emit(); - return; - } + let trait_to_impl_substs = impl_trait_ref.substs; // This code is best explained by example. Consider a trait: // @@ -295,63 +168,66 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Create mapping from trait to skolemized. let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx, - impl_m.container_id(), + impl_m.container.id(), trait_to_impl_substs.subst(tcx, impl_to_skol_substs)); debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs); - // Check region bounds. FIXME(@jroesch) refactor this away when removing - // ParamBounds. - if !check_region_bounds_on_impl_method(ccx, - impl_m_span, - impl_m, - &trait_m.generics, - &impl_m.generics, - trait_to_skol_substs, - impl_to_skol_substs) { - return; - } + let impl_m_generics = tcx.lookup_generics(impl_m.def_id); + let trait_m_generics = tcx.lookup_generics(trait_m.def_id); + let impl_m_predicates = tcx.lookup_predicates(impl_m.def_id); + let trait_m_predicates = tcx.lookup_predicates(trait_m.def_id); - tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|mut infcx| { - let mut fulfillment_cx = traits::FulfillmentContext::new(); + // Check region bounds. + check_region_bounds_on_impl_method(ccx, + impl_m_span, + impl_m, + &trait_m_generics, + &impl_m_generics, + trait_to_skol_substs, + impl_to_skol_substs)?; - // Create obligations for each predicate declared by the impl - // definition in the context of the trait's parameter - // environment. We can't just use `impl_env.caller_bounds`, - // however, because we want to replace all late-bound regions with - // region variables. - let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap()); - let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); + // Create obligations for each predicate declared by the impl + // definition in the context of the trait's parameter + // environment. We can't just use `impl_env.caller_bounds`, + // however, because we want to replace all late-bound regions with + // region variables. + let impl_predicates = tcx.lookup_predicates(impl_m_predicates.parent.unwrap()); + let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); - debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); + debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); - // This is the only tricky bit of the new way we check implementation methods - // We need to build a set of predicates where only the method-level bounds - // are from the trait and we assume all other bounds from the implementation - // to be previously satisfied. - // - // We then register the obligations from the impl_m and check to see - // if all constraints hold. - hybrid_preds.predicates - .extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); + // This is the only tricky bit of the new way we check implementation methods + // We need to build a set of predicates where only the method-level bounds + // are from the trait and we assume all other bounds from the implementation + // to be previously satisfied. + // + // We then register the obligations from the impl_m and check to see + // if all constraints hold. + hybrid_preds.predicates + .extend(trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); - // Construct trait parameter environment and then shift it into the skolemized viewpoint. - // The key step here is to update the caller_bounds's predicates to be - // the new hybrid bounds we computed. - let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id); - let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates); - let trait_param_env = - traits::normalize_param_env_or_error(tcx, trait_param_env, normalize_cause.clone()); - // FIXME(@jroesch) this seems ugly, but is a temporary change - infcx.parameter_environment = trait_param_env; + // Construct trait parameter environment and then shift it into the skolemized viewpoint. + // The key step here is to update the caller_bounds's predicates to be + // the new hybrid bounds we computed. + let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id); + let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates); + let trait_param_env = traits::normalize_param_env_or_error(tcx, + trait_param_env, + normalize_cause.clone()); + + tcx.infer_ctxt(None, Some(trait_param_env), Reveal::NotSpecializable).enter(|infcx| { + let inh = Inherited::new(ccx, infcx); + let infcx = &inh.infcx; + let fulfillment_cx = &inh.fulfillment_cx; debug!("compare_impl_method: caller_bounds={:?}", infcx.parameter_environment.caller_bounds); let mut selcx = traits::SelectionContext::new(&infcx); - let impl_m_own_bounds = impl_m.predicates.instantiate_own(tcx, impl_to_skol_substs); + let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs); let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, infer::HigherRankedType, &ty::Binder(impl_m_own_bounds.predicates)); @@ -362,10 +238,15 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let cause = traits::ObligationCause { span: impl_m_span, body_id: impl_m_body_id, - code: traits::ObligationCauseCode::CompareImplMethodObligation, + code: traits::ObligationCauseCode::CompareImplMethodObligation { + item_name: impl_m.name, + impl_item_def_id: impl_m.def_id, + trait_item_def_id: trait_m.def_id, + lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None }, + }, }; - fulfillment_cx.register_predicate_obligation( + fulfillment_cx.borrow_mut().register_predicate_obligation( &infcx, traits::Obligation::new(cause, predicate)); } @@ -387,39 +268,60 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let tcx = infcx.tcx; let origin = TypeOrigin::MethodCompatCheck(impl_m_span); - let (impl_sig, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, - infer::HigherRankedType, - &impl_m.fty.sig); - let impl_sig = impl_sig.subst(tcx, impl_to_skol_substs); - let impl_sig = assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_m_span, - impl_m_body_id, - &impl_sig); + let m_fty = |method: &ty::AssociatedItem| { + match tcx.lookup_item_type(method.def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + } + }; + let impl_m_fty = m_fty(impl_m); + let trait_m_fty = m_fty(trait_m); + + let (impl_sig, _) = + infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, + infer::HigherRankedType, + &impl_m_fty.sig); + let impl_sig = + impl_sig.subst(tcx, impl_to_skol_substs); + let impl_sig = + assoc::normalize_associated_types_in(&infcx, + &mut fulfillment_cx.borrow_mut(), + impl_m_span, + impl_m_body_id, + &impl_sig); let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: impl_m.fty.unsafety, - abi: impl_m.fty.abi, + unsafety: impl_m_fty.unsafety, + abi: impl_m_fty.abi, sig: ty::Binder(impl_sig.clone()), })); debug!("compare_impl_method: impl_fty={:?}", impl_fty); - let trait_sig = tcx.liberate_late_bound_regions(infcx.parameter_environment.free_id_outlive, - &trait_m.fty.sig); - let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs); - let trait_sig = assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_m_span, - impl_m_body_id, - &trait_sig); + let trait_sig = tcx.liberate_late_bound_regions( + infcx.parameter_environment.free_id_outlive, + &trait_m_fty.sig); + let trait_sig = + trait_sig.subst(tcx, trait_to_skol_substs); + let trait_sig = + assoc::normalize_associated_types_in(&infcx, + &mut fulfillment_cx.borrow_mut(), + impl_m_span, + impl_m_body_id, + &trait_sig); let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: trait_m.fty.unsafety, - abi: trait_m.fty.abi, + unsafety: trait_m_fty.unsafety, + abi: trait_m_fty.abi, sig: ty::Binder(trait_sig.clone()), })); debug!("compare_impl_method: trait_fty={:?}", trait_fty); - if let Err(terr) = infcx.sub_types(false, origin, impl_fty, trait_fty) { + let sub_result = infcx.sub_types(false, origin, impl_fty, trait_fty) + .map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }); + + if let Err(terr) = sub_result { debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); @@ -449,178 +351,410 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, })), &terr); diag.emit(); - return; + return Err(ErrorReported); } // Check that all obligations are satisfied by the implementation's // version. - if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) { + if let Err(ref errors) = fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { infcx.report_fulfillment_errors(errors); - return; + return Err(ErrorReported); } // Finally, resolve all regions. This catches wily misuses of - // lifetime parameters. We have to build up a plausible lifetime - // environment based on what we find in the trait. We could also - // include the obligations derived from the method argument types, - // but I don't think it's necessary -- after all, those are still - // in effect when type-checking the body, and all the - // where-clauses in the header etc should be implied by the trait - // anyway, so it shouldn't be needed there either. Anyway, we can - // always add more relations later (it's backwards compat). - let mut free_regions = FreeRegionMap::new(); - free_regions.relate_free_regions_from_predicates( - &infcx.parameter_environment.caller_bounds); - - infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); - }); - - fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - span: Span, - impl_m: &ty::Method<'tcx>, - trait_generics: &ty::Generics<'tcx>, - impl_generics: &ty::Generics<'tcx>, - trait_to_skol_substs: &Substs<'tcx>, - impl_to_skol_substs: &Substs<'tcx>) - -> bool { - - let trait_params = &trait_generics.regions[..]; - let impl_params = &impl_generics.regions[..]; - - debug!("check_region_bounds_on_impl_method: \ - trait_generics={:?} \ - impl_generics={:?} \ - trait_to_skol_substs={:?} \ - impl_to_skol_substs={:?}", - trait_generics, - impl_generics, - trait_to_skol_substs, - impl_to_skol_substs); - - // Must have same number of early-bound lifetime parameters. - // Unfortunately, if the user screws up the bounds, then this - // will change classification between early and late. E.g., - // if in trait we have `<'a,'b:'a>`, and in impl we just have - // `<'a,'b>`, then we have 2 early-bound lifetime parameters - // in trait but 0 in the impl. But if we report "expected 2 - // but found 0" it's confusing, because it looks like there - // are zero. Since I don't quite know how to phrase things at - // the moment, give a kind of vague error message. - if trait_params.len() != impl_params.len() { - struct_span_err!(ccx.tcx.sess, - span, - E0195, - "lifetime parameters or bounds on method `{}` do not match the \ - trait declaration", - impl_m.name) - .span_label(span, &format!("lifetimes do not match trait")) - .emit(); - return false; + // lifetime parameters. + if old_broken_mode { + // FIXME(#18937) -- this is how the code used to + // work. This is buggy because the fulfillment cx creates + // region obligations that get overlooked. The right + // thing to do is the code below. But we keep this old + // pass around temporarily. + let mut free_regions = FreeRegionMap::new(); + free_regions.relate_free_regions_from_predicates( + &infcx.parameter_environment.caller_bounds); + infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id); + } else { + let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id); + fcx.regionck_item(impl_m_body_id, impl_m_span, &[]); } - return true; + Ok(()) + }) +} + +fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + span: Span, + impl_m: &ty::AssociatedItem, + trait_generics: &ty::Generics<'tcx>, + impl_generics: &ty::Generics<'tcx>, + trait_to_skol_substs: &Substs<'tcx>, + impl_to_skol_substs: &Substs<'tcx>) + -> Result<(), ErrorReported> { + let trait_params = &trait_generics.regions[..]; + let impl_params = &impl_generics.regions[..]; + + debug!("check_region_bounds_on_impl_method: \ + trait_generics={:?} \ + impl_generics={:?} \ + trait_to_skol_substs={:?} \ + impl_to_skol_substs={:?}", + trait_generics, + impl_generics, + trait_to_skol_substs, + impl_to_skol_substs); + + // Must have same number of early-bound lifetime parameters. + // Unfortunately, if the user screws up the bounds, then this + // will change classification between early and late. E.g., + // if in trait we have `<'a,'b:'a>`, and in impl we just have + // `<'a,'b>`, then we have 2 early-bound lifetime parameters + // in trait but 0 in the impl. But if we report "expected 2 + // but found 0" it's confusing, because it looks like there + // are zero. Since I don't quite know how to phrase things at + // the moment, give a kind of vague error message. + if trait_params.len() != impl_params.len() { + struct_span_err!(ccx.tcx.sess, + span, + E0195, + "lifetime parameters or bounds on method `{}` do not match the \ + trait declaration", + impl_m.name) + .span_label(span, &format!("lifetimes do not match trait")) + .emit(); + return Err(ErrorReported); } - fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, - terr: &TypeError, - origin: TypeOrigin, - impl_m: &ty::Method, - impl_sig: ty::FnSig<'tcx>, - trait_m: &ty::Method, - trait_sig: ty::FnSig<'tcx>) - -> (Span, Option) { - let tcx = infcx.tcx; - let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); - let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node { - ImplItemKind::Method(ref impl_m_sig, _) => { - (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()) - } - _ => bug!("{:?} is not a method", impl_m), - }; + return Ok(()); +} - match *terr { - TypeError::Mutability => { - if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { - let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { +fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, + terr: &TypeError, + origin: TypeOrigin, + impl_m: &ty::AssociatedItem, + impl_sig: ty::FnSig<'tcx>, + trait_m: &ty::AssociatedItem, + trait_sig: ty::FnSig<'tcx>) + -> (Span, Option) { + let tcx = infcx.tcx; + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => { + (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()) + } + _ => bug!("{:?} is not a method", impl_m), + }; + + match *terr { + TypeError::Mutability => { + if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { + let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => { + trait_m_sig.decl.inputs.iter() + } + _ => bug!("{:?} is not a MethodTraitItem", trait_m), + }; + + impl_m_iter.zip(trait_m_iter) + .find(|&(ref impl_arg, ref trait_arg)| { + match (&impl_arg.ty.node, &trait_arg.ty.node) { + (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) | + (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => { + impl_mt.mutbl != trait_mt.mutbl + } + _ => false, + } + }) + .map(|(ref impl_arg, ref trait_arg)| { + match (impl_arg.to_self(), trait_arg.to_self()) { + (Some(impl_self), Some(trait_self)) => { + (impl_self.span, Some(trait_self.span)) + } + (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)), + _ => { + bug!("impl and trait fns have different first args, impl: \ + {:?}, trait: {:?}", + impl_arg, + trait_arg) + } + } + }) + .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id))) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + } + TypeError::Sorts(ExpectedFound { .. }) => { + if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { + let (trait_m_output, trait_m_iter) = + match tcx.map.expect_trait_item(trait_m_node_id).node { TraitItem_::MethodTraitItem(ref trait_m_sig, _) => { - trait_m_sig.decl.inputs.iter() + (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()) } _ => bug!("{:?} is not a MethodTraitItem", trait_m), }; - impl_m_iter.zip(trait_m_iter) - .find(|&(ref impl_arg, ref trait_arg)| { - match (&impl_arg.ty.node, &trait_arg.ty.node) { - (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) | - (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => { - impl_mt.mutbl != trait_mt.mutbl - } - _ => false, - } - }) - .map(|(ref impl_arg, ref trait_arg)| { - match (impl_arg.to_self(), trait_arg.to_self()) { - (Some(impl_self), Some(trait_self)) => { - (impl_self.span, Some(trait_self.span)) - } - (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)), - _ => { - bug!("impl and trait fns have different first args, impl: \ - {:?}, trait: {:?}", - impl_arg, - trait_arg) - } - } - }) - .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id))) - } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) - } + let impl_iter = impl_sig.inputs.iter(); + let trait_iter = trait_sig.inputs.iter(); + impl_iter.zip(trait_iter) + .zip(impl_m_iter) + .zip(trait_m_iter) + .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| { + match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) { + Ok(_) => None, + Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))), + } + }) + .next() + .unwrap_or_else(|| { + if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output) + .is_err() { + (impl_m_output.span(), Some(trait_m_output.span())) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) + } + }) + } else { + (origin.span(), tcx.map.span_if_local(trait_m.def_id)) } - TypeError::Sorts(ExpectedFound { .. }) => { - if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) { - let (trait_m_output, trait_m_iter) = - match tcx.map.expect_trait_item(trait_m_node_id).node { - TraitItem_::MethodTraitItem(ref trait_m_sig, _) => { - (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()) - } - _ => bug!("{:?} is not a MethodTraitItem", trait_m), - }; - - let impl_iter = impl_sig.inputs.iter(); - let trait_iter = trait_sig.inputs.iter(); - impl_iter.zip(trait_iter) - .zip(impl_m_iter) - .zip(trait_m_iter) - .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| { - match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) { - Ok(_) => None, - Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))), - } - }) - .next() - .unwrap_or_else(|| { - if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output) - .is_err() { - (impl_m_output.span(), Some(trait_m_output.span())) - } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) - } - }) - } else { - (origin.span(), tcx.map.span_if_local(trait_m.def_id)) - } - } - _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)), } + _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)), } } +fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_m: &ty::AssociatedItem, + impl_m_span: Span, + trait_m: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>) + -> Result<(), ErrorReported> +{ + let tcx = ccx.tcx; + // Try to give more informative error messages about self typing + // mismatches. Note that any mismatch will also be detected + // below, where we construct a canonical function type that + // includes the self parameter as a normal parameter. It's just + // that the error messages you get out of this code are a bit more + // inscrutable, particularly for cases where one method has no + // self. + + let self_string = |method: &ty::AssociatedItem| { + let untransformed_self_ty = match method.container { + ty::ImplContainer(_) => impl_trait_ref.self_ty(), + ty::TraitContainer(_) => tcx.mk_self_type() + }; + let method_ty = tcx.lookup_item_type(method.def_id).ty; + let self_arg_ty = *method_ty.fn_sig().input(0).skip_binder(); + match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) { + ExplicitSelf::ByValue => "self".to_string(), + ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_string(), + ExplicitSelf::ByReference(_, hir::MutMutable) => "&mut self".to_string(), + _ => format!("self: {}", self_arg_ty) + } + }; + + match (trait_m.method_has_self_argument, impl_m.method_has_self_argument) { + (false, false) | (true, true) => {} + + (false, true) => { + let self_descr = self_string(impl_m); + let mut err = struct_span_err!(tcx.sess, + impl_m_span, + E0185, + "method `{}` has a `{}` declaration in the impl, but \ + not in the trait", + trait_m.name, + self_descr); + err.span_label(impl_m_span, &format!("`{}` used in impl", self_descr)); + if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { + err.span_label(span, &format!("trait declared without `{}`", self_descr)); + } + err.emit(); + return Err(ErrorReported); + } + + (true, false) => { + let self_descr = self_string(trait_m); + let mut err = struct_span_err!(tcx.sess, + impl_m_span, + E0186, + "method `{}` has a `{}` declaration in the trait, but \ + not in the impl", + trait_m.name, + self_descr); + err.span_label(impl_m_span, + &format!("expected `{}` in impl", self_descr)); + if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { + err.span_label(span, &format!("`{}` used in trait", self_descr)); + } + err.emit(); + return Err(ErrorReported); + } + } + + Ok(()) +} + +fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_m: &ty::AssociatedItem, + impl_m_span: Span, + trait_m: &ty::AssociatedItem, + trait_item_span: Option) + -> Result<(), ErrorReported> { + let tcx = ccx.tcx; + let impl_m_generics = tcx.lookup_generics(impl_m.def_id); + let trait_m_generics = tcx.lookup_generics(trait_m.def_id); + let num_impl_m_type_params = impl_m_generics.types.len(); + let num_trait_m_type_params = trait_m_generics.types.len(); + if num_impl_m_type_params != num_trait_m_type_params { + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let span = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => { + if impl_m_sig.generics.is_parameterized() { + impl_m_sig.generics.span + } else { + impl_m_span + } + } + _ => bug!("{:?} is not a method", impl_m), + }; + + let mut err = struct_span_err!(tcx.sess, + span, + E0049, + "method `{}` has {} type parameter{} but its trait \ + declaration has {} type parameter{}", + trait_m.name, + num_impl_m_type_params, + if num_impl_m_type_params == 1 { "" } else { "s" }, + num_trait_m_type_params, + if num_trait_m_type_params == 1 { + "" + } else { + "s" + }); + + let mut suffix = None; + + if let Some(span) = trait_item_span { + err.span_label(span, + &format!("expected {}", + &if num_trait_m_type_params != 1 { + format!("{} type parameters", num_trait_m_type_params) + } else { + format!("{} type parameter", num_trait_m_type_params) + })); + } else { + suffix = Some(format!(", expected {}", num_trait_m_type_params)); + } + + err.span_label(span, + &format!("found {}{}", + &if num_impl_m_type_params != 1 { + format!("{} type parameters", num_impl_m_type_params) + } else { + format!("1 type parameter") + }, + suffix.as_ref().map(|s| &s[..]).unwrap_or(""))); + + err.emit(); + + return Err(ErrorReported); + } + + Ok(()) +} + +fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + impl_m: &ty::AssociatedItem, + impl_m_span: Span, + trait_m: &ty::AssociatedItem, + trait_item_span: Option) + -> Result<(), ErrorReported> { + let tcx = ccx.tcx; + let m_fty = |method: &ty::AssociatedItem| { + match tcx.lookup_item_type(method.def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + } + }; + let impl_m_fty = m_fty(impl_m); + let trait_m_fty = m_fty(trait_m); + if impl_m_fty.sig.0.inputs.len() != trait_m_fty.sig.0.inputs.len() { + let trait_number_args = trait_m_fty.sig.0.inputs.len(); + let impl_number_args = impl_m_fty.sig.0.inputs.len(); + let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id); + let trait_span = if let Some(trait_id) = trait_m_node_id { + match tcx.map.expect_trait_item(trait_id).node { + TraitItem_::MethodTraitItem(ref trait_m_sig, _) => { + if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 { + trait_number_args - 1 + } else { + 0 + }) { + Some(arg.pat.span) + } else { + trait_item_span + } + } + _ => bug!("{:?} is not a method", impl_m), + } + } else { + trait_item_span + }; + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => { + if let Some(arg) = impl_m_sig.decl.inputs.get(if impl_number_args > 0 { + impl_number_args - 1 + } else { + 0 + }) { + arg.pat.span + } else { + impl_m_span + } + } + _ => bug!("{:?} is not a method", impl_m), + }; + let mut err = struct_span_err!(tcx.sess, + impl_span, + E0050, + "method `{}` has {} parameter{} but the declaration in \ + trait `{}` has {}", + trait_m.name, + impl_number_args, + if impl_number_args == 1 { "" } else { "s" }, + tcx.item_path_str(trait_m.def_id), + trait_number_args); + if let Some(trait_span) = trait_span { + err.span_label(trait_span, + &format!("trait requires {}", + &if trait_number_args != 1 { + format!("{} parameters", trait_number_args) + } else { + format!("{} parameter", trait_number_args) + })); + } + err.span_label(impl_span, + &format!("expected {}, found {}", + &if trait_number_args != 1 { + format!("{} parameters", trait_number_args) + } else { + format!("{} parameter", trait_number_args) + }, + impl_number_args)); + err.emit(); + return Err(ErrorReported); + } + + Ok(()) +} + pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_c: &ty::AssociatedConst<'tcx>, + impl_c: &ty::AssociatedItem, impl_c_span: Span, - trait_c: &ty::AssociatedConst<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>) { + trait_c: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>) { debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); let tcx = ccx.tcx; @@ -632,7 +766,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // because we shouldn't really have to deal with lifetimes or // predicates. In fact some of this should probably be put into // shared functions because of DRY violations... - let trait_to_impl_substs = &impl_trait_ref.substs; + let trait_to_impl_substs = impl_trait_ref.substs; // Create a parameter environment that represents the implementation's // method. @@ -651,8 +785,8 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_to_skol_substs); // Compute skolemized form of impl and trait const tys. - let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs); - let trait_ty = trait_c.ty.subst(tcx, trait_to_skol_substs); + let impl_ty = tcx.lookup_item_type(impl_c.def_id).ty.subst(tcx, impl_to_skol_substs); + let trait_ty = tcx.lookup_item_type(trait_c.def_id).ty.subst(tcx, trait_to_skol_substs); let mut origin = TypeOrigin::Misc(impl_c_span); let err = infcx.commit_if_ok(|_| { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 5e2b49bac1b2..a06b3e70881a 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -13,12 +13,12 @@ use check::regionck::RegionCtxt; use hir::def_id::DefId; use middle::free_region::FreeRegionMap; -use rustc::infer; +use rustc::infer::{self, InferOk}; use middle::region; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::traits::{self, Reveal}; -use util::nodemap::FnvHashSet; +use util::nodemap::FxHashSet; use syntax::ast; use syntax_pos::{self, Span}; @@ -93,16 +93,22 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did); let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); - if let Err(_) = infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span), - named_type, fresh_impl_self_ty) { - let item_span = tcx.map.span(self_type_node_id); - struct_span_err!(tcx.sess, drop_impl_span, E0366, - "Implementations of Drop cannot be specialized") - .span_note(item_span, - "Use same sequence of generic type and region \ - parameters that is on the struct/enum definition") - .emit(); - return Err(()); + match infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span), + named_type, fresh_impl_self_ty) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + } + Err(_) => { + let item_span = tcx.map.span(self_type_node_id); + struct_span_err!(tcx.sess, drop_impl_span, E0366, + "Implementations of Drop cannot be specialized") + .span_note(item_span, + "Use same sequence of generic type and region \ + parameters that is on the struct/enum definition") + .emit(); + return Err(()); + } } if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) { @@ -283,7 +289,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( rcx: rcx, span: span, parent_scope: parent_scope, - breadcrumbs: FnvHashSet() + breadcrumbs: FxHashSet() }, TypeContext::Root, typ, @@ -341,7 +347,7 @@ enum TypeContext { struct DropckContext<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> { rcx: &'a mut RegionCtxt<'b, 'gcx, 'tcx>, /// types that have already been traversed - breadcrumbs: FnvHashSet>, + breadcrumbs: FxHashSet>, /// span for error reporting span: Span, /// the scope reachable dtorck types must outlive @@ -547,9 +553,9 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // attributes attached to the impl's generics. let dtor_method = adt_def.destructor() .expect("dtorck type without destructor impossible"); - let method = tcx.impl_or_trait_item(dtor_method); - let impl_id: DefId = method.container().id(); - let revised_ty = revise_self_ty(tcx, adt_def, impl_id, substs); + let method = tcx.associated_item(dtor_method); + let impl_def_id = method.container.id(); + let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs); return DropckKind::RevisedSelf(revised_ty); } ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 7d2547ec17f3..95d2b2211f5b 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -16,7 +16,7 @@ use rustc::infer::TypeOrigin; use rustc::ty::subst::Substs; use rustc::ty::FnSig; use rustc::ty::{self, Ty}; -use rustc::util::nodemap::FnvHashMap; +use rustc::util::nodemap::FxHashMap; use {CrateCtxt, require_same_types}; use syntax::abi::Abi; @@ -372,7 +372,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt, return } - let mut structural_to_nomimal = FnvHashMap(); + let mut structural_to_nomimal = FxHashMap(); let sig = tcx.no_late_bound_regions(i_ty.ty.fn_sig()).unwrap(); if intr.inputs.len() != sig.inputs.len() { @@ -412,7 +412,7 @@ fn match_intrinsic_type_to_type<'tcx, 'a>( ccx: &CrateCtxt<'a, 'tcx>, position: &str, span: Span, - structural_to_nominal: &mut FnvHashMap<&'a intrinsics::Type, ty::Ty<'tcx>>, + structural_to_nominal: &mut FxHashMap<&'a intrinsics::Type, ty::Ty<'tcx>>, expected: &'a intrinsics::Type, t: ty::Ty<'tcx>) { use intrinsics::Type::*; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 722089cd50c0..3894a7a2097e 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -15,7 +15,7 @@ use hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty}; -use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk, TypeOrigin}; use syntax_pos::Span; @@ -37,16 +37,6 @@ impl<'a, 'gcx, 'tcx> Deref for ConfirmContext<'a, 'gcx, 'tcx> { } } -struct InstantiatedMethodSig<'tcx> { - /// Function signature of the method being invoked. The 0th - /// argument is the receiver. - method_sig: ty::FnSig<'tcx>, - - /// Generic bounds on the method's parameters which must be added - /// as pending obligations. - method_predicates: ty::InstantiatedPredicates<'tcx>, -} - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn confirm_method(&self, span: Span, @@ -98,31 +88,18 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { debug!("all_substs={:?}", all_substs); // Create the final signature for the method, replacing late-bound regions. - let InstantiatedMethodSig { method_sig, method_predicates } = - self.instantiate_method_sig(&pick, all_substs); - let method_self_ty = method_sig.inputs[0]; + let (method_ty, method_predicates) = self.instantiate_method_sig(&pick, all_substs); // Unify the (adjusted) self type with what the method expects. - self.unify_receivers(self_ty, method_self_ty); - - // Create the method type - let def_id = pick.item.def_id(); - let method_ty = pick.item.as_opt_method().unwrap(); - let fty = self.tcx.mk_fn_def(def_id, - all_substs, - self.tcx.mk_bare_fn(ty::BareFnTy { - sig: ty::Binder(method_sig), - unsafety: method_ty.fty.unsafety, - abi: method_ty.fty.abi.clone(), - })); + self.unify_receivers(self_ty, method_ty.fn_sig().input(0).skip_binder()); // Add any trait/regions obligations specified on the method's type parameters. - self.add_obligations(fty, all_substs, &method_predicates); + self.add_obligations(method_ty, all_substs, &method_predicates); // Create the final `MethodCallee`. let callee = ty::MethodCallee { - def_id: def_id, - ty: fty, + def_id: pick.item.def_id, + ty: method_ty, substs: all_substs, }; @@ -140,20 +117,19 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { unadjusted_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>) -> Ty<'tcx> { - let (autoref, unsize) = if let Some(mutbl) = pick.autoref { + let autoref = if let Some(mutbl) = pick.autoref { let region = self.next_region_var(infer::Autoref(self.span)); - let autoref = AutoPtr(region, mutbl); - (Some(autoref), - pick.unsize.map(|target| target.adjust_for_autoref(self.tcx, Some(autoref)))) + Some(AutoBorrow::Ref(region, mutbl)) } else { // No unsizing should be performed without autoref (at // least during method dispach). This is because we // currently only unsize `[T;N]` to `[T]`, and naturally // that must occur being a reference. assert!(pick.unsize.is_none()); - (None, None) + None }; + // Commit the autoderefs by calling `autoderef` again, but this // time writing the results into the various tables. let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); @@ -163,19 +139,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { autoderef.unambiguous_final_ty(); autoderef.finalize(LvaluePreference::NoPreference, Some(self.self_expr)); - // Write out the final adjustment. - self.write_adjustment(self.self_expr.id, - AdjustDerefRef(AutoDerefRef { - autoderefs: pick.autoderefs, - autoref: autoref, - unsize: unsize, - })); + let target = pick.unsize.unwrap_or(autoderefd_ty); + let target = target.adjust_for_autoref(self.tcx, autoref); - if let Some(target) = unsize { - target - } else { - autoderefd_ty.adjust_for_autoref(self.tcx, autoref) - } + // Write out the final adjustment. + self.write_adjustment(self.self_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: pick.autoderefs, + autoref: autoref, + unsize: pick.unsize.is_some(), + }, + target: target + }); + + target } /////////////////////////////////////////////////////////////////////////// @@ -193,7 +170,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { -> &'tcx Substs<'tcx> { match pick.kind { probe::InherentImplPick => { - let impl_def_id = pick.item.container().id(); + let impl_def_id = pick.item.container.id(); assert!(self.tcx.impl_trait_ref(impl_def_id).is_none(), "impl {:?} is not an inherent impl", impl_def_id); @@ -201,7 +178,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } probe::ObjectPick => { - let trait_def_id = pick.item.container().id(); + let trait_def_id = pick.item.container.id(); self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| { // The object data has no entry for the Self // Type. For the purposes of this method call, we @@ -244,7 +221,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } probe::TraitPick => { - let trait_def_id = pick.item.container().id(); + let trait_def_id = pick.item.container.id(); // Make a trait reference `$0 : Trait<$1...$n>` // consisting entirely of type variables. Later on in @@ -299,8 +276,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let num_supplied_types = supplied_method_types.len(); - let method = pick.item.as_opt_method().unwrap(); - let num_method_types = method.generics.types.len(); + let method_generics = self.tcx.lookup_generics(pick.item.def_id); + let num_method_types = method_generics.types.len(); if num_supplied_types > 0 && num_supplied_types != num_method_types { if num_method_types == 0 { @@ -332,18 +309,15 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // parameters from the type and those from the method. // // FIXME -- permit users to manually specify lifetimes - let supplied_start = substs.params().len() + method.generics.regions.len(); - Substs::for_item(self.tcx, - method.def_id, - |def, _| { + let supplied_start = substs.params().len() + method_generics.regions.len(); + Substs::for_item(self.tcx, pick.item.def_id, |def, _| { let i = def.index as usize; if i < substs.params().len() { substs.region_at(i) } else { self.region_var_for_def(self.span, def) } - }, - |def, cur_substs| { + }, |def, cur_substs| { let i = def.index as usize; if i < substs.params().len() { substs.type_at(i) @@ -376,7 +350,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_sig(&mut self, pick: &probe::Pick<'tcx>, all_substs: &'tcx Substs<'tcx>) - -> InstantiatedMethodSig<'tcx> { + -> (Ty<'tcx>, ty::InstantiatedPredicates<'tcx>) { debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", pick, all_substs); @@ -384,36 +358,40 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Instantiate the bounds on the method with the // type/early-bound-regions substitutions performed. There can // be no late-bound regions appearing here. - let method_predicates = pick.item - .as_opt_method() - .unwrap() - .predicates - .instantiate(self.tcx, all_substs); - let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates); + let def_id = pick.item.def_id; + let method_predicates = self.tcx.lookup_predicates(def_id) + .instantiate(self.tcx, all_substs); + let method_predicates = self.normalize_associated_types_in(self.span, + &method_predicates); debug!("method_predicates after subst = {:?}", method_predicates); + let fty = match self.tcx.lookup_item_type(def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + }; + // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. // // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.item - .as_opt_method() - .unwrap() - .fty - .sig); + let method_sig = self.replace_late_bound_regions_with_fresh_var(&fty.sig); debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig); let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig); debug!("type scheme substituted, method_sig={:?}", method_sig); - InstantiatedMethodSig { - method_sig: method_sig, - method_predicates: method_predicates, - } + let method_ty = self.tcx.mk_fn_def(def_id, all_substs, + self.tcx.mk_bare_fn(ty::BareFnTy { + sig: ty::Binder(method_sig), + unsafety: fty.unsafety, + abi: fty.abi, + })); + + (method_ty, method_predicates) } fn add_obligations(&mut self, @@ -463,29 +441,23 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Fix up autoderefs and derefs. for (i, &expr) in exprs.iter().rev().enumerate() { + debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?}", i, expr); + // Count autoderefs. - let autoderef_count = match self.tables - .borrow() - .adjustments - .get(&expr.id) { - Some(&AdjustDerefRef(ref adj)) => adj.autoderefs, - Some(_) | None => 0, - }; - - debug!("convert_lvalue_derefs_to_mutable: i={} expr={:?} \ - autoderef_count={}", - i, - expr, - autoderef_count); - - if autoderef_count > 0 { - let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id)); - autoderef.nth(autoderef_count).unwrap_or_else(|| { - span_bug!(expr.span, - "expr was deref-able {} times but now isn't?", - autoderef_count); - }); - autoderef.finalize(PreferMutLvalue, Some(expr)); + let adjustment = self.tables.borrow().adjustments.get(&expr.id).cloned(); + match adjustment { + Some(Adjustment { kind: Adjust::DerefRef { autoderefs, .. }, .. }) => { + if autoderefs > 0 { + let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id)); + autoderef.nth(autoderefs).unwrap_or_else(|| { + span_bug!(expr.span, + "expr was deref-able {} times but now isn't?", + autoderefs); + }); + autoderef.finalize(PreferMutLvalue, Some(expr)); + } + } + Some(_) | None => {} } // Don't retry the first one or we might infinite loop! @@ -503,45 +475,55 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // ought to recode this routine so it doesn't // (ab)use the normal type checking paths. let adj = self.tables.borrow().adjustments.get(&base_expr.id).cloned(); - let (autoderefs, unsize) = match adj { - Some(AdjustDerefRef(adr)) => { - match adr.autoref { + let (autoderefs, unsize, adjusted_base_ty) = match adj { + Some(Adjustment { + kind: Adjust::DerefRef { autoderefs, autoref, unsize }, + target + }) => { + match autoref { None => { - assert!(adr.unsize.is_none()); - (adr.autoderefs, None) - } - Some(AutoPtr(..)) => { - (adr.autoderefs, - adr.unsize.map(|target| { - target.builtin_deref(false, NoPreference) - .expect("fixup: AutoPtr is not &T") - .ty - })) + assert!(!unsize); } + Some(AutoBorrow::Ref(..)) => {} Some(_) => { span_bug!(base_expr.span, "unexpected adjustment autoref {:?}", - adr); + adj); } } + + (autoderefs, unsize, if unsize { + target.builtin_deref(false, NoPreference) + .expect("fixup: AutoBorrow::Ref is not &T") + .ty + } else { + let ty = self.node_ty(base_expr.id); + let mut ty = self.shallow_resolve(ty); + let mut method_type = |method_call: ty::MethodCall| { + self.tables.borrow().method_map.get(&method_call).map(|m| { + self.resolve_type_vars_if_possible(&m.ty) + }) + }; + + if !ty.references_error() { + for i in 0..autoderefs { + ty = ty.adjust_for_autoderef(self.tcx, + base_expr.id, + base_expr.span, + i as u32, + &mut method_type); + } + } + + ty + }) } - None => (0, None), + None => (0, false, self.node_ty(base_expr.id)), Some(_) => { span_bug!(base_expr.span, "unexpected adjustment type"); } }; - let (adjusted_base_ty, unsize) = if let Some(target) = unsize { - (target, true) - } else { - (self.adjust_expr_ty(base_expr, - Some(&AdjustDerefRef(AutoDerefRef { - autoderefs: autoderefs, - autoref: None, - unsize: None, - }))), - false) - }; let index_expr_ty = self.node_ty(index_expr.id); let result = self.try_index_step(ty::MethodCall::expr(expr.id), @@ -583,7 +565,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) { // Disallow calls to the method `drop` defined in the `Drop` trait. - match pick.item.container() { + match pick.item.container { ty::TraitContainer(trait_def_id) => { callee::check_legal_trait_for_method_call(self.ccx, self.span, trait_def_id) } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index f084b85a45f8..579a54fb5318 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -16,7 +16,7 @@ use hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; -use rustc::ty::adjustment::{AdjustDerefRef, AutoDerefRef, AutoPtr}; +use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::infer; use syntax::ast; @@ -228,14 +228,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Trait must have a method named `m_name` and it should not have // type parameters or early-bound regions. let tcx = self.tcx; - let method_item = self.impl_or_trait_item(trait_def_id, m_name).unwrap(); - let method_ty = method_item.as_opt_method().unwrap(); - assert_eq!(method_ty.generics.types.len(), 0); - assert_eq!(method_ty.generics.regions.len(), 0); + let method_item = self.associated_item(trait_def_id, m_name).unwrap(); + let def_id = method_item.def_id; + let generics = tcx.lookup_generics(def_id); + assert_eq!(generics.types.len(), 0); + assert_eq!(generics.regions.len(), 0); - debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}", - method_item, - method_ty); + debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. @@ -243,22 +242,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let fn_sig = - self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &method_ty.fty.sig) - .0; + let original_method_ty = tcx.lookup_item_type(def_id).ty; + let fty = match original_method_ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + }; + let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, + infer::FnCall, + &fty.sig).0; let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); let transformed_self_ty = fn_sig.inputs[0]; - let def_id = method_item.def_id(); - let fty = tcx.mk_fn_def(def_id, - trait_ref.substs, - tcx.mk_bare_fn(ty::BareFnTy { - sig: ty::Binder(fn_sig), - unsafety: method_ty.fty.unsafety, - abi: method_ty.fty.abi.clone(), - })); + let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs, + tcx.mk_bare_fn(ty::BareFnTy { + sig: ty::Binder(fn_sig), + unsafety: fty.unsafety, + abi: fty.abi + })); - debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}", - fty, + debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", + method_ty, obligation); // Register obligations for the parameters. This will include the @@ -269,13 +271,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates); + let method_bounds = self.instantiate_bounds(span, def_id, trait_ref.substs); assert!(!method_bounds.has_escaping_regions()); self.add_obligations_for_parameters(traits::ObligationCause::misc(span, self.body_id), &method_bounds); // Also register an obligation for the method type being well-formed. - self.register_wf_obligation(fty, span, traits::MiscObligation); + self.register_wf_obligation(method_ty, span, traits::MiscObligation); // FIXME(#18653) -- Try to resolve obligations, giving us more // typing information, which can sometimes be needed to avoid @@ -283,61 +285,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); // Insert any adjustments needed (always an autoref of some mutability). - match self_expr { - None => {} + if let Some(self_expr) = self_expr { + debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ + (self-id={}, autoderefs={}, unsize={}, fty={:?})", + self_expr.id, autoderefs, unsize, original_method_ty); - Some(self_expr) => { - debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ - (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})", - self_expr.id, - autoderefs, - unsize, - method_ty.explicit_self); - - match method_ty.explicit_self { - ty::ExplicitSelfCategory::ByValue => { - // Trait method is fn(self), no transformation needed. - assert!(!unsize); - self.write_autoderef_adjustment(self_expr.id, autoderefs); - } - - ty::ExplicitSelfCategory::ByReference(..) => { - // Trait method is fn(&self) or fn(&mut self), need an - // autoref. Pull the region etc out of the type of first argument. - match transformed_self_ty.sty { - ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => { - self.write_adjustment(self_expr.id, - AdjustDerefRef(AutoDerefRef { - autoderefs: autoderefs, - autoref: Some(AutoPtr(region, mutbl)), - unsize: if unsize { - Some(transformed_self_ty) - } else { - None - }, - })); - } - - _ => { - span_bug!(span, - "trait method is &self but first arg is: {}", - transformed_self_ty); - } - } - } - - _ => { - span_bug!(span, - "unexpected explicit self type in operator method: {:?}", - method_ty.explicit_self); - } + let original_sig = original_method_ty.fn_sig(); + let autoref = match (&original_sig.input(0).skip_binder().sty, + &transformed_self_ty.sty) { + (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => { + // Trait method is fn(&self) or fn(&mut self), need an + // autoref. Pull the region etc out of the type of first argument. + Some(AutoBorrow::Ref(region, mutbl)) } - } + _ => { + // Trait method is fn(self), no transformation needed. + assert!(!unsize); + None + } + }; + + self.write_adjustment(self_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: autoderefs, + autoref: autoref, + unsize: unsize + }, + target: transformed_self_ty + }); } let callee = ty::MethodCallee { def_id: def_id, - ty: fty, + ty: method_ty, substs: trait_ref.substs, }; @@ -361,7 +341,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let def = pick.item.def(); if let probe::InherentImplPick = pick.kind { - if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx.map) { + if !pick.item.vis.is_accessible_from(self.body_id, &self.tcx.map) { let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str()); self.tcx.sess.span_err(span, &msg); } @@ -371,14 +351,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Find item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. - pub fn impl_or_trait_item(&self, - def_id: DefId, - item_name: ast::Name) - -> Option> { - self.tcx - .impl_or_trait_items(def_id) - .iter() - .map(|&did| self.tcx.impl_or_trait_item(did)) - .find(|m| m.name() == item_name) + pub fn associated_item(&self, def_id: DefId, item_name: ast::Name) + -> Option { + self.tcx.associated_items(def_id).find(|item| item.name == item_name) } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 43837de2f345..7068b2dea726 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -20,7 +20,7 @@ use rustc::ty::subst::{Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::infer::{InferOk, TypeOrigin}; -use rustc::util::nodemap::FnvHashSet; +use rustc::util::nodemap::FxHashSet; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use rustc::hir; @@ -40,7 +40,7 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { opt_simplified_steps: Option>, inherent_candidates: Vec>, extension_candidates: Vec>, - impl_dups: FnvHashSet, + impl_dups: FxHashSet, import_id: Option, /// Collects near misses when the candidate functions are missing a `self` keyword and is only @@ -72,7 +72,7 @@ struct CandidateStep<'tcx> { #[derive(Debug)] struct Candidate<'tcx> { xform_self_ty: Ty<'tcx>, - item: ty::ImplOrTraitItem<'tcx>, + item: ty::AssociatedItem, kind: CandidateKind<'tcx>, import_id: Option, } @@ -95,7 +95,7 @@ enum CandidateKind<'tcx> { #[derive(Debug)] pub struct Pick<'tcx> { - pub item: ty::ImplOrTraitItem<'tcx>, + pub item: ty::AssociatedItem, pub kind: PickKind<'tcx>, pub import_id: Option, @@ -263,7 +263,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { item_name: item_name, inherent_candidates: Vec::new(), extension_candidates: Vec::new(), - impl_dups: FnvHashSet(), + impl_dups: FxHashSet(), import_id: None, steps: Rc::new(steps), opt_simplified_steps: opt_simplified_steps, @@ -384,8 +384,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option) { if let Some(impl_def_id) = lang_def_id { - self.tcx.populate_implementations_for_primitive_if_necessary(impl_def_id); - self.assemble_inherent_impl_probe(impl_def_id); } } @@ -409,7 +407,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { debug!("assemble_inherent_impl_probe {:?}", impl_def_id); - let item = match self.impl_or_trait_item(impl_def_id) { + let item = match self.associated_item(impl_def_id) { Some(m) => m, None => { return; @@ -421,7 +419,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { return self.record_static_candidate(ImplSource(impl_def_id)); } - if !item.vis().is_accessible_from(self.body_id, &self.tcx.map) { + if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) { self.private_candidate = Some(item.def()); return; } @@ -512,17 +510,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let xform_self_ty = this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs); - if let Some(ref m) = item.as_opt_method() { - debug!("found match: trait_ref={:?} substs={:?} m={:?}", - trait_ref, - trait_ref.substs, - m); - assert_eq!(m.generics.parent_types as usize, - trait_ref.substs.types().count()); - assert_eq!(m.generics.parent_regions as usize, - trait_ref.substs.regions().count()); - } - // Because this trait derives from a where-clause, it // should not contain any inference variables or other // artifacts. This means it is safe to put into the @@ -544,13 +531,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn elaborate_bounds(&mut self, bounds: &[ty::PolyTraitRef<'tcx>], mut mk_cand: F) where F: for<'b> FnMut(&mut ProbeContext<'b, 'gcx, 'tcx>, ty::PolyTraitRef<'tcx>, - ty::ImplOrTraitItem<'tcx>) + ty::AssociatedItem) { debug!("elaborate_bounds(bounds={:?})", bounds); let tcx = self.tcx; for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { - let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) { + let item = match self.associated_item(bound_trait_ref.def_id()) { Some(v) => v, None => { continue; @@ -568,7 +555,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_extension_candidates_for_traits_in_scope(&mut self, expr_id: ast::NodeId) -> Result<(), MethodError<'tcx>> { - let mut duplicates = FnvHashSet(); + let mut duplicates = FxHashSet(); let opt_applicable_traits = self.tcx.trait_map.get(&expr_id); if let Some(applicable_traits) = opt_applicable_traits { for trait_candidate in applicable_traits { @@ -585,7 +572,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> { - let mut duplicates = FnvHashSet(); + let mut duplicates = FxHashSet(); for trait_info in suggest::all_traits(self.ccx) { if duplicates.insert(trait_info.def_id) { self.assemble_extension_candidates_for_trait(trait_info.def_id)?; @@ -601,9 +588,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { trait_def_id); // Check whether `trait_def_id` defines a method with suitable name: - let trait_items = self.tcx.trait_items(trait_def_id); - let maybe_item = trait_items.iter() - .find(|item| item.name() == self.item_name); + let maybe_item = self.tcx.associated_items(trait_def_id) + .find(|item| item.name == self.item_name); let item = match maybe_item { Some(i) => i, None => { @@ -612,7 +598,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { }; // Check whether `trait_def_id` defines a method with suitable name: - if !self.has_applicable_self(item) { + if !self.has_applicable_self(&item) { debug!("method has inapplicable self"); self.record_static_candidate(TraitSource(trait_def_id)); return Ok(()); @@ -631,7 +617,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_extension_candidates_for_trait_impls(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) { + item: ty::AssociatedItem) { let trait_def = self.tcx.lookup_trait_def(trait_def_id); // FIXME(arielb1): can we use for_each_relevant_impl here? @@ -700,7 +686,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_closure_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) + item: ty::AssociatedItem) -> Result<(), MethodError<'tcx>> { // Check if this is one of the Fn,FnMut,FnOnce traits. let tcx = self.tcx; @@ -765,7 +751,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_projection_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) { + item: ty::AssociatedItem) { debug!("assemble_projection_candidates(\ trait_def_id={:?}, \ item={:?})", @@ -820,7 +806,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_where_clause_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) { + item: ty::AssociatedItem) { debug!("assemble_where_clause_candidates(trait_def_id={:?})", trait_def_id); @@ -865,7 +851,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.assemble_extension_candidates_for_all_traits()?; let out_of_scope_traits = match self.pick_core() { - Some(Ok(p)) => vec![p.item.container().id()], + Some(Ok(p)) => vec![p.item.container.id()], Some(Err(MethodError::Ambiguity(v))) => { v.into_iter() .map(|source| { @@ -1065,7 +1051,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // don't have enough information to fully evaluate). let (impl_def_id, substs, ref_obligations) = match probe.kind { InherentImplCandidate(ref substs, ref ref_obligations) => { - (probe.item.container().id(), substs, ref_obligations) + (probe.item.container.id(), substs, ref_obligations) } ExtensionImplCandidate(impl_def_id, ref substs, ref ref_obligations) => { @@ -1128,12 +1114,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// use, so it's ok to just commit to "using the method from the trait Foo". fn collapse_candidates_to_trait_pick(&self, probes: &[&Candidate<'tcx>]) -> Option> { // Do all probes correspond to the same trait? - let container = probes[0].item.container(); + let container = probes[0].item.container; match container { ty::TraitContainer(_) => {} ty::ImplContainer(_) => return None, } - if probes[1..].iter().any(|p| p.item.container() != container) { + if probes[1..].iter().any(|p| p.item.container != container) { return None; } @@ -1150,19 +1136,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // MISCELLANY - fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool { + fn has_applicable_self(&self, item: &ty::AssociatedItem) -> bool { // "fast track" -- check for usage of sugar - match *item { - ty::ImplOrTraitItem::MethodTraitItem(ref method) => { - match method.explicit_self { - ty::ExplicitSelfCategory::Static => self.mode == Mode::Path, - ty::ExplicitSelfCategory::ByValue | - ty::ExplicitSelfCategory::ByReference(..) | - ty::ExplicitSelfCategory::ByBox => true, - } - } - ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path, - _ => false, + match self.mode { + Mode::MethodCall => item.method_has_self_argument, + Mode::Path => true } // FIXME -- check for types that deref to `Self`, // like `Rc` and so on. @@ -1177,24 +1155,26 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn xform_self_ty(&self, - item: &ty::ImplOrTraitItem<'tcx>, + item: &ty::AssociatedItem, impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { - match item.as_opt_method() { - Some(ref method) => self.xform_method_self_ty(method, impl_ty, substs), - None => impl_ty, + if item.kind == ty::AssociatedKind::Method && self.mode == Mode::MethodCall { + self.xform_method_self_ty(item.def_id, impl_ty, substs) + } else { + impl_ty } } fn xform_method_self_ty(&self, - method: &Rc>, + method: DefId, impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { + let self_ty = self.tcx.lookup_item_type(method).ty.fn_sig().input(0); debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", impl_ty, - method.fty.sig.0.inputs.get(0), + self_ty, substs); assert!(!substs.has_escaping_regions()); @@ -1204,26 +1184,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - assert_eq!(substs.types().count(), - method.generics.parent_types as usize); - assert_eq!(substs.regions().count(), - method.generics.parent_regions as usize); - - if self.mode == Mode::Path { - return impl_ty; - } + let generics = self.tcx.lookup_generics(method); + assert_eq!(substs.types().count(), generics.parent_types as usize); + assert_eq!(substs.regions().count(), generics.parent_regions as usize); // Erase any late-bound regions from the method and substitute // in the values from the substitution. - let xform_self_ty = method.fty.sig.input(0); - let xform_self_ty = self.erase_late_bound_regions(&xform_self_ty); + let xform_self_ty = self.erase_late_bound_regions(&self_ty); - if method.generics.types.is_empty() && method.generics.regions.is_empty() { + if generics.types.is_empty() && generics.regions.is_empty() { xform_self_ty.subst(self.tcx, substs) } else { - let substs = Substs::for_item(self.tcx, - method.def_id, - |def, _| { + let substs = Substs::for_item(self.tcx, method, |def, _| { let i = def.index as usize; if i < substs.params().len() { substs.region_at(i) @@ -1232,8 +1204,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // `impl_self_ty()` for an explanation. self.tcx.mk_region(ty::ReErased) } - }, - |def, cur_substs| { + }, |def, cur_substs| { let i = def.index as usize; if i < substs.params().len() { substs.type_at(i) @@ -1283,8 +1254,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// Find item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. - fn impl_or_trait_item(&self, def_id: DefId) -> Option> { - self.fcx.impl_or_trait_item(def_id, self.item_name) + fn associated_item(&self, def_id: DefId) -> Option { + self.fcx.associated_item(def_id, self.item_name) } } @@ -1317,11 +1288,11 @@ impl<'tcx> Candidate<'tcx> { fn to_source(&self) -> CandidateSource { match self.kind { - InherentImplCandidate(..) => ImplSource(self.item.container().id()), + InherentImplCandidate(..) => ImplSource(self.item.container.id()), ExtensionImplCandidate(def_id, ..) => ImplSource(def_id), ObjectCandidate | TraitCandidate | - WhereClauseCandidate(_) => TraitSource(self.item.container().id()), + WhereClauseCandidate(_) => TraitSource(self.item.container.id()), } } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 32bf839a4ed4..0cb8cf2a5888 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -20,7 +20,7 @@ use hir::def::Def; use hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::lang_items::FnOnceTraitLangItem; use rustc::traits::{Obligation, SelectionContext}; -use util::nodemap::FnvHashSet; +use util::nodemap::FxHashSet; use syntax::ast; use errors::DiagnosticBuilder; @@ -89,20 +89,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { CandidateSource::ImplSource(impl_did) => { // Provide the best span we can. Use the item, if local to crate, else // the impl, if local to crate (item may be defaulted), else nothing. - let item = self.impl_or_trait_item(impl_did, item_name) + let item = self.associated_item(impl_did, item_name) .or_else(|| { - self.impl_or_trait_item(self.tcx - .impl_trait_ref(impl_did) - .unwrap() - .def_id, + self.associated_item( + self.tcx.impl_trait_ref(impl_did).unwrap().def_id, - item_name) - }) - .unwrap(); - let note_span = self.tcx - .map - .span_if_local(item.def_id()) - .or_else(|| self.tcx.map.span_if_local(impl_did)); + item_name + ) + }).unwrap(); + let note_span = self.tcx.map.span_if_local(item.def_id).or_else(|| { + self.tcx.map.span_if_local(impl_did) + }); let impl_ty = self.impl_self_ty(span, impl_did).ty; @@ -127,8 +124,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } CandidateSource::TraitSource(trait_did) => { - let item = self.impl_or_trait_item(trait_did, item_name).unwrap(); - let item_span = self.tcx.map.def_id_span(item.def_id(), span); + let item = self.associated_item(trait_did, item_name).unwrap(); + let item_span = self.tcx.map.def_id_span(item.def_id, span); span_note!(err, item_span, "candidate #{} is defined in the trait `{}`", @@ -334,8 +331,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - (type_is_local || info.def_id.is_local()) && - self.impl_or_trait_item(info.def_id, item_name).is_some() + (type_is_local || info.def_id.is_local()) + && self.associated_item(info.def_id, item_name).is_some() }) .collect::>(); @@ -470,10 +467,10 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { }); // Cross-crate: - let mut external_mods = FnvHashSet(); + let mut external_mods = FxHashSet(); fn handle_external_def(ccx: &CrateCtxt, traits: &mut AllTraitsVec, - external_mods: &mut FnvHashSet, + external_mods: &mut FxHashSet, def: Def) { let def_id = def.def_id(); match def { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 75a14bb3db92..08242cff112c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -103,20 +103,21 @@ use CrateCtxt; use TypeAndSubsts; use lint; use util::common::{block_query, ErrorReported, indenter, loop_query}; -use util::nodemap::{DefIdMap, FnvHashMap, FnvHashSet, NodeMap}; +use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap}; use std::cell::{Cell, Ref, RefCell}; +use std::cmp; use std::mem::replace; -use std::ops::Deref; +use std::ops::{self, Deref}; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::codemap::{self, Spanned}; +use syntax::codemap::{self, original_sp, Spanned}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::parse::token::{self, InternedString, keywords}; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; -use syntax_pos::{self, Span}; +use syntax_pos::{self, BytePos, Span}; use rustc::hir::intravisit::{self, Visitor}; use rustc::hir::{self, PatKind}; @@ -351,6 +352,59 @@ impl UnsafetyState { } } +/// Whether a node ever exits normally or not. +/// Tracked semi-automatically (through type variables +/// marked as diverging), with some manual adjustments +/// for control-flow primitives (approximating a CFG). +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +enum Diverges { + /// Potentially unknown, some cases converge, + /// others require a CFG to determine them. + Maybe, + + /// Definitely known to diverge and therefore + /// not reach the next sibling or its parent. + Always, + + /// Same as `Always` but with a reachability + /// warning already emitted + WarnedAlways +} + +// Convenience impls for combinig `Diverges`. + +impl ops::BitAnd for Diverges { + type Output = Self; + fn bitand(self, other: Self) -> Self { + cmp::min(self, other) + } +} + +impl ops::BitOr for Diverges { + type Output = Self; + fn bitor(self, other: Self) -> Self { + cmp::max(self, other) + } +} + +impl ops::BitAndAssign for Diverges { + fn bitand_assign(&mut self, other: Self) { + *self = *self & other; + } +} + +impl ops::BitOrAssign for Diverges { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +impl Diverges { + fn always(self) -> bool { + self >= Diverges::Always + } +} + #[derive(Clone)] pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ast_ty_to_ty_cache: RefCell>>, @@ -371,6 +425,12 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ps: RefCell, + /// Whether the last checked node can ever exit. + diverges: Cell, + + /// Whether any child nodes have any type errors. + has_errors: Cell, + inh: &'a Inherited<'a, 'gcx, 'tcx>, } @@ -407,22 +467,26 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> { where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R { let ccx = self.ccx; - self.infcx.enter(|infcx| { - f(Inherited { - ccx: ccx, - infcx: infcx, - fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), - locals: RefCell::new(NodeMap()), - deferred_call_resolutions: RefCell::new(DefIdMap()), - deferred_cast_checks: RefCell::new(Vec::new()), - anon_types: RefCell::new(DefIdMap()), - deferred_obligations: RefCell::new(Vec::new()), - }) - }) + self.infcx.enter(|infcx| f(Inherited::new(ccx, infcx))) } } impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { + pub fn new(ccx: &'a CrateCtxt<'a, 'gcx>, + infcx: InferCtxt<'a, 'gcx, 'tcx>) + -> Self { + Inherited { + ccx: ccx, + infcx: infcx, + fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), + locals: RefCell::new(NodeMap()), + deferred_call_resolutions: RefCell::new(DefIdMap()), + deferred_cast_checks: RefCell::new(Vec::new()), + anon_types: RefCell::new(DefIdMap()), + deferred_obligations: RefCell::new(Vec::new()), + } + } + fn normalize_associated_types_in(&self, span: Span, body_id: ast::NodeId, @@ -530,7 +594,7 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult { fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block, + body: &'tcx hir::Expr, fn_id: ast::NodeId, span: Span) { let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty; @@ -554,7 +618,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body); fcx.select_all_obligations_and_apply_defaults(); - fcx.closure_analyze_fn(body); + fcx.closure_analyze(body); fcx.select_obligations_where_possible(); fcx.check_casts(); fcx.select_all_obligations_or_error(); // Casts can introduce new obligations. @@ -650,7 +714,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { // Don't descend into the bodies of nested closures fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl, - _: &'gcx hir::Block, _: Span, _: ast::NodeId) { } + _: &'gcx hir::Expr, _: Span, _: ast::NodeId) { } } /// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function @@ -665,7 +729,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fn_sig: &ty::FnSig<'tcx>, decl: &'gcx hir::FnDecl, fn_id: ast::NodeId, - body: &'gcx hir::Block) + body: &'gcx hir::Expr) -> FnCtxt<'a, 'gcx, 'tcx> { let mut fn_sig = fn_sig.clone(); @@ -705,18 +769,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.write_ty(input.id, arg_ty); } - visit.visit_block(body); + visit.visit_expr(body); } inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); - // FIXME(aburka) do we need this special case? and should it be is_uninhabited? - let expected = if fcx.ret_ty.is_never() { - NoExpectation - } else { - ExpectHasType(fcx.ret_ty) - }; - fcx.check_block_with_expected(body, expected); + fcx.check_expr_coercable_to_type(body, fcx.ret_ty); fcx } @@ -756,7 +814,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_impl_items_against_trait(ccx, it.span, impl_def_id, - &impl_trait_ref, + impl_trait_ref, impl_items); let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); @@ -773,7 +831,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_union(ccx, it.id, it.span); } hir::ItemTy(_, ref generics) => { - let pty_ty = ccx.tcx.node_id_to_type(it.id); + let pty_ty = ccx.tcx.tables().node_id_to_type(it.id); check_bounds_are_used(ccx, generics, pty_ty); } hir::ItemForeignMod(ref m) => { @@ -938,21 +996,13 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let ancestors = trait_def.ancestors(impl_id); - let parent = match impl_item.node { - hir::ImplItemKind::Const(..) => { - ancestors.const_defs(tcx, impl_item.name).skip(1).next() - .map(|node_item| node_item.map(|parent| parent.defaultness)) - } - hir::ImplItemKind::Method(..) => { - ancestors.fn_defs(tcx, impl_item.name).skip(1).next() - .map(|node_item| node_item.map(|parent| parent.defaultness)) - - } - hir::ImplItemKind::Type(_) => { - ancestors.type_defs(tcx, impl_item.name).skip(1).next() - .map(|node_item| node_item.map(|parent| parent.defaultness)) - } + let kind = match impl_item.node { + hir::ImplItemKind::Const(..) => ty::AssociatedKind::Const, + hir::ImplItemKind::Method(..) => ty::AssociatedKind::Method, + hir::ImplItemKind::Type(_) => ty::AssociatedKind::Type }; + let parent = ancestors.defs(tcx, impl_item.name, kind).skip(1).next() + .map(|node_item| node_item.map(|parent| parent.defaultness)); if let Some(parent) = parent { if parent.item.is_final() { @@ -965,7 +1015,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, impl_id: DefId, - impl_trait_ref: &ty::TraitRef<'tcx>, + impl_trait_ref: ty::TraitRef<'tcx>, impl_items: &[hir::ImplItem]) { // If the trait reference itself is erroneous (so the compilation is going // to fail), skip checking the items here -- the `impl_item` table in `tcx` @@ -975,93 +1025,90 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Locate trait definition and items let tcx = ccx.tcx; let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id); - let trait_items = tcx.trait_items(impl_trait_ref.def_id); let mut overridden_associated_type = None; // Check existing impl methods to see if they are both present in trait // and compatible with trait signature for impl_item in impl_items { - let ty_impl_item = tcx.impl_or_trait_item(tcx.map.local_def_id(impl_item.id)); - let ty_trait_item = trait_items.iter() - .find(|ac| ac.name() == ty_impl_item.name()); + let ty_impl_item = tcx.associated_item(tcx.map.local_def_id(impl_item.id)); + let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id) + .find(|ac| ac.name == ty_impl_item.name); // Check that impl definition matches trait definition if let Some(ty_trait_item) = ty_trait_item { match impl_item.node { hir::ImplItemKind::Const(..) => { - let impl_const = match ty_impl_item { - ty::ConstTraitItem(ref cti) => cti, - _ => span_bug!(impl_item.span, "non-const impl-item for const") - }; - // Find associated const definition. - if let &ty::ConstTraitItem(ref trait_const) = ty_trait_item { + if ty_trait_item.kind == ty::AssociatedKind::Const { compare_const_impl(ccx, - &impl_const, + &ty_impl_item, impl_item.span, - trait_const, - &impl_trait_ref); + &ty_trait_item, + impl_trait_ref); } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0323, "item `{}` is an associated const, \ which doesn't match its trait `{:?}`", - impl_const.name, + ty_impl_item.name, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); // We can only get the spans from local trait definition // Same for E0324 and E0325 - if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { + if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, &format!("item in trait")); } err.emit() } } hir::ImplItemKind::Method(_, ref body) => { - let impl_method = match ty_impl_item { - ty::MethodTraitItem(ref mti) => mti, - _ => span_bug!(impl_item.span, "non-method impl-item for method") - }; - - let trait_span = tcx.map.span_if_local(ty_trait_item.def_id()); - if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item { + let trait_span = tcx.map.span_if_local(ty_trait_item.def_id); + if ty_trait_item.kind == ty::AssociatedKind::Method { + let err_count = tcx.sess.err_count(); compare_impl_method(ccx, - &impl_method, + &ty_impl_item, impl_item.span, body.id, - &trait_method, - &impl_trait_ref, - trait_span); + &ty_trait_item, + impl_trait_ref, + trait_span, + true); // start with old-broken-mode + if err_count == tcx.sess.err_count() { + // old broken mode did not report an error. Try with the new mode. + compare_impl_method(ccx, + &ty_impl_item, + impl_item.span, + body.id, + &ty_trait_item, + impl_trait_ref, + trait_span, + false); // use the new mode + } } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0324, "item `{}` is an associated method, \ which doesn't match its trait `{:?}`", - impl_method.name, + ty_impl_item.name, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); - if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { + if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, &format!("item in trait")); } err.emit() } } hir::ImplItemKind::Type(_) => { - let impl_type = match ty_impl_item { - ty::TypeTraitItem(ref tti) => tti, - _ => span_bug!(impl_item.span, "non-type impl-item for type") - }; - - if let &ty::TypeTraitItem(ref at) = ty_trait_item { - if let Some(_) = at.ty { + if ty_trait_item.kind == ty::AssociatedKind::Type { + if ty_trait_item.has_value { overridden_associated_type = Some(impl_item); } } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0325, "item `{}` is an associated type, \ which doesn't match its trait `{:?}`", - impl_type.name, + ty_impl_item.name, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); - if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { + if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, &format!("item in trait")); } err.emit() @@ -1074,64 +1121,58 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } // Check for missing items from trait - let provided_methods = tcx.provided_trait_methods(impl_trait_ref.def_id); let mut missing_items = Vec::new(); let mut invalidated_items = Vec::new(); let associated_type_overridden = overridden_associated_type.is_some(); - for trait_item in trait_items.iter() { - let is_implemented; - let is_provided; - - match *trait_item { - ty::ConstTraitItem(ref associated_const) => { - is_provided = associated_const.has_value; - is_implemented = impl_items.iter().any(|ii| { - match ii.node { - hir::ImplItemKind::Const(..) => { - ii.name == associated_const.name - } - _ => false, - } - }); - } - ty::MethodTraitItem(ref trait_method) => { - is_provided = provided_methods.iter().any(|m| m.name == trait_method.name); - is_implemented = trait_def.ancestors(impl_id) - .fn_defs(tcx, trait_method.name) - .next() - .map(|node_item| !node_item.node.is_from_trait()) - .unwrap_or(false); - } - ty::TypeTraitItem(ref trait_assoc_ty) => { - is_provided = trait_assoc_ty.ty.is_some(); - is_implemented = trait_def.ancestors(impl_id) - .type_defs(tcx, trait_assoc_ty.name) - .next() - .map(|node_item| !node_item.node.is_from_trait()) - .unwrap_or(false); - } - } + for trait_item in tcx.associated_items(impl_trait_ref.def_id) { + let is_implemented = trait_def.ancestors(impl_id) + .defs(tcx, trait_item.name, trait_item.kind) + .next() + .map(|node_item| !node_item.node.is_from_trait()) + .unwrap_or(false); if !is_implemented { - if !is_provided { - missing_items.push(trait_item.name()); + if !trait_item.has_value { + missing_items.push(trait_item); } else if associated_type_overridden { - invalidated_items.push(trait_item.name()); + invalidated_items.push(trait_item.name); } } } + let signature = |item: &ty::AssociatedItem| { + match item.kind { + ty::AssociatedKind::Method => { + format!("{}", tcx.lookup_item_type(item.def_id).ty.fn_sig().0) + } + ty::AssociatedKind::Type => format!("type {};", item.name.to_string()), + ty::AssociatedKind::Const => { + format!("const {}: {:?};", item.name.to_string(), + tcx.lookup_item_type(item.def_id).ty) + } + } + }; + if !missing_items.is_empty() { - struct_span_err!(tcx.sess, impl_span, E0046, + let mut err = struct_span_err!(tcx.sess, impl_span, E0046, "not all trait items implemented, missing: `{}`", missing_items.iter() - .map(|name| name.to_string()) - .collect::>().join("`, `")) - .span_label(impl_span, &format!("missing `{}` in implementation", + .map(|trait_item| trait_item.name.to_string()) + .collect::>().join("`, `")); + err.span_label(impl_span, &format!("missing `{}` in implementation", missing_items.iter() - .map(|name| name.to_string()) - .collect::>().join("`, `")) - ).emit(); + .map(|trait_item| trait_item.name.to_string()) + .collect::>().join("`, `"))); + for trait_item in missing_items { + if let Some(span) = tcx.map.span_if_local(trait_item.def_id) { + err.span_label(span, &format!("`{}` from trait", trait_item.name)); + } else { + err.note(&format!("`{}` from trait: `{}`", + trait_item.name, + signature(&trait_item))); + } + } + err.emit(); } if !invalidated_items.is_empty() { @@ -1164,7 +1205,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, fcx.check_expr_coercable_to_type(expr, expected_type); fcx.select_all_obligations_and_apply_defaults(); - fcx.closure_analyze_const(expr); + fcx.closure_analyze(expr); fcx.select_obligations_where_possible(); fcx.check_casts(); fcx.select_all_obligations_or_error(); @@ -1188,7 +1229,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, item_id: ast::NodeId) -> bool { - let rty = tcx.node_id_to_type(item_id); + let rty = tcx.tables().node_id_to_type(item_id); // Check that it is possible to represent this type. This call identifies // (1) types that contain themselves and (2) types that contain a different @@ -1207,7 +1248,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::NodeId) { - let t = tcx.node_id_to_type(id); + let t = tcx.tables().node_id_to_type(id); match t.sty { ty::TyAdt(def, substs) if def.is_struct() => { let fields = &def.struct_variant().fields; @@ -1351,19 +1392,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { Ok(r) } - fn trait_defines_associated_type_named(&self, - trait_def_id: DefId, - assoc_name: ast::Name) - -> bool - { - self.tcx().impl_or_trait_items(trait_def_id).iter().any(|&def_id| { - match self.tcx().impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => item.name == assoc_name, - _ => false - } - }) - } - fn ty_infer(&self, _span: Span) -> Ty<'tcx> { self.next_ty_var() } @@ -1463,6 +1491,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ret_ty: rty, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), + diverges: Cell::new(Diverges::Maybe), + has_errors: Cell::new(false), inh: inh, } } @@ -1479,6 +1509,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.sess.err_count() - self.err_count_on_creation } + /// Produce warning on the given node, if the current point in the + /// function is unreachable, and there hasn't been another warning. + fn warn_if_unreachable(&self, id: ast::NodeId, span: Span, kind: &str) { + if self.diverges.get() == Diverges::Always { + self.diverges.set(Diverges::WarnedAlways); + + self.tcx.sess.add_lint(lint::builtin::UNREACHABLE_CODE, + id, span, + format!("unreachable {}", kind)); + } + } + /// Resolves type variables in `ty` if possible. Unlike the infcx /// version (resolve_type_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort @@ -1549,6 +1591,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("write_ty({}, {:?}) in fcx {}", node_id, ty, self.tag()); self.tables.borrow_mut().node_types.insert(node_id, ty); + + if ty.references_error() { + self.has_errors.set(true); + } + + // FIXME(canndrew): This is_never should probably be an is_uninhabited + if ty.is_never() || self.type_var_diverges(ty) { + self.diverges.set(self.diverges.get() | Diverges::Always); + } } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -1564,20 +1615,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn write_autoderef_adjustment(&self, node_id: ast::NodeId, - derefs: usize) { - self.write_adjustment( - node_id, - adjustment::AdjustDerefRef(adjustment::AutoDerefRef { + derefs: usize, + adjusted_ty: Ty<'tcx>) { + self.write_adjustment(node_id, adjustment::Adjustment { + kind: adjustment::Adjust::DerefRef { autoderefs: derefs, autoref: None, - unsize: None - }) - ); + unsize: false + }, + target: adjusted_ty + }); } pub fn write_adjustment(&self, node_id: ast::NodeId, - adj: adjustment::AutoAdjustment<'tcx>) { + adj: adjustment::Adjustment<'tcx>) { debug!("write_adjustment(node_id={}, adj={:?})", node_id, adj); if adj.is_identity() { @@ -1608,12 +1660,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// As `instantiate_type_scheme`, but for the bounds found in a /// generic type scheme. - fn instantiate_bounds(&self, - span: Span, - substs: &Substs<'tcx>, - bounds: &ty::GenericPredicates<'tcx>) - -> ty::InstantiatedPredicates<'tcx> - { + fn instantiate_bounds(&self, span: Span, def_id: DefId, substs: &Substs<'tcx>) + -> ty::InstantiatedPredicates<'tcx> { + let bounds = self.tcx.lookup_predicates(def_id); let result = bounds.instantiate(self.tcx, substs); let result = self.normalize_associated_types_in(span, &result.predicates); debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", @@ -1743,21 +1792,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { t } - /// Apply `adjustment` to the type of `expr` - pub fn adjust_expr_ty(&self, - expr: &hir::Expr, - adjustment: Option<&adjustment::AutoAdjustment<'tcx>>) - -> Ty<'tcx> - { - let raw_ty = self.node_ty(expr.id); - let raw_ty = self.shallow_resolve(raw_ty); - let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty); - raw_ty.adjust(self.tcx, expr.span, expr.id, adjustment, |method_call| { - self.tables.borrow().method_map.get(&method_call) - .map(|method| resolve_ty(method.ty)) - }) - } - pub fn node_ty(&self, id: ast::NodeId) -> Ty<'tcx> { match self.tables.borrow().node_types.get(&id) { Some(&t) => t, @@ -1972,13 +2006,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We must collect the defaults *before* we do any unification. Because we have // directly attached defaults to the type variables any unification that occurs // will erase defaults causing conflicting defaults to be completely ignored. - let default_map: FnvHashMap<_, _> = + let default_map: FxHashMap<_, _> = unsolved_variables .iter() .filter_map(|t| self.default(t).map(|d| (t, d))) .collect(); - let mut unbound_tyvars = FnvHashSet(); + let mut unbound_tyvars = FxHashSet(); debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map); @@ -2126,8 +2160,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // table then apply defaults until we find a conflict. That default must be the one // that caused conflict earlier. fn find_conflicting_default(&self, - unbound_vars: &FnvHashSet>, - default_map: &FnvHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>, + unbound_vars: &FxHashSet>, + default_map: &FxHashMap<&Ty<'tcx>, type_variable::Default<'tcx>>, conflict: Ty<'tcx>) -> Option> { use rustc::ty::error::UnconstrainedNumeric::Neither; @@ -2294,7 +2328,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("try_index_step: success, using built-in indexing"); // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. assert!(!unsize); - self.write_autoderef_adjustment(base_expr.id, autoderefs); + self.write_autoderef_adjustment(base_expr.id, autoderefs, adjusted_ty); return Some((tcx.types.usize, ty)); } _ => {} @@ -2498,21 +2532,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Check the arguments. // We do this in a pretty awful way: first we typecheck any arguments - // that are not anonymous functions, then we typecheck the anonymous - // functions. This is so that we have more information about the types - // of arguments when we typecheck the functions. This isn't really the - // right way to do this. - let xs = [false, true]; - let mut any_diverges = false; // has any of the arguments diverged? - let mut warned = false; // have we already warned about unreachable code? - for check_blocks in &xs { - let check_blocks = *check_blocks; - debug!("check_blocks={}", check_blocks); + // that are not closures, then we typecheck the closures. This is so + // that we have more information about the types of arguments when we + // typecheck the functions. This isn't really the right way to do this. + for &check_closures in &[false, true] { + debug!("check_closures={}", check_closures); // More awful hacks: before we check argument types, try to do // an "opportunistic" vtable resolution of any trait bounds on // the call. This helps coercions. - if check_blocks { + if check_closures { self.select_obligations_where_possible(); } @@ -2527,61 +2556,43 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { supplied_arg_count }; for (i, arg) in args.iter().take(t).enumerate() { - if any_diverges && !warned { - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - arg.id, - arg.span, - "unreachable expression".to_string()); - warned = true; + // Warn only for the first loop (the "no closures" one). + // Closure arguments themselves can't be diverging, but + // a previous argument can, e.g. `foo(panic!(), || {})`. + if !check_closures { + self.warn_if_unreachable(arg.id, arg.span, "expression"); } - let is_block = match arg.node { + + let is_closure = match arg.node { hir::ExprClosure(..) => true, _ => false }; - if is_block == check_blocks { - debug!("checking the argument"); - let formal_ty = formal_tys[i]; - - // The special-cased logic below has three functions: - // 1. Provide as good of an expected type as possible. - let expected = expected_arg_tys.get(i).map(|&ty| { - Expectation::rvalue_hint(self, ty) - }); - - let checked_ty = self.check_expr_with_expectation(&arg, - expected.unwrap_or(ExpectHasType(formal_ty))); - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.and_then(|e| e.only_has_type(self)); - self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty)); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty)); + if is_closure != check_closures { + continue; } - if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) { - // FIXME(canndrew): This is_never should probably be an is_uninhabited - any_diverges = any_diverges || - self.type_var_diverges(arg_ty) || - arg_ty.is_never(); - } - } - if any_diverges && !warned { - let parent = self.tcx.map.get_parent_node(args[0].id); - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - parent, - sp, - "unreachable call".to_string()); - warned = true; - } + debug!("checking the argument"); + let formal_ty = formal_tys[i]; + // The special-cased logic below has three functions: + // 1. Provide as good of an expected type as possible. + let expected = expected_arg_tys.get(i).map(|&ty| { + Expectation::rvalue_hint(self, ty) + }); + + let checked_ty = self.check_expr_with_expectation(&arg, + expected.unwrap_or(ExpectHasType(formal_ty))); + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerce_ty = expected.and_then(|e| e.only_has_type(self)); + self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty)); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty)); + } } // We also need to make sure we at least write the ty of the other @@ -2832,27 +2843,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { sp: Span, expected: Expectation<'tcx>) -> Ty<'tcx> { let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool); + let cond_diverges = self.diverges.get(); + self.diverges.set(Diverges::Maybe); let expected = expected.adjust_for_branches(self); let then_ty = self.check_block_with_expected(then_blk, expected); + let then_diverges = self.diverges.get(); + self.diverges.set(Diverges::Maybe); let unit = self.tcx.mk_nil(); let (origin, expected, found, result) = if let Some(else_expr) = opt_else_expr { let else_ty = self.check_expr_with_expectation(else_expr, expected); - let origin = TypeOrigin::IfExpression(sp); + let else_diverges = self.diverges.get(); // Only try to coerce-unify if we have a then expression // to assign coercions to, otherwise it's () or diverging. + let origin = TypeOrigin::IfExpression(sp); let result = if let Some(ref then) = then_blk.expr { let res = self.try_find_coercion_lub(origin, || Some(&**then), then_ty, else_expr, else_ty); // In case we did perform an adjustment, we have to update // the type of the block, because old trans still uses it. - let adj = self.tables.borrow().adjustments.get(&then.id).cloned(); - if res.is_ok() && adj.is_some() { - self.write_ty(then_blk.id, self.adjust_expr_ty(then, adj.as_ref())); + if res.is_ok() { + let adj = self.tables.borrow().adjustments.get(&then.id).cloned(); + if let Some(adj) = adj { + self.write_ty(then_blk.id, adj.target); + } } res @@ -2867,8 +2885,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) }) }; + + // We won't diverge unless both branches do (or the condition does). + self.diverges.set(cond_diverges | then_diverges & else_diverges); + (origin, then_ty, else_ty, result) } else { + // If the condition is false we can't diverge. + self.diverges.set(cond_diverges); + let origin = TypeOrigin::IfExpressionWithNoElse(sp); (origin, unit, then_ty, self.eq_types(true, origin, unit, then_ty) @@ -2913,7 +2938,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_ty = self.field_ty(expr.span, field, substs); if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { autoderef.finalize(lvalue_pref, Some(base)); - self.write_autoderef_adjustment(base.id, autoderefs); + self.write_autoderef_adjustment(base.id, autoderefs, base_t); return field_ty; } private_candidate = Some((base_def.did, field_ty)); @@ -3031,7 +3056,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field_ty) = field { autoderef.finalize(lvalue_pref, Some(base)); - self.write_autoderef_adjustment(base.id, autoderefs); + self.write_autoderef_adjustment(base.id, autoderefs, base_t); return field_ty; } } @@ -3118,12 +3143,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") }; - let mut remaining_fields = FnvHashMap(); + let mut remaining_fields = FxHashMap(); for field in &variant.fields { remaining_fields.insert(field.name, field); } - let mut seen_fields = FnvHashMap(); + let mut seen_fields = FxHashMap(); let mut error_happened = false; @@ -3235,6 +3260,16 @@ 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)) @@ -3246,16 +3281,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some((variant, did, substs)) = variant { - if variant.ctor_kind == CtorKind::Fn && - !self.tcx.sess.features.borrow().relaxed_adts { - emit_feature_err(&self.tcx.sess.parse_sess, - "relaxed_adts", path.span, GateIssue::Language, - "tuple structs and variants in struct patterns are unstable"); - } - // Check bounds on type arguments used in the path. - let type_predicates = self.tcx.lookup_predicates(did); - let bounds = self.instantiate_bounds(path.span, substs, &type_predicates); + let bounds = self.instantiate_bounds(path.span, did, substs); let cause = traits::ObligationCause::new(path.span, self.body_id, traits::ItemObligation(did)); self.add_obligations_for_parameters(cause, &bounds); @@ -3327,10 +3354,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lvalue_pref: LvaluePreference) -> Ty<'tcx> { debug!(">> typechecking: expr={:?} expected={:?}", expr, expected); + + // Warn for expressions after diverging siblings. + self.warn_if_unreachable(expr.id, expr.span, "expression"); + + // Hide the outer diverging and has_errors flags. + let old_diverges = self.diverges.get(); + let old_has_errors = self.has_errors.get(); + self.diverges.set(Diverges::Maybe); + self.has_errors.set(false); + let ty = self.check_expr_kind(expr, expected, lvalue_pref); + // Warn for non-block expressions with diverging children. + match expr.node { + hir::ExprBlock(_) | + hir::ExprLoop(..) | hir::ExprWhile(..) | + hir::ExprIf(..) | hir::ExprMatch(..) => {} + + _ => self.warn_if_unreachable(expr.id, expr.span, "expression") + } + + // Record the type, which applies it effects. + // We need to do this after the warning above, so that + // we don't warn for the diverging expression itself. self.write_ty(expr.id, ty); + // Combine the diverging and has_error flags. + self.diverges.set(self.diverges.get() | old_diverges); + self.has_errors.set(self.has_errors.get() | old_has_errors); + debug!("type of expr({}) {} is...", expr.id, pprust::expr_to_string(expr)); debug!("... {:?}, expected is {:?}", @@ -3341,8 +3394,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if ty.is_never() { if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(expr.id) { let adj_ty = self.next_diverging_ty_var(); - let adj = adjustment::AdjustNeverToAny(adj_ty); - self.write_adjustment(expr.id, adj); + self.write_adjustment(expr.id, adjustment::Adjustment { + kind: adjustment::Adjust::NeverToAny, + target: adj_ty + }); return adj_ty; } } @@ -3553,22 +3608,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { - let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool); + self.check_expr_has_type(&cond, tcx.types.bool); + let cond_diverging = self.diverges.get(); self.check_block_no_value(&body); - let body_ty = self.node_ty(body.id); - if cond_ty.references_error() || body_ty.references_error() { + + // We may never reach the body so it diverging means nothing. + self.diverges.set(cond_diverging); + + if self.has_errors.get() { tcx.types.err - } - else { + } else { tcx.mk_nil() } } hir::ExprLoop(ref body, _) => { self.check_block_no_value(&body); - if !may_break(tcx, expr.id, &body) { - tcx.types.never - } else { + if may_break(tcx, expr.id, &body) { + // No way to know whether it's diverging because + // of a `break` or an outer `break` or `return. + self.diverges.set(Diverges::Maybe); + tcx.mk_nil() + } else { + tcx.types.never } } hir::ExprMatch(ref discrim, ref arms, match_src) => { @@ -3901,55 +3963,66 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) { - let node_id; - let mut saw_bot = false; - let mut saw_err = false; + // Don't do all the complex logic below for DeclItem. match stmt.node { - hir::StmtDecl(ref decl, id) => { - node_id = id; - match decl.node { - hir::DeclLocal(ref l) => { - self.check_decl_local(&l); - let l_t = self.node_ty(l.id); - saw_bot = saw_bot || self.type_var_diverges(l_t); - saw_err = saw_err || l_t.references_error(); - } - hir::DeclItem(_) => {/* ignore for now */ } + hir::StmtDecl(ref decl, id) => { + match decl.node { + hir::DeclLocal(_) => {} + hir::DeclItem(_) => { + self.write_nil(id); + return; + } + } } - } - hir::StmtExpr(ref expr, id) => { - node_id = id; - // Check with expected type of () - let ty = self.check_expr_has_type(&expr, self.tcx.mk_nil()); - saw_bot = saw_bot || self.type_var_diverges(ty); - saw_err = saw_err || ty.references_error(); - } - hir::StmtSemi(ref expr, id) => { - node_id = id; - let ty = self.check_expr(&expr); - saw_bot |= self.type_var_diverges(ty); - saw_err |= ty.references_error(); - } + hir::StmtExpr(..) | hir::StmtSemi(..) => {} } - if saw_bot { - self.write_ty(node_id, self.next_diverging_ty_var()); - } - else if saw_err { + + self.warn_if_unreachable(stmt.node.id(), stmt.span, "statement"); + + // Hide the outer diverging and has_errors flags. + let old_diverges = self.diverges.get(); + let old_has_errors = self.has_errors.get(); + self.diverges.set(Diverges::Maybe); + self.has_errors.set(false); + + let node_id = match stmt.node { + hir::StmtDecl(ref decl, id) => { + match decl.node { + hir::DeclLocal(ref l) => { + self.check_decl_local(&l); + } + hir::DeclItem(_) => {/* ignore for now */ } + } + id + } + hir::StmtExpr(ref expr, id) => { + // Check with expected type of () + self.check_expr_has_type(&expr, self.tcx.mk_nil()); + id + } + hir::StmtSemi(ref expr, id) => { + self.check_expr(&expr); + id + } + }; + + if self.has_errors.get() { self.write_error(node_id); - } - else { + } else if self.diverges.get().always() { + self.write_ty(node_id, self.next_diverging_ty_var()); + } else { self.write_nil(node_id); } + + // Combine the diverging and has_error flags. + self.diverges.set(self.diverges.get() | old_diverges); + self.has_errors.set(self.has_errors.get() | old_has_errors); } pub fn check_block_no_value(&self, blk: &'gcx hir::Block) { - let blkty = self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil())); - if blkty.references_error() { - self.write_error(blk.id); - } else { - let nilty = self.tcx.mk_nil(); - self.demand_suptype(blk.span, nilty, blkty); - } + let unit = self.tcx.mk_nil(); + let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); + self.demand_suptype(blk.span, unit, ty); } fn check_block_with_expected(&self, @@ -3961,72 +4034,81 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { replace(&mut *fcx_ps, unsafety_state) }; - let mut warned = false; - let mut any_diverges = false; - let mut any_err = false; for s in &blk.stmts { self.check_stmt(s); - let s_id = s.node.id(); - let s_ty = self.node_ty(s_id); - if any_diverges && !warned && match s.node { - hir::StmtDecl(ref decl, _) => { - match decl.node { - hir::DeclLocal(_) => true, - _ => false, - } - } - hir::StmtExpr(..) | hir::StmtSemi(..) => true, - } { - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - s_id, - s.span, - "unreachable statement".to_string()); - warned = true; - } - // FIXME(canndrew): This is_never should probably be an is_uninhabited - any_diverges = any_diverges || - self.type_var_diverges(s_ty) || - s_ty.is_never(); - any_err = any_err || s_ty.references_error(); } - let ty = match blk.expr { - None => if any_err { - self.tcx.types.err - } else if any_diverges { - self.next_diverging_ty_var() - } else { - self.tcx.mk_nil() - }, - Some(ref e) => { - if any_diverges && !warned { - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - e.id, - e.span, - "unreachable expression".to_string()); - } - let ety = match expected { - ExpectHasType(ety) => { - self.check_expr_coercable_to_type(&e, ety); - ety - } - _ => { - self.check_expr_with_expectation(&e, expected) - } - }; - if any_err { - self.tcx.types.err - } else if any_diverges { - self.next_diverging_ty_var() - } else { - ety + let mut ty = match blk.expr { + Some(ref e) => self.check_expr_with_expectation(e, expected), + None => self.tcx.mk_nil() + }; + + if self.diverges.get().always() { + if let ExpectHasType(ety) = expected { + // Avoid forcing a type (only `!` for now) in unreachable code. + // FIXME(aburka) do we need this special case? and should it be is_uninhabited? + if !ety.is_never() { + if let Some(ref e) = blk.expr { + // Coerce the tail expression to the right type. + self.demand_coerce(e, ty, ety); + } } } - }; + + ty = self.next_diverging_ty_var(); + } else if let ExpectHasType(ety) = expected { + if let Some(ref e) = blk.expr { + // Coerce the tail expression to the right type. + self.demand_coerce(e, ty, ety); + } else { + // We're not diverging and there's an expected type, which, + // in case it's not `()`, could result in an error higher-up. + // We have a chance to error here early and be more helpful. + let origin = TypeOrigin::Misc(blk.span); + let trace = TypeTrace::types(origin, false, ty, ety); + match self.sub_types(false, origin, ty, ety) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }, + Err(err) => { + let mut err = self.report_and_explain_type_error(trace, &err); + + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let mut extra_semi = None; + if let Some(stmt) = blk.stmts.last() { + if let hir::StmtSemi(ref e, _) = stmt.node { + if self.can_sub_types(self.node_ty(e.id), ety).is_ok() { + extra_semi = Some(stmt); + } + } + } + if let Some(last_stmt) = extra_semi { + let original_span = original_sp(self.tcx.sess.codemap(), + last_stmt.span, blk.span); + let span_semi = Span { + lo: original_span.hi - BytePos(1), + hi: original_span.hi, + expn_id: original_span.expn_id + }; + err.span_help(span_semi, "consider removing this semicolon:"); + } + + err.emit(); + } + } + } + + // We already applied the type (and potentially errored), + // use the expected type to avoid further errors out. + ty = ety; + } + + if self.has_errors.get() || ty.references_error() { + ty = self.tcx.types.err + } + self.write_ty(blk.id, ty); *self.ps.borrow_mut() = prev; @@ -4122,7 +4204,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Case 3. Reference to a method or associated const. Def::Method(def_id) | Def::AssociatedConst(def_id) => { - let container = self.tcx.impl_or_trait_item(def_id).container(); + let container = self.tcx.associated_item(def_id).container; match container { ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(self.ccx, span, trait_did) @@ -4263,13 +4345,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. let scheme = self.tcx.lookup_item_type(def.def_id()); - let type_predicates = self.tcx.lookup_predicates(def.def_id()); assert!(!substs.has_escaping_regions()); assert!(!scheme.ty.has_escaping_regions()); // Add all the obligations that are required, substituting and // normalized appropriately. - let bounds = self.instantiate_bounds(span, &substs, &type_predicates); + let bounds = self.instantiate_bounds(span, def.def_id(), &substs); self.add_obligations_for_parameters( traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())), &bounds); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 411bd7e7b5ca..8b4975b7e3a2 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -75,8 +75,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { // && and || are a simple case. + let lhs_diverges = self.diverges.get(); self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool()); + + // Depending on the LHS' value, the RHS can never execute. + self.diverges.set(lhs_diverges); + tcx.mk_bool() } _ => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 939deee27c60..d4e5e9a5bb35 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -142,13 +142,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn regionck_fn(&self, fn_id: ast::NodeId, decl: &hir::FnDecl, - blk: &hir::Block) { + body: &hir::Expr) { debug!("regionck_fn(id={})", fn_id); - let mut rcx = RegionCtxt::new(self, RepeatingScope(blk.id), blk.id, Subject(fn_id)); + let mut rcx = RegionCtxt::new(self, RepeatingScope(body.id), body.id, Subject(fn_id)); if self.err_count_since_creation() == 0 { // regionck assumes typeck succeeded - rcx.visit_fn_body(fn_id, decl, blk, self.tcx.map.span(fn_id)); + rcx.visit_fn_body(fn_id, decl, body, self.tcx.map.span(fn_id)); } rcx.free_region_map.relate_free_regions_from_predicates( @@ -259,29 +259,16 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.resolve_type(t) } - fn resolve_method_type(&self, method_call: MethodCall) -> Option> { - let method_ty = self.tables.borrow().method_map - .get(&method_call).map(|method| method.ty); - method_ty.map(|method_ty| self.resolve_type(method_ty)) - } - /// Try to resolve the type for the given node. pub fn resolve_expr_type_adjusted(&mut self, expr: &hir::Expr) -> Ty<'tcx> { - let ty_unadjusted = self.resolve_node_type(expr.id); - if ty_unadjusted.references_error() { - ty_unadjusted - } else { - ty_unadjusted.adjust( - self.tcx, expr.span, expr.id, - self.tables.borrow().adjustments.get(&expr.id), - |method_call| self.resolve_method_type(method_call)) - } + let ty = self.tables.borrow().expr_ty_adjusted(expr); + self.resolve_type(ty) } fn visit_fn_body(&mut self, id: ast::NodeId, // the id of the fn itself fn_decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, span: Span) { // When we enter a function, we can derive @@ -318,7 +305,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.relate_free_regions(&fn_sig_tys[..], body.id, span); self.link_fn_args(self.tcx.region_maps.node_extent(body.id), &fn_decl.inputs[..]); - self.visit_block(body); + self.visit_expr(body); self.visit_region_obligations(body.id); let call_site_scope = self.call_site_scope.unwrap(); @@ -356,7 +343,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("visit_region_obligations: r_o={:?} cause={:?}", r_o, r_o.cause); let sup_type = self.resolve_type(r_o.sup_type); - let origin = self.code_to_origin(r_o.cause.span, sup_type, &r_o.cause.code); + let origin = self.code_to_origin(&r_o.cause, sup_type); self.type_must_outlive(origin, sup_type, r_o.sub_region); } @@ -366,16 +353,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } fn code_to_origin(&self, - span: Span, - sup_type: Ty<'tcx>, - code: &traits::ObligationCauseCode<'tcx>) + cause: &traits::ObligationCause<'tcx>, + sup_type: Ty<'tcx>) -> SubregionOrigin<'tcx> { - match *code { - traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => - infer::ReferenceOutlivesReferent(ref_type, span), - _ => - infer::RelateParamBound(span, sup_type), - } + SubregionOrigin::from_obligation_cause(cause, + || infer::RelateParamBound(cause.span, sup_type)) } /// This method populates the region map's `free_region_map`. It walks over the transformed @@ -498,7 +480,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { // regions, until regionck, as described in #3238. fn visit_fn(&mut self, _fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, span: Span, id: ast::NodeId) { + b: &'v hir::Expr, span: Span, id: ast::NodeId) { self.visit_fn_body(id, fd, b, span) } @@ -558,10 +540,8 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { let adjustment = self.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone()); if let Some(adjustment) = adjustment { debug!("adjustment={:?}", adjustment); - match adjustment { - adjustment::AdjustDerefRef(adjustment::AutoDerefRef { - autoderefs, ref autoref, .. - }) => { + match adjustment.kind { + adjustment::Adjust::DerefRef { autoderefs, ref autoref, .. } => { let expr_ty = self.resolve_node_type(expr.id); self.constrain_autoderefs(expr, autoderefs, expr_ty); if let Some(ref autoref) = *autoref { @@ -845,7 +825,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn check_expr_fn_block(&mut self, expr: &hir::Expr, - body: &hir::Block) { + body: &hir::Expr) { let repeating_scope = self.set_repeating_scope(body.id); intravisit::walk_expr(self, expr); self.set_repeating_scope(repeating_scope); @@ -951,7 +931,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = infer::ParameterOrigin::OverloadedDeref; self.substs_wf_in_scope(origin, method.substs, deref_expr.span, r_deref_expr); - // Treat overloaded autoderefs as if an AutoRef adjustment + // Treat overloaded autoderefs as if an AutoBorrow adjustment // was applied on the base type, as that is always the case. let fn_sig = method.ty.fn_sig(); let fn_sig = // late-bound regions should have been instantiated @@ -1065,15 +1045,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { id: ast::NodeId, minimum_lifetime: &'tcx ty::Region) { - let tcx = self.tcx; - // Try to resolve the type. If we encounter an error, then typeck // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. let ty0 = self.resolve_node_type(id); - let ty = ty0.adjust(tcx, origin.span(), id, - self.tables.borrow().adjustments.get(&id), - |method_call| self.resolve_method_type(method_call)); + let ty = self.tables.borrow().adjustments.get(&id).map_or(ty0, |adj| adj.target); + let ty = self.resolve_type(ty); debug!("constrain_regions_in_type_of_node(\ ty={}, ty0={}, id={}, minimum_lifetime={:?})", ty, ty0, @@ -1170,7 +1147,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn link_autoref(&self, expr: &hir::Expr, autoderefs: usize, - autoref: &adjustment::AutoRef<'tcx>) + autoref: &adjustment::AutoBorrow<'tcx>) { debug!("link_autoref(autoref={:?})", autoref); let mc = mc::MemCategorizationContext::new(self); @@ -1178,12 +1155,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("expr_cmt={:?}", expr_cmt); match *autoref { - adjustment::AutoPtr(r, m) => { + adjustment::AutoBorrow::Ref(r, m) => { self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } - adjustment::AutoUnsafe(m) => { + adjustment::AutoBorrow::RawPtr(m) => { let r = self.tcx.node_scope_region(expr.id); self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } @@ -1474,7 +1451,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { assert!(!ty.has_escaping_regions()); - let components = self.outlives_components(ty); + let components = self.tcx.outlives_components(ty); self.components_must_outlive(origin, components, region); } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index aa221c33b5dd..2fea86cb2120 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -57,18 +57,7 @@ use rustc::util::nodemap::NodeMap; // PUBLIC ENTRY POINTS impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn closure_analyze_fn(&self, body: &hir::Block) { - let mut seed = SeedBorrowKind::new(self); - seed.visit_block(body); - - let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); - adjust.visit_block(body); - - // it's our job to process these. - assert!(self.deferred_call_resolutions.borrow().is_empty()); - } - - pub fn closure_analyze_const(&self, body: &hir::Expr) { + pub fn closure_analyze(&self, body: &hir::Expr) { let mut seed = SeedBorrowKind::new(self); seed.visit_expr(body); @@ -110,7 +99,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { fn check_closure(&mut self, expr: &hir::Expr, capture_clause: hir::CaptureClause, - _body: &hir::Block) + _body: &hir::Expr) { let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id); if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) { @@ -164,7 +153,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { id: ast::NodeId, span: Span, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { /*! * Analysis starting point. */ @@ -497,7 +486,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'gcx, 'tcx> { fn visit_fn(&mut self, fn_kind: intravisit::FnKind<'v>, decl: &'v hir::FnDecl, - body: &'v hir::Block, + body: &'v hir::Expr, span: Span, id: ast::NodeId) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index e3634cfe5f5e..4136f543ccca 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -8,15 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use astconv::ExplicitSelf; use check::FnCtxt; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; + use hir::def_id::DefId; use middle::region::{CodeExtent}; use rustc::infer::TypeOrigin; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::util::nodemap::{FnvHashSet, FnvHashMap}; +use rustc::util::nodemap::{FxHashSet, FxHashMap}; use syntax::ast; use syntax_pos::Span; @@ -156,8 +158,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { self.check_variances_for_type_defn(item, ast_generics); } - hir::ItemTrait(.., ref items) => { - self.check_trait(item, items); + hir::ItemTrait(..) => { + self.check_trait(item); } _ => {} } @@ -172,32 +174,39 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let free_substs = &fcx.parameter_environment.free_substs; let free_id_outlive = fcx.parameter_environment.free_id_outlive; - let item = fcx.tcx.impl_or_trait_item(fcx.tcx.map.local_def_id(item_id)); + let item = fcx.tcx.associated_item(fcx.tcx.map.local_def_id(item_id)); - let (mut implied_bounds, self_ty) = match item.container() { + let (mut implied_bounds, self_ty) = match item.container { ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()), ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span), fcx.tcx.lookup_item_type(def_id).ty) }; - match item { - ty::ConstTraitItem(assoc_const) => { - let ty = fcx.instantiate_type_scheme(span, free_substs, &assoc_const.ty); + match item.kind { + ty::AssociatedKind::Const => { + let ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } - ty::MethodTraitItem(method) => { - reject_shadowing_type_parameters(fcx.tcx, span, &method.generics); - let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); - let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates); - this.check_fn_or_method(fcx, span, &method_ty, &predicates, + ty::AssociatedKind::Method => { + reject_shadowing_type_parameters(fcx.tcx, span, item.def_id); + let method_ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); + let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs); + let fty = match method_ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + }; + this.check_fn_or_method(fcx, span, fty, &predicates, free_id_outlive, &mut implied_bounds); let sig_if_method = sig_if_method.expect("bad signature for method"); - this.check_method_receiver(fcx, sig_if_method, &method, + this.check_method_receiver(fcx, sig_if_method, &item, free_id_outlive, self_ty); } - ty::TypeTraitItem(assoc_type) => { - if let Some(ref ty) = assoc_type.ty { - let ty = fcx.instantiate_type_scheme(span, free_substs, ty); + ty::AssociatedKind::Type => { + if item.has_value { + let ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } } @@ -248,19 +257,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } let free_substs = &fcx.parameter_environment.free_substs; - let predicates = fcx.tcx.lookup_predicates(fcx.tcx.map.local_def_id(item.id)); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let def_id = fcx.tcx.map.local_def_id(item.id); + let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); vec![] // no implied bounds in a struct def'n }); } - fn check_auto_trait(&mut self, - trait_def_id: DefId, - items: &[hir::TraitItem], - span: Span) - { + fn check_auto_trait(&mut self, trait_def_id: DefId, span: Span) { // We want to ensure: // // 1) that there are no items contained within @@ -302,7 +307,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { // extraneous predicates created by things like // an associated type inside the trait. let mut err = None; - if !items.is_empty() { + if !self.tcx().associated_item_def_ids(trait_def_id).is_empty() { error_380(self.ccx, span); } else if has_ty_params { err = Some(struct_span_err!(self.tcx().sess, span, E0567, @@ -326,20 +331,16 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } - fn check_trait(&mut self, - item: &hir::Item, - items: &[hir::TraitItem]) - { + fn check_trait(&mut self, item: &hir::Item) { let trait_def_id = self.tcx().map.local_def_id(item.id); if self.tcx().trait_has_default_impl(trait_def_id) { - self.check_auto_trait(trait_def_id, items, item.span); + self.check_auto_trait(trait_def_id, item.span); } self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; - let predicates = fcx.tcx.lookup_predicates(trait_def_id); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let predicates = fcx.instantiate_bounds(item.span, trait_def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); vec![] }); @@ -347,11 +348,12 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn check_item_fn(&mut self, item: &hir::Item, - body: &hir::Block) + body: &hir::Expr) { self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; - let type_scheme = fcx.tcx.lookup_item_type(fcx.tcx.map.local_def_id(item.id)); + let def_id = fcx.tcx.map.local_def_id(item.id); + let type_scheme = fcx.tcx.lookup_item_type(def_id); let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty); let bare_fn_ty = match item_ty.sty { ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty, @@ -360,8 +362,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } }; - let predicates = fcx.tcx.lookup_predicates(fcx.tcx.map.local_def_id(item.id)); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs); let mut implied_bounds = vec![]; let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body.id); @@ -416,14 +417,13 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } None => { - let self_ty = fcx.tcx.node_id_to_type(item.id); + let self_ty = fcx.tcx.tables().node_id_to_type(item.id); let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty); fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone()); } } - let predicates = fcx.tcx.lookup_predicates(item_def_id); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let predicates = fcx.instantiate_bounds(item.span, item_def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); fcx.impl_implied_bounds(fcx.tcx.map.local_def_id(item.id), item.span) @@ -476,35 +476,39 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn check_method_receiver<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, method_sig: &hir::MethodSig, - method: &ty::Method<'tcx>, + method: &ty::AssociatedItem, free_id_outlive: CodeExtent, self_ty: ty::Ty<'tcx>) { // check that the type of the method's receiver matches the // method's first parameter. - debug!("check_method_receiver({:?},cat={:?},self_ty={:?})", - method.name, method.explicit_self, self_ty); + debug!("check_method_receiver({:?}, self_ty={:?})", + method, self_ty); - let rcvr_ty = match method.explicit_self { - ty::ExplicitSelfCategory::Static => return, - ty::ExplicitSelfCategory::ByValue => self_ty, - ty::ExplicitSelfCategory::ByReference(region, mutability) => { - fcx.tcx.mk_ref(region, ty::TypeAndMut { - ty: self_ty, - mutbl: mutability - }) - } - ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty) - }; + if !method.method_has_self_argument { + return; + } let span = method_sig.decl.inputs[0].pat.span; let free_substs = &fcx.parameter_environment.free_substs; - let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); - let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig); + let method_ty = fcx.tcx.lookup_item_type(method.def_id).ty; + let fty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); + let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.fn_sig()); debug!("check_method_receiver: sig={:?}", sig); + let self_arg_ty = sig.inputs[0]; + let rcvr_ty = match ExplicitSelf::determine(self_ty, self_arg_ty) { + ExplicitSelf::ByValue => self_ty, + ExplicitSelf::ByReference(region, mutbl) => { + fcx.tcx.mk_ref(region, ty::TypeAndMut { + ty: self_ty, + mutbl: mutbl + }) + } + ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty) + }; let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty); let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(rcvr_ty)); @@ -512,14 +516,14 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); let origin = TypeOrigin::MethodReceiver(span); - fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]); + fcx.demand_eqtype_with_origin(origin, rcvr_ty, self_arg_ty); } fn check_variances_for_type_defn(&self, item: &hir::Item, ast_generics: &hir::Generics) { - let ty = self.tcx().node_id_to_type(item.id); + let ty = self.tcx().tables().node_id_to_type(item.id); if self.tcx().has_error_field(ty) { return; } @@ -529,7 +533,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { assert_eq!(ty_predicates.parent, None); let variances = self.tcx().item_variances(item_def_id); - let mut constrained_parameters: FnvHashSet<_> = + let mut constrained_parameters: FxHashSet<_> = variances.iter().enumerate() .filter(|&(_, &variance)| variance != ty::Bivariant) .map(|(index, _)| Parameter(index as u32)) @@ -578,12 +582,13 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } -fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, generics: &ty::Generics) { +fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, def_id: DefId) { + let generics = tcx.lookup_generics(def_id); let parent = tcx.lookup_generics(generics.parent.unwrap()); - let impl_params: FnvHashMap<_, _> = parent.types - .iter() - .map(|tp| (tp.name, tp.def_id)) - .collect(); + let impl_params: FxHashMap<_, _> = parent.types + .iter() + .map(|tp| (tp.name, tp.def_id)) + .collect(); for method_param in &generics.types { if impl_params.contains_key(&method_param.name) { @@ -649,7 +654,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fields = struct_def.fields().iter() .map(|field| { - let field_ty = self.tcx.node_id_to_type(field.id); + let field_ty = self.tcx.tables().node_id_to_type(field.id); let field_ty = self.instantiate_type_scheme(field.span, &self.parameter_environment .free_substs, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 8685f703a599..9f3214a0d813 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -49,11 +49,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, - blk: &hir::Block, + body: &hir::Expr, item_id: ast::NodeId) { assert_eq!(self.writeback_errors.get(), false); let mut wbcx = WritebackCx::new(self); - wbcx.visit_block(blk); + wbcx.visit_expr(body); for arg in &decl.inputs { wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id); wbcx.visit_pat(&arg.pat); @@ -229,7 +229,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> { debug!("Type for pattern binding {} (id {}) resolved to {:?}", pat_to_string(p), p.id, - self.tcx().node_id_to_type(p.id)); + self.tcx().tables().node_id_to_type(p.id)); intravisit::walk_pat(self, p); } @@ -381,36 +381,40 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } Some(adjustment) => { - let resolved_adjustment = match adjustment { - adjustment::AdjustNeverToAny(ty) => { - adjustment::AdjustNeverToAny(self.resolve(&ty, reason)) + let resolved_adjustment = match adjustment.kind { + adjustment::Adjust::NeverToAny => { + adjustment::Adjust::NeverToAny } - adjustment::AdjustReifyFnPointer => { - adjustment::AdjustReifyFnPointer + adjustment::Adjust::ReifyFnPointer => { + adjustment::Adjust::ReifyFnPointer } - adjustment::AdjustMutToConstPointer => { - adjustment::AdjustMutToConstPointer + adjustment::Adjust::MutToConstPointer => { + adjustment::Adjust::MutToConstPointer } - adjustment::AdjustUnsafeFnPointer => { - adjustment::AdjustUnsafeFnPointer + adjustment::Adjust::UnsafeFnPointer => { + adjustment::Adjust::UnsafeFnPointer } - adjustment::AdjustDerefRef(adj) => { - for autoderef in 0..adj.autoderefs { + adjustment::Adjust::DerefRef { autoderefs, autoref, unsize } => { + for autoderef in 0..autoderefs { let method_call = MethodCall::autoderef(id, autoderef as u32); self.visit_method_map_entry(reason, method_call); } - adjustment::AdjustDerefRef(adjustment::AutoDerefRef { - autoderefs: adj.autoderefs, - autoref: self.resolve(&adj.autoref, reason), - unsize: self.resolve(&adj.unsize, reason), - }) + adjustment::Adjust::DerefRef { + autoderefs: autoderefs, + autoref: self.resolve(&autoref, reason), + unsize: unsize, + } } }; + let resolved_adjustment = adjustment::Adjustment { + kind: resolved_adjustment, + target: self.resolve(&adjustment.target, reason) + }; debug!("Adjustments for node {}: {:?}", id, resolved_adjustment); self.tcx().tables.borrow_mut().adjustments.insert( id, resolved_adjustment); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index ca22faa2ec36..90541539c1e2 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -38,8 +38,6 @@ use rustc::hir::intravisit; use rustc::hir::{Item, ItemImpl}; use rustc::hir; -use std::rc::Rc; - mod orphan; mod overlap; mod unsafety; @@ -113,8 +111,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // If there are no traits, then this implementation must have a // base type. - let impl_items = self.create_impl_from_item(item); - if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) { debug!("(checking implementation) adding impl for trait '{:?}', item '{}'", trait_ref, @@ -144,8 +140,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { self.add_inherent_impl(base_def_id, impl_did); } } - - tcx.impl_or_trait_item_def_ids.borrow_mut().insert(impl_did, Rc::new(impl_items)); } fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) { @@ -161,20 +155,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref); } - // Converts an implementation in the AST to a vector of items. - fn create_impl_from_item(&self, item: &Item) -> Vec { - match item.node { - ItemImpl(.., ref impl_items) => { - impl_items.iter() - .map(|impl_item| self.crate_context.tcx.map.local_def_id(impl_item.id)) - .collect() - } - _ => { - span_bug!(item.span, "can't convert a non-impl to an impl"); - } - } - } - // Destructors // @@ -187,10 +167,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { tcx.populate_implementations_for_trait_if_necessary(drop_trait); let drop_trait = tcx.lookup_trait_def(drop_trait); - let impl_items = tcx.impl_or_trait_item_def_ids.borrow(); - drop_trait.for_each_impl(tcx, |impl_did| { - let items = impl_items.get(&impl_did).unwrap(); + let items = tcx.associated_item_def_ids(impl_did); if items.is_empty() { // We'll error out later. For now, just don't ICE. return; @@ -415,15 +393,19 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { if f.unsubst_ty().is_phantom_data() { // Ignore PhantomData fields - None - } else if infcx.sub_types(false, origin, b, a).is_ok() { - // Ignore fields that aren't significantly changed - None - } else { - // Collect up all fields that were significantly changed - // i.e. those that contain T in coerce_unsized T -> U - Some((i, a, b)) + return None; } + + // Ignore fields that aren't significantly changed + if let Ok(ok) = infcx.sub_types(false, origin, b, a) { + if ok.obligations.is_empty() { + return None; + } + } + + // Collect up all fields that were significantly changed + // i.e. those that contain T in coerce_unsized T -> U + Some((i, a, b)) }) .collect::>(); diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 1bf140c21a5a..b5aba512a66b 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -48,25 +48,23 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { Value, } - fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> (ast::Name, Namespace) { - let item = tcx.impl_or_trait_item(def_id); - (item.name(), - match item { - ty::TypeTraitItem(..) => Namespace::Type, - ty::ConstTraitItem(..) => Namespace::Value, - ty::MethodTraitItem(..) => Namespace::Value, - }) - } + let name_and_namespace = |def_id| { + let item = self.tcx.associated_item(def_id); + (item.name, match item.kind { + ty::AssociatedKind::Type => Namespace::Type, + ty::AssociatedKind::Const | + ty::AssociatedKind::Method => Namespace::Value, + }) + }; - let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow(); + let impl_items1 = self.tcx.associated_item_def_ids(impl1); + let impl_items2 = self.tcx.associated_item_def_ids(impl2); - for &item1 in &impl_items[&impl1][..] { - let (name, namespace) = name_and_namespace(self.tcx, item1); + for &item1 in &impl_items1[..] { + let (name, namespace) = name_and_namespace(item1); - for &item2 in &impl_items[&impl2][..] { - if (name, namespace) == name_and_namespace(self.tcx, item2) { + for &item2 in &impl_items2[..] { + if (name, namespace) == name_and_namespace(item2) { let msg = format!("duplicate definitions with name `{}`", name); let node_id = self.tcx.map.as_local_node_id(item1).unwrap(); self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 202e176df0db..d92a98485103 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,20 +66,19 @@ use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::Substs; -use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; +use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::util::IntTypeExt; use rscope::*; use rustc::dep_graph::DepNode; use util::common::{ErrorReported, MemoizationMap}; -use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; +use util::nodemap::{NodeMap, FxHashMap, FxHashSet}; use {CrateCtxt, write_ty_to_tcx}; use rustc_const_math::ConstInt; use std::cell::RefCell; use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::rc::Rc; use syntax::{abi, ast, attr}; use syntax::parse::token::keywords; @@ -351,24 +350,6 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { }) } - fn trait_defines_associated_type_named(&self, - trait_def_id: DefId, - assoc_name: ast::Name) - -> bool - { - if let Some(trait_id) = self.tcx().map.as_local_node_id(trait_def_id) { - trait_associated_type_names(self.tcx(), trait_id) - .any(|name| name == assoc_name) - } else { - self.tcx().impl_or_trait_items(trait_def_id).iter().any(|&def_id| { - match self.tcx().impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => item.name == assoc_name, - _ => false - } - }) - } - } - fn get_free_substs(&self) -> Option<&Substs<'tcx>> { None } @@ -557,60 +538,6 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - name: ast::Name, - id: ast::NodeId, - vis: &hir::Visibility, - sig: &hir::MethodSig, - defaultness: hir::Defaultness, - has_body: bool, - untransformed_rcvr_ty: Ty<'tcx>, - rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) { - let def_id = ccx.tcx.map.local_def_id(id); - let ty_generics = generics_of_def_id(ccx, def_id); - - let ty_generic_predicates = - ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false); - - let (fty, explicit_self_category) = { - let anon_scope = match container { - ImplContainer(_) => Some(AnonTypeScope::new(def_id)), - TraitContainer(_) => None - }; - AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - sig, untransformed_rcvr_ty, anon_scope) - }; - - let ty_method = ty::Method { - name: name, - generics: ty_generics, - predicates: ty_generic_predicates, - fty: fty, - explicit_self: explicit_self_category, - vis: ty::Visibility::from_hir(vis, id, ccx.tcx), - defaultness: defaultness, - has_body: has_body, - def_id: def_id, - container: container, - }; - - let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - ccx.tcx.map.span(id), def_id); - let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty); - debug!("method {} (id {}) has type {:?}", - name, id, fty); - ccx.tcx.tcache.borrow_mut().insert(def_id, fty); - write_ty_to_tcx(ccx, id, fty); - ccx.tcx.predicates.borrow_mut().insert(def_id, ty_method.predicates.clone()); - - debug!("writing method type: def_id={:?} mty={:?}", - def_id, ty_method); - - ccx.tcx.impl_or_trait_items.borrow_mut().insert(def_id, - ty::MethodTraitItem(Rc::new(ty_method))); -} - fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_generics: &'tcx ty::Generics<'tcx>, struct_predicates: &ty::GenericPredicates<'tcx>, @@ -631,62 +558,65 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_predicates.clone()); } +fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + container: AssociatedItemContainer, + id: ast::NodeId, + sig: &hir::MethodSig, + untransformed_rcvr_ty: Ty<'tcx>, + rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) { + let def_id = ccx.tcx.map.local_def_id(id); + let ty_generics = generics_of_def_id(ccx, def_id); + + 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 fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), + sig, untransformed_rcvr_ty, anon_scope); + + let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), + ccx.tcx.map.span(id), def_id); + let fty = ccx.tcx.mk_fn_def(def_id, substs, fty); + ccx.tcx.tcache.borrow_mut().insert(def_id, fty); + write_ty_to_tcx(ccx, id, fty); + ccx.tcx.predicates.borrow_mut().insert(def_id, ty_generic_predicates); +} + fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - name: ast::Name, + container: AssociatedItemContainer, id: ast::NodeId, - vis: &hir::Visibility, - defaultness: hir::Defaultness, - ty: ty::Ty<'tcx>, - has_value: bool) + ty: ty::Ty<'tcx>) { let predicates = ty::GenericPredicates { parent: Some(container.id()), predicates: vec![] }; - ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id), - predicates); + let def_id = ccx.tcx.map.local_def_id(id); + ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); + ccx.tcx.tcache.borrow_mut().insert(def_id, ty); write_ty_to_tcx(ccx, id, ty); - - let associated_const = Rc::new(ty::AssociatedConst { - name: name, - vis: ty::Visibility::from_hir(vis, id, ccx.tcx), - defaultness: defaultness, - def_id: ccx.tcx.map.local_def_id(id), - container: container, - ty: ty, - has_value: has_value - }); - ccx.tcx.impl_or_trait_items.borrow_mut() - .insert(ccx.tcx.map.local_def_id(id), ty::ConstTraitItem(associated_const)); } fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - name: ast::Name, + container: AssociatedItemContainer, id: ast::NodeId, - vis: &hir::Visibility, - defaultness: hir::Defaultness, ty: Option>) { let predicates = ty::GenericPredicates { parent: Some(container.id()), predicates: vec![] }; - ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id), - predicates); + let def_id = ccx.tcx.map.local_def_id(id); + ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); - let associated_type = Rc::new(ty::AssociatedType { - name: name, - vis: ty::Visibility::from_hir(vis, id, ccx.tcx), - defaultness: defaultness, - ty: ty, - def_id: ccx.tcx.map.local_def_id(id), - container: container - }); - ccx.tcx.impl_or_trait_items.borrow_mut() - .insert(ccx.tcx.map.local_def_id(id), ty::TypeTraitItem(associated_type)); + if let Some(ty) = ty { + ccx.tcx.tcache.borrow_mut().insert(def_id, ty); + write_ty_to_tcx(ccx, id, ty); + } } fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, @@ -786,8 +716,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Convert all the associated consts. // Also, check if there are any duplicate associated items - let mut seen_type_items = FnvHashMap(); - let mut seen_value_items = FnvHashMap(); + let mut seen_type_items = FxHashMap(); + let mut seen_value_items = FxHashMap(); for impl_item in impl_items { let seen_items = match impl_item.node { @@ -820,14 +750,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { generics: ty_generics, ty: ty, }); - // Trait-associated constants are always public. - let public = &hir::Public; - let visibility = if opt_trait_ref.is_some() { public } else { &impl_item.vis }; convert_associated_const(ccx, ImplContainer(def_id), - impl_item.name, impl_item.id, - visibility, - impl_item.defaultness, - ty, true /* has_value */); + impl_item.id, ty); } } @@ -844,21 +768,14 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); - convert_associated_type(ccx, ImplContainer(def_id), - impl_item.name, impl_item.id, &impl_item.vis, - impl_item.defaultness, Some(typ)); + convert_associated_type(ccx, ImplContainer(def_id), impl_item.id, Some(typ)); } } for impl_item in impl_items { if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - // Trait methods are always public. - let public = &hir::Public; - let method_vis = if opt_trait_ref.is_some() { public } else { &impl_item.vis }; - convert_method(ccx, ImplContainer(def_id), - impl_item.name, impl_item.id, method_vis, - sig, impl_item.defaultness, true, selfty, + impl_item.id, sig, selfty, &ty_predicates); } } @@ -880,7 +797,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Convert all the associated constants. for trait_item in trait_items { - if let hir::ConstTraitItem(ref ty, ref default) = trait_item.node { + if let hir::ConstTraitItem(ref ty, _) = trait_item.node { let const_def_id = ccx.tcx.map.local_def_id(trait_item.id); let ty_generics = generics_of_def_id(ccx, const_def_id); let ty = ccx.icx(&trait_predicates) @@ -890,14 +807,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { generics: ty_generics, ty: ty, }); - convert_associated_const(ccx, - container, - trait_item.name, - trait_item.id, - &hir::Public, - hir::Defaultness::Default, - ty, - default.is_some()) + convert_associated_const(ccx, container, trait_item.id, ty) } } @@ -911,39 +821,21 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty) }); - convert_associated_type(ccx, - container, - trait_item.name, - trait_item.id, - &hir::Public, - hir::Defaultness::Default, - typ); + convert_associated_type(ccx, container, trait_item.id, typ); } } // Convert all the methods for trait_item in trait_items { - if let hir::MethodTraitItem(ref sig, ref body) = trait_item.node { + if let hir::MethodTraitItem(ref sig, _) = trait_item.node { convert_method(ccx, container, - trait_item.name, trait_item.id, - &hir::Inherited, sig, - hir::Defaultness::Default, - body.is_some(), tcx.mk_self_type(), &trait_predicates); - } } - - // Add an entry mapping - let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| { - ccx.tcx.map.local_def_id(trait_item.id) - }).collect()); - tcx.impl_or_trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), - trait_item_def_ids); }, hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { @@ -1038,7 +930,7 @@ fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, disr_val: ty::Disr, def: &hir::VariantData) -> ty::VariantDefData<'tcx, 'tcx> { - let mut seen_fields: FnvHashMap = FnvHashMap(); + let mut seen_fields: FxHashMap = FxHashMap(); let node_id = ccx.tcx.map.as_local_node_id(did).unwrap(); let fields = def.fields().iter().map(|f| { let fid = ccx.tcx.map.local_def_id(f.id); @@ -1308,28 +1200,6 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, tcx.intern_trait_def(trait_def) } -pub fn trait_associated_type_names<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_node_id: ast::NodeId) - -> impl Iterator + 'a -{ - let item = match tcx.map.get(trait_node_id) { - hir_map::NodeItem(item) => item, - _ => bug!("trait_node_id {} is not an item", trait_node_id) - }; - - let trait_items = match item.node { - hir::ItemTrait(.., ref trait_items) => trait_items, - _ => bug!("trait_node_id {} is not a trait", trait_node_id) - }; - - trait_items.iter().filter_map(|trait_item| { - match trait_item.node { - hir::TypeTraitItem(..) => Some(trait_item.name), - _ => None, - } - }) -} - fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) { let tcx = ccx.tcx; let trait_def = trait_def_of_item(ccx, it); @@ -1724,16 +1594,15 @@ fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, match unbound { Some(ref tpb) => { // FIXME(#8559) currently requires the unbound to be built-in. - let trait_def_id = tcx.expect_def(tpb.ref_id).def_id(); - match kind_id { - Ok(kind_id) if trait_def_id != kind_id => { + if let Ok(kind_id) = kind_id { + let trait_def = tcx.expect_def(tpb.ref_id); + if trait_def != Def::Trait(kind_id) { tcx.sess.span_warn(span, "default bound relaxed for a type parameter, but \ this does nothing because the given bound is not \ a default. Only `?Sized` is supported"); tcx.try_add_builtin_trait(kind_id, bounds); } - _ => {} } } _ if kind_id.is_ok() => { @@ -1953,9 +1822,9 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, { let inline_bounds = from_bounds(ccx, param_bounds); let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates); - let all_bounds: FnvHashSet<_> = inline_bounds.into_iter() - .chain(where_bounds) - .collect(); + 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 { @@ -2172,7 +2041,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // The trait reference is an input, so find all type parameters // reachable from there, to start (if this is an inherent impl, // then just examine the self type). - let mut input_parameters: FnvHashSet<_> = + let mut input_parameters: FxHashSet<_> = ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); if let Some(ref trait_ref) = impl_trait_ref { input_parameters.extend(ctp::parameters_for(trait_ref, false)); @@ -2201,7 +2070,7 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let impl_predicates = ccx.tcx.lookup_predicates(impl_def_id); let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); - let mut input_parameters: FnvHashSet<_> = + let mut input_parameters: FxHashSet<_> = ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); if let Some(ref trait_ref) = impl_trait_ref { input_parameters.extend(ctp::parameters_for(trait_ref, false)); @@ -2209,14 +2078,15 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ctp::identify_constrained_type_params( &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); - let lifetimes_in_associated_types: FnvHashSet<_> = impl_items.iter() - .map(|item| ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(item.id))) - .filter_map(|item| match item { - ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, - ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None + let lifetimes_in_associated_types: FxHashSet<_> = impl_items.iter() + .map(|item| ccx.tcx.map.local_def_id(item.id)) + .filter(|&def_id| { + let item = ccx.tcx.associated_item(def_id); + item.kind == ty::AssociatedKind::Type && item.has_value }) - .flat_map(|ty| ctp::parameters_for(&ty, true)) - .collect(); + .flat_map(|def_id| { + ctp::parameters_for(&ccx.tcx.lookup_item_type(def_id).ty, true) + }).collect(); for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter() .zip(&ast_generics.lifetimes) diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 39f9e4316b9c..7918537a6c08 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -10,7 +10,7 @@ use rustc::ty::{self, Ty}; use rustc::ty::fold::{TypeFoldable, TypeVisitor}; -use rustc::util::nodemap::FnvHashSet; +use rustc::util::nodemap::FxHashSet; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct Parameter(pub u32); @@ -76,7 +76,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { pub fn identify_constrained_type_params<'tcx>(predicates: &[ty::Predicate<'tcx>], impl_trait_ref: Option>, - input_parameters: &mut FnvHashSet) + input_parameters: &mut FxHashSet) { let mut predicates = predicates.to_owned(); setup_constraining_predicates(&mut predicates, impl_trait_ref, input_parameters); @@ -125,7 +125,7 @@ pub fn identify_constrained_type_params<'tcx>(predicates: &[ty::Predicate<'tcx>] /// think of any. pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx>], impl_trait_ref: Option>, - input_parameters: &mut FnvHashSet) + input_parameters: &mut FxHashSet) { // The canonical way of doing the needed topological sort // would be a DFS, but getting the graph and its ownership diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 7dd850180d44..be012d8976f6 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -458,7 +458,7 @@ Rust only supports variadic parameters for interoperability with C code in its FFI. As such, variadic parameters can only be used with functions which are using the C ABI. Examples of erroneous code: -```compile_fail,E0045 +```compile_fail #![feature(unboxed_closures)] extern "rust-call" { fn foo(x: u8, ...); } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d636baca248d..d7573c7a7bd2 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,7 +77,7 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -106,7 +106,7 @@ pub use rustc::util; use dep_graph::DepNode; use hir::map as hir_map; -use rustc::infer::TypeOrigin; +use rustc::infer::{InferOk, TypeOrigin}; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::traits::{self, Reveal}; @@ -198,11 +198,16 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, actual: Ty<'tcx>) -> bool { ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { - if let Err(err) = infcx.eq_types(false, origin.clone(), expected, actual) { - infcx.report_mismatched_types(origin, expected, actual, err); - false - } else { - true + match infcx.eq_types(false, origin.clone(), expected, actual) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + true + } + Err(err) => { + infcx.report_mismatched_types(origin, expected, actual, err); + false + } } }) } @@ -211,7 +216,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, main_id: ast::NodeId, main_span: Span) { let tcx = ccx.tcx; - let main_t = tcx.node_id_to_type(main_id); + let main_t = tcx.tables().node_id_to_type(main_id); match main_t.sty { ty::TyFnDef(..) => { match tcx.map.find(main_id) { @@ -263,7 +268,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, start_id: ast::NodeId, start_span: Span) { let tcx = ccx.tcx; - let start_t = tcx.node_id_to_type(start_id); + let start_t = tcx.tables().node_id_to_type(start_id); match start_t.sty { ty::TyFnDef(..) => { match tcx.map.find(start_id) { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 31497b6bd335..a2955169cbb8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -19,7 +19,7 @@ use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::hir::print as pprust; use rustc::ty::{self, TyCtxt}; -use rustc::util::nodemap::FnvHashSet; +use rustc::util::nodemap::FxHashSet; use rustc_const_eval::lookup_const_by_id; @@ -163,7 +163,7 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Trait { let def = tcx.lookup_trait_def(did); - let trait_items = tcx.trait_items(did).clean(cx); + let trait_items = tcx.associated_items(did).map(|item| item.clean(cx)).collect(); let predicates = tcx.lookup_predicates(did); let generics = (def.generics, &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); @@ -307,7 +307,6 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext, for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { if !def_id.is_local() { - tcx.populate_implementations_for_primitive_if_necessary(def_id); build_impl(cx, tcx, def_id, &mut impls); } } @@ -367,21 +366,18 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } let predicates = tcx.lookup_predicates(did); - let trait_items = tcx.sess.cstore.impl_or_trait_items(did) - .iter() - .filter_map(|&did| { - match tcx.impl_or_trait_item(did) { - ty::ConstTraitItem(ref assoc_const) => { - let did = assoc_const.def_id; - let type_scheme = tcx.lookup_item_type(did); - let default = if assoc_const.has_value { + let trait_items = tcx.associated_items(did).filter_map(|item| { + match item.kind { + ty::AssociatedKind::Const => { + let type_scheme = tcx.lookup_item_type(item.def_id); + let default = if item.has_value { Some(pprust::expr_to_string( - lookup_const_by_id(tcx, did, None).unwrap().0)) + lookup_const_by_id(tcx, item.def_id, None).unwrap().0)) } else { None }; Some(clean::Item { - name: Some(assoc_const.name.clean(cx)), + name: Some(item.name.clean(cx)), inner: clean::AssociatedConstItem( type_scheme.ty.clean(cx), default, @@ -389,21 +385,21 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, source: clean::Span::empty(), attrs: vec![], visibility: None, - stability: tcx.lookup_stability(did).clean(cx), - deprecation: tcx.lookup_deprecation(did).clean(cx), - def_id: did + stability: tcx.lookup_stability(item.def_id).clean(cx), + deprecation: tcx.lookup_deprecation(item.def_id).clean(cx), + def_id: item.def_id }) } - ty::MethodTraitItem(method) => { - if method.vis != ty::Visibility::Public && associated_trait.is_none() { + ty::AssociatedKind::Method => { + if item.vis != ty::Visibility::Public && associated_trait.is_none() { return None } - let mut item = method.clean(cx); - item.inner = match item.inner.clone() { + let mut cleaned = item.clean(cx); + cleaned.inner = match cleaned.inner.clone() { clean::TyMethodItem(clean::TyMethod { unsafety, decl, generics, abi }) => { - let constness = if tcx.sess.cstore.is_const_fn(did) { + let constness = if tcx.sess.cstore.is_const_fn(item.def_id) { hir::Constness::Const } else { hir::Constness::NotConst @@ -419,12 +415,11 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } _ => panic!("not a tymethod"), }; - Some(item) + Some(cleaned) } - ty::TypeTraitItem(ref assoc_ty) => { - let did = assoc_ty.def_id; + ty::AssociatedKind::Type => { let typedef = clean::Typedef { - type_: assoc_ty.ty.unwrap().clean(cx), + type_: tcx.lookup_item_type(item.def_id).ty.clean(cx), generics: clean::Generics { lifetimes: vec![], type_params: vec![], @@ -432,14 +427,14 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } }; Some(clean::Item { - name: Some(assoc_ty.name.clean(cx)), + name: Some(item.name.clean(cx)), inner: clean::TypedefItem(typedef, true), source: clean::Span::empty(), attrs: vec![], visibility: None, - stability: tcx.lookup_stability(did).clean(cx), - deprecation: tcx.lookup_deprecation(did).clean(cx), - def_id: did + stability: tcx.lookup_stability(item.def_id).clean(cx), + deprecation: tcx.lookup_deprecation(item.def_id).clean(cx), + def_id: item.def_id }) } } @@ -460,7 +455,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, .into_iter() .map(|meth| meth.name.to_string()) .collect() - }).unwrap_or(FnvHashSet()); + }).unwrap_or(FxHashSet()); ret.push(clean::Item { inner: clean::ImplItem(clean::Impl { @@ -496,7 +491,7 @@ fn build_module<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, // If we're reexporting a reexport it may actually reexport something in // two namespaces, so the target may be listed twice. Make sure we only // visit each node at most once. - let mut visited = FnvHashSet(); + let mut visited = FxHashSet(); for item in tcx.sess.cstore.item_children(did) { let def_id = item.def.def_id(); if tcx.sess.cstore.visibility(def_id) == ty::Visibility::Public { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 265b66b01ea5..9e29d191946b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -38,7 +38,7 @@ use rustc::hir::print as pprust; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind}; use rustc::middle::stability; -use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc::hir; @@ -116,7 +116,7 @@ pub struct Crate { pub access_levels: Arc>, // These are later on moved into `CACHEKEY`, leaving the map empty. // Only here so that they can be filtered through the rustdoc passes. - pub external_traits: FnvHashMap, + pub external_traits: FxHashMap, } struct CrateNum(def_id::CrateNum); @@ -993,7 +993,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, // Note that associated types also have a sized bound by default, but we // don't actually know the set of associated types right here so that's // handled in cleaning associated types - let mut sized_params = FnvHashSet(); + let mut sized_params = FxHashSet(); where_predicates.retain(|pred| { match *pred { WP::BoundPredicate { ty: Generic(ref g), ref bounds } => { @@ -1338,47 +1338,116 @@ impl Clean for hir::ImplItem { } } -impl<'tcx> Clean for ty::Method<'tcx> { +impl<'tcx> Clean for ty::AssociatedItem { fn clean(&self, cx: &DocContext) -> Item { - let generics = (self.generics, &self.predicates).clean(cx); - let mut decl = (self.def_id, &self.fty.sig).clean(cx); - match self.explicit_self { - ty::ExplicitSelfCategory::ByValue => { - decl.inputs.values[0].type_ = Infer; + let inner = match self.kind { + ty::AssociatedKind::Const => { + let ty = cx.tcx().lookup_item_type(self.def_id).ty; + AssociatedConstItem(ty.clean(cx), None) } - ty::ExplicitSelfCategory::ByReference(..) => { - match decl.inputs.values[0].type_ { - BorrowedRef{ref mut type_, ..} => **type_ = Infer, - _ => unreachable!(), + ty::AssociatedKind::Method => { + let generics = (cx.tcx().lookup_generics(self.def_id), + &cx.tcx().lookup_predicates(self.def_id)).clean(cx); + let fty = match cx.tcx().lookup_item_type(self.def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => unreachable!() + }; + let mut decl = (self.def_id, &fty.sig).clean(cx); + + if self.method_has_self_argument { + let self_ty = match self.container { + ty::ImplContainer(def_id) => { + cx.tcx().lookup_item_type(def_id).ty + } + ty::TraitContainer(_) => cx.tcx().mk_self_type() + }; + let self_arg_ty = *fty.sig.input(0).skip_binder(); + if self_arg_ty == self_ty { + decl.inputs.values[0].type_ = Infer; + } else if let ty::TyRef(_, mt) = self_arg_ty.sty { + if mt.ty == self_ty { + match decl.inputs.values[0].type_ { + BorrowedRef{ref mut type_, ..} => **type_ = Infer, + _ => unreachable!(), + } + } + } + } + let provided = match self.container { + ty::ImplContainer(_) => false, + ty::TraitContainer(_) => self.has_value + }; + if provided { + MethodItem(Method { + unsafety: fty.unsafety, + generics: generics, + decl: decl, + abi: fty.abi, + + // trait methods canot (currently, at least) be const + constness: hir::Constness::NotConst, + }) + } else { + TyMethodItem(TyMethod { + unsafety: fty.unsafety, + generics: generics, + decl: decl, + abi: fty.abi, + }) } } - _ => {} - } - let provided = match self.container { - ty::ImplContainer(..) => false, - ty::TraitContainer(did) => { - cx.tcx().provided_trait_methods(did).iter().any(|m| { - m.def_id == self.def_id - }) - } - }; - let inner = if provided { - MethodItem(Method { - unsafety: self.fty.unsafety, - generics: generics, - decl: decl, - abi: self.fty.abi, + ty::AssociatedKind::Type => { + let my_name = self.name.clean(cx); - // trait methods canot (currently, at least) be const - constness: hir::Constness::NotConst, - }) - } else { - TyMethodItem(TyMethod { - unsafety: self.fty.unsafety, - generics: generics, - decl: decl, - abi: self.fty.abi, - }) + let mut bounds = if let ty::TraitContainer(did) = self.container { + // When loading a cross-crate associated type, the bounds for this type + // are actually located on the trait/impl itself, so we need to load + // all of the generics from there and then look for bounds that are + // applied to this associated type in question. + let def = cx.tcx().lookup_trait_def(did); + let predicates = cx.tcx().lookup_predicates(did); + let generics = (def.generics, &predicates).clean(cx); + generics.where_predicates.iter().filter_map(|pred| { + let (name, self_type, trait_, bounds) = match *pred { + WherePredicate::BoundPredicate { + ty: QPath { ref name, ref self_type, ref trait_ }, + ref bounds + } => (name, self_type, trait_, bounds), + _ => return None, + }; + if *name != my_name { return None } + match **trait_ { + ResolvedPath { did, .. } if did == self.container.id() => {} + _ => return None, + } + match **self_type { + Generic(ref s) if *s == "Self" => {} + _ => return None, + } + Some(bounds) + }).flat_map(|i| i.iter().cloned()).collect::>() + } else { + vec![] + }; + + // Our Sized/?Sized bound didn't get handled when creating the generics + // because we didn't actually get our whole set of bounds until just now + // (some of them may have come from the trait). If we do have a sized + // bound, we remove it, and if we don't then we add the `?Sized` bound + // at the end. + match bounds.iter().position(|b| b.is_sized_bound(cx)) { + Some(i) => { bounds.remove(i); } + None => bounds.push(TyParamBound::maybe_sized(cx)), + } + + let ty = if self.has_value { + Some(cx.tcx().lookup_item_type(self.def_id).ty) + } else { + None + }; + + AssociatedTypeItem(bounds, ty.clean(cx)) + } }; Item { @@ -1394,16 +1463,6 @@ impl<'tcx> Clean for ty::Method<'tcx> { } } -impl<'tcx> Clean for ty::ImplOrTraitItem<'tcx> { - fn clean(&self, cx: &DocContext) -> Item { - match *self { - ty::ConstTraitItem(ref cti) => cti.clean(cx), - ty::MethodTraitItem(ref mti) => mti.clean(cx), - ty::TypeTraitItem(ref tti) => tti.clean(cx), - } - } -} - /// A trait reference, which may have higher ranked lifetimes. #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub struct PolyTrait { @@ -1693,8 +1752,8 @@ impl Clean for hir::Ty { }); if let Some((tcx, &hir::ItemTy(ref ty, ref generics))) = tcx_and_alias { let provided_params = &path.segments.last().unwrap().parameters; - let mut ty_substs = FnvHashMap(); - let mut lt_substs = FnvHashMap(); + let mut ty_substs = FxHashMap(); + let mut lt_substs = FxHashMap(); for (i, ty_param) in generics.ty_params.iter().enumerate() { let ty_param_def = tcx.expect_def(ty_param.id); if let Some(ty) = provided_params.types().get(i).cloned() @@ -2368,7 +2427,7 @@ impl Clean for hir::ImplPolarity { pub struct Impl { pub unsafety: hir::Unsafety, pub generics: Generics, - pub provided_trait_methods: FnvHashSet, + pub provided_trait_methods: FxHashSet, pub trait_: Option, pub for_: Type, pub items: Vec, @@ -2394,7 +2453,7 @@ impl Clean> for doctree::Impl { .map(|meth| meth.name.to_string()) .collect() }) - }).unwrap_or(FnvHashSet()); + }).unwrap_or(FxHashSet()); ret.push(Item { name: None, @@ -2884,79 +2943,6 @@ impl Clean for attr::Deprecation { } } -impl<'tcx> Clean for ty::AssociatedConst<'tcx> { - fn clean(&self, cx: &DocContext) -> Item { - Item { - source: DUMMY_SP.clean(cx), - name: Some(self.name.clean(cx)), - attrs: Vec::new(), - inner: AssociatedConstItem(self.ty.clean(cx), None), - visibility: None, - def_id: self.def_id, - stability: None, - deprecation: None, - } - } -} - -impl<'tcx> Clean for ty::AssociatedType<'tcx> { - fn clean(&self, cx: &DocContext) -> Item { - let my_name = self.name.clean(cx); - - let mut bounds = if let ty::TraitContainer(did) = self.container { - // When loading a cross-crate associated type, the bounds for this type - // are actually located on the trait/impl itself, so we need to load - // all of the generics from there and then look for bounds that are - // applied to this associated type in question. - let def = cx.tcx().lookup_trait_def(did); - let predicates = cx.tcx().lookup_predicates(did); - let generics = (def.generics, &predicates).clean(cx); - generics.where_predicates.iter().filter_map(|pred| { - let (name, self_type, trait_, bounds) = match *pred { - WherePredicate::BoundPredicate { - ty: QPath { ref name, ref self_type, ref trait_ }, - ref bounds - } => (name, self_type, trait_, bounds), - _ => return None, - }; - if *name != my_name { return None } - match **trait_ { - ResolvedPath { did, .. } if did == self.container.id() => {} - _ => return None, - } - match **self_type { - Generic(ref s) if *s == "Self" => {} - _ => return None, - } - Some(bounds) - }).flat_map(|i| i.iter().cloned()).collect::>() - } else { - vec![] - }; - - // Our Sized/?Sized bound didn't get handled when creating the generics - // because we didn't actually get our whole set of bounds until just now - // (some of them may have come from the trait). If we do have a sized - // bound, we remove it, and if we don't then we add the `?Sized` bound - // at the end. - match bounds.iter().position(|b| b.is_sized_bound(cx)) { - Some(i) => { bounds.remove(i); } - None => bounds.push(TyParamBound::maybe_sized(cx)), - } - - Item { - source: DUMMY_SP.clean(cx), - name: Some(self.name.clean(cx)), - attrs: inline::load_attrs(cx, cx.tcx(), self.def_id), - inner: AssociatedTypeItem(bounds, self.ty.clean(cx)), - visibility: self.vis.clean(cx), - def_id: self.def_id, - stability: cx.tcx().lookup_stability(self.def_id).clean(cx), - deprecation: cx.tcx().lookup_deprecation(self.def_id).clean(cx), - } - } -} - fn lang_struct(cx: &DocContext, did: Option, t: ty::Ty, name: &str, fallback: fn(Box) -> Type) -> Type { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index f03b6a5ab3f1..a25cb0bacc5c 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -14,12 +14,12 @@ use rustc_driver::{driver, target_features, abort_on_err}; use rustc::dep_graph::DepGraph; use rustc::session::{self, config}; use rustc::hir::def_id::DefId; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, ExportMap}; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt}; use rustc::hir::map as hir_map; use rustc::lint; -use rustc::util::nodemap::FnvHashMap; +use rustc::util::nodemap::FxHashMap; use rustc_trans::back::link; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; @@ -48,7 +48,7 @@ pub enum MaybeTyped<'a, 'tcx: 'a> { NotTyped(&'a session::Session) } -pub type ExternalPaths = FnvHashMap, clean::TypeKind)>; +pub type ExternalPaths = FxHashMap, clean::TypeKind)>; pub struct DocContext<'a, 'tcx: 'a> { pub map: &'a hir_map::Map<'tcx>, @@ -65,15 +65,16 @@ pub struct DocContext<'a, 'tcx: 'a> { /// Later on moved into `html::render::CACHE_KEY` pub renderinfo: RefCell, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` - pub external_traits: RefCell>, + pub external_traits: RefCell>, // The current set of type and lifetime substitutions, // for expanding type aliases at the HIR level: /// Table type parameter definition -> substituted type - pub ty_substs: RefCell>, + pub ty_substs: RefCell>, /// Table node id of lifetime parameter definition -> substituted lifetime - pub lt_substs: RefCell>, + pub lt_substs: RefCell>, + pub export_map: ExportMap, } impl<'b, 'tcx> DocContext<'b, 'tcx> { @@ -99,8 +100,8 @@ impl<'b, 'tcx> DocContext<'b, 'tcx> { /// Call the closure with the given parameters set as /// the substitutions for a type alias' RHS. pub fn enter_alias(&self, - ty_substs: FnvHashMap, - lt_substs: FnvHashMap, + ty_substs: FxHashMap, + lt_substs: FxHashMap, f: F) -> R where F: FnOnce() -> R { let (old_tys, old_lts) = @@ -196,7 +197,7 @@ pub fn run_core(search_paths: SearchPaths, sess.fatal("Compilation failed, aborting rustdoc"); } - let ty::CrateAnalysis { access_levels, .. } = analysis; + let ty::CrateAnalysis { access_levels, export_map, .. } = analysis; // Convert from a NodeId set to a DefId set since we don't always have easy access // to the map from defid -> nodeid @@ -218,6 +219,7 @@ pub fn run_core(search_paths: SearchPaths, renderinfo: Default::default(), ty_substs: Default::default(), lt_substs: Default::default(), + export_map: export_map, }; debug!("crate: {:?}", ctxt.map.krate()); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index a848a011f88d..2db771d77111 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -59,7 +59,7 @@ use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; use rustc::middle::privacy::AccessLevels; use rustc::middle::stability; use rustc::hir; -use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::flock; use clean::{self, Attributes, GetDefId, SelfTy, Mutability}; @@ -111,9 +111,9 @@ pub struct SharedContext { /// `true`. pub include_sources: bool, /// The local file sources we've emitted and their respective url-paths. - pub local_sources: FnvHashMap, + pub local_sources: FxHashMap, /// All the passes that were run on this crate. - pub passes: FnvHashSet, + pub passes: FxHashSet, /// The base-URL of the issue tracker for when an item has been tagged with /// an issue number. pub issue_tracker_base_url: Option, @@ -208,7 +208,7 @@ pub struct Cache { /// Mapping of typaram ids to the name of the type parameter. This is used /// when pretty-printing a type (so pretty printing doesn't have to /// painfully maintain a context like this) - pub typarams: FnvHashMap, + pub typarams: FxHashMap, /// Maps a type id to all known implementations for that type. This is only /// recognized for intra-crate `ResolvedPath` types, and is used to print @@ -216,35 +216,35 @@ pub struct Cache { /// /// The values of the map are a list of implementations and documentation /// found on that implementation. - pub impls: FnvHashMap>, + pub impls: FxHashMap>, /// Maintains a mapping of local crate node ids to the fully qualified name /// and "short type description" of that node. This is used when generating /// URLs when a type is being linked to. External paths are not located in /// this map because the `External` type itself has all the information /// necessary. - pub paths: FnvHashMap, ItemType)>, + pub paths: FxHashMap, ItemType)>, /// Similar to `paths`, but only holds external paths. This is only used for /// generating explicit hyperlinks to other crates. - pub external_paths: FnvHashMap, ItemType)>, + pub external_paths: FxHashMap, ItemType)>, /// This map contains information about all known traits of this crate. /// Implementations of a crate should inherit the documentation of the /// parent trait if no extra documentation is specified, and default methods /// should show up in documentation about trait implementations. - pub traits: FnvHashMap, + pub traits: FxHashMap, /// When rendering traits, it's often useful to be able to list all /// implementors of the trait, and this mapping is exactly, that: a mapping /// of trait ids to the list of known implementors of the trait - pub implementors: FnvHashMap>, + pub implementors: FxHashMap>, /// Cache of where external crate documentation can be found. - pub extern_locations: FnvHashMap, + pub extern_locations: FxHashMap, /// Cache of where documentation for primitives can be found. - pub primitive_locations: FnvHashMap, + pub primitive_locations: FxHashMap, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing @@ -257,7 +257,7 @@ pub struct Cache { parent_stack: Vec, parent_is_trait_impl: bool, search_index: Vec, - seen_modules: FnvHashSet, + seen_modules: FxHashSet, seen_mod: bool, stripped_mod: bool, deref_trait_did: Option, @@ -275,9 +275,9 @@ pub struct Cache { /// Later on moved into `CACHE_KEY`. #[derive(Default)] pub struct RenderInfo { - pub inlined: FnvHashSet, + pub inlined: FxHashSet, pub external_paths: ::core::ExternalPaths, - pub external_typarams: FnvHashMap, + pub external_typarams: FxHashMap, pub deref_trait_did: Option, pub deref_mut_trait_did: Option, } @@ -376,10 +376,10 @@ impl ToJson for IndexItemFunctionType { thread_local!(static CACHE_KEY: RefCell> = Default::default()); thread_local!(pub static CURRENT_LOCATION_KEY: RefCell> = RefCell::new(Vec::new())); -thread_local!(static USED_ID_MAP: RefCell> = +thread_local!(static USED_ID_MAP: RefCell> = RefCell::new(init_ids())); -fn init_ids() -> FnvHashMap { +fn init_ids() -> FxHashMap { [ "main", "search", @@ -406,7 +406,7 @@ pub fn reset_ids(embedded: bool) { *s.borrow_mut() = if embedded { init_ids() } else { - FnvHashMap() + FxHashMap() }; }); } @@ -431,7 +431,7 @@ pub fn derive_id(candidate: String) -> String { pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: PathBuf, - passes: FnvHashSet, + passes: FxHashSet, css_file_extension: Option, renderinfo: RenderInfo) -> Result<(), Error> { let src_root = match krate.src.parent() { @@ -442,7 +442,7 @@ pub fn run(mut krate: clean::Crate, src_root: src_root, passes: passes, include_sources: true, - local_sources: FnvHashMap(), + local_sources: FxHashMap(), issue_tracker_base_url: None, layout: layout::Layout { logo: "".to_string(), @@ -510,22 +510,22 @@ pub fn run(mut krate: clean::Crate, .collect(); let mut cache = Cache { - impls: FnvHashMap(), + impls: FxHashMap(), external_paths: external_paths, - paths: FnvHashMap(), - implementors: FnvHashMap(), + paths: FxHashMap(), + implementors: FxHashMap(), stack: Vec::new(), parent_stack: Vec::new(), search_index: Vec::new(), parent_is_trait_impl: false, - extern_locations: FnvHashMap(), - primitive_locations: FnvHashMap(), - seen_modules: FnvHashSet(), + extern_locations: FxHashMap(), + primitive_locations: FxHashMap(), + seen_modules: FxHashSet(), seen_mod: false, stripped_mod: false, access_levels: krate.access_levels.clone(), orphan_impl_items: Vec::new(), - traits: mem::replace(&mut krate.external_traits, FnvHashMap()), + traits: mem::replace(&mut krate.external_traits, FxHashMap()), deref_trait_did: deref_trait_did, deref_mut_trait_did: deref_mut_trait_did, typarams: external_typarams, @@ -572,7 +572,7 @@ pub fn run(mut krate: clean::Crate, /// Build the search index from the collected metadata fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { - let mut nodeid_to_pathid = FnvHashMap(); + let mut nodeid_to_pathid = FxHashMap(); let mut crate_items = Vec::with_capacity(cache.search_index.len()); let mut crate_paths = Vec::::new(); @@ -1828,11 +1828,19 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, } else { String::new() }; + + let mut unsafety_flag = ""; + if let clean::FunctionItem(ref func) = myitem.inner { + if func.unsafety == hir::Unsafety::Unsafe { + unsafety_flag = ""; + } + } + let doc_value = myitem.doc_value().unwrap_or(""); write!(w, " {name} + title='{title}'>{name}{unsafety_flag} {stab_docs} {docs} @@ -1842,6 +1850,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, docs = shorter(Some(&Markdown(doc_value).to_string())), class = myitem.type_(), stab = myitem.stability_class(), + unsafety_flag = unsafety_flag, href = item_path(myitem.type_(), myitem.name.as_ref().unwrap()), title = full_path(cx, myitem))?; } @@ -2492,17 +2501,54 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, Ok(()) } -fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { - for attr in &it.attrs { - match *attr { - clean::Word(ref s) if *s == "must_use" => { - write!(w, "#[{}]\n", s)?; - } - clean::NameValue(ref k, ref v) if *k == "must_use" => { - write!(w, "#[{} = \"{}\"]\n", k, v)?; - } - _ => () +fn attribute_without_value(s: &str) -> bool { + ["must_use", "no_mangle", "unsafe_destructor_blind_to_params"].iter().any(|x| x == &s) +} + +fn attribute_with_value(s: &str) -> bool { + ["export_name", "lang", "link_section", "must_use"].iter().any(|x| x == &s) +} + +fn attribute_with_values(s: &str) -> bool { + ["repr"].iter().any(|x| x == &s) +} + +fn render_attribute(attr: &clean::Attribute, recurse: bool) -> Option { + match *attr { + clean::Word(ref s) if attribute_without_value(&*s) || recurse => { + Some(format!("{}", s)) } + clean::NameValue(ref k, ref v) if attribute_with_value(&*k) => { + Some(format!("{} = \"{}\"", k, v)) + } + clean::List(ref k, ref values) if attribute_with_values(&*k) => { + let display: Vec<_> = values.iter() + .filter_map(|value| render_attribute(value, true)) + .map(|entry| format!("{}", entry)) + .collect(); + + if display.len() > 0 { + Some(format!("{}({})", k, display.join(", "))) + } else { + None + } + } + _ => { + None + } + } +} + +fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { + let mut attrs = String::new(); + + for attr in &it.attrs { + if let Some(s) = render_attribute(attr, false) { + attrs.push_str(&format!("#[{}]\n", s)); + } + } + if attrs.len() > 0 { + write!(w, "
{}
", &attrs)?; } Ok(()) } @@ -2618,7 +2664,7 @@ fn render_union(w: &mut fmt::Formatter, it: &clean::Item, #[derive(Copy, Clone)] enum AssocItemLink<'a> { Anchor(Option<&'a str>), - GotoSource(DefId, &'a FnvHashSet), + GotoSource(DefId, &'a FxHashSet), } impl<'a> AssocItemLink<'a> { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 9bb7246e7a92..474d2bbe7fcb 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -963,20 +963,22 @@ } } - $("#toggle-all-docs").on("click", toggleAllDocs); - - $(document).on("click", ".collapse-toggle", function() { - var toggle = $(this); + function collapseDocs(toggle, animate) { var relatedDoc = toggle.parent().next(); if (relatedDoc.is(".stability")) { relatedDoc = relatedDoc.next(); } if (relatedDoc.is(".docblock")) { if (relatedDoc.is(":visible")) { - relatedDoc.slideUp({duration: 'fast', easing: 'linear'}); + if (animate === true) { + relatedDoc.slideUp({duration: 'fast', easing: 'linear'}); + toggle.children(".toggle-label").fadeIn(); + } else { + relatedDoc.hide(); + toggle.children(".toggle-label").show(); + } toggle.parent(".toggle-wrapper").addClass("collapsed"); toggle.children(".inner").text(labelForToggleButton(true)); - toggle.children(".toggle-label").fadeIn(); } else { relatedDoc.slideDown({duration: 'fast', easing: 'linear'}); toggle.parent(".toggle-wrapper").removeClass("collapsed"); @@ -984,6 +986,12 @@ toggle.children(".toggle-label").hide(); } } + } + + $("#toggle-all-docs").on("click", toggleAllDocs); + + $(document).on("click", ".collapse-toggle", function() { + collapseDocs($(this), true) }); $(function() { @@ -999,12 +1007,22 @@ }); var mainToggle = - $(toggle).append( + $(toggle.clone()).append( $('', {'class': 'toggle-label'}) .css('display', 'none') .html(' Expand description')); var wrapper = $("
").append(mainToggle); $("#main > .docblock").before(wrapper); + var mainToggle = + $(toggle).append( + $('', {'class': 'toggle-label'}) + .css('display', 'none') + .html(' Expand attributes')); + var wrapper = $("
").append(mainToggle); + $("#main > pre > .attributes").each(function() { + $(this).before(wrapper); + collapseDocs($($(this).prev().children()[0]), false); + }); }); $('pre.line-numbers').on('click', 'span', function() { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index f49b8556f66c..46b34b5a638b 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -14,160 +14,160 @@ /* See FiraSans-LICENSE.txt for the Fira Sans license. */ @font-face { - font-family: 'Fira Sans'; - font-style: normal; - font-weight: 400; - src: local('Fira Sans'), url("FiraSans-Regular.woff") format('woff'); + font-family: 'Fira Sans'; + font-style: normal; + font-weight: 400; + src: local('Fira Sans'), url("FiraSans-Regular.woff") format('woff'); } @font-face { - font-family: 'Fira Sans'; - font-style: normal; - font-weight: 500; - src: local('Fira Sans Medium'), url("FiraSans-Medium.woff") format('woff'); + font-family: 'Fira Sans'; + font-style: normal; + font-weight: 500; + src: local('Fira Sans Medium'), url("FiraSans-Medium.woff") format('woff'); } /* See SourceSerifPro-LICENSE.txt for the Source Serif Pro license and * Heuristica-LICENSE.txt for the Heuristica license. */ @font-face { - font-family: 'Source Serif Pro'; - font-style: normal; - font-weight: 400; - src: local('Source Serif Pro'), url("SourceSerifPro-Regular.woff") format('woff'); + font-family: 'Source Serif Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Serif Pro'), url("SourceSerifPro-Regular.woff") format('woff'); } @font-face { - font-family: 'Source Serif Pro'; - font-style: italic; - font-weight: 400; - src: url("Heuristica-Italic.woff") format('woff'); + font-family: 'Source Serif Pro'; + font-style: italic; + font-weight: 400; + src: url("Heuristica-Italic.woff") format('woff'); } @font-face { - font-family: 'Source Serif Pro'; - font-style: normal; - font-weight: 700; - src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.woff") format('woff'); + font-family: 'Source Serif Pro'; + font-style: normal; + font-weight: 700; + src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.woff") format('woff'); } /* See SourceCodePro-LICENSE.txt for the Source Code Pro license. */ @font-face { - font-family: 'Source Code Pro'; - font-style: normal; - font-weight: 400; - src: local('Source Code Pro'), url("SourceCodePro-Regular.woff") format('woff'); + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Code Pro'), url("SourceCodePro-Regular.woff") format('woff'); } @font-face { - font-family: 'Source Code Pro'; - font-style: normal; - font-weight: 600; - src: local('Source Code Pro Semibold'), url("SourceCodePro-Semibold.woff") format('woff'); + font-family: 'Source Code Pro'; + font-style: normal; + font-weight: 600; + src: local('Source Code Pro Semibold'), url("SourceCodePro-Semibold.woff") format('woff'); } * { -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } /* General structure and fonts */ body { - font: 16px/1.4 "Source Serif Pro", Georgia, Times, "Times New Roman", serif; - margin: 0; - position: relative; - padding: 10px 15px 20px 15px; + font: 16px/1.4 "Source Serif Pro", Georgia, Times, "Times New Roman", serif; + margin: 0; + position: relative; + padding: 10px 15px 20px 15px; - -webkit-font-feature-settings: "kern", "liga"; - -moz-font-feature-settings: "kern", "liga"; - font-feature-settings: "kern", "liga"; + -webkit-font-feature-settings: "kern", "liga"; + -moz-font-feature-settings: "kern", "liga"; + font-feature-settings: "kern", "liga"; } h1 { - font-size: 1.5em; + font-size: 1.5em; } h2 { - font-size: 1.4em; + font-size: 1.4em; } h3 { - font-size: 1.3em; + font-size: 1.3em; } h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { - font-weight: 500; - margin: 20px 0 15px 0; - padding-bottom: 6px; + font-weight: 500; + margin: 20px 0 15px 0; + padding-bottom: 6px; } h1.fqn { - border-bottom: 1px dashed; - margin-top: 0; - position: relative; + border-bottom: 1px dashed; + margin-top: 0; + position: relative; } h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { - border-bottom: 1px solid; + border-bottom: 1px solid; } h3.impl, h3.method, h4.method, h3.type, h4.type { - font-weight: 600; - margin-top: 10px; - margin-bottom: 10px; - position: relative; + font-weight: 600; + margin-top: 10px; + margin-bottom: 10px; + position: relative; } h3.impl, h3.method, h3.type { - margin-top: 15px; + margin-top: 15px; } h1, h2, h3, h4, .sidebar, a.source, .search-input, .content table :not(code)>a, .collapse-toggle { - font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } ol, ul { - padding-left: 25px; + padding-left: 25px; } ul ul, ol ul, ul ol, ol ol { - margin-bottom: 0; + margin-bottom: 0; } p { - margin: 0 0 .6em 0; + margin: 0 0 .6em 0; } code, pre { - font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", Inconsolata, monospace; - white-space: pre-wrap; + font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", Inconsolata, monospace; + white-space: pre-wrap; } .docblock code, .docblock-short code { - border-radius: 3px; - padding: 0 0.2em; + border-radius: 3px; + padding: 0 0.2em; } .docblock pre code, .docblock-short pre code { - padding: 0; + padding: 0; } pre { - padding: 14px; + padding: 14px; } .source pre { - padding: 20px; + padding: 20px; } img { - max-width: 100%; + max-width: 100%; } .content.source { - margin-top: 50px; - max-width: none; - overflow: visible; - margin-left: 0px; - min-width: 70em; + margin-top: 50px; + max-width: none; + overflow: visible; + margin-left: 0px; + min-width: 70em; } nav.sub { - font-size: 16px; - text-transform: uppercase; + font-size: 16px; + text-transform: uppercase; } .sidebar { - width: 200px; - position: absolute; - left: 0; - top: 0; - min-height: 100%; + width: 200px; + position: absolute; + left: 0; + top: 0; + min-height: 100%; } .content, nav { max-width: 960px; } @@ -177,88 +177,88 @@ nav.sub { .js-only, .hidden { display: none !important; } .sidebar { - padding: 10px; + padding: 10px; } .sidebar img { - margin: 20px auto; - display: block; + margin: 20px auto; + display: block; } .sidebar .location { - font-size: 17px; - margin: 30px 0 20px 0; - text-align: center; + font-size: 17px; + margin: 30px 0 20px 0; + text-align: center; } .location a:first-child { font-weight: 500; } .block { - padding: 0 10px; - margin-bottom: 14px; + padding: 0 10px; + margin-bottom: 14px; } .block h2, .block h3 { - margin-top: 0; - margin-bottom: 8px; - text-align: center; + margin-top: 0; + margin-bottom: 8px; + text-align: center; } .block ul, .block li { - margin: 0; - padding: 0; - list-style: none; + margin: 0; + padding: 0; + list-style: none; } .block a { - display: block; - text-overflow: ellipsis; - overflow: hidden; - line-height: 15px; - padding: 7px 5px; - font-size: 14px; - font-weight: 300; - transition: border 500ms ease-out; + display: block; + text-overflow: ellipsis; + overflow: hidden; + line-height: 15px; + padding: 7px 5px; + font-size: 14px; + font-weight: 300; + transition: border 500ms ease-out; } .content { - padding: 15px 0; + padding: 15px 0; } .content.source pre.rust { - white-space: pre; - overflow: auto; - padding-left: 0; + white-space: pre; + overflow: auto; + padding-left: 0; } .content pre.line-numbers { - float: left; - border: none; - position: relative; + float: left; + border: none; + position: relative; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } .line-numbers span { cursor: pointer; } .docblock-short p { - display: inline; + display: inline; } .docblock-short.nowrap { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } .docblock-short p { - overflow: hidden; - text-overflow: ellipsis; - margin: 0; + overflow: hidden; + text-overflow: ellipsis; + margin: 0; } .docblock-short code { white-space: nowrap; } .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { - border-bottom: 1px solid; + border-bottom: 1px solid; } .docblock h1 { font-size: 1.3em; } @@ -266,53 +266,53 @@ nav.sub { .docblock h3, .docblock h4, .docblock h5 { font-size: 1em; } .docblock { - margin-left: 24px; + margin-left: 24px; } .content .out-of-band { - font-size: 23px; - margin: 0px; - padding: 0px; - text-align: right; - display: inline-block; - font-weight: normal; - position: absolute; - right: 0; + font-size: 23px; + margin: 0px; + padding: 0px; + text-align: right; + display: inline-block; + font-weight: normal; + position: absolute; + right: 0; } h3.impl > .out-of-band { - font-size: 21px; + font-size: 21px; } h4 > code, h3 > code, .invisible > code { - position: inherit; + position: inherit; } .in-band, code { - z-index: 5; + z-index: 5; } .invisible { - background: rgba(0, 0, 0, 0); - width: 100%; - display: inline-block; + background: rgba(0, 0, 0, 0); + width: 100%; + display: inline-block; } .content .in-band { - margin: 0px; - padding: 0px; - display: inline-block; + margin: 0px; + padding: 0px; + display: inline-block; } #main { position: relative; } #main > .since { - top: inherit; - font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + top: inherit; + font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } .content table { - border-spacing: 0 5px; - border-collapse: separate; + border-spacing: 0 5px; + border-collapse: separate; } .content td { vertical-align: top; } .content td:first-child { padding-right: 20px; } @@ -320,45 +320,45 @@ h4 > code, h3 > code, .invisible > code { .content td h1, .content td h2 { margin-left: 0; font-size: 1.1em; } .docblock table { - border: 1px solid; - margin: .5em 0; - border-collapse: collapse; - width: 100%; + border: 1px solid; + margin: .5em 0; + border-collapse: collapse; + width: 100%; } .docblock table td { - padding: .5em; - border-top: 1px dashed; - border-bottom: 1px dashed; + padding: .5em; + border-top: 1px dashed; + border-bottom: 1px dashed; } .docblock table th { - padding: .5em; - text-align: left; - border-top: 1px solid; - border-bottom: 1px solid; + padding: .5em; + text-align: left; + border-top: 1px solid; + border-bottom: 1px solid; } .content .item-list { - list-style-type: none; - padding: 0; + list-style-type: none; + padding: 0; } .content .item-list li { margin-bottom: 3px; } .content .multi-column { - -moz-column-count: 5; - -moz-column-gap: 2.5em; - -webkit-column-count: 5; - -webkit-column-gap: 2.5em; - column-count: 5; - column-gap: 2.5em; + -moz-column-count: 5; + -moz-column-gap: 2.5em; + -webkit-column-count: 5; + -webkit-column-gap: 2.5em; + column-count: 5; + column-gap: 2.5em; } .content .multi-column li { width: 100%; display: inline-block; } .content .method { - font-size: 1em; - position: relative; + font-size: 1em; + position: relative; } /* Shift "where ..." part of method or fn definition down a line */ .content .method .where, .content .fn .where { display: block; } @@ -368,54 +368,54 @@ h4 > code, h3 > code, .invisible > code { .content .methods > div { margin-left: 40px; } .content .impl-items .docblock, .content .impl-items .stability { - margin-left: 40px; + margin-left: 40px; } .content .impl-items .method, .content .impl-items > .type { - margin-left: 20px; + margin-left: 20px; } .content .stability code { - font-size: 90%; + font-size: 90%; } /* Shift where in trait listing down a line */ pre.trait .where::before { - content: '\a '; + content: '\a '; } nav { - border-bottom: 1px solid; - padding-bottom: 10px; - margin-bottom: 10px; + border-bottom: 1px solid; + padding-bottom: 10px; + margin-bottom: 10px; } nav.main { - padding: 20px 0; - text-align: center; + padding: 20px 0; + text-align: center; } nav.main .current { - border-top: 1px solid; - border-bottom: 1px solid; + border-top: 1px solid; + border-bottom: 1px solid; } nav.main .separator { - border: 1px solid; - display: inline-block; - height: 23px; - margin: 0 20px; + border: 1px solid; + display: inline-block; + height: 23px; + margin: 0 20px; } nav.sum { text-align: right; } nav.sub form { display: inline; } nav.sub, .content { - margin-left: 230px; + margin-left: 230px; } a { - text-decoration: none; - background: transparent; + text-decoration: none; + background: transparent; } .docblock a:hover, .docblock-short a:hover, .stability a { - text-decoration: underline; + text-decoration: underline; } .content span.enum, .content a.enum, .block a.current.enum { color: #5e9766; } @@ -425,40 +425,40 @@ a { .block a.current.crate { font-weight: 500; } .search-input { - width: 100%; - /* Override Normalize.css: we have margins and do - not want to overflow - the `moz` attribute is necessary - until Firefox 29, too early to drop at this point */ - -moz-box-sizing: border-box !important; - box-sizing: border-box !important; - outline: none; - border: none; - border-radius: 1px; - margin-top: 5px; - padding: 10px 16px; - font-size: 17px; - transition: border-color 300ms ease; - transition: border-radius 300ms ease-in-out; - transition: box-shadow 300ms ease-in-out; + width: 100%; + /* Override Normalize.css: we have margins and do + not want to overflow - the `moz` attribute is necessary + until Firefox 29, too early to drop at this point */ + -moz-box-sizing: border-box !important; + box-sizing: border-box !important; + outline: none; + border: none; + border-radius: 1px; + margin-top: 5px; + padding: 10px 16px; + font-size: 17px; + transition: border-color 300ms ease; + transition: border-radius 300ms ease-in-out; + transition: box-shadow 300ms ease-in-out; } .search-input:focus { - border-color: #66afe9; - border-radius: 2px; - border: 0; - outline: 0; - box-shadow: 0 0 8px #078dd8; + border-color: #66afe9; + border-radius: 2px; + border: 0; + outline: 0; + box-shadow: 0 0 8px #078dd8; } .search-results .desc { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - display: block; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + display: block; } .search-results a { - display: block; + display: block; } .content .search-results td:first-child { padding-right: 0; } @@ -468,96 +468,96 @@ tr.result span.primitive::after { content: ' (primitive type)'; font-style: ital } body.blur > :not(#help) { - filter: blur(8px); - -webkit-filter: blur(8px); - opacity: .7; + filter: blur(8px); + -webkit-filter: blur(8px); + opacity: .7; } #help { - width: 100%; - height: 100vh; - position: fixed; - top: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; + width: 100%; + height: 100vh; + position: fixed; + top: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; } #help > div { - flex: 0 0 auto; - background: #e9e9e9; - box-shadow: 0 0 6px rgba(0,0,0,.2); - width: 550px; - height: 330px; - border: 1px solid #bfbfbf; + flex: 0 0 auto; + background: #e9e9e9; + box-shadow: 0 0 6px rgba(0,0,0,.2); + width: 550px; + height: 330px; + border: 1px solid #bfbfbf; } #help dt { - float: left; - border-radius: 4px; - border: 1px solid #bfbfbf; - background: #fff; - width: 23px; - text-align: center; - clear: left; - display: block; - margin-top: -1px; + float: left; + border-radius: 4px; + border: 1px solid #bfbfbf; + background: #fff; + width: 23px; + text-align: center; + clear: left; + display: block; + margin-top: -1px; } #help dd { margin: 5px 33px; } #help .infos { padding-left: 0; } #help h1, #help h2 { margin-top: 0; } #help > div div { - width: 50%; - float: left; - padding: 20px; + width: 50%; + float: left; + padding: 20px; } em.stab { - display: inline-block; - border-width: 1px; - border-style: solid; - padding: 3px; - margin-bottom: 5px; - font-size: 90%; - font-style: normal; + display: inline-block; + border-width: 1px; + border-style: solid; + padding: 3px; + margin-bottom: 5px; + font-size: 90%; + font-style: normal; } em.stab p { - display: inline; + display: inline; } .module-item .stab { - border-width: 0; - padding: 0; - margin: 0; - background: inherit !important; + border-width: 0; + padding: 0; + margin: 0; + background: inherit !important; } .module-item.unstable { - opacity: 0.65; + opacity: 0.65; } .since { - font-weight: normal; - font-size: initial; - color: grey; - position: absolute; - right: 0; - top: 0; + font-weight: normal; + font-size: initial; + color: grey; + position: absolute; + right: 0; + top: 0; } .variants_table { - width: 100%; + width: 100%; } .variants_table tbody tr td:first-child { - width: 1%; /* make the variant name as small as possible */ + width: 1%; /* make the variant name as small as possible */ } td.summary-column { - width: 100%; + width: 100%; } .summary { - padding-right: 0px; + padding-right: 0px; } .line-numbers :target { background-color: transparent; } @@ -571,110 +571,118 @@ pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } pre.rust .lifetime { color: #B76514; } pre.rust .question-mark { - color: #ff9011; - font-weight: bold; + color: #ff9011; + font-weight: bold; } pre.rust { position: relative; } a.test-arrow { - background-color: rgba(78, 139, 202, 0.2); - display: inline-block; - position: absolute; - padding: 5px 10px 5px 10px; - border-radius: 5px; - font-size: 130%; - top: 5px; - right: 5px; + background-color: rgba(78, 139, 202, 0.2); + display: inline-block; + position: absolute; + padding: 5px 10px 5px 10px; + border-radius: 5px; + font-size: 130%; + top: 5px; + right: 5px; } a.test-arrow:hover{ - background-color: #4e8bca; - text-decoration: none; + background-color: #4e8bca; + text-decoration: none; } .section-header:hover a:after { - content: '\2002\00a7\2002'; + content: '\2002\00a7\2002'; } .section-header:hover a { - text-decoration: none; + text-decoration: none; } .section-header a { - color: inherit; + color: inherit; } .collapse-toggle { - font-weight: 300; - position: absolute; - left: -23px; - color: #999; - top: 0; + font-weight: 300; + position: absolute; + left: -23px; + color: #999; + top: 0; } .toggle-wrapper > .collapse-toggle { - left: -24px; - margin-top: 0px; + left: -24px; + margin-top: 0px; } .toggle-wrapper { - position: relative; + position: relative; } .toggle-wrapper.collapsed { - height: 1em; - transition: height .2s; + height: 1em; + transition: height .2s; } .collapse-toggle > .inner { - display: inline-block; - width: 1.2ch; - text-align: center; + display: inline-block; + width: 1.2ch; + text-align: center; } .toggle-label { - color: #999; + color: #999; } .ghost { - display: none; + display: none; } .ghost + .since { - position: initial; - display: table-cell; + position: initial; + display: table-cell; } .since + .srclink { - display: table-cell; - padding-left: 10px; + display: table-cell; + padding-left: 10px; } span.since { - position: initial; - font-size: 20px; - margin-right: 5px; + position: initial; + font-size: 20px; + margin-right: 5px; } .toggle-wrapper > .collapse-toggle { - left: 0; + left: 0; } .variant + .toggle-wrapper > a { - margin-top: 5px; + margin-top: 5px; } .enum > .toggle-wrapper + .docblock, .struct > .toggle-wrapper + .docblock { - margin-left: 30px; - margin-bottom: 20px; - margin-top: 5px; + margin-left: 30px; + margin-bottom: 20px; + margin-top: 5px; } .enum > .collapsed, .struct > .collapsed { - margin-bottom: 25px; + margin-bottom: 25px; } .enum .variant, .struct .structfield { - display: block; + display: block; +} + +.attributes { + display: block; + margin: 0px 0px 0px 30px !important; +} +.toggle-attributes.collapsed { + margin-bottom: 5px; } :target > code { @@ -685,71 +693,71 @@ span.since { /* Media Queries */ @media (max-width: 700px) { - body { - padding-top: 0px; - } + body { + padding-top: 0px; + } - .sidebar { - height: 40px; - min-height: 40px; - width: 100%; - margin: 0px; - padding: 0px; - position: static; - } + .sidebar { + height: 40px; + min-height: 40px; + width: 100%; + margin: 0px; + padding: 0px; + position: static; + } - .sidebar .location { - float: right; - margin: 0px; - padding: 3px 10px 1px 10px; - min-height: 39px; - background: inherit; - text-align: left; - font-size: 24px; - } + .sidebar .location { + float: right; + margin: 0px; + padding: 3px 10px 1px 10px; + min-height: 39px; + background: inherit; + text-align: left; + font-size: 24px; + } - .sidebar .location:empty { - padding: 0; - } + .sidebar .location:empty { + padding: 0; + } - .sidebar img { - width: 35px; - margin-top: 5px; - margin-bottom: 0px; - float: left; - } + .sidebar img { + width: 35px; + margin-top: 5px; + margin-bottom: 0px; + float: left; + } - nav.sub { - margin: 0 auto; - } + nav.sub { + margin: 0 auto; + } - .sidebar .block { - display: none; - } + .sidebar .block { + display: none; + } - .content { - margin-left: 0px; - } + .content { + margin-left: 0px; + } - .content .in-band { - width: 100%; - } + .content .in-band { + width: 100%; + } - .content .out-of-band { - display: none; - } + .content .out-of-band { + display: none; + } - .toggle-wrapper > .collapse-toggle { - left: 0px; - } + .toggle-wrapper > .collapse-toggle { + left: 0px; + } - .toggle-wrapper { - height: 1.5em; - } + .toggle-wrapper { + height: 1.5em; + } } @media print { - nav.sub, .content .out-of-band, .collapse-toggle { - display: none; - } + nav.sub, .content .out-of-band, .collapse-toggle { + display: none; + } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index cf5e8e5e34a3..ee395e0616b8 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -20,7 +20,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(libc)] #![feature(rustc_private)] #![feature(set_stdio)] diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 1bbd67fb9be3..12d33dcb207f 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -87,7 +87,7 @@ pub fn run(input: &str, config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone())); let krate = panictry!(driver::phase_1_parse_input(&sess, &input)); - let driver::ExpansionResult { defs, mut hir_forest, .. } = { + let driver::ExpansionResult { defs, mut hir_forest, analysis, .. } = { phase_2_configure_and_expand( &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(()) ).expect("phase_2_configure_and_expand aborted in rustdoc!") @@ -110,6 +110,7 @@ pub fn run(input: &str, renderinfo: Default::default(), ty_substs: Default::default(), lt_substs: Default::default(), + export_map: analysis.export_map, }; let mut v = RustdocVisitor::new(&ctx); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4d1af1622724..d0407162793e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -21,8 +21,9 @@ use syntax_pos::Span; use rustc::hir::map as hir_map; use rustc::hir::def::Def; use rustc::hir::def_id::LOCAL_CRATE; +use rustc::middle::cstore::LoadedMacro; use rustc::middle::privacy::AccessLevel; -use rustc::util::nodemap::FnvHashSet; +use rustc::util::nodemap::FxHashSet; use rustc::hir; @@ -42,14 +43,14 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> { pub module: Module, pub attrs: hir::HirVec, pub cx: &'a core::DocContext<'a, 'tcx>, - view_item_stack: FnvHashSet, + view_item_stack: FxHashSet, inlining_from_glob: bool, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub fn new(cx: &'a core::DocContext<'a, 'tcx>) -> RustdocVisitor<'a, 'tcx> { // If the root is reexported, terminate all recursion. - let mut stack = FnvHashSet(); + let mut stack = FxHashSet(); stack.insert(ast::CRATE_NODE_ID); RustdocVisitor { module: Module::new(None), @@ -85,8 +86,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &krate.module, None); // attach the crate's exported macros to the top-level module: - self.module.macros = krate.exported_macros.iter() - .map(|def| self.visit_macro(def)).collect(); + let macro_exports: Vec<_> = + krate.exported_macros.iter().map(|def| self.visit_macro(def)).collect(); + self.module.macros.extend(macro_exports); self.module.is_crate = true; } @@ -191,6 +193,33 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let item = self.cx.map.expect_item(i.id); self.visit_item(item, None, &mut om); } + if let Some(exports) = self.cx.export_map.get(&id) { + for export in exports { + if let Def::Macro(def_id) = export.def { + if def_id.krate == LOCAL_CRATE { + continue // These are `krate.exported_macros`, handled in `self.visit()`. + } + let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) { + LoadedMacro::MacroRules(macro_rules) => macro_rules, + // FIXME(jseyfried): document proc macro reexports + LoadedMacro::ProcMacro(..) => continue, + }; + + // FIXME(jseyfried) merge with `self.visit_macro()` + let matchers = def.body.chunks(4).map(|arm| arm[0].get_span()).collect(); + om.macros.push(Macro { + id: def.id, + attrs: def.attrs.clone().into(), + name: def.ident.name, + whence: def.span, + matchers: matchers, + stab: self.stability(def.id), + depr: self.deprecation(def.id), + imported_from: def.imported_from.map(|ident| ident.name), + }) + } + } + } om } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index fb8a0c3c2655..ece51d6d8261 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,6 +11,7 @@ use self::Entry::*; use self::VacantEntryState::*; +use cell::Cell; use borrow::Borrow; use cmp::max; use fmt::{self, Debug}; @@ -2049,24 +2050,21 @@ impl RandomState { // many hash maps are created on a thread. To solve this performance // trap we cache the first set of randomly generated keys per-thread. // - // In doing this, however, we lose the property that all hash maps have - // nondeterministic iteration order as all of those created on the same - // thread would have the same hash keys. This property has been nice in - // the past as it allows for maximal flexibility in the implementation - // of `HashMap` itself. - // - // The constraint here (if there even is one) is just that maps created - // on the same thread have the same iteration order, and that *may* be - // relied upon even though it is not a documented guarantee at all of - // the `HashMap` type. In any case we've decided that this is reasonable - // for now, so caching keys thread-locally seems fine. - thread_local!(static KEYS: (u64, u64) = { + // Later in #36481 it was discovered that exposing a deterministic + // iteration order allows a form of DOS attack. To counter that we + // increment one of the seeds on every RandomState creation, giving + // every corresponding HashMap a different iteration order. + thread_local!(static KEYS: Cell<(u64, u64)> = { let r = rand::OsRng::new(); let mut r = r.expect("failed to create an OS RNG"); - (r.gen(), r.gen()) + Cell::new((r.gen(), r.gen())) }); - KEYS.with(|&(k0, k1)| RandomState { k0: k0, k1: k1 }) + KEYS.with(|keys| { + let (k0, k1) = keys.get(); + keys.set((k0.wrapping_add(1), k1)); + RandomState { k0: k0, k1: k1 } + }) } } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 3ad5b5627d31..d1b8fcd74400 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -686,7 +686,7 @@ impl ToOwned for CStr { type Owned = CString; fn to_owned(&self) -> CString { - unsafe { CString::from_vec_unchecked(self.to_bytes().to_vec()) } + CString { inner: self.to_bytes_with_nul().to_vec().into_boxed_slice() } } } diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index ddf0030858ed..795c89c00074 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -12,6 +12,7 @@ use error; use fmt; use result; use sys; +use convert::From; /// A specialized [`Result`](../result/enum.Result.html) type for I/O /// operations. @@ -62,6 +63,7 @@ pub struct Error { enum Repr { Os(i32), + Simple(ErrorKind), Custom(Box), } @@ -124,23 +126,28 @@ pub enum ErrorKind { InvalidInput, /// Data not valid for the operation were encountered. /// - /// Unlike `InvalidInput`, this typically means that the operation + /// Unlike [`InvalidInput`], this typically means that the operation /// parameters were valid, however the error was caused by malformed /// input data. /// /// For example, a function that reads a file into a string will error with /// `InvalidData` if the file's contents are not valid UTF-8. + /// + /// [`InvalidInput`]: #variant.InvalidInput #[stable(feature = "io_invalid_data", since = "1.2.0")] InvalidData, /// The I/O operation's timeout expired, causing it to be canceled. #[stable(feature = "rust1", since = "1.0.0")] TimedOut, /// An error returned when an operation could not be completed because a - /// call to `write` returned `Ok(0)`. + /// call to [`write()`] returned [`Ok(0)`]. /// /// This typically means that an operation could only succeed if it wrote a /// particular number of bytes but only a smaller number of bytes could be /// written. + /// + /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write + /// [`Ok(0)`]: ../../std/io/type.Result.html #[stable(feature = "rust1", since = "1.0.0")] WriteZero, /// This operation was interrupted. @@ -171,6 +178,43 @@ pub enum ErrorKind { __Nonexhaustive, } +impl ErrorKind { + fn as_str(&self) -> &'static str { + match *self { + ErrorKind::NotFound => "entity not found", + ErrorKind::PermissionDenied => "permission denied", + ErrorKind::ConnectionRefused => "connection refused", + ErrorKind::ConnectionReset => "connection reset", + ErrorKind::ConnectionAborted => "connection aborted", + ErrorKind::NotConnected => "not connected", + ErrorKind::AddrInUse => "address in use", + ErrorKind::AddrNotAvailable => "address not available", + ErrorKind::BrokenPipe => "broken pipe", + ErrorKind::AlreadyExists => "entity already exists", + ErrorKind::WouldBlock => "operation would block", + ErrorKind::InvalidInput => "invalid input parameter", + ErrorKind::InvalidData => "invalid data", + ErrorKind::TimedOut => "timed out", + ErrorKind::WriteZero => "write zero", + ErrorKind::Interrupted => "operation interrupted", + ErrorKind::Other => "other os error", + ErrorKind::UnexpectedEof => "unexpected end of file", + ErrorKind::__Nonexhaustive => unreachable!() + } + } +} + +/// Intended for use for errors not exposed to the user, where allocating onto +/// the heap (for normal construction via Error::new) is too costly. +#[stable(feature = "io_error_from_errorkind", since = "1.14.0")] +impl From for Error { + fn from(kind: ErrorKind) -> Error { + Error { + repr: Repr::Simple(kind) + } + } +} + impl Error { /// Creates a new I/O error from a known kind of error as well as an /// arbitrary error payload. @@ -285,6 +329,7 @@ impl Error { match self.repr { Repr::Os(i) => Some(i), Repr::Custom(..) => None, + Repr::Simple(..) => None, } } @@ -317,6 +362,7 @@ impl Error { pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(ref c) => Some(&*c.error), } } @@ -387,6 +433,7 @@ impl Error { pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(ref mut c) => Some(&mut *c.error), } } @@ -420,6 +467,7 @@ impl Error { pub fn into_inner(self) -> Option> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(c) => Some(c.error) } } @@ -447,6 +495,7 @@ impl Error { match self.repr { Repr::Os(code) => sys::decode_error_kind(code), Repr::Custom(ref c) => c.kind, + Repr::Simple(kind) => kind, } } } @@ -458,6 +507,7 @@ impl fmt::Debug for Repr { fmt.debug_struct("Os").field("code", code) .field("message", &sys::os::error_string(*code)).finish(), Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(), + Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), } } } @@ -471,6 +521,7 @@ impl fmt::Display for Error { write!(fmt, "{} (os error {})", detail, code) } Repr::Custom(ref c) => c.error.fmt(fmt), + Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()), } } } @@ -479,27 +530,7 @@ impl fmt::Display for Error { impl error::Error for Error { fn description(&self) -> &str { match self.repr { - Repr::Os(..) => match self.kind() { - ErrorKind::NotFound => "entity not found", - ErrorKind::PermissionDenied => "permission denied", - ErrorKind::ConnectionRefused => "connection refused", - ErrorKind::ConnectionReset => "connection reset", - ErrorKind::ConnectionAborted => "connection aborted", - ErrorKind::NotConnected => "not connected", - ErrorKind::AddrInUse => "address in use", - ErrorKind::AddrNotAvailable => "address not available", - ErrorKind::BrokenPipe => "broken pipe", - ErrorKind::AlreadyExists => "entity already exists", - ErrorKind::WouldBlock => "operation would block", - ErrorKind::InvalidInput => "invalid input parameter", - ErrorKind::InvalidData => "invalid data", - ErrorKind::TimedOut => "timed out", - ErrorKind::WriteZero => "write zero", - ErrorKind::Interrupted => "operation interrupted", - ErrorKind::Other => "other os error", - ErrorKind::UnexpectedEof => "unexpected end of file", - ErrorKind::__Nonexhaustive => unreachable!() - }, + Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(), Repr::Custom(ref c) => c.error.description(), } } @@ -507,6 +538,7 @@ impl error::Error for Error { fn cause(&self) -> Option<&error::Error> { match self.repr { Repr::Os(..) => None, + Repr::Simple(..) => None, Repr::Custom(ref c) => c.error.cause(), } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 193f396c0d4a..ad9ae5638b6a 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -21,7 +21,7 @@ //! of other types, and you can implement them for your types too. As such, //! you'll see a few different types of I/O throughout the documentation in //! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For -//! example, `Read` adds a `read()` method, which we can use on `File`s: +//! example, [`Read`] adds a [`read()`] method, which we can use on `File`s: //! //! ``` //! use std::io; @@ -251,6 +251,7 @@ //! [`Lines`]: struct.Lines.html //! [`io::Result`]: type.Result.html //! [`try!`]: ../macro.try.html +//! [`read()`]: trait.Read.html#tymethod.read #![stable(feature = "rust1", since = "1.0.0")] @@ -814,19 +815,23 @@ pub trait Read { /// /// Implementors of the `Write` trait are sometimes called 'writers'. /// -/// Writers are defined by two required methods, `write()` and `flush()`: +/// Writers are defined by two required methods, [`write()`] and [`flush()`]: /// -/// * The `write()` method will attempt to write some data into the object, +/// * The [`write()`] method will attempt to write some data into the object, /// returning how many bytes were successfully written. /// -/// * The `flush()` method is useful for adaptors and explicit buffers +/// * The [`flush()`] method is useful for adaptors and explicit buffers /// themselves for ensuring that all buffered data has been pushed out to the /// 'true sink'. /// /// Writers are intended to be composable with one another. Many implementors -/// throughout `std::io` take and provide types which implement the `Write` +/// throughout [`std::io`] take and provide types which implement the `Write` /// trait. /// +/// [`write()`]: #tymethod.write +/// [`flush()`]: #tymethod.flush +/// [`std::io`]: index.html +/// /// # Examples /// /// ``` @@ -1475,10 +1480,10 @@ impl BufRead for Chain { /// Reader adaptor which limits the bytes read from an underlying reader. /// -/// This struct is generally created by calling [`take()`][take] on a reader. -/// Please see the documentation of `take()` for more details. +/// This struct is generally created by calling [`take()`] on a reader. +/// Please see the documentation of [`take()`] for more details. /// -/// [take]: trait.Read.html#method.take +/// [`take()`]: trait.Read.html#method.take #[stable(feature = "rust1", since = "1.0.0")] pub struct Take { inner: T, @@ -1491,8 +1496,10 @@ impl Take { /// /// # Note /// - /// This instance may reach EOF after reading fewer bytes than indicated by - /// this method if the underlying `Read` instance reaches EOF. + /// This instance may reach `EOF` after reading fewer bytes than indicated by + /// this method if the underlying [`Read`] instance reaches EOF. + /// + /// [`Read`]: ../../std/io/trait.Read.html /// /// # Examples /// diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 27bc5f0890ce..f6ee0be47fad 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -324,10 +324,11 @@ impl<'a> BufRead for StdinLock<'a> { /// /// Each handle shares a global buffer of data to be written to the standard /// output stream. Access is also synchronized via a lock and explicit control -/// over locking is available via the `lock` method. +/// over locking is available via the [`lock()`] method. /// /// Created by the [`io::stdout`] method. /// +/// [`lock()`]: #method.lock /// [`io::stdout`]: fn.stdout.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdout { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 8d973fc1ade4..12dbbe3c4691 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -249,7 +249,7 @@ #![feature(const_fn)] #![feature(core_float)] #![feature(core_intrinsics)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(dropck_parametricity)] #![feature(float_extras)] #![feature(float_from_str_radix)] diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index c03ac496adbb..559250adac5e 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -67,6 +67,9 @@ impl UdpSocket { /// /// Address type can be any implementor of `ToSocketAddrs` trait. See its /// documentation for concrete examples. + /// This will return an error when the IP version of the local socket + /// does not match that returned from `ToSocketAddrs` + /// See https://github.com/rust-lang/rust/issues/34202 for more details. #[stable(feature = "rust1", since = "1.0.0")] pub fn send_to(&self, buf: &[u8], addr: A) -> io::Result { diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 9b7f9980cc0a..bb6883236e80 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1173,6 +1173,13 @@ impl From for PathBuf { } } +#[stable(feature = "from_path_buf_for_os_string", since = "1.14.0")] +impl From for OsString { + fn from(path_buf : PathBuf) -> OsString { + path_buf.inner + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl From for PathBuf { fn from(s: String) -> PathBuf { @@ -1283,13 +1290,6 @@ impl AsRef for PathBuf { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Into for PathBuf { - fn into(self) -> OsString { - self.inner - } -} - /// A slice of a path (akin to [`str`]). /// /// This type supports a number of operations for inspecting a path, including diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index a237d8a067e2..e4b0d980c921 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -23,7 +23,7 @@ //! integration code in `std::sys_common`. See that module's //! documentation for details. //! -//! In the future it would be desirable for the indepedent +//! In the future it would be desirable for the independent //! implementations of this module to be extracted to their own crates //! that `std` can link to, thus enabling their implementation //! out-of-tree via crate replacement. Though due to the complex diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 3aebb8c18ec8..9b1cf6ffd0e2 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -350,11 +350,19 @@ mod imp { #[link(name = "magenta")] extern { - fn mx_cprng_draw(buffer: *mut u8, len: usize) -> isize; + fn mx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; } - fn getrandom(buf: &mut [u8]) -> isize { - unsafe { mx_cprng_draw(buf.as_mut_ptr(), buf.len()) } + fn getrandom(buf: &mut [u8]) -> Result { + unsafe { + let mut actual = 0; + let status = mx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual); + if status == 0 { + Ok(actual) + } else { + Err(status) + } + } } pub struct OsRng { @@ -381,12 +389,16 @@ mod imp { let mut buf = v; while !buf.is_empty() { let ret = getrandom(buf); - if ret < 0 { - panic!("kernel mx_cprng_draw call failed! (returned {}, buf.len() {})", - ret, buf.len()); + match ret { + Err(err) => { + panic!("kernel mx_cprng_draw call failed! (returned {}, buf.len() {})", + err, buf.len()) + } + Ok(actual) => { + let move_buf = buf; + buf = &mut move_buf[(actual as usize)..]; + } } - let move_buf = buf; - buf = &mut move_buf[(ret as usize)..]; } } } diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 5f5ea09c78d6..5c07e36508c6 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -10,7 +10,7 @@ //! Platform-independent platform abstraction //! -//! This is the platform-independent portion of the standard libraries +//! This is the platform-independent portion of the standard library's //! platform abstraction layer, whereas `std::sys` is the //! platform-specific portion. //! diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f077ead1f8e0..f5cd089e923d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -399,6 +399,14 @@ impl Generics { pub fn is_parameterized(&self) -> bool { self.is_lt_parameterized() || self.is_type_parameterized() } + pub fn span_for_name(&self, name: &str) -> Option { + for t in &self.ty_params { + if t.ident.name.as_str() == name { + return Some(t.span); + } + } + None + } } impl Default for Generics { @@ -1009,10 +1017,10 @@ pub enum ExprKind { Loop(P, Option), /// A `match` block. Match(P, Vec), - /// A closure (for example, `move |a, b, c| {a + b + c}`) + /// A closure (for example, `move |a, b, c| a + b + c`) /// /// The final span is the span of the argument block `|...|` - Closure(CaptureBy, P, P, Span), + Closure(CaptureBy, P, P, Span), /// A block (`{ ... }`) Block(P), @@ -1050,7 +1058,7 @@ pub enum ExprKind { Ret(Option>), /// Output of the `asm!()` macro - InlineAsm(InlineAsm), + InlineAsm(P), /// A macro invocation; pre-expansion Mac(Mac), diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 0335f210347a..57a936bf9b0c 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -32,7 +32,8 @@ use std::cell::{RefCell, Cell}; use std::collections::HashSet; thread_local! { - static USED_ATTRS: RefCell> = RefCell::new(Vec::new()) + static USED_ATTRS: RefCell> = RefCell::new(Vec::new()); + static KNOWN_ATTRS: RefCell> = RefCell::new(Vec::new()); } enum AttrError { @@ -81,6 +82,29 @@ pub fn is_used(attr: &Attribute) -> bool { }) } +pub fn mark_known(attr: &Attribute) { + debug!("Marking {:?} as known.", attr); + let AttrId(id) = attr.node.id; + KNOWN_ATTRS.with(|slot| { + let idx = (id / 64) as usize; + let shift = id % 64; + if slot.borrow().len() <= idx { + slot.borrow_mut().resize(idx + 1, 0); + } + slot.borrow_mut()[idx] |= 1 << shift; + }); +} + +pub fn is_known(attr: &Attribute) -> bool { + let AttrId(id) = attr.node.id; + KNOWN_ATTRS.with(|slot| { + let idx = (id / 64) as usize; + let shift = id % 64; + slot.borrow().get(idx).map(|bits| bits & (1 << shift) != 0) + .unwrap_or(false) + }) +} + impl NestedMetaItem { /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. pub fn meta_item(&self) -> Option<&P> { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index cc097ab0efad..63eee7df9e85 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -517,6 +517,7 @@ pub type NamedSyntaxExtension = (Name, SyntaxExtension); pub trait Resolver { fn next_node_id(&mut self) -> ast::NodeId; fn get_module_scope(&mut self, id: ast::NodeId) -> Mark; + fn eliminate_crate_var(&mut self, item: P) -> P; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); fn add_macro(&mut self, scope: Mark, def: ast::MacroDef, export: bool); @@ -539,6 +540,7 @@ pub struct DummyResolver; impl Resolver for DummyResolver { fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID } fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() } + fn eliminate_crate_var(&mut self, item: P) -> P { item } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef, _export: bool) {} @@ -615,7 +617,9 @@ impl<'a> ExtCtxt<'a> { pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) -> parser::Parser<'a> { - parse::tts_to_parser(self.parse_sess, tts.to_vec()) + let mut parser = parse::tts_to_parser(self.parse_sess, tts.to_vec()); + parser.allow_interpolated_tts = false; // FIXME(jseyfried) `quote!` can't handle these yet + parser } pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() } pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 37bd83be7b4d..c3e28cbb006a 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -198,17 +198,13 @@ pub trait AstBuilder { fn lambda_fn_decl(&self, span: Span, fn_decl: P, - blk: P, + body: P, fn_decl_span: Span) -> P; - fn lambda(&self, span: Span, ids: Vec, blk: P) -> P; - fn lambda0(&self, span: Span, blk: P) -> P; - fn lambda1(&self, span: Span, blk: P, ident: ast::Ident) -> P; - - fn lambda_expr(&self, span: Span, ids: Vec , blk: P) -> P; - fn lambda_expr_0(&self, span: Span, expr: P) -> P; - fn lambda_expr_1(&self, span: Span, expr: P, ident: ast::Ident) -> P; + fn lambda(&self, span: Span, ids: Vec, body: P) -> P; + fn lambda0(&self, span: Span, body: P) -> P; + fn lambda1(&self, span: Span, body: P, ident: ast::Ident) -> P; fn lambda_stmts(&self, span: Span, ids: Vec, blk: Vec) -> P; @@ -940,19 +936,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn lambda_fn_decl(&self, span: Span, fn_decl: P, - blk: P, + body: P, fn_decl_span: Span) // span of the `|...|` part -> P { self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, - blk, + body, fn_decl_span)) } fn lambda(&self, span: Span, ids: Vec, - blk: P) + body: P) -> P { let fn_decl = self.fn_decl( ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(), @@ -962,26 +958,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> { // part of the lambda, but it probably (maybe?) corresponds to // the entire lambda body. Probably we should extend the API // here, but that's not entirely clear. - self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, blk, span)) + self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, body, span)) } - fn lambda0(&self, span: Span, blk: P) -> P { - self.lambda(span, Vec::new(), blk) + fn lambda0(&self, span: Span, body: P) -> P { + self.lambda(span, Vec::new(), body) } - fn lambda1(&self, span: Span, blk: P, ident: ast::Ident) -> P { - self.lambda(span, vec![ident], blk) - } - - fn lambda_expr(&self, span: Span, ids: Vec, - expr: P) -> P { - self.lambda(span, ids, self.block_expr(expr)) - } - fn lambda_expr_0(&self, span: Span, expr: P) -> P { - self.lambda0(span, self.block_expr(expr)) - } - fn lambda_expr_1(&self, span: Span, expr: P, ident: ast::Ident) -> P { - self.lambda1(span, self.block_expr(expr), ident) + fn lambda1(&self, span: Span, body: P, ident: ast::Ident) -> P { + self.lambda(span, vec![ident], body) } fn lambda_stmts(&self, @@ -989,14 +974,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ids: Vec, stmts: Vec) -> P { - self.lambda(span, ids, self.block(span, stmts)) + self.lambda(span, ids, self.expr_block(self.block(span, stmts))) } fn lambda_stmts_0(&self, span: Span, stmts: Vec) -> P { - self.lambda0(span, self.block(span, stmts)) + self.lambda0(span, self.expr_block(self.block(span, stmts))) } fn lambda_stmts_1(&self, span: Span, stmts: Vec, ident: ast::Ident) -> P { - self.lambda1(span, self.block(span, stmts), ident) + self.lambda1(span, self.expr_block(self.block(span, stmts)), ident) } fn arg(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Arg { diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index f21360755bc2..969cfa292ce8 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -80,67 +80,71 @@ pub mod rt { impl ToTokens for ast::Path { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, - token::Interpolated(token::NtPath(Box::new(self.clone()))))] + let nt = token::NtPath(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Ty { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtTy(P(self.clone()))))] + let nt = token::NtTy(P(self.clone())); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Block { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtBlock(P(self.clone()))))] + let nt = token::NtBlock(P(self.clone())); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Generics { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtGenerics(self.clone())))] + let nt = token::NtGenerics(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::WhereClause { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, - token::Interpolated(token::NtWhereClause(self.clone())))] + let nt = token::NtWhereClause(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtItem(self.clone())))] + let nt = token::NtItem(self.clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::ImplItem { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, - token::Interpolated(token::NtImplItem(P(self.clone()))))] + let nt = token::NtImplItem(self.clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtImplItem(self.clone())))] + let nt = token::NtImplItem((**self).clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::TraitItem { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, - token::Interpolated(token::NtTraitItem(P(self.clone()))))] + let nt = token::NtTraitItem(self.clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Stmt { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - let mut tts = vec![ - TokenTree::Token(self.span, token::Interpolated(token::NtStmt(P(self.clone())))) - ]; + let nt = token::NtStmt(self.clone()); + let mut tts = vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))]; // Some statements require a trailing semicolon. if classify::stmt_ends_with_semi(&self.node) { @@ -153,31 +157,36 @@ pub mod rt { impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtExpr(self.clone())))] + let nt = token::NtExpr(self.clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(self.span, token::Interpolated(token::NtPat(self.clone())))] + let nt = token::NtPat(self.clone()); + vec![TokenTree::Token(self.span, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Arm { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))] + let nt = token::NtArm(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for ast::Arg { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArg(self.clone())))] + let nt = token::NtArg(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtBlock(self.clone())))] + let nt = token::NtBlock(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } @@ -204,7 +213,8 @@ pub mod rt { impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { - vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))] + let nt = token::NtMeta(self.clone()); + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(Rc::new(nt)))] } } diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 7e3fe3285695..1066646aa8e8 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -89,7 +89,6 @@ use parse::token::{DocComment, MatchNt, SubstNt}; use parse::token::{Token, Nonterminal}; use parse::token; use print::pprust; -use ptr::P; use tokenstream::{self, TokenTree}; use util::small_vector::SmallVector; @@ -198,7 +197,7 @@ pub fn initial_matcher_pos(ms: Vec, sep: Option, lo: BytePos) pub enum NamedMatch { MatchedSeq(Vec>, syntax_pos::Span), - MatchedNonterminal(Nonterminal) + MatchedNonterminal(Rc) } pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) @@ -279,17 +278,16 @@ pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { } } -pub fn parse(sess: &ParseSess, mut rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult { - let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), - None, - rdr.peek().sp.lo)); +pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult { + let mut parser = Parser::new_with_doc_flag(sess, Box::new(rdr), true); + let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), None, parser.span.lo)); loop { let mut bb_eis = Vec::new(); // black-box parsed by parser.rs let mut next_eis = Vec::new(); // or proceed normally let mut eof_eis = Vec::new(); - let TokenAndSpan { tok, sp } = rdr.peek(); + let (sp, tok) = (parser.span, parser.token.clone()); /* we append new items to this while we go */ loop { @@ -474,23 +472,19 @@ pub fn parse(sess: &ParseSess, mut rdr: TtReader, ms: &[TokenTree]) -> NamedPars while !next_eis.is_empty() { cur_eis.push(next_eis.pop().unwrap()); } - rdr.next_token(); + parser.bump(); } else /* bb_eis.len() == 1 */ { - rdr.next_tok = { - let mut rust_parser = Parser::new(sess, Box::new(&mut rdr)); - let mut ei = bb_eis.pop().unwrap(); - if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) { - let match_cur = ei.match_cur; - (&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal( - parse_nt(&mut rust_parser, span, &ident.name.as_str())))); - ei.idx += 1; - ei.match_cur += 1; - } else { - unreachable!() - } - cur_eis.push(ei); - Some(TokenAndSpan { tok: rust_parser.token, sp: rust_parser.span }) - }; + let mut ei = bb_eis.pop().unwrap(); + if let TokenTree::Token(span, MatchNt(_, ident)) = ei.top_elts.get_tt(ei.idx) { + let match_cur = ei.match_cur; + (&mut ei.matches[match_cur]).push(Rc::new(MatchedNonterminal( + Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))))); + ei.idx += 1; + ei.match_cur += 1; + } else { + unreachable!() + } + cur_eis.push(ei); } } @@ -502,10 +496,19 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { match name { "tt" => { p.quote_depth += 1; //but in theory, non-quoted tts might be useful - let res: ::parse::PResult<'a, _> = p.parse_token_tree(); - let res = token::NtTT(P(panictry!(res))); + let mut tt = panictry!(p.parse_token_tree()); p.quote_depth -= 1; - return res; + loop { + let nt = match tt { + TokenTree::Token(_, token::Interpolated(ref nt)) => nt.clone(), + _ => break, + }; + match *nt { + token::NtTT(ref sub_tt) => tt = sub_tt.clone(), + _ => break, + } + } + return token::NtTT(tt); } _ => {} } @@ -521,7 +524,7 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { }, "block" => token::NtBlock(panictry!(p.parse_block())), "stmt" => match panictry!(p.parse_stmt()) { - Some(s) => token::NtStmt(P(s)), + Some(s) => token::NtStmt(s), None => { p.fatal("expected a statement").emit(); panic!(FatalError); @@ -534,7 +537,7 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { "ident" => match p.token { token::Ident(sn) => { p.bump(); - token::NtIdent(Box::new(Spanned::{node: sn, span: p.span})) + token::NtIdent(Spanned::{node: sn, span: p.span}) } _ => { let token_str = pprust::token_to_string(&p.token); @@ -544,7 +547,7 @@ pub fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { } }, "path" => { - token::NtPath(Box::new(panictry!(p.parse_path(PathStyle::Type)))) + token::NtPath(panictry!(p.parse_path(PathStyle::Type))) }, "meta" => token::NtMeta(panictry!(p.parse_meta_item())), // this is not supposed to happen, since it has been checked diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 431e757368c0..552d4de96174 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -236,12 +236,14 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { // Extract the arguments: let lhses = match **argument_map.get(&lhs_nm).unwrap() { MatchedSeq(ref s, _) => { - s.iter().map(|m| match **m { - MatchedNonterminal(NtTT(ref tt)) => { - valid &= check_lhs_nt_follows(sess, tt); - (**tt).clone() + s.iter().map(|m| { + if let MatchedNonterminal(ref nt) = **m { + if let NtTT(ref tt) = **nt { + valid &= check_lhs_nt_follows(sess, tt); + return (*tt).clone(); + } } - _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") + sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") }).collect::>() } _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") @@ -249,9 +251,13 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { let rhses = match **argument_map.get(&rhs_nm).unwrap() { MatchedSeq(ref s, _) => { - s.iter().map(|m| match **m { - MatchedNonterminal(NtTT(ref tt)) => (**tt).clone(), - _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs") + s.iter().map(|m| { + if let MatchedNonterminal(ref nt) = **m { + if let NtTT(ref tt) = **nt { + return (*tt).clone(); + } + } + sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") }).collect() } _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs") diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 8a6a8e53a3e4..37e329e5d3b2 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -12,9 +12,7 @@ use self::LockstepIterSize::*; use ast::Ident; use errors::{Handler, DiagnosticBuilder}; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; -use parse::token::{DocComment, MatchNt, SubstNt}; -use parse::token::{Token, Interpolated, NtIdent, NtTT}; -use parse::token; +use parse::token::{self, MatchNt, SubstNt, Token, NtIdent}; use parse::lexer::TokenAndSpan; use syntax_pos::{Span, DUMMY_SP}; use tokenstream::{self, TokenTree}; @@ -46,9 +44,7 @@ pub struct TtReader<'a> { /* cached: */ pub cur_tok: Token, pub cur_span: Span, - pub next_tok: Option, /// Transform doc comments. Only useful in macro invocations - pub desugar_doc_comments: bool, pub fatal_errs: Vec>, } @@ -59,20 +55,6 @@ pub fn new_tt_reader(sp_diag: &Handler, interp: Option>>, src: Vec) -> TtReader { - new_tt_reader_with_doc_flag(sp_diag, interp, src, false) -} - -/// The extra `desugar_doc_comments` flag enables reading doc comments -/// like any other attribute which consists of `meta` and surrounding #[ ] tokens. -/// -/// This can do Macro-By-Example transcription. On the other hand, if -/// `src` contains no `TokenTree::Sequence`s, `MatchNt`s or `SubstNt`s, `interp` can -/// (and should) be None. -pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler, - interp: Option>>, - src: Vec, - desugar_doc_comments: bool) - -> TtReader { let mut r = TtReader { sp_diag: sp_diag, stack: SmallVector::one(TtFrame { @@ -91,11 +73,9 @@ pub fn new_tt_reader_with_doc_flag(sp_diag: &Handler, }, repeat_idx: Vec::new(), repeat_len: Vec::new(), - desugar_doc_comments: desugar_doc_comments, /* dummy values, never read: */ cur_tok: token::Eof, cur_span: DUMMY_SP, - next_tok: None, fatal_errs: Vec::new(), }; tt_next_token(&mut r); /* get cur_tok and cur_span set up */ @@ -174,9 +154,6 @@ fn lockstep_iter_size(t: &TokenTree, r: &TtReader) -> LockstepIterSize { /// Return the next token from the TtReader. /// EFFECT: advances the reader's token field pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { - if let Some(tok) = r.next_tok.take() { - return tok; - } // FIXME(pcwalton): Bad copy? let ret_val = TokenAndSpan { tok: r.cur_tok.clone(), @@ -269,47 +246,35 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { } // FIXME #2887: think about span stuff here TokenTree::Token(sp, SubstNt(ident)) => { + r.stack.last_mut().unwrap().idx += 1; match lookup_cur_matched(r, ident) { None => { - r.stack.last_mut().unwrap().idx += 1; r.cur_span = sp; r.cur_tok = SubstNt(ident); return ret_val; // this can't be 0 length, just like TokenTree::Delimited } - Some(cur_matched) => { - match *cur_matched { + Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched { + match **nt { // sidestep the interpolation tricks for ident because // (a) idents can be in lots of places, so it'd be a pain // (b) we actually can, since it's a token. - MatchedNonterminal(NtIdent(ref sn)) => { - r.stack.last_mut().unwrap().idx += 1; + NtIdent(ref sn) => { r.cur_span = sn.span; r.cur_tok = token::Ident(sn.node); return ret_val; } - MatchedNonterminal(NtTT(ref tt)) => { - r.stack.push(TtFrame { - forest: TokenTree::Token(sp, Interpolated(NtTT(tt.clone()))), - idx: 0, - dotdotdoted: false, - sep: None, - }); - } - MatchedNonterminal(ref other_whole_nt) => { - r.stack.last_mut().unwrap().idx += 1; + _ => { // FIXME(pcwalton): Bad copy. r.cur_span = sp; - r.cur_tok = Interpolated((*other_whole_nt).clone()); + r.cur_tok = token::Interpolated(nt.clone()); return ret_val; } - MatchedSeq(..) => { - panic!(r.sp_diag.span_fatal( - sp, /* blame the macro writer */ - &format!("variable '{}' is still repeating at this depth", - ident))); - } } + } else { + panic!(r.sp_diag.span_fatal( + sp, /* blame the macro writer */ + &format!("variable '{}' is still repeating at this depth", ident))); } } } @@ -324,14 +289,6 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { }); // if this could be 0-length, we'd need to potentially recur here } - TokenTree::Token(sp, DocComment(name)) if r.desugar_doc_comments => { - r.stack.push(TtFrame { - forest: TokenTree::Token(sp, DocComment(name)), - idx: 0, - dotdotdoted: false, - sep: None - }); - } TokenTree::Token(sp, tok) => { r.cur_span = sp; r.cur_tok = tok; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 129e4a823380..9116b392f178 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -268,13 +268,9 @@ declare_features! ( // Allows cfg(target_has_atomic = "..."). (active, cfg_target_has_atomic, "1.9.0", Some(32976)), - // Allows `..` in tuple (struct) patterns - (active, dotdot_in_tuple_patterns, "1.10.0", Some(33627)), - // Allows `impl Trait` in function return types. (active, conservative_impl_trait, "1.12.0", Some(34511)), - // Allows tuple structs and variants in more contexts, // Permits numeric fields in struct expressions and patterns. (active, relaxed_adts, "1.12.0", Some(35626)), @@ -309,6 +305,12 @@ declare_features! ( // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. (active, field_init_shorthand, "1.14.0", Some(37340)), + + // 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)), ); declare_features! ( @@ -352,7 +354,9 @@ declare_features! ( // Allows `#[deprecated]` attribute (accepted, deprecated, "1.9.0", Some(29935)), // `expr?` - (accepted, question_mark, "1.14.0", Some(31436)), + (accepted, question_mark, "1.13.0", Some(31436)), + // Allows `..` in tuple (struct) patterns + (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627)), ); // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -417,11 +421,11 @@ macro_rules! cfg_fn { } pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> { - KNOWN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect() + BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect() } // Attributes that have a special meaning to rustc or rustdoc -pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[ +pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[ // Normal attributes ("warn", Normal, Ungated), @@ -713,6 +717,12 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat "defining reflective traits is still evolving", cfg_fn!(reflect))), + ("windows_subsystem", Whitelisted, Gated(Stability::Unstable, + "windows_subsystem", + "the windows subsystem attribute \ + is currently unstable", + cfg_fn!(windows_subsystem))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), @@ -790,12 +800,12 @@ impl<'a> Context<'a> { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); let name = &*attr.name(); - for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES { + for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES { if n == name { if let &Gated(_, ref name, ref desc, ref has_feature) = gateage { gate_feature_fn!(self, has_feature, attr.span, name, desc); } - debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage); + debug!("check_attribute: {:?} is builtin, {:?}, {:?}", name, ty, gateage); return; } } @@ -815,6 +825,8 @@ impl<'a> Context<'a> { are reserved for internal compiler diagnostics"); } else if name.starts_with("derive_") { gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE); + } else if attr::is_known(attr) { + debug!("check_attribute: {:?} is known", name); } else { // Only run the custom attribute lint during regular // feature gate checking. Macro gating runs @@ -985,6 +997,10 @@ fn contains_novel_literal(item: &ast::MetaItem) -> bool { } } +fn starts_with_digit(s: &str) -> bool { + s.as_bytes().first().cloned().map_or(false, |b| b >= b'0' && b <= b'9') +} + impl<'a> Visitor for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { if !self.context.cm.span_allows_unstable(attr.span) { @@ -1164,6 +1180,11 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { gate_feature_post!(&self, field_init_shorthand, field.span, "struct field shorthands are unstable"); } + if starts_with_digit(&field.ident.node.name.as_str()) { + gate_feature_post!(&self, relaxed_adts, + field.span, + "numeric fields in struct expressions are unstable"); + } } } _ => {} @@ -1190,22 +1211,14 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { pattern.span, "box pattern syntax is experimental"); } - PatKind::Tuple(_, ddpos) - if ddpos.is_some() => { - gate_feature_post!(&self, dotdot_in_tuple_patterns, - pattern.span, - "`..` in tuple patterns is experimental"); - } - PatKind::TupleStruct(_, ref fields, ddpos) - if ddpos.is_some() && !fields.is_empty() => { - gate_feature_post!(&self, dotdot_in_tuple_patterns, - pattern.span, - "`..` in tuple struct patterns is experimental"); - } - PatKind::TupleStruct(_, ref fields, ddpos) - if ddpos.is_none() && fields.is_empty() => { - gate_feature_post!(&self, relaxed_adts, pattern.span, - "empty tuple structs patterns are unstable"); + PatKind::Struct(_, ref fields, _) => { + for field in fields { + if starts_with_digit(&field.node.ident.name.as_str()) { + gate_feature_post!(&self, relaxed_adts, + field.span, + "numeric fields in struct patterns are unstable"); + } + } } _ => {} } @@ -1215,12 +1228,11 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { fn visit_fn(&mut self, fn_kind: FnKind, fn_decl: &ast::FnDecl, - block: &ast::Block, span: Span, _node_id: NodeId) { // check for const fn declarations match fn_kind { - FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _) => { + FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => { gate_feature_post!(&self, const_fn, span, "const fn is unstable"); } _ => { @@ -1232,13 +1244,13 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { } match fn_kind { - FnKind::ItemFn(_, _, _, _, abi, _) | - FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => { + FnKind::ItemFn(_, _, _, _, abi, _, _) | + FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => { self.check_abi(abi, span); } _ => {} } - visit::walk_fn(self, fn_kind, fn_decl, block, span); + visit::walk_fn(self, fn_kind, fn_decl, span); } fn visit_trait_item(&mut self, ti: &ast::TraitItem) { @@ -1288,19 +1300,6 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { visit::walk_impl_item(self, ii); } - fn visit_variant_data(&mut self, vdata: &ast::VariantData, _: ast::Ident, - _: &ast::Generics, _: NodeId, span: Span) { - if vdata.fields().is_empty() { - if vdata.is_tuple() { - gate_feature_post!(&self, relaxed_adts, span, - "empty tuple structs and enum variants are unstable, \ - use unit structs and enum variants instead"); - } - } - - visit::walk_struct_def(self, vdata) - } - fn visit_vis(&mut self, vis: &ast::Visibility) { let span = match *vis { ast::Visibility::Crate(span) => span, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4bf6e55d6743..2e62f23578d8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -576,7 +576,13 @@ pub fn noop_fold_token(t: token::Token, fld: &mut T) -> token::Token match t { token::Ident(id) => token::Ident(fld.fold_ident(id)), token::Lifetime(id) => token::Lifetime(fld.fold_ident(id)), - token::Interpolated(nt) => token::Interpolated(fld.fold_interpolated(nt)), + token::Interpolated(nt) => { + let nt = match Rc::try_unwrap(nt) { + Ok(nt) => nt, + Err(nt) => (*nt).clone(), + }; + token::Interpolated(Rc::new(fld.fold_interpolated(nt))) + } token::SubstNt(ident) => token::SubstNt(fld.fold_ident(ident)), token::MatchNt(name, kind) => token::MatchNt(fld.fold_ident(name), fld.fold_ident(kind)), _ => t @@ -614,26 +620,25 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) .expect_one("expected fold to produce exactly one item")), token::NtBlock(block) => token::NtBlock(fld.fold_block(block)), token::NtStmt(stmt) => - token::NtStmt(stmt.map(|stmt| fld.fold_stmt(stmt) + token::NtStmt(fld.fold_stmt(stmt) // this is probably okay, because the only folds likely // to peek inside interpolated nodes will be renamings/markings, // which map single items to single items - .expect_one("expected fold to produce exactly one statement"))), + .expect_one("expected fold to produce exactly one statement")), token::NtPat(pat) => token::NtPat(fld.fold_pat(pat)), token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)), token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)), - token::NtIdent(id) => - token::NtIdent(Box::new(Spanned::{node: fld.fold_ident(id.node), ..*id})), + token::NtIdent(id) => token::NtIdent(Spanned::{node: fld.fold_ident(id.node), ..id}), token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)), - token::NtPath(path) => token::NtPath(Box::new(fld.fold_path(*path))), - token::NtTT(tt) => token::NtTT(P(fld.fold_tt(&tt))), + token::NtPath(path) => token::NtPath(fld.fold_path(path)), + token::NtTT(tt) => token::NtTT(fld.fold_tt(&tt)), token::NtArm(arm) => token::NtArm(fld.fold_arm(arm)), - token::NtImplItem(arm) => - token::NtImplItem(arm.map(|arm| fld.fold_impl_item(arm) - .expect_one("expected fold to produce exactly one item"))), - token::NtTraitItem(arm) => - token::NtTraitItem(arm.map(|arm| fld.fold_trait_item(arm) - .expect_one("expected fold to produce exactly one item"))), + token::NtImplItem(item) => + token::NtImplItem(fld.fold_impl_item(item) + .expect_one("expected fold to produce exactly one item")), + token::NtTraitItem(item) => + token::NtTraitItem(fld.fold_trait_item(item) + .expect_one("expected fold to produce exactly one item")), token::NtGenerics(generics) => token::NtGenerics(fld.fold_generics(generics)), token::NtWhereClause(where_clause) => token::NtWhereClause(fld.fold_where_clause(where_clause)), @@ -1196,7 +1201,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Closure(capture_clause, decl, body, span) => { ExprKind::Closure(capture_clause, folder.fold_fn_decl(decl), - folder.fold_block(body), + folder.fold_expr(body), folder.new_span(span)) } ExprKind::Block(blk) => ExprKind::Block(folder.fold_block(blk)), @@ -1244,36 +1249,22 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu folder.fold_ident(label.node))) ), ExprKind::Ret(e) => ExprKind::Ret(e.map(|x| folder.fold_expr(x))), - ExprKind::InlineAsm(InlineAsm { - inputs, - outputs, - asm, - asm_str_style, - clobbers, - volatile, - alignstack, - dialect, - expn_id, - }) => ExprKind::InlineAsm(InlineAsm { - inputs: inputs.move_map(|(c, input)| { - (c, folder.fold_expr(input)) - }), - outputs: outputs.move_map(|out| { - InlineAsmOutput { - constraint: out.constraint, - expr: folder.fold_expr(out.expr), - is_rw: out.is_rw, - is_indirect: out.is_indirect, - } - }), - asm: asm, - asm_str_style: asm_str_style, - clobbers: clobbers, - volatile: volatile, - alignstack: alignstack, - dialect: dialect, - expn_id: expn_id, - }), + ExprKind::InlineAsm(asm) => ExprKind::InlineAsm(asm.map(|asm| { + InlineAsm { + inputs: asm.inputs.move_map(|(c, input)| { + (c, folder.fold_expr(input)) + }), + outputs: asm.outputs.move_map(|out| { + InlineAsmOutput { + constraint: out.constraint, + expr: folder.fold_expr(out.expr), + is_rw: out.is_rw, + is_indirect: out.is_indirect, + } + }), + ..asm + } + })), ExprKind::Mac(mac) => ExprKind::Mac(folder.fold_mac(mac)), ExprKind::Struct(path, fields, maybe_expr) => { ExprKind::Struct(folder.fold_path(path), diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index b86e508d8997..feed400897c0 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -34,7 +34,7 @@ #![cfg_attr(stage0, feature(question_mark))] #![feature(rustc_diagnostic_macros)] #![feature(specialization)] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] extern crate core; extern crate serialize; diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 3cb34fa3c91c..983c882eafca 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -215,7 +215,10 @@ impl<'a> Parser<'a> { /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, P> { let nt_meta = match self.token { - token::Interpolated(token::NtMeta(ref e)) => Some(e.clone()), + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref e) => Some(e.clone()), + _ => None, + }, _ => None, }; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 5e20f6e41927..cf48c445c80e 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -22,7 +22,7 @@ use std::char; use std::mem::replace; use std::rc::Rc; -pub use ext::tt::transcribe::{TtReader, new_tt_reader, new_tt_reader_with_doc_flag}; +pub use ext::tt::transcribe::{TtReader, new_tt_reader}; pub mod comments; mod unicode_chars; @@ -171,31 +171,10 @@ impl<'a> Reader for TtReader<'a> { self.fatal_errs.clear(); } fn peek(&self) -> TokenAndSpan { - self.next_tok.clone().unwrap_or(TokenAndSpan { + TokenAndSpan { tok: self.cur_tok.clone(), sp: self.cur_span, - }) - } -} - -impl<'a, 'b> Reader for &'b mut TtReader<'a> { - fn is_eof(&self) -> bool { - (**self).is_eof() - } - fn try_next_token(&mut self) -> Result { - (**self).try_next_token() - } - fn fatal(&self, m: &str) -> FatalError { - (**self).fatal(m) - } - fn err(&self, m: &str) { - (**self).err(m) - } - fn emit_fatal_errors(&mut self) { - (**self).emit_fatal_errors() - } - fn peek(&self) -> TokenAndSpan { - (**self).peek() + } } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b80aa667be6a..7d15334ff9f4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -107,125 +107,41 @@ pub enum SemiColonMode { /// be. The important thing is to make sure that lookahead doesn't balk at /// `token::Interpolated` tokens. macro_rules! maybe_whole_expr { - ($p:expr) => ( - { - let found = match $p.token { - token::Interpolated(token::NtExpr(ref e)) => { - Some((*e).clone()) - } - token::Interpolated(token::NtPath(_)) => { - // FIXME: The following avoids an issue with lexical borrowck scopes, - // but the clone is unfortunate. - let pt = match $p.token { - token::Interpolated(token::NtPath(ref pt)) => (**pt).clone(), - _ => unreachable!() - }; - let span = $p.span; - Some($p.mk_expr(span.lo, span.hi, ExprKind::Path(None, pt), ThinVec::new())) - } - token::Interpolated(token::NtBlock(_)) => { - // FIXME: The following avoids an issue with lexical borrowck scopes, - // but the clone is unfortunate. - let b = match $p.token { - token::Interpolated(token::NtBlock(ref b)) => (*b).clone(), - _ => unreachable!() - }; - let span = $p.span; - Some($p.mk_expr(span.lo, span.hi, ExprKind::Block(b), ThinVec::new())) - } - _ => None - }; - match found { - Some(e) => { + ($p:expr) => { + if let token::Interpolated(nt) = $p.token.clone() { + match *nt { + token::NtExpr(ref e) => { $p.bump(); - return Ok(e); + return Ok((*e).clone()); } - None => () - } + token::NtPath(ref path) => { + $p.bump(); + let span = $p.span; + let kind = ExprKind::Path(None, (*path).clone()); + return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); + } + token::NtBlock(ref block) => { + $p.bump(); + let span = $p.span; + let kind = ExprKind::Block((*block).clone()); + return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); + } + _ => {}, + }; } - ) + } } /// As maybe_whole_expr, but for things other than expressions macro_rules! maybe_whole { - ($p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok(x.clone()); + ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { + if let token::Interpolated(nt) = $p.token.clone() { + if let token::$constructor($x) = (*nt).clone() { + $p.bump(); + return Ok($e); } } - ); - (no_clone $p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok(x); - } - } - ); - (no_clone_from_p $p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok(x.unwrap()); - } - } - ); - (deref $p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok((*x).clone()); - } - } - ); - (Some deref $p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok(Some((*x).clone())); - } - } - ); - (pair_empty $p:expr, $constructor:ident) => ( - { - let found = match ($p).token { - token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) - } - _ => None - }; - if let Some(token::Interpolated(token::$constructor(x))) = found { - return Ok((Vec::new(), x)); - } - } - ) + }; } fn maybe_append(mut lhs: Vec, rhs: Option>) @@ -294,6 +210,9 @@ pub struct Parser<'a> { /// into modules, and sub-parsers have new values for this name. pub root_module_name: Option, pub expected_tokens: Vec, + pub tts: Vec<(TokenTree, usize)>, + pub desugar_doc_comments: bool, + pub allow_interpolated_tts: bool, } #[derive(PartialEq, Eq, Clone)] @@ -357,21 +276,18 @@ impl From> for LhsExpr { } impl<'a> Parser<'a> { - pub fn new(sess: &'a ParseSess, mut rdr: Box) -> Self { - let tok0 = rdr.real_token(); - let span = tok0.sp; - let mut directory = match span { - syntax_pos::DUMMY_SP => PathBuf::new(), - _ => PathBuf::from(sess.codemap().span_to_filename(span)), - }; - directory.pop(); + pub fn new(sess: &'a ParseSess, rdr: Box) -> Self { + Parser::new_with_doc_flag(sess, rdr, false) + } - Parser { + pub fn new_with_doc_flag(sess: &'a ParseSess, rdr: Box, desugar_doc_comments: bool) + -> Self { + let mut parser = Parser { reader: rdr, sess: sess, - token: tok0.tok, - span: span, - prev_span: span, + token: token::Underscore, + span: syntax_pos::DUMMY_SP, + prev_span: syntax_pos::DUMMY_SP, prev_token_kind: PrevTokenKind::Other, lookahead_buffer: Default::default(), tokens_consumed: 0, @@ -379,11 +295,63 @@ impl<'a> Parser<'a> { quote_depth: 0, parsing_token_tree: false, obsolete_set: HashSet::new(), - directory: directory, + directory: PathBuf::new(), open_braces: Vec::new(), owns_directory: true, root_module_name: None, expected_tokens: Vec::new(), + tts: Vec::new(), + desugar_doc_comments: desugar_doc_comments, + allow_interpolated_tts: true, + }; + + let tok = parser.next_tok(); + parser.token = tok.tok; + parser.span = tok.sp; + if parser.span != syntax_pos::DUMMY_SP { + parser.directory = PathBuf::from(sess.codemap().span_to_filename(parser.span)); + parser.directory.pop(); + } + parser + } + + fn next_tok(&mut self) -> TokenAndSpan { + 'outer: loop { + let mut tok = if let Some((tts, i)) = self.tts.pop() { + let tt = tts.get_tt(i); + if i + 1 < tts.len() { + self.tts.push((tts, i + 1)); + } + if let TokenTree::Token(sp, tok) = tt { + TokenAndSpan { tok: tok, sp: sp } + } else { + self.tts.push((tt, 0)); + continue + } + } else { + self.reader.real_token() + }; + + loop { + let nt = match tok.tok { + token::Interpolated(ref nt) => nt.clone(), + token::DocComment(name) if self.desugar_doc_comments => { + self.tts.push((TokenTree::Token(tok.sp, token::DocComment(name)), 0)); + continue 'outer + } + _ => return tok, + }; + match *nt { + token::NtTT(TokenTree::Token(sp, ref t)) => { + tok = TokenAndSpan { tok: t.clone(), sp: sp }; + } + token::NtTT(ref tt) => { + self.tts.push((tt.clone(), 0)); + continue 'outer + } + _ => return tok, + } + } } } @@ -516,9 +484,6 @@ impl<'a> Parser<'a> { self.bump(); Ok(i) } - token::Interpolated(token::NtIdent(..)) => { - self.bug("ident interpolation not converted to real token"); - } _ => { Err(if self.prev_token_kind == PrevTokenKind::DocComment { self.span_fatal_help(self.prev_span, @@ -935,7 +900,7 @@ impl<'a> Parser<'a> { }; let next = if self.lookahead_buffer.start == self.lookahead_buffer.end { - self.reader.real_token() + self.next_tok() } else { // Avoid token copies with `replace`. let old_start = self.lookahead_buffer.start; @@ -980,7 +945,7 @@ impl<'a> Parser<'a> { f(&self.token) } else if dist < LOOKAHEAD_BUFFER_CAPACITY { while self.lookahead_buffer.len() < dist { - self.lookahead_buffer.buffer[self.lookahead_buffer.end] = self.reader.real_token(); + self.lookahead_buffer.buffer[self.lookahead_buffer.end] = self.next_tok(); self.lookahead_buffer.end = (self.lookahead_buffer.end + 1) % LOOKAHEAD_BUFFER_CAPACITY; } @@ -1162,7 +1127,7 @@ impl<'a> Parser<'a> { /// Parse the items in a trait declaration pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> { - maybe_whole!(no_clone_from_p self, NtTraitItem); + maybe_whole!(self, NtTraitItem, |x| x); let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; @@ -1331,7 +1296,7 @@ impl<'a> Parser<'a> { /// Parse a type. pub fn parse_ty(&mut self) -> PResult<'a, P> { - maybe_whole!(no_clone self, NtTy); + maybe_whole!(self, NtTy, |x| x); let lo = self.span.lo; @@ -1476,7 +1441,7 @@ impl<'a> Parser<'a> { /// This version of parse arg doesn't necessarily require /// identifier names. pub fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> { - maybe_whole!(no_clone self, NtArg); + maybe_whole!(self, NtArg, |x| x); let pat = if require_name || self.is_named_argument() { debug!("parse_arg_general parse_pat (require_name:{})", @@ -1542,12 +1507,13 @@ impl<'a> Parser<'a> { /// Matches token_lit = LIT_INTEGER | ... pub fn parse_lit_token(&mut self) -> PResult<'a, LitKind> { let out = match self.token { - token::Interpolated(token::NtExpr(ref v)) => { - match v.node { + token::Interpolated(ref nt) => match **nt { + token::NtExpr(ref v) => match v.node { ExprKind::Lit(ref lit) => { lit.node.clone() } _ => { return self.unexpected_last(&self.token); } - } - } + }, + _ => { return self.unexpected_last(&self.token); } + }, token::Literal(lit, suf) => { let (suffix_illegal, out) = match lit { token::Byte(i) => (true, LitKind::Byte(parse::byte_lit(&i.as_str()).0)), @@ -1703,14 +1669,7 @@ impl<'a> Parser<'a> { /// bounds are permitted and whether `::` must precede type parameter /// groups. pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { - // Check for a whole path... - let found = match self.token { - token::Interpolated(token::NtPath(_)) => Some(self.bump_and_get()), - _ => None, - }; - if let Some(token::Interpolated(token::NtPath(path))) = found { - return Ok(*path); - } + maybe_whole!(self, NtPath, |x| x); let lo = self.span.lo; let is_global = self.eat(&token::ModSep); @@ -2746,8 +2705,6 @@ impl<'a> Parser<'a> { // and token::SubstNt's; it's too early to know yet // whether something will be a nonterminal or a seq // yet. - maybe_whole!(deref self, NtTT); - match self.token { token::Eof => { let mut err: DiagnosticBuilder<'a> = @@ -2760,6 +2717,17 @@ impl<'a> Parser<'a> { Err(err) }, token::OpenDelim(delim) => { + if self.tts.last().map(|&(_, i)| i == 1).unwrap_or(false) { + let tt = self.tts.pop().unwrap().0; + self.bump(); + return Ok(if self.allow_interpolated_tts { + // avoid needlessly reparsing token trees in recursive macro expansions + TokenTree::Token(tt.span(), token::Interpolated(Rc::new(token::NtTT(tt)))) + } else { + tt + }); + } + let parsing_token_tree = ::std::mem::replace(&mut self.parsing_token_tree, true); // The span for beginning of the delimited section let pre_span = self.span; @@ -2833,29 +2801,20 @@ impl<'a> Parser<'a> { close_span: close_span, }))) }, + token::CloseDelim(_) => { + // An unexpected closing delimiter (i.e., there is no + // matching opening delimiter). + let token_str = self.this_token_to_string(); + let err = self.diagnostic().struct_span_err(self.span, + &format!("unexpected close delimiter: `{}`", token_str)); + Err(err) + }, + /* we ought to allow different depths of unquotation */ + token::Dollar | token::SubstNt(..) if self.quote_depth > 0 => { + self.parse_unquoted() + } _ => { - // invariants: the current token is not a left-delimiter, - // not an EOF, and not the desired right-delimiter (if - // it were, parse_seq_to_before_end would have prevented - // reaching this point). - maybe_whole!(deref self, NtTT); - match self.token { - token::CloseDelim(_) => { - // An unexpected closing delimiter (i.e., there is no - // matching opening delimiter). - let token_str = self.this_token_to_string(); - let err = self.diagnostic().struct_span_err(self.span, - &format!("unexpected close delimiter: `{}`", token_str)); - Err(err) - }, - /* we ought to allow different depths of unquotation */ - token::Dollar | token::SubstNt(..) if self.quote_depth > 0 => { - self.parse_unquoted() - } - _ => { - Ok(TokenTree::Token(self.span, self.bump_and_get())) - } - } + Ok(TokenTree::Token(self.span, self.bump_and_get())) } } } @@ -3203,25 +3162,12 @@ impl<'a> Parser<'a> { let decl = self.parse_fn_block_decl()?; let decl_hi = self.prev_span.hi; let body = match decl.output { - FunctionRetTy::Default(_) => { - // If no explicit return type is given, parse any - // expr and wrap it up in a dummy block: - let body_expr = self.parse_expr()?; - P(ast::Block { - id: ast::DUMMY_NODE_ID, - span: body_expr.span, - stmts: vec![Stmt { - span: body_expr.span, - node: StmtKind::Expr(body_expr), - id: ast::DUMMY_NODE_ID, - }], - rules: BlockCheckMode::Default, - }) - } + FunctionRetTy::Default(_) => self.parse_expr()?, _ => { // If an explicit return type is given, require a // block to appear (RFC 968). - self.parse_block()? + let body_lo = self.span.lo; + self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())? } }; @@ -3336,7 +3282,7 @@ impl<'a> Parser<'a> { } pub fn parse_arm(&mut self) -> PResult<'a, Arm> { - maybe_whole!(no_clone self, NtArm); + maybe_whole!(self, NtArm, |x| x); let attrs = self.parse_outer_attributes()?; let pats = self.parse_pats()?; @@ -3592,7 +3538,7 @@ impl<'a> Parser<'a> { /// Parse a pattern. pub fn parse_pat(&mut self) -> PResult<'a, P> { - maybe_whole!(self, NtPat); + maybe_whole!(self, NtPat, |x| x); let lo = self.span.lo; let pat; @@ -3897,7 +3843,7 @@ impl<'a> Parser<'a> { fn parse_stmt_without_recovery(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option> { - maybe_whole!(Some deref self, NtStmt); + maybe_whole!(self, NtStmt, |x| Some(x)); let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; @@ -4086,7 +4032,7 @@ impl<'a> Parser<'a> { /// Parse a block. No inner attrs are allowed. pub fn parse_block(&mut self) -> PResult<'a, P> { - maybe_whole!(no_clone self, NtBlock); + maybe_whole!(self, NtBlock, |x| x); let lo = self.span.lo; @@ -4124,7 +4070,7 @@ impl<'a> Parser<'a> { /// Parse a block. Inner attrs are allowed. fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec, P)> { - maybe_whole!(pair_empty self, NtBlock); + maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); let lo = self.span.lo; self.expect(&token::OpenDelim(token::Brace))?; @@ -4299,7 +4245,7 @@ impl<'a> Parser<'a> { /// | ( < lifetimes , typaramseq ( , )? > ) /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { - maybe_whole!(self, NtGenerics); + maybe_whole!(self, NtGenerics, |x| x); let span_lo = self.span.lo; if self.eat(&token::Lt) { @@ -4440,7 +4386,7 @@ impl<'a> Parser<'a> { /// where T : Trait + 'b, 'a : 'b /// ``` pub fn parse_where_clause(&mut self) -> PResult<'a, ast::WhereClause> { - maybe_whole!(self, NtWhereClause); + maybe_whole!(self, NtWhereClause, |x| x); let mut where_clause = WhereClause { id: ast::DUMMY_NODE_ID, @@ -4848,7 +4794,7 @@ impl<'a> Parser<'a> { /// Parse an impl item. pub fn parse_impl_item(&mut self) -> PResult<'a, ImplItem> { - maybe_whole!(no_clone_from_p self, NtImplItem); + maybe_whole!(self, NtImplItem, |x| x); let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; @@ -5716,19 +5662,13 @@ impl<'a> Parser<'a> { /// extern crate. fn parse_item_(&mut self, attrs: Vec, macros_allowed: bool, attributes_allowed: bool) -> PResult<'a, Option>> { - let nt_item = match self.token { - token::Interpolated(token::NtItem(ref item)) => { - Some((**item).clone()) - } - _ => None - }; - if let Some(mut item) = nt_item { - self.bump(); + maybe_whole!(self, NtItem, |item| { + let mut item = item.unwrap(); let mut attrs = attrs; mem::swap(&mut item.attrs, &mut attrs); item.attrs.extend(attrs); - return Ok(Some(P(item))); - } + Some(P(item)) + }); let lo = self.span.lo; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 4d0da660302a..0198ee073d23 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -123,7 +123,7 @@ pub enum Token { Lifetime(ast::Ident), /* For interpolation */ - Interpolated(Nonterminal), + Interpolated(Rc), // Can be expanded into several tokens. /// Doc comment DocComment(ast::Name), @@ -172,12 +172,15 @@ impl Token { DotDot | DotDotDot => true, // range notation Lt | BinOp(Shl) => true, // associated path ModSep => true, - Interpolated(NtExpr(..)) => true, - Interpolated(NtIdent(..)) => true, - Interpolated(NtBlock(..)) => true, - Interpolated(NtPath(..)) => true, Pound => true, // for expression attributes - _ => false, + Interpolated(ref nt) => match **nt { + NtExpr(..) => true, + NtIdent(..) => true, + NtBlock(..) => true, + NtPath(..) => true, + _ => false, + }, + _ => false, } } @@ -215,10 +218,12 @@ impl Token { /// Returns `true` if the token is an interpolated path. pub fn is_path(&self) -> bool { - match *self { - Interpolated(NtPath(..)) => true, - _ => false, + if let Interpolated(ref nt) = *self { + if let NtPath(..) = **nt { + return true; + } } + false } /// Returns `true` if the token is a lifetime. @@ -290,19 +295,19 @@ impl Token { pub enum Nonterminal { NtItem(P), NtBlock(P), - NtStmt(P), + NtStmt(ast::Stmt), NtPat(P), NtExpr(P), NtTy(P), - NtIdent(Box), + NtIdent(ast::SpannedIdent), /// Stuff inside brackets for attributes NtMeta(P), - NtPath(Box), - NtTT(P), // needs P'ed to break a circularity + NtPath(ast::Path), + NtTT(tokenstream::TokenTree), // These are not exposed to macros, but are used by quasiquote. NtArm(ast::Arm), - NtImplItem(P), - NtTraitItem(P), + NtImplItem(ast::ImplItem), + NtTraitItem(ast::TraitItem), NtGenerics(ast::Generics), NtWhereClause(ast::WhereClause), NtArg(ast::Arg), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b0bd64467430..203c19285ac2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -285,7 +285,7 @@ pub fn token_to_string(tok: &Token) -> String { token::Comment => "/* */".to_string(), token::Shebang(s) => format!("/* shebang: {}*/", s), - token::Interpolated(ref nt) => match *nt { + token::Interpolated(ref nt) => match **nt { token::NtExpr(ref e) => expr_to_string(&e), token::NtMeta(ref e) => meta_item_to_string(&e), token::NtTy(ref e) => ty_to_string(&e), @@ -2128,26 +2128,8 @@ impl<'a> State<'a> { try!(self.print_fn_block_args(&decl)); try!(space(&mut self.s)); - - let default_return = match decl.output { - ast::FunctionRetTy::Default(..) => true, - _ => false - }; - - match body.stmts.last().map(|stmt| &stmt.node) { - Some(&ast::StmtKind::Expr(ref i_expr)) if default_return && - body.stmts.len() == 1 => { - // we extract the block, so as not to create another set of boxes - if let ast::ExprKind::Block(ref blk) = i_expr.node { - try!(self.print_block_unclosed_with_attrs(&blk, &i_expr.attrs)); - } else { - // this is a bare expression - try!(self.print_expr(&i_expr)); - try!(self.end()); // need to close a box - } - } - _ => try!(self.print_block_unclosed(&body)), - } + try!(self.print_expr(body)); + try!(self.end()); // need to close a box // a box will be closed by print_expr, but we didn't want an overall // wrapper so we closed the corresponding opening. so create an diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 9e644e59e86a..9ef6c07e489d 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -134,8 +134,10 @@ impl TokenTree { AttrStyle::Inner => 3, } } + TokenTree::Token(_, token::Interpolated(ref nt)) => { + if let Nonterminal::NtTT(..) = **nt { 1 } else { 0 } + }, TokenTree::Token(_, token::MatchNt(..)) => 3, - TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(..))) => 1, TokenTree::Delimited(_, ref delimed) => delimed.tts.len() + 2, TokenTree::Sequence(_, ref seq) => seq.tts.len(), TokenTree::Token(..) => 0, @@ -193,9 +195,6 @@ impl TokenTree { TokenTree::Token(sp, token::Ident(kind))]; v[index].clone() } - (&TokenTree::Token(_, token::Interpolated(Nonterminal::NtTT(ref tt))), _) => { - tt.clone().unwrap() - } (&TokenTree::Sequence(_, ref seq), _) => seq.tts[index].clone(), _ => panic!("Cannot expand a token tree"), } @@ -215,11 +214,9 @@ impl TokenTree { mtch: &[TokenTree], tts: &[TokenTree]) -> macro_parser::NamedParseResult { + let diag = &cx.parse_sess().span_diagnostic; // `None` is because we're not interpolating - let arg_rdr = lexer::new_tt_reader_with_doc_flag(&cx.parse_sess().span_diagnostic, - None, - tts.iter().cloned().collect(), - true); + let arg_rdr = lexer::new_tt_reader(diag, None, tts.iter().cloned().collect()); macro_parser::parse(cx.parse_sess(), arg_rdr, mtch) } diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index 14244bbdddf2..a1f07381db70 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -75,9 +75,9 @@ impl Visitor for NodeCounter { self.count += 1; walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId) { + fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, s: Span, _: NodeId) { self.count += 1; - walk_fn(self, fk, fd, b, s) + walk_fn(self, fk, fd, s) } fn visit_trait_item(&mut self, ti: &TraitItem) { self.count += 1; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 7fb3e5c6bee1..7c1ff617ab64 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -31,13 +31,13 @@ use codemap::Spanned; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - ItemFn(Ident, &'a Generics, Unsafety, Spanned, Abi, &'a Visibility), + ItemFn(Ident, &'a Generics, Unsafety, Spanned, Abi, &'a Visibility, &'a Block), /// fn foo(&self) - Method(Ident, &'a MethodSig, Option<&'a Visibility>), + Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block), - /// |x, y| {} - Closure, + /// |x, y| body + Closure(&'a Expr), } /// Each method of the Visitor trait is a hook to be potentially @@ -68,8 +68,8 @@ pub trait Visitor: Sized { fn visit_expr_post(&mut self, _ex: &Expr) { } fn visit_ty(&mut self, t: &Ty) { walk_ty(self, t) } fn visit_generics(&mut self, g: &Generics) { walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId) { - walk_fn(self, fk, fd, b, s) + fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, s: Span, _: NodeId) { + walk_fn(self, fk, fd, s) } fn visit_trait_item(&mut self, ti: &TraitItem) { walk_trait_item(self, ti) } fn visit_impl_item(&mut self, ii: &ImplItem) { walk_impl_item(self, ii) } @@ -246,9 +246,8 @@ pub fn walk_item(visitor: &mut V, item: &Item) { } ItemKind::Fn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { visitor.visit_fn(FnKind::ItemFn(item.ident, generics, unsafety, - constness, abi, &item.vis), + constness, abi, &item.vis, body), declaration, - body, item.span, item.id) } @@ -519,24 +518,25 @@ pub fn walk_fn_decl(visitor: &mut V, function_declaration: &FnDecl) visitor.visit_fn_ret_ty(&function_declaration.output) } -pub fn walk_fn_kind(visitor: &mut V, function_kind: FnKind) { - match function_kind { - FnKind::ItemFn(_, generics, _, _, _, _) => { - visitor.visit_generics(generics); - } - FnKind::Method(_, ref sig, _) => { - visitor.visit_generics(&sig.generics); - } - FnKind::Closure => {} - } -} - -pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, body: &Block, _span: Span) +pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, _span: Span) where V: Visitor, { - walk_fn_kind(visitor, kind); - walk_fn_decl(visitor, declaration); - visitor.visit_block(body) + match kind { + FnKind::ItemFn(_, generics, _, _, _, _, body) => { + visitor.visit_generics(generics); + walk_fn_decl(visitor, declaration); + visitor.visit_block(body); + } + FnKind::Method(_, ref sig, _, body) => { + visitor.visit_generics(&sig.generics); + walk_fn_decl(visitor, declaration); + visitor.visit_block(body); + } + FnKind::Closure(body) => { + walk_fn_decl(visitor, declaration); + visitor.visit_expr(body); + } + } } pub fn walk_trait_item(visitor: &mut V, trait_item: &TraitItem) { @@ -552,8 +552,8 @@ pub fn walk_trait_item(visitor: &mut V, trait_item: &TraitItem) { walk_fn_decl(visitor, &sig.decl); } TraitItemKind::Method(ref sig, Some(ref body)) => { - visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None), &sig.decl, - body, trait_item.span, trait_item.id); + visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None, body), + &sig.decl, trait_item.span, trait_item.id); } TraitItemKind::Type(ref bounds, ref default) => { walk_list!(visitor, visit_ty_param_bound, bounds); @@ -575,8 +575,8 @@ pub fn walk_impl_item(visitor: &mut V, impl_item: &ImplItem) { visitor.visit_expr(expr); } ImplItemKind::Method(ref sig, ref body) => { - visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis)), &sig.decl, - body, impl_item.span, impl_item.id); + visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis), body), + &sig.decl, impl_item.span, impl_item.id); } ImplItemKind::Type(ref ty) => { visitor.visit_ty(ty); @@ -711,9 +711,8 @@ pub fn walk_expr(visitor: &mut V, expression: &Expr) { walk_list!(visitor, visit_arm, arms); } ExprKind::Closure(_, ref function_declaration, ref body, _decl_span) => { - visitor.visit_fn(FnKind::Closure, + visitor.visit_fn(FnKind::Closure(body), function_declaration, - body, expression.span, expression.id) } diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 24c515e50280..e4d0cb740460 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -250,7 +250,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::InlineAsm(ast::InlineAsm { + node: ast::ExprKind::InlineAsm(P(ast::InlineAsm { asm: token::intern_and_get_ident(&asm), asm_str_style: asm_str_style.unwrap(), outputs: outputs, @@ -260,7 +260,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, alignstack: alignstack, dialect: dialect, expn_id: expn_id, - }), + })), span: sp, attrs: ast::ThinVec::new(), })) diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index f8cb1294a666..e101757ad232 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -12,20 +12,35 @@ use std::panic; use errors::FatalError; use proc_macro::{TokenStream, __internal}; -use syntax::ast::{self, ItemKind}; -use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan, Span}; +use syntax::ast::{self, ItemKind, Attribute}; +use syntax::attr::{mark_used, mark_known}; +use syntax::codemap::Span; use syntax::ext::base::*; use syntax::fold::Folder; -use syntax::parse::token::intern; -use syntax::print::pprust; +use syntax::parse::token::InternedString; +use syntax::visit::Visitor; + +struct MarkAttrs<'a>(&'a [InternedString]); + +impl<'a> Visitor for MarkAttrs<'a> { + fn visit_attribute(&mut self, attr: &Attribute) { + if self.0.contains(&attr.name()) { + mark_used(attr); + mark_known(attr); + } + } +} pub struct CustomDerive { inner: fn(TokenStream) -> TokenStream, + attrs: Vec, } impl CustomDerive { - pub fn new(inner: fn(TokenStream) -> TokenStream) -> CustomDerive { - CustomDerive { inner: inner } + pub fn new(inner: fn(TokenStream) -> TokenStream, + attrs: Vec) + -> CustomDerive { + CustomDerive { inner: inner, attrs: attrs } } } @@ -33,7 +48,7 @@ impl MultiItemModifier for CustomDerive { fn expand(&self, ecx: &mut ExtCtxt, span: Span, - meta_item: &ast::MetaItem, + _meta_item: &ast::MetaItem, item: Annotatable) -> Vec { let item = match item { @@ -47,7 +62,7 @@ impl MultiItemModifier for CustomDerive { }; match item.node { ItemKind::Struct(..) | - ItemKind::Enum(..) => {} + ItemKind::Enum(..) => {}, _ => { ecx.span_err(span, "custom derive attributes may only be \ applied to struct/enum items"); @@ -55,23 +70,15 @@ impl MultiItemModifier for CustomDerive { } } - let input_span = Span { - expn_id: ecx.codemap().record_expansion(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroAttribute(intern(&pprust::meta_item_to_string(meta_item))), - span: Some(span), - allow_internal_unstable: true, - }, - }), - ..item.span - }; - let input = __internal::new_token_stream(item); + // Mark attributes as known, and used. + MarkAttrs(&self.attrs).visit_item(&item); + + let input = __internal::new_token_stream(ecx.resolver.eliminate_crate_var(item.clone())); let res = __internal::set_parse_sess(&ecx.parse_sess, || { let inner = self.inner; panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input))) }); - let item = match res { + let new_items = match res { Ok(stream) => __internal::token_stream_items(stream), Err(e) => { let msg = "custom derive attribute panicked"; @@ -88,12 +95,13 @@ impl MultiItemModifier for CustomDerive { } }; - // Right now we have no knowledge of spans at all in custom derive - // macros, everything is just parsed as a string. Reassign all spans to - // the input `item` for better errors here. - item.into_iter().flat_map(|item| { - ChangeSpan { span: input_span }.fold_item(item) - }).map(Annotatable::Item).collect() + let mut res = vec![Annotatable::Item(item)]; + // Reassign spans of all expanded items to the input `item` + // for better errors here. + res.extend(new_items.into_iter().flat_map(|item| { + ChangeSpan { span: span }.fold_item(item) + }).map(Annotatable::Item)); + res } } diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 10db56d46f6d..dc1f7b4e6201 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -133,7 +133,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, cx.ident_of("read_struct"), vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), cx.expr_usize(trait_span, nfields), - cx.lambda_expr_1(trait_span, result, blkarg)]) + cx.lambda1(trait_span, result, blkarg)]) } StaticEnum(_, ref fields) => { let variant = cx.ident_of("i"); @@ -165,7 +165,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, let result = cx.expr_ok(trait_span, cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms)); - let lambda = cx.lambda_expr(trait_span, vec![blkarg, variant], result); + let lambda = cx.lambda(trait_span, vec![blkarg, variant], result); let variant_vec = cx.expr_vec(trait_span, variants); let variant_vec = cx.expr_addr_of(trait_span, variant_vec); let result = cx.expr_method_call(trait_span, @@ -176,7 +176,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, decoder, cx.ident_of("read_enum"), vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.lambda_expr_1(trait_span, result, blkarg)]) + cx.lambda1(trait_span, result, blkarg)]) } _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"), }; diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 640296d7f06f..ebbddc6e4808 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -197,7 +197,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, }; let self_ref = cx.expr_addr_of(span, self_.clone()); let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda_expr_1(span, enc, blkarg); + let lambda = cx.lambda1(span, enc, blkarg); let call = cx.expr_method_call(span, blkencoder.clone(), emit_struct_field, @@ -246,7 +246,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, let self_ref = cx.expr_addr_of(span, self_.clone()); let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda_expr_1(span, enc, blkarg); + let lambda = cx.lambda1(span, enc, blkarg); let call = cx.expr_method_call(span, blkencoder.clone(), emit_variant_arg, @@ -273,7 +273,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, cx.expr_usize(trait_span, idx), cx.expr_usize(trait_span, fields.len()), blk]); - let blk = cx.lambda_expr_1(trait_span, call, blkarg); + let blk = cx.lambda1(trait_span, call, blkarg); let ret = cx.expr_method_call(trait_span, encoder, cx.ident_of("emit_enum"), diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index c2bfead56861..b1d473820f77 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -12,10 +12,10 @@ use syntax::ast::{self, MetaItem}; use syntax::attr::HasAttrs; +use syntax::codemap; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension}; use syntax::ext::build::AstBuilder; -use syntax::feature_gate; -use syntax::codemap; +use syntax::feature_gate::{self, emit_feature_err}; use syntax::parse::token::{intern, intern_and_get_ident}; use syntax::ptr::P; use syntax_pos::Span; @@ -220,6 +220,12 @@ pub fn expand_derive(cx: &mut ExtCtxt, .filter(|&(_, ref name)| !is_builtin_trait(&name.name().unwrap())) .next(); if let Some((i, titem)) = macros_11_derive { + if !cx.ecfg.features.unwrap().proc_macro { + let issue = feature_gate::GateIssue::Language; + let msg = "custom derive macros are experimentally supported"; + emit_feature_err(cx.parse_sess, "proc_macro", titem.span, issue, msg); + } + let tname = ast::Ident::with_empty_ctxt(intern(&titem.name().unwrap())); let path = ast::Path::from_ident(titem.span, tname); let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap(); diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index f336b26ae41f..e1542c9e466a 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -19,7 +19,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] -#![feature(dotdot_in_tuple_patterns)] +#![cfg_attr(stage0, feature(dotdot_in_tuple_patterns))] #![feature(proc_macro_lib)] #![feature(proc_macro_internals)] #![feature(rustc_private)] diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index f49a5f0e0706..d6d31200a994 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -30,6 +30,7 @@ struct CustomDerive { trait_name: InternedString, function_name: Ident, span: Span, + attrs: Vec, } struct CollectCustomDerives<'a> { @@ -105,6 +106,17 @@ impl<'a> Visitor for CollectCustomDerives<'a> { match item.node { ast::ItemKind::Fn(..) => {} _ => { + // Check for invalid use of proc_macro_derive + let attr = item.attrs.iter() + .filter(|a| a.check_name("proc_macro_derive")) + .next(); + if let Some(attr) = attr { + self.handler.span_err(attr.span(), + "the `#[proc_macro_derive]` \ + attribute may only be used \ + on bare functions"); + return; + } self.check_not_pub_in_root(&item.vis, item.span); return visit::walk_item(self, item) } @@ -133,7 +145,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> { } // Once we've located the `#[proc_macro_derive]` attribute, verify - // that it's of the form `#[proc_macro_derive(Foo)]` + // that it's of the form `#[proc_macro_derive(Foo)]` or + // `#[proc_macro_derive(Foo, attributes(A, ..))]` let list = match attr.meta_item_list() { Some(list) => list, None => { @@ -143,38 +156,69 @@ impl<'a> Visitor for CollectCustomDerives<'a> { return } }; - if list.len() != 1 { + if list.len() != 1 && list.len() != 2 { self.handler.span_err(attr.span(), - "attribute must only have one argument"); + "attribute must have either one or two arguments"); return } - let attr = &list[0]; - let trait_name = match attr.name() { + let trait_attr = &list[0]; + let attributes_attr = list.get(1); + let trait_name = match trait_attr.name() { Some(name) => name, _ => { - self.handler.span_err(attr.span(), "not a meta item"); + self.handler.span_err(trait_attr.span(), "not a meta item"); return } }; - if !attr.is_word() { - self.handler.span_err(attr.span(), "must only be one word"); + if !trait_attr.is_word() { + self.handler.span_err(trait_attr.span(), "must only be one word"); } if deriving::is_builtin_trait(&trait_name) { - self.handler.span_err(attr.span(), + self.handler.span_err(trait_attr.span(), "cannot override a built-in #[derive] mode"); } if self.derives.iter().any(|d| d.trait_name == trait_name) { - self.handler.span_err(attr.span(), + self.handler.span_err(trait_attr.span(), "derive mode defined twice in this crate"); } + let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr { + if !attr.check_name("attributes") { + self.handler.span_err(attr.span(), "second argument must be `attributes`") + } + attr.meta_item_list().unwrap_or_else(|| { + self.handler.span_err(attr.span(), + "attribute must be of form: \ + `attributes(foo, bar)`"); + &[] + }).into_iter().filter_map(|attr| { + let name = match attr.name() { + Some(name) => name, + _ => { + self.handler.span_err(attr.span(), "not a meta item"); + return None; + }, + }; + + if !attr.is_word() { + self.handler.span_err(attr.span(), "must only be one word"); + return None; + } + + Some(name) + }).collect() + } else { + Vec::new() + }; + if self.in_root { self.derives.push(CustomDerive { span: item.span, trait_name: trait_name, function_name: item.ident, + attrs: proc_attrs, }); } else { let msg = "functions tagged with `#[proc_macro_derive]` must \ @@ -208,8 +252,8 @@ impl<'a> Visitor for CollectCustomDerives<'a> { // // #[plugin_registrar] // fn registrar(registrar: &mut Registry) { -// registrar.register_custom_derive($name_trait1, ::$name1); -// registrar.register_custom_derive($name_trait2, ::$name2); +// registrar.register_custom_derive($name_trait1, ::$name1, &[]); +// registrar.register_custom_derive($name_trait2, ::$name2, &["attribute_name"]); // // ... // } // } @@ -238,14 +282,18 @@ fn mk_registrar(cx: &mut ExtCtxt, let stmts = custom_derives.iter().map(|cd| { let path = cx.path_global(cd.span, vec![cd.function_name]); let trait_name = cx.expr_str(cd.span, cd.trait_name.clone()); - (path, trait_name) - }).map(|(path, trait_name)| { + let attrs = cx.expr_vec_slice( + span, + cd.attrs.iter().map(|s| cx.expr_str(cd.span, s.clone())).collect::>() + ); + (path, trait_name, attrs) + }).map(|(path, trait_name, attrs)| { let registrar = cx.expr_ident(span, registrar); let ufcs_path = cx.path(span, vec![proc_macro, __internal, registry, register_custom_derive]); cx.expr_call(span, cx.expr_path(ufcs_path), - vec![registrar, trait_name, cx.expr_path(path)]) + vec![registrar, trait_name, cx.expr_path(path), attrs]) }).map(|expr| { cx.stmt_expr(expr) }).collect::>(); diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d83d3a6c5cfa..d99850332c36 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -67,7 +67,7 @@ pub struct Span { /// the error, and would be rendered with `^^^`. /// - they can have a *label*. In this case, the label is written next /// to the mark in the snippet when we render. -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct MultiSpan { primary_spans: Vec, span_labels: Vec<(Span, String)>, 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 60697cc8b6ac..409f9dbf03c5 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -10,7 +10,6 @@ // force-host -#![feature(dotdot_in_tuple_patterns)] #![feature(plugin_registrar, quote, rustc_private)] extern crate syntax; diff --git a/src/test/compile-fail-fulldeps/proc-macro/attribute.rs b/src/test/compile-fail-fulldeps/proc-macro/attribute.rs index d1b2aa330ed5..e22339694f9b 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/attribute.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/attribute.rs @@ -33,8 +33,8 @@ pub fn foo3(input: proc_macro::TokenStream) -> proc_macro::TokenStream { input } -#[proc_macro_derive(b, c)] -//~^ ERROR: attribute must only have one argument +#[proc_macro_derive(b, c, d)] +//~^ ERROR: attribute must have either one or two arguments pub fn foo4(input: proc_macro::TokenStream) -> proc_macro::TokenStream { input } @@ -44,3 +44,21 @@ pub fn foo4(input: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn foo5(input: proc_macro::TokenStream) -> proc_macro::TokenStream { input } + +#[proc_macro_derive(f, attributes(g = "h"))] +//~^ ERROR: must only be one word +pub fn foo6(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + input +} + +#[proc_macro_derive(i, attributes(j(k)))] +//~^ ERROR: must only be one word +pub fn foo7(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + input +} + +#[proc_macro_derive(l, attributes(m), n)] +//~^ ERROR: attribute must have either one or two arguments +pub fn foo8(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs index 4aa4238611d8..8d26207273d4 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-a.rs @@ -21,5 +21,5 @@ use proc_macro::TokenStream; #[proc_macro_derive(A)] pub fn derive_a(input: TokenStream) -> TokenStream { - input + "".parse().unwrap() } diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-b.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-b.rs new file mode 100644 index 000000000000..70b778b1030e --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/derive-b.rs @@ -0,0 +1,25 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![feature(proc_macro)] +#![feature(proc_macro_lib)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(B, attributes(B))] +pub fn derive_b(input: TokenStream) -> TokenStream { + "".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable-2.rs b/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable-2.rs index 23dcbe03b5fe..4f4ed90f8fca 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable-2.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable-2.rs @@ -17,8 +17,8 @@ extern crate derive_unstable_2; #[derive(Unstable)] -struct A; //~^ ERROR: reserved for internal compiler +struct A; fn main() { foo(); diff --git a/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable.rs b/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable.rs index fb86f6f1b657..84ac776a765a 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/expand-to-unstable.rs @@ -17,8 +17,8 @@ extern crate derive_unstable; #[derive(Unstable)] -struct A; //~^ ERROR: use of unstable library feature +struct A; fn main() { unsafe { foo(); } diff --git a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs index 0fdd13bc30cc..6a8fcdf4ab78 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/feature-gate-4.rs @@ -12,4 +12,6 @@ #[macro_use] extern crate derive_a; -//~^ ERROR: loading custom derive macro crates is experimentally supported + +#[derive(A)] //~ ERROR custom derive macros are experimentally supported +struct S; diff --git a/src/test/compile-fail-fulldeps/proc-macro/require-rustc-macro-crate-type.rs b/src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs similarity index 82% rename from src/test/compile-fail-fulldeps/proc-macro/require-rustc-macro-crate-type.rs rename to src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs index 44397cdde0c0..405994b36e25 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/require-rustc-macro-crate-type.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/illegal-proc-macro-derive-use.rs @@ -18,4 +18,10 @@ pub fn foo(a: proc_macro::TokenStream) -> proc_macro::TokenStream { a } +// Issue #37590 +#[proc_macro_derive(Foo)] +//~^ ERROR: the `#[proc_macro_derive]` attribute may only be used on bare functions +pub struct Foo { +} + fn main() {} diff --git a/src/test/compile-fail-fulldeps/proc-macro/item-error.rs b/src/test/compile-fail-fulldeps/proc-macro/item-error.rs new file mode 100644 index 000000000000..2a68accf91f7 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/item-error.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-b.rs + +#![feature(proc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_b; + +#[derive(B)] +struct A { + a: &u64 +//~^ ERROR: missing lifetime specifier +} + +fn main() { +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/no-macro-use-attr.rs b/src/test/compile-fail-fulldeps/proc-macro/no-macro-use-attr.rs new file mode 100644 index 000000000000..f61b8b4073b6 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/no-macro-use-attr.rs @@ -0,0 +1,19 @@ +// 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:derive-a.rs + +#![feature(rustc_attrs)] + +extern crate derive_a; +//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]` + +#[rustc_error] +fn main() {} //~ ERROR compilation successful diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs new file mode 100644 index 000000000000..651a277d4abd --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-attributes.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-b.rs + +#![feature(proc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_b; + +#[derive(B)] +#[B] +#[C] //~ ERROR: The attribute `C` is currently unknown to the compiler +#[B(D)] +#[B(E = "foo")] +struct B; + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/proc-macro/shadow.rs b/src/test/compile-fail-fulldeps/proc-macro/shadow.rs index a04756ca19ba..dc828fbf7d16 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/shadow.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/shadow.rs @@ -15,6 +15,6 @@ #[macro_use] extern crate derive_a; #[macro_use] -extern crate derive_a; //~ ERROR `derive_a` has already been defined +extern crate derive_a; //~ ERROR `derive_a` has already been imported fn main() {} diff --git a/src/test/compile-fail/E0138.rs b/src/test/compile-fail/E0138.rs index d4630d7c2eff..11d90658ab26 100644 --- a/src/test/compile-fail/E0138.rs +++ b/src/test/compile-fail/E0138.rs @@ -11,10 +11,10 @@ #![feature(start)] #[start] -fn foo(argc: isize, argv: *const *const u8) -> isize {} +fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } //~^ NOTE previous `start` function here #[start] -fn f(argc: isize, argv: *const *const u8) -> isize {} +fn f(argc: isize, argv: *const *const u8) -> isize { 0 } //~^ ERROR E0138 //~| NOTE multiple `start` functions diff --git a/src/test/compile-fail/auxiliary/define_macro.rs b/src/test/compile-fail/auxiliary/define_macro.rs new file mode 100644 index 000000000000..6b6b14a896b2 --- /dev/null +++ b/src/test/compile-fail/auxiliary/define_macro.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_export] +macro_rules! define_macro { + ($i:ident) => { + macro_rules! $i { () => {} } + } +} diff --git a/src/test/compile-fail/auxiliary/empty-struct.rs b/src/test/compile-fail/auxiliary/empty-struct.rs index dcbb0ce178bd..4a3028656342 100644 --- a/src/test/compile-fail/auxiliary/empty-struct.rs +++ b/src/test/compile-fail/auxiliary/empty-struct.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(relaxed_adts)] - pub struct XEmpty1 {} pub struct XEmpty2; pub struct XEmpty6(); diff --git a/src/test/compile-fail/auxiliary/namespace-mix-new.rs b/src/test/compile-fail/auxiliary/namespace-mix-new.rs index 88e8b0d56fe3..d42c0ee1a4da 100644 --- a/src/test/compile-fail/auxiliary/namespace-mix-new.rs +++ b/src/test/compile-fail/auxiliary/namespace-mix-new.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(item_like_imports, relaxed_adts)] +#![feature(item_like_imports)] pub mod c { pub struct S {} diff --git a/src/test/compile-fail/auxiliary/namespace-mix-old.rs b/src/test/compile-fail/auxiliary/namespace-mix-old.rs index 7bbba7163b55..29b139d771b0 100644 --- a/src/test/compile-fail/auxiliary/namespace-mix-old.rs +++ b/src/test/compile-fail/auxiliary/namespace-mix-old.rs @@ -10,8 +10,6 @@ // FIXME: Remove when `item_like_imports` is stabilized. -#![feature(relaxed_adts)] - pub mod c { pub struct S {} pub struct TS(); diff --git a/src/test/compile-fail/consider-removing-last-semi.rs b/src/test/compile-fail/consider-removing-last-semi.rs index 2e110cb3d0bc..530a0e415622 100644 --- a/src/test/compile-fail/consider-removing-last-semi.rs +++ b/src/test/compile-fail/consider-removing-last-semi.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f() -> String { //~ ERROR E0269 +fn f() -> String { //~ ERROR mismatched types 0u8; "bla".to_string(); //~ HELP consider removing this semicolon } -fn g() -> String { //~ ERROR E0269 +fn g() -> String { //~ ERROR mismatched types "this won't work".to_string(); "removeme".to_string(); //~ HELP consider removing this semicolon } diff --git a/src/test/compile-fail/diverging-fn-tail-35849.rs b/src/test/compile-fail/diverging-fn-tail-35849.rs index 6dc447b4dc88..3a27c0841332 100644 --- a/src/test/compile-fail/diverging-fn-tail-35849.rs +++ b/src/test/compile-fail/diverging-fn-tail-35849.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn _converge() -> ! { //~ ERROR computation may converge - 42 +fn _converge() -> ! { + 42 //~ ERROR mismatched types } fn main() { } diff --git a/src/test/compile-fail/empty-struct-braces-pat-2.rs b/src/test/compile-fail/empty-struct-braces-pat-2.rs index 58e3ca6b3ac5..4349e72c5d73 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-2.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-2.rs @@ -12,8 +12,6 @@ // aux-build:empty-struct.rs -#![feature(relaxed_adts)] - extern crate empty_struct; use empty_struct::*; diff --git a/src/test/compile-fail/empty-struct-braces-pat-3.rs b/src/test/compile-fail/empty-struct-braces-pat-3.rs index 1960eca9f802..d6c5b9534921 100644 --- a/src/test/compile-fail/empty-struct-braces-pat-3.rs +++ b/src/test/compile-fail/empty-struct-braces-pat-3.rs @@ -12,8 +12,6 @@ // aux-build:empty-struct.rs -#![feature(relaxed_adts)] - extern crate empty_struct; use empty_struct::*; diff --git a/src/test/compile-fail/empty-struct-tuple-pat.rs b/src/test/compile-fail/empty-struct-tuple-pat.rs index f15c126a1260..5e683eafade8 100644 --- a/src/test/compile-fail/empty-struct-tuple-pat.rs +++ b/src/test/compile-fail/empty-struct-tuple-pat.rs @@ -12,8 +12,6 @@ // aux-build:empty-struct.rs -#![feature(relaxed_adts)] - extern crate empty_struct; use empty_struct::*; diff --git a/src/test/compile-fail/empty-struct-unit-expr.rs b/src/test/compile-fail/empty-struct-unit-expr.rs index 350b96c764ca..273ce91a7c5b 100644 --- a/src/test/compile-fail/empty-struct-unit-expr.rs +++ b/src/test/compile-fail/empty-struct-unit-expr.rs @@ -23,7 +23,11 @@ enum E { fn main() { let e2 = Empty2(); //~ ERROR expected function, found `Empty2` - let e4 = E::Empty4(); //~ ERROR expected function, found `E` + let e4 = E::Empty4(); + //~^ ERROR `E::Empty4` is being called, but it is not a function + //~| HELP did you mean to write `E::Empty4`? let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2` - let xe4 = XE::XEmpty4(); //~ ERROR expected function, found `empty_struct::XE` + let xe4 = XE::XEmpty4(); + //~^ ERROR `XE::XEmpty4` is being called, but it is not a function + //~| HELP did you mean to write `XE::XEmpty4`? } diff --git a/src/test/compile-fail/empty-struct-unit-pat.rs b/src/test/compile-fail/empty-struct-unit-pat.rs index 90f6ae5755f8..532c2d85053f 100644 --- a/src/test/compile-fail/empty-struct-unit-pat.rs +++ b/src/test/compile-fail/empty-struct-unit-pat.rs @@ -12,8 +12,6 @@ // aux-build:empty-struct.rs -#![feature(relaxed_adts)] - extern crate empty_struct; use empty_struct::*; diff --git a/src/test/compile-fail/issue-11714.rs b/src/test/compile-fail/issue-11714.rs index 998576097a0a..192f78e41cb4 100644 --- a/src/test/compile-fail/issue-11714.rs +++ b/src/test/compile-fail/issue-11714.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn blah() -> i32 { //~ ERROR not all control paths return a value +fn blah() -> i32 { //~ ERROR mismatched types 1 ; //~ HELP consider removing this semicolon: diff --git a/src/test/compile-fail/issue-13428.rs b/src/test/compile-fail/issue-13428.rs index c771970650d3..9406199afc23 100644 --- a/src/test/compile-fail/issue-13428.rs +++ b/src/test/compile-fail/issue-13428.rs @@ -10,7 +10,7 @@ // Regression test for #13428 -fn foo() -> String { //~ ERROR not all control paths return a value +fn foo() -> String { //~ ERROR mismatched types format!("Hello {}", "world") // Put the trailing semicolon on its own line to test that the @@ -18,7 +18,7 @@ fn foo() -> String { //~ ERROR not all control paths return a value ; //~ HELP consider removing this semicolon } -fn bar() -> String { //~ ERROR not all control paths return a value +fn bar() -> String { //~ ERROR mismatched types "foobar".to_string() ; //~ HELP consider removing this semicolon } diff --git a/src/test/compile-fail/issue-14853.rs b/src/test/compile-fail/issue-14853.rs index c4d882670329..e4da3e4fa43e 100644 --- a/src/test/compile-fail/issue-14853.rs +++ b/src/test/compile-fail/issue-14853.rs @@ -20,7 +20,7 @@ struct X { data: u32 } impl Something for X { fn yay(_:Option, thing: &[T]) { - //~^ ERROR the requirement `T: Str` appears on the impl method + //~^ ERROR E0276 } } diff --git a/src/test/compile-fail/issue-17800.rs b/src/test/compile-fail/issue-17800.rs index d5f1614c14d2..f7cae91aa93a 100644 --- a/src/test/compile-fail/issue-17800.rs +++ b/src/test/compile-fail/issue-17800.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(relaxed_adts)] - enum MyOption { MySome(T), MyNone, diff --git a/src/test/compile-fail/issue-18937.rs b/src/test/compile-fail/issue-18937.rs new file mode 100644 index 000000000000..8ac66bb44d20 --- /dev/null +++ b/src/test/compile-fail/issue-18937.rs @@ -0,0 +1,53 @@ +// 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. + +// Regression test for #18937. + +#![deny(extra_requirement_in_impl)] + +use std::fmt; + +#[derive(Debug)] +struct MyString<'a>(&'a String); + +struct B { + list: Vec>, +} + +trait A<'a> { + fn foo(&mut self, f: F) + where F: fmt::Debug + 'a, + Self: Sized; +} + +impl<'a> A<'a> for B { + fn foo(&mut self, f: F) //~ ERROR E0276 + //~^ WARNING future release + where F: fmt::Debug + 'static, + { + self.list.push(Box::new(f)); + } +} + +fn main() { + let mut b = B { list: Vec::new() }; + + // Create a borrowed pointer, put it in `b`, then drop what's borrowing it + let a = "hello".to_string(); + b.foo(MyString(&a)); + + // Drop the data which `b` has a reference to + drop(a); + + // Use the data, probably segfaulting + for b in b.list.iter() { + println!("{:?}", b); + } +} diff --git a/src/test/compile-fail/issue-22645.rs b/src/test/compile-fail/issue-22645.rs index 402b9a04496e..81f66e3e2cfe 100644 --- a/src/test/compile-fail/issue-22645.rs +++ b/src/test/compile-fail/issue-22645.rs @@ -17,7 +17,7 @@ struct Bob; impl Add for Bob { type Output = Bob; - fn add(self, rhs : RHS) -> Bob {} + fn add(self, rhs : RHS) -> Bob { Bob } } fn main() { diff --git a/src/test/compile-fail/issue-22684.rs b/src/test/compile-fail/issue-22684.rs index b7ffbefba6a0..a791758ad176 100644 --- a/src/test/compile-fail/issue-22684.rs +++ b/src/test/compile-fail/issue-22684.rs @@ -15,7 +15,7 @@ mod foo { } pub trait Baz { - fn bar(&self) -> bool {} + fn bar(&self) -> bool { true } } impl Baz for Foo {} } diff --git a/src/test/compile-fail/issue-29161.rs b/src/test/compile-fail/issue-29161.rs index bc09f61a754c..97ba222fe45f 100644 --- a/src/test/compile-fail/issue-29161.rs +++ b/src/test/compile-fail/issue-29161.rs @@ -13,7 +13,7 @@ mod a { impl Default for A { pub fn default() -> A { //~ ERROR unnecessary visibility qualifier - A; + A } } } diff --git a/src/test/compile-fail/issue-32323.rs b/src/test/compile-fail/issue-32323.rs index e3461e52e1c7..e5cb81303277 100644 --- a/src/test/compile-fail/issue-32323.rs +++ b/src/test/compile-fail/issue-32323.rs @@ -13,6 +13,6 @@ pub trait Tr<'a> { } pub fn f<'a, T: Tr<'a>>() -> >::Out {} -//~^ ERROR not all control paths return a value +//~^ ERROR mismatched types pub fn main() {} diff --git a/src/test/compile-fail/issue-37534.rs b/src/test/compile-fail/issue-37534.rs new file mode 100644 index 000000000000..eb676601e89c --- /dev/null +++ b/src/test/compile-fail/issue-37534.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo { } +//~^ ERROR trait `Hash` is not in scope [E0405] +//~^^ ERROR parameter `T` is never used [E0392] +//~^^^ WARN default bound relaxed for a type parameter, but this does nothing + +fn main() { } diff --git a/src/test/compile-fail/issue-3907.rs b/src/test/compile-fail/issue-3907.rs index 93556577ad34..86906ed9af20 100644 --- a/src/test/compile-fail/issue-3907.rs +++ b/src/test/compile-fail/issue-3907.rs @@ -18,7 +18,7 @@ struct S { } impl Foo for S { //~ ERROR: `Foo` is not a trait - //~| NOTE: not a trait + //~| NOTE: expected trait, found type alias //~| NOTE: type aliases cannot be used for traits fn bar() { } } diff --git a/src/test/compile-fail/issue-4736.rs b/src/test/compile-fail/issue-4736.rs index c93e75042dd1..19803079d022 100644 --- a/src/test/compile-fail/issue-4736.rs +++ b/src/test/compile-fail/issue-4736.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(relaxed_adts)] - struct NonCopyable(()); fn main() { diff --git a/src/test/compile-fail/issue-5035.rs b/src/test/compile-fail/issue-5035.rs index 7a36012925ee..8ebcba471340 100644 --- a/src/test/compile-fail/issue-5035.rs +++ b/src/test/compile-fail/issue-5035.rs @@ -11,7 +11,7 @@ trait I {} type K = I; impl K for isize {} //~ ERROR: `K` is not a trait - //~| NOTE: not a trait + //~| NOTE: expected trait, found type alias //~| NOTE: aliases cannot be used for traits use ImportError; //~ ERROR unresolved import `ImportError` [E0432] diff --git a/src/test/compile-fail/issue-5239-1.rs b/src/test/compile-fail/issue-5239-1.rs index 06e3c9a207b7..a77b27150d79 100644 --- a/src/test/compile-fail/issue-5239-1.rs +++ b/src/test/compile-fail/issue-5239-1.rs @@ -11,7 +11,7 @@ // Regression test for issue #5239 fn main() { - let x = |ref x: isize| -> isize { x += 1; }; + let x = |ref x: isize| { x += 1; }; //~^ ERROR E0368 //~| NOTE cannot use `+=` on type `&isize` } diff --git a/src/test/compile-fail/issue-6458-4.rs b/src/test/compile-fail/issue-6458-4.rs index c3f3a718ad0e..a078cdea4ac4 100644 --- a/src/test/compile-fail/issue-6458-4.rs +++ b/src/test/compile-fail/issue-6458-4.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(b: bool) -> Result { - Err("bar".to_string()); - //~^ ERROR unable to infer enough type information about `_` [E0282] - //~| NOTE cannot infer type for `_` - //~| NOTE type annotations or generic parameter binding +fn foo(b: bool) -> Result { //~ ERROR mismatched types + Err("bar".to_string()); //~ HELP consider removing this semicolon } fn main() { diff --git a/src/test/compile-fail/liveness-forgot-ret.rs b/src/test/compile-fail/liveness-forgot-ret.rs index e08515e40af7..1ee4be08a1c5 100644 --- a/src/test/compile-fail/liveness-forgot-ret.rs +++ b/src/test/compile-fail/liveness-forgot-ret.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: not all control paths return a value - fn god_exists(a: isize) -> bool { return god_exists(a); } fn f(a: isize) -> isize { if god_exists(a) { return 5; }; } +//~^ ERROR mismatched types fn main() { f(12); } diff --git a/src/test/compile-fail/liveness-issue-2163.rs b/src/test/compile-fail/liveness-issue-2163.rs index 7c94e33b47b3..69bceec8c322 100644 --- a/src/test/compile-fail/liveness-issue-2163.rs +++ b/src/test/compile-fail/liveness-issue-2163.rs @@ -13,6 +13,6 @@ use std::vec::Vec; fn main() { let a: Vec = Vec::new(); a.iter().all(|_| -> bool { - //~^ ERROR not all control paths return a value + //~^ ERROR mismatched types }); } diff --git a/src/test/compile-fail/liveness-missing-ret2.rs b/src/test/compile-fail/liveness-missing-ret2.rs index b53bb6159e8d..a35eb1af4f33 100644 --- a/src/test/compile-fail/liveness-missing-ret2.rs +++ b/src/test/compile-fail/liveness-missing-ret2.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: not all control paths return a value - -fn f() -> isize { +fn f() -> isize { //~ ERROR mismatched types // Make sure typestate doesn't interpret this match expression as // the function result match true { true => { } _ => {} }; diff --git a/src/test/compile-fail/liveness-return-last-stmt-semi.rs b/src/test/compile-fail/liveness-return-last-stmt-semi.rs index 03733cc2eb59..ada91c38d48c 100644 --- a/src/test/compile-fail/liveness-return-last-stmt-semi.rs +++ b/src/test/compile-fail/liveness-return-last-stmt-semi.rs @@ -11,16 +11,16 @@ // regression test for #8005 macro_rules! test { () => { fn foo() -> i32 { 1; } } } - //~^ ERROR not all control paths return a value + //~^ ERROR mismatched types //~| HELP consider removing this semicolon -fn no_return() -> i32 {} //~ ERROR not all control paths return a value +fn no_return() -> i32 {} //~ ERROR mismatched types -fn bar(x: u32) -> u32 { //~ ERROR not all control paths return a value +fn bar(x: u32) -> u32 { //~ ERROR mismatched types x * 2; //~ HELP consider removing this semicolon } -fn baz(x: u64) -> u32 { //~ ERROR not all control paths return a value +fn baz(x: u64) -> u32 { //~ ERROR mismatched types x * 2; } diff --git a/src/test/compile-fail/main-wrong-type-2.rs b/src/test/compile-fail/main-wrong-type-2.rs index 7434a6c960b2..2878cbc7fc15 100644 --- a/src/test/compile-fail/main-wrong-type-2.rs +++ b/src/test/compile-fail/main-wrong-type-2.rs @@ -10,4 +10,5 @@ fn main() -> char { //~^ ERROR: main function has wrong type + ' ' } diff --git a/src/test/compile-fail/match-slice-patterns.rs b/src/test/compile-fail/match-slice-patterns.rs new file mode 100644 index 000000000000..c0fc75f9713a --- /dev/null +++ b/src/test/compile-fail/match-slice-patterns.rs @@ -0,0 +1,24 @@ +// 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(advanced_slice_patterns, slice_patterns)] + +fn check(list: &[Option<()>]) { + match list { + //~^ ERROR `&[None, Some(_), None, _]` and `&[Some(_), Some(_), None, _]` not covered + &[] => {}, + &[_] => {}, + &[_, _] => {}, + &[_, None, ..] => {}, + &[.., Some(_), _] => {}, + } +} + +fn main() {} diff --git a/src/test/compile-fail/namespace-mix-new.rs b/src/test/compile-fail/namespace-mix-new.rs index 0abe8bd43909..59592e3d737d 100644 --- a/src/test/compile-fail/namespace-mix-new.rs +++ b/src/test/compile-fail/namespace-mix-new.rs @@ -10,7 +10,7 @@ // aux-build:namespace-mix-new.rs -#![feature(item_like_imports, relaxed_adts)] +#![feature(item_like_imports)] extern crate namespace_mix_new; use namespace_mix_new::*; diff --git a/src/test/compile-fail/namespace-mix-old.rs b/src/test/compile-fail/namespace-mix-old.rs index ad6766441961..8cd82050814a 100644 --- a/src/test/compile-fail/namespace-mix-old.rs +++ b/src/test/compile-fail/namespace-mix-old.rs @@ -12,8 +12,6 @@ // aux-build:namespace-mix-old.rs -#![feature(relaxed_adts)] - extern crate namespace_mix_old; use namespace_mix_old::{xm1, xm2, xm3, xm4, xm5, xm6, xm7, xm8, xm9, xmA, xmB, xmC}; diff --git a/src/test/compile-fail/no-link.rs b/src/test/compile-fail/no-link.rs index 8f6da99806b3..c4737a373992 100644 --- a/src/test/compile-fail/no-link.rs +++ b/src/test/compile-fail/no-link.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// aux-build:empty-struct.rs + #[no_link] -extern crate libc; +extern crate empty_struct; +//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]` fn main() { - unsafe { - libc::abs(0); //~ ERROR unresolved name - } + empty_struct::XEmpty1; //~ ERROR unresolved name } diff --git a/src/test/compile-fail/pat-tuple-feature-gate.rs b/src/test/compile-fail/numeric-fields-feature-gate.rs similarity index 67% rename from src/test/compile-fail/pat-tuple-feature-gate.rs rename to src/test/compile-fail/numeric-fields-feature-gate.rs index 55ca05bdef38..3ce85813a9b5 100644 --- a/src/test/compile-fail/pat-tuple-feature-gate.rs +++ b/src/test/compile-fail/numeric-fields-feature-gate.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +struct S(u8); + fn main() { - match 0 { - (..) => {} //~ ERROR `..` in tuple patterns is experimental - (pat, ..) => {} //~ ERROR `..` in tuple patterns is experimental - S(pat, ..) => {} //~ ERROR `..` in tuple struct patterns is experimental + let s = S{0: 10}; //~ ERROR numeric fields in struct expressions are unstable + match s { + S{0: a, ..} => {} //~ ERROR numeric fields in struct patterns are unstable } } diff --git a/src/test/compile-fail/on-unimplemented/on-trait.rs b/src/test/compile-fail/on-unimplemented/on-trait.rs index 3a789f3faeb2..0f4b0919b650 100644 --- a/src/test/compile-fail/on-unimplemented/on-trait.rs +++ b/src/test/compile-fail/on-unimplemented/on-trait.rs @@ -16,7 +16,7 @@ trait Foo {} fn foobar>() -> T { - + panic!() } #[rustc_on_unimplemented="a collection of type `{Self}` cannot be built from an iterator over elements of type `{A}`"] diff --git a/src/test/compile-fail/out-of-order-shadowing.rs b/src/test/compile-fail/out-of-order-shadowing.rs new file mode 100644 index 000000000000..1fafaf85112b --- /dev/null +++ b/src/test/compile-fail/out-of-order-shadowing.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:define_macro.rs +// error-pattern: `bar` is already in scope + +macro_rules! bar { () => {} } +define_macro!(bar); +bar!(); + +macro_rules! m { () => { #[macro_use] extern crate define_macro; } } +m!(); + +fn main() {} diff --git a/src/test/compile-fail/pat-tuple-bad-type.rs b/src/test/compile-fail/pat-tuple-bad-type.rs index 0d50a30dd052..fd4ab5d25315 100644 --- a/src/test/compile-fail/pat-tuple-bad-type.rs +++ b/src/test/compile-fail/pat-tuple-bad-type.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn main() { let x; diff --git a/src/test/compile-fail/pat-tuple-overfield.rs b/src/test/compile-fail/pat-tuple-overfield.rs index 069c1dc0aea1..851fa5c5be61 100644 --- a/src/test/compile-fail/pat-tuple-overfield.rs +++ b/src/test/compile-fail/pat-tuple-overfield.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - struct S(u8, u8, u8); fn main() { diff --git a/src/test/compile-fail/private-in-public-lint.rs b/src/test/compile-fail/private-in-public-lint.rs index 8e23bfcfb105..4796548112d9 100644 --- a/src/test/compile-fail/private-in-public-lint.rs +++ b/src/test/compile-fail/private-in-public-lint.rs @@ -13,7 +13,7 @@ mod m1 { struct Priv; impl Pub { - pub fn f() -> Priv {} //~ ERROR private type in public interface + pub fn f() -> Priv {Priv} //~ ERROR private type in public interface } } @@ -24,7 +24,7 @@ mod m2 { struct Priv; impl Pub { - pub fn f() -> Priv {} //~ ERROR private type in public interface + pub fn f() -> Priv {Priv} //~ ERROR private type in public interface } } diff --git a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs index 6e60a373d9b0..1d4ffe0690d2 100644 --- a/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs +++ b/src/test/compile-fail/regions-bound-missing-bound-in-impl.rs @@ -52,7 +52,7 @@ impl<'a, 't> Foo<'a, 't> for &'a isize { } fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) { - //~^ ERROR lifetime bound not satisfied + //~^ ERROR E0276 } } diff --git a/src/test/compile-fail/required-lang-item.rs b/src/test/compile-fail/required-lang-item.rs index 1aa22a1676ef..ce40702b3dc2 100644 --- a/src/test/compile-fail/required-lang-item.rs +++ b/src/test/compile-fail/required-lang-item.rs @@ -11,6 +11,7 @@ #![feature(lang_items, no_core)] #![no_core] +#[lang="copy"] pub trait Copy { } #[lang="sized"] pub trait Sized { } // error-pattern:requires `start` lang_item diff --git a/src/test/compile-fail/struct-path-associated-type.rs b/src/test/compile-fail/struct-path-associated-type.rs index 660ac44ce0b5..ecaf269fcb1a 100644 --- a/src/test/compile-fail/struct-path-associated-type.rs +++ b/src/test/compile-fail/struct-path-associated-type.rs @@ -8,6 +8,8 @@ // 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-feature-gate.rs b/src/test/compile-fail/struct-path-self-feature-gate.rs new file mode 100644 index 000000000000..a2050182a7e3 --- /dev/null +++ b/src/test/compile-fail/struct-path-self-feature-gate.rs @@ -0,0 +1,29 @@ +// 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. + +struct S; + +trait Tr { + type A; +} + +fn f>() { + let _ = T::A {}; + //~^ ERROR `Self` and associated types in struct expressions and patterns are unstable +} + +impl S { + fn f() { + let _ = Self {}; + //~^ ERROR `Self` and associated types in struct expressions and patterns are unstable + } +} + +fn main() {} 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 f694e7d277c7..8352bd6751f5 100644 --- a/src/test/compile-fail/struct-path-self-type-mismatch.rs +++ b/src/test/compile-fail/struct-path-self-type-mismatch.rs @@ -8,6 +8,8 @@ // 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 067d6ac22dc6..aeac199227b7 100644 --- a/src/test/compile-fail/struct-path-self.rs +++ b/src/test/compile-fail/struct-path-self.rs @@ -8,6 +8,8 @@ // 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/unreachable-in-call.rs b/src/test/compile-fail/unreachable-in-call.rs index 5a3257d54db2..72462468432d 100644 --- a/src/test/compile-fail/unreachable-in-call.rs +++ b/src/test/compile-fail/unreachable-in-call.rs @@ -24,7 +24,7 @@ fn diverge_first() { get_u8()); //~ ERROR unreachable expression } fn diverge_second() { - call( //~ ERROR unreachable call + call( //~ ERROR unreachable expression get_u8(), diverge()); } diff --git a/src/test/compile-fail/where-clauses-unsatisfied.rs b/src/test/compile-fail/where-clauses-unsatisfied.rs index 278a8db4e1ad..ffc39008c4e5 100644 --- a/src/test/compile-fail/where-clauses-unsatisfied.rs +++ b/src/test/compile-fail/where-clauses-unsatisfied.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn equal(_: &T, _: &T) -> bool where T : Eq { -} +fn equal(a: &T, b: &T) -> bool where T : Eq { a == b } struct Struct; diff --git a/src/test/compile-fail/windows-subsystem-gated.rs b/src/test/compile-fail/windows-subsystem-gated.rs new file mode 100644 index 000000000000..4b563e78e55c --- /dev/null +++ b/src/test/compile-fail/windows-subsystem-gated.rs @@ -0,0 +1,14 @@ +// 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. + +#![windows_subsystem = "console"] +//~^ ERROR: the windows subsystem attribute is currently unstable + +fn main() {} diff --git a/src/test/compile-fail/windows-subsystem-invalid.rs b/src/test/compile-fail/windows-subsystem-invalid.rs new file mode 100644 index 000000000000..e0003440719e --- /dev/null +++ b/src/test/compile-fail/windows-subsystem-invalid.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern: invalid windows subsystem `wrong`, only `windows` and `console` are allowed + +#![feature(windows_subsystem)] +#![windows_subsystem = "wrong"] + +fn main() {} diff --git a/src/test/debuginfo/associated-types.rs b/src/test/debuginfo/associated-types.rs index ebaad663bb4e..ccd94022711c 100644 --- a/src/test/debuginfo/associated-types.rs +++ b/src/test/debuginfo/associated-types.rs @@ -16,7 +16,8 @@ // gdb-command:run // gdb-command:print arg -// gdb-check:$1 = {b = -1, b1 = 0} +// gdbg-check:$1 = {b = -1, b1 = 0} +// gdbr-check:$1 = associated_types::Struct {b: -1, b1: 0} // gdb-command:continue // gdb-command:print inferred @@ -30,7 +31,8 @@ // gdb-command:continue // gdb-command:print arg -// gdb-check:$5 = {__0 = 4, __1 = 5} +// gdbg-check:$5 = {__0 = 4, __1 = 5} +// gdbr-check:$5 = (4, 5) // gdb-command:continue // gdb-command:print a diff --git a/src/test/debuginfo/basic-types-globals-metadata.rs b/src/test/debuginfo/basic-types-globals-metadata.rs index 8818063ddf4b..fe687dabe9ac 100644 --- a/src/test/debuginfo/basic-types-globals-metadata.rs +++ b/src/test/debuginfo/basic-types-globals-metadata.rs @@ -12,33 +12,47 @@ // compile-flags:-g // gdb-command:run -// gdb-command:whatis 'basic_types_globals_metadata::B' +// gdbg-command:whatis 'basic_types_globals_metadata::B' +// gdbr-command:whatis basic_types_globals_metadata::B // gdb-check:type = bool -// gdb-command:whatis 'basic_types_globals_metadata::I' +// gdbg-command:whatis 'basic_types_globals_metadata::I' +// gdbr-command:whatis basic_types_globals_metadata::I // gdb-check:type = isize -// gdb-command:whatis 'basic_types_globals_metadata::C' +// gdbg-command:whatis 'basic_types_globals_metadata::C' +// gdbr-command:whatis basic_types_globals_metadata::C // gdb-check:type = char -// gdb-command:whatis 'basic_types_globals_metadata::I8' +// gdbg-command:whatis 'basic_types_globals_metadata::I8' +// gdbr-command:whatis basic_types_globals_metadata::I8 // gdb-check:type = i8 -// gdb-command:whatis 'basic_types_globals_metadata::I16' +// gdbg-command:whatis 'basic_types_globals_metadata::I16' +// gdbr-command:whatis basic_types_globals_metadata::I16 // gdb-check:type = i16 -// gdb-command:whatis 'basic_types_globals_metadata::I32' +// gdbg-command:whatis 'basic_types_globals_metadata::I32' +// gdbr-command:whatis basic_types_globals_metadata::I32 // gdb-check:type = i32 -// gdb-command:whatis 'basic_types_globals_metadata::I64' +// gdbg-command:whatis 'basic_types_globals_metadata::I64' +// gdbr-command:whatis basic_types_globals_metadata::I64 // gdb-check:type = i64 -// gdb-command:whatis 'basic_types_globals_metadata::U' +// gdbg-command:whatis 'basic_types_globals_metadata::U' +// gdbr-command:whatis basic_types_globals_metadata::U // gdb-check:type = usize -// gdb-command:whatis 'basic_types_globals_metadata::U8' +// gdbg-command:whatis 'basic_types_globals_metadata::U8' +// gdbr-command:whatis basic_types_globals_metadata::U8 // gdb-check:type = u8 -// gdb-command:whatis 'basic_types_globals_metadata::U16' +// gdbg-command:whatis 'basic_types_globals_metadata::U16' +// gdbr-command:whatis basic_types_globals_metadata::U16 // gdb-check:type = u16 -// gdb-command:whatis 'basic_types_globals_metadata::U32' +// gdbg-command:whatis 'basic_types_globals_metadata::U32' +// gdbr-command:whatis basic_types_globals_metadata::U32 // gdb-check:type = u32 -// gdb-command:whatis 'basic_types_globals_metadata::U64' +// gdbg-command:whatis 'basic_types_globals_metadata::U64' +// gdbr-command:whatis basic_types_globals_metadata::U64 // gdb-check:type = u64 -// gdb-command:whatis 'basic_types_globals_metadata::F32' +// gdbg-command:whatis 'basic_types_globals_metadata::F32' +// gdbr-command:whatis basic_types_globals_metadata::F32 // gdb-check:type = f32 -// gdb-command:whatis 'basic_types_globals_metadata::F64' +// gdbg-command:whatis 'basic_types_globals_metadata::F64' +// gdbr-command:whatis basic_types_globals_metadata::F64 // gdb-check:type = f64 // gdb-command:continue diff --git a/src/test/debuginfo/basic-types-globals.rs b/src/test/debuginfo/basic-types-globals.rs index ccf9508a3856..20bc403fbbcd 100644 --- a/src/test/debuginfo/basic-types-globals.rs +++ b/src/test/debuginfo/basic-types-globals.rs @@ -18,33 +18,48 @@ // compile-flags:-g // gdb-command:run -// gdb-command:print 'basic_types_globals::B' +// gdbg-command:print 'basic_types_globals::B' +// gdbr-command:print B // gdb-check:$1 = false -// gdb-command:print 'basic_types_globals::I' +// gdbg-command:print 'basic_types_globals::I' +// gdbr-command:print I // gdb-check:$2 = -1 -// gdb-command:print 'basic_types_globals::C' -// gdb-check:$3 = 97 -// gdb-command:print/d 'basic_types_globals::I8' +// gdbg-command:print 'basic_types_globals::C' +// gdbr-command:print C +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 'a' +// gdbg-command:print/d 'basic_types_globals::I8' +// gdbr-command:print I8 // gdb-check:$4 = 68 -// gdb-command:print 'basic_types_globals::I16' +// gdbg-command:print 'basic_types_globals::I16' +// gdbr-command:print I16 // gdb-check:$5 = -16 -// gdb-command:print 'basic_types_globals::I32' +// gdbg-command:print 'basic_types_globals::I32' +// gdbr-command:print I32 // gdb-check:$6 = -32 -// gdb-command:print 'basic_types_globals::I64' +// gdbg-command:print 'basic_types_globals::I64' +// gdbr-command:print I64 // gdb-check:$7 = -64 -// gdb-command:print 'basic_types_globals::U' +// gdbg-command:print 'basic_types_globals::U' +// gdbr-command:print U // gdb-check:$8 = 1 -// gdb-command:print/d 'basic_types_globals::U8' +// gdbg-command:print/d 'basic_types_globals::U8' +// gdbr-command:print U8 // gdb-check:$9 = 100 -// gdb-command:print 'basic_types_globals::U16' +// gdbg-command:print 'basic_types_globals::U16' +// gdbr-command:print U16 // gdb-check:$10 = 16 -// gdb-command:print 'basic_types_globals::U32' +// gdbg-command:print 'basic_types_globals::U32' +// gdbr-command:print U32 // gdb-check:$11 = 32 -// gdb-command:print 'basic_types_globals::U64' +// gdbg-command:print 'basic_types_globals::U64' +// gdbr-command:print U64 // gdb-check:$12 = 64 -// gdb-command:print 'basic_types_globals::F32' +// gdbg-command:print 'basic_types_globals::F32' +// gdbr-command:print F32 // gdb-check:$13 = 2.5 -// gdb-command:print 'basic_types_globals::F64' +// gdbg-command:print 'basic_types_globals::F64' +// gdbr-command:print F64 // gdb-check:$14 = 3.5 // gdb-command:continue diff --git a/src/test/debuginfo/basic-types-metadata.rs b/src/test/debuginfo/basic-types-metadata.rs index 1a6b605d9d06..8aec1a059bdc 100644 --- a/src/test/debuginfo/basic-types-metadata.rs +++ b/src/test/debuginfo/basic-types-metadata.rs @@ -45,20 +45,29 @@ // gdb-command:whatis fnptr // gdb-check:type = [...] (*)([...]) // gdb-command:info functions _yyy -// gdb-check:[...]![...]_yyy([...]); +// gdbg-check:[...]![...]_yyy([...]); +// gdbr-check:static fn basic_types_metadata::_yyy() -> !; // gdb-command:ptype closure_0 -// gdb-check: type = struct closure { -// gdb-check: -// gdb-check: } +// gdbr-check: type = struct closure +// gdbg-check: type = struct closure { +// gdbg-check: +// gdbg-check: } // gdb-command:ptype closure_1 -// gdb-check: type = struct closure { -// gdb-check: bool *__0; -// gdb-check: } +// gdbg-check: type = struct closure { +// gdbg-check: bool *__0; +// gdbg-check: } +// gdbr-check: type = struct closure ( +// gdbr-check: bool *, +// gdbr-check: ) // gdb-command:ptype closure_2 -// gdb-check: type = struct closure { -// gdb-check: bool *__0; -// gdb-check: isize *__1; -// gdb-check: } +// gdbg-check: type = struct closure { +// gdbg-check: bool *__0; +// gdbg-check: isize *__1; +// gdbg-check: } +// gdbr-check: type = struct closure ( +// gdbr-check: bool *, +// gdbr-check: isize *, +// gdbr-check: ) // // gdb-command:continue diff --git a/src/test/debuginfo/basic-types-mut-globals.rs b/src/test/debuginfo/basic-types-mut-globals.rs index 4ebd0c957702..62325aa53ab9 100644 --- a/src/test/debuginfo/basic-types-mut-globals.rs +++ b/src/test/debuginfo/basic-types-mut-globals.rs @@ -21,64 +21,94 @@ // gdb-command:run // Check initializers -// gdb-command:print 'basic_types_mut_globals::B' +// gdbg-command:print 'basic_types_mut_globals::B' +// gdbr-command:print B // gdb-check:$1 = false -// gdb-command:print 'basic_types_mut_globals::I' +// gdbg-command:print 'basic_types_mut_globals::I' +// gdbr-command:print I // gdb-check:$2 = -1 -// gdb-command:print 'basic_types_mut_globals::C' -// gdb-check:$3 = 97 -// gdb-command:print/d 'basic_types_mut_globals::I8' +// gdbg-command:print/d 'basic_types_mut_globals::C' +// gdbr-command:print C +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 'a' +// gdbg-command:print/d 'basic_types_mut_globals::I8' +// gdbr-command:print I8 // gdb-check:$4 = 68 -// gdb-command:print 'basic_types_mut_globals::I16' +// gdbg-command:print 'basic_types_mut_globals::I16' +// gdbr-command:print I16 // gdb-check:$5 = -16 -// gdb-command:print 'basic_types_mut_globals::I32' +// gdbg-command:print 'basic_types_mut_globals::I32' +// gdbr-command:print I32 // gdb-check:$6 = -32 -// gdb-command:print 'basic_types_mut_globals::I64' +// gdbg-command:print 'basic_types_mut_globals::I64' +// gdbr-command:print I64 // gdb-check:$7 = -64 -// gdb-command:print 'basic_types_mut_globals::U' +// gdbg-command:print 'basic_types_mut_globals::U' +// gdbr-command:print U // gdb-check:$8 = 1 -// gdb-command:print/d 'basic_types_mut_globals::U8' +// gdbg-command:print/d 'basic_types_mut_globals::U8' +// gdbr-command:print U8 // gdb-check:$9 = 100 -// gdb-command:print 'basic_types_mut_globals::U16' +// gdbg-command:print 'basic_types_mut_globals::U16' +// gdbr-command:print U16 // gdb-check:$10 = 16 -// gdb-command:print 'basic_types_mut_globals::U32' +// gdbg-command:print 'basic_types_mut_globals::U32' +// gdbr-command:print U32 // gdb-check:$11 = 32 -// gdb-command:print 'basic_types_mut_globals::U64' +// gdbg-command:print 'basic_types_mut_globals::U64' +// gdbr-command:print U64 // gdb-check:$12 = 64 -// gdb-command:print 'basic_types_mut_globals::F32' +// gdbg-command:print 'basic_types_mut_globals::F32' +// gdbr-command:print F32 // gdb-check:$13 = 2.5 -// gdb-command:print 'basic_types_mut_globals::F64' +// gdbg-command:print 'basic_types_mut_globals::F64' +// gdbr-command:print F64 // gdb-check:$14 = 3.5 // gdb-command:continue // Check new values -// gdb-command:print 'basic_types_mut_globals'::B +// gdbg-command:print 'basic_types_mut_globals'::B +// gdbr-command:print B // gdb-check:$15 = true -// gdb-command:print 'basic_types_mut_globals'::I +// gdbg-command:print 'basic_types_mut_globals'::I +// gdbr-command:print I // gdb-check:$16 = 2 -// gdb-command:print 'basic_types_mut_globals'::C -// gdb-check:$17 = 102 -// gdb-command:print/d 'basic_types_mut_globals'::I8 +// gdbg-command:print/d 'basic_types_mut_globals'::C +// gdbr-command:print C +// gdbg-check:$17 = 102 +// gdbr-check:$17 = 102 'f' +// gdbg-command:print/d 'basic_types_mut_globals'::I8 +// gdbr-command:print/d I8 // gdb-check:$18 = 78 -// gdb-command:print 'basic_types_mut_globals'::I16 +// gdbg-command:print 'basic_types_mut_globals'::I16 +// gdbr-command:print I16 // gdb-check:$19 = -26 -// gdb-command:print 'basic_types_mut_globals'::I32 +// gdbg-command:print 'basic_types_mut_globals'::I32 +// gdbr-command:print I32 // gdb-check:$20 = -12 -// gdb-command:print 'basic_types_mut_globals'::I64 +// gdbg-command:print 'basic_types_mut_globals'::I64 +// gdbr-command:print I64 // gdb-check:$21 = -54 -// gdb-command:print 'basic_types_mut_globals'::U +// gdbg-command:print 'basic_types_mut_globals'::U +// gdbr-command:print U // gdb-check:$22 = 5 -// gdb-command:print/d 'basic_types_mut_globals'::U8 +// gdbg-command:print/d 'basic_types_mut_globals'::U8 +// gdbr-command:print/d U8 // gdb-check:$23 = 20 -// gdb-command:print 'basic_types_mut_globals'::U16 +// gdbg-command:print 'basic_types_mut_globals'::U16 +// gdbr-command:print U16 // gdb-check:$24 = 32 -// gdb-command:print 'basic_types_mut_globals'::U32 +// gdbg-command:print 'basic_types_mut_globals'::U32 +// gdbr-command:print U32 // gdb-check:$25 = 16 -// gdb-command:print 'basic_types_mut_globals'::U64 +// gdbg-command:print 'basic_types_mut_globals'::U64 +// gdbr-command:print U64 // gdb-check:$26 = 128 -// gdb-command:print 'basic_types_mut_globals'::F32 +// gdbg-command:print 'basic_types_mut_globals'::F32 +// gdbr-command:print F32 // gdb-check:$27 = 5.75 -// gdb-command:print 'basic_types_mut_globals'::F64 +// gdbg-command:print 'basic_types_mut_globals'::F64 +// gdbr-command:print F64 // gdb-check:$28 = 9.25 #![allow(unused_variables)] diff --git a/src/test/debuginfo/basic-types.rs b/src/test/debuginfo/basic-types.rs index 998010832881..01ce5bd31626 100644 --- a/src/test/debuginfo/basic-types.rs +++ b/src/test/debuginfo/basic-types.rs @@ -26,7 +26,8 @@ // gdb-command:print i // gdb-check:$2 = -1 // gdb-command:print c -// gdb-check:$3 = 97 +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 'a' // gdb-command:print/d i8 // gdb-check:$4 = 68 // gdb-command:print i16 diff --git a/src/test/debuginfo/borrowed-basic.rs b/src/test/debuginfo/borrowed-basic.rs index bada77b66293..f6c0ff09efe9 100644 --- a/src/test/debuginfo/borrowed-basic.rs +++ b/src/test/debuginfo/borrowed-basic.rs @@ -25,10 +25,12 @@ // gdb-check:$2 = -1 // gdb-command:print *char_ref -// gdb-check:$3 = 97 +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 'a' // gdb-command:print *i8_ref -// gdb-check:$4 = 68 'D' +// gdbg-check:$4 = 68 'D' +// gdbr-check:$4 = 68 // gdb-command:print *i16_ref // gdb-check:$5 = -16 @@ -43,7 +45,8 @@ // gdb-check:$8 = 1 // gdb-command:print *u8_ref -// gdb-check:$9 = 100 'd' +// gdbg-check:$9 = 100 'd' +// gdbr-check:$9 = 100 // gdb-command:print *u16_ref // gdb-check:$10 = 16 diff --git a/src/test/debuginfo/borrowed-c-style-enum.rs b/src/test/debuginfo/borrowed-c-style-enum.rs index c80783ef3106..d6f379634be5 100644 --- a/src/test/debuginfo/borrowed-c-style-enum.rs +++ b/src/test/debuginfo/borrowed-c-style-enum.rs @@ -17,13 +17,16 @@ // gdb-command:run // gdb-command:print *the_a_ref -// gdb-check:$1 = TheA +// gdbg-check:$1 = TheA +// gdbr-check:$1 = borrowed_c_style_enum::ABC::TheA // gdb-command:print *the_b_ref -// gdb-check:$2 = TheB +// gdbg-check:$2 = TheB +// gdbr-check:$2 = borrowed_c_style_enum::ABC::TheB // gdb-command:print *the_c_ref -// gdb-check:$3 = TheC +// gdbg-check:$3 = TheC +// gdbr-check:$3 = borrowed_c_style_enum::ABC::TheC // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/borrowed-enum.rs b/src/test/debuginfo/borrowed-enum.rs index b21574e32866..ddc29c643027 100644 --- a/src/test/debuginfo/borrowed-enum.rs +++ b/src/test/debuginfo/borrowed-enum.rs @@ -18,13 +18,16 @@ // gdb-command:run // gdb-command:print *the_a_ref -// gdb-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbr-check:$1 = borrowed_enum::ABC::TheA{x: 0, y: 8970181431921507452} // gdb-command:print *the_b_ref -// gdb-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}} +// gdbr-check:$2 = borrowed_enum::ABC::TheB(0, 286331153, 286331153) // gdb-command:print *univariant_ref -// gdb-check:$3 = {{__0 = 4820353753753434}} +// gdbg-check:$3 = {{__0 = 4820353753753434}} +// gdbr-check:$3 = borrowed_enum::Univariant::TheOnlyCase(4820353753753434) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/borrowed-struct.rs b/src/test/debuginfo/borrowed-struct.rs index ab41185cb739..01428e515e27 100644 --- a/src/test/debuginfo/borrowed-struct.rs +++ b/src/test/debuginfo/borrowed-struct.rs @@ -16,7 +16,8 @@ // gdb-command:run // gdb-command:print *stack_val_ref -// gdb-check:$1 = {x = 10, y = 23.5} +// gdbg-check:$1 = {x = 10, y = 23.5} +// gdbr-check:$1 = borrowed_struct::SomeStruct {x: 10, y: 23.5} // gdb-command:print *stack_val_interior_ref_1 // gdb-check:$2 = 10 @@ -25,10 +26,12 @@ // gdb-check:$3 = 23.5 // gdb-command:print *ref_to_unnamed -// gdb-check:$4 = {x = 11, y = 24.5} +// gdbg-check:$4 = {x = 11, y = 24.5} +// gdbr-check:$4 = borrowed_struct::SomeStruct {x: 11, y: 24.5} // gdb-command:print *unique_val_ref -// gdb-check:$5 = {x = 13, y = 26.5} +// gdbg-check:$5 = {x = 13, y = 26.5} +// gdbr-check:$5 = borrowed_struct::SomeStruct {x: 13, y: 26.5} // gdb-command:print *unique_val_interior_ref_1 // gdb-check:$6 = 13 diff --git a/src/test/debuginfo/borrowed-tuple.rs b/src/test/debuginfo/borrowed-tuple.rs index e3da3934f6d6..17db88ee37f5 100644 --- a/src/test/debuginfo/borrowed-tuple.rs +++ b/src/test/debuginfo/borrowed-tuple.rs @@ -17,13 +17,16 @@ // gdb-command:run // gdb-command:print *stack_val_ref -// gdb-check:$1 = {__0 = -14, __1 = -19} +// gdbg-check:$1 = {__0 = -14, __1 = -19} +// gdbr-check:$1 = (-14, -19) // gdb-command:print *ref_to_unnamed -// gdb-check:$2 = {__0 = -15, __1 = -20} +// gdbg-check:$2 = {__0 = -15, __1 = -20} +// gdbr-check:$2 = (-15, -20) // gdb-command:print *unique_val_ref -// gdb-check:$3 = {__0 = -17, __1 = -22} +// gdbg-check:$3 = {__0 = -17, __1 = -22} +// gdbr-check:$3 = (-17, -22) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/borrowed-unique-basic.rs b/src/test/debuginfo/borrowed-unique-basic.rs index 88af94c53628..9e95498b0c30 100644 --- a/src/test/debuginfo/borrowed-unique-basic.rs +++ b/src/test/debuginfo/borrowed-unique-basic.rs @@ -26,7 +26,8 @@ // gdb-check:$2 = -1 // gdb-command:print *char_ref -// gdb-check:$3 = 97 +// gdbg-check:$3 = 97 +// gdbr-check:$3 = 97 'a' // gdb-command:print/d *i8_ref // gdb-check:$4 = 68 diff --git a/src/test/debuginfo/box.rs b/src/test/debuginfo/box.rs index 106d0b243eb2..98c09fe09de8 100644 --- a/src/test/debuginfo/box.rs +++ b/src/test/debuginfo/box.rs @@ -19,7 +19,8 @@ // gdb-command:print *a // gdb-check:$1 = 1 // gdb-command:print *b -// gdb-check:$2 = {__0 = 2, __1 = 3.5} +// gdbg-check:$2 = {__0 = 2, __1 = 3.5} +// gdbr-check:$2 = (2, 3.5) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/boxed-struct.rs b/src/test/debuginfo/boxed-struct.rs index dd543405e4c2..ac091b4a533d 100644 --- a/src/test/debuginfo/boxed-struct.rs +++ b/src/test/debuginfo/boxed-struct.rs @@ -17,10 +17,12 @@ // gdb-command:run // gdb-command:print *unique -// gdb-check:$1 = {x = 99, y = 999, z = 9999, w = 99999} +// gdbg-check:$1 = {x = 99, y = 999, z = 9999, w = 99999} +// gdbr-check:$1 = boxed_struct::StructWithSomePadding {x: 99, y: 999, z: 9999, w: 99999} // gdb-command:print *unique_dtor -// gdb-check:$2 = {x = 77, y = 777, z = 7777, w = 77777} +// gdbg-check:$2 = {x = 77, y = 777, z = 7777, w = 77777} +// gdbr-check:$2 = boxed_struct::StructWithDestructor {x: 77, y: 777, z: 7777, w: 77777} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/by-value-non-immediate-argument.rs b/src/test/debuginfo/by-value-non-immediate-argument.rs index a329ef6d0e09..6d821dbc155d 100644 --- a/src/test/debuginfo/by-value-non-immediate-argument.rs +++ b/src/test/debuginfo/by-value-non-immediate-argument.rs @@ -18,11 +18,13 @@ // gdb-command:run // gdb-command:print s -// gdb-check:$1 = {a = 1, b = 2.5} +// gdbg-check:$1 = {a = 1, b = 2.5} +// gdbr-check:$1 = by_value_non_immediate_argument::Struct {a: 1, b: 2.5} // gdb-command:continue // gdb-command:print x -// gdb-check:$2 = {a = 3, b = 4.5} +// gdbg-check:$2 = {a = 3, b = 4.5} +// gdbr-check:$2 = by_value_non_immediate_argument::Struct {a: 3, b: 4.5} // gdb-command:print y // gdb-check:$3 = 5 // gdb-command:print z @@ -30,15 +32,18 @@ // gdb-command:continue // gdb-command:print a -// gdb-check:$5 = {__0 = 7, __1 = 8, __2 = 9.5, __3 = 10.5} +// gdbg-check:$5 = {__0 = 7, __1 = 8, __2 = 9.5, __3 = 10.5} +// gdbr-check:$5 = (7, 8, 9.5, 10.5) // gdb-command:continue // gdb-command:print a -// gdb-check:$6 = {__0 = 11.5, __1 = 12.5, __2 = 13, __3 = 14} +// gdbg-check:$6 = {__0 = 11.5, __1 = 12.5, __2 = 13, __3 = 14} +// gdbr-check:$6 = by_value_non_immediate_argument::Newtype (11.5, 12.5, 13, 14) // gdb-command:continue // gdb-command:print x -// gdb-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbg-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbr-check:$7 = by_value_non_immediate_argument::Enum::Case1{x: 0, y: 8970181431921507452} // gdb-command:continue diff --git a/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs b/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs index a768bfdd1676..c14f8c7b354f 100644 --- a/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs +++ b/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs @@ -21,11 +21,13 @@ // gdb-command:continue // gdb-command:print self -// gdb-check:$2 = {x = 2222, y = 3333} +// gdbg-check:$2 = {x = 2222, y = 3333} +// gdbr-check:$2 = by_value_self_argument_in_trait_impl::Struct {x: 2222, y: 3333} // gdb-command:continue // gdb-command:print self -// gdb-check:$3 = {__0 = 4444.5, __1 = 5555, __2 = 6666, __3 = 7777.5} +// gdbg-check:$3 = {__0 = 4444.5, __1 = 5555, __2 = 6666, __3 = 7777.5} +// gdbr-check:$3 = (4444.5, 5555, 6666, 7777.5) // gdb-command:continue diff --git a/src/test/debuginfo/c-style-enum-in-composite.rs b/src/test/debuginfo/c-style-enum-in-composite.rs index 83a22edc96fe..004e15d1cc6c 100644 --- a/src/test/debuginfo/c-style-enum-in-composite.rs +++ b/src/test/debuginfo/c-style-enum-in-composite.rs @@ -18,26 +18,32 @@ // gdb-command:run // gdb-command:print tuple_interior_padding -// gdb-check:$1 = {__0 = 0, __1 = OneHundred} +// gdbg-check:$1 = {__0 = 0, __1 = OneHundred} +// gdbr-check:$1 = (0, c_style_enum_in_composite::AnEnum::OneHundred) // gdb-command:print tuple_padding_at_end -// gdb-check:$2 = {__0 = {__0 = 1, __1 = OneThousand}, __1 = 2} +// gdbg-check:$2 = {__0 = {__0 = 1, __1 = OneThousand}, __1 = 2} +// gdbr-check:$2 = ((1, c_style_enum_in_composite::AnEnum::OneThousand), 2) // gdb-command:print tuple_different_enums -// gdb-check:$3 = {__0 = OneThousand, __1 = MountainView, __2 = OneMillion, __3 = Vienna} +// gdbg-check:$3 = {__0 = OneThousand, __1 = MountainView, __2 = OneMillion, __3 = Vienna} +// gdbr-check:$3 = (c_style_enum_in_composite::AnEnum::OneThousand, c_style_enum_in_composite::AnotherEnum::MountainView, c_style_enum_in_composite::AnEnum::OneMillion, c_style_enum_in_composite::AnotherEnum::Vienna) // gdb-command:print padded_struct -// gdb-check:$4 = {a = 3, b = OneMillion, c = 4, d = Toronto, e = 5} +// gdbg-check:$4 = {a = 3, b = OneMillion, c = 4, d = Toronto, e = 5} +// gdbr-check:$4 = c_style_enum_in_composite::PaddedStruct {a: 3, b: c_style_enum_in_composite::AnEnum::OneMillion, c: 4, d: c_style_enum_in_composite::AnotherEnum::Toronto, e: 5} // gdb-command:print packed_struct -// gdb-check:$5 = {a = 6, b = OneHundred, c = 7, d = Vienna, e = 8} +// gdbg-check:$5 = {a = 6, b = OneHundred, c = 7, d = Vienna, e = 8} +// gdbr-check:$5 = c_style_enum_in_composite::PackedStruct {a: 6, b: c_style_enum_in_composite::AnEnum::OneHundred, c: 7, d: c_style_enum_in_composite::AnotherEnum::Vienna, e: 8} // gdb-command:print non_padded_struct -// gdb-check:$6 = {a = OneMillion, b = MountainView, c = OneThousand, d = Toronto} +// gdbg-check:$6 = {a = OneMillion, b = MountainView, c = OneThousand, d = Toronto} +// gdbr-check:$6 = c_style_enum_in_composite::NonPaddedStruct {a: c_style_enum_in_composite::AnEnum::OneMillion, b: c_style_enum_in_composite::AnotherEnum::MountainView, c: c_style_enum_in_composite::AnEnum::OneThousand, d: c_style_enum_in_composite::AnotherEnum::Toronto} // gdb-command:print struct_with_drop -// gdb-check:$7 = {__0 = {a = OneHundred, b = Vienna}, __1 = 9} - +// gdbg-check:$7 = {__0 = {a = OneHundred, b = Vienna}, __1 = 9} +// gdbr-check:$7 = (c_style_enum_in_composite::StructWithDrop {a: c_style_enum_in_composite::AnEnum::OneHundred, b: c_style_enum_in_composite::AnotherEnum::Vienna}, 9) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs index dbd336d2dc68..2452c18f5434 100644 --- a/src/test/debuginfo/c-style-enum.rs +++ b/src/test/debuginfo/c-style-enum.rs @@ -16,60 +16,82 @@ // === GDB TESTS =================================================================================== // gdb-command:print 'c_style_enum::SINGLE_VARIANT' -// gdb-check:$1 = TheOnlyVariant +// gdbg-check:$1 = TheOnlyVariant +// gdbr-check:$1 = c_style_enum::SingleVariant::TheOnlyVariant // gdb-command:print 'c_style_enum::AUTO_ONE' -// gdb-check:$2 = One +// gdbg-check:$2 = One +// gdbr-check:$2 = c_style_enum::AutoDiscriminant::One // gdb-command:print 'c_style_enum::AUTO_TWO' -// gdb-check:$3 = One +// gdbg-check:$3 = One +// gdbr-check:$3 = c_style_enum::AutoDiscriminant::One // gdb-command:print 'c_style_enum::AUTO_THREE' -// gdb-check:$4 = One +// gdbg-check:$4 = One +// gdbr-check:$4 = c_style_enum::AutoDiscriminant::One // gdb-command:print 'c_style_enum::MANUAL_ONE' -// gdb-check:$5 = OneHundred +// gdbg-check:$5 = OneHundred +// gdbr-check:$5 = c_style_enum::ManualDiscriminant::OneHundred // gdb-command:print 'c_style_enum::MANUAL_TWO' -// gdb-check:$6 = OneHundred +// gdbg-check:$6 = OneHundred +// gdbr-check:$6 = c_style_enum::ManualDiscriminant::OneHundred // gdb-command:print 'c_style_enum::MANUAL_THREE' -// gdb-check:$7 = OneHundred +// gdbg-check:$7 = OneHundred +// gdbr-check:$7 = c_style_enum::ManualDiscriminant::OneHundred // gdb-command:run // gdb-command:print auto_one -// gdb-check:$8 = One +// gdbg-check:$8 = One +// gdbr-check:$8 = c_style_enum::AutoDiscriminant::One // gdb-command:print auto_two -// gdb-check:$9 = Two +// gdbg-check:$9 = Two +// gdbr-check:$9 = c_style_enum::AutoDiscriminant::Two // gdb-command:print auto_three -// gdb-check:$10 = Three +// gdbg-check:$10 = Three +// gdbr-check:$10 = c_style_enum::AutoDiscriminant::Three // gdb-command:print manual_one_hundred -// gdb-check:$11 = OneHundred +// gdbg-check:$11 = OneHundred +// gdbr-check:$11 = c_style_enum::ManualDiscriminant::OneHundred // gdb-command:print manual_one_thousand -// gdb-check:$12 = OneThousand +// gdbg-check:$12 = OneThousand +// gdbr-check:$12 = c_style_enum::ManualDiscriminant::OneThousand // gdb-command:print manual_one_million -// gdb-check:$13 = OneMillion +// gdbg-check:$13 = OneMillion +// gdbr-check:$13 = c_style_enum::ManualDiscriminant::OneMillion // gdb-command:print single_variant -// gdb-check:$14 = TheOnlyVariant +// gdbg-check:$14 = TheOnlyVariant +// gdbr-check:$14 = c_style_enum::SingleVariant::TheOnlyVariant -// gdb-command:print 'c_style_enum::AUTO_TWO' -// gdb-check:$15 = Two +// gdbg-command:print 'c_style_enum::AUTO_TWO' +// gdbr-command:print AUTO_TWO +// gdbg-check:$15 = Two +// gdbr-check:$15 = c_style_enum::AutoDiscriminant::Two -// gdb-command:print 'c_style_enum::AUTO_THREE' -// gdb-check:$16 = Three +// gdbg-command:print 'c_style_enum::AUTO_THREE' +// gdbr-command:print AUTO_THREE +// gdbg-check:$16 = Three +// gdbr-check:$16 = c_style_enum::AutoDiscriminant::Three -// gdb-command:print 'c_style_enum::MANUAL_TWO' -// gdb-check:$17 = OneThousand +// gdbg-command:print 'c_style_enum::MANUAL_TWO' +// gdbr-command:print MANUAL_TWO +// gdbg-check:$17 = OneThousand +// gdbr-check:$17 = c_style_enum::ManualDiscriminant::OneThousand -// gdb-command:print 'c_style_enum::MANUAL_THREE' -// gdb-check:$18 = OneMillion +// gdbg-command:print 'c_style_enum::MANUAL_THREE' +// gdbr-command:print MANUAL_THREE +// gdbg-check:$18 = OneMillion +// gdbr-check:$18 = c_style_enum::ManualDiscriminant::OneMillion // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/cross-crate-spans.rs b/src/test/debuginfo/cross-crate-spans.rs index 544fe2c66d5e..28728df92805 100644 --- a/src/test/debuginfo/cross-crate-spans.rs +++ b/src/test/debuginfo/cross-crate-spans.rs @@ -25,7 +25,8 @@ extern crate cross_crate_spans; // gdb-command:run // gdb-command:print result -// gdb-check:$1 = {__0 = 17, __1 = 17} +// gdbg-check:$1 = {__0 = 17, __1 = 17} +// gdbr-check:$1 = (17, 17) // gdb-command:print a_variable // gdb-check:$2 = 123456789 // gdb-command:print another_variable @@ -33,7 +34,8 @@ extern crate cross_crate_spans; // gdb-command:continue // gdb-command:print result -// gdb-check:$4 = {__0 = 1212, __1 = 1212} +// gdbg-check:$4 = {__0 = 1212, __1 = 1212} +// gdbr-check:$4 = (1212, 1212) // gdb-command:print a_variable // gdb-check:$5 = 123456789 // gdb-command:print another_variable diff --git a/src/test/debuginfo/destructured-fn-argument.rs b/src/test/debuginfo/destructured-fn-argument.rs index 954a7abe6323..efa9ee59b22b 100644 --- a/src/test/debuginfo/destructured-fn-argument.rs +++ b/src/test/debuginfo/destructured-fn-argument.rs @@ -33,13 +33,15 @@ // gdb-command:print a // gdb-check:$6 = 5 // gdb-command:print b -// gdb-check:$7 = {__0 = 6, __1 = 7} +// gdbg-check:$7 = {__0 = 6, __1 = 7} +// gdbr-check:$7 = (6, 7) // gdb-command:continue // gdb-command:print h // gdb-check:$8 = 8 // gdb-command:print i -// gdb-check:$9 = {a = 9, b = 10} +// gdbg-check:$9 = {a = 9, b = 10} +// gdbr-check:$9 = destructured_fn_argument::Struct {a: 9, b: 10} // gdb-command:print j // gdb-check:$10 = 11 // gdb-command:continue @@ -65,7 +67,8 @@ // gdb-command:print q // gdb-check:$17 = 20 // gdb-command:print r -// gdb-check:$18 = {a = 21, b = 22} +// gdbg-check:$18 = {a = 21, b = 22} +// gdbr-check:$18 = destructured_fn_argument::Struct {a: 21, b: 22} // gdb-command:continue // gdb-command:print s @@ -95,11 +98,13 @@ // gdb-command:continue // gdb-command:print aa -// gdb-check:$30 = {__0 = 34, __1 = 35} +// gdbg-check:$30 = {__0 = 34, __1 = 35} +// gdbr-check:$30 = (34, 35) // gdb-command:continue // gdb-command:print bb -// gdb-check:$31 = {__0 = 36, __1 = 37} +// gdbg-check:$31 = {__0 = 36, __1 = 37} +// gdbr-check:$31 = (36, 37) // gdb-command:continue // gdb-command:print cc @@ -107,17 +112,20 @@ // gdb-command:continue // gdb-command:print dd -// gdb-check:$33 = {__0 = 40, __1 = 41, __2 = 42} +// gdbg-check:$33 = {__0 = 40, __1 = 41, __2 = 42} +// gdbr-check:$33 = (40, 41, 42) // gdb-command:continue // gdb-command:print *ee -// gdb-check:$34 = {__0 = 43, __1 = 44, __2 = 45} +// gdbg-check:$34 = {__0 = 43, __1 = 44, __2 = 45} +// gdbr-check:$34 = (43, 44, 45) // gdb-command:continue // gdb-command:print *ff // gdb-check:$35 = 46 // gdb-command:print gg -// gdb-check:$36 = {__0 = 47, __1 = 48} +// gdbg-check:$36 = {__0 = 47, __1 = 48} +// gdbr-check:$36 = (47, 48) // gdb-command:continue // gdb-command:print *hh diff --git a/src/test/debuginfo/destructured-for-loop-variable.rs b/src/test/debuginfo/destructured-for-loop-variable.rs index a34d5d6adbfc..e973c22fd4a8 100644 --- a/src/test/debuginfo/destructured-for-loop-variable.rs +++ b/src/test/debuginfo/destructured-for-loop-variable.rs @@ -73,11 +73,13 @@ // gdb-command:continue // gdb-command:print simple_struct_ident -// gdb-check:$23 = {x = 3537, y = 35437.5, z = true} +// gdbg-check:$23 = {x = 3537, y = 35437.5, z = true} +// gdbr-check:$23 = destructured_for_loop_variable::Struct {x: 3537, y: 35437.5, z: true} // gdb-command:continue // gdb-command:print simple_tuple_ident -// gdb-check:$24 = {__0 = 34903493, __1 = 232323} +// gdbg-check:$24 = {__0 = 34903493, __1 = 232323} +// gdbr-check:$24 = (34903493, 232323) // gdb-command:continue // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/destructured-local.rs b/src/test/debuginfo/destructured-local.rs index a43e4546d4f8..1f18b77ab8f6 100644 --- a/src/test/debuginfo/destructured-local.rs +++ b/src/test/debuginfo/destructured-local.rs @@ -31,12 +31,14 @@ // gdb-command:print f // gdb-check:$6 = 5 // gdb-command:print g -// gdb-check:$7 = {__0 = 6, __1 = 7} +// gdbg-check:$7 = {__0 = 6, __1 = 7} +// gdbr-check:$7 = (6, 7) // gdb-command:print h // gdb-check:$8 = 8 // gdb-command:print i -// gdb-check:$9 = {a = 9, b = 10} +// gdbg-check:$9 = {a = 9, b = 10} +// gdbr-check:$9 = destructured_local::Struct {a: 9, b: 10} // gdb-command:print j // gdb-check:$10 = 11 @@ -58,7 +60,8 @@ // gdb-command:print q // gdb-check:$17 = 20 // gdb-command:print r -// gdb-check:$18 = {a = 21, b = 22} +// gdbg-check:$18 = {a = 21, b = 22} +// gdbr-check:$18 = destructured_local::Struct {a: 21, b: 22} // gdb-command:print s // gdb-check:$19 = 24 @@ -85,25 +88,30 @@ // gdb-check:$29 = 33 // gdb-command:print aa -// gdb-check:$30 = {__0 = 34, __1 = 35} +// gdbg-check:$30 = {__0 = 34, __1 = 35} +// gdbr-check:$30 = (34, 35) // gdb-command:print bb -// gdb-check:$31 = {__0 = 36, __1 = 37} +// gdbg-check:$31 = {__0 = 36, __1 = 37} +// gdbr-check:$31 = (36, 37) // gdb-command:print cc // gdb-check:$32 = 38 // gdb-command:print dd -// gdb-check:$33 = {__0 = 40, __1 = 41, __2 = 42} +// gdbg-check:$33 = {__0 = 40, __1 = 41, __2 = 42} +// gdbr-check:$33 = (40, 41, 42) // gdb-command:print *ee -// gdb-check:$34 = {__0 = 43, __1 = 44, __2 = 45} +// gdbg-check:$34 = {__0 = 43, __1 = 44, __2 = 45} +// gdbr-check:$34 = (43, 44, 45) // gdb-command:print *ff // gdb-check:$35 = 46 // gdb-command:print gg -// gdb-check:$36 = {__0 = 47, __1 = 48} +// gdbg-check:$36 = {__0 = 47, __1 = 48} +// gdbr-check:$36 = (47, 48) // gdb-command:print *hh // gdb-check:$37 = 50 diff --git a/src/test/debuginfo/evec-in-struct.rs b/src/test/debuginfo/evec-in-struct.rs index 8624a0cba025..2e151577590b 100644 --- a/src/test/debuginfo/evec-in-struct.rs +++ b/src/test/debuginfo/evec-in-struct.rs @@ -17,18 +17,23 @@ // gdb-command:run // gdb-command:print no_padding1 -// gdb-check:$1 = {x = {0, 1, 2}, y = -3, z = {4.5, 5.5}} +// gdbg-check:$1 = {x = {0, 1, 2}, y = -3, z = {4.5, 5.5}} +// gdbr-check:$1 = evec_in_struct::NoPadding1 {x: [0, 1, 2], y: -3, z: [4.5, 5.5]} // gdb-command:print no_padding2 -// gdb-check:$2 = {x = {6, 7, 8}, y = {{9, 10}, {11, 12}}} +// gdbg-check:$2 = {x = {6, 7, 8}, y = {{9, 10}, {11, 12}}} +// gdbr-check:$2 = evec_in_struct::NoPadding2 {x: [6, 7, 8], y: [[9, 10], [11, 12]]} // gdb-command:print struct_internal_padding -// gdb-check:$3 = {x = {13, 14}, y = {15, 16}} +// gdbg-check:$3 = {x = {13, 14}, y = {15, 16}} +// gdbr-check:$3 = evec_in_struct::StructInternalPadding {x: [13, 14], y: [15, 16]} // gdb-command:print single_vec -// gdb-check:$4 = {x = {17, 18, 19, 20, 21}} +// gdbg-check:$4 = {x = {17, 18, 19, 20, 21}} +// gdbr-check:$4 = evec_in_struct::SingleVec {x: [17, 18, 19, 20, 21]} // gdb-command:print struct_padded_at_end -// gdb-check:$5 = {x = {22, 23}, y = {24, 25}} +// gdbg-check:$5 = {x = {22, 23}, y = {24, 25}} +// gdbr-check:$5 = evec_in_struct::StructPaddedAtEnd {x: [22, 23], y: [24, 25]} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/extern-c-fn.rs b/src/test/debuginfo/extern-c-fn.rs index c93db41dc55b..01901b2c42b8 100644 --- a/src/test/debuginfo/extern-c-fn.rs +++ b/src/test/debuginfo/extern-c-fn.rs @@ -16,7 +16,8 @@ // gdb-command:run // gdb-command:print s -// gdb-check:$1 = [...]"abcd" +// gdbg-check:$1 = [...]"abcd" +// gdbr-check:$1 = [...]"abcd\000" // gdb-command:print len // gdb-check:$2 = 20 // gdb-command:print local0 diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs index 57654acaf73d..21fdc4e5e88a 100644 --- a/src/test/debuginfo/function-arg-initialization.rs +++ b/src/test/debuginfo/function-arg-initialization.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + // min-lldb-version: 310 // This test case checks if function arguments already have the correct value @@ -34,9 +36,11 @@ // NON IMMEDIATE ARGS // gdb-command:print a -// gdb-check:$4 = {a = 3, b = 4, c = 5, d = 6, e = 7, f = 8, g = 9, h = 10} +// gdbg-check:$4 = {a = 3, b = 4, c = 5, d = 6, e = 7, f = 8, g = 9, h = 10} +// gdbt-check:$4 = function_arg_initialization::BigStruct {a: 3, b: 4, c: 5, d: 6, e: 7, f: 8, g: 9, h: 10} // gdb-command:print b -// gdb-check:$5 = {a = 11, b = 12, c = 13, d = 14, e = 15, f = 16, g = 17, h = 18} +// gdbg-check:$5 = {a = 11, b = 12, c = 13, d = 14, e = 15, f = 16, g = 17, h = 18} +// gdbt-check:$5 = function_arg_initialization::BigStruct {a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18} // gdb-command:continue // BINDING diff --git a/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs b/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs index 81743a367e40..158a1f17fc03 100644 --- a/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs +++ b/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs @@ -26,13 +26,16 @@ // gdb-check:$2 = EmptyStruct // gdb-command: print c_style_enum1 -// gdb-check:$3 = CStyleEnumVar1 +// gdbg-check:$3 = CStyleEnumVar1 +// gdbr-check:$3 = gdb_pretty_struct_and_enums_pre_gdb_7_7::CStyleEnum::CStyleEnumVar1 // gdb-command: print c_style_enum2 -// gdb-check:$4 = CStyleEnumVar2 +// gdbg-check:$4 = CStyleEnumVar2 +// gdbr-check:$4 = gdb_pretty_struct_and_enums_pre_gdb_7_7::CStyleEnum::CStyleEnumVar2 // gdb-command: print c_style_enum3 -// gdb-check:$5 = CStyleEnumVar3 +// gdbg-check:$5 = CStyleEnumVar3 +// gdbr-check:$5 = gdb_pretty_struct_and_enums_pre_gdb_7_7::CStyleEnum::CStyleEnumVar3 #![allow(dead_code, unused_variables)] diff --git a/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs b/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs index 3115b3f7e761..1fc05b3752f0 100644 --- a/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs +++ b/src/test/debuginfo/generic-enum-with-different-disr-sizes.rs @@ -18,22 +18,37 @@ // gdb-command:run // gdb-command:print eight_bytes1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Variant1, __0 = 100}, {RUST$ENUM$DISR = Variant1, __0 = 100}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Variant1, __0 = 100}, {RUST$ENUM$DISR = Variant1, __0 = 100}} +// gdbr-check:$1 = generic_enum_with_different_disr_sizes::Enum::Variant1(100) + // gdb-command:print four_bytes1 -// gdb-check:$2 = {{RUST$ENUM$DISR = Variant1, __0 = 101}, {RUST$ENUM$DISR = Variant1, __0 = 101}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = Variant1, __0 = 101}, {RUST$ENUM$DISR = Variant1, __0 = 101}} +// gdbr-check:$2 = generic_enum_with_different_disr_sizes::Enum::Variant1(101) + // gdb-command:print two_bytes1 -// gdb-check:$3 = {{RUST$ENUM$DISR = Variant1, __0 = 102}, {RUST$ENUM$DISR = Variant1, __0 = 102}} +// gdbg-check:$3 = {{RUST$ENUM$DISR = Variant1, __0 = 102}, {RUST$ENUM$DISR = Variant1, __0 = 102}} +// gdbr-check:$3 = generic_enum_with_different_disr_sizes::Enum::Variant1(102) + // gdb-command:print one_byte1 -// gdb-check:$4 = {{RUST$ENUM$DISR = Variant1, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant1, __0 = 65 'A'}} +// gdbg-check:$4 = {{RUST$ENUM$DISR = Variant1, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant1, __0 = 65 'A'}} +// gdbr-check:$4 = generic_enum_with_different_disr_sizes::Enum::Variant1(65) + // gdb-command:print eight_bytes2 -// gdb-check:$5 = {{RUST$ENUM$DISR = Variant2, __0 = 100}, {RUST$ENUM$DISR = Variant2, __0 = 100}} +// gdbg-check:$5 = {{RUST$ENUM$DISR = Variant2, __0 = 100}, {RUST$ENUM$DISR = Variant2, __0 = 100}} +// gdbr-check:$5 = generic_enum_with_different_disr_sizes::Enum::Variant2(100) + // gdb-command:print four_bytes2 -// gdb-check:$6 = {{RUST$ENUM$DISR = Variant2, __0 = 101}, {RUST$ENUM$DISR = Variant2, __0 = 101}} +// gdbg-check:$6 = {{RUST$ENUM$DISR = Variant2, __0 = 101}, {RUST$ENUM$DISR = Variant2, __0 = 101}} +// gdbr-check:$6 = generic_enum_with_different_disr_sizes::Enum::Variant2(101) + // gdb-command:print two_bytes2 -// gdb-check:$7 = {{RUST$ENUM$DISR = Variant2, __0 = 102}, {RUST$ENUM$DISR = Variant2, __0 = 102}} +// gdbg-check:$7 = {{RUST$ENUM$DISR = Variant2, __0 = 102}, {RUST$ENUM$DISR = Variant2, __0 = 102}} +// gdbr-check:$7 = generic_enum_with_different_disr_sizes::Enum::Variant2(102) + // gdb-command:print one_byte2 -// gdb-check:$8 = {{RUST$ENUM$DISR = Variant2, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant2, __0 = 65 'A'}} +// gdbg-check:$8 = {{RUST$ENUM$DISR = Variant2, __0 = 65 'A'}, {RUST$ENUM$DISR = Variant2, __0 = 65 'A'}} +// gdbr-check:$8 = generic_enum_with_different_disr_sizes::Enum::Variant2(65) // gdb-command:continue diff --git a/src/test/debuginfo/generic-function.rs b/src/test/debuginfo/generic-function.rs index 415dd36212a4..f1bfc08915ed 100644 --- a/src/test/debuginfo/generic-function.rs +++ b/src/test/debuginfo/generic-function.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + // min-lldb-version: 310 // compile-flags:-g @@ -21,7 +23,8 @@ // gdb-command:print *t1 // gdb-check:$2 = 2.5 // gdb-command:print ret -// gdb-check:$3 = {__0 = {__0 = 1, __1 = 2.5}, __1 = {__0 = 2.5, __1 = 1}} +// gdbg-check:$3 = {__0 = {__0 = 1, __1 = 2.5}, __1 = {__0 = 2.5, __1 = 1}} +// gdbr-check:$3 = ((1, 2.5), (2.5, 1)) // gdb-command:continue // gdb-command:print *t0 @@ -29,15 +32,18 @@ // gdb-command:print *t1 // gdb-check:$5 = 4 // gdb-command:print ret -// gdb-check:$6 = {__0 = {__0 = 3.5, __1 = 4}, __1 = {__0 = 4, __1 = 3.5}} +// gdbg-check:$6 = {__0 = {__0 = 3.5, __1 = 4}, __1 = {__0 = 4, __1 = 3.5}} +// gdbr-check:$6 = ((3.5, 4), (4, 3.5)) // gdb-command:continue // gdb-command:print *t0 // gdb-check:$7 = 5 // gdb-command:print *t1 -// gdb-check:$8 = {a = 6, b = 7.5} +// gdbg-check:$8 = {a = 6, b = 7.5} +// gdbr-check:$8 = generic_function::Struct {a: 6, b: 7.5} // gdb-command:print ret -// gdb-check:$9 = {__0 = {__0 = 5, __1 = {a = 6, b = 7.5}}, __1 = {__0 = {a = 6, b = 7.5}, __1 = 5}} +// gdbg-check:$9 = {__0 = {__0 = 5, __1 = {a = 6, b = 7.5}}, __1 = {__0 = {a = 6, b = 7.5}, __1 = 5}} +// gdbr-check:$9 = ((5, generic_function::Struct {a: 6, b: 7.5}), (generic_function::Struct {a: 6, b: 7.5}, 5)) // gdb-command:continue diff --git a/src/test/debuginfo/generic-method-on-generic-struct.rs b/src/test/debuginfo/generic-method-on-generic-struct.rs index 968cb2e15971..4f3f6dfc821e 100644 --- a/src/test/debuginfo/generic-method-on-generic-struct.rs +++ b/src/test/debuginfo/generic-method-on-generic-struct.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = {__0 = 8888, __1 = -8888}} +// gdbg-check:$1 = {x = {__0 = 8888, __1 = -8888}} +// gdbr-check:$1 = generic_method_on_generic_struct::Struct<(u32, i32)> {x: (8888, -8888)} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = {__0 = 8888, __1 = -8888}} +// gdbg-check:$4 = {x = {__0 = 8888, __1 = -8888}} +// gdbr-check:$4 = generic_method_on_generic_struct::Struct<(u32, i32)> {x: (8888, -8888)} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 1234.5} +// gdbg-check:$7 = {x = 1234.5} +// gdbr-check:$7 = generic_method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 1234.5} +// gdbg-check:$10 = {x = 1234.5} +// gdbr-check:$10 = generic_method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 1234.5} +// gdbg-check:$13 = {x = 1234.5} +// gdbr-check:$13 = generic_method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/generic-struct-style-enum.rs b/src/test/debuginfo/generic-struct-style-enum.rs index 991404f56eff..dba9422721a9 100644 --- a/src/test/debuginfo/generic-struct-style-enum.rs +++ b/src/test/debuginfo/generic-struct-style-enum.rs @@ -17,16 +17,20 @@ // gdb-command:run // gdb-command:print case1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}} +// gdbr-check:$1 = generic_struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868} // gdb-command:print case2 -// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}} +// gdbr-check:$2 = generic_struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153} // gdb-command:print case3 -// gdb-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}} +// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}} +// gdbr-check:$3 = generic_struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897} // gdb-command:print univariant -// gdb-check:$4 = {{a = -1}} +// gdbg-check:$4 = {{a = -1}} +// gdbr-check:$4 = generic_struct_style_enum::Univariant::TheOnlyCase{a: -1} #![feature(omit_gdb_pretty_printer_section)] diff --git a/src/test/debuginfo/generic-struct.rs b/src/test/debuginfo/generic-struct.rs index 92a67a2344d1..35f00ce78717 100644 --- a/src/test/debuginfo/generic-struct.rs +++ b/src/test/debuginfo/generic-struct.rs @@ -18,13 +18,17 @@ // gdb-command:run // gdb-command:print int_int -// gdb-check:$1 = {key = 0, value = 1} +// gdbg-check:$1 = {key = 0, value = 1} +// gdbr-check:$1 = generic_struct::AGenericStruct {key: 0, value: 1} // gdb-command:print int_float -// gdb-check:$2 = {key = 2, value = 3.5} +// gdbg-check:$2 = {key = 2, value = 3.5} +// gdbr-check:$2 = generic_struct::AGenericStruct {key: 2, value: 3.5} // gdb-command:print float_int -// gdb-check:$3 = {key = 4.5, value = 5} +// gdbg-check:$3 = {key = 4.5, value = 5} +// gdbr-check:$3 = generic_struct::AGenericStruct {key: 4.5, value: 5} // gdb-command:print float_int_float -// gdb-check:$4 = {key = 6.5, value = {key = 7, value = 8.5}} +// gdbg-check:$4 = {key = 6.5, value = {key = 7, value = 8.5}} +// gdbr-check:$4 = generic_struct::AGenericStruct> {key: 6.5, value: generic_struct::AGenericStruct {key: 7, value: 8.5}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/generic-tuple-style-enum.rs b/src/test/debuginfo/generic-tuple-style-enum.rs index e2727fbe7df4..01d2ff4e3343 100644 --- a/src/test/debuginfo/generic-tuple-style-enum.rs +++ b/src/test/debuginfo/generic-tuple-style-enum.rs @@ -19,16 +19,20 @@ // gdb-command:run // gdb-command:print case1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}} +// gdbr-check:$1 = generic_tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868) // gdb-command:print case2 -// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}} +// gdbr-check:$2 = generic_tuple_style_enum::Regular::Case2(0, 286331153, 286331153) // gdb-command:print case3 -// gdb-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}} +// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}} +// gdbr-check:$3 = generic_tuple_style_enum::Regular::Case3(0, 6438275382588823897) // gdb-command:print univariant -// gdb-check:$4 = {{__0 = -1}} +// gdbg-check:$4 = {{__0 = -1}} +// gdbr-check:$4 = generic_tuple_style_enum::Univariant::TheOnlyCase(-1) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/lexical-scopes-in-block-expression.rs b/src/test/debuginfo/lexical-scopes-in-block-expression.rs index 841786f930da..8e8a194e3784 100644 --- a/src/test/debuginfo/lexical-scopes-in-block-expression.rs +++ b/src/test/debuginfo/lexical-scopes-in-block-expression.rs @@ -16,7 +16,8 @@ // gdb-command:run -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$1 = 0 // STRUCT EXPRESSION @@ -28,7 +29,8 @@ // gdb-command:print val // gdb-check:$4 = 11 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$5 = 1 // gdb-command:print ten // gdb-check:$6 = 10 @@ -49,7 +51,8 @@ // gdb-command:print val // gdb-check:$11 = 12 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$12 = 2 // gdb-command:print ten // gdb-check:$13 = 10 @@ -70,7 +73,8 @@ // gdb-command:print val // gdb-check:$18 = 13 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$19 = 3 // gdb-command:print ten // gdb-check:$20 = 10 @@ -91,7 +95,8 @@ // gdb-command:print val // gdb-check:$25 = 14 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$26 = 4 // gdb-command:print ten // gdb-check:$27 = 10 @@ -112,7 +117,8 @@ // gdb-command:print val // gdb-check:$32 = 15 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$33 = 5 // gdb-command:print ten // gdb-check:$34 = 10 @@ -133,7 +139,8 @@ // gdb-command:print val // gdb-check:$39 = 16 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$40 = 6 // gdb-command:print ten // gdb-check:$41 = 10 @@ -155,7 +162,8 @@ // gdb-command:print val // gdb-check:$46 = 17 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$47 = 7 // gdb-command:print ten // gdb-check:$48 = 10 @@ -176,7 +184,8 @@ // gdb-command:print val // gdb-check:$53 = 18 -// gdb-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbg-command:print 'lexical_scopes_in_block_expression::MUT_INT' +// gdbr-command:print lexical_scopes_in_block_expression::MUT_INT // gdb-check:$54 = 8 // gdb-command:print ten // gdb-check:$55 = 10 diff --git a/src/test/debuginfo/method-on-enum.rs b/src/test/debuginfo/method-on-enum.rs index 6437b3bb900f..7dbc0d3c5130 100644 --- a/src/test/debuginfo/method-on-enum.rs +++ b/src/test/debuginfo/method-on-enum.rs @@ -19,7 +19,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, __0 = 117901063}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, __0 = 117901063}} +// gdbr-check:$1 = method_on_enum::Enum::Variant2(117901063) // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -28,7 +29,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, __0 = 117901063}} +// gdbg-check:$4 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, __0 = 117901063}} +// gdbr-check:$4 = method_on_enum::Enum::Variant2(117901063) // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -37,7 +39,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbg-check:$7 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbr-check:$7 = method_on_enum::Enum::Variant1{x: 1799, y: 1799} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -46,7 +49,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbg-check:$10 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbr-check:$10 = method_on_enum::Enum::Variant1{x: 1799, y: 1799} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -55,7 +59,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbg-check:$13 = {{RUST$ENUM$DISR = Variant1, x = 1799, y = 1799}, {RUST$ENUM$DISR = Variant1, [...]}} +// gdbr-check:$13 = method_on_enum::Enum::Variant1{x: 1799, y: 1799} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/method-on-generic-struct.rs b/src/test/debuginfo/method-on-generic-struct.rs index 5b697f859d4e..20d419b4ac08 100644 --- a/src/test/debuginfo/method-on-generic-struct.rs +++ b/src/test/debuginfo/method-on-generic-struct.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = {__0 = 8888, __1 = -8888}} +// gdbg-check:$1 = {x = {__0 = 8888, __1 = -8888}} +// gdbr-check:$1 = method_on_generic_struct::Struct<(u32, i32)> {x: (8888, -8888)} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = {__0 = 8888, __1 = -8888}} +// gdbg-check:$4 = {x = {__0 = 8888, __1 = -8888}} +// gdbr-check:$4 = method_on_generic_struct::Struct<(u32, i32)> {x: (8888, -8888)} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 1234.5} +// gdbg-check:$7 = {x = 1234.5} +// gdbr-check:$7 = method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 1234.5} +// gdbg-check:$10 = {x = 1234.5} +// gdbr-check:$10 = method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 1234.5} +// gdbg-check:$13 = {x = 1234.5} +// gdbr-check:$13 = method_on_generic_struct::Struct {x: 1234.5} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/method-on-struct.rs b/src/test/debuginfo/method-on-struct.rs index 3bf2e775e779..c7546fe2221f 100644 --- a/src/test/debuginfo/method-on-struct.rs +++ b/src/test/debuginfo/method-on-struct.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = 100} +// gdbg-check:$1 = {x = 100} +// gdbr-check:$1 = method_on_struct::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = 100} +// gdbg-check:$4 = {x = 100} +// gdbr-check:$4 = method_on_struct::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 200} +// gdbg-check:$7 = {x = 200} +// gdbr-check:$7 = method_on_struct::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 200} +// gdbg-check:$10 = {x = 200} +// gdbr-check:$10 = method_on_struct::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 200} +// gdbg-check:$13 = {x = 200} +// gdbr-check:$13 = method_on_struct::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/method-on-trait.rs b/src/test/debuginfo/method-on-trait.rs index 5ce4a7905a1d..1dc37bb06ac4 100644 --- a/src/test/debuginfo/method-on-trait.rs +++ b/src/test/debuginfo/method-on-trait.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = 100} +// gdbg-check:$1 = {x = 100} +// gdbr-check:$1 = method_on_trait::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = 100} +// gdbg-check:$4 = {x = 100} +// gdbr-check:$4 = method_on_trait::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 200} +// gdbg-check:$7 = {x = 200} +// gdbr-check:$7 = method_on_trait::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 200} +// gdbg-check:$10 = {x = 200} +// gdbr-check:$10 = method_on_trait::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 200} +// gdbg-check:$13 = {x = 200} +// gdbr-check:$13 = method_on_trait::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/method-on-tuple-struct.rs b/src/test/debuginfo/method-on-tuple-struct.rs index d8644a3934f1..dac762ae0c35 100644 --- a/src/test/debuginfo/method-on-tuple-struct.rs +++ b/src/test/debuginfo/method-on-tuple-struct.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {__0 = 100, __1 = -100.5} +// gdbg-check:$1 = {__0 = 100, __1 = -100.5} +// gdbr-check:$1 = method_on_tuple_struct::TupleStruct (100, -100.5) // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {__0 = 100, __1 = -100.5} +// gdbg-check:$4 = {__0 = 100, __1 = -100.5} +// gdbr-check:$4 = method_on_tuple_struct::TupleStruct (100, -100.5) // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {__0 = 200, __1 = -200.5} +// gdbg-check:$7 = {__0 = 200, __1 = -200.5} +// gdbr-check:$7 = method_on_tuple_struct::TupleStruct (200, -200.5) // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {__0 = 200, __1 = -200.5} +// gdbg-check:$10 = {__0 = 200, __1 = -200.5} +// gdbr-check:$10 = method_on_tuple_struct::TupleStruct (200, -200.5) // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {__0 = 200, __1 = -200.5} +// gdbg-check:$13 = {__0 = 200, __1 = -200.5} +// gdbr-check:$13 = method_on_tuple_struct::TupleStruct (200, -200.5) // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/nil-enum.rs b/src/test/debuginfo/nil-enum.rs index 81399ec590b1..94377421c0b0 100644 --- a/src/test/debuginfo/nil-enum.rs +++ b/src/test/debuginfo/nil-enum.rs @@ -16,10 +16,12 @@ // gdb-command:run // gdb-command:print first -// gdb-check:$1 = {} +// gdbg-check:$1 = {} +// gdbr-check:$1 = // gdb-command:print second -// gdb-check:$2 = {} +// gdbg-check:$2 = {} +// gdbr-check:$2 = #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] @@ -28,8 +30,9 @@ enum ANilEnum {} enum AnotherNilEnum {} -// This test relies on gdb printing the string "{}" for empty +// This test relies on gdbg printing the string "{}" for empty // structs (which may change some time) +// The error from gdbr is expected since nil enums are not supposed to exist. fn main() { unsafe { let first: ANilEnum = ::std::mem::zeroed(); diff --git a/src/test/debuginfo/option-like-enum.rs b/src/test/debuginfo/option-like-enum.rs index f103294a94a0..39e6a4e4facf 100644 --- a/src/test/debuginfo/option-like-enum.rs +++ b/src/test/debuginfo/option-like-enum.rs @@ -18,28 +18,36 @@ // gdb-command:run // gdb-command:print some -// gdb-check:$1 = {RUST$ENCODED$ENUM$0$None = {__0 = 0x12345678}} +// gdbg-check:$1 = {RUST$ENCODED$ENUM$0$None = {__0 = 0x12345678}} +// gdbr-check:$1 = core::option::Option<&u32>::Some(0x12345678) // gdb-command:print none -// gdb-check:$2 = {RUST$ENCODED$ENUM$0$None = {__0 = 0x0}} +// gdbg-check:$2 = {RUST$ENCODED$ENUM$0$None = {__0 = 0x0}} +// gdbr-check:$2 = core::option::Option<&u32>::None // gdb-command:print full -// gdb-check:$3 = {RUST$ENCODED$ENUM$1$Empty = {__0 = 454545, __1 = 0x87654321, __2 = 9988}} +// gdbg-check:$3 = {RUST$ENCODED$ENUM$1$Empty = {__0 = 454545, __1 = 0x87654321, __2 = 9988}} +// gdbr-check:$3 = option_like_enum::MoreFields::Full(454545, 0x87654321, 9988) -// gdb-command:print empty_gdb->discr +// gdbg-command:print empty_gdb->discr +// gdbr-command:print empty_gdb.discr // gdb-check:$4 = (isize *) 0x0 // gdb-command:print droid -// gdb-check:$5 = {RUST$ENCODED$ENUM$2$Void = {id = 675675, range = 10000001, internals = 0x43218765}} +// gdbg-check:$5 = {RUST$ENCODED$ENUM$2$Void = {id = 675675, range = 10000001, internals = 0x43218765}} +// gdbr-check:$5 = option_like_enum::NamedFields::Droid{id: 675675, range: 10000001, internals: 0x43218765} -// gdb-command:print void_droid_gdb->internals +// gdbg-command:print void_droid_gdb->internals +// gdbr-command:print void_droid_gdb.internals // gdb-check:$6 = (isize *) 0x0 // gdb-command:print nested_non_zero_yep -// gdb-check:$7 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = 10.5, __1 = {a = 10, b = 20, c = [...]}}} +// gdbg-check:$7 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = 10.5, __1 = {a = 10, b = 20, c = [...]}}} +// gdbr-check:$7 = option_like_enum::NestedNonZero::Yep(10.5, option_like_enum::NestedNonZeroField {a: 10, b: 20, c: 0x[...] "x[...]"}) // gdb-command:print nested_non_zero_nope -// gdb-check:$8 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = [...], __1 = {a = [...], b = [...], c = 0x0}}} +// gdbg-check:$8 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = [...], __1 = {a = [...], b = [...], c = 0x0}}} +// gdbr-check:$8 = option_like_enum::NestedNonZero::Nope // gdb-command:continue diff --git a/src/test/debuginfo/packed-struct-with-destructor.rs b/src/test/debuginfo/packed-struct-with-destructor.rs index 9d37cb3012b7..50bd857d4607 100644 --- a/src/test/debuginfo/packed-struct-with-destructor.rs +++ b/src/test/debuginfo/packed-struct-with-destructor.rs @@ -18,29 +18,37 @@ // gdb-command:run // gdb-command:print packed -// gdb-check:$1 = {x = 123, y = 234, z = 345} +// gdbg-check:$1 = {x = 123, y = 234, z = 345} +// gdbr-check:$1 = packed_struct_with_destructor::Packed {x: 123, y: 234, z: 345} // gdb-command:print packedInPacked -// gdb-check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}} +// gdbg-check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}} +// gdbr-check:$2 = packed_struct_with_destructor::PackedInPacked {a: 1111, b: packed_struct_with_destructor::Packed {x: 2222, y: 3333, z: 4444}, c: 5555, d: packed_struct_with_destructor::Packed {x: 6666, y: 7777, z: 8888}} // gdb-command:print packedInUnpacked -// gdb-check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}} +// gdbg-check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}} +// gdbr-check:$3 = packed_struct_with_destructor::PackedInUnpacked {a: -1111, b: packed_struct_with_destructor::Packed {x: -2222, y: -3333, z: -4444}, c: -5555, d: packed_struct_with_destructor::Packed {x: -6666, y: -7777, z: -8888}} // gdb-command:print unpackedInPacked -// gdb-check:$4 = {a = 987, b = {x = 876, y = 765, z = 654}, c = {x = 543, y = 432, z = 321}, d = 210} +// gdbg-check:$4 = {a = 987, b = {x = 876, y = 765, z = 654}, c = {x = 543, y = 432, z = 321}, d = 210} +// gdbr-check:$4 = packed_struct_with_destructor::UnpackedInPacked {a: 987, b: packed_struct_with_destructor::Unpacked {x: 876, y: 765, z: 654}, c: packed_struct_with_destructor::Unpacked {x: 543, y: 432, z: 321}, d: 210} // gdb-command:print packedInPackedWithDrop -// gdb-check:$5 = {a = 11, b = {x = 22, y = 33, z = 44}, c = 55, d = {x = 66, y = 77, z = 88}} +// gdbg-check:$5 = {a = 11, b = {x = 22, y = 33, z = 44}, c = 55, d = {x = 66, y = 77, z = 88}} +// gdbr-check:$5 = packed_struct_with_destructor::PackedInPackedWithDrop {a: 11, b: packed_struct_with_destructor::Packed {x: 22, y: 33, z: 44}, c: 55, d: packed_struct_with_destructor::Packed {x: 66, y: 77, z: 88}} // gdb-command:print packedInUnpackedWithDrop -// gdb-check:$6 = {a = -11, b = {x = -22, y = -33, z = -44}, c = -55, d = {x = -66, y = -77, z = -88}} +// gdbg-check:$6 = {a = -11, b = {x = -22, y = -33, z = -44}, c = -55, d = {x = -66, y = -77, z = -88}} +// gdbr-check:$6 = packed_struct_with_destructor::PackedInUnpackedWithDrop {a: -11, b: packed_struct_with_destructor::Packed {x: -22, y: -33, z: -44}, c: -55, d: packed_struct_with_destructor::Packed {x: -66, y: -77, z: -88}} // gdb-command:print unpackedInPackedWithDrop -// gdb-check:$7 = {a = 98, b = {x = 87, y = 76, z = 65}, c = {x = 54, y = 43, z = 32}, d = 21} +// gdbg-check:$7 = {a = 98, b = {x = 87, y = 76, z = 65}, c = {x = 54, y = 43, z = 32}, d = 21} +// gdbr-check:$7 = packed_struct_with_destructor::UnpackedInPackedWithDrop {a: 98, b: packed_struct_with_destructor::Unpacked {x: 87, y: 76, z: 65}, c: packed_struct_with_destructor::Unpacked {x: 54, y: 43, z: 32}, d: 21} // gdb-command:print deeplyNested -// gdb-check:$8 = {a = {a = 1, b = {x = 2, y = 3, z = 4}, c = 5, d = {x = 6, y = 7, z = 8}}, b = {a = 9, b = {x = 10, y = 11, z = 12}, c = {x = 13, y = 14, z = 15}, d = 16}, c = {a = 17, b = {x = 18, y = 19, z = 20}, c = 21, d = {x = 22, y = 23, z = 24}}, d = {a = 25, b = {x = 26, y = 27, z = 28}, c = 29, d = {x = 30, y = 31, z = 32}}, e = {a = 33, b = {x = 34, y = 35, z = 36}, c = {x = 37, y = 38, z = 39}, d = 40}, f = {a = 41, b = {x = 42, y = 43, z = 44}, c = 45, d = {x = 46, y = 47, z = 48}}} +// gdbg-check:$8 = {a = {a = 1, b = {x = 2, y = 3, z = 4}, c = 5, d = {x = 6, y = 7, z = 8}}, b = {a = 9, b = {x = 10, y = 11, z = 12}, c = {x = 13, y = 14, z = 15}, d = 16}, c = {a = 17, b = {x = 18, y = 19, z = 20}, c = 21, d = {x = 22, y = 23, z = 24}}, d = {a = 25, b = {x = 26, y = 27, z = 28}, c = 29, d = {x = 30, y = 31, z = 32}}, e = {a = 33, b = {x = 34, y = 35, z = 36}, c = {x = 37, y = 38, z = 39}, d = 40}, f = {a = 41, b = {x = 42, y = 43, z = 44}, c = 45, d = {x = 46, y = 47, z = 48}}} +// gdbr-check:$8 = packed_struct_with_destructor::DeeplyNested {a: packed_struct_with_destructor::PackedInPacked {a: 1, b: packed_struct_with_destructor::Packed {x: 2, y: 3, z: 4}, c: 5, d: packed_struct_with_destructor::Packed {x: 6, y: 7, z: 8}}, b: packed_struct_with_destructor::UnpackedInPackedWithDrop {a: 9, b: packed_struct_with_destructor::Unpacked {x: 10, y: 11, z: 12}, c: packed_struct_with_destructor::Unpacked {x: 13, y: 14, z: 15}, d: 16}, c: packed_struct_with_destructor::PackedInUnpacked {a: 17, b: packed_struct_with_destructor::Packed {x: 18, y: 19, z: 20}, c: 21, d: packed_struct_with_destructor::Packed {x: 22, y: 23, z: 24}}, d: packed_struct_with_destructor::PackedInUnpackedWithDrop {a: 25, b: packed_struct_with_destructor::Packed {x: 26, y: 27, z: 28}, c: 29, d: packed_struct_with_destructor::Packed {x: 30, y: 31, z: 32}}, e: packed_struct_with_destructor::UnpackedInPacked {a: 33, b: packed_struct_with_destructor::Unpacked {x: 34, y: 35, z: 36}, c: packed_struct_with_destructor::Unpacked {x: 37, y: 38, z: 39}, d: 40}, f: packed_struct_with_destructor::PackedInPackedWithDrop {a: 41, b: packed_struct_with_destructor::Packed {x: 42, y: 43, z: 44}, c: 45, d: packed_struct_with_destructor::Packed {x: 46, y: 47, z: 48}}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/packed-struct.rs b/src/test/debuginfo/packed-struct.rs index e86e963f38cd..b84161c36a55 100644 --- a/src/test/debuginfo/packed-struct.rs +++ b/src/test/debuginfo/packed-struct.rs @@ -18,16 +18,20 @@ // gdb-command:run // gdb-command:print packed -// gdb-check:$1 = {x = 123, y = 234, z = 345} +// gdbg-check:$1 = {x = 123, y = 234, z = 345} +// gdbr-check:$1 = packed_struct::Packed {x: 123, y: 234, z: 345} // gdb-command:print packedInPacked -// gdb-check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}} +// gdbg-check:$2 = {a = 1111, b = {x = 2222, y = 3333, z = 4444}, c = 5555, d = {x = 6666, y = 7777, z = 8888}} +// gdbr-check:$2 = packed_struct::PackedInPacked {a: 1111, b: packed_struct::Packed {x: 2222, y: 3333, z: 4444}, c: 5555, d: packed_struct::Packed {x: 6666, y: 7777, z: 8888}} // gdb-command:print packedInUnpacked -// gdb-check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}} +// gdbg-check:$3 = {a = -1111, b = {x = -2222, y = -3333, z = -4444}, c = -5555, d = {x = -6666, y = -7777, z = -8888}} +// gdbr-check:$3 = packed_struct::PackedInUnpacked {a: -1111, b: packed_struct::Packed {x: -2222, y: -3333, z: -4444}, c: -5555, d: packed_struct::Packed {x: -6666, y: -7777, z: -8888}} // gdb-command:print unpackedInPacked -// gdb-check:$4 = {a = 987, b = {x = 876, y = 765, z = 654, w = 543}, c = {x = 432, y = 321, z = 210, w = 109}, d = -98} +// gdbg-check:$4 = {a = 987, b = {x = 876, y = 765, z = 654, w = 543}, c = {x = 432, y = 321, z = 210, w = 109}, d = -98} +// gdbr-check:$4 = packed_struct::UnpackedInPacked {a: 987, b: packed_struct::Unpacked {x: 876, y: 765, z: 654, w: 543}, c: packed_struct::Unpacked {x: 432, y: 321, z: 210, w: 109}, d: -98} // gdb-command:print sizeof(packed) // gdb-check:$5 = 14 diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 576621737e6b..153f0c8271fc 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -35,7 +35,8 @@ // gdb-check:$5 = Some = {8} // gdb-command: print none -// gdb-check:$6 = None +// gdbg-check:$6 = None +// gdbr-check:$6 = core::option::Option::None // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/recursive-struct.rs b/src/test/debuginfo/recursive-struct.rs index ea067d5bffbe..80147b14174d 100644 --- a/src/test/debuginfo/recursive-struct.rs +++ b/src/test/debuginfo/recursive-struct.rs @@ -12,57 +12,72 @@ // ignore-lldb // compile-flags:-g + // gdb-command:run // gdb-command:print stack_unique.value // gdb-check:$1 = 0 -// gdb-command:print stack_unique.next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbg-command:print stack_unique.next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbr-command:print stack_unique.next.val.value // gdb-check:$2 = 1 -// gdb-command:print unique_unique->value +// gdbg-command:print unique_unique->value +// gdbr-command:print unique_unique.value // gdb-check:$3 = 2 -// gdb-command:print unique_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbg-command:print unique_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbr-command:print unique_unique.next.val.value // gdb-check:$4 = 3 // gdb-command:print vec_unique[0].value // gdb-check:$5 = 6.5 -// gdb-command:print vec_unique[0].next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbg-command:print vec_unique[0].next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbr-command:print vec_unique[0].next.val.value // gdb-check:$6 = 7.5 -// gdb-command:print borrowed_unique->value +// gdbg-command:print borrowed_unique->value +// gdbr-command:print borrowed_unique.value // gdb-check:$7 = 8.5 -// gdb-command:print borrowed_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbg-command:print borrowed_unique->next.RUST$ENCODED$ENUM$0$Empty.val->value +// gdbr-command:print borrowed_unique.next.val.value // gdb-check:$8 = 9.5 // LONG CYCLE // gdb-command:print long_cycle1.value // gdb-check:$9 = 20 -// gdb-command:print long_cycle1.next->value +// gdbg-command:print long_cycle1.next->value +// gdbr-command:print long_cycle1.next.value // gdb-check:$10 = 21 -// gdb-command:print long_cycle1.next->next->value +// gdbg-command:print long_cycle1.next->next->value +// gdbr-command:print long_cycle1.next.next.value // gdb-check:$11 = 22 -// gdb-command:print long_cycle1.next->next->next->value +// gdbg-command:print long_cycle1.next->next->next->value +// gdbr-command:print long_cycle1.next.next.next.value // gdb-check:$12 = 23 // gdb-command:print long_cycle2.value // gdb-check:$13 = 24 -// gdb-command:print long_cycle2.next->value +// gdbg-command:print long_cycle2.next->value +// gdbr-command:print long_cycle2.next.value // gdb-check:$14 = 25 -// gdb-command:print long_cycle2.next->next->value +// gdbg-command:print long_cycle2.next->next->value +// gdbr-command:print long_cycle2.next.next.value // gdb-check:$15 = 26 // gdb-command:print long_cycle3.value // gdb-check:$16 = 27 -// gdb-command:print long_cycle3.next->value +// gdbg-command:print long_cycle3.next->value +// gdbr-command:print long_cycle3.next.value // gdb-check:$17 = 28 // gdb-command:print long_cycle4.value // gdb-check:$18 = 29.5 -// gdb-command:print (*****long_cycle_w_anonymous_types).value +// gdbg-command:print (*****long_cycle_w_anonymous_types).value +// gdbr-command:print long_cycle_w_anonymous_types.value // gdb-check:$19 = 30 -// gdb-command:print (*****((*****long_cycle_w_anonymous_types).next.RUST$ENCODED$ENUM$0$Empty.val)).value +// gdbg-command:print (*****((*****long_cycle_w_anonymous_types).next.RUST$ENCODED$ENUM$0$Empty.val)).value +// gdbr-command:print long_cycle_w_anonymous_types.next.val.value // gdb-check:$20 = 31 // gdb-command:continue diff --git a/src/test/debuginfo/self-in-default-method.rs b/src/test/debuginfo/self-in-default-method.rs index 6d3f93c5d501..796d122cd66b 100644 --- a/src/test/debuginfo/self-in-default-method.rs +++ b/src/test/debuginfo/self-in-default-method.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = 100} +// gdbg-check:$1 = {x = 100} +// gdbr-check:$1 = self_in_default_method::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = 100} +// gdbg-check:$4 = {x = 100} +// gdbr-check:$4 = self_in_default_method::Struct {x: 100} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 200} +// gdbg-check:$7 = {x = 200} +// gdbr-check:$7 = self_in_default_method::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 200} +// gdbg-check:$10 = {x = 200} +// gdbr-check:$10 = self_in_default_method::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 200} +// gdbg-check:$13 = {x = 200} +// gdbr-check:$13 = self_in_default_method::Struct {x: 200} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/self-in-generic-default-method.rs b/src/test/debuginfo/self-in-generic-default-method.rs index aea3bae4bfc1..b07d7ca5fb7b 100644 --- a/src/test/debuginfo/self-in-generic-default-method.rs +++ b/src/test/debuginfo/self-in-generic-default-method.rs @@ -18,7 +18,8 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = 987} +// gdbg-check:$1 = {x = 987} +// gdbr-check:$1 = self_in_generic_default_method::Struct {x: 987} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +28,8 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = 987} +// gdbg-check:$4 = {x = 987} +// gdbr-check:$4 = self_in_generic_default_method::Struct {x: 987} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +38,8 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {x = 879} +// gdbg-check:$7 = {x = 879} +// gdbr-check:$7 = self_in_generic_default_method::Struct {x: 879} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +48,8 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {x = 879} +// gdbg-check:$10 = {x = 879} +// gdbr-check:$10 = self_in_generic_default_method::Struct {x: 879} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +58,8 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {x = 879} +// gdbg-check:$13 = {x = 879} +// gdbr-check:$13 = self_in_generic_default_method::Struct {x: 879} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/simd.rs b/src/test/debuginfo/simd.rs index 80ac901b60fd..75e68f7efede 100644 --- a/src/test/debuginfo/simd.rs +++ b/src/test/debuginfo/simd.rs @@ -20,28 +20,46 @@ // compile-flags:-g // gdb-command:run -// gdb-command:print/d vi8x16 -// gdb-check:$1 = {__0 = 0, __1 = 1, __2 = 2, __3 = 3, __4 = 4, __5 = 5, __6 = 6, __7 = 7, __8 = 8, __9 = 9, __10 = 10, __11 = 11, __12 = 12, __13 = 13, __14 = 14, __15 = 15} -// gdb-command:print/d vi16x8 -// gdb-check:$2 = {__0 = 16, __1 = 17, __2 = 18, __3 = 19, __4 = 20, __5 = 21, __6 = 22, __7 = 23} -// gdb-command:print/d vi32x4 -// gdb-check:$3 = {__0 = 24, __1 = 25, __2 = 26, __3 = 27} -// gdb-command:print/d vi64x2 -// gdb-check:$4 = {__0 = 28, __1 = 29} +// gdbg-command:print/d vi8x16 +// gdbr-command:print vi8x16 +// gdbg-check:$1 = {__0 = 0, __1 = 1, __2 = 2, __3 = 3, __4 = 4, __5 = 5, __6 = 6, __7 = 7, __8 = 8, __9 = 9, __10 = 10, __11 = 11, __12 = 12, __13 = 13, __14 = 14, __15 = 15} +// gdbr-check:$1 = simd::i8x16 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) +// gdbg-command:print/d vi16x8 +// gdbr-command:print vi16x8 +// gdbg-check:$2 = {__0 = 16, __1 = 17, __2 = 18, __3 = 19, __4 = 20, __5 = 21, __6 = 22, __7 = 23} +// gdbr-check:$2 = simd::i16x8 (16, 17, 18, 19, 20, 21, 22, 23) +// gdbg-command:print/d vi32x4 +// gdbr-command:print vi32x4 +// gdbg-check:$3 = {__0 = 24, __1 = 25, __2 = 26, __3 = 27} +// gdbr-check:$3 = simd::i32x4 (24, 25, 26, 27) +// gdbg-command:print/d vi64x2 +// gdbr-command:print vi64x2 +// gdbg-check:$4 = {__0 = 28, __1 = 29} +// gdbr-check:$4 = simd::i64x2 (28, 29) -// gdb-command:print/d vu8x16 -// gdb-check:$5 = {__0 = 30, __1 = 31, __2 = 32, __3 = 33, __4 = 34, __5 = 35, __6 = 36, __7 = 37, __8 = 38, __9 = 39, __10 = 40, __11 = 41, __12 = 42, __13 = 43, __14 = 44, __15 = 45} -// gdb-command:print/d vu16x8 -// gdb-check:$6 = {__0 = 46, __1 = 47, __2 = 48, __3 = 49, __4 = 50, __5 = 51, __6 = 52, __7 = 53} -// gdb-command:print/d vu32x4 -// gdb-check:$7 = {__0 = 54, __1 = 55, __2 = 56, __3 = 57} -// gdb-command:print/d vu64x2 -// gdb-check:$8 = {__0 = 58, __1 = 59} +// gdbg-command:print/d vu8x16 +// gdbr-command:print vu8x16 +// gdbg-check:$5 = {__0 = 30, __1 = 31, __2 = 32, __3 = 33, __4 = 34, __5 = 35, __6 = 36, __7 = 37, __8 = 38, __9 = 39, __10 = 40, __11 = 41, __12 = 42, __13 = 43, __14 = 44, __15 = 45} +// gdbr-check:$5 = simd::u8x16 (30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45) +// gdbg-command:print/d vu16x8 +// gdbr-command:print vu16x8 +// gdbg-check:$6 = {__0 = 46, __1 = 47, __2 = 48, __3 = 49, __4 = 50, __5 = 51, __6 = 52, __7 = 53} +// gdbr-check:$6 = simd::u16x8 (46, 47, 48, 49, 50, 51, 52, 53) +// gdbg-command:print/d vu32x4 +// gdbr-command:print vu32x4 +// gdbg-check:$7 = {__0 = 54, __1 = 55, __2 = 56, __3 = 57} +// gdbr-check:$7 = simd::u32x4 (54, 55, 56, 57) +// gdbg-command:print/d vu64x2 +// gdbr-command:print vu64x2 +// gdbg-check:$8 = {__0 = 58, __1 = 59} +// gdbr-check:$8 = simd::u64x2 (58, 59) // gdb-command:print vf32x4 -// gdb-check:$9 = {__0 = 60.5, __1 = 61.5, __2 = 62.5, __3 = 63.5} +// gdbg-check:$9 = {__0 = 60.5, __1 = 61.5, __2 = 62.5, __3 = 63.5} +// gdbr-check:$9 = simd::f32x4 (60.5, 61.5, 62.5, 63.5) // gdb-command:print vf64x2 -// gdb-check:$10 = {__0 = 64.5, __1 = 65.5} +// gdbg-check:$10 = {__0 = 64.5, __1 = 65.5} +// gdbr-check:$10 = simd::f64x2 (64.5, 65.5) // gdb-command:continue diff --git a/src/test/debuginfo/simple-struct.rs b/src/test/debuginfo/simple-struct.rs index d25cd4d7c047..4956313ad221 100644 --- a/src/test/debuginfo/simple-struct.rs +++ b/src/test/debuginfo/simple-struct.rs @@ -14,61 +14,94 @@ // === GDB TESTS =================================================================================== -// gdb-command:print 'simple_struct::NO_PADDING_16' -// gdb-check:$1 = {x = 1000, y = -1001} +// there's no frame yet for gdb to reliably detect the language, set it explicitly +// gdbr-command:set language rust -// gdb-command:print 'simple_struct::NO_PADDING_32' -// gdb-check:$2 = {x = 1, y = 2, z = 3} +// gdbg-command:print 'simple_struct::NO_PADDING_16' +// gdbr-command:print simple_struct::NO_PADDING_16 +// gdbg-check:$1 = {x = 1000, y = -1001} +// gdbr-check:$1 = simple_struct::NoPadding16 {x: 1000, y: -1001} -// gdb-command:print 'simple_struct::NO_PADDING_64' -// gdb-check:$3 = {x = 4, y = 5, z = 6} +// gdbg-command:print 'simple_struct::NO_PADDING_32' +// gdbr-command:print simple_struct::NO_PADDING_32 +// gdbg-check:$2 = {x = 1, y = 2, z = 3} +// gdbr-check:$2 = simple_struct::NoPadding32 {x: 1, y: 2, z: 3} -// gdb-command:print 'simple_struct::NO_PADDING_163264' -// gdb-check:$4 = {a = 7, b = 8, c = 9, d = 10} +// gdbg-command:print 'simple_struct::NO_PADDING_64' +// gdbr-command:print simple_struct::NO_PADDING_64 +// gdbg-check:$3 = {x = 4, y = 5, z = 6} +// gdbr-check:$3 = simple_struct::NoPadding64 {x: 4, y: 5, z: 6} -// gdb-command:print 'simple_struct::INTERNAL_PADDING' -// gdb-check:$5 = {x = 11, y = 12} +// gdbg-command:print 'simple_struct::NO_PADDING_163264' +// gdbr-command:print simple_struct::NO_PADDING_163264 +// gdbg-check:$4 = {a = 7, b = 8, c = 9, d = 10} +// gdbr-check:$4 = simple_struct::NoPadding163264 {a: 7, b: 8, c: 9, d: 10} -// gdb-command:print 'simple_struct::PADDING_AT_END' -// gdb-check:$6 = {x = 13, y = 14} +// gdbg-command:print 'simple_struct::INTERNAL_PADDING' +// gdbr-command:print simple_struct::INTERNAL_PADDING +// gdbg-check:$5 = {x = 11, y = 12} +// gdbr-check:$5 = simple_struct::InternalPadding {x: 11, y: 12} + +// gdbg-command:print 'simple_struct::PADDING_AT_END' +// gdbr-command:print simple_struct::PADDING_AT_END +// gdbg-check:$6 = {x = 13, y = 14} +// gdbr-check:$6 = simple_struct::PaddingAtEnd {x: 13, y: 14} // gdb-command:run // gdb-command:print no_padding16 -// gdb-check:$7 = {x = 10000, y = -10001} +// gdbg-check:$7 = {x = 10000, y = -10001} +// gdbr-check:$7 = simple_struct::NoPadding16 {x: 10000, y: -10001} // gdb-command:print no_padding32 -// gdb-check:$8 = {x = -10002, y = -10003.5, z = 10004} +// gdbg-check:$8 = {x = -10002, y = -10003.5, z = 10004} +// gdbr-check:$8 = simple_struct::NoPadding32 {x: -10002, y: -10003.5, z: 10004} // gdb-command:print no_padding64 -// gdb-check:$9 = {x = -10005.5, y = 10006, z = 10007} +// gdbg-check:$9 = {x = -10005.5, y = 10006, z = 10007} +// gdbr-check:$9 = simple_struct::NoPadding64 {x: -10005.5, y: 10006, z: 10007} // gdb-command:print no_padding163264 -// gdb-check:$10 = {a = -10008, b = 10009, c = 10010, d = 10011} +// gdbg-check:$10 = {a = -10008, b = 10009, c = 10010, d = 10011} +// gdbr-check:$10 = simple_struct::NoPadding163264 {a: -10008, b: 10009, c: 10010, d: 10011} // gdb-command:print internal_padding -// gdb-check:$11 = {x = 10012, y = -10013} +// gdbg-check:$11 = {x = 10012, y = -10013} +// gdbr-check:$11 = simple_struct::InternalPadding {x: 10012, y: -10013} // gdb-command:print padding_at_end -// gdb-check:$12 = {x = -10014, y = 10015} +// gdbg-check:$12 = {x = -10014, y = 10015} +// gdbr-check:$12 = simple_struct::PaddingAtEnd {x: -10014, y: 10015} -// gdb-command:print 'simple_struct::NO_PADDING_16' -// gdb-check:$13 = {x = 100, y = -101} +// gdbg-command:print 'simple_struct::NO_PADDING_16' +// gdbr-command:print simple_struct::NO_PADDING_16 +// gdbg-check:$13 = {x = 100, y = -101} +// gdbr-check:$13 = simple_struct::NoPadding16 {x: 100, y: -101} -// gdb-command:print 'simple_struct::NO_PADDING_32' -// gdb-check:$14 = {x = -15, y = -16, z = 17} +// gdbg-command:print 'simple_struct::NO_PADDING_32' +// gdbr-command:print simple_struct::NO_PADDING_32 +// gdbg-check:$14 = {x = -15, y = -16, z = 17} +// gdbr-check:$14 = simple_struct::NoPadding32 {x: -15, y: -16, z: 17} -// gdb-command:print 'simple_struct::NO_PADDING_64' -// gdb-check:$15 = {x = -18, y = 19, z = 20} +// gdbg-command:print 'simple_struct::NO_PADDING_64' +// gdbr-command:print simple_struct::NO_PADDING_64 +// gdbg-check:$15 = {x = -18, y = 19, z = 20} +// gdbr-check:$15 = simple_struct::NoPadding64 {x: -18, y: 19, z: 20} -// gdb-command:print 'simple_struct::NO_PADDING_163264' -// gdb-check:$16 = {a = -21, b = 22, c = 23, d = 24} +// gdbg-command:print 'simple_struct::NO_PADDING_163264' +// gdbr-command:print simple_struct::NO_PADDING_163264 +// gdbg-check:$16 = {a = -21, b = 22, c = 23, d = 24} +// gdbr-check:$16 = simple_struct::NoPadding163264 {a: -21, b: 22, c: 23, d: 24} -// gdb-command:print 'simple_struct::INTERNAL_PADDING' -// gdb-check:$17 = {x = 25, y = -26} +// gdbg-command:print 'simple_struct::INTERNAL_PADDING' +// gdbr-command:print simple_struct::INTERNAL_PADDING +// gdbg-check:$17 = {x = 25, y = -26} +// gdbr-check:$17 = simple_struct::InternalPadding {x: 25, y: -26} -// gdb-command:print 'simple_struct::PADDING_AT_END' -// gdb-check:$18 = {x = -27, y = 28} +// gdbg-command:print 'simple_struct::PADDING_AT_END' +// gdbr-command:print simple_struct::PADDING_AT_END +// gdbg-check:$18 = {x = -27, y = 28} +// gdbr-check:$18 = simple_struct::PaddingAtEnd {x: -27, y: 28} // gdb-command:continue diff --git a/src/test/debuginfo/simple-tuple.rs b/src/test/debuginfo/simple-tuple.rs index 1b85ecc537a3..354a2c26cb36 100644 --- a/src/test/debuginfo/simple-tuple.rs +++ b/src/test/debuginfo/simple-tuple.rs @@ -14,58 +14,97 @@ // === GDB TESTS =================================================================================== -// gdb-command:print/d 'simple_tuple::NO_PADDING_8' -// gdb-check:$1 = {__0 = -50, __1 = 50} -// gdb-command:print 'simple_tuple::NO_PADDING_16' -// gdb-check:$2 = {__0 = -1, __1 = 2, __2 = 3} -// gdb-command:print 'simple_tuple::NO_PADDING_32' -// gdb-check:$3 = {__0 = 4, __1 = 5, __2 = 6} -// gdb-command:print 'simple_tuple::NO_PADDING_64' -// gdb-check:$4 = {__0 = 7, __1 = 8, __2 = 9} +// there's no frame yet for gdb to reliably detect the language, set it explicitly +// gdbr-command:set language rust -// gdb-command:print 'simple_tuple::INTERNAL_PADDING_1' -// gdb-check:$5 = {__0 = 10, __1 = 11} -// gdb-command:print 'simple_tuple::INTERNAL_PADDING_2' -// gdb-check:$6 = {__0 = 12, __1 = 13, __2 = 14, __3 = 15} +// gdbg-command:print/d 'simple_tuple::NO_PADDING_8' +// gdbr-command:print simple_tuple::NO_PADDING_8 +// gdbg-check:$1 = {__0 = -50, __1 = 50} +// gdbr-check:$1 = (-50, 50) +// gdbg-command:print 'simple_tuple::NO_PADDING_16' +// gdbr-command:print simple_tuple::NO_PADDING_16 +// gdbg-check:$2 = {__0 = -1, __1 = 2, __2 = 3} +// gdbr-check:$2 = (-1, 2, 3) +// gdbg-command:print 'simple_tuple::NO_PADDING_32' +// gdbr-command:print simple_tuple::NO_PADDING_32 +// gdbg-check:$3 = {__0 = 4, __1 = 5, __2 = 6} +// gdbr-check:$3 = (4, 5, 6) +// gdbg-command:print 'simple_tuple::NO_PADDING_64' +// gdbr-command:print simple_tuple::NO_PADDING_64 +// gdbg-check:$4 = {__0 = 7, __1 = 8, __2 = 9} +// gdbr-check:$4 = (7, 8, 9) -// gdb-command:print 'simple_tuple::PADDING_AT_END' -// gdb-check:$7 = {__0 = 16, __1 = 17} +// gdbg-command:print 'simple_tuple::INTERNAL_PADDING_1' +// gdbr-command:print simple_tuple::INTERNAL_PADDING_1 +// gdbg-check:$5 = {__0 = 10, __1 = 11} +// gdbr-check:$5 = (10, 11) +// gdbg-command:print 'simple_tuple::INTERNAL_PADDING_2' +// gdbr-command:print simple_tuple::INTERNAL_PADDING_2 +// gdbg-check:$6 = {__0 = 12, __1 = 13, __2 = 14, __3 = 15} +// gdbr-check:$6 = (12, 13, 14, 15) + +// gdbg-command:print 'simple_tuple::PADDING_AT_END' +// gdbr-command:print simple_tuple::PADDING_AT_END +// gdbg-check:$7 = {__0 = 16, __1 = 17} +// gdbr-check:$7 = (16, 17) // gdb-command:run -// gdb-command:print/d noPadding8 -// gdb-check:$8 = {__0 = -100, __1 = 100} +// gdbg-command:print/d noPadding8 +// gdbr-command:print noPadding8 +// gdbg-check:$8 = {__0 = -100, __1 = 100} +// gdbr-check:$8 = (-100, 100) // gdb-command:print noPadding16 -// gdb-check:$9 = {__0 = 0, __1 = 1, __2 = 2} +// gdbg-check:$9 = {__0 = 0, __1 = 1, __2 = 2} +// gdbr-check:$9 = (0, 1, 2) // gdb-command:print noPadding32 -// gdb-check:$10 = {__0 = 3, __1 = 4.5, __2 = 5} +// gdbg-check:$10 = {__0 = 3, __1 = 4.5, __2 = 5} +// gdbr-check:$10 = (3, 4.5, 5) // gdb-command:print noPadding64 -// gdb-check:$11 = {__0 = 6, __1 = 7.5, __2 = 8} +// gdbg-check:$11 = {__0 = 6, __1 = 7.5, __2 = 8} +// gdbr-check:$11 = (6, 7.5, 8) // gdb-command:print internalPadding1 -// gdb-check:$12 = {__0 = 9, __1 = 10} +// gdbg-check:$12 = {__0 = 9, __1 = 10} +// gdbr-check:$12 = (9, 10) // gdb-command:print internalPadding2 -// gdb-check:$13 = {__0 = 11, __1 = 12, __2 = 13, __3 = 14} +// gdbg-check:$13 = {__0 = 11, __1 = 12, __2 = 13, __3 = 14} +// gdbr-check:$13 = (11, 12, 13, 14) // gdb-command:print paddingAtEnd -// gdb-check:$14 = {__0 = 15, __1 = 16} +// gdbg-check:$14 = {__0 = 15, __1 = 16} +// gdbr-check:$14 = (15, 16) -// gdb-command:print/d 'simple_tuple::NO_PADDING_8' -// gdb-check:$15 = {__0 = -127, __1 = 127} -// gdb-command:print 'simple_tuple::NO_PADDING_16' -// gdb-check:$16 = {__0 = -10, __1 = 10, __2 = 9} -// gdb-command:print 'simple_tuple::NO_PADDING_32' -// gdb-check:$17 = {__0 = 14, __1 = 15, __2 = 16} -// gdb-command:print 'simple_tuple::NO_PADDING_64' -// gdb-check:$18 = {__0 = 17, __1 = 18, __2 = 19} +// gdbg-command:print/d 'simple_tuple::NO_PADDING_8' +// gdbr-command:print simple_tuple::NO_PADDING_8 +// gdbg-check:$15 = {__0 = -127, __1 = 127} +// gdbr-check:$15 = (-127, 127) +// gdbg-command:print 'simple_tuple::NO_PADDING_16' +// gdbr-command:print simple_tuple::NO_PADDING_16 +// gdbg-check:$16 = {__0 = -10, __1 = 10, __2 = 9} +// gdbr-check:$16 = (-10, 10, 9) +// gdbg-command:print 'simple_tuple::NO_PADDING_32' +// gdbr-command:print simple_tuple::NO_PADDING_32 +// gdbg-check:$17 = {__0 = 14, __1 = 15, __2 = 16} +// gdbr-check:$17 = (14, 15, 16) +// gdbg-command:print 'simple_tuple::NO_PADDING_64' +// gdbr-command:print simple_tuple::NO_PADDING_64 +// gdbg-check:$18 = {__0 = 17, __1 = 18, __2 = 19} +// gdbr-check:$18 = (17, 18, 19) -// gdb-command:print 'simple_tuple::INTERNAL_PADDING_1' -// gdb-check:$19 = {__0 = 110, __1 = 111} -// gdb-command:print 'simple_tuple::INTERNAL_PADDING_2' -// gdb-check:$20 = {__0 = 112, __1 = 113, __2 = 114, __3 = 115} +// gdbg-command:print 'simple_tuple::INTERNAL_PADDING_1' +// gdbr-command:print simple_tuple::INTERNAL_PADDING_1 +// gdbg-check:$19 = {__0 = 110, __1 = 111} +// gdbr-check:$19 = (110, 111) +// gdbg-command:print 'simple_tuple::INTERNAL_PADDING_2' +// gdbr-command:print simple_tuple::INTERNAL_PADDING_2 +// gdbg-check:$20 = {__0 = 112, __1 = 113, __2 = 114, __3 = 115} +// gdbr-check:$20 = (112, 113, 114, 115) -// gdb-command:print 'simple_tuple::PADDING_AT_END' -// gdb-check:$21 = {__0 = 116, __1 = 117} +// gdbg-command:print 'simple_tuple::PADDING_AT_END' +// gdbr-command:print simple_tuple::PADDING_AT_END +// gdbg-check:$21 = {__0 = 116, __1 = 117} +// gdbr-check:$21 = (116, 117) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/struct-in-enum.rs b/src/test/debuginfo/struct-in-enum.rs index 98b90de60051..d0aceaa4f3f9 100644 --- a/src/test/debuginfo/struct-in-enum.rs +++ b/src/test/debuginfo/struct-in-enum.rs @@ -19,13 +19,16 @@ // gdb-command:run // gdb-command:print case1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452, __2 = 31868}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452, __2 = 31868}} +// gdbr-check:$1 = struct_in_enum::Regular::Case1(0, struct_in_enum::Struct {x: 2088533116, y: 2088533116, z: 31868}) // gdb-command:print case2 -// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = {x = 286331153, y = 286331153, z = 4369}}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = {x = 286331153, y = 286331153, z = 4369}}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}} +// gdbr-check:$2 = struct_in_enum::Regular::Case2(0, 1229782938247303441, 4369) // gdb-command:print univariant -// gdb-check:$3 = {{__0 = {x = 123, y = 456, z = 789}}} +// gdbg-check:$3 = {{__0 = {x = 123, y = 456, z = 789}}} +// gdbr-check:$3 = struct_in_enum::Univariant::TheOnlyCase(struct_in_enum::Struct {x: 123, y: 456, z: 789}) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/struct-in-struct.rs b/src/test/debuginfo/struct-in-struct.rs index 76a1613c2314..46524cf1d029 100644 --- a/src/test/debuginfo/struct-in-struct.rs +++ b/src/test/debuginfo/struct-in-struct.rs @@ -18,13 +18,16 @@ // gdb-command:run // gdb-command:print three_simple_structs -// gdb-check:$1 = {x = {x = 1}, y = {x = 2}, z = {x = 3}} +// gdbg-check:$1 = {x = {x = 1}, y = {x = 2}, z = {x = 3}} +// gdbr-check:$1 = struct_in_struct::ThreeSimpleStructs {x: struct_in_struct::Simple {x: 1}, y: struct_in_struct::Simple {x: 2}, z: struct_in_struct::Simple {x: 3}} // gdb-command:print internal_padding_parent -// gdb-check:$2 = {x = {x = 4, y = 5}, y = {x = 6, y = 7}, z = {x = 8, y = 9}} +// gdbg-check:$2 = {x = {x = 4, y = 5}, y = {x = 6, y = 7}, z = {x = 8, y = 9}} +// gdbr-check:$2 = struct_in_struct::InternalPaddingParent {x: struct_in_struct::InternalPadding {x: 4, y: 5}, y: struct_in_struct::InternalPadding {x: 6, y: 7}, z: struct_in_struct::InternalPadding {x: 8, y: 9}} // gdb-command:print padding_at_end_parent -// gdb-check:$3 = {x = {x = 10, y = 11}, y = {x = 12, y = 13}, z = {x = 14, y = 15}} +// gdbg-check:$3 = {x = {x = 10, y = 11}, y = {x = 12, y = 13}, z = {x = 14, y = 15}} +// gdbr-check:$3 = struct_in_struct::PaddingAtEndParent {x: struct_in_struct::PaddingAtEnd {x: 10, y: 11}, y: struct_in_struct::PaddingAtEnd {x: 12, y: 13}, z: struct_in_struct::PaddingAtEnd {x: 14, y: 15}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/struct-style-enum.rs b/src/test/debuginfo/struct-style-enum.rs index 3376fc9bbd45..8abc139eb117 100644 --- a/src/test/debuginfo/struct-style-enum.rs +++ b/src/test/debuginfo/struct-style-enum.rs @@ -19,16 +19,20 @@ // gdb-command:run // gdb-command:print case1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, a = 0, b = 31868, c = 31868, d = 31868, e = 31868}, {RUST$ENUM$DISR = Case1, a = 0, b = 2088533116, c = 2088533116}, {RUST$ENUM$DISR = Case1, a = 0, b = 8970181431921507452}} +// gdbr-check:$1 = struct_style_enum::Regular::Case1{a: 0, b: 31868, c: 31868, d: 31868, e: 31868} // gdb-command:print case2 -// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, a = 0, b = 4369, c = 4369, d = 4369, e = 4369}, {RUST$ENUM$DISR = Case2, a = 0, b = 286331153, c = 286331153}, {RUST$ENUM$DISR = Case2, a = 0, b = 1229782938247303441}} +// gdbr-check:$2 = struct_style_enum::Regular::Case2{a: 0, b: 286331153, c: 286331153} // gdb-command:print case3 -// gdb-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}} +// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, a = 0, b = 22873, c = 22873, d = 22873, e = 22873}, {RUST$ENUM$DISR = Case3, a = 0, b = 1499027801, c = 1499027801}, {RUST$ENUM$DISR = Case3, a = 0, b = 6438275382588823897}} +// gdbr-check:$3 = struct_style_enum::Regular::Case3{a: 0, b: 6438275382588823897} // gdb-command:print univariant -// gdb-check:$4 = {{a = -1}} +// gdbg-check:$4 = {{a = -1}} +// gdbr-check:$4 = struct_style_enum::Univariant::TheOnlyCase{a: -1} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/struct-with-destructor.rs b/src/test/debuginfo/struct-with-destructor.rs index ad8731997abd..af70b4a63fd2 100644 --- a/src/test/debuginfo/struct-with-destructor.rs +++ b/src/test/debuginfo/struct-with-destructor.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + // min-lldb-version: 310 // compile-flags:-g @@ -16,16 +18,20 @@ // gdb-command:run // gdb-command:print simple -// gdb-check:$1 = {x = 10, y = 20} +// gdbg-check:$1 = {x = 10, y = 20} +// gdbr-check:$1 = struct_with_destructor::WithDestructor {x: 10, y: 20} // gdb-command:print noDestructor -// gdb-check:$2 = {a = {x = 10, y = 20}, guard = -1} +// gdbg-check:$2 = {a = {x = 10, y = 20}, guard = -1} +// gdbr-check:$2 = struct_with_destructor::NoDestructorGuarded {a: struct_with_destructor::NoDestructor {x: 10, y: 20}, guard: -1} // gdb-command:print withDestructor -// gdb-check:$3 = {a = {x = 10, y = 20}, guard = -1} +// gdbg-check:$3 = {a = {x = 10, y = 20}, guard = -1} +// gdbr-check:$3 = struct_with_destructor::WithDestructorGuarded {a: struct_with_destructor::WithDestructor {x: 10, y: 20}, guard: -1} // gdb-command:print nested -// gdb-check:$4 = {a = {a = {x = 7890, y = 9870}}} +// gdbg-check:$4 = {a = {a = {x = 7890, y = 9870}}} +// gdbr-check:$4 = struct_with_destructor::NestedOuter {a: struct_with_destructor::NestedInner {a: struct_with_destructor::WithDestructor {x: 7890, y: 9870}}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/tuple-in-struct.rs b/src/test/debuginfo/tuple-in-struct.rs index 1a7fde766f0d..dae1f5da542f 100644 --- a/src/test/debuginfo/tuple-in-struct.rs +++ b/src/test/debuginfo/tuple-in-struct.rs @@ -17,29 +17,39 @@ // gdb-command:run // gdb-command:print no_padding1 -// gdb-check:$1 = {x = {__0 = 0, __1 = 1}, y = 2, z = {__0 = 3, __1 = 4, __2 = 5}} +// gdbg-check:$1 = {x = {__0 = 0, __1 = 1}, y = 2, z = {__0 = 3, __1 = 4, __2 = 5}} +// gdbr-check:$1 = tuple_in_struct::NoPadding1 {x: (0, 1), y: 2, z: (3, 4, 5)} // gdb-command:print no_padding2 -// gdb-check:$2 = {x = {__0 = 6, __1 = 7}, y = {__0 = {__0 = 8, __1 = 9}, __1 = 10}} +// gdbg-check:$2 = {x = {__0 = 6, __1 = 7}, y = {__0 = {__0 = 8, __1 = 9}, __1 = 10}} +// gdbr-check:$2 = tuple_in_struct::NoPadding2 {x: (6, 7), y: ((8, 9), 10)} // gdb-command:print tuple_internal_padding -// gdb-check:$3 = {x = {__0 = 11, __1 = 12}, y = {__0 = 13, __1 = 14}} +// gdbg-check:$3 = {x = {__0 = 11, __1 = 12}, y = {__0 = 13, __1 = 14}} +// gdbr-check:$3 = tuple_in_struct::TupleInternalPadding {x: (11, 12), y: (13, 14)} // gdb-command:print struct_internal_padding -// gdb-check:$4 = {x = {__0 = 15, __1 = 16}, y = {__0 = 17, __1 = 18}} +// gdbg-check:$4 = {x = {__0 = 15, __1 = 16}, y = {__0 = 17, __1 = 18}} +// gdbr-check:$4 = tuple_in_struct::StructInternalPadding {x: (15, 16), y: (17, 18)} // gdb-command:print both_internally_padded -// gdb-check:$5 = {x = {__0 = 19, __1 = 20, __2 = 21}, y = {__0 = 22, __1 = 23}} +// gdbg-check:$5 = {x = {__0 = 19, __1 = 20, __2 = 21}, y = {__0 = 22, __1 = 23}} +// gdbr-check:$5 = tuple_in_struct::BothInternallyPadded {x: (19, 20, 21), y: (22, 23)} // gdb-command:print single_tuple -// gdb-check:$6 = {x = {__0 = 24, __1 = 25, __2 = 26}} +// gdbg-check:$6 = {x = {__0 = 24, __1 = 25, __2 = 26}} +// gdbr-check:$6 = tuple_in_struct::SingleTuple {x: (24, 25, 26)} // gdb-command:print tuple_padded_at_end -// gdb-check:$7 = {x = {__0 = 27, __1 = 28}, y = {__0 = 29, __1 = 30}} +// gdbg-check:$7 = {x = {__0 = 27, __1 = 28}, y = {__0 = 29, __1 = 30}} +// gdbr-check:$7 = tuple_in_struct::TuplePaddedAtEnd {x: (27, 28), y: (29, 30)} // gdb-command:print struct_padded_at_end -// gdb-check:$8 = {x = {__0 = 31, __1 = 32}, y = {__0 = 33, __1 = 34}} +// gdbg-check:$8 = {x = {__0 = 31, __1 = 32}, y = {__0 = 33, __1 = 34}} +// gdbr-check:$8 = tuple_in_struct::StructPaddedAtEnd {x: (31, 32), y: (33, 34)} // gdb-command:print both_padded_at_end -// gdb-check:$9 = {x = {__0 = 35, __1 = 36, __2 = 37}, y = {__0 = 38, __1 = 39}} +// gdbg-check:$9 = {x = {__0 = 35, __1 = 36, __2 = 37}, y = {__0 = 38, __1 = 39}} +// gdbr-check:$9 = tuple_in_struct::BothPaddedAtEnd {x: (35, 36, 37), y: (38, 39)} // gdb-command:print mixed_padding -// gdb-check:$10 = {x = {__0 = {__0 = 40, __1 = 41, __2 = 42}, __1 = {__0 = 43, __1 = 44}}, y = {__0 = 45, __1 = 46, __2 = 47, __3 = 48}} +// gdbg-check:$10 = {x = {__0 = {__0 = 40, __1 = 41, __2 = 42}, __1 = {__0 = 43, __1 = 44}}, y = {__0 = 45, __1 = 46, __2 = 47, __3 = 48}} +// gdbr-check:$10 = tuple_in_struct::MixedPadding {x: ((40, 41, 42), (43, 44)), y: (45, 46, 47, 48)} #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] diff --git a/src/test/debuginfo/tuple-in-tuple.rs b/src/test/debuginfo/tuple-in-tuple.rs index a514b69a2d31..4ebc740b9c0f 100644 --- a/src/test/debuginfo/tuple-in-tuple.rs +++ b/src/test/debuginfo/tuple-in-tuple.rs @@ -17,21 +17,28 @@ // gdb-command:run // gdb-command:print no_padding1 -// gdb-check:$1 = {__0 = {__0 = 0, __1 = 1}, __1 = 2, __2 = 3} +// gdbg-check:$1 = {__0 = {__0 = 0, __1 = 1}, __1 = 2, __2 = 3} +// gdbr-check:$1 = ((0, 1), 2, 3) // gdb-command:print no_padding2 -// gdb-check:$2 = {__0 = 4, __1 = {__0 = 5, __1 = 6}, __2 = 7} +// gdbg-check:$2 = {__0 = 4, __1 = {__0 = 5, __1 = 6}, __2 = 7} +// gdbr-check:$2 = (4, (5, 6), 7) // gdb-command:print no_padding3 -// gdb-check:$3 = {__0 = 8, __1 = 9, __2 = {__0 = 10, __1 = 11}} +// gdbg-check:$3 = {__0 = 8, __1 = 9, __2 = {__0 = 10, __1 = 11}} +// gdbr-check:$3 = (8, 9, (10, 11)) // gdb-command:print internal_padding1 -// gdb-check:$4 = {__0 = 12, __1 = {__0 = 13, __1 = 14}} +// gdbg-check:$4 = {__0 = 12, __1 = {__0 = 13, __1 = 14}} +// gdbr-check:$4 = (12, (13, 14)) // gdb-command:print internal_padding2 -// gdb-check:$5 = {__0 = 15, __1 = {__0 = 16, __1 = 17}} +// gdbg-check:$5 = {__0 = 15, __1 = {__0 = 16, __1 = 17}} +// gdbr-check:$5 = (15, (16, 17)) // gdb-command:print padding_at_end1 -// gdb-check:$6 = {__0 = 18, __1 = {__0 = 19, __1 = 20}} +// gdbg-check:$6 = {__0 = 18, __1 = {__0 = 19, __1 = 20}} +// gdbr-check:$6 = (18, (19, 20)) // gdb-command:print padding_at_end2 -// gdb-check:$7 = {__0 = {__0 = 21, __1 = 22}, __1 = 23} +// gdbg-check:$7 = {__0 = {__0 = 21, __1 = 22}, __1 = 23} +// gdbr-check:$7 = ((21, 22), 23) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/tuple-struct.rs b/src/test/debuginfo/tuple-struct.rs index a2ca8c2237b4..aa644d8419b5 100644 --- a/src/test/debuginfo/tuple-struct.rs +++ b/src/test/debuginfo/tuple-struct.rs @@ -17,22 +17,28 @@ // gdb-command:run // gdb-command:print no_padding16 -// gdb-check:$1 = {__0 = 10000, __1 = -10001} +// gdbg-check:$1 = {__0 = 10000, __1 = -10001} +// gdbr-check:$1 = tuple_struct::NoPadding16 (10000, -10001) // gdb-command:print no_padding32 -// gdb-check:$2 = {__0 = -10002, __1 = -10003.5, __2 = 10004} +// gdbg-check:$2 = {__0 = -10002, __1 = -10003.5, __2 = 10004} +// gdbr-check:$2 = tuple_struct::NoPadding32 (-10002, -10003.5, 10004) // gdb-command:print no_padding64 -// gdb-check:$3 = {__0 = -10005.5, __1 = 10006, __2 = 10007} +// gdbg-check:$3 = {__0 = -10005.5, __1 = 10006, __2 = 10007} +// gdbr-check:$3 = tuple_struct::NoPadding64 (-10005.5, 10006, 10007) // gdb-command:print no_padding163264 -// gdb-check:$4 = {__0 = -10008, __1 = 10009, __2 = 10010, __3 = 10011} +// gdbg-check:$4 = {__0 = -10008, __1 = 10009, __2 = 10010, __3 = 10011} +// gdbr-check:$4 = tuple_struct::NoPadding163264 (-10008, 10009, 10010, 10011) // gdb-command:print internal_padding -// gdb-check:$5 = {__0 = 10012, __1 = -10013} +// gdbg-check:$5 = {__0 = 10012, __1 = -10013} +// gdbr-check:$5 = tuple_struct::InternalPadding (10012, -10013) // gdb-command:print padding_at_end -// gdb-check:$6 = {__0 = -10014, __1 = 10015} +// gdbg-check:$6 = {__0 = -10014, __1 = 10015} +// gdbr-check:$6 = tuple_struct::PaddingAtEnd (-10014, 10015) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/tuple-style-enum.rs b/src/test/debuginfo/tuple-style-enum.rs index 52f171434b03..d05edec3e737 100644 --- a/src/test/debuginfo/tuple-style-enum.rs +++ b/src/test/debuginfo/tuple-style-enum.rs @@ -19,16 +19,20 @@ // gdb-command:run // gdb-command:print case1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}} +// gdbr-check:$1 = tuple_style_enum::Regular::Case1(0, 31868, 31868, 31868, 31868) // gdb-command:print case2 -// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}} +// gdbr-check:$2 = tuple_style_enum::Regular::Case2(0, 286331153, 286331153) // gdb-command:print case3 -// gdb-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}} +// gdbg-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}} +// gdbr-check:$3 = tuple_style_enum::Regular::Case3(0, 6438275382588823897) // gdb-command:print univariant -// gdb-check:$4 = {{__0 = -1}} +// gdbg-check:$4 = {{__0 = -1}} +// gdbr-check:$4 = tuple_style_enum::Univariant::TheOnlyCase(-1) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index 2419625cbd37..438a78743bb1 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -20,160 +20,206 @@ // STRUCTS // gdb-command:whatis simple_struct -// gdb-check:type = struct Struct1 +// gdbg-check:type = struct Struct1 +// gdbr-check:type = type_names::Struct1 // gdb-command:whatis generic_struct1 -// gdb-check:type = struct GenericStruct +// gdbg-check:type = struct GenericStruct +// gdbr-check:type = type_names::GenericStruct // gdb-command:whatis generic_struct2 -// gdb-check:type = struct GenericStruct usize> +// gdbg-check:type = struct GenericStruct usize> +// gdbr-check:type = type_names::GenericStruct usize> // gdb-command:whatis mod_struct -// gdb-check:type = struct Struct2 +// gdbg-check:type = struct Struct2 +// gdbr-check:type = type_names::mod1::Struct2 // ENUMS // gdb-command:whatis simple_enum_1 -// gdb-check:type = union Enum1 +// gdbg-check:type = union Enum1 +// gdbr-check:type = type_names::Enum1 // gdb-command:whatis simple_enum_2 -// gdb-check:type = union Enum1 +// gdbg-check:type = union Enum1 +// gdbr-check:type = type_names::Enum1 // gdb-command:whatis simple_enum_3 -// gdb-check:type = union Enum2 +// gdbg-check:type = union Enum2 +// gdbr-check:type = type_names::mod1::Enum2 // gdb-command:whatis generic_enum_1 -// gdb-check:type = union Enum3 +// gdbg-check:type = union Enum3 +// gdbr-check:type = type_names::mod1::mod2::Enum3 // gdb-command:whatis generic_enum_2 -// gdb-check:type = union Enum3 +// gdbg-check:type = union Enum3 +// gdbr-check:type = type_names::mod1::mod2::Enum3 // TUPLES // gdb-command:whatis tuple1 -// gdb-check:type = struct (u32, type_names::Struct1, type_names::mod1::mod2::Enum3) +// gdbg-check:type = struct (u32, type_names::Struct1, type_names::mod1::mod2::Enum3) +// gdbr-check:type = (u32, type_names::Struct1, type_names::mod1::mod2::Enum3) // gdb-command:whatis tuple2 -// gdb-check:type = struct ((type_names::Struct1, type_names::mod1::mod2::Struct3), type_names::mod1::Enum2, char) +// gdbg-check:type = struct ((type_names::Struct1, type_names::mod1::mod2::Struct3), type_names::mod1::Enum2, char) +// gdbr-check:type = ((type_names::Struct1, type_names::mod1::mod2::Struct3), type_names::mod1::Enum2, char) // BOX // gdb-command:whatis box1 -// gdb-check:type = struct (Box, i32) +// gdbg-check:type = struct (Box, i32) +// gdbr-check:type = (Box, i32) // gdb-command:whatis box2 -// gdb-check:type = struct (Box>, i32) +// gdbg-check:type = struct (Box>, i32) +// gdbr-check:type = (Box>, i32) // REFERENCES // gdb-command:whatis ref1 -// gdb-check:type = struct (&type_names::Struct1, i32) +// gdbg-check:type = struct (&type_names::Struct1, i32) +// gdbr-check:type = (&type_names::Struct1, i32) // gdb-command:whatis ref2 -// gdb-check:type = struct (&type_names::GenericStruct, i32) +// gdbg-check:type = struct (&type_names::GenericStruct, i32) +// gdbr-check:type = (&type_names::GenericStruct, i32) // gdb-command:whatis mut_ref1 -// gdb-check:type = struct (&mut type_names::Struct1, i32) +// gdbg-check:type = struct (&mut type_names::Struct1, i32) +// gdbr-check:type = (&mut type_names::Struct1, i32) // gdb-command:whatis mut_ref2 -// gdb-check:type = struct (&mut type_names::GenericStruct, i32) +// gdbg-check:type = struct (&mut type_names::GenericStruct, i32) +// gdbr-check:type = (&mut type_names::GenericStruct, i32) // RAW POINTERS // gdb-command:whatis mut_ptr1 -// gdb-check:type = struct (*mut type_names::Struct1, isize) +// gdbg-check:type = struct (*mut type_names::Struct1, isize) +// gdbr-check:type = (*mut type_names::Struct1, isize) // gdb-command:whatis mut_ptr2 -// gdb-check:type = struct (*mut isize, isize) +// gdbg-check:type = struct (*mut isize, isize) +// gdbr-check:type = (*mut isize, isize) // gdb-command:whatis mut_ptr3 -// gdb-check:type = struct (*mut type_names::mod1::mod2::Enum3, isize) +// gdbg-check:type = struct (*mut type_names::mod1::mod2::Enum3, isize) +// gdbr-check:type = (*mut type_names::mod1::mod2::Enum3, isize) // gdb-command:whatis const_ptr1 -// gdb-check:type = struct (*const type_names::Struct1, isize) +// gdbg-check:type = struct (*const type_names::Struct1, isize) +// gdbr-check:type = (*const type_names::Struct1, isize) // gdb-command:whatis const_ptr2 -// gdb-check:type = struct (*const isize, isize) +// gdbg-check:type = struct (*const isize, isize) +// gdbr-check:type = (*const isize, isize) // gdb-command:whatis const_ptr3 -// gdb-check:type = struct (*const type_names::mod1::mod2::Enum3, isize) +// gdbg-check:type = struct (*const type_names::mod1::mod2::Enum3, isize) +// gdbr-check:type = (*const type_names::mod1::mod2::Enum3, isize) // VECTORS // gdb-command:whatis fixed_size_vec1 -// gdb-check:type = struct ([type_names::Struct1; 3], i16) +// gdbg-check:type = struct ([type_names::Struct1; 3], i16) +// gdbr-check:type = ([type_names::Struct1; 3], i16) // gdb-command:whatis fixed_size_vec2 -// gdb-check:type = struct ([usize; 3], i16) +// gdbg-check:type = struct ([usize; 3], i16) +// gdbr-check:type = ([usize; 3], i16) // gdb-command:whatis slice1 -// gdb-check:type = struct &[usize] +// gdbg-check:type = struct &[usize] +// gdbr-check:type = &[usize] // gdb-command:whatis slice2 -// gdb-check:type = struct &[type_names::mod1::Enum2] +// gdbg-check:type = struct &[type_names::mod1::Enum2] +// gdbr-check:type = &[type_names::mod1::Enum2] // TRAITS // gdb-command:whatis box_trait -// gdb-check:type = struct Box +// gdbg-check:type = struct Box +// gdbr-check:type = type_names::Box // gdb-command:whatis ref_trait -// gdb-check:type = struct &Trait1 +// gdbg-check:type = struct &Trait1 +// gdbr-check:type = type_names::&Trait1 // gdb-command:whatis mut_ref_trait -// gdb-check:type = struct &mut Trait1 +// gdbg-check:type = struct &mut Trait1 +// gdbr-check:type = type_names::&mut Trait1 // gdb-command:whatis generic_box_trait -// gdb-check:type = struct Box> +// gdbg-check:type = struct Box> +// gdbr-check:type = type_names::Box> // gdb-command:whatis generic_ref_trait -// gdb-check:type = struct &Trait2 +// gdbg-check:type = struct &Trait2 +// gdbr-check:type = type_names::&Trait2 // gdb-command:whatis generic_mut_ref_trait -// gdb-check:type = struct &mut Trait2> +// gdbg-check:type = struct &mut Trait2> +// gdbr-check:type = type_names::&mut Trait2> // BARE FUNCTIONS // gdb-command:whatis rust_fn -// gdb-check:type = struct (fn(core::option::Option, core::option::Option<&type_names::mod1::Struct2>), usize) +// gdbg-check:type = struct (fn(core::option::Option, core::option::Option<&type_names::mod1::Struct2>), usize) +// gdbr-check:type = (fn(core::option::Option, core::option::Option<&type_names::mod1::Struct2>), usize) // gdb-command:whatis extern_c_fn -// gdb-check:type = struct (extern "C" fn(isize), usize) +// gdbg-check:type = struct (extern "C" fn(isize), usize) +// gdbr-check:type = (extern "C" fn(isize), usize) // gdb-command:whatis unsafe_fn -// gdb-check:type = struct (unsafe fn(core::result::Result), usize) +// gdbg-check:type = struct (unsafe fn(core::result::Result), usize) +// gdbr-check:type = (unsafe fn(core::result::Result), usize) // gdb-command:whatis extern_stdcall_fn -// gdb-check:type = struct (extern "stdcall" fn(), usize) +// gdbg-check:type = struct (extern "stdcall" fn(), usize) +// gdbr-check:type = (extern "stdcall" fn(), usize) // gdb-command:whatis rust_fn_with_return_value -// gdb-check:type = struct (fn(f64) -> usize, usize) +// gdbg-check:type = struct (fn(f64) -> usize, usize) +// gdbr-check:type = (fn(f64) -> usize, usize) // gdb-command:whatis extern_c_fn_with_return_value -// gdb-check:type = struct (extern "C" fn() -> type_names::Struct1, usize) +// gdbg-check:type = struct (extern "C" fn() -> type_names::Struct1, usize) +// gdbr-check:type = (extern "C" fn() -> type_names::Struct1, usize) // gdb-command:whatis unsafe_fn_with_return_value -// gdb-check:type = struct (unsafe fn(type_names::GenericStruct) -> type_names::mod1::Struct2, usize) +// gdbg-check:type = struct (unsafe fn(type_names::GenericStruct) -> type_names::mod1::Struct2, usize) +// gdbr-check:type = (unsafe fn(type_names::GenericStruct) -> type_names::mod1::Struct2, usize) // gdb-command:whatis extern_stdcall_fn_with_return_value -// gdb-check:type = struct (extern "stdcall" fn(Box) -> usize, usize) +// gdbg-check:type = struct (extern "stdcall" fn(Box) -> usize, usize) +// gdbr-check:type = (extern "stdcall" fn(Box) -> usize, usize) // gdb-command:whatis generic_function_int -// gdb-check:type = struct (fn(isize) -> isize, usize) +// gdbg-check:type = struct (fn(isize) -> isize, usize) +// gdbr-check:type = (fn(isize) -> isize, usize) // gdb-command:whatis generic_function_struct3 -// gdb-check:type = struct (fn(type_names::mod1::mod2::Struct3) -> type_names::mod1::mod2::Struct3, usize) +// gdbg-check:type = struct (fn(type_names::mod1::mod2::Struct3) -> type_names::mod1::mod2::Struct3, usize) +// gdbr-check:type = (fn(type_names::mod1::mod2::Struct3) -> type_names::mod1::mod2::Struct3, usize) // gdb-command:whatis variadic_function -// gdb-check:type = struct (unsafe extern "C" fn(*const u8, ...) -> isize, usize) +// gdbg-check:type = struct (unsafe extern "C" fn(*const u8, ...) -> isize, usize) +// gdbr-check:type = (unsafe extern "C" fn(*const u8, ...) -> isize, usize) // CLOSURES // gdb-command:whatis closure1 -// gdb-check:type = struct (closure, usize) +// gdbg-check:type = struct (closure, usize) +// gdbr-check:type = (closure, usize) // gdb-command:whatis closure2 -// gdb-check:type = struct (closure, usize) +// gdbg-check:type = struct (closure, usize) +// gdbr-check:type = (closure, usize) #![feature(box_syntax)] #![allow(unused_variables)] diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs index 319927c979bf..26e73a08ea13 100644 --- a/src/test/debuginfo/union-smoke.rs +++ b/src/test/debuginfo/union-smoke.rs @@ -16,9 +16,11 @@ // gdb-command:run // gdb-command:print u -// gdb-check:$1 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514} +// gdbg-check:$1 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514} +// gdbr-check:$1 = union_smoke::U {a: (2, 2), b: 514} // gdb-command:print union_smoke::SU -// gdb-check:$2 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257} +// gdbg-check:$2 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257} +// gdbr-check:$2 = union_smoke::U {a: (1, 1), b: 257} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/unique-enum.rs b/src/test/debuginfo/unique-enum.rs index bbf13ec756ad..e882544b802b 100644 --- a/src/test/debuginfo/unique-enum.rs +++ b/src/test/debuginfo/unique-enum.rs @@ -18,13 +18,16 @@ // gdb-command:run // gdb-command:print *the_a -// gdb-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbg-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}} +// gdbr-check:$1 = unique_enum::ABC::TheA{x: 0, y: 8970181431921507452} // gdb-command:print *the_b -// gdb-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}} +// gdbg-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}} +// gdbr-check:$2 = unique_enum::ABC::TheB(0, 286331153, 286331153) // gdb-command:print *univariant -// gdb-check:$3 = {{__0 = 123234}} +// gdbg-check:$3 = {{__0 = 123234}} +// gdbr-check:$3 = unique_enum::Univariant::TheOnlyCase(123234) // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs index 7090377e5db1..b9a1d73b6d86 100644 --- a/src/test/debuginfo/var-captured-in-nested-closure.rs +++ b/src/test/debuginfo/var-captured-in-nested-closure.rs @@ -21,9 +21,11 @@ // gdb-command:print constant // gdb-check:$2 = 2 // gdb-command:print a_struct -// gdb-check:$3 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$3 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$3 = var_captured_in_nested_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *struct_ref -// gdb-check:$4 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$4 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$4 = var_captured_in_nested_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *owned // gdb-check:$5 = 6 // gdb-command:print closure_local @@ -35,9 +37,11 @@ // gdb-command:print constant // gdb-check:$8 = 2 // gdb-command:print a_struct -// gdb-check:$9 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$9 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$9 = var_captured_in_nested_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *struct_ref -// gdb-check:$10 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$10 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$10 = var_captured_in_nested_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *owned // gdb-check:$11 = 6 // gdb-command:print closure_local diff --git a/src/test/debuginfo/var-captured-in-sendable-closure.rs b/src/test/debuginfo/var-captured-in-sendable-closure.rs index b415546faeac..120bbdd7ba90 100644 --- a/src/test/debuginfo/var-captured-in-sendable-closure.rs +++ b/src/test/debuginfo/var-captured-in-sendable-closure.rs @@ -19,7 +19,8 @@ // gdb-command:print constant // gdb-check:$1 = 1 // gdb-command:print a_struct -// gdb-check:$2 = {a = -2, b = 3.5, c = 4} +// gdbg-check:$2 = {a = -2, b = 3.5, c = 4} +// gdbr-check:$2 = var_captured_in_sendable_closure::Struct {a: -2, b: 3.5, c: 4} // gdb-command:print *owned // gdb-check:$3 = 5 // gdb-command:continue diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs index e60f964dd095..c795a095b976 100644 --- a/src/test/debuginfo/var-captured-in-stack-closure.rs +++ b/src/test/debuginfo/var-captured-in-stack-closure.rs @@ -21,9 +21,11 @@ // gdb-command:print constant // gdb-check:$2 = 2 // gdb-command:print a_struct -// gdb-check:$3 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$3 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$3 = var_captured_in_stack_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *struct_ref -// gdb-check:$4 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$4 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$4 = var_captured_in_stack_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *owned // gdb-check:$5 = 6 @@ -34,9 +36,11 @@ // gdb-command:print constant // gdb-check:$7 = 2 // gdb-command:print a_struct -// gdb-check:$8 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$8 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$8 = var_captured_in_stack_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *struct_ref -// gdb-check:$9 = {a = -3, b = 4.5, c = 5} +// gdbg-check:$9 = {a = -3, b = 4.5, c = 5} +// gdbr-check:$9 = var_captured_in_stack_closure::Struct {a: -3, b: 4.5, c: 5} // gdb-command:print *owned // gdb-check:$10 = 6 diff --git a/src/test/debuginfo/vec-slices.rs b/src/test/debuginfo/vec-slices.rs index cdb5bc4ecfb6..5553f8427e90 100644 --- a/src/test/debuginfo/vec-slices.rs +++ b/src/test/debuginfo/vec-slices.rs @@ -21,42 +21,57 @@ // gdb-command:print singleton.length // gdb-check:$2 = 1 -// gdb-command:print *((int64_t[1]*)(singleton.data_ptr)) -// gdb-check:$3 = {1} +// gdbg-command:print *((int64_t[1]*)(singleton.data_ptr)) +// gdbr-command:print *(singleton.data_ptr as &[i64; 1]) +// gdbg-check:$3 = {1} +// gdbr-check:$3 = [1] // gdb-command:print multiple.length // gdb-check:$4 = 4 -// gdb-command:print *((int64_t[4]*)(multiple.data_ptr)) -// gdb-check:$5 = {2, 3, 4, 5} +// gdbg-command:print *((int64_t[4]*)(multiple.data_ptr)) +// gdbr-command:print *(multiple.data_ptr as &[i64; 4]) +// gdbg-check:$5 = {2, 3, 4, 5} +// gdbr-check:$5 = [2, 3, 4, 5] // gdb-command:print slice_of_slice.length // gdb-check:$6 = 2 -// gdb-command:print *((int64_t[2]*)(slice_of_slice.data_ptr)) -// gdb-check:$7 = {3, 4} +// gdbg-command:print *((int64_t[2]*)(slice_of_slice.data_ptr)) +// gdbr-command:print *(slice_of_slice.data_ptr as &[i64; 2]) +// gdbg-check:$7 = {3, 4} +// gdbr-check:$7 = [3, 4] // gdb-command:print padded_tuple.length // gdb-check:$8 = 2 // gdb-command:print padded_tuple.data_ptr[0] -// gdb-check:$9 = {__0 = 6, __1 = 7} +// gdbg-check:$9 = {__0 = 6, __1 = 7} +// gdbr-check:$9 = (6, 7) // gdb-command:print padded_tuple.data_ptr[1] -// gdb-check:$10 = {__0 = 8, __1 = 9} +// gdbg-check:$10 = {__0 = 8, __1 = 9} +// gdbr-check:$10 = (8, 9) // gdb-command:print padded_struct.length // gdb-check:$11 = 2 // gdb-command:print padded_struct.data_ptr[0] -// gdb-check:$12 = {x = 10, y = 11, z = 12} +// gdbg-check:$12 = {x = 10, y = 11, z = 12} +// gdbr-check:$12 = vec_slices::AStruct {x: 10, y: 11, z: 12} // gdb-command:print padded_struct.data_ptr[1] -// gdb-check:$13 = {x = 13, y = 14, z = 15} +// gdbg-check:$13 = {x = 13, y = 14, z = 15} +// gdbr-check:$13 = vec_slices::AStruct {x: 13, y: 14, z: 15} -// gdb-command:print 'vec_slices::MUT_VECT_SLICE'.length +// gdbg-command:print 'vec_slices::MUT_VECT_SLICE'.length +// gdbr-command:print MUT_VECT_SLICE.length // gdb-check:$14 = 2 -// gdb-command:print *((int64_t[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr)) -// gdb-check:$15 = {64, 65} +// gdbg-command:print *((int64_t[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr)) +// gdbr-command:print *(MUT_VECT_SLICE.data_ptr as &[i64; 2]) +// gdbg-check:$15 = {64, 65} +// gdbr-check:$15 = [64, 65] //gdb-command:print mut_slice.length //gdb-check:$16 = 5 -//gdb-command:print *((int64_t[5]*)(mut_slice.data_ptr)) -//gdb-check:$17 = {1, 2, 3, 4, 5} +//gdbg-command:print *((int64_t[5]*)(mut_slice.data_ptr)) +//gdbr-command:print *(mut_slice.data_ptr as &[i64; 5]) +//gdbg-check:$17 = {1, 2, 3, 4, 5} +//gdbr-check:$17 = [1, 2, 3, 4, 5] // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/vec.rs b/src/test/debuginfo/vec.rs index c9827a02fc75..fbb33b94d957 100644 --- a/src/test/debuginfo/vec.rs +++ b/src/test/debuginfo/vec.rs @@ -16,9 +16,11 @@ // gdb-command:run // gdb-command:print a -// gdb-check:$1 = {1, 2, 3} +// gdbg-check:$1 = {1, 2, 3} +// gdbr-check:$1 = [1, 2, 3] // gdb-command:print vec::VECT -// gdb-check:$2 = {4, 5, 6} +// gdbg-check:$2 = {4, 5, 6} +// gdbr-check:$2 = [4, 5, 6] // === LLDB TESTS ================================================================================== diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs new file mode 100644 index 000000000000..7bfd8077a3da --- /dev/null +++ b/src/test/incremental/hashes/let_expressions.rs @@ -0,0 +1,228 @@ +// 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. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for let expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + +// Change Name ----------------------------------------------------------------- +#[cfg(cfail1)] +pub fn change_name() { + let _x = 2u64; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_name() { + let _y = 2u64; +} + + + +// Add Type -------------------------------------------------------------------- +#[cfg(cfail1)] +pub fn add_type() { + let _x = 2u32; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_type() { + let _x: u32 = 2u32; +} + + + +// Change Type ----------------------------------------------------------------- +#[cfg(cfail1)] +pub fn change_type() { + let _x: u64 = 2; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_type() { + let _x: u8 = 2; +} + + + +// Change Mutability of Reference Type ----------------------------------------- +#[cfg(cfail1)] +pub fn change_mutability_of_reference_type() { + let _x: &u64; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_mutability_of_reference_type() { + let _x: &mut u64; +} + + + +// Change Mutability of Slot --------------------------------------------------- +#[cfg(cfail1)] +pub fn change_mutability_of_slot() { + let mut _x: u64 = 0; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_mutability_of_slot() { + let _x: u64 = 0; +} + + + +// Change Simple Binding to Pattern -------------------------------------------- +#[cfg(cfail1)] +pub fn change_simple_binding_to_pattern() { + let _x = (0u8, 'x'); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_simple_binding_to_pattern() { + let (_a, _b) = (0u8, 'x'); +} + + + +// Change Name in Pattern ------------------------------------------------------ +#[cfg(cfail1)] +pub fn change_name_in_pattern() { + let (_a, _b) = (1u8, 'y'); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_name_in_pattern() { + let (_a, _c) = (1u8, 'y'); +} + + + +// Add `ref` in Pattern -------------------------------------------------------- +#[cfg(cfail1)] +pub fn add_ref_in_pattern() { + let (_a, _b) = (1u8, 'y'); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_ref_in_pattern() { + let (ref _a, _b) = (1u8, 'y'); +} + + + +// Add `&` in Pattern ---------------------------------------------------------- +#[cfg(cfail1)] +pub fn add_amp_in_pattern() { + let (_a, _b) = (&1u8, 'y'); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_amp_in_pattern() { + let (&_a, _b) = (&1u8, 'y'); +} + + + +// Change Mutability of Binding in Pattern ------------------------------------- +#[cfg(cfail1)] +pub fn change_mutability_of_binding_in_pattern() { + let (_a, _b) = (99u8, 'q'); +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_mutability_of_binding_in_pattern() { + let (mut _a, _b) = (99u8, 'q'); +} + + + +// Add Initializer ------------------------------------------------------------- +#[cfg(cfail1)] +pub fn add_initializer() { + let _x: i16; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_initializer() { + let _x: i16 = 3i16; +} + + + +// Change Initializer ---------------------------------------------------------- +#[cfg(cfail1)] +pub fn change_initializer() { + let _x = 4u16; +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_initializer() { + let _x = 5u16; +} diff --git a/src/test/incremental/hashes/match_expressions.rs b/src/test/incremental/hashes/match_expressions.rs new file mode 100644 index 000000000000..95e94a91c5bb --- /dev/null +++ b/src/test/incremental/hashes/match_expressions.rs @@ -0,0 +1,342 @@ +// 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. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for match expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph + + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + +// Add Arm --------------------------------------------------------------------- +#[cfg(cfail1)] +pub fn add_arm(x: u32) -> u32 { + match x { + 0 => 0, + 1 => 1, + _ => 100, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_arm(x: u32) -> u32 { + match x { + 0 => 0, + 1 => 1, + 2 => 2, + _ => 100, + } +} + + + +// Change Order Of Arms -------------------------------------------------------- +#[cfg(cfail1)] +pub fn change_order_of_arms(x: u32) -> u32 { + match x { + 0 => 0, + 1 => 1, + _ => 100, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_order_of_arms(x: u32) -> u32 { + match x { + 1 => 1, + 0 => 0, + _ => 100, + } +} + + + +// Add Guard Clause ------------------------------------------------------------ +#[cfg(cfail1)] +pub fn add_guard_clause(x: u32, y: bool) -> u32 { + match x { + 0 => 0, + 1 => 1, + _ => 100, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_guard_clause(x: u32, y: bool) -> u32 { + match x { + 0 => 0, + 1 if y => 1, + _ => 100, + } +} + + + +// Change Guard Clause ------------------------------------------------------------ +#[cfg(cfail1)] +pub fn change_guard_clause(x: u32, y: bool) -> u32 { + match x { + 0 => 0, + 1 if y => 1, + _ => 100, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_guard_clause(x: u32, y: bool) -> u32 { + match x { + 0 => 0, + 1 if !y => 1, + _ => 100, + } +} + + + +// Add @-Binding --------------------------------------------------------------- +#[cfg(cfail1)] +pub fn add_at_binding(x: u32) -> u32 { + match x { + 0 => 0, + 1 => 1, + _ => x, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_at_binding(x: u32) -> u32 { + match x { + 0 => 0, + 1 => 1, + x @ _ => x, + } +} + + + +// Change Name of @-Binding ---------------------------------------------------- +#[cfg(cfail1)] +pub fn change_name_of_at_binding(x: u32) -> u32 { + match x { + 0 => 0, + 1 => 1, + x @ _ => 7, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_name_of_at_binding(x: u32) -> u32 { + match x { + 0 => 0, + 1 => 1, + y @ _ => 7, + } +} + + + +// Change Simple Binding To Pattern -------------------------------------------- +#[cfg(cfail1)] +pub fn change_simple_name_to_pattern(x: u32) -> u32 { + match (x, x & 1) { + (0, 0) => 0, + a => 1 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_simple_name_to_pattern(x: u32) -> u32 { + match (x, x & 1) { + (0, 0) => 0, + (x, y) => 1 + } +} + + + +// Change Name In Pattern ------------------------------------------------------ +#[cfg(cfail1)] +pub fn change_name_in_pattern(x: u32) -> u32 { + match (x, x & 1) { + (a, 0) => 0, + (a, 1) => a, + _ => 100, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_name_in_pattern(x: u32) -> u32 { + match (x, x & 1) { + (b, 0) => 0, + (a, 1) => a, + _ => 100, + } +} + + + +// Change Mutability Of Binding In Pattern ------------------------------------- +#[cfg(cfail1)] +pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 { + match (x, x & 1) { + (a, 0) => 0, + _ => 1 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 { + match (x, x & 1) { + (mut a, 0) => 0, + _ => 1 + } +} + + + +// Add `ref` To Binding In Pattern ------------------------------------- +#[cfg(cfail1)] +pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 { + match (x, x & 1) { + (a, 0) => 0, + _ => 1 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 { + match (x, x & 1) { + (ref a, 0) => 0, + _ => 1, + } +} + + + +// Add `&` To Binding In Pattern ------------------------------------- +#[cfg(cfail1)] +pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { + match (&x, x & 1) { + (a, 0) => 0, + _ => 1 + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { + match (&x, x & 1) { + (&a, 0) => 0, + _ => 1, + } +} + + + +// Change RHS Of Arm ----------------------------------------------------------- +#[cfg(cfail1)] +pub fn change_rhs_of_arm(x: u32) -> u32 { + match x { + 0 => 0, + 1 => 1, + _ => 2, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn change_rhs_of_arm(x: u32) -> u32 { + match x { + 0 => 0, + 1 => 3, + _ => 2, + } +} + + + +// Add Alternative To Arm ------------------------------------------------------ +#[cfg(cfail1)] +pub fn add_alternative_to_arm(x: u32) -> u32 { + match x { + 0 => 0, + 1 => 1, + _ => 2, + } +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfail2")] +#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn add_alternative_to_arm(x: u32) -> u32 { + match x { + 0 | 7 => 0, + 1 => 3, + _ => 2, + } +} diff --git a/src/test/incremental/hashes/unary_and_binary_exprs.rs b/src/test/incremental/hashes/unary_and_binary_exprs.rs new file mode 100644 index 000000000000..2c0ca0043122 --- /dev/null +++ b/src/test/incremental/hashes/unary_and_binary_exprs.rs @@ -0,0 +1,514 @@ +// 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. + + +// This test case tests the incremental compilation hash (ICH) implementation +// for unary and binary expressions. + +// The general pattern followed here is: Change one thing between rev1 and rev2 +// and make sure that the hash has changed, then change nothing between rev2 and +// rev3 and make sure that the hash has not changed. + +// must-compile-successfully +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph -Z force-overflow-checks=off + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![crate_type="rlib"] + + +// Change constant operand of negation ----------------------------------------- +#[cfg(cfail1)] +pub fn const_negation() -> i32 { + -10 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn const_negation() -> i32 { + -1 +} + + + +// Change constant operand of bitwise not -------------------------------------- +#[cfg(cfail1)] +pub fn const_bitwise_not() -> i32 { + !100 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn const_bitwise_not() -> i32 { + !99 +} + + + +// Change variable operand of negation ----------------------------------------- +#[cfg(cfail1)] +pub fn var_negation(x: i32, y: i32) -> i32 { + -x +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn var_negation(x: i32, y: i32) -> i32 { + -y +} + + + +// Change variable operand of bitwise not -------------------------------------- +#[cfg(cfail1)] +pub fn var_bitwise_not(x: i32, y: i32) -> i32 { + !x +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn var_bitwise_not(x: i32, y: i32) -> i32 { + !y +} + + + +// Change variable operand of deref -------------------------------------------- +#[cfg(cfail1)] +pub fn var_deref(x: &i32, y: &i32) -> i32 { + *x +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn var_deref(x: &i32, y: &i32) -> i32 { + *y +} + + + +// Change first constant operand of addition ----------------------------------- +#[cfg(cfail1)] +pub fn first_const_add() -> i32 { + 1 + 3 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn first_const_add() -> i32 { + 2 + 3 +} + + + +// Change second constant operand of addition ----------------------------------- +#[cfg(cfail1)] +pub fn second_const_add() -> i32 { + 1 + 2 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn second_const_add() -> i32 { + 1 + 3 +} + + + +// Change first variable operand of addition ----------------------------------- +#[cfg(cfail1)] +pub fn first_var_add(a: i32, b: i32) -> i32 { + a + 2 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn first_var_add(a: i32, b: i32) -> i32 { + b + 2 +} + + + +// Change second variable operand of addition ---------------------------------- +#[cfg(cfail1)] +pub fn second_var_add(a: i32, b: i32) -> i32 { + 1 + a +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn second_var_add(a: i32, b: i32) -> i32 { + 1 + b +} + + + +// Change operator from + to - ------------------------------------------------- +#[cfg(cfail1)] +pub fn plus_to_minus(a: i32) -> i32 { + 1 + a +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn plus_to_minus(a: i32) -> i32 { + 1 - a +} + + + +// Change operator from + to * ------------------------------------------------- +#[cfg(cfail1)] +pub fn plus_to_mult(a: i32) -> i32 { + 1 + a +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn plus_to_mult(a: i32) -> i32 { + 1 * a +} + + + +// Change operator from + to / ------------------------------------------------- +#[cfg(cfail1)] +pub fn plus_to_div(a: i32) -> i32 { + 1 + a +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn plus_to_div(a: i32) -> i32 { + 1 / a +} + + + +// Change operator from + to % ------------------------------------------------- +#[cfg(cfail1)] +pub fn plus_to_mod(a: i32) -> i32 { + 1 + a +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn plus_to_mod(a: i32) -> i32 { + 1 % a +} + + + +// Change operator from && to || ----------------------------------------------- +#[cfg(cfail1)] +pub fn and_to_or(a: bool, b: bool) -> bool { + a && b +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn and_to_or(a: bool, b: bool) -> bool { + a || b +} + + + +// Change operator from & to | ------------------------------------------------- +#[cfg(cfail1)] +pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 { + 1 & a +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 { + 1 | a +} + + + +// Change operator from & to ^ ------------------------------------------------- +#[cfg(cfail1)] +pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 { + 1 & a +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 { + 1 ^ a +} + + + +// Change operator from & to << ------------------------------------------------ +#[cfg(cfail1)] +pub fn bitwise_and_to_lshift(a: i32) -> i32 { + a & 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn bitwise_and_to_lshift(a: i32) -> i32 { + a << 1 +} + + + +// Change operator from & to >> ------------------------------------------------ +#[cfg(cfail1)] +pub fn bitwise_and_to_rshift(a: i32) -> i32 { + a & 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn bitwise_and_to_rshift(a: i32) -> i32 { + a >> 1 +} + + + +// Change operator from == to != ----------------------------------------------- +#[cfg(cfail1)] +pub fn eq_to_uneq(a: i32) -> bool { + a == 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn eq_to_uneq(a: i32) -> bool { + a != 1 +} + + + +// Change operator from == to < ------------------------------------------------ +#[cfg(cfail1)] +pub fn eq_to_lt(a: i32) -> bool { + a == 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn eq_to_lt(a: i32) -> bool { + a < 1 +} + + + +// Change operator from == to > ------------------------------------------------ +#[cfg(cfail1)] +pub fn eq_to_gt(a: i32) -> bool { + a == 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn eq_to_gt(a: i32) -> bool { + a > 1 +} + + + +// Change operator from == to <= ----------------------------------------------- +#[cfg(cfail1)] +pub fn eq_to_le(a: i32) -> bool { + a == 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn eq_to_le(a: i32) -> bool { + a <= 1 +} + + + +// Change operator from == to >= ----------------------------------------------- +#[cfg(cfail1)] +pub fn eq_to_ge(a: i32) -> bool { + a == 1 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn eq_to_ge(a: i32) -> bool { + a >= 1 +} + + + +// Change type in cast expression ---------------------------------------------- +#[cfg(cfail1)] +pub fn type_cast(a: u8) -> u64 { + let b = a as i32; + let c = b as u64; + c +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn type_cast(a: u8) -> u64 { + let b = a as u32; + let c = b as u64; + c +} + + + +// Change value in cast expression --------------------------------------------- +#[cfg(cfail1)] +pub fn value_cast(a: u32) -> i32 { + 1 as i32 +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn value_cast(a: u32) -> i32 { + 2 as i32 +} + + + +// Change l-value in assignment ------------------------------------------------ +#[cfg(cfail1)] +pub fn lvalue() -> i32 { + let mut x = 10; + let mut y = 11; + x = 9; + x +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn lvalue() -> i32 { + let mut x = 10; + let mut y = 11; + y = 9; + x +} + + + +// Change r-value in assignment ------------------------------------------------ +#[cfg(cfail1)] +pub fn rvalue() -> i32 { + let mut x = 10; + x = 9; + x +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn rvalue() -> i32 { + let mut x = 10; + x = 8; + x +} + + + +// Change index into slice ----------------------------------------------------- +#[cfg(cfail1)] +pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 { + s[i] +} + +#[cfg(not(cfail1))] +#[rustc_dirty(label="Hir", cfg="cfails2")] +#[rustc_clean(label="Hir", cfg="cfails3")] +#[rustc_metadata_dirty(cfg="cfail2")] +#[rustc_metadata_clean(cfg="cfail3")] +pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 { + s[j] +} diff --git a/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs b/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs index 9c7721589d9b..70055a101815 100644 --- a/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs +++ b/src/test/parse-fail/associated-types-project-from-hrtb-explicit.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error // Test you can't use a higher-ranked trait bound inside of a qualified // path (just won't parse). diff --git a/src/test/parse-fail/closure-return-syntax.rs b/src/test/parse-fail/closure-return-syntax.rs index da6245597f8f..1da673591801 100644 --- a/src/test/parse-fail/closure-return-syntax.rs +++ b/src/test/parse-fail/closure-return-syntax.rs @@ -12,5 +12,6 @@ // unless it uses braces. fn main() { - let x = || -> i32 22; //~ ERROR expected `{`, found `22` + let x = || -> i32 22; + //~^ ERROR expected one of `!`, `(`, `::`, `<`, or `{`, found `22` } diff --git a/src/test/parse-fail/generic-non-trailing-defaults.rs b/src/test/parse-fail/generic-non-trailing-defaults.rs index 26ee6ce80d68..2bb593258ae4 100644 --- a/src/test/parse-fail/generic-non-trailing-defaults.rs +++ b/src/test/parse-fail/generic-non-trailing-defaults.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error struct Heap; diff --git a/src/test/parse-fail/issue-17904.rs b/src/test/parse-fail/issue-17904.rs index 580b8c66c748..de5aeb02ab78 100644 --- a/src/test/parse-fail/issue-17904.rs +++ b/src/test/parse-fail/issue-17904.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error 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. diff --git a/src/test/parse-fail/lex-bad-octal-literal.rs b/src/test/parse-fail/lex-bad-octal-literal.rs index bf9880cb6cfb..c8406af52ae0 100644 --- a/src/test/parse-fail/lex-bad-octal-literal.rs +++ b/src/test/parse-fail/lex-bad-octal-literal.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z parse-only -Z continue-parse-after-error + fn main() { 0o18; //~ ERROR invalid digit for a base 8 literal 0o1234_9_5670; //~ ERROR invalid digit for a base 8 literal diff --git a/src/test/parse-fail/lifetime-no-keyword.rs b/src/test/parse-fail/lifetime-no-keyword.rs index 9ca81d9918ef..a8771ae93af5 100644 --- a/src/test/parse-fail/lifetime-no-keyword.rs +++ b/src/test/parse-fail/lifetime-no-keyword.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error fn foo<'a>(a: &'a isize) { } fn bar(a: &'static isize) { } diff --git a/src/test/parse-fail/raw-byte-string-literals.rs b/src/test/parse-fail/raw-byte-string-literals.rs index d6be8fce53e0..2e33f98add6b 100644 --- a/src/test/parse-fail/raw-byte-string-literals.rs +++ b/src/test/parse-fail/raw-byte-string-literals.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error pub fn main() { - br"é"; //~ raw byte string must be ASCII - br##~"a"~##; //~ only `#` is allowed in raw string delimitation + br"é"; //~ ERROR raw byte string must be ASCII + br##~"a"~##; //~ ERROR only `#` is allowed in raw string delimitation } diff --git a/src/test/parse-fail/removed-syntax-field-let.rs b/src/test/parse-fail/removed-syntax-field-let.rs index 4e542fd7477f..6deb3bb2e951 100644 --- a/src/test/parse-fail/removed-syntax-field-let.rs +++ b/src/test/parse-fail/removed-syntax-field-let.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error struct s { let foo: (), diff --git a/src/test/parse-fail/syntax-trait-polarity.rs b/src/test/parse-fail/syntax-trait-polarity.rs index c0d850343839..1971ffeaf264 100644 --- a/src/test/parse-fail/syntax-trait-polarity.rs +++ b/src/test/parse-fail/syntax-trait-polarity.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error #![feature(optin_builtin_traits)] diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/parse-fail/trailing-plus-in-bounds.rs index 4abdbad9a030..44bb1f930c7b 100644 --- a/src/test/parse-fail/trailing-plus-in-bounds.rs +++ b/src/test/parse-fail/trailing-plus-in-bounds.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error use std::fmt::Debug; diff --git a/src/test/parse-fail/trait-bounds-not-on-impl.rs b/src/test/parse-fail/trait-bounds-not-on-impl.rs index 3bd8908d18bd..b7dcc8a8b3bc 100644 --- a/src/test/parse-fail/trait-bounds-not-on-impl.rs +++ b/src/test/parse-fail/trait-bounds-not-on-impl.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error trait Foo { } diff --git a/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs b/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs index c1e1cc1c7f7f..9e16e29ba50b 100644 --- a/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs +++ b/src/test/parse-fail/use-as-where-use-ends-with-mod-sep.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error use std::any:: as foo; //~ ERROR expected identifier, found keyword `as` //~^ ERROR: expected one of `::`, `;`, or `as`, found `foo` 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 3ac71176342b..45165b76c4af 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 @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// compile-flags: -Z parse-only -Z continue-parse-after-error fn equal1(_: &T, _: &T) -> bool where { //~^ ERROR a `where` clause must have at least one predicate in it diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 40ff4852e385..24b0f90d08e4 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -18,18 +18,18 @@ extern crate std as std; // #4264 fixed-length vector types -pub fn foo(_: [i32; (3 as usize)]) { } +pub fn foo(_: [i32; (3 as usize)]) ({ } as ()) -pub fn bar() { - const FOO: usize = ((5 as usize) - (4 as usize) as usize); - let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); +pub fn bar() ({ + const FOO: usize = ((5 as usize) - (4 as usize) as usize); + let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); - let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); + let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); - let _ = - (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as &[i32; 3]) - as *const _ as *const [i32; 3]) as *const [i32; (3 as usize)] as - *const [i32; 3]); + let _ = + (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) + as &[i32; 3]) as *const _ as *const [i32; 3]) as + *const [i32; (3 as usize)] as *const [i32; 3]); @@ -38,58 +38,66 @@ pub fn bar() { - (($crate::fmt::format as - fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1 - as - fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({ - static __STATIC_FMTSTR: - &'static [&'static str] - = - (&([("test" - as - &'static str)] - as - [&'static str; 1]) - as - &'static [&'static str; 1]); - (__STATIC_FMTSTR - as - &'static [&'static str]) - } - as - &[&str]), - (&(match (() - as - ()) - { - () - => - ([] - as - [std::fmt::ArgumentV1<'_>; 0]), - } - as - [std::fmt::ArgumentV1<'_>; 0]) - as - &[std::fmt::ArgumentV1<'_>; 0])) - as - std::fmt::Arguments<'_>)) - as std::string::String); -} + + (($crate::fmt::format as + fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1 + as + fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({ + static __STATIC_FMTSTR: + &'static [&'static str] + = + (&([("test" + as + &'static str)] + as + [&'static str; 1]) + as + &'static [&'static str; 1]); + (__STATIC_FMTSTR + as + &'static [&'static str]) + } + as + &[&str]), + (&(match (() + as + ()) + { + () + => + ([] + as + [std::fmt::ArgumentV1<'_>; 0]), + } + as + [std::fmt::ArgumentV1<'_>; 0]) + as + &[std::fmt::ArgumentV1<'_>; 0])) + as + std::fmt::Arguments<'_>)) + as std::string::String); + } as ()) pub type Foo = [i32; (3 as usize)]; pub struct Bar { pub x: [i32; (3 as usize)], } pub struct TupleBar([i32; (4 as usize)]); pub enum Baz { BazVariant([i32; (5 as usize)]), } -pub fn id(x: T) -> T { (x as T) } -pub fn use_id() { - let _ = - ((id::<[i32; (3 as usize)]> as - fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32), - (2 as i32), - (3 as i32)] as - [i32; 3])) as - [i32; 3]); -} -fn main() { } +pub fn id(x: T) -> T ({ (x as T) } as T) +pub fn use_id() ({ + let _ = + ((id::<[i32; (3 as usize)]> as + fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 + as + i32), + (2 + as + i32), + (3 + as + i32)] + as + [i32; 3])) + as [i32; 3]); + } as ()) +fn main() ({ } as ()) diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index e52932cd7bef..1c443020d2e9 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -198,14 +198,20 @@ fn _11() { }; let _ = #[attr] || #[attr] (); let _ = #[attr] move || #[attr] (); - let _ = #[attr] || { - #![attr] - #[attr] - () }; - let _ = #[attr] move || { - #![attr] - #[attr] - () }; + let _ = + #[attr] || + { + #![attr] + #[attr] + () + }; + let _ = + #[attr] move || + { + #![attr] + #[attr] + () + }; let _ = #[attr] { #![attr] diff --git a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot index f699771ef24c..8ea8370ab235 100644 --- a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot @@ -2,6 +2,8 @@ digraph block { N0[label="entry"]; N1[label="exit"]; N2[label="block { }"]; + N3[label="expr { }"]; N0 -> N2; - N2 -> N1; + N2 -> N3; + N3 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot index d924890b3118..5982fbea7690 100644 --- a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot @@ -4,8 +4,10 @@ digraph block { N2[label="expr 1"]; N3[label="stmt 1;"]; N4[label="block { 1; }"]; + N5[label="expr { 1; }"]; N0 -> N2; N2 -> N3; N3 -> N4; - N4 -> N1; + N4 -> N5; + N5 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot index 1f4a58ba0a3c..1639785bd68c 100644 --- a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot @@ -4,8 +4,10 @@ digraph block { N2[label="local _x"]; N3[label="stmt let _x: isize;"]; N4[label="block { let _x: isize; }"]; + N5[label="expr { let _x: isize; }"]; N0 -> N2; N2 -> N3; N3 -> N4; - N4 -> N1; + N4 -> N5; + N5 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot index 8b6500761850..b0ae00d81675 100644 --- a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot @@ -6,10 +6,12 @@ digraph block { N4[label="expr 3 + 4"]; N5[label="stmt 3 + 4;"]; N6[label="block { 3 + 4; }"]; + N7[label="expr { 3 + 4; }"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; - N6 -> N1; + N6 -> N7; + N7 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot index fde6cc290055..41ace15a4c68 100644 --- a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot @@ -5,9 +5,11 @@ digraph block { N3[label="local _x"]; N4[label="stmt let _x = 4;"]; N5[label="block { let _x = 4; }"]; + N6[label="expr { let _x = 4; }"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; - N5 -> N1; + N5 -> N6; + N6 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot index efd56cd0c75e..72b8ae71751c 100644 --- a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot @@ -9,6 +9,7 @@ digraph block { N7[label="pat (_x, _y)"]; N8[label="stmt let (_x, _y) = (5, 55);"]; N9[label="block { let (_x, _y) = (5, 55); }"]; + N10[label="expr { let (_x, _y) = (5, 55); }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -17,5 +18,6 @@ digraph block { N6 -> N7; N7 -> N8; N8 -> N9; - N9 -> N1; + N9 -> N10; + N10 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot index 54e9d89d3fb5..acba71ef625f 100644 --- a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot @@ -7,11 +7,13 @@ digraph block { N5[label="pat S6 { val: _x }"]; N6[label="stmt let S6 { val: _x } = S6{val: 6,};"]; N7[label="block { let S6 { val: _x } = S6{val: 6,}; }"]; + N8[label="expr { let S6 { val: _x } = S6{val: 6,}; }"]; N0 -> N2; N2 -> N3; N3 -> N4; N4 -> N5; N5 -> N6; N6 -> N7; - N7 -> N1; + N7 -> N8; + N8 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot index c60cd1cfd277..251e2b39f14c 100644 --- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot @@ -17,6 +17,7 @@ digraph block { N15[label="expr x + y"]; N16[label="stmt match [7, 77, 777, 7777] { [x, y, ..] => x + y, };"]; N17[label="block { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"]; + N18[label="expr { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -33,5 +34,6 @@ digraph block { N15 -> N7; N7 -> N16; N16 -> N17; - N17 -> N1; + N17 -> N18; + N18 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot index da0120b7bdc5..e2779c9414a9 100644 --- a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot @@ -16,6 +16,7 @@ digraph block { N14[label="block { _y = 888; }"]; N15[label="expr if x > 88 { _y = 888; }"]; N16[label="block { let x = 8; let _y; if x > 88 { _y = 888; } }"]; + N17[label="expr { let x = 8; let _y; if x > 88 { _y = 888; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -32,5 +33,6 @@ digraph block { N9 -> N15; N14 -> N15; N15 -> N16; - N16 -> N1; + N16 -> N17; + N17 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot index c98d1b0bed5d..536abde91e81 100644 --- a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot @@ -24,6 +24,7 @@ digraph block { N22[label="expr { _y = 94 + 95; }"]; N23[label="expr if x > 92 { _y = 93; } else { _y = 94 + 95; }"]; N24[label="block { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; + N25[label="expr { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -48,5 +49,6 @@ digraph block { N14 -> N23; N22 -> N23; N23 -> N24; - N24 -> N1; + N24 -> N25; + N25 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot index 516c39ef560a..a3b531b1e2f4 100644 --- a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot @@ -15,6 +15,7 @@ digraph block { N13[label="stmt x -= 1;"]; N14[label="block { x -= 1; }"]; N15[label="block { let mut x = 10; while x > 0 { x -= 1; } }"]; + N16[label="expr { let mut x = 10; while x > 0 { x -= 1; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -30,5 +31,6 @@ digraph block { N13 -> N14; N14 -> N5; N9 -> N15; - N15 -> N1; + N15 -> N16; + N16 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot index 9b66fd581cb4..70034d299ba9 100644 --- a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot @@ -15,6 +15,7 @@ digraph block { N13[label="expr \"unreachable\""]; N14[label="stmt \"unreachable\";"]; N15[label="block { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; + N16[label="expr { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -29,5 +30,6 @@ digraph block { N12 -> N13; N13 -> N14; N14 -> N15; - N15 -> N1; + N15 -> N16; + N16 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot index 071af6faf6f9..245afc43504c 100644 --- a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot @@ -22,6 +22,7 @@ digraph block { N20[label="expr if x == 2 { break ; \"unreachable\"; }"]; N21[label="block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; N22[label="block { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; + N23[label="expr { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -44,5 +45,6 @@ digraph block { N20 -> N21; N21 -> N5; N6 -> N22; - N22 -> N1; + N22 -> N23; + N23 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot index fb7d2ad97bd5..0f268bd0f2ae 100644 --- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot @@ -24,6 +24,7 @@ digraph block { N22[label="expr _y"]; N23[label="expr _y = v + 1"]; N24[label="block {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"]; + N25[label="expr {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -48,5 +49,6 @@ digraph block { N22 -> N23; N23 -> N10; N10 -> N24; - N24 -> N1; + N24 -> N25; + N25 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot index 66250aa441e4..719a6cf2619d 100644 --- a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot @@ -15,6 +15,7 @@ digraph block { N13[label="block { return; \"unreachable\"; }"]; N14[label="expr if x > 1 { return; \"unreachable\"; }"]; N15[label="block { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; + N16[label="expr { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -30,5 +31,6 @@ digraph block { N7 -> N14; N13 -> N14; N14 -> N15; - N15 -> N1; + N15 -> N16; + N16 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot index 4c94630f4e1f..d8cbd8411e20 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot @@ -49,6 +49,7 @@ digraph block { N47[label="stmt x -= 5;"]; N48[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"]; N49[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; + N50[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -99,5 +100,6 @@ digraph block { N47 -> N48; N48 -> N8; N9 -> N49; - N49 -> N1; + N49 -> N50; + N50 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot index d7d027cefb59..b11881247fb6 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot @@ -52,6 +52,7 @@ digraph block { N50[label="expr \"unreachable\""]; N51[label="stmt \"unreachable\";"]; N52[label="block {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; + N53[label="expr {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -105,5 +106,6 @@ digraph block { N49 -> N50; N50 -> N51; N51 -> N52; - N52 -> N1; + N52 -> N53; + N53 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot index f87b70a71cae..705eece77558 100644 --- a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot @@ -8,6 +8,7 @@ digraph block { N6[label="local _v"]; N7[label="stmt let _v = [1, 7, 17];"]; N8[label="block { let _v = [1, 7, 17]; }"]; + N9[label="expr { let _v = [1, 7, 17]; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -15,5 +16,6 @@ digraph block { N5 -> N6; N6 -> N7; N7 -> N8; - N8 -> N1; + N8 -> N9; + N9 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot index 8ea425613329..c1d6e3023fbc 100644 --- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot @@ -9,6 +9,7 @@ digraph block { N7[label="expr inner(inner(18))"]; N8[label="stmt inner(inner(18));"]; N9[label="block { inner(inner(18)); }"]; + N10[label="expr { inner(inner(18)); }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -17,5 +18,6 @@ digraph block { N6 -> N7; N7 -> N8; N8 -> N9; - N9 -> N1; + N9 -> N10; + N10 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot index bc0ca08d4225..d2f9f41f647b 100644 --- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot @@ -12,6 +12,7 @@ digraph block { N10[label="expr s.inner().inner()"]; N11[label="stmt s.inner().inner();"]; N12[label="block { let s = S19{x: 19,}; s.inner().inner(); }"]; + N13[label="expr { let s = S19{x: 19,}; s.inner().inner(); }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -23,5 +24,6 @@ digraph block { N9 -> N10; N10 -> N11; N11 -> N12; - N12 -> N1; + N12 -> N13; + N13 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot index 21e84fb858bc..120eab4dac90 100644 --- a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot @@ -12,6 +12,7 @@ digraph block { N10[label="expr v[20]"]; N11[label="stmt v[20];"]; N12[label="block { let v = [2, 0, 20]; v[20]; }"]; + N13[label="expr { let v = [2, 0, 20]; v[20]; }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -23,5 +24,6 @@ digraph block { N9 -> N10; N10 -> N11; N11 -> N12; - N12 -> N1; + N12 -> N13; + N13 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot index 796bf4910c9e..370dcdd8554d 100644 --- a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot @@ -47,6 +47,7 @@ digraph block { N45[label="stmt \"unreachable\";"]; N46[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l}\l"]; N47[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; + N48[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -95,5 +96,6 @@ digraph block { N45 -> N46; N46 -> N8; N9 -> N47; - N47 -> N1; + N47 -> N48; + N48 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot index 9e8049f07415..9d3bc22831a1 100644 --- a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot @@ -50,6 +50,7 @@ digraph block { N48[label="expr \"unreachable\""]; N49[label="stmt \"unreachable\";"]; N50[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; + N51[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -101,5 +102,6 @@ digraph block { N47 -> N48; N48 -> N49; N49 -> N50; - N50 -> N1; + N50 -> N51; + N51 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot index b3f285049c57..f152977438c5 100644 --- a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot @@ -52,6 +52,7 @@ digraph block { N50[label="block { y -= 1; while z > 0 { z -= 1; } if x > 10 { return; \"unreachable\"; } }"]; N51[label="block {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; N52[label="block {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; + N53[label="expr {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -107,5 +108,6 @@ digraph block { N24 -> N51; N51 -> N11; N15 -> N52; - N52 -> N1; + N52 -> N53; + N53 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot index 43b3295bf3be..e40dd014f0a4 100644 --- a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot @@ -76,6 +76,7 @@ digraph block { N74[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"]; N75[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"]; N76[label="block {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; + N77[label="expr {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -155,5 +156,6 @@ digraph block { N29 -> N75; N75 -> N11; N12 -> N76; - N76 -> N1; + N76 -> N77; + N77 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot index 50fdffb781d1..1e2df1ab5e7b 100644 --- a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot @@ -76,6 +76,7 @@ digraph block { N74[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"]; N75[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l}\l"]; N76[label="block {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; + N77[label="expr {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -155,5 +156,6 @@ digraph block { N29 -> N75; N75 -> N11; N12 -> N76; - N76 -> N1; + N76 -> N77; + N77 -> N1; } diff --git a/src/test/run-make/missing-items/Makefile b/src/test/run-make/missing-items/Makefile new file mode 100644 index 000000000000..bcc9cdf2d652 --- /dev/null +++ b/src/test/run-make/missing-items/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +all: + $(RUSTC) m1.rs -C prefer-dynamic + $(RUSTC) m2.rs 2>&1 | grep "error\[E0046\]: not all trait items implemented, missing: .*" + $(RUSTC) m2.rs 2>&1 | grep " --> m2.rs:18:1" + $(RUSTC) m2.rs 2>&1 | grep " | ^ missing .CONSTANT., .Type., .method. in implementation" + $(RUSTC) m2.rs 2>&1 | grep " = note: .CONSTANT. from trait: .const CONSTANT: u32;." + $(RUSTC) m2.rs 2>&1 | grep " = note: .Type. from trait: .type Type;." + $(RUSTC) m2.rs 2>&1 | grep " = note: .method. from trait: .fn(&Self, std::string::String) -> ::Type." diff --git a/src/test/run-make/missing-items/m1.rs b/src/test/run-make/missing-items/m1.rs new file mode 100644 index 000000000000..060c7a9571b7 --- /dev/null +++ b/src/test/run-make/missing-items/m1.rs @@ -0,0 +1,17 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_consts)] +#![crate_type = "dylib"] +pub trait X { + const CONSTANT: u32; + type Type; + fn method(&self, s: String) -> Self::Type; +} diff --git a/src/test/run-make/missing-items/m2.rs b/src/test/run-make/missing-items/m2.rs new file mode 100644 index 000000000000..7055673acc9a --- /dev/null +++ b/src/test/run-make/missing-items/m2.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_consts)] +#![crate_type = "dylib"] +extern crate m1; + +struct X { +} + +impl m1::X for X { +} diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 3f36ebe64923..e9ed897bf302 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -10,7 +10,6 @@ #![ crate_name = "test" ] #![feature(box_syntax)] -#![feature(dotdot_in_tuple_patterns)] #![feature(rustc_private)] extern crate graphviz; diff --git a/src/test/run-make/windows-subsystem/Makefile b/src/test/run-make/windows-subsystem/Makefile new file mode 100644 index 000000000000..34fb5db32f95 --- /dev/null +++ b/src/test/run-make/windows-subsystem/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: + $(RUSTC) windows.rs + $(RUSTC) console.rs diff --git a/src/test/run-make/windows-subsystem/console.rs b/src/test/run-make/windows-subsystem/console.rs new file mode 100644 index 000000000000..3aedb0ecab72 --- /dev/null +++ b/src/test/run-make/windows-subsystem/console.rs @@ -0,0 +1,15 @@ +// 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(windows_subsystem)] +#![windows_subsystem = "console"] + +fn main() {} + diff --git a/src/test/run-make/windows-subsystem/windows.rs b/src/test/run-make/windows-subsystem/windows.rs new file mode 100644 index 000000000000..5d875a5a1bf1 --- /dev/null +++ b/src/test/run-make/windows-subsystem/windows.rs @@ -0,0 +1,14 @@ +// 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(windows_subsystem)] +#![windows_subsystem = "windows"] + +fn main() {} diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs index 5df95ba5facb..6b58fee15758 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs @@ -12,7 +12,6 @@ #![feature(plugin_registrar)] #![feature(box_syntax)] -#![feature(dotdot_in_tuple_patterns)] #![feature(rustc_private)] extern crate syntax; 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 15ec0ccae8fd..7257444ee870 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -10,7 +10,6 @@ // force-host -#![feature(dotdot_in_tuple_patterns)] #![feature(plugin_registrar, quote, rustc_private)] extern crate syntax; diff --git a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs index 5229d42f1fdd..6ac0d5ad1a3b 100644 --- a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs +++ b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs @@ -18,10 +18,10 @@ extern crate syntax_pos; extern crate rustc; extern crate rustc_plugin; -use syntax::parse::token::{self, str_to_ident, NtExpr, NtPat}; +use syntax::parse::token::{str_to_ident, NtExpr, NtPat}; use syntax::ast::{Pat}; use syntax::tokenstream::{TokenTree}; -use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; +use syntax::ext::base::{ExtCtxt, MacResult, MacEager}; use syntax::ext::build::AstBuilder; use syntax::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use syntax::ext::tt::macro_parser::{Success, Failure, Error}; @@ -30,35 +30,12 @@ use syntax::ptr::P; use syntax_pos::Span; use rustc_plugin::Registry; -fn expand_mbe_matches(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) +fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree]) -> Box { let mbe_matcher = quote_matcher!(cx, $matched:expr, $($pat:pat)|+); - - let mac_expr = match TokenTree::parse(cx, &mbe_matcher[..], args) { - Success(map) => { - match (&*map[&str_to_ident("matched")], &*map[&str_to_ident("pat")]) { - (&MatchedNonterminal(NtExpr(ref matched_expr)), - &MatchedSeq(ref pats, seq_sp)) => { - let pats: Vec> = pats.iter().map(|pat_nt| - if let &MatchedNonterminal(NtPat(ref pat)) = &**pat_nt { - pat.clone() - } else { - unreachable!() - } - ).collect(); - let arm = cx.arm(seq_sp, pats, cx.expr_bool(seq_sp, true)); - - quote_expr!(cx, - match $matched_expr { - $arm - _ => false - } - ) - } - _ => unreachable!() - } - } + let map = match TokenTree::parse(cx, &mbe_matcher, args) { + Success(map) => map, Failure(_, tok) => { panic!("expected Success, but got Failure: {}", parse_failure_msg(tok)); } @@ -67,6 +44,34 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) } }; + let matched_nt = match *map[&str_to_ident("matched")] { + MatchedNonterminal(ref nt) => nt.clone(), + _ => unreachable!(), + }; + + let mac_expr = match (&*matched_nt, &*map[&str_to_ident("pat")]) { + (&NtExpr(ref matched_expr), &MatchedSeq(ref pats, seq_sp)) => { + let pats: Vec> = pats.iter().map(|pat_nt| { + match **pat_nt { + MatchedNonterminal(ref nt) => match **nt { + NtPat(ref pat) => pat.clone(), + _ => unreachable!(), + }, + _ => unreachable!(), + } + }).collect(); + let arm = cx.arm(seq_sp, pats, cx.expr_bool(seq_sp, true)); + + quote_expr!(cx, + match $matched_expr { + $arm + _ => false + } + ) + } + _ => unreachable!() + }; + MacEager::expr(mac_expr) } diff --git a/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs index 66ffff94333e..79ce3cb68d4b 100644 --- a/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs +++ b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs @@ -10,7 +10,6 @@ // `#[derive(Trait)]` works for empty structs/variants with braces or parens. -#![feature(relaxed_adts)] #![feature(rustc_private)] extern crate serialize as rustc_serialize; diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/add-impl.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/add-impl.rs index 99586b0bb493..1d34049db249 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/add-impl.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/add-impl.rs @@ -21,13 +21,12 @@ use proc_macro::TokenStream; #[proc_macro_derive(AddImpl)] // #[cfg(proc_macro)] pub fn derive(input: TokenStream) -> TokenStream { - (input.to_string() + " - impl B { + "impl B { fn foo(&self) {} } fn foo() {} mod bar { pub fn foo() {} } - ").parse().unwrap() + ".parse().unwrap() } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/append-impl.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/append-impl.rs index 27c3d643ca4f..7260bc4a5e7b 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/append-impl.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/append-impl.rs @@ -21,11 +21,8 @@ use proc_macro::TokenStream; #[proc_macro_derive(Append)] pub fn derive_a(input: TokenStream) -> TokenStream { - let mut input = input.to_string(); - input.push_str(" - impl Append for A { - fn foo(&self) {} - } - "); - input.parse().unwrap() + "impl Append for A { + fn foo(&self) {} + } + ".parse().unwrap() } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-a.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-a.rs index c2de173568b4..eaada5542274 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-a.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-a.rs @@ -23,5 +23,5 @@ pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); assert!(input.contains("struct A;")); assert!(input.contains("#[derive(Debug, PartialEq, Eq, Copy, Clone)]")); - "#[derive(Debug, PartialEq, Eq, Copy, Clone)] struct A;".parse().unwrap() + "".parse().unwrap() } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs new file mode 100644 index 000000000000..a02b798c8023 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-b.rs @@ -0,0 +1,29 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(B, attributes(B, C))] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert!(input.contains("#[B]")); + assert!(input.contains("struct B {")); + assert!(input.contains("#[C]")); + assert!(input.contains("#[derive(Debug, PartialEq, Eq, Copy, Clone)]")); + "".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs similarity index 80% rename from src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs rename to src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs index f6f1be37fc3c..05a6cbec69c5 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/cannot-link.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-reexport.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:derive-a.rs +// ignore-test +#![feature(macro_reexport, proc_macro)] + +#[macro_reexport(A)] extern crate derive_a; -//~^ ERROR: crates of the `proc-macro` crate type cannot be linked at runtime - -fn main() {} diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-same-struct.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-same-struct.rs index bd283ca57ebd..bc8a0d575913 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-same-struct.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-same-struct.rs @@ -21,7 +21,7 @@ use proc_macro::TokenStream; #[proc_macro_derive(AToB)] pub fn derive1(input: TokenStream) -> TokenStream { println!("input1: {:?}", input.to_string()); - assert_eq!(input.to_string(), "#[derive(BToC)]\nstruct A;\n"); + assert_eq!(input.to_string(), "struct A;\n"); "#[derive(BToC)] struct B;".parse().unwrap() } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/double.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/double.rs new file mode 100644 index 000000000000..969ed91f595e --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/double.rs @@ -0,0 +1,24 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro)] +#![feature(proc_macro_lib)] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(Double)] +pub fn derive(input: TokenStream) -> TokenStream { + format!("mod foo {{ {} }}", input.to_string()).parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/expand-with-a-macro.rs index 155b125690cc..50eaf035962f 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/expand-with-a-macro.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/expand-with-a-macro.rs @@ -24,8 +24,6 @@ pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); assert!(input.contains("struct A;")); r#" - struct A; - impl A { fn a(&self) { panic!("hello"); diff --git a/src/test/run-pass-fulldeps/proc-macro/crate-var.rs b/src/test/run-pass-fulldeps/proc-macro/crate-var.rs new file mode 100644 index 000000000000..d19b49ab18c0 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/crate-var.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:double.rs + +#![feature(proc_macro)] +#![allow(unused)] + +#[macro_use] +extern crate double; + +struct Foo; + +macro_rules! m { () => { + #[derive(Double)] + struct Bar($crate::Foo); +} } +m!(); + +fn main() {} diff --git a/src/test/run-pass-fulldeps/proc-macro/derive-b.rs b/src/test/run-pass-fulldeps/proc-macro/derive-b.rs new file mode 100644 index 000000000000..f5bb93f01249 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/derive-b.rs @@ -0,0 +1,32 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-b.rs +// ignore-stage1 + +#![feature(proc_macro)] + +#[macro_use] +extern crate derive_b; + +#[derive(Debug, PartialEq, B, Eq, Copy, Clone)] +#[B] +struct B { + #[C] + a: u64 +} + +fn main() { + B { a: 3 }; + assert_eq!(B { a: 3 }, B { a: 3 }); + let b = B { a: 3 }; + let _d = b; + let _e = b; +} diff --git a/src/test/run-pass-fulldeps/proc-macro/derive-same-struct.rs b/src/test/run-pass-fulldeps/proc-macro/derive-same-struct.rs index b3edc8f1c310..608f86bca576 100644 --- a/src/test/run-pass-fulldeps/proc-macro/derive-same-struct.rs +++ b/src/test/run-pass-fulldeps/proc-macro/derive-same-struct.rs @@ -15,7 +15,7 @@ #[macro_use] extern crate derive_same_struct; -#[derive(AToB, BToC)] +#[derive(AToB)] struct A; fn main() { diff --git a/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs b/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs new file mode 100644 index 000000000000..7f09d8faebbb --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/use-reexport.rs @@ -0,0 +1,22 @@ +// 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:derive-a.rs +// aux-build:derive-reexport.rs + +#![feature(proc_macro)] + +#[macro_use] +extern crate derive_reexport; + +#[derive(Debug, PartialEq, A, Eq, Copy, Clone)] +struct A; + +fn main() {} diff --git a/src/test/run-pass/auxiliary/empty-struct.rs b/src/test/run-pass/auxiliary/empty-struct.rs index b599d7bee73d..734e57a774d8 100644 --- a/src/test/run-pass/auxiliary/empty-struct.rs +++ b/src/test/run-pass/auxiliary/empty-struct.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(relaxed_adts)] - pub struct XEmpty1 {} pub struct XEmpty2; pub struct XEmpty7(); diff --git a/src/test/run-pass/auxiliary/issue-36954.rs b/src/test/run-pass/auxiliary/issue-36954.rs new file mode 100644 index 000000000000..832ee1d7c1b4 --- /dev/null +++ b/src/test/run-pass/auxiliary/issue-36954.rs @@ -0,0 +1,18 @@ +// 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(const_fn)] +#![crate_type = "lib"] + +const fn foo(i: i32) -> i32 { + i +} + +pub const FOO: i32 = foo(1); diff --git a/src/test/run-pass/empty-struct-braces.rs b/src/test/run-pass/empty-struct-braces.rs index 48966f24a2e5..7c161ba8dd96 100644 --- a/src/test/run-pass/empty-struct-braces.rs +++ b/src/test/run-pass/empty-struct-braces.rs @@ -13,8 +13,6 @@ // aux-build:empty-struct.rs -#![feature(relaxed_adts)] - extern crate empty_struct; use empty_struct::*; diff --git a/src/test/run-pass/issue-18060.rs b/src/test/run-pass/issue-18060.rs new file mode 100644 index 000000000000..d6c9a92ca029 --- /dev/null +++ b/src/test/run-pass/issue-18060.rs @@ -0,0 +1,17 @@ +// 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. + +// Regression test for #18060: match arms were matching in the wrong order. + +fn main() { + assert_eq!(2, match (1, 3) { (0, 2...5) => 1, (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4 }); + assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2...5) => 3, (_, _) => 4 }); + assert_eq!(2, match (1, 7) { (0, 2...5) => 1, (1, 7) => 2, (_, 2...5) => 3, (_, _) => 4 }); +} diff --git a/src/test/run-pass/issue-18937-1.rs b/src/test/run-pass/issue-18937-1.rs new file mode 100644 index 000000000000..7a24d087b44e --- /dev/null +++ b/src/test/run-pass/issue-18937-1.rs @@ -0,0 +1,30 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to type-check this example. In particular, +// knowing that `T: 'a` allows us to deduce that `[U]: 'a` (because +// when `T=[U]` it implies that `U: 'a`). +// +// Regr. test for live code we found in the wild when fixing #18937. + +pub trait Leak { + fn leak<'a>(self) -> &'a T where T: 'a; +} + +impl Leak<[U]> for Vec { + fn leak<'a>(mut self) -> &'a [U] where [U]: 'a { + let r: *mut [U] = &mut self[..]; + std::mem::forget(self); + unsafe { &mut *r } + } +} +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/run-pass/issue-36954.rs b/src/test/run-pass/issue-36954.rs new file mode 100644 index 000000000000..f8330ba99b7a --- /dev/null +++ b/src/test/run-pass/issue-36954.rs @@ -0,0 +1,17 @@ +// 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:issue-36954.rs + +extern crate issue_36954 as lib; + +fn main() { + let _ = lib::FOO; +} diff --git a/src/test/run-pass/issue-37598.rs b/src/test/run-pass/issue-37598.rs new file mode 100644 index 000000000000..d32d2fc29544 --- /dev/null +++ b/src/test/run-pass/issue-37598.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(advanced_slice_patterns, slice_patterns)] + +fn check(list: &[u8]) { + match list { + &[] => {}, + &[_u1, _u2, ref _next..] => {}, + &[_u1] => {}, + } +} + +fn main() {} diff --git a/src/test/compile-fail/feature-gate-relaxed-adts.rs b/src/test/run-pass/issue-37686.rs similarity index 56% rename from src/test/compile-fail/feature-gate-relaxed-adts.rs rename to src/test/run-pass/issue-37686.rs index dc5e347aadf3..47881d4d530f 100644 --- a/src/test/compile-fail/feature-gate-relaxed-adts.rs +++ b/src/test/run-pass/issue-37686.rs @@ -8,19 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct S(); //~ ERROR empty tuple structs and enum variants are unstable -struct Z(u8, u8); - -enum E { - V(), //~ ERROR empty tuple structs and enum variants are unstable - U(u8, u8), -} - fn main() { - match S() { - S() => {} //~ ERROR empty tuple structs patterns are unstable - } - match E::V() { - E::V() => {} //~ ERROR empty tuple structs patterns are unstable + match (0, 0) { + (std::usize::MIN, std::usize::MAX) => {} + _ => {} } } diff --git a/src/test/run-pass/iter-step-overflow-debug.rs b/src/test/run-pass/iter-step-overflow-debug.rs new file mode 100644 index 000000000000..5b9b58f02889 --- /dev/null +++ b/src/test/run-pass/iter-step-overflow-debug.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C debug_assertions=yes + +use std::panic; + +fn main() { + let r = panic::catch_unwind(|| { + let mut it = u8::max_value()..; + it.next().unwrap(); // 255 + it.next().unwrap(); + }); + assert!(r.is_err()); + + let r = panic::catch_unwind(|| { + let mut it = i8::max_value()..; + it.next().unwrap(); // 127 + it.next().unwrap(); + }); + assert!(r.is_err()); +} diff --git a/src/test/run-pass/iter-step-overflow-ndebug.rs b/src/test/run-pass/iter-step-overflow-ndebug.rs new file mode 100644 index 000000000000..8642f1643c11 --- /dev/null +++ b/src/test/run-pass/iter-step-overflow-ndebug.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C debug_assertions=no + +fn main() { + let mut it = u8::max_value()..; + assert_eq!(it.next().unwrap(), 255); + assert_eq!(it.next().unwrap(), u8::min_value()); + + let mut it = i8::max_value()..; + assert_eq!(it.next().unwrap(), 127); + assert_eq!(it.next().unwrap(), i8::min_value()); +} diff --git a/src/test/run-pass/pat-tuple-1.rs b/src/test/run-pass/pat-tuple-1.rs index c3796210a8e5..45a9a2b303c9 100644 --- a/src/test/run-pass/pat-tuple-1.rs +++ b/src/test/run-pass/pat-tuple-1.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { let x = (1, 2, 3); match x { diff --git a/src/test/run-pass/pat-tuple-2.rs b/src/test/run-pass/pat-tuple-2.rs index 881e96a9d788..ee60d1c01cf8 100644 --- a/src/test/run-pass/pat-tuple-2.rs +++ b/src/test/run-pass/pat-tuple-2.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { let x = (1,); match x { diff --git a/src/test/run-pass/pat-tuple-3.rs b/src/test/run-pass/pat-tuple-3.rs index 94d33d41899a..7a46c1deb59b 100644 --- a/src/test/run-pass/pat-tuple-3.rs +++ b/src/test/run-pass/pat-tuple-3.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { let x = (1, 2, 3); let branch = match x { diff --git a/src/test/run-pass/pat-tuple-4.rs b/src/test/run-pass/pat-tuple-4.rs index ffd82fea9962..1d75e1e9d14d 100644 --- a/src/test/run-pass/pat-tuple-4.rs +++ b/src/test/run-pass/pat-tuple-4.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { let x = (1, 2, 3); match x { diff --git a/src/test/run-pass/pat-tuple-5.rs b/src/test/run-pass/pat-tuple-5.rs index 41c4d02abcbd..1192932f13da 100644 --- a/src/test/run-pass/pat-tuple-5.rs +++ b/src/test/run-pass/pat-tuple-5.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { struct S; struct Z; diff --git a/src/test/run-pass/pat-tuple-6.rs b/src/test/run-pass/pat-tuple-6.rs index 6f3f2b3aed55..9d3cd65b455c 100644 --- a/src/test/run-pass/pat-tuple-6.rs +++ b/src/test/run-pass/pat-tuple-6.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dotdot_in_tuple_patterns)] - fn tuple() { let x = (1, 2, 3, 4, 5); match x { diff --git a/src/test/run-pass/struct-path-associated-type.rs b/src/test/run-pass/struct-path-associated-type.rs index b033ed5c8021..292761dfd005 100644 --- a/src/test/run-pass/struct-path-associated-type.rs +++ b/src/test/run-pass/struct-path-associated-type.rs @@ -8,6 +8,8 @@ // 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 c7a282c2a2fa..b569ab62c1bf 100644 --- a/src/test/run-pass/struct-path-self.rs +++ b/src/test/run-pass/struct-path-self.rs @@ -8,6 +8,8 @@ // 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/traits-elaborate-type-region.rs b/src/test/run-pass/traits-elaborate-type-region.rs new file mode 100644 index 000000000000..4621c2ca4be2 --- /dev/null +++ b/src/test/run-pass/traits-elaborate-type-region.rs @@ -0,0 +1,58 @@ +// 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. + +#![allow(dead_code)] + +// Test that we elaborate `Type: 'region` constraints and infer various important things. + +trait Master<'a, T: ?Sized> { + fn foo() where T: 'a; +} + +// [U]: 'a => U: 'a +impl<'a, U> Master<'a, [U]> for () { + fn foo() where U: 'a { } +} + +// &'b U: 'a => 'b: 'a, U: 'a +impl<'a, 'b, U> Master<'a, &'b U> for () { + fn foo() where 'b: 'a, U: 'a { } +} + +// &'b [U]: 'a => 'b: 'a, U: 'a +impl<'a, 'b, U> Master<'a, &'b [U]> for () { + fn foo() where 'b: 'a, U: 'a { } +} + +// Foo<'b>: 'a => 'b: 'a +struct Foo<'a> { x: &'a () } +impl<'a, 'b> Master<'a, Foo<'b>> for () { + fn foo() where 'b: 'a { } +} + +// Bar<'b, T>: 'a => 'b: 'a, T: 'a +struct Bar<'a, T: 'a> { x: &'a T } +impl<'a, 'b, T> Master<'a, Bar<'b, T>> for () { + fn foo() where 'b: 'a, T: 'a { } +} + +// fn(T): 'a => T: 'a +impl<'a, T> Master<'a, fn(T)> for () { + fn foo() where T: 'a { } +} + +// fn() -> T: 'a => T: 'a +impl<'a, T> Master<'a, fn() -> T> for () { + fn foo() where T: 'a { } +} + +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index d58e7148f610..d05e6eb2bbe4 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -2,7 +2,7 @@ error[E0404]: `Bar` is not a trait --> $DIR/two_files.rs:15:6 | 15 | impl Bar for Baz { } - | ^^^ not a trait + | ^^^ expected trait, found type alias | = note: type aliases cannot be used for traits diff --git a/src/test/compile-fail/feature-gate-relaxed-adts-2.rs b/src/test/ui/compare-method/proj-outlives-region.rs similarity index 55% rename from src/test/compile-fail/feature-gate-relaxed-adts-2.rs rename to src/test/ui/compare-method/proj-outlives-region.rs index a75f2647f49a..54cfe4be9c10 100644 --- a/src/test/compile-fail/feature-gate-relaxed-adts-2.rs +++ b/src/test/ui/compare-method/proj-outlives-region.rs @@ -8,20 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Z(u8, u8); +#![allow(dead_code)] +#![deny(extra_requirement_in_impl)] -enum E { - U(u8, u8), +// Test that we elaborate `Type: 'region` constraints and infer various important things. + +trait Master<'a, T: ?Sized, U> { + fn foo() where T: 'a; +} + +// `U::Item: 'a` does not imply that `U: 'a` +impl<'a, U: Iterator> Master<'a, U::Item, U> for () { + fn foo() where U: 'a { } //~ ERROR E0276 } fn main() { - match Z(0, 1) { - Z{..} => {} //~ ERROR tuple structs and variants in struct patterns are unstable - } - match E::U(0, 1) { - E::U{..} => {} //~ ERROR tuple structs and variants in struct patterns are unstable - } - - let z1 = Z(0, 1); - let z2 = Z { ..z1 }; //~ ERROR tuple structs and variants in struct patterns are unstable + println!("Hello, world!"); } diff --git a/src/test/ui/compare-method/proj-outlives-region.stderr b/src/test/ui/compare-method/proj-outlives-region.stderr new file mode 100644 index 000000000000..79293e0deed6 --- /dev/null +++ b/src/test/ui/compare-method/proj-outlives-region.stderr @@ -0,0 +1,19 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/proj-outlives-region.rs:22:5 + | +17 | fn foo() where T: 'a; + | --------------------- definition of `foo` from trait +... +22 | fn foo() where U: 'a { } //~ ERROR E0276 + | ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `U: 'a` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #37166 +note: lint level defined here + --> $DIR/proj-outlives-region.rs:12:9 + | +12 | #![deny(extra_requirement_in_impl)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/compare-method/proj-outlives-region.stdout b/src/test/ui/compare-method/proj-outlives-region.stdout new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/test/compile-fail/region-bound-extra-bound-in-impl.rs b/src/test/ui/compare-method/region-extra-2.rs similarity index 94% rename from src/test/compile-fail/region-bound-extra-bound-in-impl.rs rename to src/test/ui/compare-method/region-extra-2.rs index 5bcc6be4c3d3..b0cd3b8fdd29 100644 --- a/src/test/compile-fail/region-bound-extra-bound-in-impl.rs +++ b/src/test/ui/compare-method/region-extra-2.rs @@ -17,7 +17,7 @@ trait Tr<'a, T> { impl<'a, T> Tr<'a, T> for &'a mut [T] { fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { - //~^ ERROR lifetime bound not satisfied + //~^ ERROR E0276 &mut self[..] } } diff --git a/src/test/ui/compare-method/region-extra-2.stderr b/src/test/ui/compare-method/region-extra-2.stderr new file mode 100644 index 000000000000..54a551bcfed5 --- /dev/null +++ b/src/test/ui/compare-method/region-extra-2.stderr @@ -0,0 +1,11 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/region-extra-2.rs:19:5 + | +15 | fn renew<'b: 'a>(self) -> &'b mut [T]; + | -------------------------------------- definition of `renew` from trait +... +19 | fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b { + | ^ impl has extra requirement `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/compare-method/region-extra.rs b/src/test/ui/compare-method/region-extra.rs new file mode 100644 index 000000000000..d61d0250211d --- /dev/null +++ b/src/test/ui/compare-method/region-extra.rs @@ -0,0 +1,27 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] +#![deny(extra_requirement_in_impl)] + +// Test that you cannot add an extra where clause in the impl relating +// two regions. + +trait Master<'a, 'b> { + fn foo(); +} + +impl<'a, 'b> Master<'a, 'b> for () { + fn foo() where 'a: 'b { } +} + +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/ui/compare-method/region-extra.stderr b/src/test/ui/compare-method/region-extra.stderr new file mode 100644 index 000000000000..e657813221a1 --- /dev/null +++ b/src/test/ui/compare-method/region-extra.stderr @@ -0,0 +1,11 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/region-extra.rs:22:5 + | +18 | fn foo(); + | --------- definition of `foo` from trait +... +22 | fn foo() where 'a: 'b { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'a: 'b` + +error: aborting due to previous error + diff --git a/src/test/ui/compare-method/region-extra.stdout b/src/test/ui/compare-method/region-extra.stdout new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/test/ui/compare-method/region-unrelated.rs b/src/test/ui/compare-method/region-unrelated.rs new file mode 100644 index 000000000000..8f79b30bd5f3 --- /dev/null +++ b/src/test/ui/compare-method/region-unrelated.rs @@ -0,0 +1,28 @@ +// 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. + +#![allow(dead_code)] +#![deny(extra_requirement_in_impl)] + +// Test that we elaborate `Type: 'region` constraints and infer various important things. + +trait Master<'a, T: ?Sized, U> { + fn foo() where T: 'a; +} + +// `U: 'a` does not imply `V: 'a` +impl<'a, U, V> Master<'a, U, V> for () { + fn foo() where V: 'a { } + //~^ ERROR parameter type `V` may not live long enough +} + +fn main() { + println!("Hello, world!"); +} diff --git a/src/test/ui/compare-method/region-unrelated.stderr b/src/test/ui/compare-method/region-unrelated.stderr new file mode 100644 index 000000000000..b7cfdf799bc9 --- /dev/null +++ b/src/test/ui/compare-method/region-unrelated.stderr @@ -0,0 +1,19 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/region-unrelated.rs:22:5 + | +17 | fn foo() where T: 'a; + | --------------------- definition of `foo` from trait +... +22 | fn foo() where V: 'a { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `V: 'a` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #37166 +note: lint level defined here + --> $DIR/region-unrelated.rs:12:9 + | +12 | #![deny(extra_requirement_in_impl)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/compare-method/region-unrelated.stdout b/src/test/ui/compare-method/region-unrelated.stdout new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/test/compile-fail/issue-2611-5.rs b/src/test/ui/compare-method/reordered-type-param.rs similarity index 98% rename from src/test/compile-fail/issue-2611-5.rs rename to src/test/ui/compare-method/reordered-type-param.rs index 440294f38ae9..0b844d4521d7 100644 --- a/src/test/compile-fail/issue-2611-5.rs +++ b/src/test/ui/compare-method/reordered-type-param.rs @@ -10,6 +10,8 @@ // Tests that ty params get matched correctly when comparing // an impl against a trait +// +// cc #26111 trait A { fn b(&self, x: C) -> C; diff --git a/src/test/ui/compare-method/reordered-type-param.stderr b/src/test/ui/compare-method/reordered-type-param.stderr new file mode 100644 index 000000000000..985b85cc4ec4 --- /dev/null +++ b/src/test/ui/compare-method/reordered-type-param.stderr @@ -0,0 +1,14 @@ +error[E0053]: method `b` has an incompatible type for trait + --> $DIR/reordered-type-param.rs:26:30 + | +17 | fn b(&self, x: C) -> C; + | - type in trait +... +26 | fn b(&self, _x: G) -> G { panic!() } //~ ERROR method `b` has an incompatible type + | ^ expected type parameter, found a different type parameter + | + = note: expected type `fn(&E, F) -> F` + = note: found type `fn(&E, G) -> G` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-2611-4.rs b/src/test/ui/compare-method/trait-bound-on-type-parameter.rs similarity index 71% rename from src/test/compile-fail/issue-2611-4.rs rename to src/test/ui/compare-method/trait-bound-on-type-parameter.rs index 16d7ea468466..09e9fb4ca2b6 100644 --- a/src/test/compile-fail/issue-2611-4.rs +++ b/src/test/ui/compare-method/trait-bound-on-type-parameter.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Tests that an impl method's bounds aren't *more* restrictive -// than the trait method it's implementing +// Tests that impl can't add extra `F: Sync` bound aren't *more* restrictive +// than the trait method it's implementing. +// +// Regr test for #26111. trait A { fn b(&self, x: C) -> C; @@ -20,8 +22,7 @@ struct E { } impl A for E { - fn b(&self, _x: F) -> F { panic!() } - //~^ ERROR `F: std::marker::Sync` appears on the impl method + fn b(&self, _x: F) -> F { panic!() } //~ ERROR E0276 } fn main() {} diff --git a/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr new file mode 100644 index 000000000000..7112a00c7b79 --- /dev/null +++ b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr @@ -0,0 +1,11 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/trait-bound-on-type-parameter.rs:25:5 + | +17 | fn b(&self, x: C) -> C; + | ---------------------------- definition of `b` from trait +... +25 | fn b(&self, _x: F) -> F { panic!() } //~ ERROR E0276 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `F: std::marker::Sync` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs b/src/test/ui/compare-method/traits-misc-mismatch-1.rs similarity index 82% rename from src/test/compile-fail/trait-bounds-impl-comparison-1.rs rename to src/test/ui/compare-method/traits-misc-mismatch-1.rs index 9cf65a9d00d0..cca282a1d195 100644 --- a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs +++ b/src/test/ui/compare-method/traits-misc-mismatch-1.rs @@ -34,15 +34,15 @@ trait Foo { impl Foo for isize { // invalid bound for T, was defined as Eq in trait fn test_error1_fn(&self) {} - //~^ ERROR the requirement `T: std::cmp::Ord` appears on the impl + //~^ ERROR E0276 // invalid bound for T, was defined as Eq + Ord in trait fn test_error2_fn(&self) {} - //~^ ERROR the requirement `T: B` appears on the impl + //~^ ERROR E0276 // invalid bound for T, was defined as Eq + Ord in trait fn test_error3_fn(&self) {} - //~^ ERROR the requirement `T: B` appears on the impl + //~^ ERROR E0276 // multiple bounds, same order as in trait fn test3_fn(&self) {} @@ -52,16 +52,16 @@ impl Foo for isize { // parameters in impls must be equal or more general than in the defining trait fn test_error5_fn(&self) {} - //~^ ERROR the requirement `T: B` appears on the impl + //~^ ERROR E0276 // bound `std::cmp::Eq` not enforced by this implementation, but this is OK fn test6_fn(&self) {} fn test_error7_fn(&self) {} - //~^ ERROR the requirement `T: std::cmp::Eq` appears on the impl + //~^ ERROR E0276 fn test_error8_fn(&self) {} - //~^ ERROR the requirement `T: C` appears on the impl + //~^ ERROR E0276 } trait Getter { @@ -74,7 +74,7 @@ trait Trait { impl Trait for usize { fn method>(&self) {} - //~^ ERROR `G: Getter` appears on the impl method + //~^ ERROR E0276 } fn main() {} diff --git a/src/test/ui/compare-method/traits-misc-mismatch-1.stderr b/src/test/ui/compare-method/traits-misc-mismatch-1.stderr new file mode 100644 index 000000000000..f221ebe3302c --- /dev/null +++ b/src/test/ui/compare-method/traits-misc-mismatch-1.stderr @@ -0,0 +1,65 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:36:5 + | +23 | fn test_error1_fn(&self); + | -------------------------------- definition of `test_error1_fn` from trait +... +36 | fn test_error1_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::cmp::Ord` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:40:5 + | +24 | fn test_error2_fn(&self); + | -------------------------------------- definition of `test_error2_fn` from trait +... +40 | fn test_error2_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: B` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:44:5 + | +25 | fn test_error3_fn(&self); + | -------------------------------------- definition of `test_error3_fn` from trait +... +44 | fn test_error3_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: B` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:54:5 + | +28 | fn test_error5_fn(&self); + | ------------------------------- definition of `test_error5_fn` from trait +... +54 | fn test_error5_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: B` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:60:5 + | +30 | fn test_error7_fn(&self); + | ------------------------------- definition of `test_error7_fn` from trait +... +60 | fn test_error7_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::cmp::Eq` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:63:5 + | +31 | fn test_error8_fn(&self); + | ------------------------------- definition of `test_error8_fn` from trait +... +63 | fn test_error8_fn(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: C` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-1.rs:76:5 + | +72 | fn method>(&self); + | ---------------------------------- definition of `method` from trait +... +76 | fn method>(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `G: Getter` + +error: aborting due to 7 previous errors + diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-2.rs b/src/test/ui/compare-method/traits-misc-mismatch-2.rs similarity index 92% rename from src/test/compile-fail/trait-bounds-impl-comparison-2.rs rename to src/test/ui/compare-method/traits-misc-mismatch-2.rs index 8d587b29ba98..e82cf256df13 100644 --- a/src/test/compile-fail/trait-bounds-impl-comparison-2.rs +++ b/src/test/ui/compare-method/traits-misc-mismatch-2.rs @@ -21,7 +21,7 @@ trait IteratorUtil: Sized impl> IteratorUtil for T { fn zip>(self, other: U) -> ZipIterator { - //~^ ERROR the requirement `U: Iterator` appears on the impl method + //~^ ERROR E0276 ZipIterator{a: self, b: other} } } diff --git a/src/test/ui/compare-method/traits-misc-mismatch-2.stderr b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr new file mode 100644 index 000000000000..5003550fd1ee --- /dev/null +++ b/src/test/ui/compare-method/traits-misc-mismatch-2.stderr @@ -0,0 +1,11 @@ +error[E0276]: impl has stricter requirements than trait + --> $DIR/traits-misc-mismatch-2.rs:23:5 + | +19 | fn zip>(self, other: U) -> ZipIterator; + | ------------------------------------------------------------------ definition of `zip` from trait +... +23 | fn zip>(self, other: U) -> ZipIterator { + | ^ impl has extra requirement `U: Iterator` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/E0046.rs b/src/test/ui/span/E0046.rs similarity index 95% rename from src/test/compile-fail/E0046.rs rename to src/test/ui/span/E0046.rs index a8b56b2b9ab3..9e757860a857 100644 --- a/src/test/compile-fail/E0046.rs +++ b/src/test/ui/span/E0046.rs @@ -10,6 +10,7 @@ trait Foo { fn foo(); + //~^ NOTE `foo` from trait } struct Bar; diff --git a/src/test/ui/span/E0046.stderr b/src/test/ui/span/E0046.stderr new file mode 100644 index 000000000000..729a51561246 --- /dev/null +++ b/src/test/ui/span/E0046.stderr @@ -0,0 +1,11 @@ +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/E0046.rs:18:1 + | +12 | fn foo(); + | --------- `foo` from trait +... +18 | impl Foo for Bar {} + | ^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error: aborting due to previous error + diff --git a/src/test/compile-fail/impl-wrong-item-for-trait.rs b/src/test/ui/span/impl-wrong-item-for-trait.rs similarity index 92% rename from src/test/compile-fail/impl-wrong-item-for-trait.rs rename to src/test/ui/span/impl-wrong-item-for-trait.rs index 388c9a1729cc..54ed42af5d58 100644 --- a/src/test/compile-fail/impl-wrong-item-for-trait.rs +++ b/src/test/ui/span/impl-wrong-item-for-trait.rs @@ -10,11 +10,11 @@ #![feature(associated_consts)] +use std::fmt::Debug; + trait Foo { fn bar(&self); - //~^ NOTE item in trait - //~| NOTE item in trait - const MY_CONST: u32; //~ NOTE item in trait + const MY_CONST: u32; } pub struct FooConstForMethod; @@ -50,4 +50,7 @@ impl Foo for FooTypeForMethod { const MY_CONST: u32 = 1; } +impl Debug for FooTypeForMethod { +} + fn main () {} diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr new file mode 100644 index 000000000000..244285e35845 --- /dev/null +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -0,0 +1,64 @@ +error[E0323]: item `bar` is an associated const, which doesn't match its trait `` + --> $DIR/impl-wrong-item-for-trait.rs:25:5 + | +16 | fn bar(&self); + | -------------- item in trait +... +25 | const bar: u64 = 1; + | ^^^^^^^^^^^^^^^^^^^ does not match trait + +error[E0046]: not all trait items implemented, missing: `bar` + --> $DIR/impl-wrong-item-for-trait.rs:22:1 + | +16 | fn bar(&self); + | -------------- `bar` from trait +... +22 | impl Foo for FooConstForMethod { + | ^ missing `bar` in implementation + +error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `` + --> $DIR/impl-wrong-item-for-trait.rs:37:5 + | +17 | const MY_CONST: u32; + | -------------------- item in trait +... +37 | fn MY_CONST() {} + | ^^^^^^^^^^^^^^^^ does not match trait + +error[E0046]: not all trait items implemented, missing: `MY_CONST` + --> $DIR/impl-wrong-item-for-trait.rs:33:1 + | +17 | const MY_CONST: u32; + | -------------------- `MY_CONST` from trait +... +33 | impl Foo for FooMethodForConst { + | ^ missing `MY_CONST` in implementation + +error[E0325]: item `bar` is an associated type, which doesn't match its trait `` + --> $DIR/impl-wrong-item-for-trait.rs:47:5 + | +16 | fn bar(&self); + | -------------- item in trait +... +47 | type bar = u64; + | ^^^^^^^^^^^^^^^ does not match trait + +error[E0046]: not all trait items implemented, missing: `bar` + --> $DIR/impl-wrong-item-for-trait.rs:44:1 + | +16 | fn bar(&self); + | -------------- `bar` from trait +... +44 | impl Foo for FooTypeForMethod { + | ^ missing `bar` in implementation + +error[E0046]: not all trait items implemented, missing: `fmt` + --> $DIR/impl-wrong-item-for-trait.rs:53:1 + | +53 | impl Debug for FooTypeForMethod { + | ^ missing `fmt` in implementation + | + = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` + +error: aborting due to 7 previous errors + diff --git a/src/test/compile-fail/issue-23729.rs b/src/test/ui/span/issue-23729.rs similarity index 96% rename from src/test/compile-fail/issue-23729.rs rename to src/test/ui/span/issue-23729.rs index b1047ce18ccc..66134a03baf4 100644 --- a/src/test/compile-fail/issue-23729.rs +++ b/src/test/ui/span/issue-23729.rs @@ -20,6 +20,7 @@ fn main() { impl Iterator for Recurrence { //~^ ERROR E0046 //~| NOTE missing `Item` in implementation + //~| NOTE `Item` from trait: `type Item;` #[inline] fn next(&mut self) -> Option { if self.pos < 2 { diff --git a/src/test/ui/span/issue-23729.stderr b/src/test/ui/span/issue-23729.stderr new file mode 100644 index 000000000000..493ca01778bc --- /dev/null +++ b/src/test/ui/span/issue-23729.stderr @@ -0,0 +1,10 @@ +error[E0046]: not all trait items implemented, missing: `Item` + --> $DIR/issue-23729.rs:20:9 + | +20 | impl Iterator for Recurrence { + | ^ missing `Item` in implementation + | + = note: `Item` from trait: `type Item;` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-23827.rs b/src/test/ui/span/issue-23827.rs similarity index 96% rename from src/test/compile-fail/issue-23827.rs rename to src/test/ui/span/issue-23827.rs index 2062e2373129..a5ab443597b9 100644 --- a/src/test/compile-fail/issue-23827.rs +++ b/src/test/ui/span/issue-23827.rs @@ -36,6 +36,7 @@ impl FnMut<(C,)> for Prototype { impl FnOnce<(C,)> for Prototype { //~^ ERROR E0046 //~| NOTE missing `Output` in implementation + //~| NOTE `Output` from trait: `type Output;` extern "rust-call" fn call_once(self, (comp,): (C,)) -> Prototype { Fn::call(&self, (comp,)) } diff --git a/src/test/ui/span/issue-23827.stderr b/src/test/ui/span/issue-23827.stderr new file mode 100644 index 000000000000..5130bb53a198 --- /dev/null +++ b/src/test/ui/span/issue-23827.stderr @@ -0,0 +1,10 @@ +error[E0046]: not all trait items implemented, missing: `Output` + --> $DIR/issue-23827.rs:36:1 + | +36 | impl FnOnce<(C,)> for Prototype { + | ^ missing `Output` in implementation + | + = note: `Output` from trait: `type Output;` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-24356.rs b/src/test/ui/span/issue-24356.rs similarity index 94% rename from src/test/compile-fail/issue-24356.rs rename to src/test/ui/span/issue-24356.rs index d39fd539dceb..0997dc802f88 100644 --- a/src/test/compile-fail/issue-24356.rs +++ b/src/test/ui/span/issue-24356.rs @@ -30,6 +30,7 @@ fn main() { impl Deref for Thing { //~^ ERROR E0046 //~| NOTE missing `Target` in implementation + //~| NOTE `Target` from trait: `type Target;` fn deref(&self) -> i8 { self.0 } } diff --git a/src/test/ui/span/issue-24356.stderr b/src/test/ui/span/issue-24356.stderr new file mode 100644 index 000000000000..906ef25ca0e1 --- /dev/null +++ b/src/test/ui/span/issue-24356.stderr @@ -0,0 +1,10 @@ +error[E0046]: not all trait items implemented, missing: `Target` + --> $DIR/issue-24356.rs:30:9 + | +30 | impl Deref for Thing { + | ^ missing `Target` in implementation + | + = note: `Target` from trait: `type Target;` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-16819.rs b/src/test/ui/span/issue-35987.rs similarity index 57% rename from src/test/compile-fail/issue-16819.rs rename to src/test/ui/span/issue-35987.rs index 4301b47f2e9b..8ff5f3b83986 100644 --- a/src/test/compile-fail/issue-16819.rs +++ b/src/test/ui/span/issue-35987.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,19 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct TS ( //~ ERROR empty tuple structs and enum variants are unstable - #[cfg(untrue)] - i32, -); +struct Foo(T); -enum E { - TV ( //~ ERROR empty tuple structs and enum variants are unstable - #[cfg(untrue)] - i32, - ) -} +use std::ops::Add; -fn main() { - let s = TS; - let tv = E::TV; +impl Add for Foo { + type Output = usize; + + fn add(self, rhs: Self) -> Self::Output { + unimplemented!(); + } } diff --git a/src/test/ui/span/issue-35987.stderr b/src/test/ui/span/issue-35987.stderr new file mode 100644 index 000000000000..2370b3d6c612 --- /dev/null +++ b/src/test/ui/span/issue-35987.stderr @@ -0,0 +1,12 @@ +error[E0404]: `Add` is not a trait + --> $DIR/issue-35987.rs:15:21 + | +15 | impl Add for Foo { + | --- ^^^ expected trait, found type parameter + | | + | type parameter defined here + +error: main function not found + +error: cannot continue compilation due to previous error + diff --git a/src/test/ui/update-references.sh b/src/test/ui/update-references.sh index f0a6f8a3d440..aa99d35f7aa7 100755 --- a/src/test/ui/update-references.sh +++ b/src/test/ui/update-references.sh @@ -36,12 +36,12 @@ while [[ "$1" != "" ]]; do STDOUT_NAME="${1/%.rs/.stdout}" shift if [ -f $BUILD_DIR/$STDOUT_NAME ] && \ - ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME > /dev/null); then + ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then echo updating $MYDIR/$STDOUT_NAME cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME fi if [ -f $BUILD_DIR/$STDERR_NAME ] && \ - ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME > /dev/null); then + ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then echo updating $MYDIR/$STDERR_NAME cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME fi diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 81cb927f26b0..34f3837d8bbb 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -146,8 +146,14 @@ pub struct Config { // Host triple for the compiler being invoked pub host: String, - // Version of GDB - pub gdb_version: Option, + // Path to / name of the GDB executable + pub gdb: Option, + + // Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch + pub gdb_version: Option, + + // Whether GDB has native rust support + pub gdb_native_rust: bool, // Version of LLDB pub lldb_version: Option, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 503a85167692..e57c9949b1c5 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -18,6 +18,8 @@ use common::Config; use common; use util; +use extract_gdb_version; + /// Properties which must be known very early, before actually running /// the test. pub struct EarlyProps { @@ -75,7 +77,7 @@ impl EarlyProps { return true; } - if let Some(ref actual_version) = config.gdb_version { + if let Some(actual_version) = config.gdb_version { if line.contains("min-gdb-version") { let min_version = line.trim() .split(' ') @@ -83,7 +85,7 @@ impl EarlyProps { .expect("Malformed GDB version directive"); // Ignore if actual version is smaller the minimum required // version - gdb_version_to_int(actual_version) < gdb_version_to_int(min_version) + actual_version < extract_gdb_version(min_version).unwrap() } else { false } @@ -464,23 +466,6 @@ pub fn parse_name_value_directive(line: &str, directive: &str) -> Option } } -pub fn gdb_version_to_int(version_string: &str) -> isize { - let error_string = format!("Encountered GDB version string with unexpected format: {}", - version_string); - let error_string = error_string; - - let components: Vec<&str> = version_string.trim().split('.').collect(); - - if components.len() != 2 { - panic!("{}", error_string); - } - - let major: isize = components[0].parse().ok().expect(&error_string); - let minor: isize = components[1].parse().ok().expect(&error_string); - - return major * 1000 + minor; -} - pub fn lldb_version_to_int(version_string: &str) -> isize { let error_string = format!("Encountered LLDB version string with unexpected format: {}", version_string); diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 2dc7cdbf9350..806363679d17 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -12,6 +12,7 @@ #![feature(box_syntax)] #![feature(rustc_private)] +#![feature(static_in_const)] #![feature(test)] #![feature(libc)] @@ -35,6 +36,7 @@ use std::ffi::OsString; use std::fs; use std::io; use std::path::{Path, PathBuf}; +use std::process::Command; use getopts::{optopt, optflag, reqopt}; use common::Config; use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Mode}; @@ -98,7 +100,7 @@ pub fn parse_config(args: Vec ) -> Config { optopt("", "logfile", "file to log test execution to", "FILE"), optopt("", "target", "the target to build for", "TARGET"), optopt("", "host", "the host to build for", "HOST"), - optopt("", "gdb-version", "the version of GDB used", "VERSION STRING"), + optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH"), optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"), optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING"), optopt("", "android-cross-path", "Android NDK standalone path", "PATH"), @@ -149,6 +151,8 @@ pub fn parse_config(args: Vec ) -> Config { } } + let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb")); + Config { compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), @@ -171,7 +175,9 @@ pub fn parse_config(args: Vec ) -> Config { target_rustcflags: matches.opt_str("target-rustcflags"), target: opt_str2(matches.opt_str("target")), host: opt_str2(matches.opt_str("host")), - gdb_version: extract_gdb_version(matches.opt_str("gdb-version")), + gdb: gdb, + gdb_version: gdb_version, + gdb_native_rust: gdb_native_rust, lldb_version: extract_lldb_version(matches.opt_str("lldb-version")), llvm_version: matches.opt_str("llvm-version"), android_cross_path: opt_path(matches, "android-cross-path"), @@ -470,44 +476,96 @@ pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn })) } -fn extract_gdb_version(full_version_line: Option) -> Option { - match full_version_line { - Some(ref full_version_line) - if !full_version_line.trim().is_empty() => { - let full_version_line = full_version_line.trim(); +/// Returns (Path to GDB, GDB Version, GDB has Rust Support) +fn analyze_gdb(gdb: Option) -> (Option, Option, bool) { + #[cfg(not(windows))] + const GDB_FALLBACK: &str = "gdb"; + #[cfg(windows)] + const GDB_FALLBACK: &str = "gdb.exe"; - // used to be a regex "(^|[^0-9])([0-9]\.[0-9]+)" - for (pos, c) in full_version_line.char_indices() { - if !c.is_digit(10) { - continue - } - if pos + 2 >= full_version_line.len() { - continue - } - if full_version_line[pos + 1..].chars().next().unwrap() != '.' { - continue - } - if !full_version_line[pos + 2..].chars().next().unwrap().is_digit(10) { - continue - } - if pos > 0 && full_version_line[..pos].chars().next_back() - .unwrap().is_digit(10) { - continue - } - let mut end = pos + 3; - while end < full_version_line.len() && - full_version_line[end..].chars().next() - .unwrap().is_digit(10) { - end += 1; - } - return Some(full_version_line[pos..end].to_owned()); - } - println!("Could not extract GDB version from line '{}'", - full_version_line); - None - }, - _ => None + const MIN_GDB_WITH_RUST: u32 = 7011010; + + let gdb = match gdb { + None => GDB_FALLBACK, + Some(ref s) if s.is_empty() => GDB_FALLBACK, // may be empty if configure found no gdb + Some(ref s) => s, + }; + + let version_line = Command::new(gdb).arg("--version").output().map(|output| { + String::from_utf8_lossy(&output.stdout).lines().next().unwrap().to_string() + }).ok(); + + let version = match version_line { + Some(line) => extract_gdb_version(&line), + None => return (None, None, false), + }; + + let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST); + + return (Some(gdb.to_owned()), version, gdb_native_rust); +} + +fn extract_gdb_version(full_version_line: &str) -> Option { + let full_version_line = full_version_line.trim(); + + // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both + // of the ? sections being optional + + // We will parse up to 3 digits for minor and patch, ignoring the date + // We limit major to 1 digit, otherwise, on openSUSE, we parse the openSUSE version + + // don't start parsing in the middle of a number + let mut prev_was_digit = false; + for (pos, c) in full_version_line.char_indices() { + if prev_was_digit || !c.is_digit(10) { + prev_was_digit = c.is_digit(10); + continue + } + + prev_was_digit = true; + + let line = &full_version_line[pos..]; + + let next_split = match line.find(|c: char| !c.is_digit(10)) { + Some(idx) => idx, + None => continue, // no minor version + }; + + if line.as_bytes()[next_split] != b'.' { + continue; // no minor version + } + + let major = &line[..next_split]; + let line = &line[next_split + 1..]; + + let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) { + Some(idx) => if line.as_bytes()[idx] == b'.' { + let patch = &line[idx + 1..]; + + let patch_len = patch.find(|c: char| !c.is_digit(10)).unwrap_or(patch.len()); + let patch = &patch[..patch_len]; + let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) }; + + (&line[..idx], patch) + } else { + (&line[..idx], None) + }, + None => (line, None), + }; + + if major.len() != 1 || minor.is_empty() { + continue; + } + + let major: u32 = major.parse().unwrap(); + let minor: u32 = minor.parse().unwrap(); + let patch: u32 = patch.unwrap_or("0").parse().unwrap(); + + return Some(((major * 1000) + minor) * 1000 + patch); } + + println!("Could not extract GDB version from line '{}'", full_version_line); + None } fn extract_lldb_version(full_version_line: Option) -> Option { @@ -553,3 +611,44 @@ fn extract_lldb_version(full_version_line: Option) -> Option { fn is_blacklisted_lldb_version(version: &str) -> bool { version == "350" } + +#[test] +fn test_extract_gdb_version() { + macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$( + assert_eq!(extract_gdb_version($input), Some($expectation)); + )*}}} + + test! { + 7000001: "GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)", + + 7002000: "GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)", + + 7004000: "GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04", + 7004001: "GNU gdb (GDB) 7.4.1-debian", + + 7006001: "GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7", + + 7007001: "GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1", + 7007001: "GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1", + 7007001: "GNU gdb (GDB) Fedora 7.7.1-21.fc20", + + 7008000: "GNU gdb (GDB; openSUSE 13.2) 7.8", + 7009001: "GNU gdb (GDB) Fedora 7.9.1-20.fc22", + 7010001: "GNU gdb (GDB) Fedora 7.10.1-31.fc23", + + 7011000: "GNU gdb (Ubuntu 7.11-0ubuntu1) 7.11", + 7011001: "GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1", + 7011001: "GNU gdb (Debian 7.11.1-2) 7.11.1", + 7011001: "GNU gdb (GDB) Fedora 7.11.1-86.fc24", + 7011001: "GNU gdb (GDB; openSUSE Leap 42.1) 7.11.1", + 7011001: "GNU gdb (GDB; openSUSE Tumbleweed) 7.11.1", + + 7011090: "7.11.90", + 7011090: "GNU gdb (Ubuntu 7.11.90.20161005-0ubuntu1) 7.11.90.20161005-git", + + 7012000: "7.12", + 7012000: "GNU gdb (GDB) 7.12", + 7012000: "GNU gdb (GDB) 7.12.20161027-git", + 7012050: "GNU gdb (GDB) 7.12.50.20161027-git", + } +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 03c05f919b79..8cb2e3b1c2de 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -32,6 +32,8 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Output, ExitStatus}; use std::str; +use extract_gdb_version; + pub fn run(config: Config, testpaths: &TestPaths) { match &*config.target { @@ -41,7 +43,12 @@ pub fn run(config: Config, testpaths: &TestPaths) { } } - _=> { } + _ => { + // android has it's own gdb handling + if config.mode == DebugInfoGdb && config.gdb.is_none() { + panic!("gdb not available but debuginfo gdb debuginfo test requested"); + } + } } if config.verbose { @@ -430,11 +437,23 @@ actual:\n\ } fn run_debuginfo_gdb_test_no_opt(&self) { + let prefixes = if self.config.gdb_native_rust { + // GDB with Rust + static PREFIXES: &'static [&'static str] = &["gdb", "gdbr"]; + println!("NOTE: compiletest thinks it is using GDB with native rust support"); + PREFIXES + } else { + // Generic GDB + static PREFIXES: &'static [&'static str] = &["gdb", "gdbg"]; + println!("NOTE: compiletest thinks it is using GDB without native rust support"); + PREFIXES + }; + let DebuggerCommands { commands, check_lines, breakpoint_lines - } = self.parse_debugger_commands("gdb"); + } = self.parse_debugger_commands(prefixes); let mut cmds = commands.join("\n"); // compile test file (it should have 'compile-flags:-g' in the header) @@ -586,19 +605,18 @@ actual:\n\ script_str.push_str("show version\n"); match self.config.gdb_version { - Some(ref version) => { + Some(version) => { println!("NOTE: compiletest thinks it is using GDB version {}", version); - if header::gdb_version_to_int(version) > - header::gdb_version_to_int("7.4") { - // Add the directory containing the pretty printers to - // GDB's script auto loading safe path - script_str.push_str( - &format!("add-auto-load-safe-path {}\n", - rust_pp_module_abs_path.replace(r"\", r"\\")) - ); - } + if version > extract_gdb_version("7.4").unwrap() { + // Add the directory containing the pretty printers to + // GDB's script auto loading safe path + script_str.push_str( + &format!("add-auto-load-safe-path {}\n", + rust_pp_module_abs_path.replace(r"\", r"\\")) + ); + } } _ => { println!("NOTE: compiletest does not know which version of \ @@ -633,11 +651,6 @@ actual:\n\ debug!("script_str = {}", script_str); self.dump_output_file(&script_str, "debugger.script"); - // run debugger script with gdb - fn debugger() -> &'static str { - if cfg!(windows) {"gdb.exe"} else {"gdb"} - } - let debugger_script = self.make_out_name("debugger.script"); // FIXME (#9639): This needs to handle non-utf8 paths @@ -648,7 +661,7 @@ actual:\n\ format!("-command={}", debugger_script.to_str().unwrap())]; let proc_args = ProcArgs { - prog: debugger().to_owned(), + prog: self.config.gdb.as_ref().unwrap().to_owned(), args: debugger_opts, }; @@ -731,7 +744,7 @@ actual:\n\ check_lines, breakpoint_lines, .. - } = self.parse_debugger_commands("lldb"); + } = self.parse_debugger_commands(&["lldb"]); // Write debugger script: // We don't want to hang when calling `quit` while the process is still running @@ -826,9 +839,11 @@ actual:\n\ } } - fn parse_debugger_commands(&self, debugger_prefix: &str) -> DebuggerCommands { - let command_directive = format!("{}-command", debugger_prefix); - let check_directive = format!("{}-check", debugger_prefix); + fn parse_debugger_commands(&self, debugger_prefixes: &[&str]) -> DebuggerCommands { + let directives = debugger_prefixes.iter().map(|prefix| ( + format!("{}-command", prefix), + format!("{}-check", prefix), + )).collect::>(); let mut breakpoint_lines = vec![]; let mut commands = vec![]; @@ -842,17 +857,19 @@ actual:\n\ breakpoint_lines.push(counter); } - header::parse_name_value_directive( - &line, - &command_directive).map(|cmd| { - commands.push(cmd) - }); + for &(ref command_directive, ref check_directive) in &directives { + header::parse_name_value_directive( + &line, + &command_directive).map(|cmd| { + commands.push(cmd) + }); - header::parse_name_value_directive( - &line, - &check_directive).map(|cmd| { - check_lines.push(cmd) - }); + header::parse_name_value_directive( + &line, + &check_directive).map(|cmd| { + check_lines.push(cmd) + }); + } } Err(e) => { self.fatal(&format!("Error while parsing debugger commands: {}", e)) diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index 415b6f056728..d6b7dafea40e 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -3,9 +3,6 @@ name = "linkchecker" version = "0.1.0" authors = ["Alex Crichton "] -[dependencies] -url = "1.2" - [[bin]] name = "linkchecker" path = "main.rs" diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index f79cc76e67d0..0e70c2b432f2 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -24,17 +24,13 @@ //! A few whitelisted exceptions are allowed as there's known bugs in rustdoc, //! but this should catch the majority of "broken link" cases. -extern crate url; - use std::env; use std::fs::File; use std::io::prelude::*; -use std::path::{Path, PathBuf}; +use std::path::{Path, PathBuf, Component}; use std::collections::{HashMap, HashSet}; use std::collections::hash_map::Entry; -use url::Url; - use Redirect::*; macro_rules! t { @@ -47,9 +43,8 @@ macro_rules! t { fn main() { let docs = env::args().nth(1).unwrap(); let docs = env::current_dir().unwrap().join(docs); - let mut url = Url::from_file_path(&docs).unwrap(); let mut errors = false; - walk(&mut HashMap::new(), &docs, &docs, &mut url, &mut errors); + walk(&mut HashMap::new(), &docs, &docs, &mut errors); if errors { panic!("found some broken links"); } @@ -88,15 +83,14 @@ impl FileEntry { } } -fn walk(cache: &mut Cache, root: &Path, dir: &Path, url: &mut Url, errors: &mut bool) { +fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) { for entry in t!(dir.read_dir()).map(|e| t!(e)) { let path = entry.path(); let kind = t!(entry.file_type()); - url.path_segments_mut().unwrap().push(entry.file_name().to_str().unwrap()); if kind.is_dir() { - walk(cache, root, &path, url, errors); + walk(cache, root, &path, errors); } else { - let pretty_path = check(cache, root, &path, url, errors); + let pretty_path = check(cache, root, &path, errors); if let Some(pretty_path) = pretty_path { let entry = cache.get_mut(&pretty_path).unwrap(); // we don't need the source anymore, @@ -104,14 +98,12 @@ fn walk(cache: &mut Cache, root: &Path, dir: &Path, url: &mut Url, errors: &mut entry.source = String::new(); } } - url.path_segments_mut().unwrap().pop(); } } fn check(cache: &mut Cache, root: &Path, file: &Path, - base: &Url, errors: &mut bool) -> Option { // ignore js files as they are not prone to errors as the rest of the @@ -157,19 +149,28 @@ fn check(cache: &mut Cache, url.starts_with("irc:") || url.starts_with("data:") { return; } + let mut parts = url.splitn(2, "#"); + let url = parts.next().unwrap(); + if url.is_empty() { + return + } + let fragment = parts.next(); + let mut parts = url.splitn(2, "?"); + let url = parts.next().unwrap(); + // Once we've plucked out the URL, parse it using our base url and // then try to extract a file path. - let (parsed_url, path) = match url_to_file_path(&base, url) { - Some((url, path)) => (url, PathBuf::from(path)), - None => { - *errors = true; - println!("{}:{}: invalid link - {}", - pretty_file.display(), - i + 1, - url); - return; + let mut path = file.to_path_buf(); + path.pop(); + for part in Path::new(url).components() { + match part { + Component::Prefix(_) | + Component::RootDir => panic!(), + Component::CurDir => {} + Component::ParentDir => { path.pop(); } + Component::Normal(s) => { path.push(s); } } - }; + } // Alright, if we've found a file name then this file had better // exist! If it doesn't then we register and print an error. @@ -200,7 +201,7 @@ fn check(cache: &mut Cache, Err(LoadError::IsRedirect) => unreachable!(), }; - if let Some(ref fragment) = parsed_url.fragment() { + if let Some(ref fragment) = fragment { // Fragments like `#1-6` are most likely line numbers to be // interpreted by javascript, so we're ignoring these if fragment.splitn(2, '-') @@ -231,7 +232,7 @@ fn check(cache: &mut Cache, fn load_file(cache: &mut Cache, root: &Path, - file: PathBuf, + mut file: PathBuf, redirect: Redirect) -> Result<(PathBuf, String), LoadError> { let mut contents = String::new(); @@ -266,10 +267,9 @@ fn load_file(cache: &mut Cache, maybe } }; - let base = Url::from_file_path(&file).unwrap(); - - match maybe_redirect.and_then(|url| url_to_file_path(&base, &url)) { - Some((_, redirect_file)) => { + file.pop(); + match maybe_redirect.map(|url| file.join(url)) { + Some(redirect_file) => { let path = PathBuf::from(redirect_file); load_file(cache, root, path, FromRedirect(true)) } @@ -293,12 +293,6 @@ fn maybe_redirect(source: &str) -> Option { }) } -fn url_to_file_path(parser: &Url, url: &str) -> Option<(Url, PathBuf)> { - parser.join(url) - .ok() - .and_then(|parsed_url| parsed_url.to_file_path().ok().map(|f| (parsed_url, f))) -} - fn with_attrs_in_source(contents: &str, attr: &str, mut f: F) { for (i, mut line) in contents.lines().enumerate() { while let Some(j) = line.find(attr) { diff --git a/src/tools/tidy/src/cargo.rs b/src/tools/tidy/src/cargo.rs index a7784e65c5b1..11acb64743a7 100644 --- a/src/tools/tidy/src/cargo.rs +++ b/src/tools/tidy/src/cargo.rs @@ -20,6 +20,9 @@ use std::fs::File; use std::path::Path; pub fn check(path: &Path, bad: &mut bool) { + if path.ends_with("vendor") { + return + } for entry in t!(path.read_dir(), path).map(|e| t!(e)) { // Look for `Cargo.toml` with a sibling `src/lib.rs` or `lib.rs` if entry.file_name().to_str() == Some("Cargo.toml") { diff --git a/src/tools/tidy/src/cargo_lock.rs b/src/tools/tidy/src/cargo_lock.rs deleted file mode 100644 index 165dd52758ec..000000000000 --- a/src/tools/tidy/src/cargo_lock.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::path::Path; -use std::ffi::OsStr; - -const CARGO_LOCK: &'static str = "Cargo.lock"; - -pub fn check(path: &Path, bad: &mut bool) { - use std::process::Command; - - super::walk(path, - &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), - &mut |file| { - if let Some(CARGO_LOCK) = file.file_name().and_then(OsStr::to_str) { - let rel_path = file.strip_prefix(path).unwrap(); - let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/"); - let ret_code = Command::new("git") - .arg("diff") - .arg("--exit-code") - .arg("--patch") - .arg("HEAD") - .arg(&git_friendly_path) - .current_dir(path) - .status() - .unwrap_or_else(|e| { - panic!("could not run git diff-index: {}", e); - }); - if !ret_code.success() { - let parent_path = file.parent().unwrap().join("Cargo.toml"); - print!("dirty lock file found at {} ", rel_path.display()); - println!("please commit your changes or update the lock file by running:"); - println!("\n\tcargo update --manifest-path {}", parent_path.display()); - *bad = true; - } - } - }); -} diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index cabaee5d0600..cb11fe261c45 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -35,7 +35,6 @@ mod style; mod errors; mod features; mod cargo; -mod cargo_lock; mod pal; fn main() { @@ -48,7 +47,6 @@ fn main() { errors::check(&path, &mut bad); cargo::check(&path, &mut bad); features::check(&path, &mut bad); - cargo_lock::check(&path, &mut bad); pal::check(&path, &mut bad); if bad { @@ -66,6 +64,7 @@ fn filter_dirs(path: &Path) -> bool { "src/rustllvm", "src/rust-installer", "src/liblibc", + "src/vendor", ]; skip.iter().any(|p| path.ends_with(p)) } diff --git a/src/vendor/cmake/.cargo-checksum.json b/src/vendor/cmake/.cargo-checksum.json new file mode 100644 index 000000000000..b81d7d2fa04e --- /dev/null +++ b/src/vendor/cmake/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"c1e953ee360e77de57f7b02f1b7880bd6a3dc22d1a69e953c2ac2c52cc52d247",".travis.yml":"5d83ed1ae0b80cd6cebfc6a25b1fdb58c893ead400f0f84cd0ebf08d9ad48b28","Cargo.toml":"2266412ecb4504137a90d378ebdbf3a41f0e8b7188858cfb149da54792f7f8d9","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"8ca528d20639506546044c676ff9069e3e850937b02bff4194dcf9e5c3c50d64","src/lib.rs":"dae5d93c005bf8d16427e29eb3bfb50c5527a1ec7c39a383d0694a8e8e38af90","src/registry.rs":"ca16433f51b5e3aedb0560bba41370b0c42de9238926a5118d1c0a3a072b64b2"},"package":"0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283"} \ No newline at end of file diff --git a/src/vendor/cmake/.cargo-ok b/src/vendor/cmake/.cargo-ok new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/vendor/cmake/.gitignore b/src/vendor/cmake/.gitignore new file mode 100644 index 000000000000..4fffb2f89cbd --- /dev/null +++ b/src/vendor/cmake/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/src/vendor/cmake/.travis.yml b/src/vendor/cmake/.travis.yml new file mode 100644 index 000000000000..3ac040c5c094 --- /dev/null +++ b/src/vendor/cmake/.travis.yml @@ -0,0 +1,19 @@ +language: rust +rust: + - stable + - beta + - nightly +sudo: false +before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH +script: + - cargo test --verbose + - cargo doc --no-deps +after_success: + - travis-cargo --only nightly doc-upload +env: + global: + secure: WSQJRyheeMf7eRdivHextSEQzyFnTIw2yeemO2+ZkHVftp0XYsTXQVca3RGlQNsVmjI0RP8lbDVe7HG23uwbTMeRgm+9hzSwNMa0ndJZ06TNMpPM6nqcXFUaNGeuf7EqU370xcgVBO+ZA0cSh55pJkOBg5ALd9bfRWbjEAjHkx8= +notifications: + email: + on_success: never diff --git a/src/vendor/cmake/Cargo.toml b/src/vendor/cmake/Cargo.toml new file mode 100644 index 000000000000..c17bbff92258 --- /dev/null +++ b/src/vendor/cmake/Cargo.toml @@ -0,0 +1,17 @@ +[package] + +name = "cmake" +version = "0.1.18" +authors = ["Alex Crichton "] +license = "MIT/Apache-2.0" +readme = "README.md" +keywords = ["build-dependencies"] +repository = "https://github.com/alexcrichton/cmake-rs" +homepage = "https://github.com/alexcrichton/cmake-rs" +documentation = "http://alexcrichton.com/cmake-rs" +description = """ +A build dependency for running `cmake` to build a native library +""" + +[dependencies] +gcc = "0.3.17" diff --git a/src/vendor/cmake/LICENSE-APACHE b/src/vendor/cmake/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/src/vendor/cmake/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/vendor/cmake/LICENSE-MIT b/src/vendor/cmake/LICENSE-MIT new file mode 100644 index 000000000000..39e0ed660215 --- /dev/null +++ b/src/vendor/cmake/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/vendor/cmake/README.md b/src/vendor/cmake/README.md new file mode 100644 index 000000000000..8b2586eb01e2 --- /dev/null +++ b/src/vendor/cmake/README.md @@ -0,0 +1,22 @@ +# cmake + +[![Build Status](https://travis-ci.org/alexcrichton/cmake-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/cmake-rs) + +[Documentation](http://alexcrichton.com/cmake-rs) + +A build dependency for running the `cmake` build tool to compile a native +library. + +```toml +# Cargo.toml +[build-dependencies] +cmake = "0.2" +``` + +# License + +`cmake-rs` is primarily distributed under the terms of both the MIT license and +the Apache License (Version 2.0), with portions covered by various BSD-like +licenses. + +See LICENSE-APACHE, and LICENSE-MIT for details. diff --git a/src/vendor/cmake/src/lib.rs b/src/vendor/cmake/src/lib.rs new file mode 100644 index 000000000000..3607d29026a0 --- /dev/null +++ b/src/vendor/cmake/src/lib.rs @@ -0,0 +1,522 @@ +//! A build dependency for running `cmake` to build a native library +//! +//! This crate provides some necessary boilerplate and shim support for running +//! the system `cmake` command to build a native library. It will add +//! appropriate cflags for building code to link into Rust, handle cross +//! compilation, and use the necessary generator for the platform being +//! targeted. +//! +//! The builder-style configuration allows for various variables and such to be +//! passed down into the build as well. +//! +//! ## Installation +//! +//! Add this to your `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! cmake = "0.1" +//! ``` +//! +//! ## Examples +//! +//! ```no_run +//! use cmake; +//! +//! // Builds the project in the directory located in `libfoo`, installing it +//! // into $OUT_DIR +//! let dst = cmake::build("libfoo"); +//! +//! println!("cargo:rustc-link-search=native={}", dst.display()); +//! println!("cargo:rustc-link-lib=static=foo"); +//! ``` +//! +//! ```no_run +//! use cmake::Config; +//! +//! let dst = Config::new("libfoo") +//! .define("FOO", "BAR") +//! .cflag("-foo") +//! .build(); +//! println!("cargo:rustc-link-search=native={}", dst.display()); +//! println!("cargo:rustc-link-lib=static=foo"); +//! ``` + +#![deny(missing_docs)] + +extern crate gcc; + +use std::env; +use std::ffi::{OsString, OsStr}; +use std::fs::{self, File}; +use std::io::ErrorKind; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; +use std::process::Command; + +#[cfg(windows)] +mod registry; + +/// Builder style configuration for a pending CMake build. +pub struct Config { + path: PathBuf, + generator: Option, + cflags: OsString, + cxxflags: OsString, + defines: Vec<(OsString, OsString)>, + deps: Vec, + target: Option, + host: Option, + out_dir: Option, + profile: Option, + build_args: Vec, + cmake_target: Option, +} + +/// Builds the native library rooted at `path` with the default cmake options. +/// This will return the directory in which the library was installed. +/// +/// # Examples +/// +/// ```no_run +/// use cmake; +/// +/// // Builds the project in the directory located in `libfoo`, installing it +/// // into $OUT_DIR +/// let dst = cmake::build("libfoo"); +/// +/// println!("cargo:rustc-link-search=native={}", dst.display()); +/// println!("cargo:rustc-link-lib=static=foo"); +/// ``` +/// +pub fn build>(path: P) -> PathBuf { + Config::new(path.as_ref()).build() +} + +impl Config { + /// Creates a new blank set of configuration to build the project specified + /// at the path `path`. + pub fn new>(path: P) -> Config { + Config { + path: env::current_dir().unwrap().join(path), + generator: None, + cflags: OsString::new(), + cxxflags: OsString::new(), + defines: Vec::new(), + deps: Vec::new(), + profile: None, + out_dir: None, + target: None, + host: None, + build_args: Vec::new(), + cmake_target: None, + } + } + + /// Sets the build-tool generator (`-G`) for this compilation. + pub fn generator>(&mut self, generator: T) -> &mut Config { + self.generator = Some(generator.as_ref().to_owned()); + self + } + + /// Adds a custom flag to pass down to the C compiler, supplementing those + /// that this library already passes. + pub fn cflag>(&mut self, flag: P) -> &mut Config { + self.cflags.push(" "); + self.cflags.push(flag.as_ref()); + self + } + + /// Adds a custom flag to pass down to the C++ compiler, supplementing those + /// that this library already passes. + pub fn cxxflag>(&mut self, flag: P) -> &mut Config { + self.cxxflags.push(" "); + self.cxxflags.push(flag.as_ref()); + self + } + + /// Adds a new `-D` flag to pass to cmake during the generation step. + pub fn define(&mut self, k: K, v: V) -> &mut Config + where K: AsRef, V: AsRef + { + self.defines.push((k.as_ref().to_owned(), v.as_ref().to_owned())); + self + } + + /// Registers a dependency for this compilation on the native library built + /// by Cargo previously. + /// + /// This registration will modify the `CMAKE_PREFIX_PATH` environment + /// variable for the build system generation step. + pub fn register_dep(&mut self, dep: &str) -> &mut Config { + self.deps.push(dep.to_string()); + self + } + + /// Sets the target triple for this compilation. + /// + /// This is automatically scraped from `$TARGET` which is set for Cargo + /// build scripts so it's not necessary to call this from a build script. + pub fn target(&mut self, target: &str) -> &mut Config { + self.target = Some(target.to_string()); + self + } + + /// Sets the host triple for this compilation. + /// + /// This is automatically scraped from `$HOST` which is set for Cargo + /// build scripts so it's not necessary to call this from a build script. + pub fn host(&mut self, host: &str) -> &mut Config { + self.host = Some(host.to_string()); + self + } + + /// Sets the output directory for this compilation. + /// + /// This is automatically scraped from `$OUT_DIR` which is set for Cargo + /// build scripts so it's not necessary to call this from a build script. + pub fn out_dir>(&mut self, out: P) -> &mut Config { + self.out_dir = Some(out.as_ref().to_path_buf()); + self + } + + /// Sets the profile for this compilation. + /// + /// This is automatically scraped from `$PROFILE` which is set for Cargo + /// build scripts so it's not necessary to call this from a build script. + pub fn profile(&mut self, profile: &str) -> &mut Config { + self.profile = Some(profile.to_string()); + self + } + + /// Add an argument to the final `cmake` build step + pub fn build_arg>(&mut self, arg: A) -> &mut Config { + self.build_args.push(arg.as_ref().to_owned()); + self + } + + /// Sets the build target for the final `cmake` build step, this will + /// default to "install" if not specified. + pub fn build_target(&mut self, target: &str) -> &mut Config { + self.cmake_target = Some(target.to_string()); + self + } + + /// Run this configuration, compiling the library with all the configured + /// options. + /// + /// This will run both the build system generator command as well as the + /// command to build the library. + pub fn build(&mut self) -> PathBuf { + let target = self.target.clone().unwrap_or_else(|| { + getenv_unwrap("TARGET") + }); + let host = self.host.clone().unwrap_or_else(|| { + getenv_unwrap("HOST") + }); + let msvc = target.contains("msvc"); + let c_compiler = gcc::Config::new().cargo_metadata(false) + .opt_level(0) + .debug(false) + .target(&target) + .host(&host) + .get_compiler(); + let cxx_compiler = gcc::Config::new().cargo_metadata(false) + .cpp(true) + .opt_level(0) + .debug(false) + .target(&target) + .host(&host) + .get_compiler(); + + let dst = self.out_dir.clone().unwrap_or_else(|| { + PathBuf::from(getenv_unwrap("OUT_DIR")) + }); + let build = dst.join("build"); + self.maybe_clear(&build); + let _ = fs::create_dir(&build); + + // Add all our dependencies to our cmake paths + let mut cmake_prefix_path = Vec::new(); + for dep in &self.deps { + if let Some(root) = env::var_os(&format!("DEP_{}_ROOT", dep)) { + cmake_prefix_path.push(PathBuf::from(root)); + } + } + let system_prefix = env::var_os("CMAKE_PREFIX_PATH") + .unwrap_or(OsString::new()); + cmake_prefix_path.extend(env::split_paths(&system_prefix) + .map(|s| s.to_owned())); + let cmake_prefix_path = env::join_paths(&cmake_prefix_path).unwrap(); + + // Build up the first cmake command to build the build system. + let mut cmd = Command::new("cmake"); + cmd.arg(&self.path) + .current_dir(&build); + if target.contains("windows-gnu") { + if host.contains("windows") { + // On MinGW we need to coerce cmake to not generate a visual + // studio build system but instead use makefiles that MinGW can + // use to build. + if self.generator.is_none() { + cmd.arg("-G").arg("MSYS Makefiles"); + } + } else { + // If we're cross compiling onto windows, then set some + // variables which will hopefully get things to succeed. Some + // systems may need the `windres` or `dlltool` variables set, so + // set them if possible. + if !self.defined("CMAKE_SYSTEM_NAME") { + cmd.arg("-DCMAKE_SYSTEM_NAME=Windows"); + } + if !self.defined("CMAKE_RC_COMPILER") { + let exe = find_exe(c_compiler.path()); + if let Some(name) = exe.file_name().unwrap().to_str() { + let name = name.replace("gcc", "windres"); + let windres = exe.with_file_name(name); + if windres.is_file() { + let mut arg = OsString::from("-DCMAKE_RC_COMPILER="); + arg.push(&windres); + cmd.arg(arg); + } + } + } + } + } else if msvc { + // If we're on MSVC we need to be sure to use the right generator or + // otherwise we won't get 32/64 bit correct automatically. + if self.generator.is_none() { + cmd.arg("-G").arg(self.visual_studio_generator(&target)); + } + } + if let Some(ref generator) = self.generator { + cmd.arg("-G").arg(generator); + } + let profile = self.profile.clone().unwrap_or_else(|| { + match &getenv_unwrap("PROFILE")[..] { + "bench" | "release" => "Release", + // currently we need to always use the same CRT for MSVC + _ if msvc => "Release", + _ => "Debug", + }.to_string() + }); + for &(ref k, ref v) in &self.defines { + let mut os = OsString::from("-D"); + os.push(k); + os.push("="); + os.push(v); + cmd.arg(os); + } + + if !self.defined("CMAKE_INSTALL_PREFIX") { + let mut dstflag = OsString::from("-DCMAKE_INSTALL_PREFIX="); + dstflag.push(&dst); + cmd.arg(dstflag); + } + + { + let mut set_compiler = |kind: &str, + compiler: &gcc::Tool, + extra: &OsString| { + let flag_var = format!("CMAKE_{}_FLAGS", kind); + let tool_var = format!("CMAKE_{}_COMPILER", kind); + if !self.defined(&flag_var) { + let mut flagsflag = OsString::from("-D"); + flagsflag.push(&flag_var); + flagsflag.push("="); + flagsflag.push(extra); + for arg in compiler.args() { + flagsflag.push(" "); + flagsflag.push(arg); + } + cmd.arg(flagsflag); + } + + // Apparently cmake likes to have an absolute path to the + // compiler as otherwise it sometimes thinks that this variable + // changed as it thinks the found compiler, /usr/bin/cc, + // differs from the specified compiler, cc. Not entirely sure + // what's up, but at least this means cmake doesn't get + // confused? + // + // Also don't specify this on Windows as it's not needed for + // MSVC and for MinGW it doesn't really vary. + if !self.defined("CMAKE_TOOLCHAIN_FILE") + && !self.defined(&tool_var) + && env::consts::FAMILY != "windows" { + let mut ccompiler = OsString::from("-D"); + ccompiler.push(&tool_var); + ccompiler.push("="); + ccompiler.push(find_exe(compiler.path())); + cmd.arg(ccompiler); + } + }; + + set_compiler("C", &c_compiler, &self.cflags); + set_compiler("CXX", &cxx_compiler, &self.cxxflags); + } + + if !self.defined("CMAKE_BUILD_TYPE") { + cmd.arg(&format!("-DCMAKE_BUILD_TYPE={}", profile)); + } + + if !self.defined("CMAKE_TOOLCHAIN_FILE") { + if let Ok(s) = env::var("CMAKE_TOOLCHAIN_FILE") { + cmd.arg(&format!("-DCMAKE_TOOLCHAIN_FILE={}", s)); + } + } + + run(cmd.env("CMAKE_PREFIX_PATH", cmake_prefix_path), "cmake"); + + let mut parallel_args = Vec::new(); + if fs::metadata(&dst.join("build/Makefile")).is_ok() { + if let Ok(s) = env::var("NUM_JOBS") { + parallel_args.push(format!("-j{}", s)); + } + } + + // And build! + let target = self.cmake_target.clone().unwrap_or("install".to_string()); + run(Command::new("cmake") + .arg("--build").arg(".") + .arg("--target").arg(target) + .arg("--config").arg(profile) + .arg("--").args(&self.build_args) + .args(¶llel_args) + .current_dir(&build), "cmake"); + + println!("cargo:root={}", dst.display()); + return dst + } + + fn visual_studio_generator(&self, target: &str) -> String { + let base = match std::env::var("VisualStudioVersion") { + Ok(version) => { + match &version[..] { + "15.0" => "Visual Studio 15", + "14.0" => "Visual Studio 14 2015", + "12.0" => "Visual Studio 12 2013", + vers => panic!("\n\n\ + unsupported or unknown VisualStudio version: {}\n\ + if another version is installed consider running \ + the appropriate vcvars script before building this \ + crate\n\ + ", vers), + } + } + _ => { + // Check for the presense of a specific registry key + // that indicates visual studio is installed. + if self.has_msbuild_version("15.0") { + "Visual Studio 15" + } else if self.has_msbuild_version("14.0") { + "Visual Studio 14 2015" + } else if self.has_msbuild_version("12.0") { + "Visual Studio 12 2013" + } else { + panic!("\n\n\ + couldn't determine visual studio generator\n\ + if VisualStudio is installed, however, consider \ + running the appropriate vcvars script before building \ + this crate\n\ + "); + } + } + }; + + if target.contains("i686") { + base.to_string() + } else if target.contains("x86_64") { + format!("{} Win64", base) + } else { + panic!("unsupported msvc target: {}", target); + } + } + + #[cfg(not(windows))] + fn has_msbuild_version(&self, _version: &str) -> bool { + false + } + + #[cfg(windows)] + fn has_msbuild_version(&self, version: &str) -> bool { + let key = format!("SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}", + version); + registry::LOCAL_MACHINE.open(key.as_ref()).is_ok() + } + + fn defined(&self, var: &str) -> bool { + self.defines.iter().any(|&(ref a, _)| a == var) + } + + // If a cmake project has previously been built (e.g. CMakeCache.txt already + // exists), then cmake will choke if the source directory for the original + // project being built has changed. Detect this situation through the + // `CMAKE_HOME_DIRECTORY` variable that cmake emits and if it doesn't match + // we blow away the build directory and start from scratch (the recommended + // solution apparently [1]). + // + // [1]: https://cmake.org/pipermail/cmake/2012-August/051545.html + fn maybe_clear(&self, dir: &Path) { + // CMake will apparently store canonicalized paths which normally + // isn't relevant to us but we canonicalize it here to ensure + // we're both checking the same thing. + let path = fs::canonicalize(&self.path).unwrap_or(self.path.clone()); + let src = match path.to_str() { + Some(src) => src, + None => return, + }; + let mut f = match File::open(dir.join("CMakeCache.txt")) { + Ok(f) => f, + Err(..) => return, + }; + let mut u8contents = Vec::new(); + match f.read_to_end(&mut u8contents) { + Ok(f) => f, + Err(..) => return, + }; + let contents = String::from_utf8_lossy(&u8contents); + drop(f); + for line in contents.lines() { + if line.contains("CMAKE_HOME_DIRECTORY") && !line.contains(src) { + println!("detected home dir change, cleaning out entire build \ + directory"); + fs::remove_dir_all(dir).unwrap(); + break + } + } + } +} + +fn run(cmd: &mut Command, program: &str) { + println!("running: {:?}", cmd); + let status = match cmd.status() { + Ok(status) => status, + Err(ref e) if e.kind() == ErrorKind::NotFound => { + fail(&format!("failed to execute command: {}\nis `{}` not installed?", + e, program)); + } + Err(e) => fail(&format!("failed to execute command: {}", e)), + }; + if !status.success() { + fail(&format!("command did not execute successfully, got: {}", status)); + } +} + +fn find_exe(path: &Path) -> PathBuf { + env::split_paths(&env::var_os("PATH").unwrap_or(OsString::new())) + .map(|p| p.join(path)) + .find(|p| fs::metadata(p).is_ok()) + .unwrap_or(path.to_owned()) +} + +fn getenv_unwrap(v: &str) -> String { + match env::var(v) { + Ok(s) => s, + Err(..) => fail(&format!("environment variable `{}` not defined", v)), + } +} + +fn fail(s: &str) -> ! { + panic!("\n{}\n\nbuild script failed, must exit now", s) +} diff --git a/src/vendor/cmake/src/registry.rs b/src/vendor/cmake/src/registry.rs new file mode 100644 index 000000000000..8819b094151e --- /dev/null +++ b/src/vendor/cmake/src/registry.rs @@ -0,0 +1,84 @@ +// 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. + +use std::ffi::OsStr; +use std::io; +use std::os::raw; +use std::os::windows::prelude::*; + +pub struct RegistryKey(Repr); + +type HKEY = *mut u8; +type DWORD = u32; +type LPDWORD = *mut DWORD; +type LPCWSTR = *const u16; +type LPWSTR = *mut u16; +type LONG = raw::c_long; +type PHKEY = *mut HKEY; +type PFILETIME = *mut u8; +type LPBYTE = *mut u8; +type REGSAM = u32; + +const ERROR_SUCCESS: DWORD = 0; +const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY; +const KEY_READ: DWORD = 0x20019; +const KEY_WOW64_32KEY: DWORD = 0x200; + +#[link(name = "advapi32")] +extern "system" { + fn RegOpenKeyExW(key: HKEY, + lpSubKey: LPCWSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY) -> LONG; + fn RegCloseKey(hKey: HKEY) -> LONG; +} + +struct OwnedKey(HKEY); + +enum Repr { + Const(HKEY), + Owned(OwnedKey), +} + +unsafe impl Sync for Repr {} +unsafe impl Send for Repr {} + +pub static LOCAL_MACHINE: RegistryKey = + RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE)); + +impl RegistryKey { + fn raw(&self) -> HKEY { + match self.0 { + Repr::Const(val) => val, + Repr::Owned(ref val) => val.0, + } + } + + pub fn open(&self, key: &OsStr) -> io::Result { + let key = key.encode_wide().chain(Some(0)).collect::>(); + let mut ret = 0 as *mut _; + let err = unsafe { + RegOpenKeyExW(self.raw(), key.as_ptr(), 0, + KEY_READ | KEY_WOW64_32KEY, &mut ret) + }; + if err == ERROR_SUCCESS as LONG { + Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) + } else { + Err(io::Error::from_raw_os_error(err as i32)) + } + } +} + +impl Drop for OwnedKey { + fn drop(&mut self) { + unsafe { RegCloseKey(self.0); } + } +} diff --git a/src/vendor/env_logger/.cargo-checksum.json b/src/vendor/env_logger/.cargo-checksum.json new file mode 100644 index 000000000000..e3d83501ad07 --- /dev/null +++ b/src/vendor/env_logger/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","Cargo.toml":"4af0565a97a599bba727315d9aff1f57a350dcfee7d9f00986c851e54a24b4ca","src/lib.rs":"484cec14a5f18a25b71d7b1842f7b184f0530165021b71b36dde9fc57b7fc15a","src/regex.rs":"d8e2a6958d4ed8084867063aae4b5c77ffc5d271dc2e17909d56c5a5e1552034","src/string.rs":"26ede9ab41a2673c3ad6001bc1802c005ce9a4f190f55860a24aa66b6b71bbc7","tests/regexp_filter.rs":"a3f9c01623e90e54b247a62c53b25caf5f502d054f28c0bdf92abbea486a95b5"},"package":"15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"} \ No newline at end of file diff --git a/src/vendor/env_logger/.cargo-ok b/src/vendor/env_logger/.cargo-ok new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/vendor/env_logger/Cargo.toml b/src/vendor/env_logger/Cargo.toml new file mode 100644 index 000000000000..5efadbf0d629 --- /dev/null +++ b/src/vendor/env_logger/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "env_logger" +version = "0.3.5" +authors = ["The Rust Project Developers"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/log" +documentation = "http://doc.rust-lang.org/log/env_logger" +homepage = "https://github.com/rust-lang/log" +description = """ +An logging implementation for `log` which is configured via an environment +variable. +""" + +[dependencies] +log = { version = "0.3", path = ".." } +regex = { version = "0.1", optional = true } + +[[test]] +name = "regexp_filter" +harness = false + +[features] +default = ["regex"] diff --git a/src/vendor/env_logger/src/lib.rs b/src/vendor/env_logger/src/lib.rs new file mode 100644 index 000000000000..9105c19c65cd --- /dev/null +++ b/src/vendor/env_logger/src/lib.rs @@ -0,0 +1,623 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A logger configured via an environment variable which writes to standard +//! error. +//! +//! ## Example +//! +//! ``` +//! #[macro_use] extern crate log; +//! extern crate env_logger; +//! +//! use log::LogLevel; +//! +//! fn main() { +//! env_logger::init().unwrap(); +//! +//! debug!("this is a debug {}", "message"); +//! error!("this is printed by default"); +//! +//! if log_enabled!(LogLevel::Info) { +//! let x = 3 * 4; // expensive computation +//! info!("the answer was: {}", x); +//! } +//! } +//! ``` +//! +//! Assumes the binary is `main`: +//! +//! ```{.bash} +//! $ RUST_LOG=error ./main +//! ERROR:main: this is printed by default +//! ``` +//! +//! ```{.bash} +//! $ RUST_LOG=info ./main +//! ERROR:main: this is printed by default +//! INFO:main: the answer was: 12 +//! ``` +//! +//! ```{.bash} +//! $ RUST_LOG=debug ./main +//! DEBUG:main: this is a debug message +//! ERROR:main: this is printed by default +//! INFO:main: the answer was: 12 +//! ``` +//! +//! You can also set the log level on a per module basis: +//! +//! ```{.bash} +//! $ RUST_LOG=main=info ./main +//! ERROR:main: this is printed by default +//! INFO:main: the answer was: 12 +//! ``` +//! +//! And enable all logging: +//! +//! ```{.bash} +//! $ RUST_LOG=main ./main +//! DEBUG:main: this is a debug message +//! ERROR:main: this is printed by default +//! INFO:main: the answer was: 12 +//! ``` +//! +//! See the documentation for the log crate for more information about its API. +//! +//! ## Enabling logging +//! +//! Log levels are controlled on a per-module basis, and by default all logging +//! is disabled except for `error!`. Logging is controlled via the `RUST_LOG` +//! environment variable. The value of this environment variable is a +//! comma-separated list of logging directives. A logging directive is of the +//! form: +//! +//! ```text +//! path::to::module=log_level +//! ``` +//! +//! The path to the module is rooted in the name of the crate it was compiled +//! for, so if your program is contained in a file `hello.rs`, for example, to +//! turn on logging for this file you would use a value of `RUST_LOG=hello`. +//! Furthermore, this path is a prefix-search, so all modules nested in the +//! specified module will also have logging enabled. +//! +//! The actual `log_level` is optional to specify. If omitted, all logging will +//! be enabled. If specified, it must be one of the strings `debug`, `error`, +//! `info`, `warn`, or `trace`. +//! +//! As the log level for a module is optional, the module to enable logging for +//! is also optional. If only a `log_level` is provided, then the global log +//! level for all modules is set to this value. +//! +//! Some examples of valid values of `RUST_LOG` are: +//! +//! * `hello` turns on all logging for the 'hello' module +//! * `info` turns on all info logging +//! * `hello=debug` turns on debug logging for 'hello' +//! * `hello,std::option` turns on hello, and std's option logging +//! * `error,hello=warn` turn on global error logging and also warn for hello +//! +//! ## Filtering results +//! +//! A RUST_LOG directive may include a regex filter. The syntax is to append `/` +//! followed by a regex. Each message is checked against the regex, and is only +//! logged if it matches. Note that the matching is done after formatting the +//! log string but before adding any logging meta-data. There is a single filter +//! for all modules. +//! +//! Some examples: +//! +//! * `hello/foo` turns on all logging for the 'hello' module where the log +//! message includes 'foo'. +//! * `info/f.o` turns on all info logging where the log message includes 'foo', +//! 'f1o', 'fao', etc. +//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log +//! message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc. +//! * `error,hello=warn/[0-9] scopes` turn on global error logging and also +//! warn for hello. In both cases the log message must include a single digit +//! number followed by 'scopes'. + +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/env_logger/")] +#![cfg_attr(test, deny(warnings))] + +extern crate log; + +use std::env; +use std::io::prelude::*; +use std::io; +use std::mem; + +use log::{Log, LogLevel, LogLevelFilter, LogRecord, SetLoggerError, LogMetadata}; + +#[cfg(feature = "regex")] +#[path = "regex.rs"] +mod filter; + +#[cfg(not(feature = "regex"))] +#[path = "string.rs"] +mod filter; + +/// The logger. +pub struct Logger { + directives: Vec, + filter: Option, + format: Box String + Sync + Send>, +} + +/// LogBuilder acts as builder for initializing the Logger. +/// It can be used to customize the log format, change the enviromental variable used +/// to provide the logging directives and also set the default log level filter. +/// +/// ## Example +/// +/// ``` +/// #[macro_use] +/// extern crate log; +/// extern crate env_logger; +/// +/// use std::env; +/// use log::{LogRecord, LogLevelFilter}; +/// use env_logger::LogBuilder; +/// +/// fn main() { +/// let format = |record: &LogRecord| { +/// format!("{} - {}", record.level(), record.args()) +/// }; +/// +/// let mut builder = LogBuilder::new(); +/// builder.format(format).filter(None, LogLevelFilter::Info); +/// +/// if env::var("RUST_LOG").is_ok() { +/// builder.parse(&env::var("RUST_LOG").unwrap()); +/// } +/// +/// builder.init().unwrap(); +/// +/// error!("error message"); +/// info!("info message"); +/// } +/// ``` +pub struct LogBuilder { + directives: Vec, + filter: Option, + format: Box String + Sync + Send>, +} + +impl LogBuilder { + /// Initializes the log builder with defaults + pub fn new() -> LogBuilder { + LogBuilder { + directives: Vec::new(), + filter: None, + format: Box::new(|record: &LogRecord| { + format!("{}:{}: {}", record.level(), + record.location().module_path(), record.args()) + }), + } + } + + /// Adds filters to the logger + /// + /// The given module (if any) will log at most the specified level provided. + /// If no module is provided then the filter will apply to all log messages. + pub fn filter(&mut self, + module: Option<&str>, + level: LogLevelFilter) -> &mut Self { + self.directives.push(LogDirective { + name: module.map(|s| s.to_string()), + level: level, + }); + self + } + + /// Sets the format function for formatting the log output. + /// + /// This function is called on each record logged to produce a string which + /// is actually printed out. + pub fn format(&mut self, format: F) -> &mut Self + where F: Fn(&LogRecord) -> String + Sync + Send + { + self.format = Box::new(format); + self + } + + /// Parses the directives string in the same form as the RUST_LOG + /// environment variable. + /// + /// See the module documentation for more details. + pub fn parse(&mut self, filters: &str) -> &mut Self { + let (directives, filter) = parse_logging_spec(filters); + + self.filter = filter; + + for directive in directives { + self.directives.push(directive); + } + self + } + + /// Initializes the global logger with an env logger. + /// + /// This should be called early in the execution of a Rust program, and the + /// global logger may only be initialized once. Future initialization + /// attempts will return an error. + pub fn init(&mut self) -> Result<(), SetLoggerError> { + log::set_logger(|max_level| { + let logger = self.build(); + max_level.set(logger.filter()); + Box::new(logger) + }) + } + + /// Build an env logger. + pub fn build(&mut self) -> Logger { + if self.directives.is_empty() { + // Adds the default filter if none exist + self.directives.push(LogDirective { + name: None, + level: LogLevelFilter::Error, + }); + } else { + // Sort the directives by length of their name, this allows a + // little more efficient lookup at runtime. + self.directives.sort_by(|a, b| { + let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0); + let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0); + alen.cmp(&blen) + }); + } + + Logger { + directives: mem::replace(&mut self.directives, Vec::new()), + filter: mem::replace(&mut self.filter, None), + format: mem::replace(&mut self.format, Box::new(|_| String::new())), + } + } +} + +impl Logger { + pub fn new() -> Logger { + let mut builder = LogBuilder::new(); + + if let Ok(s) = env::var("RUST_LOG") { + builder.parse(&s); + } + + builder.build() + } + + pub fn filter(&self) -> LogLevelFilter { + self.directives.iter() + .map(|d| d.level).max() + .unwrap_or(LogLevelFilter::Off) + } + + fn enabled(&self, level: LogLevel, target: &str) -> bool { + // Search for the longest match, the vector is assumed to be pre-sorted. + for directive in self.directives.iter().rev() { + match directive.name { + Some(ref name) if !target.starts_with(&**name) => {}, + Some(..) | None => { + return level <= directive.level + } + } + } + false + } +} + +impl Log for Logger { + fn enabled(&self, metadata: &LogMetadata) -> bool { + self.enabled(metadata.level(), metadata.target()) + } + + fn log(&self, record: &LogRecord) { + if !Log::enabled(self, record.metadata()) { + return; + } + + if let Some(filter) = self.filter.as_ref() { + if !filter.is_match(&*record.args().to_string()) { + return; + } + } + + let _ = writeln!(&mut io::stderr(), "{}", (self.format)(record)); + } +} + +struct LogDirective { + name: Option, + level: LogLevelFilter, +} + +/// Initializes the global logger with an env logger. +/// +/// This should be called early in the execution of a Rust program, and the +/// global logger may only be initialized once. Future initialization attempts +/// will return an error. +pub fn init() -> Result<(), SetLoggerError> { + let mut builder = LogBuilder::new(); + + if let Ok(s) = env::var("RUST_LOG") { + builder.parse(&s); + } + + builder.init() +} + +/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=error/foo") +/// and return a vector with log directives. +fn parse_logging_spec(spec: &str) -> (Vec, Option) { + let mut dirs = Vec::new(); + + let mut parts = spec.split('/'); + let mods = parts.next(); + let filter = parts.next(); + if parts.next().is_some() { + println!("warning: invalid logging spec '{}', \ + ignoring it (too many '/'s)", spec); + return (dirs, None); + } + mods.map(|m| { for s in m.split(',') { + if s.len() == 0 { continue } + let mut parts = s.split('='); + let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { + (Some(part0), None, None) => { + // if the single argument is a log-level string or number, + // treat that as a global fallback + match part0.parse() { + Ok(num) => (num, None), + Err(_) => (LogLevelFilter::max(), Some(part0)), + } + } + (Some(part0), Some(""), None) => (LogLevelFilter::max(), Some(part0)), + (Some(part0), Some(part1), None) => { + match part1.parse() { + Ok(num) => (num, Some(part0)), + _ => { + println!("warning: invalid logging spec '{}', \ + ignoring it", part1); + continue + } + } + }, + _ => { + println!("warning: invalid logging spec '{}', \ + ignoring it", s); + continue + } + }; + dirs.push(LogDirective { + name: name.map(|s| s.to_string()), + level: log_level, + }); + }}); + + let filter = filter.map_or(None, |filter| { + match filter::Filter::new(filter) { + Ok(re) => Some(re), + Err(e) => { + println!("warning: invalid regex filter - {}", e); + None + } + } + }); + + return (dirs, filter); +} + +#[cfg(test)] +mod tests { + use log::{LogLevel, LogLevelFilter}; + + use super::{LogBuilder, Logger, LogDirective, parse_logging_spec}; + + fn make_logger(dirs: Vec) -> Logger { + let mut logger = LogBuilder::new().build(); + logger.directives = dirs; + logger + } + + #[test] + fn filter_info() { + let logger = LogBuilder::new().filter(None, LogLevelFilter::Info).build(); + assert!(logger.enabled(LogLevel::Info, "crate1")); + assert!(!logger.enabled(LogLevel::Debug, "crate1")); + } + + #[test] + fn filter_beginning_longest_match() { + let logger = LogBuilder::new() + .filter(Some("crate2"), LogLevelFilter::Info) + .filter(Some("crate2::mod"), LogLevelFilter::Debug) + .filter(Some("crate1::mod1"), LogLevelFilter::Warn) + .build(); + assert!(logger.enabled(LogLevel::Debug, "crate2::mod1")); + assert!(!logger.enabled(LogLevel::Debug, "crate2")); + } + + #[test] + fn parse_default() { + let logger = LogBuilder::new().parse("info,crate1::mod1=warn").build(); + assert!(logger.enabled(LogLevel::Warn, "crate1::mod1")); + assert!(logger.enabled(LogLevel::Info, "crate2::mod2")); + } + + #[test] + fn match_full_path() { + let logger = make_logger(vec![ + LogDirective { + name: Some("crate2".to_string()), + level: LogLevelFilter::Info + }, + LogDirective { + name: Some("crate1::mod1".to_string()), + level: LogLevelFilter::Warn + } + ]); + assert!(logger.enabled(LogLevel::Warn, "crate1::mod1")); + assert!(!logger.enabled(LogLevel::Info, "crate1::mod1")); + assert!(logger.enabled(LogLevel::Info, "crate2")); + assert!(!logger.enabled(LogLevel::Debug, "crate2")); + } + + #[test] + fn no_match() { + let logger = make_logger(vec![ + LogDirective { name: Some("crate2".to_string()), level: LogLevelFilter::Info }, + LogDirective { name: Some("crate1::mod1".to_string()), level: LogLevelFilter::Warn } + ]); + assert!(!logger.enabled(LogLevel::Warn, "crate3")); + } + + #[test] + fn match_beginning() { + let logger = make_logger(vec![ + LogDirective { name: Some("crate2".to_string()), level: LogLevelFilter::Info }, + LogDirective { name: Some("crate1::mod1".to_string()), level: LogLevelFilter::Warn } + ]); + assert!(logger.enabled(LogLevel::Info, "crate2::mod1")); + } + + #[test] + fn match_beginning_longest_match() { + let logger = make_logger(vec![ + LogDirective { name: Some("crate2".to_string()), level: LogLevelFilter::Info }, + LogDirective { name: Some("crate2::mod".to_string()), level: LogLevelFilter::Debug }, + LogDirective { name: Some("crate1::mod1".to_string()), level: LogLevelFilter::Warn } + ]); + assert!(logger.enabled(LogLevel::Debug, "crate2::mod1")); + assert!(!logger.enabled(LogLevel::Debug, "crate2")); + } + + #[test] + fn match_default() { + let logger = make_logger(vec![ + LogDirective { name: None, level: LogLevelFilter::Info }, + LogDirective { name: Some("crate1::mod1".to_string()), level: LogLevelFilter::Warn } + ]); + assert!(logger.enabled(LogLevel::Warn, "crate1::mod1")); + assert!(logger.enabled(LogLevel::Info, "crate2::mod2")); + } + + #[test] + fn zero_level() { + let logger = make_logger(vec![ + LogDirective { name: None, level: LogLevelFilter::Info }, + LogDirective { name: Some("crate1::mod1".to_string()), level: LogLevelFilter::Off } + ]); + assert!(!logger.enabled(LogLevel::Error, "crate1::mod1")); + assert!(logger.enabled(LogLevel::Info, "crate2::mod2")); + } + + #[test] + fn parse_logging_spec_valid() { + let (dirs, filter) = parse_logging_spec("crate1::mod1=error,crate1::mod2,crate2=debug"); + assert_eq!(dirs.len(), 3); + assert_eq!(dirs[0].name, Some("crate1::mod1".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Error); + + assert_eq!(dirs[1].name, Some("crate1::mod2".to_string())); + assert_eq!(dirs[1].level, LogLevelFilter::max()); + + assert_eq!(dirs[2].name, Some("crate2".to_string())); + assert_eq!(dirs[2].level, LogLevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_invalid_crate() { + // test parse_logging_spec with multiple = in specification + let (dirs, filter) = parse_logging_spec("crate1::mod1=warn=info,crate2=debug"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_invalid_log_level() { + // test parse_logging_spec with 'noNumber' as log level + let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=debug"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_string_log_level() { + // test parse_logging_spec with 'warn' as log level + let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Warn); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_empty_log_level() { + // test parse_logging_spec with '' as log level + let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2="); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::max()); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_global() { + // test parse_logging_spec with no crate + let (dirs, filter) = parse_logging_spec("warn,crate2=debug"); + assert_eq!(dirs.len(), 2); + assert_eq!(dirs[0].name, None); + assert_eq!(dirs[0].level, LogLevelFilter::Warn); + assert_eq!(dirs[1].name, Some("crate2".to_string())); + assert_eq!(dirs[1].level, LogLevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_valid_filter() { + let (dirs, filter) = parse_logging_spec("crate1::mod1=error,crate1::mod2,crate2=debug/abc"); + assert_eq!(dirs.len(), 3); + assert_eq!(dirs[0].name, Some("crate1::mod1".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Error); + + assert_eq!(dirs[1].name, Some("crate1::mod2".to_string())); + assert_eq!(dirs[1].level, LogLevelFilter::max()); + + assert_eq!(dirs[2].name, Some("crate2".to_string())); + assert_eq!(dirs[2].level, LogLevelFilter::Debug); + assert!(filter.is_some() && filter.unwrap().to_string() == "abc"); + } + + #[test] + fn parse_logging_spec_invalid_crate_filter() { + let (dirs, filter) = parse_logging_spec("crate1::mod1=error=warn,crate2=debug/a.c"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Debug); + assert!(filter.is_some() && filter.unwrap().to_string() == "a.c"); + } + + #[test] + fn parse_logging_spec_empty_with_filter() { + let (dirs, filter) = parse_logging_spec("crate1/a*c"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate1".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::max()); + assert!(filter.is_some() && filter.unwrap().to_string() == "a*c"); + } +} diff --git a/src/vendor/env_logger/src/regex.rs b/src/vendor/env_logger/src/regex.rs new file mode 100644 index 000000000000..0df03e673304 --- /dev/null +++ b/src/vendor/env_logger/src/regex.rs @@ -0,0 +1,28 @@ +extern crate regex; + +use std::fmt; + +use self::regex::Regex; + +pub struct Filter { + inner: Regex, +} + +impl Filter { + pub fn new(spec: &str) -> Result { + match Regex::new(spec){ + Ok(r) => Ok(Filter { inner: r }), + Err(e) => Err(e.to_string()), + } + } + + pub fn is_match(&self, s: &str) -> bool { + self.inner.is_match(s) + } +} + +impl fmt::Display for Filter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} diff --git a/src/vendor/env_logger/src/string.rs b/src/vendor/env_logger/src/string.rs new file mode 100644 index 000000000000..74d0e04dbd6e --- /dev/null +++ b/src/vendor/env_logger/src/string.rs @@ -0,0 +1,21 @@ +use std::fmt; + +pub struct Filter { + inner: String, +} + +impl Filter { + pub fn new(spec: &str) -> Result { + Ok(Filter { inner: spec.to_string() }) + } + + pub fn is_match(&self, s: &str) -> bool { + s.contains(&self.inner) + } +} + +impl fmt::Display for Filter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} diff --git a/src/vendor/env_logger/tests/regexp_filter.rs b/src/vendor/env_logger/tests/regexp_filter.rs new file mode 100644 index 000000000000..5036fb8e3c9c --- /dev/null +++ b/src/vendor/env_logger/tests/regexp_filter.rs @@ -0,0 +1,51 @@ +#[macro_use] extern crate log; +extern crate env_logger; + +use std::process; +use std::env; +use std::str; + +fn main() { + if env::var("LOG_REGEXP_TEST").ok() == Some(String::from("1")) { + child_main(); + } else { + parent_main() + } +} + +fn child_main() { + env_logger::init().unwrap(); + info!("XYZ Message"); +} + +fn run_child(rust_log: String) -> bool { + let exe = env::current_exe().unwrap(); + let out = process::Command::new(exe) + .env("LOG_REGEXP_TEST", "1") + .env("RUST_LOG", rust_log) + .output() + .unwrap_or_else(|e| panic!("Unable to start child process: {}", e)); + str::from_utf8(out.stderr.as_ref()).unwrap().contains("XYZ Message") +} + +fn assert_message_printed(rust_log: &str) { + if !run_child(rust_log.to_string()) { + panic!("RUST_LOG={} should allow the test log message", rust_log) + } +} + +fn assert_message_not_printed(rust_log: &str) { + if run_child(rust_log.to_string()) { + panic!("RUST_LOG={} should not allow the test log message", rust_log) + } +} + +fn parent_main() { + // test normal log severity levels + assert_message_printed("info"); + assert_message_not_printed("warn"); + + // test of regular expression filters + assert_message_printed("info/XYZ"); + assert_message_not_printed("info/XXX"); +} diff --git a/src/vendor/filetime/.cargo-checksum.json b/src/vendor/filetime/.cargo-checksum.json new file mode 100644 index 000000000000..674ae31b296b --- /dev/null +++ b/src/vendor/filetime/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"c8cfe2c700e7b1d6500d0ad8084694be7009095e9572aaf54bf695c1fe7822d6","Cargo.toml":"4e414fe72ef2afcae81fb5a89f39e59ec40844272b589381746623f612333305","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"fef1998633eb2f460e6b12bc1133a21f5674e0b53ae5914ba1e53f1b63a185c3","appveyor.yml":"da991211b72fa6f231af7adb84c9fb72f5a9131d1c0a3d47b8ceffe5a82c8542","src/lib.rs":"8fa03e69ab113e5a30c742f60b6beddc0b77ef41a1eb45e82f9df867c9265815"},"package":"5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"} \ No newline at end of file diff --git a/src/vendor/filetime/.cargo-ok b/src/vendor/filetime/.cargo-ok new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/vendor/filetime/.gitignore b/src/vendor/filetime/.gitignore new file mode 100644 index 000000000000..a9d37c560c6a --- /dev/null +++ b/src/vendor/filetime/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/src/vendor/filetime/.travis.yml b/src/vendor/filetime/.travis.yml new file mode 100644 index 000000000000..001cdd259ecf --- /dev/null +++ b/src/vendor/filetime/.travis.yml @@ -0,0 +1,26 @@ +language: rust +rust: + - stable + - beta + - nightly +sudo: false +script: + - cargo build --verbose + - cargo test --verbose + - cargo doc --no-deps +after_success: | + [ $TRAVIS_BRANCH = master ] && + [ $TRAVIS_PULL_REQUEST = false ] && + echo '' > target/doc/index.html && + pip install ghp-import --user $USER && + $HOME/.local/bin/ghp-import -n target/doc && + git push -qf https://${TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages +notifications: + email: + on_success: never +env: + global: + secure: dsIj09BQvGF872zKmqzG+WwCl7gfqwsnxcm3GZlAMgyLYm4juvHOwCRhIERCN3BCxPvdlSRKhe9Rwmp1RkiKuqTK3ITUTAy29Maf2vuL1T+zcdpZE0t6JSCU1gbEwzCA2foB1jzgy7Q47EzeJusmGNwibscjYmXKlH6JCFwTobM= +os: + - linux + - osx diff --git a/src/vendor/filetime/Cargo.toml b/src/vendor/filetime/Cargo.toml new file mode 100644 index 000000000000..971eaf601469 --- /dev/null +++ b/src/vendor/filetime/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "filetime" +authors = ["Alex Crichton "] +version = "0.1.10" +license = "MIT/Apache-2.0" +readme = "README.md" +keywords = ["timestamp", "mtime"] +repository = "https://github.com/alexcrichton/filetime" +homepage = "https://github.com/alexcrichton/filetime" +documentation = "http://alexcrichton.com/filetime" +description = """ +Platform-agnostic accessors of timestamps in File metadata +""" + +[dependencies] +libc = "0.2" + +[dev-dependencies] +tempdir = "0.3" diff --git a/src/vendor/filetime/LICENSE-APACHE b/src/vendor/filetime/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/src/vendor/filetime/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/vendor/filetime/LICENSE-MIT b/src/vendor/filetime/LICENSE-MIT new file mode 100644 index 000000000000..39e0ed660215 --- /dev/null +++ b/src/vendor/filetime/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/vendor/filetime/README.md b/src/vendor/filetime/README.md new file mode 100644 index 000000000000..0422084e7e20 --- /dev/null +++ b/src/vendor/filetime/README.md @@ -0,0 +1,25 @@ +# filetime + +[![Build Status](https://travis-ci.org/alexcrichton/filetime.svg?branch=master)](https://travis-ci.org/alexcrichton/filetime) +[![Build status](https://ci.appveyor.com/api/projects/status/9tatexq47i3ee13k?svg=true)](https://ci.appveyor.com/project/alexcrichton/filetime) + +[Documentation](http://alexcrichton.com/filetime/filetime/index.html) + +A helper library for inspecting the various timestamps of files in Rust. This +library takes into account cross-platform differences in terms of where the +timestamps are located, what they are called, and how to convert them into a +platform-independent representation. + +```toml +# Cargo.toml +[dependencies] +filetime = "0.1" +``` + +# License + +`filetime` is primarily distributed under the terms of both the MIT license and +the Apache License (Version 2.0), with portions covered by various BSD-like +licenses. + +See LICENSE-APACHE, and LICENSE-MIT for details. diff --git a/src/vendor/filetime/appveyor.yml b/src/vendor/filetime/appveyor.yml new file mode 100644 index 000000000000..6a1b8dc19c03 --- /dev/null +++ b/src/vendor/filetime/appveyor.yml @@ -0,0 +1,17 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose diff --git a/src/vendor/filetime/src/lib.rs b/src/vendor/filetime/src/lib.rs new file mode 100644 index 000000000000..aa6bec1dfefe --- /dev/null +++ b/src/vendor/filetime/src/lib.rs @@ -0,0 +1,305 @@ +//! Timestamps for files in Rust +//! +//! This library provides platform-agnostic inspection of the various timestamps +//! present in the standard `fs::Metadata` structure. +//! +//! # Installation +//! +//! Add this to you `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! filetime = "0.1" +//! ``` +//! +//! # Usage +//! +//! ```no_run +//! use std::fs; +//! use filetime::FileTime; +//! +//! let metadata = fs::metadata("foo.txt").unwrap(); +//! +//! let mtime = FileTime::from_last_modification_time(&metadata); +//! println!("{}", mtime); +//! +//! let atime = FileTime::from_last_access_time(&metadata); +//! assert!(mtime < atime); +//! +//! // Inspect values that can be interpreted across platforms +//! println!("{}", mtime.seconds_relative_to_1970()); +//! println!("{}", mtime.nanoseconds()); +//! +//! // Print the platform-specific value of seconds +//! println!("{}", mtime.seconds()); +//! ``` + +extern crate libc; + +#[cfg(unix)] use std::os::unix::prelude::*; +#[cfg(windows)] use std::os::windows::prelude::*; + +use std::fmt; +use std::fs; +use std::io; +use std::path::Path; + +/// A helper structure to represent a timestamp for a file. +/// +/// The actual value contined within is platform-specific and does not have the +/// same meaning across platforms, but comparisons and stringification can be +/// significant among the same platform. +#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone, Hash)] +pub struct FileTime { + seconds: u64, + nanos: u32, +} + +impl FileTime { + /// Creates a new timestamp representing a 0 time. + /// + /// Useful for creating the base of a cmp::max chain of times. + pub fn zero() -> FileTime { + FileTime { seconds: 0, nanos: 0 } + } + + /// Creates a new instance of `FileTime` with a number of seconds and + /// nanoseconds relative to January 1, 1970. + /// + /// Note that this is typically the relative point that Unix time stamps are + /// from, but on Windows the native time stamp is relative to January 1, + /// 1601 so the return value of `seconds` from the returned `FileTime` + /// instance may not be the same as that passed in. + pub fn from_seconds_since_1970(seconds: u64, nanos: u32) -> FileTime { + FileTime { + seconds: seconds + if cfg!(windows) {11644473600} else {0}, + nanos: nanos, + } + } + + /// Creates a new timestamp from the last modification time listed in the + /// specified metadata. + /// + /// The returned value corresponds to the `mtime` field of `stat` on Unix + /// platforms and the `ftLastWriteTime` field on Windows platforms. + pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { + #[cfg(unix)] + fn imp(meta: &fs::Metadata) -> FileTime { + FileTime::from_os_repr(meta.mtime() as u64, meta.mtime_nsec() as u32) + } + #[cfg(windows)] + fn imp(meta: &fs::Metadata) -> FileTime { + FileTime::from_os_repr(meta.last_write_time()) + } + imp(meta) + } + + /// Creates a new timestamp from the last access time listed in the + /// specified metadata. + /// + /// The returned value corresponds to the `atime` field of `stat` on Unix + /// platforms and the `ftLastAccessTime` field on Windows platforms. + pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { + #[cfg(unix)] + fn imp(meta: &fs::Metadata) -> FileTime { + FileTime::from_os_repr(meta.atime() as u64, meta.atime_nsec() as u32) + } + #[cfg(windows)] + fn imp(meta: &fs::Metadata) -> FileTime { + FileTime::from_os_repr(meta.last_access_time()) + } + imp(meta) + } + + /// Creates a new timestamp from the creation time listed in the specified + /// metadata. + /// + /// The returned value corresponds to the `birthtime` field of `stat` on + /// Unix platforms and the `ftCreationTime` field on Windows platforms. Note + /// that not all Unix platforms have this field available and may return + /// `None` in some circumstances. + pub fn from_creation_time(meta: &fs::Metadata) -> Option { + macro_rules! birthtim { + ($(($e:expr, $i:ident)),*) => { + #[cfg(any($(target_os = $e),*))] + fn imp(meta: &fs::Metadata) -> Option { + $( + #[cfg(target_os = $e)] + use std::os::$i::fs::MetadataExt; + )* + let raw = meta.as_raw_stat(); + Some(FileTime::from_os_repr(raw.st_birthtime as u64, + raw.st_birthtime_nsec as u32)) + } + + #[cfg(all(not(windows), + $(not(target_os = $e)),*))] + fn imp(_meta: &fs::Metadata) -> Option { + None + } + } + } + + birthtim! { + ("bitrig", bitrig), + ("freebsd", freebsd), + ("ios", ios), + ("macos", macos), + ("openbsd", openbsd) + } + + #[cfg(windows)] + fn imp(meta: &fs::Metadata) -> Option { + Some(FileTime::from_os_repr(meta.last_access_time())) + } + imp(meta) + } + + #[cfg(windows)] + fn from_os_repr(time: u64) -> FileTime { + // Windows write times are in 100ns intervals, so do a little math to + // get it into the right representation. + FileTime { + seconds: time / (1_000_000_000 / 100), + nanos: ((time % (1_000_000_000 / 100)) * 100) as u32, + } + } + + #[cfg(unix)] + fn from_os_repr(seconds: u64, nanos: u32) -> FileTime { + FileTime { seconds: seconds, nanos: nanos } + } + + /// Returns the whole number of seconds represented by this timestamp. + /// + /// Note that this value's meaning is **platform specific**. On Unix + /// platform time stamps are typically relative to January 1, 1970, but on + /// Windows platforms time stamps are relative to January 1, 1601. + pub fn seconds(&self) -> u64 { self.seconds } + + /// Returns the whole number of seconds represented by this timestamp, + /// relative to the Unix epoch start of January 1, 1970. + /// + /// Note that this does not return the same value as `seconds` for Windows + /// platforms as seconds are relative to a different date there. + pub fn seconds_relative_to_1970(&self) -> u64 { + self.seconds - if cfg!(windows) {11644473600} else {0} + } + + /// Returns the nanosecond precision of this timestamp. + /// + /// The returned value is always less than one billion and represents a + /// portion of a second forward from the seconds returned by the `seconds` + /// method. + pub fn nanoseconds(&self) -> u32 { self.nanos } +} + +impl fmt::Display for FileTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}.{:09}s", self.seconds, self.nanos) + } +} + +/// Set the last access and modification times for a file on the filesystem. +/// +/// This function will set the `atime` and `mtime` metadata fields for a file +/// on the local filesystem, returning any error encountered. +pub fn set_file_times

(p: P, atime: FileTime, mtime: FileTime) + -> io::Result<()> where P: AsRef { + set_file_times_(p.as_ref(), atime, mtime) +} + +#[cfg(unix)] +fn set_file_times_(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + use std::ffi::CString; + use libc::{timeval, time_t, suseconds_t, utimes}; + + let times = [to_timeval(&atime), to_timeval(&mtime)]; + let p = try!(CString::new(p.as_os_str().as_bytes())); + return unsafe { + if utimes(p.as_ptr() as *const _, times.as_ptr()) == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + }; + + fn to_timeval(ft: &FileTime) -> timeval { + timeval { + tv_sec: ft.seconds() as time_t, + tv_usec: (ft.nanoseconds() / 1000) as suseconds_t, + } + } +} + +#[cfg(windows)] +#[allow(bad_style)] +fn set_file_times_(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + use std::fs::OpenOptions; + + type BOOL = i32; + type HANDLE = *mut u8; + type DWORD = u32; + #[repr(C)] + struct FILETIME { + dwLowDateTime: u32, + dwHighDateTime: u32, + } + extern "system" { + fn SetFileTime(hFile: HANDLE, + lpCreationTime: *const FILETIME, + lpLastAccessTime: *const FILETIME, + lpLastWriteTime: *const FILETIME) -> BOOL; + } + + let f = try!(OpenOptions::new().write(true).open(p)); + let atime = to_filetime(&atime); + let mtime = to_filetime(&mtime); + return unsafe { + let ret = SetFileTime(f.as_raw_handle() as *mut _, + 0 as *const _, + &atime, &mtime); + if ret != 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + }; + + fn to_filetime(ft: &FileTime) -> FILETIME { + let intervals = ft.seconds() * (1_000_000_000 / 100) + + ((ft.nanoseconds() as u64) / 100); + FILETIME { + dwLowDateTime: intervals as DWORD, + dwHighDateTime: (intervals >> 32) as DWORD, + } + } +} + +#[cfg(test)] +mod tests { + extern crate tempdir; + + use std::fs::{self, File}; + use self::tempdir::TempDir; + use super::{FileTime, set_file_times}; + + #[test] + fn set_file_times_test() { + let td = TempDir::new("filetime").unwrap(); + let path = td.path().join("foo.txt"); + File::create(&path).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + let atime = FileTime::from_last_access_time(&metadata); + set_file_times(&path, atime, mtime).unwrap(); + + let new_mtime = FileTime::from_seconds_since_1970(10_000, 0); + set_file_times(&path, atime, new_mtime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + } +} diff --git a/src/vendor/gcc/.cargo-checksum.json b/src/vendor/gcc/.cargo-checksum.json new file mode 100644 index 000000000000..efe1ebb7d44c --- /dev/null +++ b/src/vendor/gcc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"f9b1ca6ae27d1c18215265024629a8960c31379f206d9ed20f64e0b2dcf79805",".travis.yml":"5cee7774cf6d876246a0ae0f8362cceeecec5924b751049c945faac9342565ff","Cargo.toml":"2634dedd87889b33a794e31b41a8d8d4713ef40382be3d464229707679bd83da","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"ecb2d93f4c81edbd48d8742ff7887dc0a4530a5890967839090bbc972d49bebe","appveyor.yml":"46c77d913eaa45871296942c2cd96ef092c9dcaf19201cb5c500a5107faeb06f","src/bin/gcc-shim.rs":"11edfe1fc6f932bd42ffffda5145833302bc163e0b87dc0d54f4bd0997ad4708","src/lib.rs":"5eb0e311367226ed0420f5e2dac10cc35fc0a3be639a612b6e8ea6d24f646634","src/registry.rs":"3e2a42581ebb82e325dd5600c6571cef937b35003b2927dc618967f5238a2058","src/windows_registry.rs":"906653c020ffe9d572e435f3fc3a8892d9e0a13240ba297db01ce0a288e08cdb","tests/cc_env.rs":"d92c5e3d3d43ac244e63b2cd2c93a521fcf124bf1ccf8d4c6bfa7f8333d88976","tests/support/mod.rs":"d11ed0db4dda5ecf5fb970c9b0c56428cd47421a2742f07032e2cc6b0a0f07e2","tests/test.rs":"164220f11be2eebc20315826513999970660a82feff8cc4b15b4e9d73d98324e"},"package":"553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"} \ No newline at end of file diff --git a/src/vendor/gcc/.cargo-ok b/src/vendor/gcc/.cargo-ok new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/vendor/gcc/.gitignore b/src/vendor/gcc/.gitignore new file mode 100644 index 000000000000..a9d37c560c6a --- /dev/null +++ b/src/vendor/gcc/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/src/vendor/gcc/.travis.yml b/src/vendor/gcc/.travis.yml new file mode 100644 index 000000000000..6b508b9d8bc9 --- /dev/null +++ b/src/vendor/gcc/.travis.yml @@ -0,0 +1,40 @@ +language: rust +rust: + - stable + - beta + - nightly +sudo: false +install: + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then OS=unknown-linux-gnu; else OS=apple-darwin; fi + - export TARGET=$ARCH-$OS + - curl https://static.rust-lang.org/rustup.sh | + sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot` +before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH +script: + - cargo build --verbose + - cargo test --verbose + - cargo test --verbose --features parallel + - cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET + - cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET --features parallel + - cargo test --manifest-path gcc-test/Cargo.toml --target $TARGET --release + - cargo doc + - rustdoc --test README.md -L target/debug -L target/debug/deps +after_success: + - travis-cargo --only nightly doc-upload +env: + global: + secure: ilbcq9zX+UaiBcwqkBGldeanbEQus9npLsi0/nF1PUxKbQsoWSVtVOehAD8Hy92D3hX2npIRyNL8GxBn85XEcBYc1h7DiWUhLcXfZie79v8Ly/qboHCfZLXlB1ofbypbyQfouEdOE9zHf0ZILYVpAgUkliv6KuVShsrKNlbn4QE= + matrix: + - ARCH=x86_64 + - ARCH=i686 +notifications: + email: + on_success: never +os: + - linux + - osx +addons: + apt: + packages: + - g++-multilib diff --git a/src/vendor/gcc/Cargo.toml b/src/vendor/gcc/Cargo.toml new file mode 100644 index 000000000000..fd51ce0e9f45 --- /dev/null +++ b/src/vendor/gcc/Cargo.toml @@ -0,0 +1,23 @@ +[package] + +name = "gcc" +version = "0.3.38" +authors = ["Alex Crichton "] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/gcc-rs" +documentation = "http://alexcrichton.com/gcc-rs" +description = """ +A build-time dependency for Cargo build scripts to assist in invoking the native +C compiler to compile native C code into a static archive to be linked into Rust +code. +""" +keywords = ["build-dependencies"] + +[dependencies] +rayon = { version = "0.4", optional = true } + +[features] +parallel = ["rayon"] + +[dev-dependencies] +tempdir = "0.3" diff --git a/src/vendor/gcc/LICENSE-APACHE b/src/vendor/gcc/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/src/vendor/gcc/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/vendor/gcc/LICENSE-MIT b/src/vendor/gcc/LICENSE-MIT new file mode 100644 index 000000000000..39e0ed660215 --- /dev/null +++ b/src/vendor/gcc/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/vendor/gcc/README.md b/src/vendor/gcc/README.md new file mode 100644 index 000000000000..ecc79c673526 --- /dev/null +++ b/src/vendor/gcc/README.md @@ -0,0 +1,161 @@ +# gcc-rs + +A library to compile C/C++ code into a Rust library/application. + +[![Build Status](https://travis-ci.org/alexcrichton/gcc-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/gcc-rs) +[![Build status](https://ci.appveyor.com/api/projects/status/onu270iw98h81nwv?svg=true)](https://ci.appveyor.com/project/alexcrichton/gcc-rs) + +[Documentation](http://alexcrichton.com/gcc-rs) + +A simple library meant to be used as a build dependency with Cargo packages in +order to build a set of C/C++ files into a static archive. Note that while this +crate is called "gcc", it actually calls out to the most relevant compile for +a platform, for example using `cl` on MSVC. That is, this crate does indeed work +on MSVC! + +## Using gcc-rs + +First, you'll want to both add a build script for your crate (`build.rs`) and +also add this crate to your `Cargo.toml` via: + +```toml +[package] +# ... +build = "build.rs" + +[build-dependencies] +gcc = "0.3" +``` + +Next up, you'll want to write a build script like so: + +```rust,no_run +// build.rs + +extern crate gcc; + +fn main() { + gcc::compile_library("libfoo.a", &["foo.c", "bar.c"]); +} +``` + +And that's it! Running `cargo build` should take care of the rest and your Rust +application will now have the C files `foo.c` and `bar.c` compiled into it. You +can call the functions in Rust by declaring functions in your Rust code like so: + +``` +extern { + fn foo_function(); + fn bar_function(); +} + +pub fn call() { + unsafe { + foo_function(); + bar_function(); + } +} + +fn main() { + // ... +} +``` + +## External configuration via environment variables + +To control the programs and flags used for building, the builder can set a +number of different environment variables. + +* `CFLAGS` - a series of space separated flags passed to "gcc". Note that + individual flags cannot currently contain spaces, so doing + something like: "-L=foo\ bar" is not possible. +* `CC` - the actual C compiler used. Note that this is used as an exact + executable name, so (for example) no extra flags can be passed inside + this variable, and the builder must ensure that there aren't any + trailing spaces. This compiler must understand the `-c` flag. For + certain `TARGET`s, it also is assumed to know about other flags (most + common is `-fPIC`). +* `AR` - the `ar` (archiver) executable to use to build the static library. + +Each of these variables can also be supplied with certain prefixes and suffixes, +in the following prioritized order: + +1. `_` - for example, `CC_x86_64-unknown-linux-gnu` +2. `_` - for example, `CC_x86_64_unknown_linux_gnu` +3. `_` - for example, `HOST_CC` or `TARGET_CFLAGS` +4. `` - a plain `CC`, `AR` as above. + +If none of these variables exist, gcc-rs uses built-in defaults + +In addition to the the above optional environment variables, `gcc-rs` has some +functions with hard requirements on some variables supplied by [cargo's +build-script driver][cargo] that it has the `TARGET`, `OUT_DIR`, `OPT_LEVEL`, +and `HOST` variables. + +[cargo]: http://doc.crates.io/build-script.html#inputs-to-the-build-script + +## Optional features + +Currently gcc-rs supports parallel compilation (think `make -jN`) but this +feature is turned off by default. To enable gcc-rs to compile C/C++ in parallel, +you can change your dependency to: + +```toml +[build-dependencies] +gcc = { version = "0.3", features = ["parallel"] } +``` + +By default gcc-rs will limit parallelism to `$NUM_JOBS`, or if not present it +will limit it to the number of cpus on the machine. + +## Compile-time Requirements + +To work properly this crate needs access to a C compiler when the build script +is being run. This crate does not ship a C compiler with it. The compiler +required varies per platform, but there are three broad categories: + +* Unix platforms require `cc` to be the C compiler. This can be found by + installing gcc/clang on Linux distributions and Xcode on OSX, for example. +* Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`) + require `cl.exe` to be available and in `PATH`. This is typically found in + standard Visual Studio installations and the `PATH` can be set up by running + the appropriate developer tools shell. +* Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`) + require `gcc` to be available in `PATH`. We recommend the + [MinGW-w64](http://mingw-w64.org) distribution, which is using the + [Win-builds](http://win-builds.org) installation system. + You may also acquire it via + [MSYS2](http://msys2.github.io), as explained [here][msys2-help]. Make sure + to install the appropriate architecture corresponding to your installation of + rustc. GCC from older [MinGW](http://www.mingw.org) project is compatible + only with 32-bit rust compiler. + +[msys2-help]: http://github.com/rust-lang/rust#building-on-windows + +## C++ support + +`gcc-rs` supports C++ libraries compilation by using the `cpp` method on +`Config`: + +```rust,no_run +extern crate gcc; + +fn main() { + gcc::Config::new() + .cpp(true) // Switch to C++ library compilation. + .file("foo.cpp") + .compile("libfoo.a"); +} +``` + +When using C++ library compilation switch, the `CXX` and `CXXFLAGS` env +variables are used instead of `CC` and `CFLAGS` and the C++ standard library is +linked to the crate target. + +## License + +`gcc-rs` is primarily distributed under the terms of both the MIT license and +the Apache License (Version 2.0), with portions covered by various BSD-like +licenses. + +See LICENSE-APACHE, and LICENSE-MIT for details. diff --git a/src/vendor/gcc/appveyor.yml b/src/vendor/gcc/appveyor.yml new file mode 100644 index 000000000000..f6108c66514e --- /dev/null +++ b/src/vendor/gcc/appveyor.yml @@ -0,0 +1,35 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + ARCH: amd64 + VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat + - TARGET: x86_64-pc-windows-msvc + ARCH: amd64 + VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat + - TARGET: i686-pc-windows-msvc + ARCH: x86 + VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat + - TARGET: i686-pc-windows-msvc + ARCH: x86 + VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat + - TARGET: x86_64-pc-windows-gnu + MSYS_BITS: 64 + - TARGET: i686-pc-windows-gnu + MSYS_BITS: 32 +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - if defined VS call "%VS%" %ARCH% + - set PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - if defined MSYS_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS_BITS%\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --target %TARGET% + - cargo test --features parallel --target %TARGET% + - cargo test --manifest-path gcc-test/Cargo.toml --target %TARGET% + - cargo test --manifest-path gcc-test/Cargo.toml --features parallel --target %TARGET% + - cargo test --manifest-path gcc-test/Cargo.toml --release --target %TARGET% diff --git a/src/vendor/gcc/src/bin/gcc-shim.rs b/src/vendor/gcc/src/bin/gcc-shim.rs new file mode 100644 index 000000000000..43fd811d3615 --- /dev/null +++ b/src/vendor/gcc/src/bin/gcc-shim.rs @@ -0,0 +1,23 @@ +#![cfg_attr(test, allow(dead_code))] + +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; + +fn main() { + let out_dir = PathBuf::from(env::var_os("GCCTEST_OUT_DIR").unwrap()); + for i in 0.. { + let candidate = out_dir.join(format!("out{}", i)); + if candidate.exists() { + continue + } + let mut f = File::create(candidate).unwrap(); + for arg in env::args().skip(1) { + writeln!(f, "{}", arg).unwrap(); + } + + File::create(out_dir.join("libfoo.a")).unwrap(); + break + } +} diff --git a/src/vendor/gcc/src/lib.rs b/src/vendor/gcc/src/lib.rs new file mode 100644 index 000000000000..f319e9313ad7 --- /dev/null +++ b/src/vendor/gcc/src/lib.rs @@ -0,0 +1,959 @@ +//! A library for build scripts to compile custom C code +//! +//! This library is intended to be used as a `build-dependencies` entry in +//! `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! gcc = "0.3" +//! ``` +//! +//! The purpose of this crate is to provide the utility functions necessary to +//! compile C code into a static archive which is then linked into a Rust crate. +//! The top-level `compile_library` function serves as a convenience and more +//! advanced configuration is available through the `Config` builder. +//! +//! This crate will automatically detect situations such as cross compilation or +//! other environment variables set by Cargo and will build code appropriately. +//! +//! # Examples +//! +//! Use the default configuration: +//! +//! ```no_run +//! extern crate gcc; +//! +//! fn main() { +//! gcc::compile_library("libfoo.a", &["src/foo.c"]); +//! } +//! ``` +//! +//! Use more advanced configuration: +//! +//! ```no_run +//! extern crate gcc; +//! +//! fn main() { +//! gcc::Config::new() +//! .file("src/foo.c") +//! .define("FOO", Some("bar")) +//! .include("src") +//! .compile("libfoo.a"); +//! } +//! ``` + +#![doc(html_root_url = "http://alexcrichton.com/gcc-rs")] +#![cfg_attr(test, deny(warnings))] +#![deny(missing_docs)] + +#[cfg(feature = "parallel")] +extern crate rayon; + +use std::env; +use std::ffi::{OsString, OsStr}; +use std::fs; +use std::io; +use std::path::{PathBuf, Path}; +use std::process::{Command, Stdio}; +use std::io::{BufReader, BufRead, Write}; + +#[cfg(windows)] +mod registry; +pub mod windows_registry; + +/// Extra configuration to pass to gcc. +pub struct Config { + include_directories: Vec, + definitions: Vec<(String, Option)>, + objects: Vec, + flags: Vec, + files: Vec, + cpp: bool, + cpp_link_stdlib: Option>, + cpp_set_stdlib: Option, + target: Option, + host: Option, + out_dir: Option, + opt_level: Option, + debug: Option, + env: Vec<(OsString, OsString)>, + compiler: Option, + archiver: Option, + cargo_metadata: bool, + pic: Option, +} + +/// Configuration used to represent an invocation of a C compiler. +/// +/// This can be used to figure out what compiler is in use, what the arguments +/// to it are, and what the environment variables look like for the compiler. +/// This can be used to further configure other build systems (e.g. forward +/// along CC and/or CFLAGS) or the `to_command` method can be used to run the +/// compiler itself. +pub struct Tool { + path: PathBuf, + args: Vec, + env: Vec<(OsString, OsString)>, +} + +/// Compile a library from the given set of input C files. +/// +/// This will simply compile all files into object files and then assemble them +/// into the output. This will read the standard environment variables to detect +/// cross compilations and such. +/// +/// This function will also print all metadata on standard output for Cargo. +/// +/// # Example +/// +/// ```no_run +/// gcc::compile_library("libfoo.a", &["foo.c", "bar.c"]); +/// ``` +pub fn compile_library(output: &str, files: &[&str]) { + let mut c = Config::new(); + for f in files.iter() { + c.file(*f); + } + c.compile(output) +} + +impl Config { + /// Construct a new instance of a blank set of configuration. + /// + /// This builder is finished with the `compile` function. + pub fn new() -> Config { + Config { + include_directories: Vec::new(), + definitions: Vec::new(), + objects: Vec::new(), + flags: Vec::new(), + files: Vec::new(), + cpp: false, + cpp_link_stdlib: None, + cpp_set_stdlib: None, + target: None, + host: None, + out_dir: None, + opt_level: None, + debug: None, + env: Vec::new(), + compiler: None, + archiver: None, + cargo_metadata: true, + pic: None, + } + } + + /// Add a directory to the `-I` or include path for headers + pub fn include>(&mut self, dir: P) -> &mut Config { + self.include_directories.push(dir.as_ref().to_path_buf()); + self + } + + /// Specify a `-D` variable with an optional value. + pub fn define(&mut self, var: &str, val: Option<&str>) -> &mut Config { + self.definitions.push((var.to_string(), val.map(|s| s.to_string()))); + self + } + + /// Add an arbitrary object file to link in + pub fn object>(&mut self, obj: P) -> &mut Config { + self.objects.push(obj.as_ref().to_path_buf()); + self + } + + /// Add an arbitrary flag to the invocation of the compiler + pub fn flag(&mut self, flag: &str) -> &mut Config { + self.flags.push(flag.to_string()); + self + } + + /// Add a file which will be compiled + pub fn file>(&mut self, p: P) -> &mut Config { + self.files.push(p.as_ref().to_path_buf()); + self + } + + /// Set C++ support. + /// + /// The other `cpp_*` options will only become active if this is set to + /// `true`. + pub fn cpp(&mut self, cpp: bool) -> &mut Config { + self.cpp = cpp; + self + } + + /// Set the standard library to link against when compiling with C++ + /// support. + /// + /// The default value of this property depends on the current target: On + /// OS X `Some("c++")` is used, when compiling for a Visual Studio based + /// target `None` is used and for other targets `Some("stdc++")` is used. + /// + /// A value of `None` indicates that no automatic linking should happen, + /// otherwise cargo will link against the specified library. + /// + /// The given library name must not contain the `lib` prefix. + pub fn cpp_link_stdlib(&mut self, cpp_link_stdlib: Option<&str>) + -> &mut Config { + self.cpp_link_stdlib = Some(cpp_link_stdlib.map(|s| s.into())); + self + } + + /// Force the C++ compiler to use the specified standard library. + /// + /// Setting this option will automatically set `cpp_link_stdlib` to the same + /// value. + /// + /// The default value of this option is always `None`. + /// + /// This option has no effect when compiling for a Visual Studio based + /// target. + /// + /// This option sets the `-stdlib` flag, which is only supported by some + /// compilers (clang, icc) but not by others (gcc). The library will not + /// detect which compiler is used, as such it is the responsibility of the + /// caller to ensure that this option is only used in conjuction with a + /// compiler which supports the `-stdlib` flag. + /// + /// A value of `None` indicates that no specific C++ standard library should + /// be used, otherwise `-stdlib` is added to the compile invocation. + /// + /// The given library name must not contain the `lib` prefix. + pub fn cpp_set_stdlib(&mut self, cpp_set_stdlib: Option<&str>) + -> &mut Config { + self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into()); + self.cpp_link_stdlib(cpp_set_stdlib); + self + } + + /// Configures the target this configuration will be compiling for. + /// + /// This option is automatically scraped from the `TARGET` environment + /// variable by build scripts, so it's not required to call this function. + pub fn target(&mut self, target: &str) -> &mut Config { + self.target = Some(target.to_string()); + self + } + + /// Configures the host assumed by this configuration. + /// + /// This option is automatically scraped from the `HOST` environment + /// variable by build scripts, so it's not required to call this function. + pub fn host(&mut self, host: &str) -> &mut Config { + self.host = Some(host.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level(&mut self, opt_level: u32) -> &mut Config { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level_str(&mut self, opt_level: &str) -> &mut Config { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures whether the compiler will emit debug information when + /// generating object files. + /// + /// This option is automatically scraped from the `PROFILE` environment + /// variable by build scripts (only enabled when the profile is "debug"), so + /// it's not required to call this function. + pub fn debug(&mut self, debug: bool) -> &mut Config { + self.debug = Some(debug); + self + } + + /// Configures the output directory where all object files and static + /// libraries will be located. + /// + /// This option is automatically scraped from the `OUT_DIR` environment + /// variable by build scripts, so it's not required to call this function. + pub fn out_dir>(&mut self, out_dir: P) -> &mut Config { + self.out_dir = Some(out_dir.as_ref().to_owned()); + self + } + + /// Configures the compiler to be used to produce output. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn compiler>(&mut self, compiler: P) -> &mut Config { + self.compiler = Some(compiler.as_ref().to_owned()); + self + } + + /// Configures the tool used to assemble archives. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn archiver>(&mut self, archiver: P) -> &mut Config { + self.archiver = Some(archiver.as_ref().to_owned()); + self + } + /// Define whether metadata should be emitted for cargo allowing it to + /// automatically link the binary. Defaults to `true`. + pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Config { + self.cargo_metadata = cargo_metadata; + self + } + + /// Configures whether the compiler will emit position independent code. + /// + /// This option defaults to `false` for `i686` and `windows-gnu` targets and to `true` for all + /// other targets. + pub fn pic(&mut self, pic: bool) -> &mut Config { + self.pic = Some(pic); + self + } + + + #[doc(hidden)] + pub fn __set_env(&mut self, a: A, b: B) -> &mut Config + where A: AsRef, B: AsRef + { + self.env.push((a.as_ref().to_owned(), b.as_ref().to_owned())); + self + } + + /// Run the compiler, generating the file `output` + /// + /// The name `output` must begin with `lib` and end with `.a` + pub fn compile(&self, output: &str) { + assert!(output.starts_with("lib")); + assert!(output.ends_with(".a")); + let lib_name = &output[3..output.len() - 2]; + let dst = self.get_out_dir(); + + let mut objects = Vec::new(); + let mut src_dst = Vec::new(); + for file in self.files.iter() { + let obj = dst.join(file).with_extension("o"); + let obj = if !obj.starts_with(&dst) { + dst.join(obj.file_name().unwrap()) + } else { + obj + }; + fs::create_dir_all(&obj.parent().unwrap()).unwrap(); + src_dst.push((file.to_path_buf(), obj.clone())); + objects.push(obj); + } + self.compile_objects(&src_dst); + self.assemble(lib_name, &dst.join(output), &objects); + + self.print(&format!("cargo:rustc-link-lib=static={}", + &output[3..output.len() - 2])); + self.print(&format!("cargo:rustc-link-search=native={}", dst.display())); + + // Add specific C++ libraries, if enabled. + if self.cpp { + if let Some(stdlib) = self.get_cpp_link_stdlib() { + self.print(&format!("cargo:rustc-link-lib={}", stdlib)); + } + } + } + + #[cfg(feature = "parallel")] + fn compile_objects(&self, objs: &[(PathBuf, PathBuf)]) { + use self::rayon::prelude::*; + + let mut cfg = rayon::Configuration::new(); + if let Ok(amt) = env::var("NUM_JOBS") { + if let Ok(amt) = amt.parse() { + cfg = cfg.set_num_threads(amt); + } + } + drop(rayon::initialize(cfg)); + + objs.par_iter().weight_max().for_each(|&(ref src, ref dst)| { + self.compile_object(src, dst) + }) + } + + #[cfg(not(feature = "parallel"))] + fn compile_objects(&self, objs: &[(PathBuf, PathBuf)]) { + for &(ref src, ref dst) in objs { + self.compile_object(src, dst); + } + } + + fn compile_object(&self, file: &Path, dst: &Path) { + let is_asm = file.extension().and_then(|s| s.to_str()) == Some("asm"); + let msvc = self.get_target().contains("msvc"); + let (mut cmd, name) = if msvc && is_asm { + self.msvc_macro_assembler() + } else { + let compiler = self.get_compiler(); + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + (cmd, compiler.path.file_name().unwrap() + .to_string_lossy().into_owned()) + }; + if msvc && is_asm { + cmd.arg("/Fo").arg(dst); + } else if msvc { + let mut s = OsString::from("/Fo"); + s.push(&dst); + cmd.arg(s); + } else { + cmd.arg("-o").arg(&dst); + } + cmd.arg(if msvc {"/c"} else {"-c"}); + cmd.arg(file); + + run(&mut cmd, &name); + } + + /// Get the compiler that's in use for this configuration. + /// + /// This function will return a `Tool` which represents the culmination + /// of this configuration at a snapshot in time. The returned compiler can + /// be inspected (e.g. the path, arguments, environment) to forward along to + /// other tools, or the `to_command` method can be used to invoke the + /// compiler itself. + /// + /// This method will take into account all configuration such as debug + /// information, optimization level, include directories, defines, etc. + /// Additionally, the compiler binary in use follows the standard + /// conventions for this path, e.g. looking at the explicitly set compiler, + /// environment variables (a number of which are inspected here), and then + /// falling back to the default configuration. + pub fn get_compiler(&self) -> Tool { + let opt_level = self.get_opt_level(); + let debug = self.get_debug(); + let target = self.get_target(); + let msvc = target.contains("msvc"); + self.print(&format!("debug={} opt-level={}", debug, opt_level)); + + let mut cmd = self.get_base_compiler(); + let nvcc = cmd.path.to_str() + .map(|path| path.contains("nvcc")) + .unwrap_or(false); + + if msvc { + cmd.args.push("/nologo".into()); + cmd.args.push("/MD".into()); // link against msvcrt.dll for now + match &opt_level[..] { + "z" | "s" => cmd.args.push("/Os".into()), + "2" => cmd.args.push("/O2".into()), + "1" => cmd.args.push("/O1".into()), + _ => {} + } + if target.contains("i686") { + cmd.args.push("/SAFESEH".into()); + } else if target.contains("i586") { + cmd.args.push("/SAFESEH".into()); + cmd.args.push("/ARCH:IA32".into()); + } + } else if nvcc { + cmd.args.push(format!("-O{}", opt_level).into()); + } else { + cmd.args.push(format!("-O{}", opt_level).into()); + cmd.args.push("-ffunction-sections".into()); + cmd.args.push("-fdata-sections".into()); + } + for arg in self.envflags(if self.cpp {"CXXFLAGS"} else {"CFLAGS"}) { + cmd.args.push(arg.into()); + } + + if debug { + cmd.args.push(if msvc {"/Z7"} else {"-g"}.into()); + } + + if target.contains("-ios") { + self.ios_flags(&mut cmd); + } else if !msvc { + if target.contains("i686") || target.contains("i586") { + cmd.args.push("-m32".into()); + } else if target.contains("x86_64") || target.contains("powerpc64") { + cmd.args.push("-m64".into()); + } + + if !nvcc && self.pic.unwrap_or(!target.contains("i686") && !target.contains("windows-gnu")) { + cmd.args.push("-fPIC".into()); + } else if nvcc && self.pic.unwrap_or(false) { + cmd.args.push("-Xcompiler".into()); + cmd.args.push("\'-fPIC\'".into()); + } + if target.contains("musl") { + cmd.args.push("-static".into()); + } + + if target.starts_with("armv7-unknown-linux-") { + cmd.args.push("-march=armv7-a".into()); + } + if target.starts_with("armv7-linux-androideabi") { + cmd.args.push("-march=armv7-a".into()); + cmd.args.push("-mfpu=vfpv3-d16".into()); + } + if target.starts_with("arm-unknown-linux-") { + cmd.args.push("-march=armv6".into()); + cmd.args.push("-marm".into()); + } + if target.starts_with("i586-unknown-linux-") { + cmd.args.push("-march=pentium".into()); + } + if target.starts_with("i686-unknown-linux-") { + cmd.args.push("-march=i686".into()); + } + if target.starts_with("thumb") { + cmd.args.push("-mthumb".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfloat-abi=hard".into()) + } + } + if target.starts_with("thumbv6m") { + cmd.args.push("-march=armv6-m".into()); + } + if target.starts_with("thumbv7em") { + cmd.args.push("-march=armv7e-m".into()); + } + if target.starts_with("thumbv7m") { + cmd.args.push("-march=armv7-m".into()); + } + } + + if self.cpp && !msvc { + if let Some(ref stdlib) = self.cpp_set_stdlib { + cmd.args.push(format!("-stdlib=lib{}", stdlib).into()); + } + } + + for directory in self.include_directories.iter() { + cmd.args.push(if msvc {"/I"} else {"-I"}.into()); + cmd.args.push(directory.into()); + } + + for flag in self.flags.iter() { + cmd.args.push(flag.into()); + } + + for &(ref key, ref value) in self.definitions.iter() { + let lead = if msvc {"/"} else {"-"}; + if let &Some(ref value) = value { + cmd.args.push(format!("{}D{}={}", lead, key, value).into()); + } else { + cmd.args.push(format!("{}D{}", lead, key).into()); + } + } + cmd + } + + fn msvc_macro_assembler(&self) -> (Command, String) { + let target = self.get_target(); + let tool = if target.contains("x86_64") {"ml64.exe"} else {"ml.exe"}; + let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| { + self.cmd(tool) + }); + for directory in self.include_directories.iter() { + cmd.arg("/I").arg(directory); + } + for &(ref key, ref value) in self.definitions.iter() { + if let &Some(ref value) = value { + cmd.arg(&format!("/D{}={}", key, value)); + } else { + cmd.arg(&format!("/D{}", key)); + } + } + + if target.contains("i686") || target.contains("i586") { + cmd.arg("/safeseh"); + } + for flag in self.flags.iter() { + cmd.arg(flag); + } + + (cmd, tool.to_string()) + } + + fn assemble(&self, lib_name: &str, dst: &Path, objects: &[PathBuf]) { + // Delete the destination if it exists as the `ar` tool at least on Unix + // appends to it, which we don't want. + let _ = fs::remove_file(&dst); + + let target = self.get_target(); + if target.contains("msvc") { + let mut cmd = match self.archiver { + Some(ref s) => self.cmd(s), + None => windows_registry::find(&target, "lib.exe") + .unwrap_or(self.cmd("lib.exe")), + }; + let mut out = OsString::from("/OUT:"); + out.push(dst); + run(cmd.arg(out).arg("/nologo") + .args(objects) + .args(&self.objects), "lib.exe"); + + // The Rust compiler will look for libfoo.a and foo.lib, but the + // MSVC linker will also be passed foo.lib, so be sure that both + // exist for now. + let lib_dst = dst.with_file_name(format!("{}.lib", lib_name)); + let _ = fs::remove_file(&lib_dst); + fs::hard_link(&dst, &lib_dst).or_else(|_| { + //if hard-link fails, just copy (ignoring the number of bytes written) + fs::copy(&dst, &lib_dst).map(|_| ()) + }).ok().expect("Copying from {:?} to {:?} failed.");; + } else { + let ar = self.get_ar(); + let cmd = ar.file_name().unwrap().to_string_lossy(); + run(self.cmd(&ar).arg("crs") + .arg(dst) + .args(objects) + .args(&self.objects), &cmd); + } + } + + fn ios_flags(&self, cmd: &mut Tool) { + enum ArchSpec { + Device(&'static str), + Simulator(&'static str), + } + + let target = self.get_target(); + let arch = target.split('-').nth(0).unwrap(); + let arch = match arch { + "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"), + "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"), + "arm64" | "aarch64" => ArchSpec::Device("arm64"), + "i386" | "i686" => ArchSpec::Simulator("-m32"), + "x86_64" => ArchSpec::Simulator("-m64"), + _ => fail("Unknown arch for iOS target") + }; + + let sdk = match arch { + ArchSpec::Device(arch) => { + cmd.args.push("-arch".into()); + cmd.args.push(arch.into()); + cmd.args.push("-miphoneos-version-min=7.0".into()); + "iphoneos" + }, + ArchSpec::Simulator(arch) => { + cmd.args.push(arch.into()); + cmd.args.push("-mios-simulator-version-min=7.0".into()); + "iphonesimulator" + } + }; + + self.print(&format!("Detecting iOS SDK path for {}", sdk)); + let sdk_path = self.cmd("xcrun") + .arg("--show-sdk-path") + .arg("--sdk") + .arg(sdk) + .stderr(Stdio::inherit()) + .output() + .unwrap() + .stdout; + + let sdk_path = String::from_utf8(sdk_path).unwrap(); + + cmd.args.push("-isysroot".into()); + cmd.args.push(sdk_path.trim().into()); + } + + fn cmd>(&self, prog: P) -> Command { + let mut cmd = Command::new(prog); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + return cmd + } + + fn get_base_compiler(&self) -> Tool { + if let Some(ref c) = self.compiler { + return Tool::new(c.clone()) + } + let host = self.get_host(); + let target = self.get_target(); + let (env, msvc, gnu, default) = if self.cpp { + ("CXX", "cl.exe", "g++", "c++") + } else { + ("CC", "cl.exe", "gcc", "cc") + }; + self.env_tool(env).map(|(tool, args)| { + let mut t = Tool::new(PathBuf::from(tool)); + for arg in args { + t.args.push(arg.into()); + } + return t + }).or_else(|| { + if target.contains("emscripten") { + if self.cpp { + Some(Tool::new(PathBuf::from("em++"))) + } else { + Some(Tool::new(PathBuf::from("emcc"))) + } + } else { + None + } + }).or_else(|| { + windows_registry::find_tool(&target, "cl.exe") + }).unwrap_or_else(|| { + let compiler = if host.contains("windows") && + target.contains("windows") { + if target.contains("msvc") { + msvc.to_string() + } else { + format!("{}.exe", gnu) + } + } else if target.contains("android") { + format!("{}-{}", target, gnu) + } else if self.get_host() != target { + // CROSS_COMPILE is of the form: "arm-linux-gnueabi-" + let cc_env = self.getenv("CROSS_COMPILE"); + let cross_compile = cc_env.as_ref().map(|s| s.trim_right_matches('-')); + let prefix = cross_compile.or(match &target[..] { + "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"), + "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"), + "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "arm-unknown-netbsdelf-eabi" => Some("arm--netbsdelf-eabi"), + "armv6-unknown-netbsdelf-eabihf" => Some("armv6--netbsdelf-eabihf"), + "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7-unknown-netbsdelf-eabihf" => Some("armv7--netbsdelf-eabihf"), + "i686-pc-windows-gnu" => Some("i686-w64-mingw32"), + "i686-unknown-linux-musl" => Some("musl"), + "i686-unknown-netbsdelf" => Some("i486--netbsdelf"), + "mips-unknown-linux-gnu" => Some("mips-linux-gnu"), + "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"), + "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"), + "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"), + "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc-unknown-netbsd" => Some("powerpc--netbsd"), + "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"), + "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"), + "thumbv6m-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabihf" => Some("arm-none-eabi"), + "thumbv7m-none-eabi" => Some("arm-none-eabi"), + "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"), + "x86_64-unknown-linux-musl" => Some("musl"), + "x86_64-unknown-netbsd" => Some("x86_64--netbsd"), + _ => None, + }); + match prefix { + Some(prefix) => format!("{}-{}", prefix, gnu), + None => default.to_string(), + } + } else { + default.to_string() + }; + Tool::new(PathBuf::from(compiler)) + }) + } + + fn get_var(&self, var_base: &str) -> Result { + let target = self.get_target(); + let host = self.get_host(); + let kind = if host == target {"HOST"} else {"TARGET"}; + let target_u = target.replace("-", "_"); + let res = self.getenv(&format!("{}_{}", var_base, target)) + .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u))) + .or_else(|| self.getenv(&format!("{}_{}", kind, var_base))) + .or_else(|| self.getenv(var_base)); + + match res { + Some(res) => Ok(res), + None => Err("could not get environment variable".to_string()), + } + } + + fn envflags(&self, name: &str) -> Vec { + self.get_var(name).unwrap_or(String::new()) + .split(|c: char| c.is_whitespace()).filter(|s| !s.is_empty()) + .map(|s| s.to_string()) + .collect() + } + + fn env_tool(&self, name: &str) -> Option<(String, Vec)> { + self.get_var(name).ok().map(|tool| { + let whitelist = ["ccache", "distcc"]; + for t in whitelist.iter() { + if tool.starts_with(t) && tool[t.len()..].starts_with(" ") { + return (t.to_string(), + vec![tool[t.len()..].trim_left().to_string()]) + } + } + (tool, Vec::new()) + }) + } + + /// Returns the default C++ standard library for the current target: `libc++` + /// for OS X and `libstdc++` for anything else. + fn get_cpp_link_stdlib(&self) -> Option { + self.cpp_link_stdlib.clone().unwrap_or_else(|| { + let target = self.get_target(); + if target.contains("msvc") { + None + } else if target.contains("darwin") { + Some("c++".to_string()) + } else { + Some("stdc++".to_string()) + } + }) + } + + fn get_ar(&self) -> PathBuf { + self.archiver.clone().or_else(|| { + self.get_var("AR").map(PathBuf::from).ok() + }).unwrap_or_else(|| { + if self.get_target().contains("android") { + PathBuf::from(format!("{}-ar", self.get_target())) + } else if self.get_target().contains("emscripten") { + PathBuf::from("emar") + } else { + PathBuf::from("ar") + } + }) + } + + fn get_target(&self) -> String { + self.target.clone().unwrap_or_else(|| self.getenv_unwrap("TARGET")) + } + + fn get_host(&self) -> String { + self.host.clone().unwrap_or_else(|| self.getenv_unwrap("HOST")) + } + + fn get_opt_level(&self) -> String { + self.opt_level.as_ref().cloned().unwrap_or_else(|| { + self.getenv_unwrap("OPT_LEVEL") + }) + } + + fn get_debug(&self) -> bool { + self.debug.unwrap_or_else(|| self.getenv_unwrap("PROFILE") == "debug") + } + + fn get_out_dir(&self) -> PathBuf { + self.out_dir.clone().unwrap_or_else(|| { + env::var_os("OUT_DIR").map(PathBuf::from).unwrap() + }) + } + + fn getenv(&self, v: &str) -> Option { + let r = env::var(v).ok(); + self.print(&format!("{} = {:?}", v, r)); + r + } + + fn getenv_unwrap(&self, v: &str) -> String { + match self.getenv(v) { + Some(s) => s, + None => fail(&format!("environment variable `{}` not defined", v)), + } + } + + fn print(&self, s: &str) { + if self.cargo_metadata { + println!("{}", s); + } + } +} + +impl Tool { + fn new(path: PathBuf) -> Tool { + Tool { + path: path, + args: Vec::new(), + env: Vec::new(), + } + } + + /// Converts this compiler into a `Command` that's ready to be run. + /// + /// This is useful for when the compiler needs to be executed and the + /// command returned will already have the initial arguments and environment + /// variables configured. + pub fn to_command(&self) -> Command { + let mut cmd = Command::new(&self.path); + cmd.args(&self.args); + for &(ref k, ref v) in self.env.iter() { + cmd.env(k, v); + } + return cmd + } + + /// Returns the path for this compiler. + /// + /// Note that this may not be a path to a file on the filesystem, e.g. "cc", + /// but rather something which will be resolved when a process is spawned. + pub fn path(&self) -> &Path { + &self.path + } + + /// Returns the default set of arguments to the compiler needed to produce + /// executables for the target this compiler generates. + pub fn args(&self) -> &[OsString] { + &self.args + } + + /// Returns the set of environment variables needed for this compiler to + /// operate. + /// + /// This is typically only used for MSVC compilers currently. + pub fn env(&self) -> &[(OsString, OsString)] { + &self.env + } +} + +fn run(cmd: &mut Command, program: &str) { + println!("running: {:?}", cmd); + // Capture the standard error coming from these programs, and write it out + // with cargo:warning= prefixes. Note that this is a bit wonky to avoid + // requiring the output to be UTF-8, we instead just ship bytes from one + // location to another. + let spawn_result = match cmd.stderr(Stdio::piped()).spawn() { + Ok(mut child) => { + let stderr = BufReader::new(child.stderr.take().unwrap()); + for line in stderr.split(b'\n').filter_map(|l| l.ok()) { + print!("cargo:warning="); + std::io::stdout().write_all(&line).unwrap(); + println!(""); + } + child.wait() + } + Err(e) => Err(e), + }; + let status = match spawn_result { + Ok(status) => status, + Err(ref e) if e.kind() == io::ErrorKind::NotFound => { + let extra = if cfg!(windows) { + " (see https://github.com/alexcrichton/gcc-rs#compile-time-requirements \ + for help)" + } else { + "" + }; + fail(&format!("failed to execute command: {}\nIs `{}` \ + not installed?{}", e, program, extra)); + } + Err(e) => fail(&format!("failed to execute command: {}", e)), + }; + println!("{:?}", status); + if !status.success() { + fail(&format!("command did not execute successfully, got: {}", status)); + } +} + +fn fail(s: &str) -> ! { + println!("\n\n{}\n\n", s); + panic!() +} diff --git a/src/vendor/gcc/src/registry.rs b/src/vendor/gcc/src/registry.rs new file mode 100644 index 000000000000..d871cd21f3c0 --- /dev/null +++ b/src/vendor/gcc/src/registry.rs @@ -0,0 +1,169 @@ +// 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. + +use std::ffi::{OsString, OsStr}; +use std::io; +use std::ops::RangeFrom; +use std::os::raw; +use std::os::windows::prelude::*; + +pub struct RegistryKey(Repr); + +type HKEY = *mut u8; +type DWORD = u32; +type LPDWORD = *mut DWORD; +type LPCWSTR = *const u16; +type LPWSTR = *mut u16; +type LONG = raw::c_long; +type PHKEY = *mut HKEY; +type PFILETIME = *mut u8; +type LPBYTE = *mut u8; +type REGSAM = u32; + +const ERROR_SUCCESS: DWORD = 0; +const ERROR_NO_MORE_ITEMS: DWORD = 259; +const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY; +const REG_SZ: DWORD = 1; +const KEY_READ: DWORD = 0x20019; +const KEY_WOW64_32KEY: DWORD = 0x200; + +#[link(name = "advapi32")] +extern "system" { + fn RegOpenKeyExW(key: HKEY, + lpSubKey: LPCWSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY) -> LONG; + fn RegEnumKeyExW(key: HKEY, + dwIndex: DWORD, + lpName: LPWSTR, + lpcName: LPDWORD, + lpReserved: LPDWORD, + lpClass: LPWSTR, + lpcClass: LPDWORD, + lpftLastWriteTime: PFILETIME) -> LONG; + fn RegQueryValueExW(hKey: HKEY, + lpValueName: LPCWSTR, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD) -> LONG; + fn RegCloseKey(hKey: HKEY) -> LONG; +} + +struct OwnedKey(HKEY); + +enum Repr { + Const(HKEY), + Owned(OwnedKey), +} + +pub struct Iter<'a> { + idx: RangeFrom, + key: &'a RegistryKey, +} + +unsafe impl Sync for Repr {} +unsafe impl Send for Repr {} + +pub static LOCAL_MACHINE: RegistryKey = + RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE)); + +impl RegistryKey { + fn raw(&self) -> HKEY { + match self.0 { + Repr::Const(val) => val, + Repr::Owned(ref val) => val.0, + } + } + + pub fn open(&self, key: &OsStr) -> io::Result { + let key = key.encode_wide().chain(Some(0)).collect::>(); + let mut ret = 0 as *mut _; + let err = unsafe { + RegOpenKeyExW(self.raw(), key.as_ptr(), 0, + KEY_READ | KEY_WOW64_32KEY, &mut ret) + }; + if err == ERROR_SUCCESS as LONG { + Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) + } else { + Err(io::Error::from_raw_os_error(err as i32)) + } + } + + pub fn iter(&self) -> Iter { + Iter { idx: 0.., key: self } + } + + pub fn query_str(&self, name: &str) -> io::Result { + let name: &OsStr = name.as_ref(); + let name = name.encode_wide().chain(Some(0)).collect::>(); + let mut len = 0; + let mut kind = 0; + unsafe { + let err = RegQueryValueExW(self.raw(), name.as_ptr(), 0 as *mut _, + &mut kind, 0 as *mut _, &mut len); + if err != ERROR_SUCCESS as LONG { + return Err(io::Error::from_raw_os_error(err as i32)) + } + if kind != REG_SZ { + return Err(io::Error::new(io::ErrorKind::Other, + "registry key wasn't a string")) + } + + // The length here is the length in bytes, but we're using wide + // characters so we need to be sure to halve it for the capacity + // passed in. + let mut v = Vec::with_capacity(len as usize / 2); + let err = RegQueryValueExW(self.raw(), name.as_ptr(), 0 as *mut _, + 0 as *mut _, v.as_mut_ptr() as *mut _, + &mut len); + if err != ERROR_SUCCESS as LONG { + return Err(io::Error::from_raw_os_error(err as i32)) + } + v.set_len(len as usize / 2); + + // Some registry keys may have a terminating nul character, but + // we're not interested in that, so chop it off if it's there. + if v[v.len() - 1] == 0 { + v.pop(); + } + Ok(OsString::from_wide(&v)) + } + } +} + +impl Drop for OwnedKey { + fn drop(&mut self) { + unsafe { RegCloseKey(self.0); } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.idx.next().and_then(|i| unsafe { + let mut v = Vec::with_capacity(256); + let mut len = v.capacity() as DWORD; + let ret = RegEnumKeyExW(self.key.raw(), i, v.as_mut_ptr(), &mut len, + 0 as *mut _, 0 as *mut _, 0 as *mut _, + 0 as *mut _); + if ret == ERROR_NO_MORE_ITEMS as LONG { + None + } else if ret != ERROR_SUCCESS as LONG { + Some(Err(io::Error::from_raw_os_error(ret as i32))) + } else { + v.set_len(len as usize); + Some(Ok(OsString::from_wide(&v))) + } + }) + } +} diff --git a/src/vendor/gcc/src/windows_registry.rs b/src/vendor/gcc/src/windows_registry.rs new file mode 100644 index 000000000000..b2c719d27ffd --- /dev/null +++ b/src/vendor/gcc/src/windows_registry.rs @@ -0,0 +1,425 @@ +// 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. + +//! A helper module to probe the Windows Registry when looking for +//! windows-specific tools. + +use std::process::Command; + +use Tool; + +macro_rules! otry { + ($expr:expr) => (match $expr { + Some(val) => val, + None => return None, + }) +} + +/// Attempts to find a tool within an MSVC installation using the Windows +/// registry as a point to search from. +/// +/// The `target` argument is the target that the tool should work for (e.g. +/// compile or link for) and the `tool` argument is the tool to find (e.g. +/// `cl.exe` or `link.exe`). +/// +/// This function will return `None` if the tool could not be found, or it will +/// return `Some(cmd)` which represents a command that's ready to execute the +/// tool with the appropriate environment variables set. +/// +/// Note that this function always returns `None` for non-MSVC targets. +pub fn find(target: &str, tool: &str) -> Option { + find_tool(target, tool).map(|c| c.to_command()) +} + +/// Similar to the `find` function above, this function will attempt the same +/// operation (finding a MSVC tool in a local install) but instead returns a +/// `Tool` which may be introspected. +#[cfg(not(windows))] +pub fn find_tool(_target: &str, _tool: &str) -> Option { + None +} + +/// Documented above. +#[cfg(windows)] +pub fn find_tool(target: &str, tool: &str) -> Option { + use std::env; + use std::ffi::OsString; + use std::mem; + use std::path::{Path, PathBuf}; + use registry::{RegistryKey, LOCAL_MACHINE}; + + struct MsvcTool { + tool: PathBuf, + libs: Vec, + path: Vec, + include: Vec, + } + + impl MsvcTool { + fn new(tool: PathBuf) -> MsvcTool { + MsvcTool { + tool: tool, + libs: Vec::new(), + path: Vec::new(), + include: Vec::new(), + } + } + + fn into_tool(self) -> Tool { + let MsvcTool { tool, libs, path, include } = self; + let mut tool = Tool::new(tool.into()); + add_env(&mut tool, "LIB", libs); + add_env(&mut tool, "PATH", path); + add_env(&mut tool, "INCLUDE", include); + return tool + } + } + + // This logic is all tailored for MSVC, if we're not that then bail out + // early. + if !target.contains("msvc") { + return None + } + + // Looks like msbuild isn't located in the same location as other tools like + // cl.exe and lib.exe. To handle this we probe for it manually with + // dedicated registry keys. + if tool.contains("msbuild") { + return find_msbuild(target) + } + + // If VCINSTALLDIR is set, then someone's probably already run vcvars and we + // should just find whatever that indicates. + if env::var_os("VCINSTALLDIR").is_some() { + return env::var_os("PATH").and_then(|path| { + env::split_paths(&path).map(|p| p.join(tool)).find(|p| p.exists()) + }).map(|path| { + Tool::new(path.into()) + }) + } + + // Ok, if we're here, now comes the fun part of the probing. Default shells + // or shells like MSYS aren't really configured to execute `cl.exe` and the + // various compiler tools shipped as part of Visual Studio. Here we try to + // first find the relevant tool, then we also have to be sure to fill in + // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that + // the tool is actually usable. + + return find_msvc_latest(tool, target, "15.0").or_else(|| { + find_msvc_latest(tool, target, "14.0") + }).or_else(|| { + find_msvc_12(tool, target) + }).or_else(|| { + find_msvc_11(tool, target) + }); + + // For MSVC 14 or newer we need to find the Universal CRT as well as either + // the Windows 10 SDK or Windows 8.1 SDK. + fn find_msvc_latest(tool: &str, target: &str, ver: &str) -> Option { + let vcdir = otry!(get_vc_dir(ver)); + let mut tool = otry!(get_tool(tool, &vcdir, target)); + let sub = otry!(lib_subdir(target)); + let (ucrt, ucrt_version) = otry!(get_ucrt_dir()); + + let ucrt_include = ucrt.join("include").join(&ucrt_version); + tool.include.push(ucrt_include.join("ucrt")); + + let ucrt_lib = ucrt.join("lib").join(&ucrt_version); + tool.libs.push(ucrt_lib.join("ucrt").join(sub)); + + if let Some((sdk, version)) = get_sdk10_dir() { + tool.path.push(sdk.join("bin").join(sub)); + let sdk_lib = sdk.join("lib").join(&version); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include").join(&version); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } else if let Some(sdk) = get_sdk81_dir() { + tool.path.push(sdk.join("bin").join(sub)); + let sdk_lib = sdk.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include"); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } else { + return None + } + Some(tool.into_tool()) + } + + // For MSVC 12 we need to find the Windows 8.1 SDK. + fn find_msvc_12(tool: &str, target: &str) -> Option { + let vcdir = otry!(get_vc_dir("12.0")); + let mut tool = otry!(get_tool(tool, &vcdir, target)); + let sub = otry!(lib_subdir(target)); + let sdk81 = otry!(get_sdk81_dir()); + tool.path.push(sdk81.join("bin").join(sub)); + let sdk_lib = sdk81.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk81.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + // For MSVC 11 we need to find the Windows 8 SDK. + fn find_msvc_11(tool: &str, target: &str) -> Option { + let vcdir = otry!(get_vc_dir("11.0")); + let mut tool = otry!(get_tool(tool, &vcdir, target)); + let sub = otry!(lib_subdir(target)); + let sdk8 = otry!(get_sdk8_dir()); + tool.path.push(sdk8.join("bin").join(sub)); + let sdk_lib = sdk8.join("lib").join("win8"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk8.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + fn add_env(tool: &mut Tool, env: &str, paths: Vec) { + let prev = env::var_os(env).unwrap_or(OsString::new()); + let prev = env::split_paths(&prev); + let new = paths.into_iter().chain(prev); + tool.env.push((env.to_string().into(), env::join_paths(new).unwrap())); + } + + // Given a possible MSVC installation directory, we look for the linker and + // then add the MSVC library path. + fn get_tool(tool: &str, path: &Path, target: &str) -> Option { + bin_subdir(target).into_iter().map(|(sub, host)| { + (path.join("bin").join(sub).join(tool), + path.join("bin").join(host)) + }).filter(|&(ref path, _)| { + path.is_file() + }).map(|(path, host)| { + let mut tool = MsvcTool::new(path); + tool.path.push(host); + tool + }).filter_map(|mut tool| { + let sub = otry!(vc_lib_subdir(target)); + tool.libs.push(path.join("lib").join(sub)); + tool.include.push(path.join("include")); + Some(tool) + }).next() + } + + // To find MSVC we look in a specific registry key for the version we are + // trying to find. + fn get_vc_dir(ver: &str) -> Option { + let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let path = otry!(key.query_str(ver).ok()); + Some(path.into()) + } + + // To find the Universal CRT we look in a specific registry key for where + // all the Universal CRTs are located and then sort them asciibetically to + // find the newest version. While this sort of sorting isn't ideal, it is + // what vcvars does so that's good enough for us. + // + // Returns a pair of (root, version) for the ucrt dir if found + fn get_ucrt_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("KitsRoot10").ok()); + let readdir = otry!(Path::new(&root).join("lib").read_dir().ok()); + let max_libdir = otry!(readdir.filter_map(|dir| { + dir.ok() + }).map(|dir| { + dir.path() + }).filter(|dir| { + dir.components().last().and_then(|c| { + c.as_os_str().to_str() + }).map(|c| { + c.starts_with("10.") && dir.join("ucrt").is_dir() + }).unwrap_or(false) + }).max()); + let version = max_libdir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Vcvars finds the correct version of the Windows 10 SDK by looking + // for the include `um\Windows.h` because sometimes a given version will + // only have UCRT bits without the rest of the SDK. Since we only care about + // libraries and not includes, we instead look for `um\x64\kernel32.lib`. + // Since the 32-bit and 64-bit libraries are always installed together we + // only need to bother checking x64, making this code a tiny bit simpler. + // Like we do for the Universal CRT, we sort the possibilities + // asciibetically to find the newest one as that is what vcvars does. + fn get_sdk10_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("InstallationFolder").ok()); + let readdir = otry!(Path::new(&root).join("lib").read_dir().ok()); + let mut dirs = readdir.filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .collect::>(); + dirs.sort(); + let dir = otry!(dirs.into_iter().rev().filter(|dir| { + dir.join("um").join("x64").join("kernel32.lib").is_file() + }).next()); + let version = dir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Interestingly there are several subdirectories, `win7` `win8` and + // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same + // applies to us. Note that if we were targetting kernel mode drivers + // instead of user mode applications, we would care. + fn get_sdk81_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("InstallationFolder").ok()); + Some(root.into()) + } + + fn get_sdk8_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("InstallationFolder").ok()); + Some(root.into()) + } + + const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0; + const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9; + const X86: u16 = PROCESSOR_ARCHITECTURE_INTEL; + const X86_64: u16 = PROCESSOR_ARCHITECTURE_AMD64; + + // When choosing the tool to use, we have to choose the one which matches + // the target architecture. Otherwise we end up in situations where someone + // on 32-bit Windows is trying to cross compile to 64-bit and it tries to + // invoke the native 64-bit compiler which won't work. + // + // For the return value of this function, the first member of the tuple is + // the folder of the tool we will be invoking, while the second member is + // the folder of the host toolchain for that tool which is essential when + // using a cross linker. We return a Vec since on x64 there are often two + // linkers that can target the architecture we desire. The 64-bit host + // linker is preferred, and hence first, due to 64-bit allowing it more + // address space to work with and potentially being faster. + fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> { + let arch = target.split('-').next().unwrap(); + match (arch, host_arch()) { + ("i586", X86) | + ("i686", X86) => vec![("", "")], + ("i586", X86_64) | + ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")], + ("x86_64", X86) => vec![("x86_amd64", "")], + ("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")], + ("arm", X86) => vec![("x86_arm", "")], + ("arm", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")], + _ => vec![], + } + } + + fn lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some("x86"), + "x86_64" => Some("x64"), + "arm" => Some("arm"), + _ => None, + } + } + + // MSVC's x86 libraries are not in a subfolder + fn vc_lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some(""), + "x86_64" => Some("amd64"), + "arm" => Some("arm"), + _ => None, + } + } + + #[allow(bad_style)] + fn host_arch() -> u16 { + type DWORD = u32; + type WORD = u16; + type LPVOID = *mut u8; + type DWORD_PTR = usize; + + #[repr(C)] + struct SYSTEM_INFO { + wProcessorArchitecture: WORD, + _wReserved: WORD, + _dwPageSize: DWORD, + _lpMinimumApplicationAddress: LPVOID, + _lpMaximumApplicationAddress: LPVOID, + _dwActiveProcessorMask: DWORD_PTR, + _dwNumberOfProcessors: DWORD, + _dwProcessorType: DWORD, + _dwAllocationGranularity: DWORD, + _wProcessorLevel: WORD, + _wProcessorRevision: WORD, + } + + extern "system" { + fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO); + } + + unsafe { + let mut info = mem::zeroed(); + GetNativeSystemInfo(&mut info); + info.wProcessorArchitecture + } + } + + // Given a registry key, look at all the sub keys and find the one which has + // the maximal numeric value. + // + // Returns the name of the maximal key as well as the opened maximal key. + fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> { + let mut max_vers = 0; + let mut max_key = None; + for subkey in key.iter().filter_map(|k| k.ok()) { + let val = subkey.to_str().and_then(|s| { + s.trim_left_matches("v").replace(".", "").parse().ok() + }); + let val = match val { + Some(s) => s, + None => continue, + }; + if val > max_vers { + if let Ok(k) = key.open(&subkey) { + max_vers = val; + max_key = Some((subkey, k)); + } + } + } + return max_key + } + + // see http://stackoverflow.com/questions/328017/path-to-msbuild + fn find_msbuild(target: &str) -> Option { + let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions"; + LOCAL_MACHINE.open(key.as_ref()).ok().and_then(|key| { + max_version(&key).and_then(|(_vers, key)| { + key.query_str("MSBuildToolsPath").ok() + }) + }).map(|path| { + let mut path = PathBuf::from(path); + path.push("MSBuild.exe"); + let mut tool = Tool::new(path); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + tool + }) + } +} diff --git a/src/vendor/gcc/tests/cc_env.rs b/src/vendor/gcc/tests/cc_env.rs new file mode 100644 index 000000000000..559dbe8ad4e5 --- /dev/null +++ b/src/vendor/gcc/tests/cc_env.rs @@ -0,0 +1,49 @@ +extern crate tempdir; +extern crate gcc; + +use std::env; + +mod support; +use support::Test; + +#[test] +fn main() { + ccache(); + distcc(); + ccache_spaces(); +} + +fn ccache() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache lol-this-is-not-a-compiler foo"); + test.gcc().file("foo.c").compile("libfoo.a"); + + test.cmd(0) + .must_have("lol-this-is-not-a-compiler foo") + .must_have("foo.c") + .must_not_have("ccache"); +} + +fn ccache_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache lol-this-is-not-a-compiler foo"); + test.gcc().file("foo.c").compile("libfoo.a"); + test.cmd(0).must_have("lol-this-is-not-a-compiler foo"); +} + +fn distcc() { + let test = Test::gnu(); + test.shim("distcc"); + + env::set_var("CC", "distcc lol-this-is-not-a-compiler foo"); + test.gcc().file("foo.c").compile("libfoo.a"); + + test.cmd(0) + .must_have("lol-this-is-not-a-compiler foo") + .must_have("foo.c") + .must_not_have("distcc"); +} diff --git a/src/vendor/gcc/tests/support/mod.rs b/src/vendor/gcc/tests/support/mod.rs new file mode 100644 index 000000000000..b5703d2fd8b1 --- /dev/null +++ b/src/vendor/gcc/tests/support/mod.rs @@ -0,0 +1,111 @@ +#![allow(dead_code)] + +use std::env; +use std::ffi::OsStr; +use std::fs::{self, File}; +use std::io::prelude::*; +use std::path::PathBuf; + +use gcc; +use tempdir::TempDir; + +pub struct Test { + pub td: TempDir, + pub gcc: PathBuf, + pub msvc: bool, +} + +pub struct Execution { + args: Vec, +} + +impl Test { + pub fn new() -> Test { + let mut gcc = PathBuf::from(env::current_exe().unwrap()); + gcc.pop(); + gcc.push(format!("gcc-shim{}", env::consts::EXE_SUFFIX)); + Test { + td: TempDir::new("gcc-test").unwrap(), + gcc: gcc, + msvc: false, + } + } + + pub fn gnu() -> Test { + let t = Test::new(); + t.shim("cc").shim("ar"); + return t + } + + pub fn msvc() -> Test { + let mut t = Test::new(); + t.shim("cl").shim("lib.exe"); + t.msvc = true; + return t + } + + pub fn shim(&self, name: &str) -> &Test { + let fname = format!("{}{}", name, env::consts::EXE_SUFFIX); + fs::hard_link(&self.gcc, self.td.path().join(&fname)).or_else(|_| { + fs::copy(&self.gcc, self.td.path().join(&fname)).map(|_| ()) + }).unwrap(); + self + } + + pub fn gcc(&self) -> gcc::Config { + let mut cfg = gcc::Config::new(); + let mut path = env::split_paths(&env::var_os("PATH").unwrap()) + .collect::>(); + path.insert(0, self.td.path().to_owned()); + let target = if self.msvc { + "x86_64-pc-windows-msvc" + } else { + "x86_64-unknown-linux-gnu" + }; + + cfg.target(target).host(target) + .opt_level(2) + .debug(false) + .out_dir(self.td.path()) + .__set_env("PATH", env::join_paths(path).unwrap()) + .__set_env("GCCTEST_OUT_DIR", self.td.path()); + if self.msvc { + cfg.compiler(self.td.path().join("cl")); + cfg.archiver(self.td.path().join("lib.exe")); + } + return cfg + } + + pub fn cmd(&self, i: u32) -> Execution { + let mut s = String::new(); + File::open(self.td.path().join(format!("out{}", i))).unwrap() + .read_to_string(&mut s).unwrap(); + Execution { + args: s.lines().map(|s| s.to_string()).collect(), + } + } +} + +impl Execution { + pub fn must_have>(&self, p: P) -> &Execution { + if !self.has(p.as_ref()) { + panic!("didn't find {:?} in {:?}", p.as_ref(), self.args); + } else { + self + } + } + + pub fn must_not_have>(&self, p: P) -> &Execution { + if self.has(p.as_ref()) { + panic!("found {:?}", p.as_ref()); + } else { + self + } + } + + pub fn has(&self, p: &OsStr) -> bool { + self.args.iter().any(|arg| { + OsStr::new(arg) == p + }) + } +} diff --git a/src/vendor/gcc/tests/test.rs b/src/vendor/gcc/tests/test.rs new file mode 100644 index 000000000000..1b6a0bd0d10a --- /dev/null +++ b/src/vendor/gcc/tests/test.rs @@ -0,0 +1,207 @@ +extern crate gcc; +extern crate tempdir; + +use support::Test; + +mod support; + +#[test] +fn gnu_smoke() { + let test = Test::gnu(); + test.gcc() + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_have("-O2") + .must_have("foo.c") + .must_not_have("-g") + .must_have("-c") + .must_have("-ffunction-sections") + .must_have("-fdata-sections"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn gnu_opt_level_1() { + let test = Test::gnu(); + test.gcc() + .opt_level(1) + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_have("-O1") + .must_not_have("-O2"); +} + +#[test] +fn gnu_opt_level_s() { + let test = Test::gnu(); + test.gcc() + .opt_level_str("s") + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_have("-Os") + .must_not_have("-O1") + .must_not_have("-O2") + .must_not_have("-O3") + .must_not_have("-Oz"); +} + +#[test] +fn gnu_debug() { + let test = Test::gnu(); + test.gcc() + .debug(true) + .file("foo.c").compile("libfoo.a"); + test.cmd(0).must_have("-g"); +} + +#[test] +fn gnu_x86_64() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_have("-fPIC") + .must_have("-m64"); + } +} + +#[test] +fn gnu_x86_64_no_pic() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(false) + .target(&target) + .host(&target) + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_not_have("-fPIC"); + } +} + +#[test] +fn gnu_i686() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_not_have("-fPIC") + .must_have("-m32"); + } +} + +#[test] +fn gnu_i686_pic() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(true) + .target(&target) + .host(&target) + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_have("-fPIC"); + } +} + +#[test] +fn gnu_set_stdlib() { + let test = Test::gnu(); + test.gcc() + .cpp_set_stdlib(Some("foo")) + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_not_have("-stdlib=foo"); +} + +#[test] +fn gnu_include() { + let test = Test::gnu(); + test.gcc() + .include("foo/bar") + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_have("-I").must_have("foo/bar"); +} + +#[test] +fn gnu_define() { + let test = Test::gnu(); + test.gcc() + .define("FOO", Some("bar")) + .define("BAR", None) + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR"); +} + +#[test] +fn gnu_compile_assembly() { + let test = Test::gnu(); + test.gcc() + .file("foo.S").compile("libfoo.a"); + test.cmd(0).must_have("foo.S"); +} + +#[test] +fn msvc_smoke() { + let test = Test::msvc(); + test.gcc() + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_have("/O2") + .must_have("foo.c") + .must_not_have("/Z7") + .must_have("/c"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn msvc_opt_level_0() { + let test = Test::msvc(); + test.gcc() + .opt_level(0) + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_not_have("/O2"); +} + +#[test] +fn msvc_debug() { + let test = Test::msvc(); + test.gcc() + .debug(true) + .file("foo.c").compile("libfoo.a"); + test.cmd(0).must_have("/Z7"); +} + +#[test] +fn msvc_include() { + let test = Test::msvc(); + test.gcc() + .include("foo/bar") + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_have("/I").must_have("foo/bar"); +} + +#[test] +fn msvc_define() { + let test = Test::msvc(); + test.gcc() + .define("FOO", Some("bar")) + .define("BAR", None) + .file("foo.c").compile("libfoo.a"); + + test.cmd(0).must_have("/DFOO=bar").must_have("/DBAR"); +} diff --git a/src/vendor/getopts/.cargo-checksum.json b/src/vendor/getopts/.cargo-checksum.json new file mode 100644 index 000000000000..0c13fda1c116 --- /dev/null +++ b/src/vendor/getopts/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"c1e953ee360e77de57f7b02f1b7880bd6a3dc22d1a69e953c2ac2c52cc52d247",".travis.yml":"f01015154ac55bebd8ff25742496135c40395959f772005bdf7c63bc9b373c12","Cargo.toml":"a027aa6d21622b42c545707ba04f78341cc28079b46da775827ab1ec37fe3ca7","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"4002d78e71c4e1fb82c77590eddb999371f40dce037d895f96e6d6df42c728d3","appveyor.yml":"da991211b72fa6f231af7adb84c9fb72f5a9131d1c0a3d47b8ceffe5a82c8542","src/lib.rs":"9512dd4ec1053c9fc61f630d869053ca50c55e0839e3ab7091246a8654423bf0","tests/smoke.rs":"26a95ac42e42b766ae752fe8531fb740fd147d5cdff352dec0763d175ce91806"},"package":"d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"} \ No newline at end of file diff --git a/src/vendor/getopts/.cargo-ok b/src/vendor/getopts/.cargo-ok new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/vendor/getopts/.gitignore b/src/vendor/getopts/.gitignore new file mode 100644 index 000000000000..4fffb2f89cbd --- /dev/null +++ b/src/vendor/getopts/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/src/vendor/getopts/.travis.yml b/src/vendor/getopts/.travis.yml new file mode 100644 index 000000000000..d7e3f4787aea --- /dev/null +++ b/src/vendor/getopts/.travis.yml @@ -0,0 +1,20 @@ +language: rust +rust: + - 1.0.0 + - beta + - nightly +sudo: false +before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH +script: + - cargo build --verbose + - cargo test --verbose + - cargo doc --no-deps +after_success: + - travis-cargo --only nightly doc-upload +env: + global: + secure: by+Jo/boBPbcF5c1N6RNCA008oJm2aRFE5T0SUc3OIfTXxY08dZc0WCBJCHrplp44VjpeKRp/89Y+k1CKncIeU8LiS6ZgsKqaQcCglE2O1KS90B6FYB7+rBqT3ib25taq1nW38clnBHYHV9nz4gOElSdKGRxCcBy+efQ5ZXr2tY= +notifications: + email: + on_success: never diff --git a/src/vendor/getopts/Cargo.toml b/src/vendor/getopts/Cargo.toml new file mode 100644 index 000000000000..f84899fe8120 --- /dev/null +++ b/src/vendor/getopts/Cargo.toml @@ -0,0 +1,16 @@ +[package] + +name = "getopts" +version = "0.2.14" +authors = ["The Rust Project Developers"] +license = "MIT/Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-lang/getopts" +documentation = "http://doc.rust-lang.org/getopts" +homepage = "https://github.com/rust-lang/getopts" +description = """ +getopts-like option parsing. +""" + +[dev-dependencies] +log = "0.3" diff --git a/src/vendor/getopts/LICENSE-APACHE b/src/vendor/getopts/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/src/vendor/getopts/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/vendor/getopts/LICENSE-MIT b/src/vendor/getopts/LICENSE-MIT new file mode 100644 index 000000000000..39d4bdb5acd3 --- /dev/null +++ b/src/vendor/getopts/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/vendor/getopts/README.md b/src/vendor/getopts/README.md new file mode 100644 index 000000000000..c19f48fb06b5 --- /dev/null +++ b/src/vendor/getopts/README.md @@ -0,0 +1,23 @@ +getopts +=== + +A Rust library for option parsing for CLI utilities. + +[![Build Status](https://travis-ci.org/rust-lang/getopts.svg?branch=master)](https://travis-ci.org/rust-lang/getopts) + +[Documentation](http://doc.rust-lang.org/getopts) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +getopts = "0.2.4" +``` + +and this to your crate root: + +```rust +extern crate getopts; +``` diff --git a/src/vendor/getopts/appveyor.yml b/src/vendor/getopts/appveyor.yml new file mode 100644 index 000000000000..6a1b8dc19c03 --- /dev/null +++ b/src/vendor/getopts/appveyor.yml @@ -0,0 +1,17 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose diff --git a/src/vendor/getopts/src/lib.rs b/src/vendor/getopts/src/lib.rs new file mode 100644 index 000000000000..8f0c866fae90 --- /dev/null +++ b/src/vendor/getopts/src/lib.rs @@ -0,0 +1,1831 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// ignore-lexer-test FIXME #15677 + +//! Simple getopt alternative. +//! +//! Construct a vector of options, either by using `reqopt`, `optopt`, and +//! `optflag` or by building them from components yourself, and pass them to +//! `getopts`, along with a vector of actual arguments (not including +//! `argv[0]`). You'll either get a failure code back, or a match. You'll have +//! to verify whether the amount of 'free' arguments in the match is what you +//! expect. Use `opt_*` accessors to get argument values out of the matches +//! object. +//! +//! Single-character options are expected to appear on the command line with a +//! single preceding dash; multiple-character options are expected to be +//! proceeded by two dashes. Options that expect an argument accept their +//! argument following either a space or an equals sign. Single-character +//! options don't require the space. +//! +//! # Usage +//! +//! This crate is [on crates.io](https://crates.io/crates/getopts) and can be +//! used by adding `getopts` to the dependencies in your project's `Cargo.toml`. +//! +//! ```toml +//! [dependencies] +//! getopts = "0.2" +//! ``` +//! +//! and this to your crate root: +//! +//! ```rust +//! extern crate getopts; +//! ``` +//! +//! # Example +//! +//! The following example shows simple command line parsing for an application +//! that requires an input file to be specified, accepts an optional output file +//! name following `-o`, and accepts both `-h` and `--help` as optional flags. +//! +//! ```{.rust} +//! extern crate getopts; +//! use getopts::Options; +//! use std::env; +//! +//! fn do_work(inp: &str, out: Option) { +//! println!("{}", inp); +//! match out { +//! Some(x) => println!("{}", x), +//! None => println!("No Output"), +//! } +//! } +//! +//! fn print_usage(program: &str, opts: Options) { +//! let brief = format!("Usage: {} FILE [options]", program); +//! print!("{}", opts.usage(&brief)); +//! } +//! +//! fn main() { +//! let args: Vec = env::args().collect(); +//! let program = args[0].clone(); +//! +//! let mut opts = Options::new(); +//! opts.optopt("o", "", "set output file name", "NAME"); +//! opts.optflag("h", "help", "print this help menu"); +//! let matches = match opts.parse(&args[1..]) { +//! Ok(m) => { m } +//! Err(f) => { panic!(f.to_string()) } +//! }; +//! if matches.opt_present("h") { +//! print_usage(&program, opts); +//! return; +//! } +//! let output = matches.opt_str("o"); +//! let input = if !matches.free.is_empty() { +//! matches.free[0].clone() +//! } else { +//! print_usage(&program, opts); +//! return; +//! }; +//! do_work(&input, output); +//! } +//! ``` + +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/getopts/")] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] +#![cfg_attr(rust_build, feature(staged_api))] +#![cfg_attr(rust_build, staged_api)] +#![cfg_attr(rust_build, + unstable(feature = "rustc_private", + reason = "use the crates.io `getopts` library instead"))] + +#[cfg(test)] #[macro_use] extern crate log; + +use self::Name::*; +use self::HasArg::*; +use self::Occur::*; +use self::Fail::*; +use self::Optval::*; +use self::SplitWithinState::*; +use self::Whitespace::*; +use self::LengthLimit::*; + +use std::error::Error; +use std::ffi::OsStr; +use std::fmt; +use std::iter::{repeat, IntoIterator}; +use std::result; + +/// A description of the options that a program can handle. +pub struct Options { + grps: Vec, + parsing_style : ParsingStyle +} + +impl Options { + /// Create a blank set of options. + pub fn new() -> Options { + Options { + grps: Vec::new(), + parsing_style: ParsingStyle::FloatingFrees + } + } + + /// Set the parsing style. + pub fn parsing_style(&mut self, style: ParsingStyle) -> &mut Options { + self.parsing_style = style; + self + } + + /// Create a generic option group, stating all parameters explicitly. + pub fn opt(&mut self, short_name: &str, long_name: &str, desc: &str, + hint: &str, hasarg: HasArg, occur: Occur) -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: hint.to_string(), + desc: desc.to_string(), + hasarg: hasarg, + occur: occur + }); + self + } + + /// Create a long option that is optional and does not take an argument. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str) + -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: "".to_string(), + desc: desc.to_string(), + hasarg: No, + occur: Optional + }); + self + } + + /// Create a long option that can occur more than once and does not + /// take an argument. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + pub fn optflagmulti(&mut self, short_name: &str, long_name: &str, desc: &str) + -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: "".to_string(), + desc: desc.to_string(), + hasarg: No, + occur: Multi + }); + self + } + + /// Create a long option that is optional and takes an optional argument. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + /// * `hint` - Hint that is used in place of the argument in the usage help, + /// e.g. `"FILE"` for a `-o FILE` option + pub fn optflagopt(&mut self, short_name: &str, long_name: &str, desc: &str, + hint: &str) -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: hint.to_string(), + desc: desc.to_string(), + hasarg: Maybe, + occur: Optional + }); + self + } + + /// Create a long option that is optional, takes an argument, and may occur + /// multiple times. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + /// * `hint` - Hint that is used in place of the argument in the usage help, + /// e.g. `"FILE"` for a `-o FILE` option + pub fn optmulti(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) + -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: hint.to_string(), + desc: desc.to_string(), + hasarg: Yes, + occur: Multi + }); + self + } + + /// Create a long option that is optional and takes an argument. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + /// * `hint` - Hint that is used in place of the argument in the usage help, + /// e.g. `"FILE"` for a `-o FILE` option + pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) + -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: hint.to_string(), + desc: desc.to_string(), + hasarg: Yes, + occur: Optional + }); + self + } + + /// Create a long option that is required and takes an argument. + /// + /// * `short_name` - e.g. `"h"` for a `-h` option, or `""` for none + /// * `long_name` - e.g. `"help"` for a `--help` option, or `""` for none + /// * `desc` - Description for usage help + /// * `hint` - Hint that is used in place of the argument in the usage help, + /// e.g. `"FILE"` for a `-o FILE` option + pub fn reqopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) + -> &mut Options { + let len = short_name.len(); + assert!(len == 1 || len == 0); + self.grps.push(OptGroup { + short_name: short_name.to_string(), + long_name: long_name.to_string(), + hint: hint.to_string(), + desc: desc.to_string(), + hasarg: Yes, + occur: Req + }); + self + } + + /// Parse command line arguments according to the provided options. + /// + /// On success returns `Ok(Matches)`. Use methods such as `opt_present` + /// `opt_str`, etc. to interrogate results. + /// # Panics + /// + /// Returns `Err(Fail)` on failure: use the `Debug` implementation of `Fail` + /// to display information about it. + pub fn parse(&self, args: C) -> Result + where C::Item: AsRef + { + let opts: Vec = self.grps.iter().map(|x| x.long_to_short()).collect(); + let n_opts = opts.len(); + + fn f(_x: usize) -> Vec { return Vec::new(); } + + let mut vals = (0 .. n_opts).map(f).collect::>(); + let mut free: Vec = Vec::new(); + let args = try!(args.into_iter().map(|i| { + i.as_ref().to_str().ok_or_else(|| { + Fail::UnrecognizedOption(format!("{:?}", i.as_ref())) + }).map(|s| s.to_owned()) + }).collect::<::std::result::Result, _>>()); + let l = args.len(); + let mut i = 0; + while i < l { + let cur = args[i].clone(); + let curlen = cur.len(); + if !is_arg(&cur) { + match self.parsing_style { + ParsingStyle::FloatingFrees => free.push(cur), + ParsingStyle::StopAtFirstFree => { + while i < l { + free.push(args[i].clone()); + i += 1; + } + break; + } + } + } else if cur == "--" { + let mut j = i + 1; + while j < l { free.push(args[j].clone()); j += 1; } + break; + } else { + let mut names; + let mut i_arg = None; + if cur.as_bytes()[1] == b'-' { + let tail = &cur[2..curlen]; + let tail_eq: Vec<&str> = tail.splitn(2, '=').collect(); + if tail_eq.len() <= 1 { + names = vec!(Long(tail.to_string())); + } else { + names = + vec!(Long(tail_eq[0].to_string())); + i_arg = Some(tail_eq[1].to_string()); + } + } else { + names = Vec::new(); + for (j, ch) in cur.char_indices().skip(1) { + let opt = Short(ch); + + /* In a series of potential options (eg. -aheJ), if we + see one which takes an argument, we assume all + subsequent characters make up the argument. This + allows options such as -L/usr/local/lib/foo to be + interpreted correctly + */ + + let opt_id = match find_opt(&opts, opt.clone()) { + Some(id) => id, + None => return Err(UnrecognizedOption(opt.to_string())) + }; + + names.push(opt); + + let arg_follows = match opts[opt_id].hasarg { + Yes | Maybe => true, + No => false + }; + + if arg_follows { + let next = j + ch.len_utf8(); + if next < curlen { + i_arg = Some(cur[next..curlen].to_string()); + break; + } + } + } + } + let mut name_pos = 0; + for nm in names.iter() { + name_pos += 1; + let optid = match find_opt(&opts, (*nm).clone()) { + Some(id) => id, + None => return Err(UnrecognizedOption(nm.to_string())) + }; + match opts[optid].hasarg { + No => { + if name_pos == names.len() && !i_arg.is_none() { + return Err(UnexpectedArgument(nm.to_string())); + } + vals[optid].push(Given); + } + Maybe => { + if !i_arg.is_none() { + vals[optid] + .push(Val((i_arg.clone()) + .unwrap())); + } else if name_pos < names.len() || i + 1 == l || + is_arg(&args[i + 1]) { + vals[optid].push(Given); + } else { + i += 1; + vals[optid].push(Val(args[i].clone())); + } + } + Yes => { + if !i_arg.is_none() { + vals[optid].push(Val(i_arg.clone().unwrap())); + } else if i + 1 == l { + return Err(ArgumentMissing(nm.to_string())); + } else { + i += 1; + vals[optid].push(Val(args[i].clone())); + } + } + } + } + } + i += 1; + } + for i in 0 .. n_opts { + let n = vals[i].len(); + let occ = opts[i].occur; + if occ == Req && n == 0 { + return Err(OptionMissing(opts[i].name.to_string())); + } + if occ != Multi && n > 1 { + return Err(OptionDuplicated(opts[i].name.to_string())); + } + } + Ok(Matches { + opts: opts, + vals: vals, + free: free + }) + } + + /// Derive a short one-line usage summary from a set of long options. + #[allow(deprecated)] // connect => join in 1.3 + pub fn short_usage(&self, program_name: &str) -> String { + let mut line = format!("Usage: {} ", program_name); + line.push_str(&self.grps.iter() + .map(format_option) + .collect::>() + .connect(" ")); + line + } + + /// Derive a usage message from a set of options. + #[allow(deprecated)] // connect => join in 1.3 + pub fn usage(&self, brief: &str) -> String { + let desc_sep = format!("\n{}", repeat(" ").take(24).collect::()); + + let any_short = self.grps.iter().any(|optref| { + optref.short_name.len() > 0 + }); + + let rows = self.grps.iter().map(|optref| { + let OptGroup{short_name, + long_name, + hint, + desc, + hasarg, + ..} = (*optref).clone(); + + let mut row = " ".to_string(); + + // short option + match short_name.len() { + 0 => { + if any_short { + row.push_str(" "); + } + } + 1 => { + row.push('-'); + row.push_str(&short_name); + if long_name.len() > 0 { + row.push_str(", "); + } else { + // Only a single space here, so that any + // argument is printed in the correct spot. + row.push(' '); + } + } + _ => panic!("the short name should only be 1 ascii char long"), + } + + // long option + match long_name.len() { + 0 => {} + _ => { + row.push_str("--"); + row.push_str(&long_name); + row.push(' '); + } + } + + // arg + match hasarg { + No => {} + Yes => row.push_str(&hint), + Maybe => { + row.push('['); + row.push_str(&hint); + row.push(']'); + } + } + + // FIXME: #5516 should be graphemes not codepoints + // here we just need to indent the start of the description + let rowlen = row.chars().count(); + if rowlen < 24 { + for _ in 0 .. 24 - rowlen { + row.push(' '); + } + } else { + row.push_str(&desc_sep) + } + + // Normalize desc to contain words separated by one space character + let mut desc_normalized_whitespace = String::new(); + for word in desc.split(|c: char| c.is_whitespace()) + .filter(|s| !s.is_empty()) { + desc_normalized_whitespace.push_str(word); + desc_normalized_whitespace.push(' '); + } + + // FIXME: #5516 should be graphemes not codepoints + let mut desc_rows = Vec::new(); + each_split_within(&desc_normalized_whitespace, + 54, + |substr| { + desc_rows.push(substr.to_string()); + true + }); + + // FIXME: #5516 should be graphemes not codepoints + // wrapped description + row.push_str(&desc_rows.connect(&desc_sep)); + + row + }); + + format!("{}\n\nOptions:\n{}\n", brief, + rows.collect::>().connect("\n")) + } +} + +/// What parsing style to use when parsing arguments. +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum ParsingStyle { + /// Flags and "free" arguments can be freely inter-mixed. + FloatingFrees, + /// As soon as a "free" argument (i.e. non-flag) is encountered, stop + /// considering any remaining arguments as flags. + StopAtFirstFree +} + +/// Name of an option. Either a string or a single char. +#[derive(Clone, PartialEq, Eq)] +enum Name { + /// A string representing the long name of an option. + /// For example: "help" + Long(String), + /// A char representing the short name of an option. + /// For example: 'h' + Short(char), +} + +/// Describes whether an option has an argument. +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum HasArg { + /// The option requires an argument. + Yes, + /// The option takes no argument. + No, + /// The option argument is optional. + Maybe, +} + +/// Describes how often an option may occur. +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum Occur { + /// The option occurs once. + Req, + /// The option occurs at most once. + Optional, + /// The option occurs zero or more times. + Multi, +} + +/// A description of a possible option. +#[derive(Clone, PartialEq, Eq)] +struct Opt { + /// Name of the option + name: Name, + /// Whether it has an argument + hasarg: HasArg, + /// How often it can occur + occur: Occur, + /// Which options it aliases + aliases: Vec, +} + +/// One group of options, e.g., both `-h` and `--help`, along with +/// their shared description and properties. +#[derive(Clone, PartialEq, Eq)] +struct OptGroup { + /// Short name of the option, e.g. `h` for a `-h` option + short_name: String, + /// Long name of the option, e.g. `help` for a `--help` option + long_name: String, + /// Hint for argument, e.g. `FILE` for a `-o FILE` option + hint: String, + /// Description for usage help text + desc: String, + /// Whether option has an argument + hasarg: HasArg, + /// How often it can occur + occur: Occur +} + +/// Describes whether an option is given at all or has a value. +#[derive(Clone, PartialEq, Eq)] +enum Optval { + Val(String), + Given, +} + +/// The result of checking command line arguments. Contains a vector +/// of matches and a vector of free strings. +#[derive(Clone, PartialEq, Eq)] +pub struct Matches { + /// Options that matched + opts: Vec, + /// Values of the Options that matched + vals: Vec>, + /// Free string fragments + pub free: Vec, +} + +/// The type returned when the command line does not conform to the +/// expected format. Use the `Debug` implementation to output detailed +/// information. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Fail { + /// The option requires an argument but none was passed. + ArgumentMissing(String), + /// The passed option is not declared among the possible options. + UnrecognizedOption(String), + /// A required option is not present. + OptionMissing(String), + /// A single occurrence option is being used multiple times. + OptionDuplicated(String), + /// There's an argument being passed to a non-argument option. + UnexpectedArgument(String), +} + +impl Error for Fail { + fn description(&self) -> &str { + match *self { + ArgumentMissing(_) => "missing argument", + UnrecognizedOption(_) => "unrecognized option", + OptionMissing(_) => "missing option", + OptionDuplicated(_) => "duplicated option", + UnexpectedArgument(_) => "unexpected argument", + } + } +} + +/// The type of failure that occurred. +#[derive(Clone, Copy, PartialEq, Eq)] +#[allow(missing_docs)] +pub enum FailType { + ArgumentMissing_, + UnrecognizedOption_, + OptionMissing_, + OptionDuplicated_, + UnexpectedArgument_, +} + +/// The result of parsing a command line with a set of options. +pub type Result = result::Result; + +impl Name { + fn from_str(nm: &str) -> Name { + if nm.len() == 1 { + Short(nm.as_bytes()[0] as char) + } else { + Long(nm.to_string()) + } + } + + fn to_string(&self) -> String { + match *self { + Short(ch) => ch.to_string(), + Long(ref s) => s.to_string() + } + } +} + +impl OptGroup { + /// Translate OptGroup into Opt. + /// (Both short and long names correspond to different Opts). + fn long_to_short(&self) -> Opt { + let OptGroup { + short_name, + long_name, + hasarg, + occur, + .. + } = (*self).clone(); + + match (short_name.len(), long_name.len()) { + (0,0) => panic!("this long-format option was given no name"), + (0,_) => Opt { + name: Long((long_name)), + hasarg: hasarg, + occur: occur, + aliases: Vec::new() + }, + (1,0) => Opt { + name: Short(short_name.as_bytes()[0] as char), + hasarg: hasarg, + occur: occur, + aliases: Vec::new() + }, + (1,_) => Opt { + name: Long((long_name)), + hasarg: hasarg, + occur: occur, + aliases: vec!( + Opt { + name: Short(short_name.as_bytes()[0] as char), + hasarg: hasarg, + occur: occur, + aliases: Vec::new() + } + ) + }, + (_,_) => panic!("something is wrong with the long-form opt") + } + } +} + +impl Matches { + fn opt_vals(&self, nm: &str) -> Vec { + match find_opt(&self.opts, Name::from_str(nm)) { + Some(id) => self.vals[id].clone(), + None => panic!("No option '{}' defined", nm) + } + } + + fn opt_val(&self, nm: &str) -> Option { + self.opt_vals(nm).into_iter().next() + } + + /// Returns true if an option was matched. + pub fn opt_present(&self, nm: &str) -> bool { + !self.opt_vals(nm).is_empty() + } + + /// Returns the number of times an option was matched. + pub fn opt_count(&self, nm: &str) -> usize { + self.opt_vals(nm).len() + } + + /// Returns true if any of several options were matched. + pub fn opts_present(&self, names: &[String]) -> bool { + names.iter().any(|nm| { + match find_opt(&self.opts, Name::from_str(&nm)) { + Some(id) if !self.vals[id].is_empty() => true, + _ => false, + } + }) + } + + /// Returns the string argument supplied to one of several matching options or `None`. + pub fn opts_str(&self, names: &[String]) -> Option { + names.iter().filter_map(|nm| { + match self.opt_val(&nm) { + Some(Val(s)) => Some(s), + _ => None, + } + }).next() + } + + /// Returns a vector of the arguments provided to all matches of the given + /// option. + /// + /// Used when an option accepts multiple values. + pub fn opt_strs(&self, nm: &str) -> Vec { + self.opt_vals(nm).into_iter().filter_map(|v| { + match v { + Val(s) => Some(s), + _ => None, + } + }).collect() + } + + /// Returns the string argument supplied to a matching option or `None`. + pub fn opt_str(&self, nm: &str) -> Option { + match self.opt_val(nm) { + Some(Val(s)) => Some(s), + _ => None, + } + } + + + /// Returns the matching string, a default, or `None`. + /// + /// Returns `None` if the option was not present, `def` if the option was + /// present but no argument was provided, and the argument if the option was + /// present and an argument was provided. + pub fn opt_default(&self, nm: &str, def: &str) -> Option { + match self.opt_val(nm) { + Some(Val(s)) => Some(s), + Some(_) => Some(def.to_string()), + None => None, + } + } + +} + +fn is_arg(arg: &str) -> bool { + arg.as_bytes().get(0) == Some(&b'-') && arg.len() > 1 +} + +fn find_opt(opts: &[Opt], nm: Name) -> Option { + // Search main options. + let pos = opts.iter().position(|opt| opt.name == nm); + if pos.is_some() { + return pos + } + + // Search in aliases. + for candidate in opts.iter() { + if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() { + return opts.iter().position(|opt| opt.name == candidate.name); + } + } + + None +} + +impl fmt::Display for Fail { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + ArgumentMissing(ref nm) => { + write!(f, "Argument to option '{}' missing.", *nm) + } + UnrecognizedOption(ref nm) => { + write!(f, "Unrecognized option: '{}'.", *nm) + } + OptionMissing(ref nm) => { + write!(f, "Required option '{}' missing.", *nm) + } + OptionDuplicated(ref nm) => { + write!(f, "Option '{}' given more than once.", *nm) + } + UnexpectedArgument(ref nm) => { + write!(f, "Option '{}' does not take an argument.", *nm) + } + } + } +} + +fn format_option(opt: &OptGroup) -> String { + let mut line = String::new(); + + if opt.occur != Req { + line.push('['); + } + + // Use short_name if possible, but fall back to long_name. + if opt.short_name.len() > 0 { + line.push('-'); + line.push_str(&opt.short_name); + } else { + line.push_str("--"); + line.push_str(&opt.long_name); + } + + if opt.hasarg != No { + line.push(' '); + if opt.hasarg == Maybe { + line.push('['); + } + line.push_str(&opt.hint); + if opt.hasarg == Maybe { + line.push(']'); + } + } + + if opt.occur != Req { + line.push(']'); + } + if opt.occur == Multi { + line.push_str(".."); + } + + line +} + +#[derive(Clone, Copy)] +enum SplitWithinState { + A, // leading whitespace, initial state + B, // words + C, // internal and trailing whitespace +} + +#[derive(Clone, Copy)] +enum Whitespace { + Ws, // current char is whitespace + Cr // current char is not whitespace +} + +#[derive(Clone, Copy)] +enum LengthLimit { + UnderLim, // current char makes current substring still fit in limit + OverLim // current char makes current substring no longer fit in limit +} + + +/// Splits a string into substrings with possibly internal whitespace, +/// each of them at most `lim` bytes long. The substrings have leading and trailing +/// whitespace removed, and are only cut at whitespace boundaries. +/// +/// Note: Function was moved here from `std::str` because this module is the only place that +/// uses it, and because it was too specific for a general string function. +/// +/// # Panics +/// +/// Panics during iteration if the string contains a non-whitespace +/// sequence longer than the limit. +fn each_split_within<'a, F>(ss: &'a str, lim: usize, mut it: F) + -> bool where F: FnMut(&'a str) -> bool { + // Just for fun, let's write this as a state machine: + + let mut slice_start = 0; + let mut last_start = 0; + let mut last_end = 0; + let mut state = A; + let mut fake_i = ss.len(); + let mut lim = lim; + + let mut cont = true; + + // if the limit is larger than the string, lower it to save cycles + if lim >= fake_i { + lim = fake_i; + } + + let mut machine = |cont: &mut bool, (i, c): (usize, char)| { + let whitespace = if c.is_whitespace() { Ws } else { Cr }; + let limit = if (i - slice_start + 1) <= lim { UnderLim } else { OverLim }; + + state = match (state, whitespace, limit) { + (A, Ws, _) => { A } + (A, Cr, _) => { slice_start = i; last_start = i; B } + + (B, Cr, UnderLim) => { B } + (B, Cr, OverLim) if (i - last_start + 1) > lim + => panic!("word starting with {} longer than limit!", + &ss[last_start..i + 1]), + (B, Cr, OverLim) => { + *cont = it(&ss[slice_start..last_end]); + slice_start = last_start; + B + } + (B, Ws, UnderLim) => { + last_end = i; + C + } + (B, Ws, OverLim) => { + last_end = i; + *cont = it(&ss[slice_start..last_end]); + A + } + + (C, Cr, UnderLim) => { + last_start = i; + B + } + (C, Cr, OverLim) => { + *cont = it(&ss[slice_start..last_end]); + slice_start = i; + last_start = i; + last_end = i; + B + } + (C, Ws, OverLim) => { + *cont = it(&ss[slice_start..last_end]); + A + } + (C, Ws, UnderLim) => { + C + } + }; + + *cont + }; + + ss.char_indices().all(|x| machine(&mut cont, x)); + + // Let the automaton 'run out' by supplying trailing whitespace + while cont && match state { B | C => true, A => false } { + machine(&mut cont, (fake_i, ' ')); + fake_i += 1; + } + return cont; +} + +#[test] +fn test_split_within() { + fn t(s: &str, i: usize, u: &[String]) { + let mut v = Vec::new(); + each_split_within(s, i, |s| { v.push(s.to_string()); true }); + assert!(v.iter().zip(u.iter()).all(|(a,b)| a == b)); + } + t("", 0, &[]); + t("", 15, &[]); + t("hello", 15, &["hello".to_string()]); + t("\nMary had a little lamb\nLittle lamb\n", 15, &[ + "Mary had a".to_string(), + "little lamb".to_string(), + "Little lamb".to_string() + ]); + t("\nMary had a little lamb\nLittle lamb\n", ::std::usize::MAX, + &["Mary had a little lamb\nLittle lamb".to_string()]); +} + +#[cfg(test)] +mod tests { + use super::{HasArg, Name, Occur, Opt, Options, ParsingStyle}; + use super::Fail::*; + + // Tests for reqopt + #[test] + fn test_reqopt() { + let long_args = vec!("--test=20".to_string()); + let mut opts = Options::new(); + opts.reqopt("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { + Ok(ref m) => { + assert!(m.opt_present("test")); + assert_eq!(m.opt_str("test").unwrap(), "20"); + assert!(m.opt_present("t")); + assert_eq!(m.opt_str("t").unwrap(), "20"); + } + _ => { panic!("test_reqopt failed (long arg)"); } + } + let short_args = vec!("-t".to_string(), "20".to_string()); + match opts.parse(&short_args) { + Ok(ref m) => { + assert!((m.opt_present("test"))); + assert_eq!(m.opt_str("test").unwrap(), "20"); + assert!((m.opt_present("t"))); + assert_eq!(m.opt_str("t").unwrap(), "20"); + } + _ => { panic!("test_reqopt failed (short arg)"); } + } + } + + #[test] + fn test_reqopt_missing() { + let args = vec!("blah".to_string()); + match Options::new() + .reqopt("t", "test", "testing", "TEST") + .parse(&args) { + Err(OptionMissing(_)) => {}, + _ => panic!() + } + } + + #[test] + fn test_reqopt_no_arg() { + let long_args = vec!("--test".to_string()); + let mut opts = Options::new(); + opts.reqopt("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { + Err(ArgumentMissing(_)) => {}, + _ => panic!() + } + let short_args = vec!("-t".to_string()); + match opts.parse(&short_args) { + Err(ArgumentMissing(_)) => {}, + _ => panic!() + } + } + + #[test] + fn test_reqopt_multi() { + let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string()); + match Options::new() + .reqopt("t", "test", "testing", "TEST") + .parse(&args) { + Err(OptionDuplicated(_)) => {}, + _ => panic!() + } + } + + // Tests for optopt + #[test] + fn test_optopt() { + let long_args = vec!("--test=20".to_string()); + let mut opts = Options::new(); + opts.optopt("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { + Ok(ref m) => { + assert!(m.opt_present("test")); + assert_eq!(m.opt_str("test").unwrap(), "20"); + assert!((m.opt_present("t"))); + assert_eq!(m.opt_str("t").unwrap(), "20"); + } + _ => panic!() + } + let short_args = vec!("-t".to_string(), "20".to_string()); + match opts.parse(&short_args) { + Ok(ref m) => { + assert!((m.opt_present("test"))); + assert_eq!(m.opt_str("test").unwrap(), "20"); + assert!((m.opt_present("t"))); + assert_eq!(m.opt_str("t").unwrap(), "20"); + } + _ => panic!() + } + } + + #[test] + fn test_optopt_missing() { + let args = vec!("blah".to_string()); + match Options::new() + .optopt("t", "test", "testing", "TEST") + .parse(&args) { + Ok(ref m) => { + assert!(!m.opt_present("test")); + assert!(!m.opt_present("t")); + } + _ => panic!() + } + } + + #[test] + fn test_optopt_no_arg() { + let long_args = vec!("--test".to_string()); + let mut opts = Options::new(); + opts.optopt("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { + Err(ArgumentMissing(_)) => {}, + _ => panic!() + } + let short_args = vec!("-t".to_string()); + match opts.parse(&short_args) { + Err(ArgumentMissing(_)) => {}, + _ => panic!() + } + } + + #[test] + fn test_optopt_multi() { + let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string()); + match Options::new() + .optopt("t", "test", "testing", "TEST") + .parse(&args) { + Err(OptionDuplicated(_)) => {}, + _ => panic!() + } + } + + // Tests for optflag + #[test] + fn test_optflag() { + let long_args = vec!("--test".to_string()); + let mut opts = Options::new(); + opts.optflag("t", "test", "testing"); + match opts.parse(&long_args) { + Ok(ref m) => { + assert!(m.opt_present("test")); + assert!(m.opt_present("t")); + } + _ => panic!() + } + let short_args = vec!("-t".to_string()); + match opts.parse(&short_args) { + Ok(ref m) => { + assert!(m.opt_present("test")); + assert!(m.opt_present("t")); + } + _ => panic!() + } + } + + #[test] + fn test_optflag_missing() { + let args = vec!("blah".to_string()); + match Options::new() + .optflag("t", "test", "testing") + .parse(&args) { + Ok(ref m) => { + assert!(!m.opt_present("test")); + assert!(!m.opt_present("t")); + } + _ => panic!() + } + } + + #[test] + fn test_optflag_long_arg() { + let args = vec!("--test=20".to_string()); + match Options::new() + .optflag("t", "test", "testing") + .parse(&args) { + Err(UnexpectedArgument(_)) => {}, + _ => panic!() + } + } + + #[test] + fn test_optflag_multi() { + let args = vec!("--test".to_string(), "-t".to_string()); + match Options::new() + .optflag("t", "test", "testing") + .parse(&args) { + Err(OptionDuplicated(_)) => {}, + _ => panic!() + } + } + + #[test] + fn test_optflag_short_arg() { + let args = vec!("-t".to_string(), "20".to_string()); + match Options::new() + .optflag("t", "test", "testing") + .parse(&args) { + Ok(ref m) => { + // The next variable after the flag is just a free argument + + assert!(m.free[0] == "20"); + } + _ => panic!() + } + } + + // Tests for optflagmulti + #[test] + fn test_optflagmulti_short1() { + let args = vec!("-v".to_string()); + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { + Ok(ref m) => { + assert_eq!(m.opt_count("v"), 1); + } + _ => panic!() + } + } + + #[test] + fn test_optflagmulti_short2a() { + let args = vec!("-v".to_string(), "-v".to_string()); + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { + Ok(ref m) => { + assert_eq!(m.opt_count("v"), 2); + } + _ => panic!() + } + } + + #[test] + fn test_optflagmulti_short2b() { + let args = vec!("-vv".to_string()); + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { + Ok(ref m) => { + assert_eq!(m.opt_count("v"), 2); + } + _ => panic!() + } + } + + #[test] + fn test_optflagmulti_long1() { + let args = vec!("--verbose".to_string()); + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { + Ok(ref m) => { + assert_eq!(m.opt_count("verbose"), 1); + } + _ => panic!() + } + } + + #[test] + fn test_optflagmulti_long2() { + let args = vec!("--verbose".to_string(), "--verbose".to_string()); + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { + Ok(ref m) => { + assert_eq!(m.opt_count("verbose"), 2); + } + _ => panic!() + } + } + + #[test] + fn test_optflagmulti_mix() { + let args = vec!("--verbose".to_string(), "-v".to_string(), + "-vv".to_string(), "verbose".to_string()); + match Options::new() + .optflagmulti("v", "verbose", "verbosity") + .parse(&args) { + Ok(ref m) => { + assert_eq!(m.opt_count("verbose"), 4); + assert_eq!(m.opt_count("v"), 4); + } + _ => panic!() + } + } + + // Tests for optflagopt + #[test] + fn test_optflagopt() { + let long_args = vec!("--test".to_string()); + let mut opts = Options::new(); + opts.optflag("t", "test", "testing"); + match opts.parse(&long_args) { + Ok(ref m) => { + assert!(m.opt_present("test")); + assert!(m.opt_present("t")); + } + _ => panic!() + } + let short_args = vec!("-t".to_string()); + match opts.parse(&short_args) { + Ok(ref m) => { + assert!(m.opt_present("test")); + assert!(m.opt_present("t")); + } + _ => panic!() + } + let no_args: Vec = vec!(); + match opts.parse(&no_args) { + Ok(ref m) => { + assert!(!m.opt_present("test")); + assert!(!m.opt_present("t")); + } + _ => panic!() + } + } + + // Tests for optmulti + #[test] + fn test_optmulti() { + let long_args = vec!("--test=20".to_string()); + let mut opts = Options::new(); + opts.optmulti("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { + Ok(ref m) => { + assert!((m.opt_present("test"))); + assert_eq!(m.opt_str("test").unwrap(), "20"); + assert!((m.opt_present("t"))); + assert_eq!(m.opt_str("t").unwrap(), "20"); + } + _ => panic!() + } + let short_args = vec!("-t".to_string(), "20".to_string()); + match opts.parse(&short_args) { + Ok(ref m) => { + assert!((m.opt_present("test"))); + assert_eq!(m.opt_str("test").unwrap(), "20"); + assert!((m.opt_present("t"))); + assert_eq!(m.opt_str("t").unwrap(), "20"); + } + _ => panic!() + } + } + + #[test] + fn test_optmulti_missing() { + let args = vec!("blah".to_string()); + match Options::new() + .optmulti("t", "test", "testing", "TEST") + .parse(&args) { + Ok(ref m) => { + assert!(!m.opt_present("test")); + assert!(!m.opt_present("t")); + } + _ => panic!() + } + } + + #[test] + fn test_optmulti_no_arg() { + let long_args = vec!("--test".to_string()); + let mut opts = Options::new(); + opts.optmulti("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { + Err(ArgumentMissing(_)) => {}, + _ => panic!() + } + let short_args = vec!("-t".to_string()); + match opts.parse(&short_args) { + Err(ArgumentMissing(_)) => {}, + _ => panic!() + } + } + + #[test] + fn test_optmulti_multi() { + let args = vec!("--test=20".to_string(), "-t".to_string(), "30".to_string()); + match Options::new() + .optmulti("t", "test", "testing", "TEST") + .parse(&args) { + Ok(ref m) => { + assert!(m.opt_present("test")); + assert_eq!(m.opt_str("test").unwrap(), "20"); + assert!(m.opt_present("t")); + assert_eq!(m.opt_str("t").unwrap(), "20"); + let pair = m.opt_strs("test"); + assert!(pair[0] == "20"); + assert!(pair[1] == "30"); + } + _ => panic!() + } + } + + #[test] + fn test_free_argument_is_hyphen() { + let args = vec!("-".to_string()); + match Options::new().parse(&args) { + Ok(ref m) => { + assert_eq!(m.free.len(), 1); + assert_eq!(m.free[0], "-"); + } + _ => panic!() + } + } + + #[test] + fn test_unrecognized_option() { + let long_args = vec!("--untest".to_string()); + let mut opts = Options::new(); + opts.optmulti("t", "test", "testing", "TEST"); + match opts.parse(&long_args) { + Err(UnrecognizedOption(_)) => {}, + _ => panic!() + } + let short_args = vec!("-u".to_string()); + match opts.parse(&short_args) { + Err(UnrecognizedOption(_)) => {}, + _ => panic!() + } + } + + #[test] + fn test_combined() { + let args = + vec!("prog".to_string(), + "free1".to_string(), + "-s".to_string(), + "20".to_string(), + "free2".to_string(), + "--flag".to_string(), + "--long=30".to_string(), + "-f".to_string(), + "-m".to_string(), + "40".to_string(), + "-m".to_string(), + "50".to_string(), + "-n".to_string(), + "-A B".to_string(), + "-n".to_string(), + "-60 70".to_string()); + match Options::new() + .optopt("s", "something", "something", "SOMETHING") + .optflag("", "flag", "a flag") + .reqopt("", "long", "hi", "LONG") + .optflag("f", "", "another flag") + .optmulti("m", "", "mmmmmm", "YUM") + .optmulti("n", "", "nothing", "NOTHING") + .optopt("", "notpresent", "nothing to see here", "NOPE") + .parse(&args) { + Ok(ref m) => { + assert!(m.free[0] == "prog"); + assert!(m.free[1] == "free1"); + assert_eq!(m.opt_str("s").unwrap(), "20"); + assert!(m.free[2] == "free2"); + assert!((m.opt_present("flag"))); + assert_eq!(m.opt_str("long").unwrap(), "30"); + assert!((m.opt_present("f"))); + let pair = m.opt_strs("m"); + assert!(pair[0] == "40"); + assert!(pair[1] == "50"); + let pair = m.opt_strs("n"); + assert!(pair[0] == "-A B"); + assert!(pair[1] == "-60 70"); + assert!((!m.opt_present("notpresent"))); + } + _ => panic!() + } + } + + #[test] + fn test_mixed_stop() { + let args = + vec!("-a".to_string(), + "b".to_string(), + "-c".to_string(), + "d".to_string()); + match Options::new() + .parsing_style(ParsingStyle::StopAtFirstFree) + .optflag("a", "", "") + .optopt("c", "", "", "") + .parse(&args) { + Ok(ref m) => { + println!("{}", m.opt_present("c")); + assert!(m.opt_present("a")); + assert!(!m.opt_present("c")); + assert_eq!(m.free.len(), 3); + assert_eq!(m.free[0], "b"); + assert_eq!(m.free[1], "-c"); + assert_eq!(m.free[2], "d"); + } + _ => panic!() + } + } + + #[test] + fn test_mixed_stop_hyphen() { + let args = + vec!("-a".to_string(), + "-".to_string(), + "-c".to_string(), + "d".to_string()); + match Options::new() + .parsing_style(ParsingStyle::StopAtFirstFree) + .optflag("a", "", "") + .optopt("c", "", "", "") + .parse(&args) { + Ok(ref m) => { + println!("{}", m.opt_present("c")); + assert!(m.opt_present("a")); + assert!(!m.opt_present("c")); + assert_eq!(m.free.len(), 3); + assert_eq!(m.free[0], "-"); + assert_eq!(m.free[1], "-c"); + assert_eq!(m.free[2], "d"); + } + _ => panic!() + } + } + + #[test] + fn test_multi() { + let mut opts = Options::new(); + opts.optopt("e", "", "encrypt", "ENCRYPT"); + opts.optopt("", "encrypt", "encrypt", "ENCRYPT"); + opts.optopt("f", "", "flag", "FLAG"); + + let args_single = vec!("-e".to_string(), "foo".to_string()); + let matches_single = &match opts.parse(&args_single) { + Ok(m) => m, + Err(_) => panic!() + }; + assert!(matches_single.opts_present(&["e".to_string()])); + assert!(matches_single.opts_present(&["encrypt".to_string(), "e".to_string()])); + assert!(matches_single.opts_present(&["e".to_string(), "encrypt".to_string()])); + assert!(!matches_single.opts_present(&["encrypt".to_string()])); + assert!(!matches_single.opts_present(&["thing".to_string()])); + assert!(!matches_single.opts_present(&[])); + + assert_eq!(matches_single.opts_str(&["e".to_string()]).unwrap(), "foo"); + assert_eq!(matches_single.opts_str(&["e".to_string(), "encrypt".to_string()]).unwrap(), + "foo"); + assert_eq!(matches_single.opts_str(&["encrypt".to_string(), "e".to_string()]).unwrap(), + "foo"); + + let args_both = vec!("-e".to_string(), "foo".to_string(), "--encrypt".to_string(), + "foo".to_string()); + let matches_both = &match opts.parse(&args_both) { + Ok(m) => m, + Err(_) => panic!() + }; + assert!(matches_both.opts_present(&["e".to_string()])); + assert!(matches_both.opts_present(&["encrypt".to_string()])); + assert!(matches_both.opts_present(&["encrypt".to_string(), "e".to_string()])); + assert!(matches_both.opts_present(&["e".to_string(), "encrypt".to_string()])); + assert!(!matches_both.opts_present(&["f".to_string()])); + assert!(!matches_both.opts_present(&["thing".to_string()])); + assert!(!matches_both.opts_present(&[])); + + assert_eq!(matches_both.opts_str(&["e".to_string()]).unwrap(), "foo"); + assert_eq!(matches_both.opts_str(&["encrypt".to_string()]).unwrap(), "foo"); + assert_eq!(matches_both.opts_str(&["e".to_string(), "encrypt".to_string()]).unwrap(), + "foo"); + assert_eq!(matches_both.opts_str(&["encrypt".to_string(), "e".to_string()]).unwrap(), + "foo"); + } + + #[test] + fn test_nospace() { + let args = vec!("-Lfoo".to_string(), "-M.".to_string()); + let matches = &match Options::new() + .optmulti("L", "", "library directory", "LIB") + .optmulti("M", "", "something", "MMMM") + .parse(&args) { + Ok(m) => m, + Err(_) => panic!() + }; + assert!(matches.opts_present(&["L".to_string()])); + assert_eq!(matches.opts_str(&["L".to_string()]).unwrap(), "foo"); + assert!(matches.opts_present(&["M".to_string()])); + assert_eq!(matches.opts_str(&["M".to_string()]).unwrap(), "."); + + } + + #[test] + fn test_nospace_conflict() { + let args = vec!("-vvLverbose".to_string(), "-v".to_string() ); + let matches = &match Options::new() + .optmulti("L", "", "library directory", "LIB") + .optflagmulti("v", "verbose", "Verbose") + .parse(&args) { + Ok(m) => m, + Err(e) => panic!( "{}", e ) + }; + assert!(matches.opts_present(&["L".to_string()])); + assert_eq!(matches.opts_str(&["L".to_string()]).unwrap(), "verbose"); + assert!(matches.opts_present(&["v".to_string()])); + assert_eq!(3, matches.opt_count("v")); + } + + #[test] + fn test_long_to_short() { + let mut short = Opt { + name: Name::Long("banana".to_string()), + hasarg: HasArg::Yes, + occur: Occur::Req, + aliases: Vec::new(), + }; + short.aliases = vec!(Opt { name: Name::Short('b'), + hasarg: HasArg::Yes, + occur: Occur::Req, + aliases: Vec::new() }); + let mut opts = Options::new(); + opts.reqopt("b", "banana", "some bananas", "VAL"); + let ref verbose = opts.grps[0]; + assert!(verbose.long_to_short() == short); + } + + #[test] + fn test_aliases_long_and_short() { + let args = vec!("-a".to_string(), "--apple".to_string(), "-a".to_string()); + + let matches = Options::new() + .optflagmulti("a", "apple", "Desc") + .parse(&args) + .unwrap(); + assert_eq!(3, matches.opt_count("a")); + assert_eq!(3, matches.opt_count("apple")); + } + + #[test] + fn test_usage() { + let mut opts = Options::new(); + opts.reqopt("b", "banana", "Desc", "VAL"); + opts.optopt("a", "012345678901234567890123456789", + "Desc", "VAL"); + opts.optflag("k", "kiwi", "Desc"); + opts.optflagopt("p", "", "Desc", "VAL"); + opts.optmulti("l", "", "Desc", "VAL"); + opts.optflag("", "starfruit", "Starfruit"); + + let expected = +"Usage: fruits + +Options: + -b, --banana VAL Desc + -a, --012345678901234567890123456789 VAL + Desc + -k, --kiwi Desc + -p [VAL] Desc + -l VAL Desc + --starfruit Starfruit +"; + + let generated_usage = opts.usage("Usage: fruits"); + + debug!("expected: <<{}>>", expected); + debug!("generated: <<{}>>", generated_usage); + assert_eq!(generated_usage, expected); + } + + #[test] + fn test_usage_description_wrapping() { + // indentation should be 24 spaces + // lines wrap after 78: or rather descriptions wrap after 54 + + let mut opts = Options::new(); + opts.optflag("k", "kiwi", + "This is a long description which won't be wrapped..+.."); // 54 + opts.optflag("a", "apple", + "This is a long description which _will_ be wrapped..+.."); + + let expected = +"Usage: fruits + +Options: + -k, --kiwi This is a long description which won't be wrapped..+.. + -a, --apple This is a long description which _will_ be + wrapped..+.. +"; + + let usage = opts.usage("Usage: fruits"); + + debug!("expected: <<{}>>", expected); + debug!("generated: <<{}>>", usage); + assert!(usage == expected) + } + + #[test] + fn test_usage_description_multibyte_handling() { + let mut opts = Options::new(); + opts.optflag("k", "k\u{2013}w\u{2013}", + "The word kiwi is normally spelled with two i's"); + opts.optflag("a", "apple", + "This \u{201C}description\u{201D} has some characters that could \ +confuse the line wrapping; an apple costs 0.51€ in some parts of Europe."); + + let expected = +"Usage: fruits + +Options: + -k, --k–w– The word kiwi is normally spelled with two i's + -a, --apple This “description” has some characters that could + confuse the line wrapping; an apple costs 0.51€ in + some parts of Europe. +"; + + let usage = opts.usage("Usage: fruits"); + + debug!("expected: <<{}>>", expected); + debug!("generated: <<{}>>", usage); + assert!(usage == expected) + } + + #[test] + fn test_usage_short_only() { + let mut opts = Options::new(); + opts.optopt("k", "", "Kiwi", "VAL"); + opts.optflag("s", "", "Starfruit"); + opts.optflagopt("a", "", "Apple", "TYPE"); + + let expected = +"Usage: fruits + +Options: + -k VAL Kiwi + -s Starfruit + -a [TYPE] Apple +"; + + let usage = opts.usage("Usage: fruits"); + debug!("expected: <<{}>>", expected); + debug!("generated: <<{}>>", usage); + assert!(usage == expected) + } + + #[test] + fn test_usage_long_only() { + let mut opts = Options::new(); + opts.optopt("", "kiwi", "Kiwi", "VAL"); + opts.optflag("", "starfruit", "Starfruit"); + opts.optflagopt("", "apple", "Apple", "TYPE"); + + let expected = +"Usage: fruits + +Options: + --kiwi VAL Kiwi + --starfruit Starfruit + --apple [TYPE] Apple +"; + + let usage = opts.usage("Usage: fruits"); + debug!("expected: <<{}>>", expected); + debug!("generated: <<{}>>", usage); + assert!(usage == expected) + } + + #[test] + fn test_short_usage() { + let mut opts = Options::new(); + opts.reqopt("b", "banana", "Desc", "VAL"); + opts.optopt("a", "012345678901234567890123456789", + "Desc", "VAL"); + opts.optflag("k", "kiwi", "Desc"); + opts.optflagopt("p", "", "Desc", "VAL"); + opts.optmulti("l", "", "Desc", "VAL"); + + let expected = "Usage: fruits -b VAL [-a VAL] [-k] [-p [VAL]] [-l VAL]..".to_string(); + let generated_usage = opts.short_usage("fruits"); + + debug!("expected: <<{}>>", expected); + debug!("generated: <<{}>>", generated_usage); + assert_eq!(generated_usage, expected); + } + + #[test] + fn test_args_with_equals() { + let mut opts = Options::new(); + opts.optopt("o", "one", "One", "INFO"); + opts.optopt("t", "two", "Two", "INFO"); + + let args = vec!("--one".to_string(), "A=B".to_string(), + "--two=C=D".to_string()); + let matches = &match opts.parse(&args) { + Ok(m) => m, + Err(e) => panic!("{}", e) + }; + assert_eq!(matches.opts_str(&["o".to_string()]).unwrap(), "A=B"); + assert_eq!(matches.opts_str(&["t".to_string()]).unwrap(), "C=D"); + } +} diff --git a/src/vendor/getopts/tests/smoke.rs b/src/vendor/getopts/tests/smoke.rs new file mode 100644 index 000000000000..a46f9c0167ab --- /dev/null +++ b/src/vendor/getopts/tests/smoke.rs @@ -0,0 +1,8 @@ +extern crate getopts; + +use std::env; + +#[test] +fn main() { + getopts::Options::new().parse(env::args()).unwrap(); +} diff --git a/src/vendor/libc/.cargo-checksum.json b/src/vendor/libc/.cargo-checksum.json new file mode 100644 index 000000000000..56c0bb8d2559 --- /dev/null +++ b/src/vendor/libc/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"7150ee9391a955b2ef7e0762fc61c0c1aab167620ca36d88d78062d93b8334ba",".travis.yml":"ca5e05b688a8c9a3215de3b38f22f4b468f73d26738a80bd939af503ddb222e1","Cargo.toml":"4b1f0d59b5fb939877a639d1d4cac5a12440c6e2d366edf2abcb45c46e3dcd3e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"c1f46480074340f17f1c3ea989b28e6b632b9d324e57792293a60399b90bfda0","appveyor.yml":"c0d70c650b6231e6ff78a352224f1a522a9be69d9da4251adbaddb3f0393294d","ci/README.md":"be804f15e2128e5fd4b160cb0b13cff5f19e7d77b55ec5254aa6fd8731c84f0d","ci/docker/aarch64-unknown-linux-gnu/Dockerfile":"62ca7317439f9c303990e897450a91cd467be05eb75dfc01456d417932ac8672","ci/docker/arm-linux-androideabi/Dockerfile":"c3d60f2ba389e60e59cb6973542751c66a0e7bd484e11589c8ee7346e9ff2bab","ci/docker/arm-unknown-linux-gnueabihf/Dockerfile":"e349f7caa463adbde8d6ec4d2b9f7720ed81c77f48d75bbfb78c89751f55c2dc","ci/docker/i686-unknown-linux-gnu/Dockerfile":"07e9df6ba91025cbec7ae81ade63f8cfb8a54c5e1e5a8f8def0617e17bd59db0","ci/docker/i686-unknown-linux-musl/Dockerfile":"1a4d064adff4a8f58773305567cfe5d915bcd0762bcb0e101cf6f4ca628a96da","ci/docker/mips-unknown-linux-gnu/Dockerfile":"860299d96ee50ebdbd788e65eb6ba1f561ef66107647bddffcb2567ac350896b","ci/docker/mips-unknown-linux-musl/Dockerfile":"b5917a15c0998adb79ebfdb8aff9ab0e5c4098c4bd5ca78e90ee05859dcfbda3","ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile":"163776e0fd38f66df7415421202ac29efc7d345a628947434e573c3885594ab5","ci/docker/mipsel-unknown-linux-musl/Dockerfile":"b2dd4c26890c1070228df9694adde8fdb1fe78d7d5a71a8cb5c1b54835f93c46","ci/docker/powerpc-unknown-linux-gnu/Dockerfile":"08b846a338c2ee70100f4e80db812668dc58bfb536c44a95cd1cf004d965186b","ci/docker/powerpc64-unknown-linux-gnu/Dockerfile":"4da285ffd035d16f5da9e3701841eb86049c8cfa417fa81e53da4ef74152eac0","ci/docker/x86_64-rumprun-netbsd/Dockerfile":"44c3107fb30380785aaed6ff73fa334017a5bb4e3b5c7d4876154f09023a2b99","ci/docker/x86_64-unknown-freebsd/Dockerfile":"56fce89ceb70792be9005425f3e896361f5ba8a0553db659da87daced93f9785","ci/docker/x86_64-unknown-linux-gnu/Dockerfile":"67fabbc8c6ac02376cf9344251ad49ecdac396b71accb572fd1ae65225325bc0","ci/docker/x86_64-unknown-linux-musl/Dockerfile":"f71019fed5204b950843ef5e56144161fda7e27fad68ed0e8bc4353c388c7bcf","ci/docker/x86_64-unknown-openbsd/Dockerfile":"4a5583797a613056d87f6ae0b1d7a3d3a55552efa7c30e1e0aa67e34d69b4d9c","ci/dox.sh":"2161cb17ee0d6a2279a64149c6b7c73a5b2eab344f248ea1fa0e6c8f6335ec5f","ci/landing-page-footer.html":"b70b3112c2147f5c967e7481061ef38bc2d79a28dd55a16fb916d9c9426da2c4","ci/landing-page-head.html":"ad69663fac7924f27d0209bc519d55838e86edfc4133713a6fd08caadac1b142","ci/run-docker.sh":"325648a92ff4d74f18fdf3d190a5cd483306ed2a98479c0742ca7284acd6b948","ci/run-qemu.sh":"bb859421170871ef23a8940c5e150efec0c01b95e32d2ce2d37b79a45d9d346c","ci/run.sh":"3bb839c2d28986c6915b8f11ed820ff6c62e755fb96bd921a18899ee5f7efd32","ci/style.rs":"60564abc1d5197ed1598426dd0d6ee9939a16d2875b03373538f58843bb616c4","src/dox.rs":"eb6fbcc0b8b59430271bb71ee023961fd165337fc5fd6ca433882457a3c735bd","src/lib.rs":"4cece0e880ec8731913e5110b58d1b134148b0a43e72d6b990c1d999916fc706","src/macros.rs":"bd9802772b0e5c8b3c550d1c24307f06c0d1e4ce656b4ae1cf092142bbe5412c","src/unix/bsd/apple/b32.rs":"110ecff78da0e8d405d861447904da403d8b3f6da1f0f9dc9987633f3f04fe46","src/unix/bsd/apple/b64.rs":"e6808081c0b276cca3189628716f507c7c0d00b62417cd44addbdaefe848cec7","src/unix/bsd/apple/mod.rs":"6691f81221d455b882d68d1102de049d5b9729bb4b59050c1d62c835dcaddafb","src/unix/bsd/freebsdlike/dragonfly/mod.rs":"d87f02c64649ce63367d9f0e39de7213bd30366bbd5e497f7d88f0dc3c319294","src/unix/bsd/freebsdlike/freebsd/mod.rs":"0a675c4b7f54b410547e10e433503487eb1e738394ab81cac82112a96d275bdc","src/unix/bsd/freebsdlike/freebsd/x86.rs":"54311d3ebf2bb091ab22361e377e6ef9224aec2ecfe459fbfcedde4932db9c58","src/unix/bsd/freebsdlike/freebsd/x86_64.rs":"c7f46b9ae23fde5a9e245a28ed1380066e67f081323b4d253a18e9da3b97b860","src/unix/bsd/freebsdlike/mod.rs":"574f7a1368058fad551cdebea4f576fe672f9bbe95a85468c91f9ff5661908c3","src/unix/bsd/mod.rs":"bd422d4bca87a3e8ea4bd78b9ae019643399807d036913f42fdd7476f260297d","src/unix/bsd/netbsdlike/mod.rs":"7b62b89c6ba0d5a8e0cf0937587a81e0314f9c5dabb0c9a9164106b677cf4dd8","src/unix/bsd/netbsdlike/netbsd/mod.rs":"d62a02a78275ed705b2080cae452eb8954ef0f66ac9acb0f44c819d453904c5c","src/unix/bsd/netbsdlike/netbsd/other/b32/mod.rs":"bd251a102bed65d5cb3459275f6ec3310fe5803ff4c9651212115548f86256d0","src/unix/bsd/netbsdlike/netbsd/other/b64/mod.rs":"927eeccaf3269d299db4c2a55f8010807bf43dfa894aea6a783215f5d3560baa","src/unix/bsd/netbsdlike/netbsd/other/mod.rs":"8ce39030f3e4fb45a3d676ade97da8f6d1b3d5f6d8d141224d341c993c57e090","src/unix/bsd/netbsdlike/openbsdlike/bitrig.rs":"f8cd05dacd3a3136c58da5a2fbe26f703767823b28e74fe8a2b57a7bd98d6d5c","src/unix/bsd/netbsdlike/openbsdlike/mod.rs":"769647209be7b8fc5b7e5c1970f16d5cf9cc3fba04bb456c9584f19a5c406e08","src/unix/bsd/netbsdlike/openbsdlike/openbsd.rs":"b1b9cf7be9f0e4d294a57092594074ad03a65fe0eeac9d1104fa874c313e7900","src/unix/haiku/b32.rs":"bd251a102bed65d5cb3459275f6ec3310fe5803ff4c9651212115548f86256d0","src/unix/haiku/b64.rs":"b422430c550c0ba833c9206d1350861e344e3a2eb33d7d58693efb35044be1cc","src/unix/haiku/mod.rs":"d14c45d536f24cd9cd8d5170b9829026da4c782ff2d5855644cc217553e309cf","src/unix/mod.rs":"82952d405742b8b21bfbc29648115b3909d9c64422ad04fb6aca443c16ddaa99","src/unix/notbsd/android/b32.rs":"148e1b4ed8b4f700d5aa24178af925164176e1c18b54db877ced4b55ba9f03d4","src/unix/notbsd/android/b64.rs":"302caf0aa95fa022030717c58de17d85d814b04350eca081a722ec435bc4f217","src/unix/notbsd/android/mod.rs":"f7c0145110a406c5cb14243dc71b98af8971674aa7620e5f55dabfa5c8b344c8","src/unix/notbsd/linux/mips.rs":"7736e565499b04560bc7e6f8636fd39c74f4a588c671ece931d27de8ca263963","src/unix/notbsd/linux/mips64.rs":"f269d516e0f5203fbfd18ff6b22ff33f206be1584d9df03c35743f5e80127d8b","src/unix/notbsd/linux/mod.rs":"81dbebd7dd798dc57e5b5b84cec69af2b6027a415262f4ad07b8c609ad2c95ee","src/unix/notbsd/linux/musl/b32/arm.rs":"a8416bc6e36460f3c60e2f7730dad7c43466790d11214441ef227ffb05ea450f","src/unix/notbsd/linux/musl/b32/asmjs.rs":"c660c5eef21a5f7580e9258eb44881014d2aeba5928af431dfc782b6c4393f33","src/unix/notbsd/linux/musl/b32/mips.rs":"76d835acd06c7bcd07a293a6f141b715ac88b959b633df9af3610e8d6eeb1ab4","src/unix/notbsd/linux/musl/b32/mod.rs":"bd29a02c67b69791e7cabd7666503c35ed5322d244a005b9cc7fd0cb28b552a8","src/unix/notbsd/linux/musl/b32/x86.rs":"da2e557a6afa9d15649d8862a5d17032597c924cd8bb290105500905fe975133","src/unix/notbsd/linux/musl/b64/aarch64.rs":"4009c7eaf703472daef2a70bdac910d9fc395a33689ef2e8cf1c4e692445d3f0","src/unix/notbsd/linux/musl/b64/mod.rs":"20f34e48124d8ca2a08cc0d28353b310238d37a345dfa0d58993e2e930a1ae23","src/unix/notbsd/linux/musl/b64/powerpc64.rs":"dc28f5b7284235d6cf5519053cac59a1c16dc39223b71cca0871e4880755f852","src/unix/notbsd/linux/musl/b64/x86_64.rs":"43291acc0dfc92c2fec8ba6ce77ee9ca3c20bcdccec18e149f95ba911cee704b","src/unix/notbsd/linux/musl/mod.rs":"c195e04167d26f82885f9157e32a28caccfd4eabe807af683708f33e28562021","src/unix/notbsd/linux/other/b32/arm.rs":"f5cb989075fa3b5f997e7101495532c8d5c9f3577412d4c07e4c8c1a16f7b43c","src/unix/notbsd/linux/other/b32/mod.rs":"8b774feb5510b963ed031db7ab3d7e24f1ba5524a6396db0b851d237ccc16fd3","src/unix/notbsd/linux/other/b32/powerpc.rs":"3b62052bb9741afa5349098e6e9c675b60e822e41fed6b5e1b694be1872097b1","src/unix/notbsd/linux/other/b32/x86.rs":"1eda37736f5966c7968b594f74f5018f56b6b8c67bbdeb31fc3db1b6e4ac31b4","src/unix/notbsd/linux/other/b64/aarch64.rs":"a978e82d037a9c8127b2f704323864aff42ac910e721ecc69c255671ca96b950","src/unix/notbsd/linux/other/b64/mod.rs":"efb7740c2fb925ea98977a6a3ff52bc0b72205c1f88a9ba281a939b66b7f0efe","src/unix/notbsd/linux/other/b64/powerpc64.rs":"06a795bca8e91a0143ef1787b034201ed7a21d01960ce9fe869d18c274d5bdb4","src/unix/notbsd/linux/other/b64/x86_64.rs":"0ed128e93f212c0d65660bd95e29190a2dae7c9d15d6fa0d3c4c6656f89e9bdc","src/unix/notbsd/linux/other/mod.rs":"0f7b29425273101ce90a9565637e5f7f61905db2a1e8f5360b285c73b1287da1","src/unix/notbsd/linux/s390x.rs":"6eddef139e18191bc3894f759ca8bd83c59b547bc572ad8938dc61fb5a97d2e9","src/unix/notbsd/mod.rs":"6ba17e2e9a6d05d4470ba595fd38dc55f70fea874a46425a4733ae52d93ee8ff","src/unix/solaris/mod.rs":"6d1f023b637467fe26385d23b32219dbb4573ea177d159e32dad75e4a6ff95de","src/windows.rs":"08f351462388566dcdc6566fb183a467942db63a1caa1bc97f85284fb7a74063"},"package":"044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"} \ No newline at end of file diff --git a/src/vendor/libc/.cargo-ok b/src/vendor/libc/.cargo-ok new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/vendor/libc/.gitignore b/src/vendor/libc/.gitignore new file mode 100644 index 000000000000..f0ff2599d09b --- /dev/null +++ b/src/vendor/libc/.gitignore @@ -0,0 +1,3 @@ +target +Cargo.lock +*~ diff --git a/src/vendor/libc/.travis.yml b/src/vendor/libc/.travis.yml new file mode 100644 index 000000000000..703329b70572 --- /dev/null +++ b/src/vendor/libc/.travis.yml @@ -0,0 +1,125 @@ +language: rust +sudo: required +dist: trusty +services: + - docker +install: + - curl https://static.rust-lang.org/rustup.sh | + sh -s -- --add-target=$TARGET --disable-sudo -y --prefix=`rustc --print sysroot` +script: + - cargo build + - cargo build --no-default-features + - cargo generate-lockfile --manifest-path libc-test/Cargo.toml + - if [[ $TRAVIS_OS_NAME = "linux" ]]; then + sh ci/run-docker.sh $TARGET; + else + export CARGO_TARGET_DIR=`pwd`/target; + sh ci/run.sh $TARGET; + fi + - rustc ci/style.rs && ./style src +osx_image: xcode7.3 +env: + global: + secure: eIDEoQdTyglcsTD13zSGotAX2HDhRSXIaaTnVZTThqLSrySOc3/6KY3qmOc2Msf7XaBqfFy9QA+alk7OwfePp253eiy1Kced67ffjjFOytEcRT7FlQiYpcYQD6WNHZEj62/bJBO4LTM9sGtWNCTJVEDKW0WM8mUK7qNuC+honPM= +matrix: + include: + # 1.0.0 compat + - os: linux + env: TARGET=x86_64-unknown-linux-gnu + rust: 1.0.0 + script: cargo build + install: + + # build documentation + - os: linux + env: TARGET=x86_64-unknown-linux-gnu + rust: stable + script: sh ci/dox.sh + + # stable compat + - os: linux + env: TARGET=x86_64-unknown-linux-gnu + rust: stable + - os: linux + env: TARGET=i686-unknown-linux-gnu + rust: stable + - os: osx + env: TARGET=x86_64-apple-darwin + rust: stable + - os: osx + env: TARGET=i686-apple-darwin + rust: stable + - os: linux + env: TARGET=arm-linux-androideabi + rust: stable + - os: linux + env: TARGET=x86_64-unknown-linux-musl + rust: stable + - os: linux + env: TARGET=i686-unknown-linux-musl + rust: stable + - os: linux + env: TARGET=arm-unknown-linux-gnueabihf + rust: stable + - os: linux + env: TARGET=aarch64-unknown-linux-gnu + rust: stable + - os: osx + env: TARGET=i386-apple-ios + rust: stable + - os: osx + env: TARGET=x86_64-apple-ios + rust: stable + - os: linux + env: TARGET=x86_64-rumprun-netbsd + rust: stable + - os: linux + env: TARGET=powerpc-unknown-linux-gnu + rust: stable + - os: linux + env: TARGET=powerpc64-unknown-linux-gnu + rust: stable + - os: linux + env: TARGET=mips-unknown-linux-musl + rust: stable + - os: linux + env: TARGET=mipsel-unknown-linux-musl + rust: stable + - os: linux + env: TARGET=mips64-unknown-linux-gnuabi64 + rust: nightly + + # beta + - os: linux + env: TARGET=x86_64-unknown-linux-gnu + rust: beta + - os: osx + env: TARGET=x86_64-apple-darwin + rust: beta + + # nightly + - os: linux + env: TARGET=x86_64-unknown-linux-gnu + rust: nightly + - os: osx + env: TARGET=x86_64-apple-darwin + rust: nightly + - os: linux + env: TARGET=mips-unknown-linux-gnu + # not sure why this has to be nightly... + rust: nightly + + # QEMU based targets that compile in an emulator + - os: linux + env: TARGET=x86_64-unknown-freebsd + rust: stable + - os: linux + env: TARGET=x86_64-unknown-openbsd QEMU=openbsd.qcow2 + rust: stable + script: sh ci/run-docker.sh $TARGET + install: + +notifications: + email: + on_success: never + webhooks: https://buildbot.rust-lang.org/homu/travis diff --git a/src/vendor/libc/Cargo.toml b/src/vendor/libc/Cargo.toml new file mode 100644 index 000000000000..c08ab3aab9da --- /dev/null +++ b/src/vendor/libc/Cargo.toml @@ -0,0 +1,21 @@ +[package] + +name = "libc" +version = "0.2.17" +authors = ["The Rust Project Developers"] +license = "MIT/Apache-2.0" +readme = "README.md" +repository = "https://github.com/rust-lang/libc" +homepage = "https://github.com/rust-lang/libc" +documentation = "http://doc.rust-lang.org/libc" +description = """ +A library for types and bindings to native C functions often found in libc or +other common platform libraries. +""" + +[features] +default = ["use_std"] +use_std = [] + +[workspace] +members = ["libc-test", "libc-test/generate-files"] diff --git a/src/vendor/libc/LICENSE-APACHE b/src/vendor/libc/LICENSE-APACHE new file mode 100644 index 000000000000..16fe87b06e80 --- /dev/null +++ b/src/vendor/libc/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/src/vendor/libc/LICENSE-MIT b/src/vendor/libc/LICENSE-MIT new file mode 100644 index 000000000000..39d4bdb5acd3 --- /dev/null +++ b/src/vendor/libc/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/src/vendor/libc/README.md b/src/vendor/libc/README.md new file mode 100644 index 000000000000..5ea812320f05 --- /dev/null +++ b/src/vendor/libc/README.md @@ -0,0 +1,137 @@ +libc +==== + +A Rust library with native bindings to the types and functions commonly found on +various systems, including libc. + +[![Build Status](https://travis-ci.org/rust-lang/libc.svg?branch=master)](https://travis-ci.org/rust-lang/libc) +[![Build status](https://ci.appveyor.com/api/projects/status/34csq3uurnw7c0rl?svg=true)](https://ci.appveyor.com/project/alexcrichton/libc) + +[Documentation](#platforms-and-documentation) + +## Usage + +First, add the following to your `Cargo.toml`: + +```toml +[dependencies] +libc = "0.2" +``` + +Next, add this to your crate root: + +```rust +extern crate libc; +``` + +Currently libc by default links to the standard library, but if you would +instead like to use libc in a `#![no_std]` situation or crate you can request +this via: + +```toml +[dependencies] +libc = { version = "0.2", default-features = false } +``` + +## What is libc? + +The primary purpose of this crate is to provide all of the definitions necessary +to easily interoperate with C code (or "C-like" code) on each of the platforms +that Rust supports. This includes type definitions (e.g. `c_int`), constants +(e.g. `EINVAL`) as well as function headers (e.g. `malloc`). + +This crate does not strive to have any form of compatibility across platforms, +but rather it is simply a straight binding to the system libraries on the +platform in question. + +## Public API + +This crate exports all underlying platform types, functions, and constants under +the crate root, so all items are accessible as `libc::foo`. The types and values +of all the exported APIs match the platform that libc is compiled for. + +More detailed information about the design of this library can be found in its +[associated RFC][rfc]. + +[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1291-promote-libc.md + +## Adding an API + +Want to use an API which currently isn't bound in `libc`? It's quite easy to add +one! + +The internal structure of this crate is designed to minimize the number of +`#[cfg]` attributes in order to easily be able to add new items which apply +to all platforms in the future. As a result, the crate is organized +hierarchically based on platform. Each module has a number of `#[cfg]`'d +children, but only one is ever actually compiled. Each module then reexports all +the contents of its children. + +This means that for each platform that libc supports, the path from a +leaf module to the root will contain all bindings for the platform in question. +Consequently, this indicates where an API should be added! Adding an API at a +particular level in the hierarchy means that it is supported on all the child +platforms of that level. For example, when adding a Unix API it should be added +to `src/unix/mod.rs`, but when adding a Linux-only API it should be added to +`src/unix/notbsd/linux/mod.rs`. + +If you're not 100% sure at what level of the hierarchy an API should be added +at, fear not! This crate has CI support which tests any binding against all +platforms supported, so you'll see failures if an API is added at the wrong +level or has different signatures across platforms. + +With that in mind, the steps for adding a new API are: + +1. Determine where in the module hierarchy your API should be added. +2. Add the API. +3. Send a PR to this repo. +4. Wait for CI to pass, fixing errors. +5. Wait for a merge! + +### Test before you commit + +We have two automated tests running on [Travis](https://travis-ci.org/rust-lang/libc): + +1. [`libc-test`](https://github.com/alexcrichton/ctest) + - `cd libc-test && cargo run` + - Use the `skip_*()` functions in `build.rs` if you really need a workaround. +2. Style checker + - `rustc ci/style.rs && ./style src` + +## Platforms and Documentation + +The following platforms are currently tested and have documentation available: + +Tested: + * [`i686-pc-windows-msvc`](https://doc.rust-lang.org/libc/i686-pc-windows-msvc/libc/) + * [`x86_64-pc-windows-msvc`](https://doc.rust-lang.org/libc/x86_64-pc-windows-msvc/libc/) + (Windows) + * [`i686-pc-windows-gnu`](https://doc.rust-lang.org/libc/i686-pc-windows-gnu/libc/) + * [`x86_64-pc-windows-gnu`](https://doc.rust-lang.org/libc/x86_64-pc-windows-gnu/libc/) + * [`i686-apple-darwin`](https://doc.rust-lang.org/libc/i686-apple-darwin/libc/) + * [`x86_64-apple-darwin`](https://doc.rust-lang.org/libc/x86_64-apple-darwin/libc/) + (OSX) + * `i686-apple-ios` + * `x86_64-apple-ios` + * [`i686-unknown-linux-gnu`](https://doc.rust-lang.org/libc/i686-unknown-linux-gnu/libc/) + * [`x86_64-unknown-linux-gnu`](https://doc.rust-lang.org/libc/x86_64-unknown-linux-gnu/libc/) + (Linux) + * [`x86_64-unknown-linux-musl`](https://doc.rust-lang.org/libc/x86_64-unknown-linux-musl/libc/) + (Linux MUSL) + * [`aarch64-unknown-linux-gnu`](https://doc.rust-lang.org/libc/aarch64-unknown-linux-gnu/libc/) + * [`mips-unknown-linux-gnu`](https://doc.rust-lang.org/libc/mips-unknown-linux-gnu/libc/) + * [`arm-unknown-linux-gnueabihf`](https://doc.rust-lang.org/libc/arm-unknown-linux-gnueabihf/libc/) + * [`arm-linux-androideabi`](https://doc.rust-lang.org/libc/arm-linux-androideabi/libc/) + (Android) + * [`x86_64-unknown-freebsd`](https://doc.rust-lang.org/libc/x86_64-unknown-freebsd/libc/) + * [`x86_64-unknown-openbsd`](https://doc.rust-lang.org/libc/x86_64-unknown-openbsd/libc/) + * [`x86_64-rumprun-netbsd`](https://doc.rust-lang.org/libc/x86_64-unknown-netbsd/libc/) + +The following may be supported, but are not guaranteed to always work: + + * `i686-unknown-freebsd` + * [`x86_64-unknown-bitrig`](https://doc.rust-lang.org/libc/x86_64-unknown-bitrig/libc/) + * [`x86_64-unknown-dragonfly`](https://doc.rust-lang.org/libc/x86_64-unknown-dragonfly/libc/) + * `i686-unknown-haiku` + * `x86_64-unknown-haiku` + * [`x86_64-unknown-netbsd`](https://doc.rust-lang.org/libc/x86_64-unknown-netbsd/libc/) diff --git a/src/vendor/libc/appveyor.yml b/src/vendor/libc/appveyor.yml new file mode 100644 index 000000000000..a851bb87b6c3 --- /dev/null +++ b/src/vendor/libc/appveyor.yml @@ -0,0 +1,25 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-gnu + MSYS2_BITS: 64 + - TARGET: i686-pc-windows-gnu + MSYS2_BITS: 32 + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc +install: + - curl -sSf -o rustup-init.exe https://win.rustup.rs/ + - rustup-init.exe -y --default-host %TARGET% + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - if defined MSYS2_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS2_BITS%\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --target %TARGET% + - cargo run --manifest-path libc-test/Cargo.toml --target %TARGET% + +cache: + - target + - C:\Users\appveyor\.cargo\registry diff --git a/src/vendor/libc/ci/README.md b/src/vendor/libc/ci/README.md new file mode 100644 index 000000000000..13c7c8da52fc --- /dev/null +++ b/src/vendor/libc/ci/README.md @@ -0,0 +1,203 @@ +The goal of the libc crate is to have CI running everywhere to have the +strongest guarantees about the definitions that this library contains, and as a +result the CI is pretty complicated and also pretty large! Hopefully this can +serve as a guide through the sea of scripts in this directory and elsewhere in +this project. + +# Files + +First up, let's talk about the files in this directory: + +* `run-travis.sh` - a shell script run by all Travis builders, this is + responsible for setting up the rest of the environment such as installing new + packages, downloading Rust target libraries, etc. + +* `run.sh` - the actual script which runs tests for a particular architecture. + Called from the `run-travis.sh` script this will run all tests for the target + specified. + +* `cargo-config` - Cargo configuration of linkers to use copied into place by + the `run-travis.sh` script before builds are run. + +* `dox.sh` - script called from `run-travis.sh` on only the linux 64-bit nightly + Travis bots to build documentation for this crate. + +* `landing-page-*.html` - used by `dox.sh` to generate a landing page for all + architectures' documentation. + +* `run-qemu.sh` - see discussion about QEMU below + +* `mips`, `rumprun` - instructions to build the docker image for each respective + CI target + +# CI Systems + +Currently this repository leverages a combination of Travis CI and AppVeyor for +running tests. The triples tested are: + +* AppVeyor + * `{i686,x86_64}-pc-windows-{msvc,gnu}` +* Travis + * `{i686,x86_64,mips,aarch64}-unknown-linux-gnu` + * `x86_64-unknown-linux-musl` + * `arm-unknown-linux-gnueabihf` + * `arm-linux-androideabi` + * `{i686,x86_64}-apple-{darwin,ios}` + * `x86_64-rumprun-netbsd` + * `x86_64-unknown-freebsd` + * `x86_64-unknown-openbsd` + +The Windows triples are all pretty standard, they just set up their environment +then run tests, no need for downloading any extra target libs (we just download +the right installer). The Intel Linux/OSX builds are similar in that we just +download the right target libs and run tests. Note that the Intel Linux/OSX +builds are run on stable/beta/nightly, but are the only ones that do so. + +The remaining architectures look like: + +* Android runs in a [docker image][android-docker] with an emulator, the NDK, + and the SDK already set up. The entire build happens within the docker image. +* The MIPS, ARM, and AArch64 builds all use the QEMU userspace emulator to run + the generated binary to actually verify the tests pass. +* The MUSL build just has to download a MUSL compiler and target libraries and + then otherwise runs tests normally. +* iOS builds need an extra linker flag currently, but beyond that they're built + as standard as everything else. +* The rumprun target builds an entire kernel from the test suite and then runs + it inside QEMU using the serial console to test whether it succeeded or + failed. +* The BSD builds, currently OpenBSD and FreeBSD, use QEMU to boot up a system + and compile/run tests. More information on that below. + +[android-docker]: https://github.com/rust-lang/rust-buildbot/blob/master/slaves/android/Dockerfile + +## QEMU + +Lots of the architectures tested here use QEMU in the tests, so it's worth going +over all the crazy capabilities QEMU has and the various flavors in which we use +it! + +First up, QEMU has userspace emulation where it doesn't boot a full kernel, it +just runs a binary from another architecture (using the `qemu-` wrappers). +We provide it the runtime path for the dynamically loaded system libraries, +however. This strategy is used for all Linux architectures that aren't intel. +Note that one downside of this QEMU system is that threads are barely +implemented, so we're careful to not spawn many threads. + +For the rumprun target the only output is a kernel image, so we just use that +plus the `rumpbake` command to create a full kernel image which is then run from +within QEMU. + +Finally, the fun part, the BSDs. Quite a few hoops are jumped through to get CI +working for these platforms, but the gist of it looks like: + +* Cross compiling from Linux to any of the BSDs seems to be quite non-standard. + We may be able to get it working but it might be difficult at that point to + ensure that the libc definitions align with what you'd get on the BSD itself. + As a result, we try to do compiles within the BSD distro. +* On Travis we can't run a VM-in-a-VM, so we resort to userspace emulation + (QEMU). +* Unfortunately on Travis we also can't use KVM, so the emulation is super slow. + +With all that in mind, the way BSD is tested looks like: + +1. Download a pre-prepared image for the OS being tested. +2. Generate the tests for the OS being tested. This involves running the `ctest` + library over libc to generate a Rust file and a C file which will then be + compiled into the final test. +3. Generate a disk image which will later be mounted by the OS being tested. + This image is mostly just the libc directory, but some modifications are made + to compile the generated files from step 2. +4. The kernel is booted in QEMU, and it is configured to detect the libc-test + image being available, run the test script, and then shut down afterwards. +5. Look for whether the tests passed in the serial console output of the kernel. + +There's some pretty specific instructions for setting up each image (detailed +below), but the main gist of this is that we must avoid a vanilla `cargo run` +inside of the `libc-test` directory (which is what it's intended for) because +that would compile `syntex_syntax`, a large library, with userspace emulation. +This invariably times out on Travis, so we can't do that. + +Once all those hoops are jumped through, however, we can be happy that we're +testing almost everything! + +Below are some details of how to set up the initial OS images which are +downloaded. Each image must be enabled have input/output over the serial +console, log in automatically at the serial console, detect if a second drive in +QEMU is available, and if so mount it, run a script (it'll specifically be +`run-qemu.sh` in this folder which is copied into the generated image talked +about above), and then shut down. + +### QEMU setup - FreeBSD + +1. Download CD installer (most minimal is fine) +2. `qemu-img create -f qcow2 foo.qcow2 2G` +3. `qemu -cdrom foo.iso -drive if=virtio,file=foo.qcow2 -net nic,model=virtio -net user` +4. run installer +5. `echo 'console="comconsole"' >> /boot/loader.conf` +6. `echo 'autoboot_delay="0"' >> /boot/loader.conf` +7. look at /etc/ttys, see what getty argument is for ttyu0 +8. edit /etc/gettytab, look for ttyu0 argument, prepend `:al=root` to line + beneath + +(note that the current image has a `freebsd` user, but this isn't really +necessary) + +Once that's done, arrange for this script to run at login: + +``` +#!/bin/sh + +sudo kldload ext2fs +[ -e /dev/vtbd1 ] || exit 0 +sudo mount -t ext2fs /dev/vtbd1 /mnt +sh /mnt/run.sh /mnt +sudo poweroff +``` + +Helpful links + +* https://en.wikibooks.org/wiki/QEMU/Images +* https://blog.nekoconeko.nl/blog/2015/06/04/creating-an-openstack-freebsd-image.html +* https://www.freebsd.org/doc/handbook/serialconsole-setup.html + + +### QEMU setup - OpenBSD + +1. Download CD installer +2. `qemu-img create -f qcow2 foo.qcow2 2G` +3. `qemu -cdrom foo.iso -drive if=virtio,file=foo.qcow2 -net nic,model=virtio -net user` +4. run installer +5. `echo 'set tty com0' >> /etc/boot.conf` +6. `echo 'boot' >> /etc/boot.conf` +7. Modify /etc/ttys, change the `tty00` at the end from 'unknown off' to + 'vt220 on secure' +8. Modify same line in /etc/ttys to have `"/root/foo.sh"` as the shell +9. Add this script to `/root/foo.sh` + +``` +#!/bin/sh +exec 1>/dev/tty00 +exec 2>&1 + +if mount -t ext2fs /dev/sd1c /mnt; then + sh /mnt/run.sh /mnt + shutdown -ph now +fi + +# limited shell... +exec /bin/sh < /dev/tty00 +``` + +10. `chmod +x /root/foo.sh` + +Helpful links: + +* https://en.wikibooks.org/wiki/QEMU/Images +* http://www.openbsd.org/faq/faq7.html#SerCon + +# Questions? + +Hopefully that's at least somewhat of an introduction to everything going on +here, and feel free to ping @alexcrichton with questions! + diff --git a/src/vendor/libc/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/src/vendor/libc/ci/docker/aarch64-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000000..2ba69e15442f --- /dev/null +++ b/src/vendor/libc/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:16.10 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross qemu-user +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + PATH=$PATH:/rust/bin diff --git a/src/vendor/libc/ci/docker/arm-linux-androideabi/Dockerfile b/src/vendor/libc/ci/docker/arm-linux-androideabi/Dockerfile new file mode 100644 index 000000000000..0e41ba6dbee6 --- /dev/null +++ b/src/vendor/libc/ci/docker/arm-linux-androideabi/Dockerfile @@ -0,0 +1,4 @@ +FROM alexcrichton/rust-slave-android:2015-11-22 +ENV CARGO_TARGET_ARM_LINUX_ANDROIDEABI_LINKER=arm-linux-androideabi-gcc \ + PATH=$PATH:/rust/bin +ENTRYPOINT ["sh"] diff --git a/src/vendor/libc/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile b/src/vendor/libc/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile new file mode 100644 index 000000000000..3824c0466401 --- /dev/null +++ b/src/vendor/libc/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile @@ -0,0 +1,7 @@ +FROM ubuntu:16.10 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates \ + gcc-arm-linux-gnueabihf libc6-dev-armhf-cross qemu-user +ENV CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc \ + PATH=$PATH:/rust/bin diff --git a/src/vendor/libc/ci/docker/i686-unknown-linux-gnu/Dockerfile b/src/vendor/libc/ci/docker/i686-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000000..c149d8407291 --- /dev/null +++ b/src/vendor/libc/ci/docker/i686-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:16.10 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc-multilib libc6-dev ca-certificates +ENV PATH=$PATH:/rust/bin diff --git a/src/vendor/libc/ci/docker/i686-unknown-linux-musl/Dockerfile b/src/vendor/libc/ci/docker/i686-unknown-linux-musl/Dockerfile new file mode 100644 index 000000000000..87459a1672bd --- /dev/null +++ b/src/vendor/libc/ci/docker/i686-unknown-linux-musl/Dockerfile @@ -0,0 +1,22 @@ +FROM ubuntu:16.10 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc make libc6-dev git curl ca-certificates +# Below we're cross-compiling musl for i686 using the system compiler on an +# x86_64 system. This is an awkward thing to be doing and so we have to jump +# through a couple hoops to get musl to be happy. In particular: +# +# * We specifically pass -m32 in CFLAGS and override CC when running ./configure, +# since otherwise the script will fail to find a compiler. +# * We manually unset CROSS_COMPILE when running make; otherwise the makefile +# will call the non-existent binary 'i686-ar'. +RUN curl https://www.musl-libc.org/releases/musl-1.1.15.tar.gz | \ + tar xzf - && \ + cd musl-1.1.15 && \ + CC=gcc CFLAGS=-m32 ./configure --prefix=/musl-i686 --disable-shared --target=i686 && \ + make CROSS_COMPILE= install -j4 && \ + cd .. && \ + rm -rf musl-1.1.15 +ENV PATH=$PATH:/musl-i686/bin:/rust/bin \ + CC_i686_unknown_linux_musl=musl-gcc diff --git a/src/vendor/libc/ci/docker/mips-unknown-linux-gnu/Dockerfile b/src/vendor/libc/ci/docker/mips-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000000..eea1f652c3cb --- /dev/null +++ b/src/vendor/libc/ci/docker/mips-unknown-linux-gnu/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:16.10 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user ca-certificates \ + gcc-mips-linux-gnu libc6-dev-mips-cross \ + qemu-system-mips + +ENV CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc \ + PATH=$PATH:/rust/bin diff --git a/src/vendor/libc/ci/docker/mips-unknown-linux-musl/Dockerfile b/src/vendor/libc/ci/docker/mips-unknown-linux-musl/Dockerfile new file mode 100644 index 000000000000..77c6adb435f1 --- /dev/null +++ b/src/vendor/libc/ci/docker/mips-unknown-linux-musl/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:16.10 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user ca-certificates qemu-system-mips curl \ + bzip2 + +RUN mkdir /toolchain +RUN curl -L https://downloads.openwrt.org/snapshots/trunk/ar71xx/generic/OpenWrt-SDK-ar71xx-generic_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2 | \ + tar xjf - -C /toolchain --strip-components=1 + +ENV PATH=$PATH:/rust/bin:/toolchain/staging_dir/toolchain-mips_34kc_gcc-5.3.0_musl-1.1.15/bin \ + CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \ + CARGO_TARGET_MIPS_UNKNOWN_LINUX_MUSL_LINKER=mips-openwrt-linux-gcc diff --git a/src/vendor/libc/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile b/src/vendor/libc/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile new file mode 100644 index 000000000000..2eb5de245380 --- /dev/null +++ b/src/vendor/libc/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile @@ -0,0 +1,11 @@ +FROM ubuntu:16.10 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user ca-certificates \ + gcc-mips64-linux-gnuabi64 libc6-dev-mips64-cross \ + qemu-system-mips64 + +ENV CARGO_TARGET_MIPS64_UNKNOWN_LINUX_GNUABI64_LINKER=mips64-linux-gnuabi64-gcc \ + CC_mips64_unknown_linux_gnuabi64=mips64-linux-gnuabi64-gcc \ + PATH=$PATH:/rust/bin diff --git a/src/vendor/libc/ci/docker/mipsel-unknown-linux-musl/Dockerfile b/src/vendor/libc/ci/docker/mipsel-unknown-linux-musl/Dockerfile new file mode 100644 index 000000000000..36c4d90ef68f --- /dev/null +++ b/src/vendor/libc/ci/docker/mipsel-unknown-linux-musl/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:16.10 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user ca-certificates qemu-system-mips curl \ + bzip2 + +RUN mkdir /toolchain +RUN curl -L https://downloads.openwrt.org/snapshots/trunk/malta/generic/OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2 | \ + tar xjf - -C /toolchain --strip-components=2 + +ENV PATH=$PATH:/rust/bin:/toolchain/bin \ + CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ + CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_MUSL_LINKER=mipsel-openwrt-linux-gcc diff --git a/src/vendor/libc/ci/docker/powerpc-unknown-linux-gnu/Dockerfile b/src/vendor/libc/ci/docker/powerpc-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000000..d9d7db0f41dd --- /dev/null +++ b/src/vendor/libc/ci/docker/powerpc-unknown-linux-gnu/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:16.10 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user ca-certificates \ + gcc-powerpc-linux-gnu libc6-dev-powerpc-cross \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC_UNKNOWN_LINUX_GNU_LINKER=powerpc-linux-gnu-gcc \ + PATH=$PATH:/rust/bin diff --git a/src/vendor/libc/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile b/src/vendor/libc/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000000..df0e6057b4f7 --- /dev/null +++ b/src/vendor/libc/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,11 @@ +FROM ubuntu:16.10 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu-user ca-certificates \ + gcc-powerpc64-linux-gnu libc6-dev-ppc64-cross \ + qemu-system-ppc + +ENV CARGO_TARGET_POWERPC64_UNKNOWN_LINUX_GNU_LINKER=powerpc64-linux-gnu-gcc \ + CC=powerpc64-linux-gnu-gcc \ + PATH=$PATH:/rust/bin diff --git a/src/vendor/libc/ci/docker/x86_64-rumprun-netbsd/Dockerfile b/src/vendor/libc/ci/docker/x86_64-rumprun-netbsd/Dockerfile new file mode 100644 index 000000000000..129771e76b74 --- /dev/null +++ b/src/vendor/libc/ci/docker/x86_64-rumprun-netbsd/Dockerfile @@ -0,0 +1,6 @@ +FROM mato/rumprun-toolchain-hw-x86_64 +USER root +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + qemu +ENV PATH=$PATH:/rust/bin diff --git a/src/vendor/libc/ci/docker/x86_64-unknown-freebsd/Dockerfile b/src/vendor/libc/ci/docker/x86_64-unknown-freebsd/Dockerfile new file mode 100644 index 000000000000..b12733822236 --- /dev/null +++ b/src/vendor/libc/ci/docker/x86_64-unknown-freebsd/Dockerfile @@ -0,0 +1,13 @@ +FROM alexcrichton/rust-slave-linux-cross:2016-04-15 +USER root + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + qemu genext2fs + +ENTRYPOINT ["sh"] + +ENV PATH=$PATH:/rust/bin \ + QEMU=freebsd.qcow2.gz \ + CAN_CROSS=1 \ + CARGO_TARGET_X86_64_UNKNOWN_FREEBSD_LINKER=x86_64-unknown-freebsd10-gcc diff --git a/src/vendor/libc/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/src/vendor/libc/ci/docker/x86_64-unknown-linux-gnu/Dockerfile new file mode 100644 index 000000000000..4af3f834cbe6 --- /dev/null +++ b/src/vendor/libc/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:16.10 +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev ca-certificates +ENV PATH=$PATH:/rust/bin diff --git a/src/vendor/libc/ci/docker/x86_64-unknown-linux-musl/Dockerfile b/src/vendor/libc/ci/docker/x86_64-unknown-linux-musl/Dockerfile new file mode 100644 index 000000000000..9c2499948a28 --- /dev/null +++ b/src/vendor/libc/ci/docker/x86_64-unknown-linux-musl/Dockerfile @@ -0,0 +1,13 @@ +FROM ubuntu:16.10 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc make libc6-dev git curl ca-certificates +RUN curl https://www.musl-libc.org/releases/musl-1.1.15.tar.gz | \ + tar xzf - && \ + cd musl-1.1.15 && \ + ./configure --prefix=/musl-x86_64 && \ + make install -j4 && \ + cd .. && \ + rm -rf musl-1.1.15 +ENV PATH=$PATH:/musl-x86_64/bin:/rust/bin diff --git a/src/vendor/libc/ci/docker/x86_64-unknown-openbsd/Dockerfile b/src/vendor/libc/ci/docker/x86_64-unknown-openbsd/Dockerfile new file mode 100644 index 000000000000..26340a5ed1ec --- /dev/null +++ b/src/vendor/libc/ci/docker/x86_64-unknown-openbsd/Dockerfile @@ -0,0 +1,8 @@ +FROM ubuntu:16.10 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc libc6-dev qemu curl ca-certificates \ + genext2fs +ENV PATH=$PATH:/rust/bin \ + QEMU=2016-09-07/openbsd-6.0-without-pkgs.qcow2 diff --git a/src/vendor/libc/ci/dox.sh b/src/vendor/libc/ci/dox.sh new file mode 100644 index 000000000000..88d882dcacdd --- /dev/null +++ b/src/vendor/libc/ci/dox.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +# Builds documentation for all target triples that we have a registered URL for +# in liblibc. This scrapes the list of triples to document from `src/lib.rs` +# which has a bunch of `html_root_url` directives we pick up. + +set -e + +TARGETS=`grep html_root_url src/lib.rs | sed 's/.*".*\/\(.*\)"/\1/'` + +rm -rf target/doc +mkdir -p target/doc + +cp ci/landing-page-head.html target/doc/index.html + +for target in $TARGETS; do + echo documenting $target + + rustdoc -o target/doc/$target --target $target src/lib.rs --cfg dox \ + --crate-name libc + + echo "

" \ + >> target/doc/index.html +done + +cat ci/landing-page-footer.html >> target/doc/index.html + +# If we're on travis, not a PR, and on the right branch, publish! +if [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ "$TRAVIS_BRANCH" = "master" ]; then + pip install ghp-import --user $USER + $HOME/.local/bin/ghp-import -n target/doc + git push -qf https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages +fi diff --git a/src/vendor/libc/ci/landing-page-footer.html b/src/vendor/libc/ci/landing-page-footer.html new file mode 100644 index 000000000000..941cc8d2b403 --- /dev/null +++ b/src/vendor/libc/ci/landing-page-footer.html @@ -0,0 +1,3 @@ + + + diff --git a/src/vendor/libc/ci/landing-page-head.html b/src/vendor/libc/ci/landing-page-head.html new file mode 100644 index 000000000000..fc69fa88eb5c --- /dev/null +++ b/src/vendor/libc/ci/landing-page-head.html @@ -0,0 +1,7 @@ + + + + + + +
  • $target