diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2017-04-07 07:19:44 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2017-04-07 14:55:45 -0700 |
| commit | 8c31412c2f84c7d76602b2598c5c1352da61d022 (patch) | |
| tree | cbc08b79f16f1533e27d84dee16e90f9f319a679 | |
| parent | b83352e44c36e81db7f00eb60e78ff3828c51c9e (diff) | |
| parent | 4c59c92bc4d4d6e5b2b66c4cc08dd1a058283a0d (diff) | |
| download | rust-8c31412c2f84c7d76602b2598c5c1352da61d022.tar.gz rust-8c31412c2f84c7d76602b2598c5c1352da61d022.zip | |
Merge branch 'master' into ty-placeholder
278 files changed, 7309 insertions, 3328 deletions
diff --git a/.gitmodules b/.gitmodules index 53d17874924..3533f0df5d1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,4 +25,4 @@ url = https://github.com/rust-lang-nursery/reference.git [submodule "book"] path = src/doc/book - url = https://github.com/rust-lang/book + url = https://github.com/rust-lang/book.git diff --git a/.travis.yml b/.travis.yml index 8fe92ff7d02..0ffba70d2ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,19 +15,27 @@ matrix: - env: IMAGE=arm-android - env: IMAGE=armhf-gnu - env: IMAGE=cross DEPLOY=1 + - env: IMAGE=dist-aarch64-linux DEPLOY=1 - env: IMAGE=dist-android DEPLOY=1 - env: IMAGE=dist-arm-linux DEPLOY=1 - - env: IMAGE=dist-armv7-aarch64-linux DEPLOY=1 - - env: IMAGE=dist-freebsd DEPLOY=1 - - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1 + - env: IMAGE=dist-armhf-linux DEPLOY=1 + - env: IMAGE=dist-armv7-linux DEPLOY=1 - env: IMAGE=dist-fuchsia DEPLOY=1 + - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1 + - env: IMAGE=dist-i686-freebsd DEPLOY=1 + - env: IMAGE=dist-i686-linux DEPLOY=1 - env: IMAGE=dist-mips-linux DEPLOY=1 - env: IMAGE=dist-mips64-linux DEPLOY=1 + - env: IMAGE=dist-mips64el-linux DEPLOY=1 + - env: IMAGE=dist-mipsel-linux DEPLOY=1 - env: IMAGE=dist-powerpc-linux DEPLOY=1 - env: IMAGE=dist-powerpc64-linux DEPLOY=1 - - env: IMAGE=dist-s390x-linux-netbsd DEPLOY=1 - - env: IMAGE=dist-x86-linux DEPLOY=1 + - env: IMAGE=dist-powerpc64le-linux DEPLOY=1 + - env: IMAGE=dist-s390x-linux DEPLOY=1 + - env: IMAGE=dist-x86_64-freebsd DEPLOY=1 + - env: IMAGE=dist-x86_64-linux DEPLOY=1 - env: IMAGE=dist-x86_64-musl DEPLOY=1 + - env: IMAGE=dist-x86_64-netbsd DEPLOY=1 - env: IMAGE=emscripten - env: IMAGE=i686-gnu - env: IMAGE=i686-gnu-nopt @@ -55,7 +63,7 @@ matrix: os: osx osx_image: xcode8.2 install: &osx_install_sccache > - travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-apple-darwin && + travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-apple-darwin && chmod +x /usr/local/bin/sccache && travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && chmod +x /usr/local/bin/stamp @@ -104,7 +112,7 @@ matrix: # turned on, they're deployed to a different location primarily for projects # which are stuck on nightly and don't want llvm assertions in the artifacts # that they use. - - env: IMAGE=dist-x86-linux DEPLOY_ALT=1 + - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1 - env: > RUST_CHECK_TARGET=dist RUST_CONFIGURE_ARGS="--enable-extended" diff --git a/appveyor.yml b/appveyor.yml index 68b2a239aff..83cfea0dd83 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -115,8 +115,8 @@ install: - set PATH=C:\Python27;%PATH% # Download and install sccache - - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-pc-windows-msvc - - mv 2017-03-24-sccache-x86_64-pc-windows-msvc sccache.exe + - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-pc-windows-msvc + - mv 2017-04-04-sccache-x86_64-pc-windows-msvc sccache.exe - set PATH=%PATH%;%CD% # Download and install ninja diff --git a/cargo b/cargo -Subproject 4e95c6b41eca3388f54dd5f7787366ad2df637b +Subproject 4729175045b41b688ab903120860866ce7a22ba diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index d5bc6127a1e..526beb41aae 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -163,12 +163,13 @@ class RustBuild(object): if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) + channel = self.stage0_rustc_channel() + if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): self.print_what_it_means_to_bootstrap() if os.path.exists(self.bin_root()): shutil.rmtree(self.bin_root()) - channel = self.stage0_rustc_channel() filename = "rust-std-{}-{}.tar.gz".format(channel, self.build) url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() tarball = os.path.join(rustc_cache, filename) @@ -189,6 +190,14 @@ class RustBuild(object): with open(self.rustc_stamp(), 'w') as f: f.write(self.stage0_rustc_date()) + if "pc-windows-gnu" in self.build: + filename = "rust-mingw-{}-{}.tar.gz".format(channel, self.build) + url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() + tarball = os.path.join(rustc_cache, filename) + if not os.path.exists(tarball): + get("{}/{}".format(url, filename), tarball, verbose=self.verbose) + unpack(tarball, self.bin_root(), match="rust-mingw", verbose=self.verbose) + if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.cargo_out_of_date()): self.print_what_it_means_to_bootstrap() @@ -591,16 +600,19 @@ def bootstrap(): def main(): start_time = time() + help_triggered = ('-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1) try: bootstrap() - print("Build completed successfully in %s" % format_build_time(time() - start_time)) + if not help_triggered: + print("Build completed successfully in %s" % format_build_time(time() - start_time)) except (SystemExit, KeyboardInterrupt) as e: if hasattr(e, 'code') and isinstance(e.code, int): exit_code = e.code else: exit_code = 1 print(e) - print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) + if not help_triggered: + print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) sys.exit(exit_code) if __name__ == '__main__': diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index e9547ee42d0..308a0ab3076 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -44,26 +44,25 @@ pub fn clean(build: &Build) { } fn rm_rf(path: &Path) { - if !path.exists() { - return - } - if path.is_file() { - return do_op(path, "remove file", |p| fs::remove_file(p)); - } - - for file in t!(fs::read_dir(path)) { - let file = t!(file).path(); + match path.symlink_metadata() { + Err(e) => { + if e.kind() == ErrorKind::NotFound { + return; + } + panic!("failed to get metadata for file {}: {}", path.display(), e); + }, + Ok(metadata) => { + if metadata.file_type().is_file() || metadata.file_type().is_symlink() { + do_op(path, "remove file", |p| fs::remove_file(p)); + return; + } - if file.is_dir() { - rm_rf(&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)); + for file in t!(fs::read_dir(path)) { + rm_rf(&t!(file).path()); + } + do_op(path, "remove dir", |p| fs::remove_dir(p)); + }, + }; } fn do_op<F>(path: &Path, desc: &str, mut f: F) @@ -71,9 +70,12 @@ fn do_op<F>(path: &Path, desc: &str, mut f: F) { match f(path) { Ok(()) => {} + // 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. + // This is also the reason that we can't use things like fs::remove_dir_all(). Err(ref e) if cfg!(windows) && e.kind() == ErrorKind::PermissionDenied => { - let mut p = t!(path.metadata()).permissions(); + let mut p = t!(path.symlink_metadata()).permissions(); p.set_readonly(false); t!(fs::set_permissions(path, p)); f(path).unwrap_or_else(|e| { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index b55f3d710ca..a1466d68a13 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -18,7 +18,7 @@ use std::fs; use std::path::PathBuf; use std::process; -use getopts::{Matches, Options}; +use getopts::Options; use Build; use config::Config; @@ -75,7 +75,22 @@ pub enum Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { + let mut extra_help = String::new(); + let mut subcommand_help = format!("\ +Usage: x.py <subcommand> [options] [<paths>...] + +Subcommands: + build Compile either the compiler or libraries + test Build and run some test suites + bench Build and run some benchmarks + doc Build documentation + clean Clean out build directories + dist Build and/or install distribution artifacts + +To learn more about a subcommand, run `./x.py <subcommand> -h`"); + let mut opts = Options::new(); + // Options common to all subcommands opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)"); opts.optflag("i", "incremental", "use incremental compilation"); opts.optopt("", "config", "TOML configuration file for build", "FILE"); @@ -89,21 +104,83 @@ impl Flags { opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); - let usage = |n, opts: &Options| -> ! { - let command = args.get(0).map(|s| &**s); - let brief = format!("Usage: x.py {} [options] [<args>...]", - command.unwrap_or("<command>")); + // fn usage() + let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { + println!("{}", opts.usage(subcommand_help)); + if !extra_help.is_empty() { + println!("{}", extra_help); + } + process::exit(exit_code); + }; + + // We can't use getopt to parse the options until we have completed specifying which + // options are valid, but under the current implementation, some options are conditional on + // the subcommand. Therefore we must manually identify the subcommand first, so that we can + // complete the definition of the options. Then we can use the getopt::Matches object from + // there on out. + let mut possible_subcommands = args.iter().collect::<Vec<_>>(); + possible_subcommands.retain(|&s| + (s == "build") + || (s == "test") + || (s == "bench") + || (s == "doc") + || (s == "clean") + || (s == "dist")); + let subcommand = match possible_subcommands.first() { + Some(s) => s, + None => { + // No subcommand -- show the general usage and subcommand help + println!("{}\n", subcommand_help); + process::exit(0); + } + }; - println!("{}", opts.usage(&brief)); - match command { - Some("build") => { - println!("\ + // Some subcommands get extra options + match subcommand.as_str() { + "test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, + "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, + "dist" => { opts.optflag("", "install", "run installer as well"); }, + _ => { }, + }; + + // Done specifying what options are possible, so do the getopts parsing + let matches = opts.parse(&args[..]).unwrap_or_else(|e| { + // Invalid argument/option format + println!("\n{}\n", e); + usage(1, &opts, &subcommand_help, &extra_help); + }); + // Extra sanity check to make sure we didn't hit this crazy corner case: + // + // ./x.py --frobulate clean build + // ^-- option ^ ^- actual subcommand + // \_ arg to option could be mistaken as subcommand + let mut pass_sanity_check = true; + match matches.free.get(0) { + Some(check_subcommand) => { + if &check_subcommand != subcommand { + pass_sanity_check = false; + } + }, + None => { + pass_sanity_check = false; + } + } + if !pass_sanity_check { + println!("{}\n", subcommand_help); + println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ + You may need to move some options to after the subcommand.\n"); + process::exit(1); + } + // Extra help text for some commands + match subcommand.as_str() { + "build" => { + subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of positional arguments of directories to - the crates and/or artifacts to compile. For example: + This subcommand accepts a number of paths to 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/libcore src/libproc_macro ./x.py build src/libstd --stage 1 If no arguments are passed then the complete artifacts for that stage are @@ -114,15 +191,13 @@ Arguments: For a quick build with a usable compile, you can pass: - ./x.py build --stage 1 src/libtest -"); - } - - Some("test") => { - println!("\ + ./x.py build --stage 1 src/libtest"); + } + "test" => { + subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of positional arguments of directories to - tests that should be compiled and run. For example: + This subcommand accepts a number of paths to directories to tests that + should be compiled and run. For example: ./x.py test src/test/run-pass ./x.py test src/libstd --test-args hash_map @@ -132,139 +207,90 @@ Arguments: compiled and tested. ./x.py test - ./x.py test --stage 1 -"); - } - - Some("doc") => { - println!("\ + ./x.py test --stage 1"); + } + "doc" => { + subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of positional arguments of directories of - documentation to build. For example: + This subcommand accepts a number of paths to directories of documentation + to build. For example: ./x.py doc src/doc/book ./x.py doc src/doc/nomicon - ./x.py doc src/libstd + ./x.py doc src/doc/book src/libstd If no arguments are passed then everything is documented: ./x.py doc - ./x.py doc --stage 1 -"); - } - - _ => {} + ./x.py doc --stage 1"); } - - if let Some(command) = command { - if command == "build" || - command == "dist" || - command == "doc" || - command == "test" || - command == "bench" || - 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 - bench Build and run some benchmarks - doc Build documentation - clean Clean out build directories - dist Build and/or install distribution artifacts - -To learn more about a subcommand, run `./x.py <command> -h` -"); - - process::exit(n); + _ => { } }; - 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); + // Get any optional paths which occur after the subcommand + let cwd = t!(env::current_dir()); + let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::<Vec<_>>(); + + + // All subcommands can have an optional "Available paths" section + if matches.opt_present("verbose") { + 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); + let maybe_rules_help = step::build_rules(&build).get_help(subcommand); + if maybe_rules_help.is_some() { + extra_help.push_str(maybe_rules_help.unwrap().as_str()); } - return m - }; + } else { + extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.", + subcommand).as_str()); + } - let cwd = t!(env::current_dir()); - let remaining_as_path = |m: &Matches| { - m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>() - }; + // User passed in -h/--help? + if matches.opt_present("help") { + usage(0, &opts, &subcommand_help, &extra_help); + } - let m: Matches; - let cmd = match &args[0][..] { + let cmd = match subcommand.as_str() { "build" => { - m = parse(&opts); - Subcommand::Build { paths: remaining_as_path(&m) } - } - "doc" => { - m = parse(&opts); - Subcommand::Doc { paths: remaining_as_path(&m) } + Subcommand::Build { paths: paths } } "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"), + paths: paths, + test_args: matches.opt_strs("test-args"), } } "bench" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - m = parse(&opts); Subcommand::Bench { - paths: remaining_as_path(&m), - test_args: m.opt_strs("test-args"), + paths: paths, + test_args: matches.opt_strs("test-args"), } } + "doc" => { + Subcommand::Doc { paths: paths } + } "clean" => { - m = parse(&opts); - if m.free.len() > 0 { - println!("clean takes no arguments"); - usage(1, &opts); + if paths.len() > 0 { + println!("\nclean takes no arguments\n"); + usage(1, &opts, &subcommand_help, &extra_help); } Subcommand::Clean } "dist" => { - opts.optflag("", "install", "run installer as well"); - m = parse(&opts); Subcommand::Dist { - paths: remaining_as_path(&m), - install: m.opt_present("install"), + paths: paths, + install: matches.opt_present("install"), } } - "--help" => usage(0, &opts), - cmd => { - println!("unknown command: {}", cmd); - usage(1, &opts); + _ => { + usage(1, &opts, &subcommand_help, &extra_help); } }; - let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| { + let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { Some(PathBuf::from("config.toml")) } else { @@ -272,31 +298,29 @@ To learn more about a subcommand, run `./x.py <command> -h` } }); - let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap()); - - let incremental = m.opt_present("i"); + let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap()); - if incremental { + if matches.opt_present("incremental") { if stage.is_none() { stage = Some(1); } } Flags { - verbose: m.opt_count("v"), + verbose: matches.opt_count("verbose"), stage: stage, - on_fail: m.opt_str("on-fail"), - keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()), - build: m.opt_str("build").unwrap_or_else(|| { + on_fail: matches.opt_str("on-fail"), + keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()), + build: matches.opt_str("build").unwrap_or_else(|| { env::var("BUILD").unwrap() }), - host: split(m.opt_strs("host")), - target: split(m.opt_strs("target")), + host: split(matches.opt_strs("host")), + target: split(matches.opt_strs("target")), config: cfg_file, - src: m.opt_str("src").map(PathBuf::from), - jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()), + src: matches.opt_str("src").map(PathBuf::from), + jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd: cmd, - incremental: incremental, + incremental: matches.opt_present("incremental"), } } } diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 249f241a151..25082e3a9d0 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -49,12 +49,17 @@ pub fn install(build: &Build, stage: u32, host: &str) { install_sh(&build, "docs", "rust-docs", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } + + for target in build.config.target.iter() { + install_sh(&build, "std", "rust-std", stage, target, &prefix, + &docdir, &libdir, &mandir, &empty_dir); + } + if build.config.rust_save_analysis { install_sh(&build, "analysis", "rust-analysis", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } - install_sh(&build, "std", "rust-std", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); + install_sh(&build, "rustc", "rustc", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); t!(fs::remove_dir_all(&empty_dir)); diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 6eb12fed5ab..5560b5b0333 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -978,26 +978,25 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? } } - pub fn print_help(&self, command: &str) { + pub fn get_help(&self, command: &str) -> Option<String> { let kind = match command { "build" => Kind::Build, "doc" => Kind::Doc, "test" => Kind::Test, "bench" => Kind::Bench, "dist" => Kind::Dist, - _ => return, + _ => return None, }; let rules = self.rules.values().filter(|r| r.kind == kind); let rules = rules.filter(|r| !r.path.contains("nowhere")); let mut rules = rules.collect::<Vec<_>>(); rules.sort_by_key(|r| r.path); - println!("Available paths:\n"); + let mut help_string = String::from("Available paths:\n"); for rule in rules { - print!(" ./x.py {} {}", command, rule.path); - - println!(""); + help_string.push_str(format!(" ./x.py {} {}\n", command, rule.path).as_str()); } + Some(help_string) } /// Construct the top-level build steps that we're going to be executing, diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index 933562c79e5..d42b35d488c 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -74,7 +74,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 8dc02ab522c..7c198441007 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile index 369e5a7dffe..d9a5429d2b8 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-aarch64-linux/Dockerfile @@ -56,28 +56,22 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools USER rustbuild WORKDIR /tmp -COPY armv7-linux-gnueabihf.config /tmp/ -COPY armv7-linux-gnueabihf.config aarch64-linux-gnu.config build-toolchains.sh /tmp/ +COPY aarch64-linux-gnu.config build-toolchains.sh /tmp/ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin -ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \ AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-ar \ - CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ \ - CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ - AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \ - CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ + CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ -ENV HOSTS=armv7-unknown-linux-gnueabihf -ENV HOSTS=$HOSTS,aarch64-unknown-linux-gnu +ENV HOSTS=aarch64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config b/src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config index 3d30ee49022..3d30ee49022 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config +++ b/src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config diff --git a/src/ci/docker/dist-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh new file mode 100755 index 00000000000..94f785c96f8 --- /dev/null +++ b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../aarch64-linux-gnu.config .config +ct-ng oldconfig +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 44d6863bf0b..31f4b8b777b 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -32,7 +32,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index 7facc52390f..7162aa0efc0 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -56,27 +56,22 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools USER rustbuild WORKDIR /tmp -COPY arm-linux-gnueabihf.config arm-linux-gnueabi.config build-toolchains.sh /tmp/ +COPY arm-linux-gnueabi.config build-toolchains.sh /tmp/ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin -ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \ AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \ - CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ \ - CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ - AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \ - CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ + CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ ENV HOSTS=arm-unknown-linux-gnueabi -ENV HOSTS=$HOSTS,arm-unknown-linux-gnueabihf ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-arm-linux/build-toolchains.sh b/src/ci/docker/dist-arm-linux/build-toolchains.sh index ed1406bd7cf..f78ecf9381a 100755 --- a/src/ci/docker/dist-arm-linux/build-toolchains.sh +++ b/src/ci/docker/dist-arm-linux/build-toolchains.sh @@ -35,11 +35,3 @@ ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build - -mkdir build -cd build -cp ../arm-linux-gnueabihf.config .config -ct-ng oldconfig -hide_output ct-ng build -cd .. -rm -rf build diff --git a/src/ci/docker/dist-armhf-linux/Dockerfile b/src/ci/docker/dist-armhf-linux/Dockerfile new file mode 100644 index 00000000000..8fa1cbe492f --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY arm-linux-gnueabihf.config build-toolchains.sh /tmp/ +RUN ./build-toolchains.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin + +ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ + AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \ + CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ + +ENV HOSTS=arm-unknown-linux-gnueabihf + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config b/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config index 1feeef15557..1feeef15557 100644 --- a/src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config +++ b/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config diff --git a/src/ci/docker/dist-armhf-linux/build-toolchains.sh b/src/ci/docker/dist-armhf-linux/build-toolchains.sh new file mode 100755 index 00000000000..df1134d5483 --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/build-toolchains.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../arm-linux-gnueabihf.config .config +ct-ng oldconfig +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile new file mode 100644 index 00000000000..9fcd827fc99 --- /dev/null +++ b/src/ci/docker/dist-armv7-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY build-toolchains.sh armv7-linux-gnueabihf.config /tmp/ +RUN ./build-toolchains.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin + +ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ + AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \ + CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ + +ENV HOSTS=armv7-unknown-linux-gnueabihf + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config index 79d6c77c411..79d6c77c411 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config +++ b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config diff --git a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-armv7-linux/build-toolchains.sh index ebd5ef4cfc4..2d395fee792 100755 --- a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh +++ b/src/ci/docker/dist-armv7-linux/build-toolchains.sh @@ -35,11 +35,3 @@ ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build - -mkdir build -cd build -cp ../aarch64-linux-gnu.config .config -ct-ng oldconfig -hide_output ct-ng build -cd .. -rm -rf build diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index ed37a9e842e..bfffd9637fc 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -29,7 +29,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index d88ec7aab34..d2727cbdb35 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh index a50a25c7913..ad285a57a84 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh +++ b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh @@ -15,11 +15,14 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL -CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686 -make -j10 +CC=gcc \ + CFLAGS="$CFLAGS -m32" \ + ./configure --prefix=/musl-i686 --disable-shared \ + --target=i686 +make AR=ar RANLIB=ranlib -j10 make install cd .. diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-i686-freebsd/Dockerfile index 633f58ea474..3b81216c643 100644 --- a/src/ci/docker/dist-freebsd/Dockerfile +++ b/src/ci/docker/dist-i686-freebsd/Dockerfile @@ -17,7 +17,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config COPY build-toolchain.sh /tmp/ -RUN /tmp/build-toolchain.sh x86_64 RUN /tmp/build-toolchain.sh i686 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -26,19 +25,15 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ \ AR_i686_unknown_freebsd=i686-unknown-freebsd10-ar \ CC_i686_unknown_freebsd=i686-unknown-freebsd10-gcc \ CXX_i686_unknown_freebsd=i686-unknown-freebsd10-g++ -ENV HOSTS=x86_64-unknown-freebsd -ENV HOSTS=$HOSTS,i686-unknown-freebsd +ENV HOSTS=i686-unknown-freebsd ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-freebsd/build-toolchain.sh b/src/ci/docker/dist-i686-freebsd/build-toolchain.sh index 5642e6fc937..5642e6fc937 100755 --- a/src/ci/docker/dist-freebsd/build-toolchain.sh +++ b/src/ci/docker/dist-i686-freebsd/build-toolchain.sh diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index 18c7a4d2b3e..b322f56f0d0 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -2,6 +2,12 @@ FROM centos:5 WORKDIR /build +# Centos 5 is EOL and is no longer available from the usual mirrors, so switch +# to http://vault.centos.org/ +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf +RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo +RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo + RUN yum upgrade -y && yum install -y \ curl \ bzip2 \ @@ -76,11 +82,10 @@ RUN curl -Lo /rustroot/dumb-init \ ENTRYPOINT ["/rustroot/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu -ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ diff --git a/src/ci/docker/dist-x86-linux/build-binutils.sh b/src/ci/docker/dist-i686-linux/build-binutils.sh index 80aa1f2a016..80aa1f2a016 100755 --- a/src/ci/docker/dist-x86-linux/build-binutils.sh +++ b/src/ci/docker/dist-i686-linux/build-binutils.sh diff --git a/src/ci/docker/dist-x86-linux/build-cmake.sh b/src/ci/docker/dist-i686-linux/build-cmake.sh index 82e46455cb0..82e46455cb0 100755 --- a/src/ci/docker/dist-x86-linux/build-cmake.sh +++ b/src/ci/docker/dist-i686-linux/build-cmake.sh diff --git a/src/ci/docker/dist-x86-linux/build-curl.sh b/src/ci/docker/dist-i686-linux/build-curl.sh index b7d22755a57..b7d22755a57 100755 --- a/src/ci/docker/dist-x86-linux/build-curl.sh +++ b/src/ci/docker/dist-i686-linux/build-curl.sh diff --git a/src/ci/docker/dist-x86-linux/build-gcc.sh b/src/ci/docker/dist-i686-linux/build-gcc.sh index ab2562538d6..ab2562538d6 100755 --- a/src/ci/docker/dist-x86-linux/build-gcc.sh +++ b/src/ci/docker/dist-i686-linux/build-gcc.sh diff --git a/src/ci/docker/dist-x86-linux/build-git.sh b/src/ci/docker/dist-i686-linux/build-git.sh index 92fa66b496d..92fa66b496d 100755 --- a/src/ci/docker/dist-x86-linux/build-git.sh +++ b/src/ci/docker/dist-i686-linux/build-git.sh diff --git a/src/ci/docker/dist-x86-linux/build-headers.sh b/src/ci/docker/dist-i686-linux/build-headers.sh index 4ce38fd9205..4ce38fd9205 100755 --- a/src/ci/docker/dist-x86-linux/build-headers.sh +++ b/src/ci/docker/dist-i686-linux/build-headers.sh diff --git a/src/ci/docker/dist-x86-linux/build-openssl.sh b/src/ci/docker/dist-i686-linux/build-openssl.sh index 64b1abf82a8..64b1abf82a8 100755 --- a/src/ci/docker/dist-x86-linux/build-openssl.sh +++ b/src/ci/docker/dist-i686-linux/build-openssl.sh diff --git a/src/ci/docker/dist-x86-linux/build-python.sh b/src/ci/docker/dist-i686-linux/build-python.sh index a7a450f3c8d..a7a450f3c8d 100755 --- a/src/ci/docker/dist-x86-linux/build-python.sh +++ b/src/ci/docker/dist-i686-linux/build-python.sh diff --git a/src/ci/docker/dist-x86-linux/shared.sh b/src/ci/docker/dist-i686-linux/shared.sh index 97e6d2908cf..97e6d2908cf 100644 --- a/src/ci/docker/dist-x86-linux/shared.sh +++ b/src/ci/docker/dist-i686-linux/shared.sh diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index 938c53ae488..33cca061103 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -13,12 +13,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ g++-mips-linux-gnu \ - g++-mipsel-linux-gnu \ libssl-dev \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] ENV HOSTS=mips-unknown-linux-gnu -ENV HOSTS=$HOSTS,mipsel-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index 45de8100b4f..157de83abb7 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -13,12 +13,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ g++-mips64-linux-gnuabi64 \ - g++-mips64el-linux-gnuabi64 \ libssl-dev \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] ENV HOSTS=mips64-unknown-linux-gnuabi64 -ENV HOSTS=$HOSTS,mips64el-unknown-linux-gnuabi64 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mips64el-linux/Dockerfile b/src/ci/docker/dist-mips64el-linux/Dockerfile new file mode 100644 index 00000000000..739d5ff6ac4 --- /dev/null +++ b/src/ci/docker/dist-mips64el-linux/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-mips64el-linux-gnuabi64 \ + libssl-dev \ + pkg-config + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV HOSTS=mips64el-unknown-linux-gnuabi64 + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mipsel-linux/Dockerfile b/src/ci/docker/dist-mipsel-linux/Dockerfile new file mode 100644 index 00000000000..9339063bc19 --- /dev/null +++ b/src/ci/docker/dist-mipsel-linux/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-mipsel-linux-gnu \ + libssl-dev \ + pkg-config + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV HOSTS=mipsel-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index c1e5e863ae0..92342caed2a 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-powerpc-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 7413c327323..182dfd93cc7 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -62,12 +62,8 @@ RUN ./build-powerpc64-toolchain.sh USER root -RUN apt-get install -y --no-install-recommends rpm2cpio cpio -COPY build-powerpc64le-toolchain.sh /tmp/ -RUN ./build-powerpc64le-toolchain.sh - RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin @@ -75,13 +71,9 @@ ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin ENV \ AR_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-ar \ CC_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-gcc \ - CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ \ - AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ - CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ - CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ ENV HOSTS=powerpc64-unknown-linux-gnu -ENV HOSTS=$HOSTS,powerpc64le-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/dist-powerpc64le-linux/Dockerfile new file mode 100644 index 00000000000..6b9f964d5a3 --- /dev/null +++ b/src/ci/docker/dist-powerpc64le-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +USER root + +RUN apt-get install -y --no-install-recommends rpm2cpio cpio +COPY shared.sh build-powerpc64le-toolchain.sh /tmp/ +RUN ./build-powerpc64le-toolchain.sh + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ + CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ + CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + +ENV HOSTS=powerpc64le-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh index 4d3e638916d..4d3e638916d 100755 --- a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh +++ b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh diff --git a/src/ci/docker/dist-powerpc64le-linux/shared.sh b/src/ci/docker/dist-powerpc64le-linux/shared.sh new file mode 100644 index 00000000000..97e6d2908cf --- /dev/null +++ b/src/ci/docker/dist-powerpc64le-linux/shared.sh @@ -0,0 +1,25 @@ +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux/Dockerfile index 4180006690f..7c94f713e18 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux/Dockerfile @@ -60,27 +60,20 @@ COPY patches/ /tmp/patches/ COPY s390x-linux-gnu.config build-s390x-toolchain.sh /tmp/ RUN ./build-s390x-toolchain.sh -COPY build-netbsd-toolchain.sh /tmp/ -RUN ./build-netbsd-toolchain.sh - USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache -ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin:/x-tools/x86_64-unknown-netbsd/bin +ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin ENV \ - AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \ - CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \ - CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot \ CC_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-gcc \ AR_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-ar \ CXX_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-g++ -ENV HOSTS=x86_64-unknown-netbsd -ENV HOSTS=$HOSTS,s390x-unknown-linux-gnu +ENV HOSTS=s390x-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh b/src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh index b4995e20dc6..b4995e20dc6 100755 --- a/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh +++ b/src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh diff --git a/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch index cba416ed2f7..cba416ed2f7 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch +++ b/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch diff --git a/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config b/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config index fa5e4510987..fa5e4510987 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config +++ b/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config diff --git a/src/ci/docker/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/dist-x86_64-freebsd/Dockerfile new file mode 100644 index 00000000000..a2939c8c485 --- /dev/null +++ b/src/ci/docker/dist-x86_64-freebsd/Dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + bzip2 \ + xz-utils \ + wget \ + libssl-dev \ + pkg-config + +COPY build-toolchain.sh /tmp/ +RUN /tmp/build-toolchain.sh x86_64 + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ + +ENV HOSTS=x86_64-unknown-freebsd + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh new file mode 100755 index 00000000000..5642e6fc937 --- /dev/null +++ b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +ARCH=$1 +BINUTILS=2.25.1 +GCC=5.3.0 + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir binutils +cd binutils + +# First up, build binutils +curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - +mkdir binutils-build +cd binutils-build +hide_output ../binutils-$BINUTILS/configure \ + --target=$ARCH-unknown-freebsd10 +hide_output make -j10 +hide_output make install +cd ../.. +rm -rf binutils + +# Next, download the FreeBSD libc and relevant header files + +mkdir freebsd +case "$ARCH" in + x86_64) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz + ;; + i686) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz + ;; +esac +curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib + +dst=/usr/local/$ARCH-unknown-freebsd10 + +cp -r freebsd/usr/include $dst/ +cp freebsd/usr/lib/crt1.o $dst/lib +cp freebsd/usr/lib/Scrt1.o $dst/lib +cp freebsd/usr/lib/crti.o $dst/lib +cp freebsd/usr/lib/crtn.o $dst/lib +cp freebsd/usr/lib/libc.a $dst/lib +cp freebsd/usr/lib/libutil.a $dst/lib +cp freebsd/usr/lib/libutil_p.a $dst/lib +cp freebsd/usr/lib/libm.a $dst/lib +cp freebsd/usr/lib/librt.so.1 $dst/lib +cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib +cp freebsd/lib/libc.so.7 $dst/lib +cp freebsd/lib/libm.so.5 $dst/lib +cp freebsd/lib/libutil.so.9 $dst/lib +cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so + +ln -s libc.so.7 $dst/lib/libc.so +ln -s libm.so.5 $dst/lib/libm.so +ln -s librt.so.1 $dst/lib/librt.so +ln -s libutil.so.9 $dst/lib/libutil.so +ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so +rm -rf freebsd + +# Finally, download and build gcc to target FreeBSD +mkdir gcc +cd gcc +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites + +mkdir ../gcc-build +cd ../gcc-build +hide_output ../gcc-$GCC/configure \ + --enable-languages=c,c++ \ + --target=$ARCH-unknown-freebsd10 \ + --disable-multilib \ + --disable-nls \ + --disable-libgomp \ + --disable-libquadmath \ + --disable-libssp \ + --disable-libvtv \ + --disable-libcilkrts \ + --disable-libada \ + --disable-libsanitizer \ + --disable-libquadmath-support \ + --disable-lto +hide_output make -j10 +hide_output make install +cd ../.. +rm -rf gcc diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile new file mode 100644 index 00000000000..cbe5f5936a5 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -0,0 +1,101 @@ +FROM centos:5 + +WORKDIR /build + +# Centos 5 is EOL and is no longer available from the usual mirrors, so switch +# to http://vault.centos.org/ +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf +RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo +RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo + +RUN yum upgrade -y && yum install -y \ + curl \ + bzip2 \ + gcc \ + gcc-c++ \ + make \ + glibc-devel \ + perl \ + zlib-devel \ + file \ + xz \ + which \ + pkgconfig \ + wget \ + autoconf \ + gettext + +ENV PATH=/rustroot/bin:$PATH +ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib +ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig +WORKDIR /tmp +COPY shared.sh build-binutils.sh /tmp/ + +# We need a build of openssl which supports SNI to download artifacts from +# static.rust-lang.org. This'll be used to link into libcurl below (and used +# later as well), so build a copy of OpenSSL with dynamic libraries into our +# generic root. +COPY build-openssl.sh /tmp/ +RUN ./build-openssl.sh + +# The `curl` binary on CentOS doesn't support SNI which is needed for fetching +# some https urls we have, so install a new version of libcurl + curl which is +# using the openssl we just built previously. +# +# Note that we also disable a bunch of optional features of curl that we don't +# really need. +COPY build-curl.sh /tmp/ +RUN ./build-curl.sh + +# binutils < 2.22 has a bug where the 32-bit executables it generates +# immediately segfault in Rust, so we need to install our own binutils. +# +# See https://github.com/rust-lang/rust/issues/20440 for more info +RUN ./build-binutils.sh + +# Need a newer version of gcc than centos has to compile LLVM nowadays +COPY build-gcc.sh /tmp/ +RUN ./build-gcc.sh + +# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+ +COPY build-python.sh /tmp/ +RUN ./build-python.sh + +# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for +# cloning, so download and build it here. +COPY build-git.sh /tmp/ +RUN ./build-git.sh + +# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS +# only has 2.6.4, so build our own +COPY build-cmake.sh /tmp/ +RUN ./build-cmake.sh + +# for sanitizers, we need kernel headers files newer than the ones CentOS ships +# with so we install newer ones here +COPY build-headers.sh /tmp/ +RUN ./build-headers.sh + +RUN curl -Lo /rustroot/dumb-init \ + https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 && \ + chmod +x /rustroot/dumb-init +ENTRYPOINT ["/rustroot/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV HOSTS=x86_64-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS \ + --host=$HOSTS \ + --enable-extended \ + --enable-sanitizers +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS + +# This is the only builder which will create source tarballs +ENV DIST_SRC 1 + +# When we build cargo in this container, we don't want it to use the system +# libcurl, instead it should compile its own. +ENV LIBCURL_NO_PKG_CONFIG 1 diff --git a/src/ci/docker/dist-x86_64-linux/build-binutils.sh b/src/ci/docker/dist-x86_64-linux/build-binutils.sh new file mode 100755 index 00000000000..80aa1f2a016 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-binutils.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +source shared.sh + +curl https://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2 | tar xfj - + +mkdir binutils-build +cd binutils-build +hide_output ../binutils-2.25.1/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf binutils-build +rm -rf binutils-2.25.1 diff --git a/src/ci/docker/dist-x86_64-linux/build-cmake.sh b/src/ci/docker/dist-x86_64-linux/build-cmake.sh new file mode 100755 index 00000000000..82e46455cb0 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-cmake.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://cmake.org/files/v3.6/cmake-3.6.3.tar.gz | tar xzf - + +mkdir cmake-build +cd cmake-build +hide_output ../cmake-3.6.3/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf cmake-build +rm -rf cmake-3.6.3 diff --git a/src/ci/docker/dist-x86_64-linux/build-curl.sh b/src/ci/docker/dist-x86_64-linux/build-curl.sh new file mode 100755 index 00000000000..b7d22755a57 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-curl.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +VERSION=7.51.0 + +curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf - + +mkdir curl-build +cd curl-build +hide_output ../curl-$VERSION/configure \ + --prefix=/rustroot \ + --with-ssl=/rustroot \ + --disable-sspi \ + --disable-gopher \ + --disable-smtp \ + --disable-smb \ + --disable-imap \ + --disable-pop3 \ + --disable-tftp \ + --disable-telnet \ + --disable-manual \ + --disable-dict \ + --disable-rtsp \ + --disable-ldaps \ + --disable-ldap +hide_output make -j10 +hide_output make install + +cd .. +rm -rf curl-build +rm -rf curl-$VERSION +yum erase -y curl diff --git a/src/ci/docker/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/dist-x86_64-linux/build-gcc.sh new file mode 100755 index 00000000000..ab2562538d6 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +source shared.sh + +GCC=4.8.5 + +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites +mkdir ../gcc-build +cd ../gcc-build +hide_output ../gcc-$GCC/configure \ + --prefix=/rustroot \ + --enable-languages=c,c++ +hide_output make -j10 +hide_output make install +ln -nsf gcc /rustroot/bin/cc + +cd .. +rm -rf gcc-build +rm -rf gcc-$GCC +yum erase -y gcc gcc-c++ binutils diff --git a/src/ci/docker/dist-x86_64-linux/build-git.sh b/src/ci/docker/dist-x86_64-linux/build-git.sh new file mode 100755 index 00000000000..92fa66b496d --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-git.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - + +cd git-2.10.0 +make configure +hide_output ./configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf git-2.10.0 diff --git a/src/ci/docker/dist-x86_64-linux/build-headers.sh b/src/ci/docker/dist-x86_64-linux/build-headers.sh new file mode 100755 index 00000000000..4ce38fd9205 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-headers.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x + +cd linux-3.2.84 +hide_output make mrproper +hide_output make INSTALL_HDR_PATH=dest headers_install + +find dest/include \( -name .install -o -name ..install.cmd \) -delete +yes | cp -fr dest/include/* /usr/include + +cd .. +rm -rf linux-3.2.84 diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh new file mode 100755 index 00000000000..64b1abf82a8 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +VERSION=1.0.2j + +curl https://www.openssl.org/source/openssl-$VERSION.tar.gz | tar xzf - + +cd openssl-$VERSION +hide_output ./config --prefix=/rustroot shared -fPIC +hide_output make -j10 +hide_output make install +cd .. +rm -rf openssl-$VERSION + +# Make the system cert collection available to the new install. +ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/ diff --git a/src/ci/docker/dist-x86_64-linux/build-python.sh b/src/ci/docker/dist-x86_64-linux/build-python.sh new file mode 100755 index 00000000000..a7a450f3c8d --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-python.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz | \ + tar xzf - + +mkdir python-build +cd python-build + +# Gotta do some hackery to tell python about our custom OpenSSL build, but other +# than that fairly normal. +CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ + hide_output ../Python-2.7.12/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf python-build +rm -rf Python-2.7.12 diff --git a/src/ci/docker/dist-x86_64-linux/shared.sh b/src/ci/docker/dist-x86_64-linux/shared.sh new file mode 100644 index 00000000000..97e6d2908cf --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/shared.sh @@ -0,0 +1,25 @@ +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 085aa351659..a41c0cca3b5 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ diff --git a/src/ci/docker/dist-x86_64-musl/build-musl.sh b/src/ci/docker/dist-x86_64-musl/build-musl.sh index 86bb259c854..776da009397 100644 --- a/src/ci/docker/dist-x86_64-musl/build-musl.sh +++ b/src/ci/docker/dist-x86_64-musl/build-musl.sh @@ -15,7 +15,7 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL ./configure --prefix=/musl-x86_64 --disable-shared diff --git a/src/ci/docker/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/dist-x86_64-netbsd/Dockerfile new file mode 100644 index 00000000000..a1dd9a3724a --- /dev/null +++ b/src/ci/docker/dist-x86_64-netbsd/Dockerfile @@ -0,0 +1,78 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY build-netbsd-toolchain.sh /tmp/ +RUN ./build-netbsd-toolchain.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/x86_64-unknown-netbsd/bin + +ENV \ + AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \ + CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \ + CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot + +ENV HOSTS=x86_64-unknown-netbsd + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh index ea335a24973..ea335a24973 100755 --- a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile index 77cf54a19a7..ffdb1d18a94 100644 --- a/src/ci/docker/emscripten/Dockerfile +++ b/src/ci/docker/emscripten/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lib32stdc++6 RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile index c84cf56e4e8..34d0567a440 100644 --- a/src/ci/docker/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile index f4bb9083b85..960a0fa7a38 100644 --- a/src/ci/docker/i686-gnu/Dockerfile +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile index 68184c65cf1..9871df90e00 100644 --- a/src/ci/docker/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 6320a806fc3..197b0ec9b9b 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile index 180f53ec33f..60af302791a 100644 --- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile index 4500fc0f642..4ec0b5c1525 100644 --- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile +++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile index ad1227fa581..6448f88950f 100644 --- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile index f1240201805..c00667fe1dd 100644 --- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile index fa9707d1a73..7284d231b84 100644 --- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index e5d89034dbe..1dce84bc5fd 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 292f5a1ec81..20812de524a 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -123,6 +123,7 @@ - [no_debug](no-debug.md) - [non_ascii_idents](non-ascii-idents.md) - [nonzero](nonzero.md) +- [offset_to](offset-to.md) - [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md) - [on_unimplemented](on-unimplemented.md) - [once_poison](once-poison.md) @@ -171,6 +172,7 @@ - [slice_concat_ext](slice-concat-ext.md) - [slice_get_slice](slice-get-slice.md) - [slice_patterns](slice-patterns.md) +- [slice_rsplit](slice-rsplit.md) - [sort_internals](sort-internals.md) - [sort_unstable](sort-unstable.md) - [specialization](specialization.md) @@ -203,11 +205,11 @@ - [unwind_attributes](unwind-attributes.md) - [update_panic_count](update-panic-count.md) - [use_extern_macros](use-extern-macros.md) +- [used](used.md) - [utf8_error_error_len](utf8-error-error-len.md) - [vec_remove_item](vec-remove-item.md) - [windows_c](windows-c.md) - [windows_handle](windows-handle.md) - [windows_net](windows-net.md) - [windows_stdio](windows-stdio.md) -- [windows_subsystem](windows-subsystem.md) - [zero_one](zero-one.md) diff --git a/src/doc/unstable-book/src/offset-to.md b/src/doc/unstable-book/src/offset-to.md new file mode 100644 index 00000000000..03d990eb4ae --- /dev/null +++ b/src/doc/unstable-book/src/offset-to.md @@ -0,0 +1,7 @@ +# `offset_to` + +The tracking issue for this feature is: [#41079] + +[#41079]: https://github.com/rust-lang/rust/issues/41079 + +------------------------ diff --git a/src/doc/unstable-book/src/slice-rsplit.md b/src/doc/unstable-book/src/slice-rsplit.md new file mode 100644 index 00000000000..8c2954f7294 --- /dev/null +++ b/src/doc/unstable-book/src/slice-rsplit.md @@ -0,0 +1,10 @@ +# `slice_rsplit` + +The tracking issue for this feature is: [#41020] + +[#41020]: https://github.com/rust-lang/rust/issues/41020 + +------------------------ + +The `slice_rsplit` feature enables two methods on slices: +`slice.rsplit(predicate)` and `slice.rsplit_mut(predicate)`. diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md new file mode 100644 index 00000000000..75a8b2774f4 --- /dev/null +++ b/src/doc/unstable-book/src/used.md @@ -0,0 +1,153 @@ +# `used` + +The tracking issue for this feature +is: [40289](https://github.com/rust-lang/rust/issues/40289). + +------------------------ + +The `#[used]` attribute can be applied to `static` variables to prevent the Rust +compiler from optimizing them away even if they appear to be unused by the crate +(appear to be "dead code"). + +``` rust +#![feature(used)] + +#[used] +static FOO: i32 = 1; + +static BAR: i32 = 2; + +fn main() {} +``` + +If you compile this program into an object file, you'll see that `FOO` makes it +to the object file but `BAR` doesn't. Neither static variable is used by the +program. + +``` text +$ rustc -C opt-level=3 --emit=obj used.rs + +$ nm -C used.o +0000000000000000 T main + U std::rt::lang_start +0000000000000000 r used::FOO +0000000000000000 t used::main +``` + +Note that the *linker* knows nothing about the `#[used]` attribute and will +remove `#[used]` symbols if they are not referenced by other parts of the +program: + +``` text +$ rustc -C opt-level=3 used.rs + +$ nm -C used | grep FOO +``` + +"This doesn't sound too useful then!" you may think but keep reading. + +To preserve the symbols all the way to the final binary, you'll need the +cooperation of the linker. Here's one example: + +The ELF standard defines two special sections, `.init_array` and +`.pre_init_array`, that may contain function pointers which will be executed +*before* the `main` function is invoked. The linker will preserve symbols placed +in these sections (at least when linking programs that target the `*-*-linux-*` +targets). + +``` rust,ignore +#![feature(used)] + +extern "C" fn before_main() { + println!("Hello, world!"); +} + +#[link_section = ".init_array"] +#[used] +static INIT_ARRAY: [extern "C" fn(); 1] = [before_main]; + +fn main() {} +``` + +So, `#[used]` and `#[link_section]` can be combined to obtain "life before +main". + +``` text +$ rustc -C opt-level=3 before-main.rs + +$ ./before-main +Hello, world! +``` + +Another example: ARM Cortex-M microcontrollers need their reset handler, a +pointer to the function that will executed right after the microcontroller is +turned on, to be placed near the start of their FLASH memory to boot properly. + +This condition can be met using `#[used]` and `#[link_section]` plus a linker +script. + +``` rust,ignore +#![feature(lang_items)] +#![feature(used)] +#![no_main] +#![no_std] + +extern "C" fn reset_handler() -> ! { + loop {} +} + +#[link_section = ".reset_handler"] +#[used] +static RESET_HANDLER: extern "C" fn() -> ! = reset_handler; + +#[lang = "panic_fmt"] +fn panic_fmt() {} +``` + +``` text +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 128K + RAM : ORIGIN = 0x20000000, LENGTH = 20K +} + +SECTIONS +{ + .text ORIGIN(FLASH) : + { + /* Vector table */ + LONG(ORIGIN(RAM) + LENGTH(RAM)); /* initial SP value */ + KEEP(*(.reset_handler)); + + /* Omitted: The rest of the vector table */ + + *(.text.*); + } > FLASH + + /DISCARD/ : + { + /* Unused unwinding stuff */ + *(.ARM.exidx.*) + } +} +``` + +``` text +$ xargo rustc --target thumbv7m-none-eabi --release -- \ + -C link-arg=-Tlink.x -C link-arg=-nostartfiles + +$ arm-none-eabi-objdump -Cd target/thumbv7m-none-eabi/release/app +./target/thumbv7m-none-eabi/release/app: file format elf32-littlearm + + +Disassembly of section .text: + +08000000 <app::RESET_HANDLER-0x4>: + 8000000: 20005000 .word 0x20005000 + +08000004 <app::RESET_HANDLER>: + 8000004: 08000009 .... + +08000008 <app::reset_handler>: + 8000008: e7fe b.n 8000008 <app::reset_handler> +``` diff --git a/src/doc/unstable-book/src/windows-subsystem.md b/src/doc/unstable-book/src/windows-subsystem.md deleted file mode 100644 index 80583352fbf..00000000000 --- a/src/doc/unstable-book/src/windows-subsystem.md +++ /dev/null @@ -1,10 +0,0 @@ -# `windows_subsystem` - -The tracking issue for this feature is: [#37499] - -[#37499]: https://github.com/rust-lang/rust/issues/37499 - ------------------------- - - - diff --git a/src/etc/char_private.py b/src/etc/char_private.py index 9d15f98e067..75ab3f1a17b 100644 --- a/src/etc/char_private.py +++ b/src/etc/char_private.py @@ -76,6 +76,66 @@ def get_codepoints(f): for c in range(prev_codepoint + 1, NUM_CODEPOINTS): yield Codepoint(c, None) +def compress_singletons(singletons): + uppers = [] # (upper, # items in lowers) + lowers = [] + + for i in singletons: + upper = i >> 8 + lower = i & 0xff + if len(uppers) == 0 or uppers[-1][0] != upper: + uppers.append((upper, 1)) + else: + upper, count = uppers[-1] + uppers[-1] = upper, count + 1 + lowers.append(lower) + + return uppers, lowers + +def compress_normal(normal): + # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f + # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff + compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] + + prev_start = 0 + for start, count in normal: + truelen = start - prev_start + falselen = count + prev_start = start + count + + assert truelen < 0x8000 and falselen < 0x8000 + entry = [] + if truelen > 0x7f: + entry.append(0x80 | (truelen >> 8)) + entry.append(truelen & 0xff) + else: + entry.append(truelen & 0x7f) + if falselen > 0x7f: + entry.append(0x80 | (falselen >> 8)) + entry.append(falselen & 0xff) + else: + entry.append(falselen & 0x7f) + + compressed.append(entry) + + return compressed + +def print_singletons(uppers, lowers, uppersname, lowersname): + print("const {}: &'static [(u8, u8)] = &[".format(uppersname)) + for u, c in uppers: + print(" ({:#04x}, {}),".format(u, c)) + print("];") + print("const {}: &'static [u8] = &[".format(lowersname)) + for i in range(0, len(lowers), 8): + print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) + print("];") + +def print_normal(normal, normalname): + print("const {}: &'static [u8] = &[".format(normalname)) + for v in normal: + print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) + print("];") + def main(): file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt") @@ -111,6 +171,11 @@ def main(): else: normal0.append((a, b - a)) + singletons0u, singletons0l = compress_singletons(singletons0) + singletons1u, singletons1l = compress_singletons(singletons1) + normal0 = compress_normal(normal0) + normal1 = compress_normal(normal1) + print("""\ // Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at @@ -125,38 +190,49 @@ def main(): // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - -fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { - for &s in singletons { - if x == s { - return false; - } else if x < s { +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } + } + } else if xupper < upper { break; } + lowerstart = lowerend; } - for w in normal.chunks(2) { - let start = w[0]; - let len = w[1]; - let difference = (x as i32) - (start as i32); - if 0 <= difference { - if difference < len as i32 { - return false; - } + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 } else { + v as i32 + }; + x -= len; + if x < 0 { break; } + current = !current; } - true + current } pub fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { - check(lower, SINGLETONS0, NORMAL0) + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) } else if x < 0x20000 { - check(lower, SINGLETONS1, NORMAL1) + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else {\ """) for a, b in extra: @@ -169,22 +245,10 @@ pub fn is_printable(x: char) -> bool { }\ """) print() - print("const SINGLETONS0: &'static [u16] = &[") - for s in singletons0: - print(" 0x{:x},".format(s)) - print("];") - print("const SINGLETONS1: &'static [u16] = &[") - for s in singletons1: - print(" 0x{:x},".format(s)) - print("];") - print("const NORMAL0: &'static [u16] = &[") - for a, b in normal0: - print(" 0x{:x}, 0x{:x},".format(a, b)) - print("];") - print("const NORMAL1: &'static [u16] = &[") - for a, b in normal1: - print(" 0x{:x}, 0x{:x},".format(a, b)) - print("];") + print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L') + print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L') + print_normal(normal0, 'NORMAL0') + print_normal(normal1, 'NORMAL1') if __name__ == '__main__': main() diff --git a/src/etc/make-win-dist.py b/src/etc/make-win-dist.py index eda5f854085..394ff97d845 100644 --- a/src/etc/make-win-dist.py +++ b/src/etc/make-win-dist.py @@ -51,7 +51,7 @@ def make_win_dist(rust_root, plat_root, target_triple): target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe"] - rustc_dlls = ["libstdc++-6.dll"] + rustc_dlls = ["libstdc++-6.dll", "libwinpthread-1.dll"] if target_triple.startswith("i686-"): rustc_dlls.append("libgcc_s_dw2-1.dll") else: @@ -67,6 +67,7 @@ def make_win_dist(rust_root, plat_root, target_triple): "libstdc++.a", "libiconv.a", "libmoldname.a", + "libpthread.a", # Windows import libs "libadvapi32.a", "libbcrypt.a", diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml index 02b2171a224..7e92404bc0d 100644 --- a/src/libcollections/Cargo.toml +++ b/src/libcollections/Cargo.toml @@ -13,8 +13,8 @@ core = { path = "../libcore" } std_unicode = { path = "../libstd_unicode" } [[test]] -name = "collectionstest" -path = "../libcollectionstest/lib.rs" +name = "collectionstests" +path = "../libcollections/tests/lib.rs" [[bench]] name = "collectionsbenches" diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 00448b6abb2..248c15e96f8 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -52,6 +52,7 @@ #![feature(shared)] #![feature(slice_get_slice)] #![feature(slice_patterns)] +#![feature(slice_rsplit)] #![cfg_attr(not(test), feature(sort_unstable))] #![feature(specialization)] #![feature(staged_api)] @@ -62,6 +63,7 @@ #![feature(untagged_unions)] #![cfg_attr(not(test), feature(str_checked_slicing))] #![cfg_attr(test, feature(rand, test))] +#![feature(offset_to)] #![no_std] diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 8f0488f6936..1b3eeb837d9 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -697,8 +697,8 @@ impl<T> LinkedList<T> { /// Returns a place for insertion at the front of the list. /// - /// Using this method with placement syntax is equivalent to [`push_front`] - /// (#method.push_front), but may be more efficient. + /// Using this method with placement syntax is equivalent to + /// [`push_front`](#method.push_front), but may be more efficient. /// /// # Examples /// diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 6f8843c2374..6cff315a6cc 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -115,6 +115,8 @@ pub use core::slice::{Iter, IterMut}; pub use core::slice::{SplitMut, ChunksMut, Split}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; +#[unstable(feature = "slice_rsplit", issue = "41020")] +pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; #[unstable(feature = "slice_get_slice", issue = "35729")] @@ -780,6 +782,72 @@ impl<T> [T] { } /// Returns an iterator over subslices separated by elements that match + /// `pred`, starting at the end of the slice and working backwards. + /// The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_rsplit)] + /// + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let mut iter = slice.rsplit(|num| *num == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[44, 55]); + /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// As with `split()`, if the first or last element is matched, an empty + /// slice will be the first (or last) item returned by the iterator. + /// + /// ``` + /// #![feature(slice_rsplit)] + /// + /// let v = &[0, 1, 1, 2, 3, 5, 8]; + /// let mut it = v.rsplit(|n| *n % 2 == 0); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next().unwrap(), &[3, 5]); + /// assert_eq!(it.next().unwrap(), &[1, 1]); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next(), None); + /// ``` + #[unstable(feature = "slice_rsplit", issue = "41020")] + #[inline] + pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F> + where F: FnMut(&T) -> bool + { + core_slice::SliceExt::rsplit(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, starting at the end of the slice and working + /// backwards. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_rsplit)] + /// + /// let mut v = [100, 400, 300, 200, 600, 500]; + /// + /// let mut count = 0; + /// for group in v.rsplit_mut(|num| *num % 3 == 0) { + /// count += 1; + /// group[0] = count; + /// } + /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// ``` + /// + #[unstable(feature = "slice_rsplit", issue = "41020")] + #[inline] + pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F> + where F: FnMut(&T) -> bool + { + core_slice::SliceExt::rsplit_mut(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match /// `pred`, limited to returning at most `n` items. The matched element is /// not contained in the subslices. /// diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollections/tests/binary_heap.rs index d284937a9e6..d284937a9e6 100644 --- a/src/libcollectionstest/binary_heap.rs +++ b/src/libcollections/tests/binary_heap.rs diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollections/tests/btree/map.rs index 2c899d96940..2c899d96940 100644 --- a/src/libcollectionstest/btree/map.rs +++ b/src/libcollections/tests/btree/map.rs diff --git a/src/libcollectionstest/btree/mod.rs b/src/libcollections/tests/btree/mod.rs index ae8b18d0c9f..ae8b18d0c9f 100644 --- a/src/libcollectionstest/btree/mod.rs +++ b/src/libcollections/tests/btree/mod.rs diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollections/tests/btree/set.rs index 6171b8ba624..6171b8ba624 100644 --- a/src/libcollectionstest/btree/set.rs +++ b/src/libcollections/tests/btree/set.rs diff --git a/src/libcollectionstest/cow_str.rs b/src/libcollections/tests/cow_str.rs index b29245121da..b29245121da 100644 --- a/src/libcollectionstest/cow_str.rs +++ b/src/libcollections/tests/cow_str.rs diff --git a/src/libcollectionstest/fmt.rs b/src/libcollections/tests/fmt.rs index 70e21c65a18..70e21c65a18 100644 --- a/src/libcollectionstest/fmt.rs +++ b/src/libcollections/tests/fmt.rs diff --git a/src/libcollectionstest/lib.rs b/src/libcollections/tests/lib.rs index 618eb386c0f..618eb386c0f 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollections/tests/lib.rs diff --git a/src/libcollectionstest/linked_list.rs b/src/libcollections/tests/linked_list.rs index a59724a017b..a59724a017b 100644 --- a/src/libcollectionstest/linked_list.rs +++ b/src/libcollections/tests/linked_list.rs diff --git a/src/libcollectionstest/slice.rs b/src/libcollections/tests/slice.rs index c3e5304fb2b..c3e5304fb2b 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollections/tests/slice.rs diff --git a/src/libcollectionstest/str.rs b/src/libcollections/tests/str.rs index c9b7104fec4..c9b7104fec4 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollections/tests/str.rs diff --git a/src/libcollectionstest/string.rs b/src/libcollections/tests/string.rs index 2f021b9935d..2f021b9935d 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollections/tests/string.rs diff --git a/src/libcollectionstest/vec.rs b/src/libcollections/tests/vec.rs index 63df0eb7305..63df0eb7305 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollections/tests/vec.rs diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollections/tests/vec_deque.rs index f2935c05d4f..f2935c05d4f 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollections/tests/vec_deque.rs diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 56b60a3e003..35ecf411db4 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -678,8 +678,9 @@ impl<T> Vec<T> { self.len = len; } - /// Removes an element from anywhere in the vector and return it, replacing - /// it with the last element. + /// Removes an element from the vector and returns it. + /// + /// The removed element is replaced by the last element of the vector. /// /// This does not preserve ordering, but is O(1). /// @@ -972,6 +973,29 @@ impl<T> Vec<T> { } } + /// Returns a place for insertion at the back of the `Vec`. + /// + /// Using this method with placement syntax is equivalent to [`push`](#method.push), + /// but may be more efficient. + /// + /// # Examples + /// + /// ``` + /// #![feature(collection_placement)] + /// #![feature(placement_in_syntax)] + /// + /// let mut vec = vec![1, 2]; + /// vec.place_back() <- 3; + /// vec.place_back() <- 4; + /// assert_eq!(&vec, &[1, 2, 3, 4]); + /// ``` + #[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] + pub fn place_back(&mut self) -> PlaceBack<T> { + PlaceBack { vec: self } + } + /// Removes the last element from a vector and returns it, or [`None`] if it /// is empty. /// @@ -1266,29 +1290,6 @@ impl<T: Clone> Vec<T> { pub fn extend_from_slice(&mut self, other: &[T]) { self.spec_extend(other.iter()) } - - /// Returns a place for insertion at the back of the `Vec`. - /// - /// Using this method with placement syntax is equivalent to [`push`](#method.push), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// let mut vec = vec![1, 2]; - /// vec.place_back() <- 3; - /// vec.place_back() <- 4; - /// assert_eq!(&vec, &[1, 2, 3, 4]); - /// ``` - #[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] - pub fn place_back(&mut self) -> PlaceBack<T> { - PlaceBack { vec: self } - } } // Set the length of the vec when the `SetLenOnDrop` value goes out of scope. @@ -1345,7 +1346,7 @@ impl<T: PartialEq> Vec<T> { /// # Examples /// /// ``` - ///# #![feature(vec_remove_item)] + /// # #![feature(vec_remove_item)] /// let mut vec = vec![1, 2, 3, 1]; /// /// vec.remove_item(&1); @@ -2073,14 +2074,10 @@ impl<T> Iterator for IntoIter<T> { #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - let diff = (self.end as usize) - (self.ptr as usize); - let size = mem::size_of::<T>(); - let exact = diff / - (if size == 0 { - 1 - } else { - size - }); + let exact = match self.ptr.offset_to(self.end) { + Some(x) => x as usize, + None => (self.end as usize).wrapping_sub(self.ptr as usize), + }; (exact, Some(exact)) } diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index cb92236ec73..22f2ff1a346 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -635,7 +635,7 @@ impl<T> VecDeque<T> { } } - /// Shortens a `VecDeque`, dropping excess elements from the back. + /// Shortens the `VecDeque`, dropping excess elements from the back. /// /// If `len` is greater than the `VecDeque`'s current length, this has no /// effect. @@ -941,7 +941,7 @@ impl<T> VecDeque<T> { a.contains(x) || b.contains(x) } - /// Provides a reference to the front element, or `None` if the sequence is + /// Provides a reference to the front element, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -966,7 +966,7 @@ impl<T> VecDeque<T> { } /// Provides a mutable reference to the front element, or `None` if the - /// sequence is empty. + /// `VecDeque` is empty. /// /// # Examples /// @@ -993,7 +993,7 @@ impl<T> VecDeque<T> { } } - /// Provides a reference to the back element, or `None` if the sequence is + /// Provides a reference to the back element, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -1018,7 +1018,7 @@ impl<T> VecDeque<T> { } /// Provides a mutable reference to the back element, or `None` if the - /// sequence is empty. + /// `VecDeque` is empty. /// /// # Examples /// @@ -1046,7 +1046,7 @@ impl<T> VecDeque<T> { } } - /// Removes the first element and returns it, or `None` if the sequence is + /// Removes the first element and returns it, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -1073,7 +1073,7 @@ impl<T> VecDeque<T> { } } - /// Inserts an element first in the sequence. + /// Prepends an element to the `VecDeque`. /// /// # Examples /// @@ -1096,7 +1096,7 @@ impl<T> VecDeque<T> { } } - /// Appends an element to the back of a buffer + /// Appends an element to the back of the `VecDeque`. /// /// # Examples /// @@ -1117,7 +1117,7 @@ impl<T> VecDeque<T> { unsafe { self.buffer_write(head, value) } } - /// Removes the last element from a buffer and returns it, or `None` if + /// Removes the last element from the `VecDeque` and returns it, or `None` if /// it is empty. /// /// # Examples diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index e847c7fa3a0..5af63aa970f 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -10,8 +10,8 @@ test = false bench = false [[test]] -name = "coretest" -path = "../libcoretest/lib.rs" +name = "coretests" +path = "../libcore/tests/lib.rs" [[bench]] name = "corebenches" diff --git a/src/libcore/char_private.rs b/src/libcore/char_private.rs index ddc473592a2..2c0f449b276 100644 --- a/src/libcore/char_private.rs +++ b/src/libcore/char_private.rs @@ -11,38 +11,49 @@ // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - -fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { - for &s in singletons { - if x == s { - return false; - } else if x < s { +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } + } + } else if xupper < upper { break; } + lowerstart = lowerend; } - for w in normal.chunks(2) { - let start = w[0]; - let len = w[1]; - let difference = (x as i32) - (start as i32); - if 0 <= difference { - if difference < len as i32 { - return false; - } + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 } else { + v as i32 + }; + x -= len; + if x < 0 { break; } + current = !current; } - true + current } pub fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { - check(lower, SINGLETONS0, NORMAL0) + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) } else if x < 0x20000 { - check(lower, SINGLETONS1, NORMAL1) + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else { if 0x2a6d7 <= x && x < 0x2a700 { return false; @@ -66,761 +77,446 @@ pub fn is_printable(x: char) -> bool { } } -const SINGLETONS0: &'static [u16] = &[ - 0xad, - 0x378, - 0x379, - 0x38b, - 0x38d, - 0x3a2, - 0x530, - 0x557, - 0x558, - 0x560, - 0x588, - 0x58b, - 0x58c, - 0x590, - 0x61c, - 0x61d, - 0x6dd, - 0x70e, - 0x70f, - 0x74b, - 0x74c, - 0x82e, - 0x82f, - 0x83f, - 0x85c, - 0x85d, - 0x8b5, - 0x8e2, - 0x984, - 0x98d, - 0x98e, - 0x991, - 0x992, - 0x9a9, - 0x9b1, - 0x9ba, - 0x9bb, - 0x9c5, - 0x9c6, - 0x9c9, - 0x9ca, - 0x9de, - 0x9e4, - 0x9e5, - 0xa04, - 0xa11, - 0xa12, - 0xa29, - 0xa31, - 0xa34, - 0xa37, - 0xa3a, - 0xa3b, - 0xa3d, - 0xa49, - 0xa4a, - 0xa5d, - 0xa84, - 0xa8e, - 0xa92, - 0xaa9, - 0xab1, - 0xab4, - 0xaba, - 0xabb, - 0xac6, - 0xaca, - 0xace, - 0xacf, - 0xae4, - 0xae5, - 0xb04, - 0xb0d, - 0xb0e, - 0xb11, - 0xb12, - 0xb29, - 0xb31, - 0xb34, - 0xb3a, - 0xb3b, - 0xb45, - 0xb46, - 0xb49, - 0xb4a, - 0xb5e, - 0xb64, - 0xb65, - 0xb84, - 0xb91, - 0xb9b, - 0xb9d, - 0xbc9, - 0xbce, - 0xbcf, - 0xc04, - 0xc0d, - 0xc11, - 0xc29, - 0xc45, - 0xc49, - 0xc57, - 0xc64, - 0xc65, - 0xc84, - 0xc8d, - 0xc91, - 0xca9, - 0xcb4, - 0xcba, - 0xcbb, - 0xcc5, - 0xcc9, - 0xcdf, - 0xce4, - 0xce5, - 0xcf0, - 0xd04, - 0xd0d, - 0xd11, - 0xd3b, - 0xd3c, - 0xd45, - 0xd49, - 0xd64, - 0xd65, - 0xd80, - 0xd81, - 0xd84, - 0xdb2, - 0xdbc, - 0xdbe, - 0xdbf, - 0xdd5, - 0xdd7, - 0xdf0, - 0xdf1, - 0xe83, - 0xe85, - 0xe86, - 0xe89, - 0xe8b, - 0xe8c, - 0xe98, - 0xea0, - 0xea4, - 0xea6, - 0xea8, - 0xea9, - 0xeac, - 0xeba, - 0xebe, - 0xebf, - 0xec5, - 0xec7, - 0xece, - 0xecf, - 0xeda, - 0xedb, - 0xf48, - 0xf98, - 0xfbd, - 0xfcd, - 0x10c6, - 0x10ce, - 0x10cf, - 0x1249, - 0x124e, - 0x124f, - 0x1257, - 0x1259, - 0x125e, - 0x125f, - 0x1289, - 0x128e, - 0x128f, - 0x12b1, - 0x12b6, - 0x12b7, - 0x12bf, - 0x12c1, - 0x12c6, - 0x12c7, - 0x12d7, - 0x1311, - 0x1316, - 0x1317, - 0x135b, - 0x135c, - 0x13f6, - 0x13f7, - 0x13fe, - 0x13ff, - 0x1680, - 0x170d, - 0x176d, - 0x1771, - 0x17de, - 0x17df, - 0x180e, - 0x180f, - 0x191f, - 0x196e, - 0x196f, - 0x1a1c, - 0x1a1d, - 0x1a5f, - 0x1a7d, - 0x1a7e, - 0x1aae, - 0x1aaf, - 0x1cf7, - 0x1f16, - 0x1f17, - 0x1f1e, - 0x1f1f, - 0x1f46, - 0x1f47, - 0x1f4e, - 0x1f4f, - 0x1f58, - 0x1f5a, - 0x1f5c, - 0x1f5e, - 0x1f7e, - 0x1f7f, - 0x1fb5, - 0x1fc5, - 0x1fd4, - 0x1fd5, - 0x1fdc, - 0x1ff0, - 0x1ff1, - 0x1ff5, - 0x2072, - 0x2073, - 0x208f, - 0x23ff, - 0x2b74, - 0x2b75, - 0x2b96, - 0x2b97, - 0x2bc9, - 0x2c2f, - 0x2c5f, - 0x2d26, - 0x2d2e, - 0x2d2f, - 0x2da7, - 0x2daf, - 0x2db7, - 0x2dbf, - 0x2dc7, - 0x2dcf, - 0x2dd7, - 0x2ddf, - 0x2e9a, - 0x3040, - 0x3097, - 0x3098, - 0x318f, - 0x321f, - 0x32ff, - 0xa7af, - 0xa8fe, - 0xa8ff, - 0xa9ce, - 0xa9ff, - 0xaa4e, - 0xaa4f, - 0xaa5a, - 0xaa5b, - 0xab07, - 0xab08, - 0xab0f, - 0xab10, - 0xab27, - 0xab2f, - 0xabee, - 0xabef, - 0xfa6e, - 0xfa6f, - 0xfb37, - 0xfb3d, - 0xfb3f, - 0xfb42, - 0xfb45, - 0xfd90, - 0xfd91, - 0xfdfe, - 0xfdff, - 0xfe53, - 0xfe67, - 0xfe75, - 0xffc8, - 0xffc9, - 0xffd0, - 0xffd1, - 0xffd8, - 0xffd9, - 0xffe7, - 0xfffe, - 0xffff, +const SINGLETONS0U: &'static [(u8, u8)] = &[ + (0x00, 1), + (0x03, 5), + (0x05, 8), + (0x06, 3), + (0x07, 4), + (0x08, 7), + (0x09, 16), + (0x0a, 27), + (0x0b, 24), + (0x0c, 22), + (0x0d, 20), + (0x0e, 22), + (0x0f, 4), + (0x10, 3), + (0x12, 18), + (0x13, 9), + (0x16, 1), + (0x17, 5), + (0x18, 2), + (0x19, 3), + (0x1a, 7), + (0x1c, 1), + (0x1f, 22), + (0x20, 3), + (0x23, 1), + (0x2b, 5), + (0x2c, 2), + (0x2d, 11), + (0x2e, 1), + (0x30, 3), + (0x31, 1), + (0x32, 2), + (0xa7, 1), + (0xa8, 2), + (0xa9, 2), + (0xaa, 4), + (0xab, 8), + (0xfa, 2), + (0xfb, 5), + (0xfd, 4), + (0xfe, 3), + (0xff, 9), ]; -const SINGLETONS1: &'static [u16] = &[ - 0xc, - 0x27, - 0x3b, - 0x3e, - 0x4e, - 0x4f, - 0x18f, - 0x39e, - 0x49e, - 0x49f, - 0x806, - 0x807, - 0x809, - 0x836, - 0x83d, - 0x83e, - 0x856, - 0x8f3, - 0x9d0, - 0x9d1, - 0xa04, - 0xa14, - 0xa18, - 0xb56, - 0xb57, - 0x10bd, - 0x1135, - 0x11ce, - 0x11cf, - 0x11e0, - 0x1212, - 0x1287, - 0x1289, - 0x128e, - 0x129e, - 0x1304, - 0x130d, - 0x130e, - 0x1311, - 0x1312, - 0x1329, - 0x1331, - 0x1334, - 0x133a, - 0x133b, - 0x1345, - 0x1346, - 0x1349, - 0x134a, - 0x134e, - 0x134f, - 0x1364, - 0x1365, - 0x145a, - 0x145c, - 0x15b6, - 0x15b7, - 0x1c09, - 0x1c37, - 0x1c90, - 0x1c91, - 0x1ca8, - 0x246f, - 0x6a5f, - 0x6aee, - 0x6aef, - 0x6b5a, - 0x6b62, - 0xbc9a, - 0xbc9b, - 0xd127, - 0xd128, - 0xd455, - 0xd49d, - 0xd4a0, - 0xd4a1, - 0xd4a3, - 0xd4a4, - 0xd4a7, - 0xd4a8, - 0xd4ad, - 0xd4ba, - 0xd4bc, - 0xd4c4, - 0xd506, - 0xd50b, - 0xd50c, - 0xd515, - 0xd51d, - 0xd53a, - 0xd53f, - 0xd545, - 0xd551, - 0xd6a6, - 0xd6a7, - 0xd7cc, - 0xd7cd, - 0xdaa0, - 0xe007, - 0xe019, - 0xe01a, - 0xe022, - 0xe025, - 0xe8c5, - 0xe8c6, - 0xee04, - 0xee20, - 0xee23, - 0xee25, - 0xee26, - 0xee28, - 0xee33, - 0xee38, - 0xee3a, - 0xee48, - 0xee4a, - 0xee4c, - 0xee50, - 0xee53, - 0xee55, - 0xee56, - 0xee58, - 0xee5a, - 0xee5c, - 0xee5e, - 0xee60, - 0xee63, - 0xee65, - 0xee66, - 0xee6b, - 0xee73, - 0xee78, - 0xee7d, - 0xee7f, - 0xee8a, - 0xeea4, - 0xeeaa, - 0xf0af, - 0xf0b0, - 0xf0c0, - 0xf0d0, - 0xf12f, - 0xf91f, - 0xf931, - 0xf932, - 0xf93f, +const SINGLETONS0L: &'static [u8] = &[ + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, + 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, + 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, + 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, 0xc9, + 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, 0x29, + 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, + 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, + 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, 0x04, + 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, + 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, 0xcf, 0x04, + 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, + 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, + 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, 0x0d, 0x11, + 0x3b, 0x3c, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, + 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, + 0xf1, 0x83, 0x85, 0x86, 0x89, 0x8b, 0x8c, 0x98, + 0xa0, 0xa4, 0xa6, 0xa8, 0xa9, 0xac, 0xba, 0xbe, + 0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb, 0x48, + 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e, + 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, + 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, + 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, + 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, + 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, + 0x7e, 0xae, 0xaf, 0xf7, 0x16, 0x17, 0x1e, 0x1f, + 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, + 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, + 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0xff, 0x74, 0x75, + 0x96, 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, + 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, + 0x9a, 0x40, 0x97, 0x98, 0x8f, 0x1f, 0xff, 0xaf, + 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, + 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, 0xef, + 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, + 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, + 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, ]; -const NORMAL0: &'static [u16] = &[ - 0x0, 0x20, - 0x7f, 0x22, - 0x380, 0x4, - 0x5c8, 0x8, - 0x5eb, 0x5, - 0x5f5, 0x11, - 0x7b2, 0xe, - 0x7fb, 0x5, - 0x85f, 0x41, - 0x8be, 0x16, - 0x9b3, 0x3, - 0x9cf, 0x8, - 0x9d8, 0x4, - 0x9fc, 0x5, - 0xa0b, 0x4, - 0xa43, 0x4, - 0xa4e, 0x3, - 0xa52, 0x7, - 0xa5f, 0x7, - 0xa76, 0xb, - 0xad1, 0xf, - 0xaf2, 0x7, - 0xafa, 0x7, - 0xb4e, 0x8, - 0xb58, 0x4, - 0xb78, 0xa, - 0xb8b, 0x3, - 0xb96, 0x3, - 0xba0, 0x3, - 0xba5, 0x3, - 0xbab, 0x3, - 0xbba, 0x4, - 0xbc3, 0x3, - 0xbd1, 0x6, - 0xbd8, 0xe, - 0xbfb, 0x5, - 0xc3a, 0x3, - 0xc4e, 0x7, - 0xc5b, 0x5, - 0xc70, 0x8, - 0xcce, 0x7, - 0xcd7, 0x7, - 0xcf3, 0xe, - 0xd50, 0x4, - 0xd97, 0x3, - 0xdc7, 0x3, - 0xdcb, 0x4, - 0xde0, 0x6, - 0xdf5, 0xc, - 0xe3b, 0x4, - 0xe5c, 0x25, - 0xe8e, 0x6, - 0xee0, 0x20, - 0xf6d, 0x4, - 0xfdb, 0x25, - 0x10c8, 0x5, - 0x137d, 0x3, - 0x139a, 0x6, - 0x169d, 0x3, - 0x16f9, 0x7, - 0x1715, 0xb, - 0x1737, 0x9, - 0x1754, 0xc, - 0x1774, 0xc, - 0x17ea, 0x6, - 0x17fa, 0x6, - 0x181a, 0x6, - 0x1878, 0x8, - 0x18ab, 0x5, - 0x18f6, 0xa, - 0x192c, 0x4, - 0x193c, 0x4, - 0x1941, 0x3, - 0x1975, 0xb, - 0x19ac, 0x4, - 0x19ca, 0x6, - 0x19db, 0x3, - 0x1a8a, 0x6, - 0x1a9a, 0x6, - 0x1abf, 0x41, - 0x1b4c, 0x4, - 0x1b7d, 0x3, - 0x1bf4, 0x8, - 0x1c38, 0x3, - 0x1c4a, 0x3, - 0x1c89, 0x37, - 0x1cc8, 0x8, - 0x1cfa, 0x6, - 0x1df6, 0x5, - 0x1fff, 0x11, - 0x2028, 0x8, - 0x205f, 0x11, - 0x209d, 0x3, - 0x20bf, 0x11, - 0x20f1, 0xf, - 0x218c, 0x4, - 0x2427, 0x19, - 0x244b, 0x15, - 0x2bba, 0x3, - 0x2bd2, 0x1a, - 0x2bf0, 0x10, - 0x2cf4, 0x5, - 0x2d28, 0x5, - 0x2d68, 0x7, - 0x2d71, 0xe, - 0x2d97, 0x9, - 0x2e45, 0x3b, - 0x2ef4, 0xc, - 0x2fd6, 0x1a, - 0x2ffc, 0x5, - 0x3100, 0x5, - 0x312e, 0x3, - 0x31bb, 0x5, - 0x31e4, 0xc, - 0x4db6, 0xa, - 0x9fd6, 0x2a, - 0xa48d, 0x3, - 0xa4c7, 0x9, - 0xa62c, 0x14, - 0xa6f8, 0x8, - 0xa7b8, 0x3f, - 0xa82c, 0x4, - 0xa83a, 0x6, - 0xa878, 0x8, - 0xa8c6, 0x8, - 0xa8da, 0x6, - 0xa954, 0xb, - 0xa97d, 0x3, - 0xa9da, 0x4, - 0xaa37, 0x9, - 0xaac3, 0x18, - 0xaaf7, 0xa, - 0xab17, 0x9, - 0xab66, 0xa, - 0xabfa, 0x6, - 0xd7a4, 0xc, - 0xd7c7, 0x4, - 0xd7fc, 0x2104, - 0xfada, 0x26, - 0xfb07, 0xc, - 0xfb18, 0x5, - 0xfbc2, 0x11, - 0xfd40, 0x10, - 0xfdc8, 0x28, - 0xfe1a, 0x6, - 0xfe6c, 0x4, - 0xfefd, 0x4, - 0xffbf, 0x3, - 0xffdd, 0x3, - 0xffef, 0xd, +const SINGLETONS1U: &'static [(u8, u8)] = &[ + (0x00, 6), + (0x01, 1), + (0x03, 1), + (0x04, 2), + (0x08, 8), + (0x09, 2), + (0x0a, 3), + (0x0b, 2), + (0x10, 1), + (0x11, 4), + (0x12, 5), + (0x13, 18), + (0x14, 2), + (0x15, 2), + (0x1c, 5), + (0x24, 1), + (0x6a, 3), + (0x6b, 2), + (0xbc, 2), + (0xd1, 2), + (0xd4, 12), + (0xd5, 9), + (0xd6, 2), + (0xd7, 2), + (0xda, 1), + (0xe0, 5), + (0xe8, 2), + (0xee, 32), + (0xf0, 4), + (0xf1, 1), + (0xf9, 4), ]; -const NORMAL1: &'static [u16] = &[ +const SINGLETONS1L: &'static [u8] = &[ + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, + 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, + 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56, + 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, + 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, + 0xb7, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x6f, 0x5f, + 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, + 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, + 0xad, 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, + 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, + 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, + 0xc6, 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, + 0x38, 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, + 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, + 0x66, 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, + 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x1f, 0x31, + 0x32, 0x3f, +]; +const NORMAL0: &'static [u8] = &[ + 0x00, 0x20, + 0x5f, 0x22, + 0x82, 0xdf, 0x04, + 0x82, 0x44, 0x08, + 0x1b, 0x05, + 0x05, 0x11, + 0x81, 0xac, 0x0e, + 0x3b, 0x05, + 0x5f, 0x41, + 0x1e, 0x16, + 0x80, 0xdf, 0x03, + 0x19, 0x08, + 0x01, 0x04, + 0x20, 0x05, + 0x0a, 0x04, + 0x34, 0x04, + 0x07, 0x03, + 0x01, 0x07, + 0x06, 0x07, + 0x10, 0x0b, + 0x50, 0x0f, + 0x12, 0x07, + 0x01, 0x07, + 0x4d, 0x08, + 0x02, 0x04, + 0x1c, 0x0a, + 0x09, 0x03, + 0x08, 0x03, + 0x07, 0x03, + 0x02, 0x03, + 0x03, 0x03, + 0x0c, 0x04, + 0x05, 0x03, + 0x0b, 0x06, + 0x01, 0x0e, + 0x15, 0x05, + 0x3a, 0x03, + 0x11, 0x07, + 0x06, 0x05, + 0x10, 0x08, + 0x56, 0x07, + 0x02, 0x07, + 0x15, 0x0e, + 0x4f, 0x04, + 0x43, 0x03, + 0x2d, 0x03, + 0x01, 0x04, + 0x11, 0x06, + 0x0f, 0x0c, + 0x3a, 0x04, + 0x1d, 0x25, + 0x0d, 0x06, + 0x4c, 0x20, + 0x6d, 0x04, + 0x6a, 0x25, + 0x80, 0xc8, 0x05, + 0x82, 0xb0, 0x03, + 0x1a, 0x06, + 0x82, 0xfd, 0x03, + 0x59, 0x07, + 0x15, 0x0b, + 0x17, 0x09, + 0x14, 0x0c, + 0x14, 0x0c, + 0x6a, 0x06, + 0x0a, 0x06, + 0x1a, 0x06, + 0x58, 0x08, + 0x2b, 0x05, + 0x46, 0x0a, + 0x2c, 0x04, + 0x0c, 0x04, + 0x01, 0x03, + 0x31, 0x0b, + 0x2c, 0x04, + 0x1a, 0x06, + 0x0b, 0x03, + 0x80, 0xac, 0x06, + 0x0a, 0x06, + 0x1f, 0x41, + 0x4c, 0x04, + 0x2d, 0x03, + 0x74, 0x08, + 0x3c, 0x03, + 0x0f, 0x03, + 0x3c, 0x37, + 0x08, 0x08, + 0x2a, 0x06, + 0x80, 0xf6, 0x05, + 0x82, 0x04, 0x11, + 0x18, 0x08, + 0x2f, 0x11, + 0x2d, 0x03, + 0x1f, 0x11, + 0x21, 0x0f, + 0x80, 0x8c, 0x04, + 0x82, 0x97, 0x19, + 0x0b, 0x15, + 0x87, 0x5a, 0x03, + 0x15, 0x1a, + 0x04, 0x10, + 0x80, 0xf4, 0x05, + 0x2f, 0x05, + 0x3b, 0x07, + 0x02, 0x0e, + 0x18, 0x09, + 0x80, 0xa5, 0x3b, + 0x74, 0x0c, + 0x80, 0xd6, 0x1a, + 0x0c, 0x05, + 0x80, 0xff, 0x05, + 0x29, 0x03, + 0x80, 0x8a, 0x05, + 0x24, 0x0c, + 0x9b, 0xc6, 0x0a, + 0xd2, 0x16, 0x2a, + 0x84, 0x8d, 0x03, + 0x37, 0x09, + 0x81, 0x5c, 0x14, + 0x80, 0xb8, 0x08, + 0x80, 0xb8, 0x3f, + 0x35, 0x04, + 0x0a, 0x06, + 0x38, 0x08, + 0x46, 0x08, + 0x0c, 0x06, + 0x74, 0x0b, + 0x1e, 0x03, + 0x5a, 0x04, + 0x59, 0x09, + 0x80, 0x83, 0x18, + 0x1c, 0x0a, + 0x16, 0x09, + 0x46, 0x0a, + 0x80, 0x8a, 0x06, + 0xab, 0xa4, 0x0c, + 0x17, 0x04, + 0x31, 0xa1, 0x04, + 0x81, 0xda, 0x26, + 0x07, 0x0c, + 0x05, 0x05, + 0x80, 0xa5, 0x11, + 0x81, 0x6d, 0x10, + 0x78, 0x28, + 0x2a, 0x06, + 0x4c, 0x04, + 0x80, 0x8d, 0x04, + 0x80, 0xbe, 0x03, + 0x1b, 0x03, + 0x0f, 0x0d, +]; +const NORMAL1: &'static [u8] = &[ + 0x5e, 0x22, + 0x7b, 0x05, + 0x03, 0x04, + 0x2d, 0x03, + 0x65, 0x04, + 0x01, 0x2f, + 0x2e, 0x80, 0x82, + 0x1d, 0x03, + 0x31, 0x0f, + 0x1c, 0x04, + 0x24, 0x0c, + 0x1b, 0x05, + 0x2b, 0x05, + 0x44, 0x04, + 0x0e, 0x2a, + 0x80, 0xaa, 0x06, + 0x24, 0x04, + 0x24, 0x04, + 0x28, 0x08, + 0x34, 0x0b, + 0x01, 0x80, 0x90, + 0x81, 0x37, 0x09, + 0x16, 0x0a, + 0x08, 0x80, 0x98, + 0x39, 0x03, + 0x63, 0x08, + 0x09, 0x30, + 0x16, 0x05, + 0x21, 0x03, + 0x1b, 0x05, + 0x01, 0x40, + 0x38, 0x04, + 0x4b, 0x05, + 0x28, 0x04, + 0x03, 0x04, + 0x09, 0x08, + 0x09, 0x07, + 0x40, 0x20, + 0x27, 0x04, + 0x0c, 0x09, + 0x36, 0x03, + 0x3a, 0x05, + 0x1a, 0x07, + 0x04, 0x0c, + 0x07, 0x50, + 0x49, 0x37, + 0x33, 0x0d, + 0x33, 0x07, + 0x06, 0x81, 0x60, + 0x1f, 0x81, 0x81, + 0x4e, 0x04, + 0x1e, 0x0f, + 0x43, 0x0e, + 0x19, 0x07, + 0x0a, 0x06, + 0x44, 0x0c, + 0x27, 0x09, + 0x75, 0x0b, + 0x3f, 0x41, + 0x2a, 0x06, + 0x3b, 0x05, + 0x0a, 0x06, + 0x51, 0x06, + 0x01, 0x05, + 0x10, 0x03, + 0x05, 0x80, 0x8b, + 0x5e, 0x22, + 0x48, 0x08, + 0x0a, 0x80, 0xa6, 0x5e, 0x22, - 0xfb, 0x5, - 0x103, 0x4, - 0x134, 0x3, - 0x19c, 0x4, - 0x1a1, 0x2f, - 0x1fe, 0x82, - 0x29d, 0x3, - 0x2d1, 0xf, - 0x2fc, 0x4, - 0x324, 0xc, - 0x34b, 0x5, - 0x37b, 0x5, - 0x3c4, 0x4, - 0x3d6, 0x2a, - 0x4aa, 0x6, - 0x4d4, 0x4, - 0x4fc, 0x4, - 0x528, 0x8, - 0x564, 0xb, - 0x570, 0x90, - 0x737, 0x9, - 0x756, 0xa, - 0x768, 0x98, - 0x839, 0x3, - 0x89f, 0x8, - 0x8b0, 0x30, - 0x8f6, 0x5, - 0x91c, 0x3, - 0x93a, 0x5, - 0x940, 0x40, - 0x9b8, 0x4, - 0xa07, 0x5, - 0xa34, 0x4, - 0xa3b, 0x4, - 0xa48, 0x8, - 0xa59, 0x7, - 0xaa0, 0x20, - 0xae7, 0x4, - 0xaf7, 0x9, - 0xb36, 0x3, - 0xb73, 0x5, - 0xb92, 0x7, - 0xb9d, 0xc, - 0xbb0, 0x50, - 0xc49, 0x37, - 0xcb3, 0xd, - 0xcf3, 0x7, - 0xd00, 0x160, - 0xe7f, 0x181, - 0x104e, 0x4, - 0x1070, 0xf, - 0x10c2, 0xe, - 0x10e9, 0x7, - 0x10fa, 0x6, - 0x1144, 0xc, - 0x1177, 0x9, - 0x11f5, 0xb, - 0x123f, 0x41, - 0x12aa, 0x6, - 0x12eb, 0x5, - 0x12fa, 0x6, - 0x1351, 0x6, - 0x1358, 0x5, - 0x136d, 0x3, - 0x1375, 0x8b, - 0x145e, 0x22, - 0x14c8, 0x8, - 0x14da, 0xa6, - 0x15de, 0x22, - 0x1645, 0xb, - 0x165a, 0x6, - 0x166d, 0x13, - 0x16b8, 0x8, - 0x16ca, 0x36, - 0x171a, 0x3, - 0x172c, 0x4, - 0x1740, 0x160, - 0x18f3, 0xc, - 0x1900, 0x1c0, - 0x1af9, 0x107, - 0x1c46, 0xa, - 0x1c6d, 0x3, - 0x1cb7, 0x349, - 0x239a, 0x66, - 0x2475, 0xb, - 0x2544, 0xabc, - 0x342f, 0xfd1, - 0x4647, 0x21b9, - 0x6a39, 0x7, - 0x6a6a, 0x4, - 0x6a70, 0x60, - 0x6af6, 0xa, - 0x6b46, 0xa, - 0x6b78, 0x5, - 0x6b90, 0x370, - 0x6f45, 0xb, - 0x6f7f, 0x10, - 0x6fa0, 0x40, - 0x6fe1, 0x1f, - 0x87ed, 0x13, - 0x8af3, 0x250d, - 0xb002, 0xbfe, - 0xbc6b, 0x5, - 0xbc7d, 0x3, - 0xbc89, 0x7, - 0xbca0, 0x1360, - 0xd0f6, 0xa, - 0xd173, 0x8, - 0xd1e9, 0x17, - 0xd246, 0xba, - 0xd357, 0x9, - 0xd372, 0x8e, - 0xd547, 0x3, - 0xda8c, 0xf, - 0xdab0, 0x550, - 0xe02b, 0x7d5, - 0xe8d7, 0x29, - 0xe94b, 0x5, - 0xe95a, 0x4, - 0xe960, 0x4a0, - 0xee3c, 0x6, - 0xee43, 0x4, - 0xee9c, 0x5, - 0xeebc, 0x34, - 0xeef2, 0x10e, - 0xf02c, 0x4, - 0xf094, 0xc, - 0xf0f6, 0xa, - 0xf10d, 0x3, - 0xf16c, 0x4, - 0xf1ad, 0x39, - 0xf203, 0xd, - 0xf23c, 0x4, - 0xf249, 0x7, - 0xf252, 0xae, - 0xf6d3, 0xd, - 0xf6ed, 0x3, - 0xf6f7, 0x9, - 0xf774, 0xc, - 0xf7d5, 0x2b, - 0xf80c, 0x4, - 0xf848, 0x8, - 0xf85a, 0x6, - 0xf888, 0x8, - 0xf8ae, 0x62, - 0xf928, 0x8, - 0xf94c, 0x4, - 0xf95f, 0x21, - 0xf992, 0x2e, - 0xf9c1, 0x63f, + 0x45, 0x0b, + 0x0a, 0x06, + 0x0d, 0x13, + 0x38, 0x08, + 0x0a, 0x36, + 0x1a, 0x03, + 0x0f, 0x04, + 0x10, 0x81, 0x60, + 0x53, 0x0c, + 0x01, 0x81, 0xc0, + 0x39, 0x81, 0x07, + 0x46, 0x0a, + 0x1d, 0x03, + 0x47, 0x83, 0x49, + 0x83, 0x9a, 0x66, + 0x75, 0x0b, + 0x80, 0xc4, 0x8a, 0xbc, + 0x84, 0x2f, 0x8f, 0xd1, + 0x82, 0x47, 0xa1, 0xb9, + 0x82, 0x39, 0x07, + 0x2a, 0x04, + 0x02, 0x60, + 0x26, 0x0a, + 0x46, 0x0a, + 0x28, 0x05, + 0x13, 0x83, 0x70, + 0x45, 0x0b, + 0x2f, 0x10, + 0x11, 0x40, + 0x01, 0x1f, + 0x97, 0xed, 0x13, + 0x82, 0xf3, 0xa5, 0x0d, + 0x02, 0x8b, 0xfe, + 0x6b, 0x05, + 0x0d, 0x03, + 0x09, 0x07, + 0x10, 0x93, 0x60, + 0x80, 0xf6, 0x0a, + 0x73, 0x08, + 0x6e, 0x17, + 0x46, 0x80, 0xba, + 0x57, 0x09, + 0x12, 0x80, 0x8e, + 0x81, 0x47, 0x03, + 0x85, 0x42, 0x0f, + 0x15, 0x85, 0x50, + 0x2b, 0x87, 0xd5, + 0x80, 0xd7, 0x29, + 0x4b, 0x05, + 0x0a, 0x04, + 0x02, 0x84, 0xa0, + 0x3c, 0x06, + 0x01, 0x04, + 0x55, 0x05, + 0x1b, 0x34, + 0x02, 0x81, 0x0e, + 0x2c, 0x04, + 0x64, 0x0c, + 0x56, 0x0a, + 0x0d, 0x03, + 0x5c, 0x04, + 0x3d, 0x39, + 0x1d, 0x0d, + 0x2c, 0x04, + 0x09, 0x07, + 0x02, 0x80, 0xae, + 0x83, 0xd3, 0x0d, + 0x0d, 0x03, + 0x07, 0x09, + 0x74, 0x0c, + 0x55, 0x2b, + 0x0c, 0x04, + 0x38, 0x08, + 0x0a, 0x06, + 0x28, 0x08, + 0x1e, 0x62, + 0x18, 0x08, + 0x1c, 0x04, + 0x0f, 0x21, + 0x12, 0x2e, + 0x01, 0x86, 0x3f, ]; diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1ae8b6bb451..e0a4707ff66 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -61,16 +61,18 @@ extern "rust-intrinsic" { /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -79,8 +81,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -89,16 +92,18 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acqrel<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -107,8 +112,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -117,8 +123,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_failacq<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -127,8 +134,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acq_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -137,8 +145,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acqrel_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. @@ -146,16 +155,18 @@ extern "rust-intrinsic" { /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -164,8 +175,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -174,16 +186,18 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -192,8 +206,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -202,8 +217,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failacq<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -212,8 +228,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -222,8 +239,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool); /// Loads the current value of the pointer. @@ -1253,17 +1271,17 @@ extern "rust-intrinsic" { #[cfg(not(stage0))] pub fn unchecked_shr<T>(x: T, y: T) -> T; - /// Returns (a + b) mod 2^N, where N is the width of T in bits. + /// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) pub fn overflowing_add<T>(a: T, b: T) -> T; - /// Returns (a - b) mod 2^N, where N is the width of T in bits. + /// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) pub fn overflowing_sub<T>(a: T, b: T) -> T; - /// Returns (a * b) mod 2^N, where N is the width of T in bits. + /// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 04394e0a3a8..273f9d0e6f6 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -358,12 +358,24 @@ impl<I> Iterator for Rev<I> where I: DoubleEndedIterator { fn next(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next_back() } #[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } + + fn find<P>(&mut self, predicate: P) -> Option<Self::Item> + where P: FnMut(&Self::Item) -> bool + { + self.iter.rfind(predicate) + } } #[stable(feature = "rust1", since = "1.0.0")] impl<I> DoubleEndedIterator for Rev<I> where I: DoubleEndedIterator { #[inline] fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() } + + fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item> + where P: FnMut(&Self::Item) -> bool + { + self.iter.find(predicate) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 34f14ef53f8..798dda19928 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -467,7 +467,7 @@ pub trait DoubleEndedIterator: Iterator { Self: Sized, P: FnMut(&Self::Item) -> bool { - for x in self.by_ref().rev() { + while let Some(x) = self.next_back() { if predicate(&x) { return Some(x) } } None diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index 8904322ca48..b5553fb2947 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -19,7 +19,7 @@ //! inputs, but we don't do so to avoid the code bloat. Each bignum is still //! tracked for the actual usages, so it normally doesn't matter. -// This module is only for dec2flt and flt2dec, and only public because of libcoretest. +// This module is only for dec2flt and flt2dec, and only public because of coretests. // It is not intended to ever be stabilized. #![doc(hidden)] #![unstable(feature = "core_private_bignum", diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index e3b58b6cc7c..45fa721a5a3 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -10,12 +10,12 @@ //! Bit fiddling on positive IEEE 754 floats. Negative numbers aren't and needn't be handled. //! Normal floating point numbers have a canonical representation as (frac, exp) such that the -//! value is 2^exp * (1 + sum(frac[N-i] / 2^i)) where N is the number of bits. Subnormals are -//! slightly different and weird, but the same principle applies. +//! value is 2<sup>exp</sup> * (1 + sum(frac[N-i] / 2<sup>i</sup>)) where N is the number of bits. +//! Subnormals are slightly different and weird, but the same principle applies. //! -//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * 2^e. -//! Besides making the "hidden bit" explicit, this changes the exponent by the so-called -//! mantissa shift. +//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * +//! 2<sup>e</sup>. Besides making the "hidden bit" explicit, this changes the exponent by the +//! so-called mantissa shift. //! //! Put another way, normally floats are written as (1) but here they are written as (2): //! @@ -94,7 +94,8 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp /// represented, the other code in this module makes sure to never let that happen. fn from_int(x: u64) -> Self; - /// Get the value 10^e from a pre-computed table. Panics for e >= ceil_log5_of_max_sig(). + /// Get the value 10<sup>e</sup> from a pre-computed table. Panics for e >= + /// ceil_log5_of_max_sig(). fn short_fast_pow10(e: usize) -> Self; // FIXME Everything that follows should be associated constants, but taking the value of an diff --git a/src/libcore/num/diy_float.rs b/src/libcore/num/diy_float.rs index 11eea753f93..6635d95155f 100644 --- a/src/libcore/num/diy_float.rs +++ b/src/libcore/num/diy_float.rs @@ -10,7 +10,7 @@ //! Extended precision "soft float", for internal use only. -// This module is only for dec2flt and flt2dec, and only public because of libcoretest. +// This module is only for dec2flt and flt2dec, and only public because of coretests. // It is not intended to ever be stabilized. #![doc(hidden)] #![unstable(feature = "core_private_diy_float", diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs index f6c03a59f81..5123e42df61 100644 --- a/src/libcore/num/flt2dec/mod.rs +++ b/src/libcore/num/flt2dec/mod.rs @@ -118,7 +118,7 @@ provide a large enough buffer and `Part` array, and to assemble the final string from resulting `Part`s itself. All algorithms and formatting functions are accompanied by extensive tests -in `coretest::num::flt2dec` module. It also shows how to use individual +in `coretests::num::flt2dec` module. It also shows how to use individual functions. */ diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index df343c9d45f..f665cfdee77 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -90,7 +90,7 @@ impl<T: fmt::UpperHex> fmt::UpperHex for Wrapping<T> { mod wrapping; -// All these modules are technically private and only exposed for libcoretest: +// All these modules are technically private and only exposed for coretests: pub mod flt2dec; pub mod dec2flt; pub mod bignum; diff --git a/src/libcore/option.rs b/src/libcore/option.rs index d997f3592fd..1a48f277625 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -894,9 +894,15 @@ impl<A> ExactSizeIterator for Item<A> {} impl<A> FusedIterator for Item<A> {} unsafe impl<A> TrustedLen for Item<A> {} -/// An iterator over a reference of the contained item in an [`Option`]. +/// An iterator over a reference to the [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. +/// +/// This `struct` is created by the [`Option::iter`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::iter`]: enum.Option.html#method.iter #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, A: 'a> { inner: Item<&'a A> } @@ -933,9 +939,15 @@ impl<'a, A> Clone for Iter<'a, A> { } } -/// An iterator over a mutable reference of the contained item in an [`Option`]. +/// An iterator over a mutable reference to the [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. +/// +/// This `struct` is created by the [`Option::iter_mut`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::iter_mut`]: enum.Option.html#method.iter_mut #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> } @@ -964,9 +976,15 @@ 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`]. +/// An iterator over the value in [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. +/// +/// This `struct` is created by the [`Option::into_iter`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::into_iter`]: enum.Option.html#method.into_iter #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter<A> { inner: Item<A> } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index d2830a6d00c..04480fc5d31 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -500,6 +500,44 @@ impl<T: ?Sized> *const T { intrinsics::arith_offset(self, count) } } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`. + /// + /// If the address different between the two pointers ia not a multiple of + /// `mem::size_of::<T>()` then the result of the division is rounded towards + /// zero. + /// + /// This function returns `None` if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(offset_to)] + /// + /// fn main() { + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// assert_eq!(ptr1.offset_to(ptr2), Some(2)); + /// assert_eq!(ptr2.offset_to(ptr1), Some(-2)); + /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2); + /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); + /// } + /// ``` + #[unstable(feature = "offset_to", issue = "41079")] + #[inline] + pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized { + let size = mem::size_of::<T>(); + if size == 0 { + None + } else { + let diff = (other as isize).wrapping_sub(self as isize); + Some(diff / size as isize) + } + } } #[lang = "mut_ptr"] @@ -653,6 +691,44 @@ impl<T: ?Sized> *mut T { Some(&mut *self) } } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`. + /// + /// If the address different between the two pointers ia not a multiple of + /// `mem::size_of::<T>()` then the result of the division is rounded towards + /// zero. + /// + /// This function returns `None` if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(offset_to)] + /// + /// fn main() { + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// assert_eq!(ptr1.offset_to(ptr2), Some(2)); + /// assert_eq!(ptr2.offset_to(ptr1), Some(-2)); + /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2); + /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); + /// } + /// ``` + #[unstable(feature = "offset_to", issue = "41079")] + #[inline] + pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized { + let size = mem::size_of::<T>(); + if size == 0 { + None + } else { + let diff = (other as isize).wrapping_sub(self as isize); + Some(diff / size as isize) + } + } } // Equality for pointers diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 45667bb4299..6d598677c9b 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -81,6 +81,10 @@ pub trait SliceExt { fn split<P>(&self, pred: P) -> Split<Self::Item, P> where P: FnMut(&Self::Item) -> bool; + #[unstable(feature = "slice_rsplit", issue = "41020")] + fn rsplit<P>(&self, pred: P) -> RSplit<Self::Item, P> + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn splitn<P>(&self, n: usize, pred: P) -> SplitN<Self::Item, P> where P: FnMut(&Self::Item) -> bool; @@ -159,6 +163,10 @@ pub trait SliceExt { fn split_mut<P>(&mut self, pred: P) -> SplitMut<Self::Item, P> where P: FnMut(&Self::Item) -> bool; + #[unstable(feature = "slice_rsplit", issue = "41020")] + fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<Self::Item, P> + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<Self::Item, P> where P: FnMut(&Self::Item) -> bool; @@ -294,14 +302,20 @@ impl<T> SliceExt for [T] { } #[inline] + fn rsplit<P>(&self, pred: P) -> RSplit<T, P> + where P: FnMut(&T) -> bool + { + RSplit { inner: self.split(pred) } + } + + #[inline] fn splitn<P>(&self, n: usize, pred: P) -> SplitN<T, P> where P: FnMut(&T) -> bool { SplitN { inner: GenericSplitN { iter: self.split(pred), - count: n, - invert: false + count: n } } } @@ -312,9 +326,8 @@ impl<T> SliceExt for [T] { { RSplitN { inner: GenericSplitN { - iter: self.split(pred), - count: n, - invert: true + iter: self.rsplit(pred), + count: n } } } @@ -476,14 +489,20 @@ impl<T> SliceExt for [T] { } #[inline] + fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<T, P> + where P: FnMut(&T) -> bool + { + RSplitMut { inner: self.split_mut(pred) } + } + + #[inline] fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<T, P> where P: FnMut(&T) -> bool { SplitNMut { inner: GenericSplitN { iter: self.split_mut(pred), - count: n, - invert: false + count: n } } } @@ -494,9 +513,8 @@ impl<T> SliceExt for [T] { { RSplitNMut { inner: GenericSplitN { - iter: self.split_mut(pred), - count: n, - invert: true + iter: self.rsplit_mut(pred), + count: n } } } @@ -1498,9 +1516,10 @@ unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} // Return the arithmetic difference if `T` is zero size. #[inline(always)] fn ptrdistance<T>(start: *const T, end: *const T) -> usize { - let diff = (end as usize).wrapping_sub(start as usize); - let size = mem::size_of::<T>(); - diff / (if size == 0 { 1 } else { size }) + match start.offset_to(end) { + Some(x) => x as usize, + None => (end as usize).wrapping_sub(start as usize), + } } // Extension methods for raw pointers, used by the iterators @@ -1735,6 +1754,123 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where #[unstable(feature = "fused", issue = "35602")] impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {} +/// An iterator over subslices separated by elements that match a predicate +/// function, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit`] method on [slices]. +/// +/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "slice_rsplit", issue = "41020")] +#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? +pub struct RSplit<'a, T:'a, P> where P: FnMut(&T) -> bool { + inner: Split<'a, T, P> +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("RSplit") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.inner.size_hint() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + self.inner.next() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + self.inner.finish() + } +} + +//#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the subslices of the vector which are separated +/// by elements that match `pred`, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit_mut`] method on [slices]. +/// +/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "slice_rsplit", issue = "41020")] +pub struct RSplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool { + inner: SplitMut<'a, T, P> +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("RSplitMut") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + self.inner.finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.inner.size_hint() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + self.inner.next() + } +} + +//#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} + /// An private iterator over subslices separated by elements that /// match a predicate function, splitting at most a fixed number of /// times. @@ -1742,7 +1878,6 @@ impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool { struct GenericSplitN<I> { iter: I, count: usize, - invert: bool } impl<T, I: SplitIter<Item=T>> Iterator for GenericSplitN<I> { @@ -1753,10 +1888,7 @@ impl<T, I: SplitIter<Item=T>> Iterator for GenericSplitN<I> { match self.count { 0 => None, 1 => { self.count -= 1; self.iter.finish() } - _ => { - self.count -= 1; - if self.invert {self.iter.next_back()} else {self.iter.next()} - } + _ => { self.count -= 1; self.iter.next() } } } @@ -1798,7 +1930,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for SplitN<'a, T, P> where P: FnMut(& /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct RSplitN<'a, T: 'a, P> where P: FnMut(&T) -> bool { - inner: GenericSplitN<Split<'a, T, P>> + inner: GenericSplitN<RSplit<'a, T, P>> } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -1841,7 +1973,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for SplitNMut<'a, T, P> where P: FnMu /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct RSplitNMut<'a, T: 'a, P> where P: FnMut(&T) -> bool { - inner: GenericSplitN<SplitMut<'a, T, P>> + inner: GenericSplitN<RSplitMut<'a, T, P>> } #[stable(feature = "core_impl_debug", since = "1.9.0")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index f75a1f7ab6e..352cc926994 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -152,11 +152,16 @@ impl fmt::Display for ParseBoolError { Section: Creating a string */ -/// Errors which can occur when attempting to interpret a sequence of `u8` +/// Errors which can occur when attempting to interpret a sequence of [`u8`] /// as a string. /// -/// As such, the `from_utf8` family of functions and methods for both `String`s -/// and `&str`s make use of this error, for example. +/// [`u8`]: ../../std/primitive.u8.html +/// +/// As such, the `from_utf8` family of functions and methods for both [`String`]s +/// and [`&str`]s make use of this error, for example. +/// +/// [`String`]: ../../std/string/struct.String.html#method.from_utf8 +/// [`&str`]: ../../std/str/fn.from_utf8.html #[derive(Copy, Eq, PartialEq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Utf8Error { @@ -210,11 +215,15 @@ impl Utf8Error { /// Converts a slice of bytes to a string slice. /// -/// A string slice (`&str`) is made of bytes (`u8`), and a byte slice (`&[u8]`) -/// is made of bytes, so this function converts between the two. Not all byte -/// slices are valid string slices, however: `&str` requires that it is valid -/// UTF-8. `from_utf8()` checks to ensure that the bytes are valid UTF-8, and -/// then does the conversion. +/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice +/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between +/// the two. Not all byte slices are valid string slices, however: [`&str`] requires +/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid +/// UTF-8, and then does the conversion. +/// +/// [`&str`]: ../../std/primitive.str.html +/// [`u8`]: ../../std/primitive.u8.html +/// [byteslice]: ../../std/primitive.slice.html /// /// If you are sure that the byte slice is valid UTF-8, and you don't want to /// incur the overhead of the validity check, there is an unsafe version of @@ -228,9 +237,12 @@ impl Utf8Error { /// /// [string]: ../../std/string/struct.String.html#method.from_utf8 /// -/// Because you can stack-allocate a `[u8; N]`, and you can take a `&[u8]` of -/// it, this function is one way to have a stack-allocated string. There is -/// an example of this in the examples section below. +/// Because you can stack-allocate a `[u8; N]`, and you can take a +/// [`&[u8]`][byteslice] of it, this function is one way to have a +/// stack-allocated string. There is an example of this in the +/// examples section below. +/// +/// [byteslice]: ../../std/primitive.slice.html /// /// # Errors /// diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index ae47e6fdfa9..2e1058bfc34 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -153,8 +153,9 @@ unsafe impl<T> Sync for AtomicPtr<T> {} /// Rust's memory orderings are [the same as /// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations). /// -/// For more information see the [nomicon][1]. -/// [1]: ../../../nomicon/atomics.html +/// For more information see the [nomicon]. +/// +/// [nomicon]: ../../../nomicon/atomics.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Debug)] pub enum Ordering { @@ -321,7 +322,7 @@ impl AtomicBool { } } - /// Stores a value into the bool, returning the old value. + /// Stores a value into the bool, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. @@ -732,7 +733,7 @@ impl<T> AtomicPtr<T> { } } - /// Stores a value into the pointer, returning the old value. + /// Stores a value into the pointer, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. @@ -1047,7 +1048,7 @@ macro_rules! atomic_int { unsafe { atomic_store(self.v.get(), val, order); } } - /// Stores a value into the atomic integer, returning the old value. + /// Stores a value into the atomic integer, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this /// operation. @@ -1201,7 +1202,9 @@ macro_rules! atomic_int { } } - /// Add to the current value, returning the previous value. + /// Adds to the current value, returning the previous value. + /// + /// This operation wraps around on overflow. /// /// # Examples /// @@ -1218,7 +1221,9 @@ macro_rules! atomic_int { unsafe { atomic_add(self.v.get(), val, order) } } - /// Subtract from the current value, returning the previous value. + /// Subtracts from the current value, returning the previous value. + /// + /// This operation wraps around on overflow. /// /// # Examples /// @@ -1235,7 +1240,12 @@ macro_rules! atomic_int { unsafe { atomic_sub(self.v.get(), val, order) } } - /// Bitwise and with the current value, returning the previous value. + /// Bitwise "and" with the current value. + /// + /// Performs a bitwise "and" operation on the current value and the argument `val`, and + /// sets the new value to the result. + /// + /// Returns the previous value. /// /// # Examples /// @@ -1251,7 +1261,12 @@ macro_rules! atomic_int { unsafe { atomic_and(self.v.get(), val, order) } } - /// Bitwise or with the current value, returning the previous value. + /// Bitwise "or" with the current value. + /// + /// Performs a bitwise "or" operation on the current value and the argument `val`, and + /// sets the new value to the result. + /// + /// Returns the previous value. /// /// # Examples /// @@ -1267,7 +1282,12 @@ macro_rules! atomic_int { unsafe { atomic_or(self.v.get(), val, order) } } - /// Bitwise xor with the current value, returning the previous value. + /// Bitwise "xor" with the current value. + /// + /// Performs a bitwise "xor" operation on the current value and the argument `val`, and + /// sets the new value to the result. + /// + /// Returns the previous value. /// /// # Examples /// @@ -1415,7 +1435,7 @@ unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T { } } -/// Returns the old value (like __sync_fetch_and_add). +/// Returns the previous value (like __sync_fetch_and_add). #[inline] unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T { match order { @@ -1428,7 +1448,7 @@ unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T { } } -/// Returns the old value (like __sync_fetch_and_sub). +/// Returns the previous value (like __sync_fetch_and_sub). #[inline] unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T { match order { diff --git a/src/libcoretest/any.rs b/src/libcore/tests/any.rs index 2d3e81aa131..2d3e81aa131 100644 --- a/src/libcoretest/any.rs +++ b/src/libcore/tests/any.rs diff --git a/src/libcoretest/array.rs b/src/libcore/tests/array.rs index 6af031dee58..6af031dee58 100644 --- a/src/libcoretest/array.rs +++ b/src/libcore/tests/array.rs diff --git a/src/libcoretest/atomic.rs b/src/libcore/tests/atomic.rs index b6bb5fddf4a..b6bb5fddf4a 100644 --- a/src/libcoretest/atomic.rs +++ b/src/libcore/tests/atomic.rs diff --git a/src/libcoretest/cell.rs b/src/libcore/tests/cell.rs index 8585f2f0871..8585f2f0871 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcore/tests/cell.rs diff --git a/src/libcoretest/char.rs b/src/libcore/tests/char.rs index e4012ec91e2..e4012ec91e2 100644 --- a/src/libcoretest/char.rs +++ b/src/libcore/tests/char.rs diff --git a/src/libcoretest/clone.rs b/src/libcore/tests/clone.rs index 91d68ba3344..91d68ba3344 100644 --- a/src/libcoretest/clone.rs +++ b/src/libcore/tests/clone.rs diff --git a/src/libcoretest/cmp.rs b/src/libcore/tests/cmp.rs index e3c65ad8b33..e3c65ad8b33 100644 --- a/src/libcoretest/cmp.rs +++ b/src/libcore/tests/cmp.rs diff --git a/src/libcoretest/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs index e71e61bda5e..e71e61bda5e 100644 --- a/src/libcoretest/fmt/builders.rs +++ b/src/libcore/tests/fmt/builders.rs diff --git a/src/libcoretest/fmt/float.rs b/src/libcore/tests/fmt/float.rs index 695001312e4..695001312e4 100644 --- a/src/libcoretest/fmt/float.rs +++ b/src/libcore/tests/fmt/float.rs diff --git a/src/libcoretest/fmt/mod.rs b/src/libcore/tests/fmt/mod.rs index 5d204c7d523..5d204c7d523 100644 --- a/src/libcoretest/fmt/mod.rs +++ b/src/libcore/tests/fmt/mod.rs diff --git a/src/libcoretest/fmt/num.rs b/src/libcore/tests/fmt/num.rs index 4ddedd91004..4ddedd91004 100644 --- a/src/libcoretest/fmt/num.rs +++ b/src/libcore/tests/fmt/num.rs diff --git a/src/libcoretest/hash/mod.rs b/src/libcore/tests/hash/mod.rs index 53ac17c052f..53ac17c052f 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcore/tests/hash/mod.rs diff --git a/src/libcoretest/hash/sip.rs b/src/libcore/tests/hash/sip.rs index 4a9657e0340..4a9657e0340 100644 --- a/src/libcoretest/hash/sip.rs +++ b/src/libcore/tests/hash/sip.rs diff --git a/src/libcoretest/intrinsics.rs b/src/libcore/tests/intrinsics.rs index 2b380abf63c..2b380abf63c 100644 --- a/src/libcoretest/intrinsics.rs +++ b/src/libcore/tests/intrinsics.rs diff --git a/src/libcoretest/iter.rs b/src/libcore/tests/iter.rs index 08442f9bcbf..08442f9bcbf 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcore/tests/iter.rs diff --git a/src/libcoretest/lib.rs b/src/libcore/tests/lib.rs index d92c378160d..d92c378160d 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcore/tests/lib.rs diff --git a/src/libcoretest/mem.rs b/src/libcore/tests/mem.rs index 86e59c736ba..86e59c736ba 100644 --- a/src/libcoretest/mem.rs +++ b/src/libcore/tests/mem.rs diff --git a/src/libcoretest/nonzero.rs b/src/libcore/tests/nonzero.rs index 7a367ddeec8..7a367ddeec8 100644 --- a/src/libcoretest/nonzero.rs +++ b/src/libcore/tests/nonzero.rs diff --git a/src/libcoretest/num/bignum.rs b/src/libcore/tests/num/bignum.rs index 58a9dd1b128..58a9dd1b128 100644 --- a/src/libcoretest/num/bignum.rs +++ b/src/libcore/tests/num/bignum.rs diff --git a/src/libcoretest/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs index 5d546c643e7..5d546c643e7 100644 --- a/src/libcoretest/num/dec2flt/mod.rs +++ b/src/libcore/tests/num/dec2flt/mod.rs diff --git a/src/libcoretest/num/dec2flt/parse.rs b/src/libcore/tests/num/dec2flt/parse.rs index 09acf2bc517..09acf2bc517 100644 --- a/src/libcoretest/num/dec2flt/parse.rs +++ b/src/libcore/tests/num/dec2flt/parse.rs diff --git a/src/libcoretest/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs index 1a3533317da..1a3533317da 100644 --- a/src/libcoretest/num/dec2flt/rawfp.rs +++ b/src/libcore/tests/num/dec2flt/rawfp.rs diff --git a/src/libcoretest/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs index 0bca616ea9a..0bca616ea9a 100644 --- a/src/libcoretest/num/flt2dec/estimator.rs +++ b/src/libcore/tests/num/flt2dec/estimator.rs diff --git a/src/libcoretest/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs index 0f4d19e7092..0f4d19e7092 100644 --- a/src/libcoretest/num/flt2dec/mod.rs +++ b/src/libcore/tests/num/flt2dec/mod.rs diff --git a/src/libcoretest/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs index 4edb0f3df60..4edb0f3df60 100644 --- a/src/libcoretest/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/tests/num/flt2dec/strategy/dragon.rs diff --git a/src/libcoretest/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs index 79e66ee669e..79e66ee669e 100644 --- a/src/libcoretest/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/tests/num/flt2dec/strategy/grisu.rs diff --git a/src/libcoretest/num/i16.rs b/src/libcore/tests/num/i16.rs index 7435831ac6d..7435831ac6d 100644 --- a/src/libcoretest/num/i16.rs +++ b/src/libcore/tests/num/i16.rs diff --git a/src/libcoretest/num/i32.rs b/src/libcore/tests/num/i32.rs index 3b3407e1ada..3b3407e1ada 100644 --- a/src/libcoretest/num/i32.rs +++ b/src/libcore/tests/num/i32.rs diff --git a/src/libcoretest/num/i64.rs b/src/libcore/tests/num/i64.rs index 9e1aec256ee..9e1aec256ee 100644 --- a/src/libcoretest/num/i64.rs +++ b/src/libcore/tests/num/i64.rs diff --git a/src/libcoretest/num/i8.rs b/src/libcore/tests/num/i8.rs index f72244239b2..f72244239b2 100644 --- a/src/libcoretest/num/i8.rs +++ b/src/libcore/tests/num/i8.rs diff --git a/src/libcoretest/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs index 8d791283ab8..8d791283ab8 100644 --- a/src/libcoretest/num/int_macros.rs +++ b/src/libcore/tests/num/int_macros.rs diff --git a/src/libcoretest/num/mod.rs b/src/libcore/tests/num/mod.rs index 51737c9c3b4..51737c9c3b4 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcore/tests/num/mod.rs diff --git a/src/libcoretest/num/u16.rs b/src/libcore/tests/num/u16.rs index 8455207583c..8455207583c 100644 --- a/src/libcoretest/num/u16.rs +++ b/src/libcore/tests/num/u16.rs diff --git a/src/libcoretest/num/u32.rs b/src/libcore/tests/num/u32.rs index b44e60f6529..b44e60f6529 100644 --- a/src/libcoretest/num/u32.rs +++ b/src/libcore/tests/num/u32.rs diff --git a/src/libcoretest/num/u64.rs b/src/libcore/tests/num/u64.rs index ffcd1015d58..ffcd1015d58 100644 --- a/src/libcoretest/num/u64.rs +++ b/src/libcore/tests/num/u64.rs diff --git a/src/libcoretest/num/u8.rs b/src/libcore/tests/num/u8.rs index 4ee14e22f2d..4ee14e22f2d 100644 --- a/src/libcoretest/num/u8.rs +++ b/src/libcore/tests/num/u8.rs diff --git a/src/libcoretest/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index daa1cc3a7f4..daa1cc3a7f4 100644 --- a/src/libcoretest/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs diff --git a/src/libcoretest/ops.rs b/src/libcore/tests/ops.rs index 1c6c13b0d02..1c6c13b0d02 100644 --- a/src/libcoretest/ops.rs +++ b/src/libcore/tests/ops.rs diff --git a/src/libcoretest/option.rs b/src/libcore/tests/option.rs index 51b0655f680..51b0655f680 100644 --- a/src/libcoretest/option.rs +++ b/src/libcore/tests/option.rs diff --git a/src/libcoretest/ptr.rs b/src/libcore/tests/ptr.rs index 7f6f472bfbb..7f6f472bfbb 100644 --- a/src/libcoretest/ptr.rs +++ b/src/libcore/tests/ptr.rs diff --git a/src/libcoretest/result.rs b/src/libcore/tests/result.rs index 4c5f19dee12..4c5f19dee12 100644 --- a/src/libcoretest/result.rs +++ b/src/libcore/tests/result.rs diff --git a/src/libcoretest/slice.rs b/src/libcore/tests/slice.rs index ec38345030f..ec38345030f 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcore/tests/slice.rs diff --git a/src/libcoretest/str.rs b/src/libcore/tests/str.rs index b7d9ba4463d..08daafccc54 100644 --- a/src/libcoretest/str.rs +++ b/src/libcore/tests/str.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// All `str` tests live in libcollectiontest::str +// All `str` tests live in collectionstests::str diff --git a/src/libcoretest/tuple.rs b/src/libcore/tests/tuple.rs index 4fe5e0a740b..4fe5e0a740b 100644 --- a/src/libcoretest/tuple.rs +++ b/src/libcore/tests/tuple.rs diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 809d5db3071..dca9ebb3397 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -394,6 +394,10 @@ impl Definitions { } } + pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { + self.node_to_hir_id[node_id] + } + /// Add a definition with a parent definition. pub fn create_def_with_parent(&mut self, parent: Option<DefIndex>, diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs new file mode 100644 index 00000000000..73d81212cd7 --- /dev/null +++ b/src/librustc/ich/hcx.rs @@ -0,0 +1,300 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use hir; +use hir::def_id::DefId; +use ich::{self, CachingCodemapView, DefPathHashes}; +use session::config::DebugInfoLevel::NoDebugInfo; +use ty; + +use std::hash as std_hash; + +use syntax::ast; +use syntax::attr; +use syntax::ext::hygiene::SyntaxContext; +use syntax::symbol::Symbol; +use syntax_pos::Span; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use rustc_data_structures::accumulate_vec::AccumulateVec; + +/// This is the context state available during incr. comp. hashing. It contains +/// enough information to transform DefIds and HirIds into stable DefPaths (i.e. +/// a reference to the TyCtxt) and it holds a few caches for speeding up various +/// things (e.g. each DefId/DefPath is only hashed once). +pub struct StableHashingContext<'a, 'tcx: 'a> { + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + def_path_hashes: DefPathHashes<'a, 'tcx>, + codemap: CachingCodemapView<'tcx>, + hash_spans: bool, + hash_bodies: bool, + overflow_checks_enabled: bool, + node_id_hashing_mode: NodeIdHashingMode, + // A sorted array of symbol keys for fast lookup. + ignored_attr_names: Vec<Symbol>, +} + +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum NodeIdHashingMode { + Ignore, + HashDefPath, + HashTraitsInScope, +} + +impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { + + pub fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Self { + let hash_spans_initial = tcx.sess.opts.debuginfo != NoDebugInfo; + let check_overflow_initial = tcx.sess.overflow_checks(); + + let mut ignored_attr_names: Vec<_> = ich::IGNORED_ATTRIBUTES + .iter() + .map(|&s| Symbol::intern(s)) + .collect(); + + ignored_attr_names.sort(); + + StableHashingContext { + tcx: tcx, + def_path_hashes: DefPathHashes::new(tcx), + codemap: CachingCodemapView::new(tcx), + hash_spans: hash_spans_initial, + hash_bodies: true, + overflow_checks_enabled: check_overflow_initial, + node_id_hashing_mode: NodeIdHashingMode::HashDefPath, + ignored_attr_names: ignored_attr_names, + } + } + + #[inline] + pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, + hash_bodies: bool, + f: F) { + let prev_hash_bodies = self.hash_bodies; + self.hash_bodies = hash_bodies; + f(self); + self.hash_bodies = prev_hash_bodies; + } + + #[inline] + pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, + hash_spans: bool, + f: F) { + let prev_hash_spans = self.hash_spans; + self.hash_spans = hash_spans; + f(self); + self.hash_spans = prev_hash_spans; + } + + #[inline] + pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(&mut self, + mode: NodeIdHashingMode, + f: F) { + let prev = self.node_id_hashing_mode; + self.node_id_hashing_mode = mode; + f(self); + self.node_id_hashing_mode = prev; + } + + #[inline] + pub fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + + #[inline] + pub fn def_path_hash(&mut self, def_id: DefId) -> u64 { + self.def_path_hashes.hash(def_id) + } + + #[inline] + pub fn hash_spans(&self) -> bool { + self.hash_spans + } + + #[inline] + pub fn hash_bodies(&self) -> bool { + self.hash_bodies + } + + #[inline] + pub fn codemap(&mut self) -> &mut CachingCodemapView<'tcx> { + &mut self.codemap + } + + #[inline] + pub fn is_ignored_attr(&self, name: Symbol) -> bool { + self.ignored_attr_names.binary_search(&name).is_ok() + } + + pub fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, + item_attrs: &[ast::Attribute], + f: F) { + let prev_overflow_checks = self.overflow_checks_enabled; + if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") { + self.overflow_checks_enabled = true; + } + let prev_hash_node_ids = self.node_id_hashing_mode; + self.node_id_hashing_mode = NodeIdHashingMode::Ignore; + + f(self); + + self.node_id_hashing_mode = prev_hash_node_ids; + self.overflow_checks_enabled = prev_overflow_checks; + } + + #[inline] + pub fn binop_can_panic_at_runtime(&self, binop: hir::BinOp_) -> bool + { + match binop { + hir::BiAdd | + hir::BiSub | + hir::BiMul => self.overflow_checks_enabled, + + hir::BiDiv | + hir::BiRem => true, + + hir::BiAnd | + hir::BiOr | + hir::BiBitXor | + hir::BiBitAnd | + hir::BiBitOr | + hir::BiShl | + hir::BiShr | + hir::BiEq | + hir::BiLt | + hir::BiLe | + hir::BiNe | + hir::BiGe | + hir::BiGt => false + } + } + + #[inline] + pub fn unop_can_panic_at_runtime(&self, unop: hir::UnOp) -> bool + { + match unop { + hir::UnDeref | + hir::UnNot => false, + hir::UnNeg => self.overflow_checks_enabled, + } + } +} + + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::NodeId { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + match hcx.node_id_hashing_mode { + NodeIdHashingMode::Ignore => { + // Most NodeIds in the HIR can be ignored, but if there is a + // corresponding entry in the `trait_map` we need to hash that. + // Make sure we don't ignore too much by checking that there is + // no entry in a debug_assert!(). + debug_assert!(hcx.tcx.trait_map.get(self).is_none()); + } + NodeIdHashingMode::HashDefPath => { + hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher); + } + NodeIdHashingMode::HashTraitsInScope => { + if let Some(traits) = hcx.tcx.trait_map.get(self) { + // The ordering of the candidates is not fixed. So we hash + // the def-ids and then sort them and hash the collection. + let mut candidates: AccumulateVec<[_; 8]> = + traits.iter() + .map(|&hir::TraitCandidate { def_id, import_id: _ }| { + hcx.def_path_hash(def_id) + }) + .collect(); + if traits.len() > 1 { + candidates.sort(); + } + candidates.hash_stable(hcx, hasher); + } + } + } + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for Span { + + // Hash a span in a stable way. We can't directly hash the span's BytePos + // fields (that would be similar to hashing pointers, since those are just + // offsets into the CodeMap). Instead, we hash the (file name, line, column) + // triple, which stays the same even if the containing FileMap has moved + // 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_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + use syntax_pos::Pos; + + if !hcx.hash_spans { + return + } + + // If this is not an empty or invalid span, we want to hash the last + // position that belongs to it, as opposed to hashing the first + // position past it. + let span_hi = if self.hi > self.lo { + // We might end up in the middle of a multibyte character here, + // but that's OK, since we are not trying to decode anything at + // this position. + self.hi - ::syntax_pos::BytePos(1) + } else { + self.hi + }; + + { + let loc1 = hcx.codemap().byte_pos_to_line_and_col(self.lo); + let loc1 = loc1.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) + .unwrap_or(("???", 0, 0)); + + let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi); + let loc2 = loc2.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) + .unwrap_or(("???", 0, 0)); + + if loc1.0 == loc2.0 { + std_hash::Hash::hash(&0u8, hasher); + + std_hash::Hash::hash(loc1.0, hasher); + std_hash::Hash::hash(&loc1.1, hasher); + std_hash::Hash::hash(&loc1.2, hasher); + + // Do not hash the file name twice + std_hash::Hash::hash(&loc2.1, hasher); + std_hash::Hash::hash(&loc2.2, hasher); + } else { + std_hash::Hash::hash(&1u8, hasher); + + std_hash::Hash::hash(loc1.0, hasher); + std_hash::Hash::hash(&loc1.1, hasher); + std_hash::Hash::hash(&loc1.2, hasher); + + std_hash::Hash::hash(loc2.0, hasher); + std_hash::Hash::hash(&loc2.1, hasher); + std_hash::Hash::hash(&loc2.2, hasher); + } + } + + if self.ctxt == SyntaxContext::empty() { + 0u8.hash_stable(hcx, hasher); + } else { + 1u8.hash_stable(hcx, hasher); + self.source_callsite().hash_stable(hcx, hasher); + } + } +} diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs new file mode 100644 index 00000000000..6d11f2a87a4 --- /dev/null +++ b/src/librustc/ich/impls_const_math.rs @@ -0,0 +1,71 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains `HashStable` implementations for various data types +//! from `rustc_const_math` in no particular order. + +impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat { + F32(val), + F64(val) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstInt { + I8(val), + I16(val), + I32(val), + I64(val), + I128(val), + Isize(val), + U8(val), + U16(val), + U32(val), + U64(val), + U128(val), + Usize(val) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize { + Is16(i16), + Is32(i32), + Is64(i64) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize { + Us16(i16), + Us32(i32), + Us64(i64) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr { + NotInRange, + CmpBetweenUnequalTypes, + UnequalTypes(op), + Overflow(op), + ShiftNegative, + DivisionByZero, + RemainderByZero, + UnsignedNegation, + ULitOutOfRange(int_ty), + LitOutOfRange(int_ty) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::Op { + Add, + Sub, + Mul, + Div, + Rem, + Shr, + Shl, + Neg, + BitAnd, + BitOr, + BitXor +}); diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs new file mode 100644 index 00000000000..9cf8a0693d3 --- /dev/null +++ b/src/librustc/ich/impls_hir.rs @@ -0,0 +1,1106 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains `HashStable` implementations for various HIR data +//! types in no particular order. + +use hir; +use hir::def_id::DefId; +use ich::{StableHashingContext, NodeIdHashingMode}; +use std::mem; + +use syntax::ast; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for DefId { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + hcx.def_path_hash(*self).hash_stable(hcx, hasher); + } +} + + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::HirId { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let hir::HirId { + owner, + local_id, + } = *self; + + hcx.def_path_hash(DefId::local(owner)).hash_stable(hcx, hasher); + local_id.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); + +// The following implementations of HashStable for ItemId, TraitItemId, and +// ImplItemId deserve special attention. Normally we do not hash NodeIds within +// the HIR, since they just signify a HIR nodes own path. But ItemId et al +// are used when another item in the HIR is *referenced* and we certainly +// want to pick up on a reference changing its target, so we hash the NodeIds +// in "DefPath Mode". + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ItemId { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let hir::ItemId { + id + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + id.hash_stable(hcx, hasher); + }) + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitItemId { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let hir::TraitItemId { + node_id + } = * self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + node_id.hash_stable(hcx, hasher); + }) + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ImplItemId { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let hir::ImplItemId { + node_id + } = * self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + node_id.hash_stable(hcx, hasher); + }) + } +} + +impl_stable_hash_for!(struct hir::Lifetime { + id, + span, + name +}); + +impl_stable_hash_for!(struct hir::LifetimeDef { + lifetime, + bounds, + pure_wrt_drop +}); + +impl_stable_hash_for!(struct hir::Path { + span, + def, + segments +}); + +impl_stable_hash_for!(struct hir::PathSegment { + name, + parameters +}); + +impl_stable_hash_for!(enum hir::PathParameters { + AngleBracketedParameters(data), + ParenthesizedParameters(data) +}); + +impl_stable_hash_for!(struct hir::AngleBracketedParameterData { + lifetimes, + types, + infer_types, + bindings +}); + +impl_stable_hash_for!(struct hir::ParenthesizedParameterData { + span, + inputs, + output +}); + +impl_stable_hash_for!(enum hir::TyParamBound { + TraitTyParamBound(poly_trait_ref, trait_bound_modifier), + RegionTyParamBound(lifetime) +}); + +impl_stable_hash_for!(enum hir::TraitBoundModifier { + None, + Maybe +}); + +impl_stable_hash_for!(struct hir::TyParam { + name, + id, + bounds, + default, + span, + pure_wrt_drop +}); + +impl_stable_hash_for!(struct hir::Generics { + lifetimes, + ty_params, + where_clause, + span +}); + +impl_stable_hash_for!(struct hir::WhereClause { + id, + predicates +}); + +impl_stable_hash_for!(enum hir::WherePredicate { + BoundPredicate(pred), + RegionPredicate(pred), + EqPredicate(pred) +}); + +impl_stable_hash_for!(struct hir::WhereBoundPredicate { + span, + bound_lifetimes, + bounded_ty, + bounds +}); + +impl_stable_hash_for!(struct hir::WhereRegionPredicate { + span, + lifetime, + bounds +}); + +impl_stable_hash_for!(struct hir::WhereEqPredicate { + id, + span, + lhs_ty, + rhs_ty +}); + +impl_stable_hash_for!(struct hir::MutTy { + ty, + mutbl +}); + +impl_stable_hash_for!(struct hir::MethodSig { + unsafety, + constness, + abi, + decl, + generics +}); + +impl_stable_hash_for!(struct hir::TypeBinding { + id, + name, + ty, + span +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Ty { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let node_id_hashing_mode = match self.node { + hir::TySlice(..) | + hir::TyArray(..) | + hir::TyPtr(..) | + hir::TyRptr(..) | + hir::TyBareFn(..) | + hir::TyNever | + hir::TyTup(..) | + hir::TyTraitObject(..) | + hir::TyImplTrait(..) | + hir::TyTypeof(..) | + hir::TyErr | + hir::TyInfer => { + NodeIdHashingMode::Ignore + } + hir::TyPath(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + hcx.while_hashing_hir_bodies(true, |hcx| { + let hir::Ty { + id, + ref node, + ref span, + } = *self; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }) + } +} + +impl_stable_hash_for!(enum hir::PrimTy { + TyInt(int_ty), + TyUint(uint_ty), + TyFloat(float_ty), + TyStr, + TyBool, + TyChar +}); + +impl_stable_hash_for!(struct hir::BareFnTy { + unsafety, + abi, + lifetimes, + decl +}); + +impl_stable_hash_for!(enum hir::Ty_ { + TySlice(t), + TyArray(t, body_id), + TyPtr(t), + TyRptr(lifetime, t), + TyBareFn(t), + TyNever, + TyTup(ts), + TyPath(qpath), + TyTraitObject(trait_refs, lifetime), + TyImplTrait(bounds), + TyTypeof(body_id), + TyErr, + TyInfer +}); + +impl_stable_hash_for!(struct hir::FnDecl { + inputs, + output, + variadic, + has_implicit_self +}); + +impl_stable_hash_for!(enum hir::FunctionRetTy { + DefaultReturn(span), + Return(t) +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitRef { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let hir::TraitRef { + ref path, + ref_id, + } = *self; + + path.hash_stable(hcx, hasher); + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| { + ref_id.hash_stable(hcx, hasher); + }); + } +} + + +impl_stable_hash_for!(struct hir::PolyTraitRef { + bound_lifetimes, + trait_ref, + span +}); + +impl_stable_hash_for!(enum hir::QPath { + Resolved(t, path), + TypeRelative(t, path_segment) +}); + +impl_stable_hash_for!(struct hir::MacroDef { + name, + attrs, + id, + span, + body +}); + + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Block { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let hir::Block { + ref stmts, + ref expr, + id, + rules, + span, + targeted_by_break, + } = *self; + + let non_item_stmts = || stmts.iter().filter(|stmt| { + match stmt.node { + hir::StmtDecl(ref decl, _) => { + match decl.node { + // If this is a declaration of a nested item, we don't + // want to leave any trace of it in the hash value, not + // even that it exists. Otherwise changing the position + // of nested items would invalidate the containing item + // even though that does not constitute a semantic + // change. + hir::DeclItem(_) => false, + hir::DeclLocal(_) => true + } + } + hir::StmtExpr(..) | + hir::StmtSemi(..) => true + } + }); + + let count = non_item_stmts().count(); + + count.hash_stable(hcx, hasher); + + for stmt in non_item_stmts() { + stmt.hash_stable(hcx, hasher); + } + + expr.hash_stable(hcx, hasher); + id.hash_stable(hcx, hasher); + rules.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + targeted_by_break.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Pat { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let node_id_hashing_mode = match self.node { + hir::PatKind::Wild | + hir::PatKind::Binding(..) | + hir::PatKind::Tuple(..) | + hir::PatKind::Box(..) | + hir::PatKind::Ref(..) | + hir::PatKind::Lit(..) | + hir::PatKind::Range(..) | + hir::PatKind::Slice(..) => { + NodeIdHashingMode::Ignore + } + hir::PatKind::Path(..) | + hir::PatKind::Struct(..) | + hir::PatKind::TupleStruct(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + let hir::Pat { + id, + ref node, + ref span + } = *self; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for_spanned!(hir::FieldPat); +impl_stable_hash_for!(struct hir::FieldPat { + name, + pat, + is_shorthand +}); + +impl_stable_hash_for!(enum hir::BindingMode { + BindByRef(mutability), + BindByValue(mutability) +}); + +impl_stable_hash_for!(enum hir::RangeEnd { + Included, + Excluded +}); + +impl_stable_hash_for!(enum hir::PatKind { + Wild, + Binding(binding_mode, var, name, sub), + Struct(path, field_pats, dotdot), + TupleStruct(path, field_pats, dotdot), + Path(path), + Tuple(field_pats, dotdot), + Box(sub), + Ref(sub, mutability), + Lit(expr), + Range(start, end, end_kind), + Slice(one, two, three) +}); + +impl_stable_hash_for!(enum hir::BinOp_ { + BiAdd, + BiSub, + BiMul, + BiDiv, + BiRem, + BiAnd, + BiOr, + BiBitXor, + BiBitAnd, + BiBitOr, + BiShl, + BiShr, + BiEq, + BiLt, + BiLe, + BiNe, + BiGe, + BiGt +}); + +impl_stable_hash_for_spanned!(hir::BinOp_); + +impl_stable_hash_for!(enum hir::UnOp { + UnDeref, + UnNot, + UnNeg +}); + +impl_stable_hash_for_spanned!(hir::Stmt_); + +impl_stable_hash_for!(struct hir::Local { + pat, + ty, + init, + id, + span, + attrs +}); + +impl_stable_hash_for_spanned!(hir::Decl_); +impl_stable_hash_for!(enum hir::Decl_ { + DeclLocal(local), + DeclItem(item_id) +}); + +impl_stable_hash_for!(struct hir::Arm { + attrs, + pats, + guard, + body +}); + +impl_stable_hash_for!(struct hir::Field { + name, + expr, + span, + is_shorthand +}); + +impl_stable_hash_for_spanned!(ast::Name); + + +impl_stable_hash_for!(enum hir::BlockCheckMode { + DefaultBlock, + UnsafeBlock(src), + PushUnsafeBlock(src), + PopUnsafeBlock(src) +}); + +impl_stable_hash_for!(enum hir::UnsafeSource { + CompilerGenerated, + UserProvided +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Expr { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + hcx.while_hashing_hir_bodies(true, |hcx| { + let hir::Expr { + id, + ref span, + ref node, + ref attrs + } = *self; + + let (spans_always_on, node_id_hashing_mode) = match *node { + hir::ExprBox(..) | + hir::ExprArray(..) | + hir::ExprCall(..) | + hir::ExprLit(..) | + hir::ExprCast(..) | + hir::ExprType(..) | + hir::ExprIf(..) | + hir::ExprWhile(..) | + hir::ExprLoop(..) | + hir::ExprMatch(..) | + hir::ExprClosure(..) | + hir::ExprBlock(..) | + hir::ExprAssign(..) | + hir::ExprTupField(..) | + hir::ExprAddrOf(..) | + hir::ExprBreak(..) | + hir::ExprAgain(..) | + hir::ExprRet(..) | + hir::ExprInlineAsm(..) | + hir::ExprRepeat(..) | + hir::ExprTup(..) => { + // For these we only hash the span when debuginfo is on. + (false, NodeIdHashingMode::Ignore) + } + // For the following, spans might be significant because of + // panic messages indicating the source location. + hir::ExprBinary(op, ..) => { + (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore) + } + hir::ExprUnary(op, _) => { + (hcx.unop_can_panic_at_runtime(op), NodeIdHashingMode::Ignore) + } + hir::ExprAssignOp(op, ..) => { + (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore) + } + hir::ExprIndex(..) => { + (true, NodeIdHashingMode::Ignore) + } + // For these we don't care about the span, but want to hash the + // trait in scope + hir::ExprMethodCall(..) | + hir::ExprPath(..) | + hir::ExprStruct(..) | + hir::ExprField(..) => { + (false, NodeIdHashingMode::HashTraitsInScope) + } + }; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + + if spans_always_on { + hcx.while_hashing_spans(true, |hcx| { + span.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + }); + } else { + span.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + } + }) + } +} + +impl_stable_hash_for!(enum hir::Expr_ { + ExprBox(sub), + ExprArray(subs), + ExprCall(callee, args), + ExprMethodCall(name, ts, args), + ExprTup(fields), + ExprBinary(op, lhs, rhs), + ExprUnary(op, operand), + ExprLit(value), + ExprCast(expr, t), + ExprType(expr, t), + ExprIf(cond, then, els), + ExprWhile(cond, body, label), + ExprLoop(body, label, loop_src), + ExprMatch(matchee, arms, match_src), + ExprClosure(capture_clause, decl, body_id, span), + ExprBlock(blk), + ExprAssign(lhs, rhs), + ExprAssignOp(op, lhs, rhs), + ExprField(owner, field_name), + ExprTupField(owner, idx), + ExprIndex(lhs, rhs), + ExprPath(path), + ExprAddrOf(mutability, sub), + ExprBreak(destination, sub), + ExprAgain(destination), + ExprRet(val), + ExprInlineAsm(asm, inputs, outputs), + ExprStruct(path, fields, base), + ExprRepeat(val, times) +}); + +impl_stable_hash_for!(enum hir::LoopSource { + Loop, + WhileLet, + ForLoop +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::MatchSource { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + use hir::MatchSource; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + MatchSource::Normal | + MatchSource::WhileLetDesugar | + MatchSource::ForLoopDesugar | + MatchSource::TryDesugar => { + // No fields to hash. + } + MatchSource::IfLetDesugar { contains_else_clause } => { + contains_else_clause.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum hir::CaptureClause { + CaptureByValue, + CaptureByRef +}); + +impl_stable_hash_for_spanned!(usize); + +impl_stable_hash_for!(struct hir::Destination { + ident, + target_id +}); + +impl_stable_hash_for_spanned!(ast::Ident); + +impl_stable_hash_for!(enum hir::LoopIdResult { + Ok(node_id), + Err(loop_id_error) +}); + +impl_stable_hash_for!(enum hir::LoopIdError { + OutsideLoopScope, + UnlabeledCfInWhileCondition, + UnresolvedLabel +}); + +impl_stable_hash_for!(enum hir::ScopeTarget { + Block(node_id), + Loop(loop_id_result) +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Ident { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let ast::Ident { + ref name, + ctxt: _ // Ignore this + } = *self; + + name.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitItem { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let hir::TraitItem { + id, + name, + ref attrs, + ref node, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::TraitMethod { + Required(name), + Provided(body) +}); + +impl_stable_hash_for!(enum hir::TraitItemKind { + Const(t, body), + Method(sig, method), + Type(bounds, rhs) +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ImplItem { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let hir::ImplItem { + id, + name, + ref vis, + defaultness, + ref attrs, + ref node, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + defaultness.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::ImplItemKind { + Const(t, body), + Method(sig, body), + Type(t) +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Visibility { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::Visibility::Public | + hir::Visibility::Crate | + hir::Visibility::Inherited => { + // No fields to hash. + } + hir::Visibility::Restricted { ref path, id } => { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| { + id.hash_stable(hcx, hasher); + }); + path.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Defaultness { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::Defaultness::Final => { + // No fields to hash. + } + hir::Defaultness::Default { has_value } => { + has_value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum hir::ImplPolarity { + Positive, + Negative +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Mod { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let hir::Mod { + inner, + // We are not hashing the IDs of the items contained in the module. + // This is harmless and matches the current behavior but it's not + // actually correct. See issue #40876. + item_ids: _, + } = *self; + + inner.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct hir::ForeignMod { + abi, + items +}); + +impl_stable_hash_for!(struct hir::EnumDef { + variants +}); + +impl_stable_hash_for!(struct hir::Variant_ { + name, + attrs, + data, + disr_expr +}); + +impl_stable_hash_for_spanned!(hir::Variant_); + +impl_stable_hash_for!(enum hir::UseKind { + Single, + Glob, + ListStem +}); + +impl_stable_hash_for!(struct hir::StructField { + span, + name, + vis, + id, + ty, + attrs +}); + +impl_stable_hash_for!(enum hir::VariantData { + Struct(fields, id), + Tuple(fields, id), + Unit(id) +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Item { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let node_id_hashing_mode = match self.node { + hir::ItemExternCrate(..) | + hir::ItemStatic(..) | + hir::ItemConst(..) | + hir::ItemFn(..) | + hir::ItemMod(..) | + hir::ItemForeignMod(..) | + hir::ItemTy(..) | + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemTrait(..) | + hir::ItemDefaultImpl(..) | + hir::ItemImpl(..) => { + NodeIdHashingMode::Ignore + } + hir::ItemUse(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + let hir::Item { + name, + ref attrs, + id, + ref node, + ref vis, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::Item_ { + ItemExternCrate(name), + ItemUse(path, use_kind), + ItemStatic(ty, mutability, body_id), + ItemConst(ty, body_id), + ItemFn(fn_decl, unsafety, constness, abi, generics, body_id), + ItemMod(module), + ItemForeignMod(foreign_mod), + ItemTy(ty, generics), + ItemEnum(enum_def, generics), + ItemStruct(variant_data, generics), + ItemUnion(variant_data, generics), + ItemTrait(unsafety, generics, bounds, item_refs), + ItemDefaultImpl(unsafety, trait_ref), + ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs) +}); + +impl_stable_hash_for!(struct hir::TraitItemRef { + id, + name, + kind, + span, + defaultness +}); + +impl_stable_hash_for!(struct hir::ImplItemRef { + id, + name, + kind, + span, + vis, + defaultness +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::AssociatedItemKind { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::AssociatedItemKind::Const | + hir::AssociatedItemKind::Type => { + // No fields to hash. + } + hir::AssociatedItemKind::Method { has_self } => { + has_self.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct hir::ForeignItem { + name, + attrs, + node, + id, + span, + vis +}); + +impl_stable_hash_for!(enum hir::ForeignItem_ { + ForeignItemFn(fn_decl, arg_names, generics), + ForeignItemStatic(ty, is_mutbl) +}); + +impl_stable_hash_for!(enum hir::Stmt_ { + StmtDecl(decl, id), + StmtExpr(expr, id), + StmtSemi(expr, id) +}); + +impl_stable_hash_for!(struct hir::Arg { + pat, + id +}); + +impl_stable_hash_for!(struct hir::Body { + arguments, + value +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::BodyId { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + if hcx.hash_bodies() { + hcx.tcx().hir.body(*self).hash_stable(hcx, hasher); + } + } +} + +impl_stable_hash_for!(struct hir::InlineAsmOutput { + constraint, + is_rw, + is_indirect +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::InlineAsm { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let hir::InlineAsm { + asm, + asm_str_style, + ref outputs, + ref inputs, + ref clobbers, + volatile, + alignstack, + dialect, + ctxt: _, // This is used for error reporting + } = *self; + + asm.hash_stable(hcx, hasher); + asm_str_style.hash_stable(hcx, hasher); + outputs.hash_stable(hcx, hasher); + inputs.hash_stable(hcx, hasher); + clobbers.hash_stable(hcx, hasher); + volatile.hash_stable(hcx, hasher); + alignstack.hash_stable(hcx, hasher); + dialect.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum hir::def::CtorKind { + Fn, + Const, + Fictive +}); + +impl_stable_hash_for!(enum hir::def::Def { + Mod(def_id), + Struct(def_id), + Union(def_id), + Enum(def_id), + Variant(def_id), + Trait(def_id), + TyAlias(def_id), + AssociatedTy(def_id), + PrimTy(prim_ty), + TyParam(def_id), + SelfTy(trait_def_id, impl_def_id), + Fn(def_id), + Const(def_id), + Static(def_id, is_mutbl), + StructCtor(def_id, ctor_kind), + VariantCtor(def_id, ctor_kind), + Method(def_id), + AssociatedConst(def_id), + Local(def_id), + Upvar(def_id, index, expr_id), + Label(node_id), + Macro(def_id, macro_kind), + Err +}); + +impl_stable_hash_for!(enum hir::Mutability { + MutMutable, + MutImmutable +}); + + +impl_stable_hash_for!(enum hir::Unsafety { + Unsafe, + Normal +}); + + +impl_stable_hash_for!(enum hir::Constness { + Const, + NotConst +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::def_id::DefIndex { + + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + DefId::local(*self).hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct hir::def::Export { + name, + def, + span +}); diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs new file mode 100644 index 00000000000..401f7e1921a --- /dev/null +++ b/src/librustc/ich/impls_mir.rs @@ -0,0 +1,407 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains `HashStable` implementations for various MIR data +//! types in no particular order. + +use ich::StableHashingContext; +use mir; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::mem; + + +impl_stable_hash_for!(struct mir::SourceInfo { span, scope }); +impl_stable_hash_for!(enum mir::Mutability { Mut, Not }); +impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut }); +impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer }); +impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info }); +impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); +impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); +impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Local { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::BasicBlock { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Field { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::VisibilityScope { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Promoted { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::TerminatorKind<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::TerminatorKind::Goto { ref target } => { + target.hash_stable(hcx, hasher); + } + mir::TerminatorKind::SwitchInt { ref discr, + switch_ty, + ref values, + ref targets } => { + discr.hash_stable(hcx, hasher); + switch_ty.hash_stable(hcx, hasher); + values.hash_stable(hcx, hasher); + targets.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Resume | + mir::TerminatorKind::Return | + mir::TerminatorKind::Unreachable => {} + mir::TerminatorKind::Drop { ref location, target, unwind } => { + location.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + unwind.hash_stable(hcx, hasher); + } + mir::TerminatorKind::DropAndReplace { ref location, + ref value, + target, + unwind, } => { + location.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + unwind.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Call { ref func, + ref args, + ref destination, + cleanup } => { + func.hash_stable(hcx, hasher); + args.hash_stable(hcx, hasher); + destination.hash_stable(hcx, hasher); + cleanup.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Assert { ref cond, + expected, + ref msg, + target, + cleanup } => { + cond.hash_stable(hcx, hasher); + expected.hash_stable(hcx, hasher); + msg.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + cleanup.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::AssertMessage<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::AssertMessage::BoundsCheck { ref len, ref index } => { + len.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + } + mir::AssertMessage::Math(ref const_math_err) => { + const_math_err.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::StatementKind<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::StatementKind::Assign(ref lvalue, ref rvalue) => { + lvalue.hash_stable(hcx, hasher); + rvalue.hash_stable(hcx, hasher); + } + mir::StatementKind::SetDiscriminant { ref lvalue, variant_index } => { + lvalue.hash_stable(hcx, hasher); + variant_index.hash_stable(hcx, hasher); + } + mir::StatementKind::StorageLive(ref lvalue) | + mir::StatementKind::StorageDead(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::StatementKind::Nop => {} + mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { + asm.hash_stable(hcx, hasher); + outputs.hash_stable(hcx, hasher); + inputs.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Lvalue<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::Lvalue::Local(ref local) => { + local.hash_stable(hcx, hasher); + } + mir::Lvalue::Static(ref statik) => { + statik.hash_stable(hcx, hasher); + } + mir::Lvalue::Projection(ref lvalue_projection) => { + lvalue_projection.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx, B, V> HashStable<StableHashingContext<'a, 'tcx>> for mir::Projection<'tcx, B, V> + where B: HashStable<StableHashingContext<'a, 'tcx>>, + V: HashStable<StableHashingContext<'a, 'tcx>> +{ + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let mir::Projection { + ref base, + ref elem, + } = *self; + + base.hash_stable(hcx, hasher); + elem.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx, V> HashStable<StableHashingContext<'a, 'tcx>> for mir::ProjectionElem<'tcx, V> + where V: HashStable<StableHashingContext<'a, 'tcx>> +{ + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::ProjectionElem::Deref => {} + mir::ProjectionElem::Field(field, ty) => { + field.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Index(ref value) => { + value.hash_stable(hcx, hasher); + } + mir::ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + offset.hash_stable(hcx, hasher); + min_length.hash_stable(hcx, hasher); + from_end.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Subslice { from, to } => { + from.hash_stable(hcx, hasher); + to.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Downcast(adt_def, variant) => { + adt_def.hash_stable(hcx, hasher); + variant.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope }); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Operand<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::Operand::Consume(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Operand::Constant(ref constant) => { + constant.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Rvalue<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::Rvalue::Use(ref operand) => { + operand.hash_stable(hcx, hasher); + } + mir::Rvalue::Repeat(ref operand, ref val) => { + operand.hash_stable(hcx, hasher); + val.hash_stable(hcx, hasher); + } + mir::Rvalue::Ref(region, borrow_kind, ref lvalue) => { + region.hash_stable(hcx, hasher); + borrow_kind.hash_stable(hcx, hasher); + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Len(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Cast(cast_kind, ref operand, ty) => { + cast_kind.hash_stable(hcx, hasher); + operand.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); + } + mir::Rvalue::BinaryOp(op, ref operand1, ref operand2) | + mir::Rvalue::CheckedBinaryOp(op, ref operand1, ref operand2) => { + op.hash_stable(hcx, hasher); + operand1.hash_stable(hcx, hasher); + operand2.hash_stable(hcx, hasher); + } + mir::Rvalue::UnaryOp(op, ref operand) => { + op.hash_stable(hcx, hasher); + operand.hash_stable(hcx, hasher); + } + mir::Rvalue::Discriminant(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Box(ty) => { + ty.hash_stable(hcx, hasher); + } + mir::Rvalue::Aggregate(ref kind, ref operands) => { + kind.hash_stable(hcx, hasher); + operands.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum mir::CastKind { + Misc, + ReifyFnPointer, + ClosureFnPointer, + UnsafeFnPointer, + Unsize +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::AggregateKind<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::AggregateKind::Tuple => {} + mir::AggregateKind::Array(t) => { + t.hash_stable(hcx, hasher); + } + mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => { + adt_def.hash_stable(hcx, hasher); + idx.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + active_field.hash_stable(hcx, hasher); + } + mir::AggregateKind::Closure(def_id, ref substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum mir::BinOp { + Add, + Sub, + Mul, + Div, + Rem, + BitXor, + BitAnd, + BitOr, + Shl, + Shr, + Eq, + Lt, + Le, + Ne, + Ge, + Gt +}); + +impl_stable_hash_for!(enum mir::UnOp { + Not, + Neg +}); + + +impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Literal<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::Literal::Item { def_id, substs } => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + mir::Literal::Value { ref value } => { + value.hash_stable(hcx, hasher); + } + mir::Literal::Promoted { index } => { + index.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::Location { block, statement_index }); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs new file mode 100644 index 00000000000..26734500001 --- /dev/null +++ b/src/librustc/ich/impls_syntax.rs @@ -0,0 +1,301 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains `HashStable` implementations for various data types +//! from libsyntax in no particular order. + +use ich::StableHashingContext; + +use std::hash as std_hash; +use std::mem; + +use syntax::ast; +use syntax::parse::token; +use syntax::tokenstream; +use syntax_pos::Span; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use rustc_data_structures::accumulate_vec::AccumulateVec; + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::symbol::InternedString { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let s: &str = &**self; + s.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Name { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + self.as_str().hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum ::syntax::ast::AsmDialect { + Att, + Intel +}); + +impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { + Bang, + Attr, + Derive +}); + + +impl_stable_hash_for!(enum ::syntax::abi::Abi { + Cdecl, + Stdcall, + Fastcall, + Vectorcall, + Aapcs, + Win64, + SysV64, + PtxKernel, + Msp430Interrupt, + X86Interrupt, + Rust, + C, + System, + RustIntrinsic, + RustCall, + PlatformIntrinsic, + Unadjusted +}); + +impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note }); +impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr }); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::attr::StabilityLevel { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => { + reason.hash_stable(hcx, hasher); + issue.hash_stable(hcx, hasher); + } + ::syntax::attr::StabilityLevel::Stable { ref since } => { + since.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason }); + + +impl_stable_hash_for!(enum ::syntax::attr::IntType { + SignedInt(int_ty), + UnsignedInt(uint_ty) +}); + +impl_stable_hash_for!(enum ::syntax::ast::LitIntType { + Signed(int_ty), + Unsigned(int_ty), + Unsuffixed +}); + +impl_stable_hash_for_spanned!(::syntax::ast::LitKind); +impl_stable_hash_for!(enum ::syntax::ast::LitKind { + Str(value, style), + ByteStr(value), + Byte(value), + Char(value), + Int(value, lit_int_type), + Float(value, float_ty), + FloatUnsuffixed(value), + Bool(value) +}); + +impl_stable_hash_for!(enum ::syntax::ast::IntTy { Is, I8, I16, I32, I64, I128 }); +impl_stable_hash_for!(enum ::syntax::ast::UintTy { Us, U8, U16, U32, U64, U128 }); +impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 }); +impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal }); +impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst }); +impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final }); +impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, name }); +impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); +impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for [ast::Attribute] { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + // Some attributes are always ignored during hashing. + let filtered: AccumulateVec<[&ast::Attribute; 8]> = self + .iter() + .filter(|attr| { + !attr.is_sugared_doc && + attr.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true) + }) + .collect(); + + filtered.len().hash_stable(hcx, hasher); + for attr in filtered { + attr.hash_stable(hcx, hasher); + } + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Attribute { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + // Make sure that these have been filtered out. + debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)); + debug_assert!(!self.is_sugared_doc); + + let ast::Attribute { + id: _, + style, + ref path, + ref tokens, + is_sugared_doc: _, + span, + } = *self; + + style.hash_stable(hcx, hasher); + path.segments.len().hash_stable(hcx, hasher); + for segment in &path.segments { + segment.identifier.name.hash_stable(hcx, hasher); + } + for tt in tokens.trees() { + tt.hash_stable(hcx, hasher); + } + span.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for tokenstream::TokenTree { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + tokenstream::TokenTree::Token(span, ref token) => { + span.hash_stable(hcx, hasher); + hash_token(token, hcx, hasher, span); + } + tokenstream::TokenTree::Delimited(span, ref delimited) => { + span.hash_stable(hcx, hasher); + std_hash::Hash::hash(&delimited.delim, hasher); + for sub_tt in delimited.stream().trees() { + sub_tt.hash_stable(hcx, hasher); + } + } + } + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for tokenstream::TokenStream { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + for sub_tt in self.trees() { + sub_tt.hash_stable(hcx, hasher); + } + } +} + +fn hash_token<'a, 'tcx, W: StableHasherResult>(token: &token::Token, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>, + error_reporting_span: Span) { + mem::discriminant(token).hash_stable(hcx, hasher); + match *token { + token::Token::Eq | + token::Token::Lt | + token::Token::Le | + token::Token::EqEq | + token::Token::Ne | + token::Token::Ge | + token::Token::Gt | + token::Token::AndAnd | + token::Token::OrOr | + token::Token::Not | + token::Token::Tilde | + token::Token::At | + token::Token::Dot | + token::Token::DotDot | + token::Token::DotDotDot | + token::Token::Comma | + token::Token::Semi | + token::Token::Colon | + token::Token::ModSep | + token::Token::RArrow | + token::Token::LArrow | + token::Token::FatArrow | + token::Token::Pound | + token::Token::Dollar | + token::Token::Question | + token::Token::Underscore | + token::Token::Whitespace | + token::Token::Comment | + token::Token::Eof => {} + + token::Token::BinOp(bin_op_token) | + token::Token::BinOpEq(bin_op_token) => { + std_hash::Hash::hash(&bin_op_token, hasher); + } + + token::Token::OpenDelim(delim_token) | + token::Token::CloseDelim(delim_token) => { + std_hash::Hash::hash(&delim_token, hasher); + } + token::Token::Literal(ref lit, ref opt_name) => { + mem::discriminant(lit).hash_stable(hcx, hasher); + match *lit { + token::Lit::Byte(val) | + token::Lit::Char(val) | + token::Lit::Integer(val) | + token::Lit::Float(val) | + token::Lit::Str_(val) | + token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher), + token::Lit::StrRaw(val, n) | + token::Lit::ByteStrRaw(val, n) => { + val.hash_stable(hcx, hasher); + n.hash_stable(hcx, hasher); + } + }; + opt_name.hash_stable(hcx, hasher); + } + + token::Token::Ident(ident) | + token::Token::Lifetime(ident) | + token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher), + + token::Token::Interpolated(ref non_terminal) => { + // FIXME(mw): This could be implemented properly. It's just a + // lot of work, since we would need to hash the AST + // in a stable way, in addition to the HIR. + // Since this is hardly used anywhere, just emit a + // warning for now. + if hcx.tcx().sess.opts.debugging_opts.incremental.is_some() { + let msg = format!("Quasi-quoting might make incremental \ + compilation very inefficient: {:?}", + non_terminal); + hcx.tcx().sess.span_warn(error_reporting_span, &msg[..]); + } + + std_hash::Hash::hash(non_terminal, hasher); + } + + token::Token::DocComment(val) | + token::Token::Shebang(val) => val.hash_stable(hcx, hasher), + } +} diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs new file mode 100644 index 00000000000..7b6f3af2a11 --- /dev/null +++ b/src/librustc/ich/impls_ty.rs @@ -0,0 +1,415 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains `HashStable` implementations for various data types +//! from rustc::ty in no particular order. + +use ich::StableHashingContext; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::hash as std_hash; +use std::mem; +use ty; + + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Ty<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let type_hash = hcx.tcx().type_id_hash(*self); + type_hash.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); + +impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for ty::Slice<T> + where T: HashStable<StableHashingContext<'a, 'tcx>> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + (&**self).hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::subst::Kind<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + self.as_type().hash_stable(hcx, hasher); + self.as_region().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Region { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::ReErased | + ty::ReStatic | + ty::ReEmpty => { + // No variant fields to hash for these ... + } + ty::ReLateBound(db, ty::BrAnon(i)) => { + db.depth.hash_stable(hcx, hasher); + i.hash_stable(hcx, hasher); + } + ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => { + index.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + } + ty::ReLateBound(..) | + ty::ReFree(..) | + ty::ReScope(..) | + ty::ReVar(..) | + ty::ReSkolemized(..) => { + bug!("TypeIdHasher: unexpected region {:?}", *self) + } + } + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::AutoBorrow<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::adjustment::AutoBorrow::Ref(ref region, mutability) => { + region.hash_stable(hcx, hasher); + mutability.hash_stable(hcx, hasher); + } + ty::adjustment::AutoBorrow::RawPtr(mutability) => { + mutability.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::Adjust<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::adjustment::Adjust::NeverToAny | + ty::adjustment::Adjust::ReifyFnPointer | + ty::adjustment::Adjust::UnsafeFnPointer | + ty::adjustment::Adjust::ClosureFnPointer | + ty::adjustment::Adjust::MutToConstPointer => {} + ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => { + autoderefs.hash_stable(hcx, hasher); + autoref.hash_stable(hcx, hasher); + unsize.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); +impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef }); +impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs }); +impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); +impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); + +impl_stable_hash_for!(enum ty::BorrowKind { + ImmBorrow, + UniqueImmBorrow, + MutBorrow +}); + + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::UpvarCapture<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByRef(ref up_var_borrow) => { + up_var_borrow.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::FnSig<'tcx> { + inputs_and_output, + variadic, + unsafety, + abi +}); + +impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for ty::Binder<T> + where T: HashStable<StableHashingContext<'a, 'tcx>> + ty::fold::TypeFoldable<'tcx> +{ + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum ty::ClosureKind { Fn, FnMut, FnOnce }); + +impl_stable_hash_for!(enum ty::Visibility { + Public, + Restricted(def_id), + Invisible +}); + +impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); +impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); +impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); + +impl<'a, 'tcx, A, B> HashStable<StableHashingContext<'a, 'tcx>> for ty::OutlivesPredicate<A, B> + where A: HashStable<StableHashingContext<'a, 'tcx>>, + B: HashStable<StableHashingContext<'a, 'tcx>>, +{ + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let ty::OutlivesPredicate(ref a, ref b) = *self; + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty }); +impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_name }); + + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Predicate<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::Predicate::Trait(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Equate(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::RegionOutlives(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::TypeOutlives(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Projection(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::WellFormed(ty) => { + ty.hash_stable(hcx, hasher); + } + ty::Predicate::ObjectSafe(def_id) => { + def_id.hash_stable(hcx, hasher); + } + ty::Predicate::ClosureKind(def_id, closure_kind) => { + def_id.hash_stable(hcx, hasher); + closure_kind.hash_stable(hcx, hasher); + } + } + } +} + + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::AdtFlags { + fn hash_stable<W: StableHasherResult>(&self, + _: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + std_hash::Hash::hash(self, hasher); + } +} + +impl_stable_hash_for!(struct ty::VariantDef { + did, + name, + discr, + fields, + ctor_kind +}); + +impl_stable_hash_for!(enum ty::VariantDiscr { + Explicit(def_id), + Relative(distance) +}); + +impl_stable_hash_for!(struct ty::FieldDef { + did, + name, + vis +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> +for ::middle::const_val::ConstVal<'tcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + use middle::const_val::ConstVal; + + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + ConstVal::Float(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Integral(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Str(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::ByteStr(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Bool(value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Function(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + ConstVal::Struct(ref _name_value_map) => { + // BTreeMap<ast::Name, ConstVal<'tcx>>), + panic!("Ordering still unstable") + } + ConstVal::Tuple(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Array(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Repeat(ref value, times) => { + value.hash_stable(hcx, hasher); + times.hash_stable(hcx, hasher); + } + ConstVal::Char(value) => { + value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); + + +impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { + parent, + predicates +}); + +impl_stable_hash_for!(enum ty::Variance { + Covariant, + Invariant, + Contravariant, + Bivariant +}); + +impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized { + Struct(index) +}); + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Generics { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let ty::Generics { + parent, + parent_regions, + parent_types, + ref regions, + ref types, + + // Reverse map to each `TypeParameterDef`'s `index` field, from + // `def_id.index` (`def_id.krate` is the same as the item's). + type_param_to_index: _, // Don't hash this + has_self, + } = *self; + + parent.hash_stable(hcx, hasher); + parent_regions.hash_stable(hcx, hasher); + parent_types.hash_stable(hcx, hasher); + regions.hash_stable(hcx, hasher); + types.hash_stable(hcx, hasher); + has_self.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionParameterDef { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let ty::RegionParameterDef { + name, + def_id, + index, + issue_32330: _, + pure_wrt_drop + } = *self; + + name.hash_stable(hcx, hasher); + def_id.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + pure_wrt_drop.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::TypeParameterDef { + name, + def_id, + index, + has_default, + object_lifetime_default, + pure_wrt_drop +}); + + +impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> +for ::middle::resolve_lifetime::Set1<T> + where T: HashStable<StableHashingContext<'a, 'tcx>> +{ + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + use middle::resolve_lifetime::Set1; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + Set1::Empty | + Set1::Many => { + // Nothing to do. + } + Set1::One(ref value) => { + value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region { + Static, + EarlyBound(index, decl), + LateBound(db_index, decl), + LateBoundAnon(db_index, anon_index), + Free(call_site_scope_data, decl) +}); + +impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData { + fn_id, + body_id +}); + +impl_stable_hash_for!(struct ty::DebruijnIndex { + depth +}); diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index 209953f3c68..f0601a0efab 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -8,13 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! ICH - Incremental Compilation Hash + pub use self::fingerprint::Fingerprint; pub use self::def_path_hash::DefPathHashes; pub use self::caching_codemap_view::CachingCodemapView; +pub use self::hcx::{StableHashingContext, NodeIdHashingMode}; mod fingerprint; mod def_path_hash; mod caching_codemap_view; +mod hcx; + +mod impls_const_math; +mod impls_hir; +mod impls_mir; +mod impls_ty; +mod impls_syntax; pub const ATTR_DIRTY: &'static str = "rustc_dirty"; pub const ATTR_CLEAN: &'static str = "rustc_clean"; @@ -22,6 +32,20 @@ pub const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty"; pub const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_clean"; pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed"; pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; +pub const ATTR_PARTITION_REUSED: &'static str = "rustc_partition_reused"; +pub const ATTR_PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; + + +pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[ + ATTR_IF_THIS_CHANGED, + ATTR_THEN_THIS_WOULD_NEED, + ATTR_DIRTY, + ATTR_CLEAN, + ATTR_DIRTY_METADATA, + ATTR_CLEAN_METADATA, + ATTR_PARTITION_REUSED, + ATTR_PARTITION_TRANSLATED, +]; pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ "cfg", @@ -30,5 +54,7 @@ pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, - ATTR_CLEAN_METADATA + ATTR_CLEAN_METADATA, + ATTR_PARTITION_REUSED, + ATTR_PARTITION_TRANSLATED, ]; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 294f80d7d23..3b002fd4dfc 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -41,6 +41,7 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(unboxed_closures)] +#![feature(discriminant_value)] extern crate arena; extern crate core; diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 76dca1bb5b6..c18e585f795 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + macro_rules! enum_from_u32 { ($(#[$attr:meta])* pub enum $name:ident { $($variant:ident = $e:expr,)* @@ -59,3 +61,80 @@ macro_rules! span_bug { $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) }) } + +#[macro_export] +macro_rules! __impl_stable_hash_field { + (DECL IGNORED) => (_); + (DECL $name:ident) => (ref $name); + (USE IGNORED $ctx:expr, $hasher:expr) => ({}); + (USE $name:ident, $ctx:expr, $hasher:expr) => ($name.hash_stable($ctx, $hasher)); +} + +#[macro_export] +macro_rules! impl_stable_hash_for { + (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name { + #[inline] + fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) { + use $enum_name::*; + ::std::mem::discriminant(self).hash_stable(__ctx, __hasher); + + match *self { + $( + $variant $( ( $( __impl_stable_hash_field!(DECL $arg) ),* ) )* => { + $($( __impl_stable_hash_field!(USE $arg, __ctx, __hasher) );*)* + } + )* + } + } + } + }; + (struct $struct_name:path { $($field:ident),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + #[inline] + fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) { + let $struct_name { + $(ref $field),* + } = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; + (tuple_struct $struct_name:path { $($field:ident),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + #[inline] + fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) { + let $struct_name ( + $(ref $field),* + ) = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; +} + +#[macro_export] +macro_rules! impl_stable_hash_for_spanned { + ($T:path) => ( + + impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::codemap::Spanned<$T> + { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + self.node.hash_stable(hcx, hasher); + self.span.hash_stable(hcx, hasher); + } + } + ); +} + diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3b52e85e08e..7d3c17a0489 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -202,11 +202,14 @@ pub enum ImmutabilityBlame<'tcx> { } impl<'tcx> cmt_<'tcx> { - fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef) + fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)> { - let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| { - bug!("interior cmt {:?} is not an ADT", self) - }); + let adt_def = match self.ty.sty { + ty::TyAdt(def, _) => def, + ty::TyTuple(..) => return None, + // closures get `Categorization::Upvar` rather than `Categorization::Interior` + _ => bug!("interior cmt {:?} is not an ADT", self) + }; let variant_def = match self.cat { Categorization::Downcast(_, variant_did) => { adt_def.variant_with_id(variant_did) @@ -220,7 +223,7 @@ impl<'tcx> cmt_<'tcx> { NamedField(name) => variant_def.field_named(name), PositionalField(idx) => &variant_def.fields[idx] }; - (adt_def, field_def) + Some((adt_def, field_def)) } pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> { @@ -232,8 +235,9 @@ impl<'tcx> cmt_<'tcx> { Categorization::Local(node_id) => Some(ImmutabilityBlame::LocalDeref(node_id)), Categorization::Interior(ref base_cmt, InteriorField(field_name)) => { - let (adt_def, field_def) = base_cmt.resolve_field(field_name); - Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)) + base_cmt.resolve_field(field_name).map(|(adt_def, field_def)| { + ImmutabilityBlame::AdtFieldDeref(adt_def, field_def) + }) } Categorization::Upvar(Upvar { id, .. }) => { if let NoteClosureEnv(..) = self.note { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index b0e39442af9..e5dd48534a6 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -15,11 +15,11 @@ // makes all other generics or inline functions that it references // reachable as well. -use dep_graph::DepNode; use hir::map as hir_map; use hir::def::Def; -use hir::def_id::DefId; +use hir::def_id::{DefId, CrateNum}; use ty::{self, TyCtxt}; +use ty::maps::Providers; use middle::privacy; use session::config; use util::nodemap::{NodeSet, FxHashSet}; @@ -362,7 +362,11 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { - let _task = tcx.dep_graph.in_task(DepNode::Reachability); + ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE) +} + +fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet { + debug_assert!(crate_num == LOCAL_CRATE); let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); @@ -408,3 +412,10 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { // Return the set of reachable symbols. reachable_context.reachable_symbols } + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + reachable_set, + ..*providers + }; +} diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index bc9bbebb179..799686ceca4 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -10,7 +10,9 @@ use std::cell::{Ref, RefCell}; use rustc_data_structures::indexed_vec::IndexVec; - +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use ich::StableHashingContext; use mir::{Mir, BasicBlock}; use rustc_serialize as serialize; @@ -33,6 +35,13 @@ impl serialize::Decodable for Cache { } } +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for Cache { + fn hash_stable<W: StableHasherResult>(&self, + _: &mut StableHashingContext<'a, 'tcx>, + _: &mut StableHasher<W>) { + // do nothing + } +} impl Cache { pub fn new() -> Self { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 01dc7f51e29..aea4684e526 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -243,6 +243,19 @@ impl<'tcx> Mir<'tcx> { } } +impl_stable_hash_for!(struct Mir<'tcx> { + basic_blocks, + visibility_scopes, + promoted, + return_ty, + local_decls, + arg_count, + upvar_decls, + spread_arg, + span, + cache +}); + impl<'tcx> Index<BasicBlock> for Mir<'tcx> { type Output = BasicBlockData<'tcx>; @@ -830,6 +843,11 @@ pub struct Static<'tcx> { pub ty: Ty<'tcx>, } +impl_stable_hash_for!(struct Static<'tcx> { + def_id, + ty +}); + /// The `Projection` data structure defines things of the form `B.x` /// or `*B` or `B[index]`. Note that it is parameterized because it is /// shared between `Constant` and `Lvalue`. See the aliases diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 123db6e8947..571ef30b6b9 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -267,7 +267,7 @@ impl Size { /// Alignment of a type in bytes, both ABI-mandated and preferred. /// Since alignments are always powers of 2, we can pack both in one byte, -/// giving each a nibble (4 bits) for a maximum alignment of 2^15 = 32768. +/// giving each a nibble (4 bits) for a maximum alignment of 2<sup>15</sup> = 32768. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Align { raw: u8 diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 4a183191cef..823bdc9e092 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -15,6 +15,7 @@ use middle::privacy::AccessLevels; use mir; use session::CompileResult; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use util::nodemap::NodeSet; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; @@ -209,6 +210,11 @@ impl<'tcx> QueryDescription for queries::typeck_item_bodies<'tcx> { } } +impl<'tcx> QueryDescription for queries::reachable_set<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("reachability") + } +} macro_rules! define_maps { (<$tcx:tt> @@ -440,6 +446,8 @@ define_maps! { <'tcx> /// Performs the privacy check and computes "access levels". pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>, + pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet, + pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>> } @@ -451,6 +459,10 @@ fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> { DepNode::Coherence } +fn reachability_dep_node(_: CrateNum) -> DepNode<DefId> { + DepNode::Reachability +} + fn mir_shim(instance: ty::InstanceDef) -> DepNode<DefId> { instance.dep_node() } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6a4e7db21dd..3c529a69820 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -19,6 +19,7 @@ use dep_graph::{self, DepNode}; use hir::{map as hir_map, FreevarMap, TraitMap}; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; +use ich::StableHashingContext; use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::privacy::AccessLevels; @@ -50,6 +51,8 @@ use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; use hir; use hir::itemlikevisit::ItemLikeVisitor; @@ -1379,6 +1382,25 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {} + +impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for AdtDef { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher<W>) { + let ty::AdtDef { + did, + ref variants, + ref flags, + ref repr, + } = *self; + + did.hash_stable(hcx, hasher); + variants.hash_stable(hcx, hasher); + flags.hash_stable(hcx, hasher); + repr.hash_stable(hcx, hasher); + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } @@ -1391,6 +1413,13 @@ pub struct ReprOptions { pub int: Option<attr::IntType>, } +impl_stable_hash_for!(struct ReprOptions { + c, + packed, + simd, + int +}); + impl ReprOptions { pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { let mut ret = ReprOptions::default(); diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c5d577ce571..54f5cff16ed 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -490,6 +490,17 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, _ => span_bug!(e.span, "typeck error"), }) } + (Char(a), Char(b)) => { + Bool(match op.node { + hir::BiEq => a == b, + hir::BiNe => a != b, + hir::BiLt => a < b, + hir::BiLe => a <= b, + hir::BiGe => a >= b, + hir::BiGt => a > b, + _ => span_bug!(e.span, "typeck error"), + }) + } _ => signal!(e, MiscBinaryOp), } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 9ccd95dd8d8..c1735b4a4ec 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -37,6 +37,8 @@ #![feature(unsize)] #![feature(i128_type)] #![feature(conservative_impl_trait)] +#![feature(discriminant_value)] +#![feature(specialization)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 231c01c9ab7..dc412a0763e 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::hash::Hasher; +use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem; use blake2b::Blake2bHasher; @@ -174,3 +174,193 @@ impl<W> Hasher for StableHasher<W> { self.write_ileb128(i as i64); } } + + +/// Something that implements `HashStable<CTX>` can be hashed in a way that is +/// stable across multiple compiliation sessions. +pub trait HashStable<CTX> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut CTX, + hasher: &mut StableHasher<W>); +} + +// Implement HashStable by just calling `Hash::hash()`. This works fine for +// self-contained values that don't depend on the hashing context `CTX`. +macro_rules! impl_stable_hash_via_hash { + ($t:ty) => ( + impl<CTX> HashStable<CTX> for $t { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + _: &mut CTX, + hasher: &mut StableHasher<W>) { + ::std::hash::Hash::hash(self, hasher); + } + } + ); +} + +impl_stable_hash_via_hash!(i8); +impl_stable_hash_via_hash!(i16); +impl_stable_hash_via_hash!(i32); +impl_stable_hash_via_hash!(i64); +impl_stable_hash_via_hash!(isize); + +impl_stable_hash_via_hash!(u8); +impl_stable_hash_via_hash!(u16); +impl_stable_hash_via_hash!(u32); +impl_stable_hash_via_hash!(u64); +impl_stable_hash_via_hash!(usize); + +impl_stable_hash_via_hash!(u128); +impl_stable_hash_via_hash!(i128); + +impl_stable_hash_via_hash!(char); +impl_stable_hash_via_hash!(()); + +impl<CTX> HashStable<CTX> for f32 { + fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + let val: u32 = unsafe { + ::std::mem::transmute(*self) + }; + val.hash_stable(ctx, hasher); + } +} + +impl<CTX> HashStable<CTX> for f64 { + fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + let val: u64 = unsafe { + ::std::mem::transmute(*self) + }; + val.hash_stable(ctx, hasher); + } +} + +impl<T1: HashStable<CTX>, T2: HashStable<CTX>, CTX> HashStable<CTX> for (T1, T2) { + fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + self.0.hash_stable(ctx, hasher); + self.1.hash_stable(ctx, hasher); + } +} + +impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] { + default fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + self.len().hash_stable(ctx, hasher); + for item in self { + item.hash_stable(ctx, hasher); + } + } +} + +impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + (&self[..]).hash_stable(ctx, hasher); + } +} + +impl<CTX> HashStable<CTX> for str { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + _: &mut CTX, + hasher: &mut StableHasher<W>) { + self.len().hash(hasher); + self.as_bytes().hash(hasher); + } +} + +impl<CTX> HashStable<CTX> for bool { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher); + } +} + + +impl<T, CTX> HashStable<CTX> for Option<T> + where T: HashStable<CTX> +{ + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + if let Some(ref value) = *self { + 1u8.hash_stable(ctx, hasher); + value.hash_stable(ctx, hasher); + } else { + 0u8.hash_stable(ctx, hasher); + } + } +} + +impl<'a, T, CTX> HashStable<CTX> for &'a T + where T: HashStable<CTX> +{ + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + (**self).hash_stable(ctx, hasher); + } +} + +impl<T, CTX> HashStable<CTX> for ::std::mem::Discriminant<T> { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + _: &mut CTX, + hasher: &mut StableHasher<W>) { + ::std::hash::Hash::hash(self, hasher); + } +} + +impl<K, V, CTX> HashStable<CTX> for ::std::collections::BTreeMap<K, V> + where K: Ord + HashStable<CTX>, + V: HashStable<CTX>, +{ + fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + self.len().hash_stable(ctx, hasher); + for (k, v) in self { + k.hash_stable(ctx, hasher); + v.hash_stable(ctx, hasher); + } + } +} + +impl<T, CTX> HashStable<CTX> for ::std::collections::BTreeSet<T> + where T: Ord + HashStable<CTX>, +{ + fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + self.len().hash_stable(ctx, hasher); + for v in self { + v.hash_stable(ctx, hasher); + } + } +} + +impl<I: ::indexed_vec::Idx, T, CTX> HashStable<CTX> for ::indexed_vec::IndexVec<I, T> + where T: HashStable<CTX>, +{ + fn hash_stable<W: StableHasherResult>(&self, + ctx: &mut CTX, + hasher: &mut StableHasher<W>) { + self.len().hash_stable(ctx, hasher); + for v in &self.raw { + v.hash_stable(ctx, hasher); + } + } +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 977382b33ad..0fb386341a9 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -889,6 +889,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, rustc_privacy::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); + reachable::provide(&mut local_providers); let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); @@ -1358,10 +1359,9 @@ pub fn build_output_filenames(input: &Input, .values() .filter(|a| a.is_none()) .count(); - let ofile = if unnamed_output_types > 1 && - sess.opts.output_types.contains_key(&OutputType::Exe) { - sess.warn("ignoring specified output filename for 'link' output because multiple \ - outputs were requested"); + let ofile = if unnamed_output_types > 1 { + sess.warn("due to multiple output types requested, the explicitly specified \ + output file name will be adapted for each output type"); None } else { Some(out_file.clone()) diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index c9496a4deb8..c80a5a16277 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -27,24 +27,17 @@ //! at the end of compilation would be different from those computed //! at the beginning. -use syntax::ast; use std::cell::RefCell; use std::hash::Hash; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::hir::intravisit as visit; -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; -use rustc::ich::{Fingerprint, DefPathHashes, CachingCodemapView}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::ich::{Fingerprint, StableHashingContext}; use rustc::ty::TyCtxt; -use rustc_data_structures::stable_hasher::StableHasher; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use rustc_data_structures::fx::FxHashMap; use rustc::util::common::record_time; -use rustc::session::config::DebugInfoLevel::NoDebugInfo; - -use self::svh_visitor::StrictVersionHashVisitor; - -mod svh_visitor; pub type IchHasher = StableHasher<Fingerprint>; @@ -94,91 +87,42 @@ impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap { } } - -pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> IncrementalHashesMap { - let _ignore = tcx.dep_graph.in_ignore(); - let krate = tcx.hir.krate(); - let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo; - let mut visitor = HashItemsVisitor { - tcx: tcx, - hashes: IncrementalHashesMap::new(), - def_path_hashes: DefPathHashes::new(tcx), - codemap: CachingCodemapView::new(tcx), - hash_spans: hash_spans, - }; - record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { - visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| { - v.hash_crate_root_module(krate); - }); - krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); - - for macro_def in krate.exported_macros.iter() { - visitor.calculate_node_id(macro_def.id, - |v| v.visit_macro_def(macro_def)); - } - }); - - tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); - - record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); - visitor.hashes -} - -struct HashItemsVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_path_hashes: DefPathHashes<'a, 'tcx>, - codemap: CachingCodemapView<'tcx>, +struct ComputeItemHashesVisitor<'a, 'tcx: 'a> { + hcx: StableHashingContext<'a, 'tcx>, hashes: IncrementalHashesMap, - hash_spans: bool, } -impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { - fn calculate_node_id<W>(&mut self, id: ast::NodeId, walk_op: W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) - { - let def_id = self.tcx.hir.local_def_id(id); - self.calculate_def_id(def_id, walk_op) - } - - fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) +impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { + fn compute_and_store_ich_for_item_like<T>(&mut self, + dep_node: DepNode<DefId>, + hash_bodies: bool, + item_like: T) + where T: HashStable<StableHashingContext<'a, 'tcx>> { - assert!(def_id.is_local()); - debug!("HashItemsVisitor::calculate(def_id={:?})", def_id); - self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op); - self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op); - } + let mut hasher = IchHasher::new(); + self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| { + item_like.hash_stable(hcx, &mut hasher); + }); - fn calculate_def_hash<W>(&mut self, - dep_node: DepNode<DefId>, - hash_bodies: bool, - walk_op: &mut W) - where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>) - { - let mut state = IchHasher::new(); - walk_op(&mut StrictVersionHashVisitor::new(&mut state, - self.tcx, - &mut self.def_path_hashes, - &mut self.codemap, - self.hash_spans, - hash_bodies)); - let bytes_hashed = state.bytes_hashed(); - let item_hash = state.finish(); + let bytes_hashed = hasher.bytes_hashed(); + let item_hash = hasher.finish(); debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash); self.hashes.insert(dep_node, item_hash); - let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + + let tcx = self.hcx.tcx(); + let bytes_hashed = + tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + bytes_hashed; - self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed); + tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed); } fn compute_crate_hash(&mut self) { - let krate = self.tcx.hir.krate(); + let tcx = self.hcx.tcx(); + let krate = tcx.hir.krate(); let mut crate_state = IchHasher::new(); - let crate_disambiguator = self.tcx.sess.local_crate_disambiguator(); + let crate_disambiguator = tcx.sess.local_crate_disambiguator(); "crate_disambiguator".hash(&mut crate_state); crate_disambiguator.as_str().len().hash(&mut crate_state); crate_disambiguator.as_str().hash(&mut crate_state); @@ -186,7 +130,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { // add each item (in some deterministic order) to the overall // crate hash. { - let def_path_hashes = &mut self.def_path_hashes; + let hcx = &mut self.hcx; let mut item_hashes: Vec<_> = self.hashes.iter() .map(|(item_dep_node, &item_hash)| { @@ -194,7 +138,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { // DepNode<u64> where the u64 is the // hash of the def-id's def-path: let item_dep_node = - item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did))) + item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did))) .unwrap(); (item_dep_node, item_hash) }) @@ -203,40 +147,85 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { item_hashes.hash(&mut crate_state); } - { - let mut visitor = StrictVersionHashVisitor::new(&mut crate_state, - self.tcx, - &mut self.def_path_hashes, - &mut self.codemap, - self.hash_spans, - false); - visitor.hash_attributes(&krate.attrs); - } + krate.attrs.hash_stable(&mut self.hcx, &mut crate_state); let crate_hash = crate_state.finish(); self.hashes.insert(DepNode::Krate, crate_hash); debug!("calculate_crate_hash: crate_hash={:?}", crate_hash); } -} - -impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None + fn hash_crate_root_module(&mut self, krate: &'tcx hir::Crate) { + let hir::Crate { + ref module, + // Crate attributes are not copied over to the root `Mod`, so hash + // them explicitly here. + ref attrs, + span, + + // These fields are handled separately: + exported_macros: _, + items: _, + trait_items: _, + impl_items: _, + bodies: _, + trait_impls: _, + trait_default_impl: _, + body_ids: _, + } = *krate; + + let def_id = DefId::local(CRATE_DEF_INDEX); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), + false, + (module, (span, attrs))); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), + true, + (module, (span, attrs))); } +} +impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - self.calculate_node_id(item.id, |v| v.visit_item(item)); - visit::walk_item(self, item); + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } - fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item)); - visit::walk_trait_item(self, trait_item); + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) { + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } - fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item)); - visit::walk_impl_item(self, impl_item); + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) { + let def_id = self.hcx.tcx().hir.local_def_id(item.id); + self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); + self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); } } + +pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> IncrementalHashesMap { + let _ignore = tcx.dep_graph.in_ignore(); + let krate = tcx.hir.krate(); + + let mut visitor = ComputeItemHashesVisitor { + hcx: StableHashingContext::new(tcx), + hashes: IncrementalHashesMap::new(), + }; + + record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { + visitor.hash_crate_root_module(krate); + krate.visit_all_item_likes(&mut visitor); + + for macro_def in krate.exported_macros.iter() { + let def_id = tcx.hir.local_def_id(macro_def.id); + visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def); + visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def); + } + }); + + tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64); + + record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); + visitor.hashes +} diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs deleted file mode 100644 index 4700b77be07..00000000000 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ /dev/null @@ -1,1113 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use self::SawExprComponent::*; -use self::SawAbiComponent::*; -use self::SawItemComponent::*; -use self::SawPatComponent::*; -use self::SawTyComponent::*; -use self::SawTraitOrImplItemComponent::*; -use syntax::abi::Abi; -use syntax::ast::{self, Name, NodeId}; -use syntax::attr; -use syntax::ext::hygiene::SyntaxContext; -use syntax::parse::token; -use syntax::symbol::InternedString; -use syntax_pos::{Span, BytePos}; -use syntax::tokenstream; -use rustc::hir; -use rustc::hir::*; -use rustc::hir::def::Def; -use rustc::hir::def_id::DefId; -use rustc::hir::intravisit::{self as visit, Visitor}; -use rustc::ich::{DefPathHashes, CachingCodemapView, IGNORED_ATTRIBUTES}; -use rustc::ty::TyCtxt; -use std::hash::{Hash, Hasher}; - -use super::IchHasher; - -pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { - pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, - pub st: &'a mut IchHasher, - // collect a deterministic hash of def-ids that we have seen - def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, - hash_spans: bool, - codemap: &'a mut CachingCodemapView<'tcx>, - overflow_checks_enabled: bool, - hash_bodies: bool, -} - -impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { - pub fn new(st: &'a mut IchHasher, - tcx: TyCtxt<'hash, 'tcx, 'tcx>, - def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, - codemap: &'a mut CachingCodemapView<'tcx>, - hash_spans: bool, - hash_bodies: bool) - -> Self { - let check_overflow = tcx.sess.overflow_checks(); - - StrictVersionHashVisitor { - st: st, - tcx: tcx, - def_path_hashes: def_path_hashes, - hash_spans: hash_spans, - codemap: codemap, - overflow_checks_enabled: check_overflow, - hash_bodies: hash_bodies, - } - } - - fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 { - self.def_path_hashes.hash(def_id) - } - - // Hash a span in a stable way. We can't directly hash the span's BytePos - // fields (that would be similar to hashing pointers, since those are just - // offsets into the CodeMap). Instead, we hash the (file name, line, column) - // triple, which stays the same even if the containing FileMap has moved - // 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); - - // If this is not an empty or invalid span, we want to hash the last - // position that belongs to it, as opposed to hashing the first - // position past it. - let span_hi = if span.hi > span.lo { - // We might end up in the middle of a multibyte character here, - // but that's OK, since we are not trying to decode anything at - // this position. - span.hi - BytePos(1) - } else { - span.hi - }; - - let expn_kind = if span.ctxt == SyntaxContext::empty() { - SawSpanExpnKind::NoExpansion - } else { - SawSpanExpnKind::SomeExpansion - }; - - 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))); - - 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 { - self.hash_span(span.source_callsite()); - } - } - - fn hash_discriminant<T>(&mut self, v: &T) { - unsafe { - let disr = ::std::intrinsics::discriminant_value(v); - debug!("hash_discriminant: disr={}, st={:?}", disr, self.st); - disr.hash(self.st); - } - } -} - -// To off-load the bulk of the hash-computation on #[derive(Hash)], -// we define a set of enums corresponding to the content that our -// crate visitor will encounter as it traverses the ast. -// -// The important invariant is that all of the Saw*Component enums -// do not carry any Spans, Names, or Idents. -// -// Not carrying any Names/Idents is the important fix for problem -// noted on PR #13948: using the ident.name as the basis for a -// hash leads to unstable SVH, because ident.name is just an index -// into intern table (i.e. essentially a random address), not -// computed from the name content. -// -// With the below enums, the SVH computation is not sensitive to -// artifacts of how rustc was invoked nor of how the source code -// was laid out. (Or at least it is *less* sensitive.) - -// This enum represents the different potential bits of code the -// visitor could encounter that could affect the ABI for the crate, -// and assigns each a distinct tag to feed into the hash computation. -#[derive(Hash)] -enum SawAbiComponent<'a> { - - // FIXME (#14132): should we include (some function of) - // ident.ctxt as well? - SawIdent(InternedString), - SawStructDef(InternedString), - - SawLifetime, - SawLifetimeDef(usize), - - SawMod, - SawForeignItem(SawForeignItemComponent), - SawItem(SawItemComponent), - SawTy(SawTyComponent), - SawFnDecl(bool), - SawGenerics, - SawTraitItem(SawTraitOrImplItemComponent), - SawImplItem(SawTraitOrImplItemComponent), - SawStructField, - SawVariant(bool), - SawQPath, - SawPathSegment, - SawPathParameters, - SawBlock, - SawPat(SawPatComponent), - SawLocal, - SawArm, - SawExpr(SawExprComponent<'a>), - SawStmt, - SawVis, - SawAssociatedItemKind(hir::AssociatedItemKind), - SawDefaultness(hir::Defaultness), - SawWherePredicate, - SawTyParamBound, - SawPolyTraitRef, - SawAssocTypeBinding, - SawAttribute(ast::AttrStyle), - SawMacroDef, - 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 -/// to include in the hash that *won't* be covered by the -/// subsequent recursive traversal of the expression's -/// substructure by the visitor. -/// -/// We know every Expr_ variant is covered by a variant because -/// `fn saw_expr` maps each to some case below. Ensuring that -/// each variant carries an appropriate payload has to be verified -/// by hand. -/// -/// (However, getting that *exactly* right is not so important -/// because the SVH is just a developer convenience; there is no -/// guarantee of collision-freedom, hash collisions are just -/// (hopefully) unlikely.) -/// -/// The xxxComponent enums and saw_xxx functions for Item, Pat, -/// Ty, TraitItem and ImplItem follow the same methodology. -#[derive(Hash)] -enum SawExprComponent<'a> { - - SawExprLoop(Option<InternedString>), - SawExprField(InternedString), - SawExprTupField(usize), - SawExprBreak(Option<InternedString>), - SawExprAgain(Option<InternedString>), - - SawExprBox, - SawExprArray, - SawExprCall, - SawExprMethodCall, - SawExprTup, - SawExprBinary(hir::BinOp_), - SawExprUnary(hir::UnOp), - SawExprLit(ast::LitKind), - SawExprLitStr(InternedString, ast::StrStyle), - SawExprLitFloat(InternedString, Option<ast::FloatTy>), - SawExprCast, - SawExprType, - SawExprIf, - SawExprWhile, - SawExprMatch, - SawExprClosure(CaptureClause), - SawExprBlock, - SawExprAssign, - SawExprAssignOp(hir::BinOp_), - SawExprIndex, - SawExprPath, - SawExprAddrOf(hir::Mutability), - SawExprRet, - SawExprInlineAsm(StableInlineAsm<'a>), - SawExprStruct, - SawExprRepeat, -} - -// The boolean returned indicates whether the span of this expression is always -// significant, regardless of debuginfo. -fn saw_expr<'a>(node: &'a Expr_, - overflow_checks_enabled: bool) - -> (SawExprComponent<'a>, bool) { - let binop_can_panic_at_runtime = |binop| { - match binop { - BiAdd | - BiSub | - BiMul => overflow_checks_enabled, - - BiDiv | - BiRem => true, - - BiAnd | - BiOr | - BiBitXor | - BiBitAnd | - BiBitOr | - BiShl | - BiShr | - BiEq | - BiLt | - BiLe | - BiNe | - BiGe | - BiGt => false - } - }; - - let unop_can_panic_at_runtime = |unop| { - match unop { - UnDeref | - UnNot => false, - UnNeg => overflow_checks_enabled, - } - }; - - match *node { - ExprBox(..) => (SawExprBox, false), - ExprArray(..) => (SawExprArray, false), - ExprCall(..) => (SawExprCall, false), - ExprMethodCall(..) => (SawExprMethodCall, false), - ExprTup(..) => (SawExprTup, false), - ExprBinary(op, ..) => { - (SawExprBinary(op.node), binop_can_panic_at_runtime(op.node)) - } - ExprUnary(op, _) => { - (SawExprUnary(op), unop_can_panic_at_runtime(op)) - } - ExprLit(ref lit) => (saw_lit(lit), false), - ExprCast(..) => (SawExprCast, false), - ExprType(..) => (SawExprType, false), - ExprIf(..) => (SawExprIf, false), - ExprWhile(..) => (SawExprWhile, false), - ExprLoop(_, id, _) => (SawExprLoop(id.map(|id| id.node.as_str())), false), - ExprMatch(..) => (SawExprMatch, false), - ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false), - ExprBlock(..) => (SawExprBlock, false), - ExprAssign(..) => (SawExprAssign, false), - ExprAssignOp(op, ..) => { - (SawExprAssignOp(op.node), binop_can_panic_at_runtime(op.node)) - } - ExprField(_, name) => (SawExprField(name.node.as_str()), false), - ExprTupField(_, id) => (SawExprTupField(id.node), false), - ExprIndex(..) => (SawExprIndex, true), - ExprPath(_) => (SawExprPath, false), - ExprAddrOf(m, _) => (SawExprAddrOf(m), false), - ExprBreak(label, _) => (SawExprBreak(label.ident.map(|i| - i.node.name.as_str())), false), - ExprAgain(label) => (SawExprAgain(label.ident.map(|i| - i.node.name.as_str())), false), - ExprRet(..) => (SawExprRet, false), - ExprInlineAsm(ref a,..) => (SawExprInlineAsm(StableInlineAsm(a)), false), - ExprStruct(..) => (SawExprStruct, false), - ExprRepeat(..) => (SawExprRepeat, false), - } -} - -fn saw_lit(lit: &ast::Lit) -> SawExprComponent<'static> { - match lit.node { - ast::LitKind::Str(s, style) => SawExprLitStr(s.as_str(), style), - ast::LitKind::Float(s, ty) => SawExprLitFloat(s.as_str(), Some(ty)), - ast::LitKind::FloatUnsuffixed(s) => SawExprLitFloat(s.as_str(), None), - ref node @ _ => SawExprLit(node.clone()), - } -} - -#[derive(Hash)] -enum SawItemComponent { - SawItemExternCrate, - SawItemUse(UseKind), - SawItemStatic(Mutability), - SawItemConst, - SawItemFn(Unsafety, Constness, Abi), - SawItemMod, - SawItemForeignMod(Abi), - SawItemTy, - SawItemEnum, - SawItemStruct, - SawItemUnion, - SawItemTrait(Unsafety), - SawItemDefaultImpl(Unsafety), - SawItemImpl(Unsafety, ImplPolarity) -} - -fn saw_item(node: &Item_) -> SawItemComponent { - match *node { - ItemExternCrate(..) => SawItemExternCrate, - ItemUse(_, kind) => SawItemUse(kind), - ItemStatic(_, mutability, _) => SawItemStatic(mutability), - ItemConst(..) =>SawItemConst, - ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi), - ItemMod(..) => SawItemMod, - ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi), - ItemTy(..) => SawItemTy, - ItemEnum(..) => SawItemEnum, - ItemStruct(..) => SawItemStruct, - ItemUnion(..) => SawItemUnion, - ItemTrait(unsafety, ..) => SawItemTrait(unsafety), - ItemDefaultImpl(unsafety, _) => SawItemDefaultImpl(unsafety), - ItemImpl(unsafety, implpolarity, ..) => SawItemImpl(unsafety, implpolarity) - } -} - -#[derive(Hash)] -enum SawForeignItemComponent { - Static { mutable: bool }, - Fn, -} - -#[derive(Hash)] -enum SawPatComponent { - SawPatWild, - SawPatBinding(BindingMode), - SawPatStruct, - SawPatTupleStruct, - SawPatPath, - SawPatTuple, - SawPatBox, - SawPatRef(Mutability), - SawPatLit, - SawPatRange, - SawPatSlice -} - -fn saw_pat(node: &PatKind) -> SawPatComponent { - match *node { - PatKind::Wild => SawPatWild, - PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode), - PatKind::Struct(..) => SawPatStruct, - PatKind::TupleStruct(..) => SawPatTupleStruct, - PatKind::Path(_) => SawPatPath, - PatKind::Tuple(..) => SawPatTuple, - PatKind::Box(..) => SawPatBox, - PatKind::Ref(_, mutability) => SawPatRef(mutability), - PatKind::Lit(..) => SawPatLit, - PatKind::Range(..) => SawPatRange, - PatKind::Slice(..) => SawPatSlice - } -} - -#[derive(Hash)] -enum SawTyComponent { - SawTySlice, - SawTyArray, - SawTyPtr(Mutability), - SawTyRptr(Mutability), - SawTyBareFn(Unsafety, Abi), - SawTyNever, - SawTyTup, - SawTyPath, - SawTyObjectSum, - SawTyImplTrait, - SawTyTypeof, - SawTyInfer, - SawTyErr, -} - -fn saw_ty(node: &Ty_) -> SawTyComponent { - match *node { - TySlice(..) => SawTySlice, - TyArray(..) => SawTyArray, - TyPtr(ref mty) => SawTyPtr(mty.mutbl), - TyRptr(_, ref mty) => SawTyRptr(mty.mutbl), - TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi), - TyNever => SawTyNever, - TyTup(..) => SawTyTup, - TyPath(_) => SawTyPath, - TyTraitObject(..) => SawTyObjectSum, - TyImplTrait(..) => SawTyImplTrait, - TyTypeof(..) => SawTyTypeof, - TyInfer => SawTyInfer, - TyErr => SawTyErr, - } -} - -#[derive(Hash)] -enum SawTraitOrImplItemComponent { - SawTraitOrImplItemConst, - // The boolean signifies whether a body is present - SawTraitOrImplItemMethod(Unsafety, Constness, Abi, bool), - SawTraitOrImplItemType -} - -fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent { - match *ti { - TraitItemKind::Const(..) => SawTraitOrImplItemConst, - TraitItemKind::Method(ref sig, TraitMethod::Required(_)) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false), - TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true), - TraitItemKind::Type(..) => SawTraitOrImplItemType - } -} - -fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent { - match *ii { - ImplItemKind::Const(..) => SawTraitOrImplItemConst, - ImplItemKind::Method(ref sig, _) => - SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true), - ImplItemKind::Type(..) => SawTraitOrImplItemType - } -} - -#[derive(Clone, Copy, Hash, Eq, PartialEq)] -enum SawSpanExpnKind { - NoExpansion, - SomeExpansion, -} - -/// A wrapper that provides a stable Hash implementation. -struct StableInlineAsm<'a>(&'a InlineAsm); - -impl<'a> Hash for StableInlineAsm<'a> { - fn hash<H: Hasher>(&self, state: &mut H) { - let InlineAsm { - asm, - asm_str_style, - ref outputs, - ref inputs, - ref clobbers, - volatile, - alignstack, - dialect, - ctxt: _, // This is used for error reporting - } = *self.0; - - asm.as_str().hash(state); - asm_str_style.hash(state); - outputs.len().hash(state); - for output in outputs { - let InlineAsmOutput { constraint, is_rw, is_indirect } = *output; - constraint.as_str().hash(state); - is_rw.hash(state); - is_indirect.hash(state); - } - inputs.len().hash(state); - for input in inputs { - input.as_str().hash(state); - } - clobbers.len().hash(state); - for clobber in clobbers { - clobber.as_str().hash(state); - } - volatile.hash(state); - alignstack.hash(state); - dialect.hash(state); - } -} - -macro_rules! hash_attrs { - ($visitor:expr, $attrs:expr) => ({ - let attrs = $attrs; - if attrs.len() > 0 { - $visitor.hash_attributes(attrs); - } - }) -} - -macro_rules! hash_span { - ($visitor:expr, $span:expr) => ({ - hash_span!($visitor, $span, false) - }); - ($visitor:expr, $span:expr, $force:expr) => ({ - if $force || $visitor.hash_spans { - $visitor.hash_span($span); - } - }); -} - -impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> { - if self.hash_bodies { - visit::NestedVisitorMap::OnlyBodies(&self.tcx.hir) - } else { - visit::NestedVisitorMap::None - } - } - - fn visit_variant_data(&mut self, - s: &'tcx VariantData, - name: Name, - _: &'tcx Generics, - _: NodeId, - span: Span) { - debug!("visit_variant_data: st={:?}", self.st); - SawStructDef(name.as_str()).hash(self.st); - hash_span!(self, span); - visit::walk_struct_def(self, s); - } - - fn visit_variant(&mut self, - v: &'tcx Variant, - g: &'tcx Generics, - item_id: NodeId) { - debug!("visit_variant: st={:?}", self.st); - SawVariant(v.node.disr_expr.is_some()).hash(self.st); - hash_attrs!(self, &v.node.attrs); - visit::walk_variant(self, v, g, item_id) - } - - fn visit_name(&mut self, span: Span, name: Name) { - debug!("visit_name: st={:?}", self.st); - SawIdent(name.as_str()).hash(self.st); - hash_span!(self, span); - } - - fn visit_lifetime(&mut self, l: &'tcx Lifetime) { - debug!("visit_lifetime: st={:?}", self.st); - SawLifetime.hash(self.st); - visit::walk_lifetime(self, l); - } - - fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) { - debug!("visit_lifetime_def: st={:?}", self.st); - SawLifetimeDef(l.bounds.len()).hash(self.st); - visit::walk_lifetime_def(self, l); - } - - fn visit_expr(&mut self, ex: &'tcx Expr) { - debug!("visit_expr: st={:?}", self.st); - let (saw_expr, force_span) = saw_expr(&ex.node, - self.overflow_checks_enabled); - SawExpr(saw_expr).hash(self.st); - // No need to explicitly hash the discriminant here, since we are - // implicitly hashing the discriminant of SawExprComponent. - hash_span!(self, ex.span, force_span); - hash_attrs!(self, &ex.attrs); - - // Always hash nested constant bodies (e.g. n in `[x; n]`). - let hash_bodies = self.hash_bodies; - self.hash_bodies = true; - visit::walk_expr(self, ex); - self.hash_bodies = hash_bodies; - } - - fn visit_stmt(&mut self, s: &'tcx Stmt) { - debug!("visit_stmt: st={:?}", self.st); - - // We don't want to modify the hash for decls, because - // they might be item decls (if they are local decls, - // we'll hash that fact in visit_local); but we do want to - // remember if this was a StmtExpr or StmtSemi (the later - // had an explicit semi-colon; this affects the typing - // rules). - match s.node { - StmtDecl(..) => (), - StmtExpr(..) => { - SawStmt.hash(self.st); - self.hash_discriminant(&s.node); - hash_span!(self, s.span); - } - StmtSemi(..) => { - SawStmt.hash(self.st); - self.hash_discriminant(&s.node); - hash_span!(self, s.span); - } - } - - visit::walk_stmt(self, s) - } - - fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) { - debug!("visit_foreign_item: st={:?}", self.st); - - match i.node { - ForeignItemFn(..) => { - SawForeignItem(SawForeignItemComponent::Fn) - } - ForeignItemStatic(_, mutable) => { - SawForeignItem(SawForeignItemComponent::Static { - mutable: mutable - }) - } - }.hash(self.st); - - hash_span!(self, i.span); - hash_attrs!(self, &i.attrs); - visit::walk_foreign_item(self, i) - } - - fn visit_item(&mut self, i: &'tcx Item) { - debug!("visit_item: {:?} st={:?}", i, self.st); - - self.maybe_enable_overflow_checks(&i.attrs); - - SawItem(saw_item(&i.node)).hash(self.st); - hash_span!(self, i.span); - hash_attrs!(self, &i.attrs); - visit::walk_item(self, i) - } - - fn visit_mod(&mut self, m: &'tcx Mod, span: Span, n: NodeId) { - debug!("visit_mod: st={:?}", self.st); - SawMod.hash(self.st); - hash_span!(self, span); - visit::walk_mod(self, m, n) - } - - fn visit_ty(&mut self, t: &'tcx Ty) { - debug!("visit_ty: st={:?}", self.st); - SawTy(saw_ty(&t.node)).hash(self.st); - hash_span!(self, t.span); - - // Always hash nested constant bodies (e.g. N in `[T; N]`). - let hash_bodies = self.hash_bodies; - self.hash_bodies = true; - visit::walk_ty(self, t); - self.hash_bodies = hash_bodies; - } - - fn visit_generics(&mut self, g: &'tcx Generics) { - debug!("visit_generics: st={:?}", self.st); - SawGenerics.hash(self.st); - visit::walk_generics(self, g) - } - - fn visit_fn_decl(&mut self, fd: &'tcx FnDecl) { - debug!("visit_fn_decl: st={:?}", self.st); - SawFnDecl(fd.variadic).hash(self.st); - visit::walk_fn_decl(self, fd) - } - - fn visit_trait_item(&mut self, ti: &'tcx TraitItem) { - debug!("visit_trait_item: st={:?}", self.st); - - self.maybe_enable_overflow_checks(&ti.attrs); - - SawTraitItem(saw_trait_item(&ti.node)).hash(self.st); - hash_span!(self, ti.span); - hash_attrs!(self, &ti.attrs); - visit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'tcx ImplItem) { - debug!("visit_impl_item: st={:?}", self.st); - - self.maybe_enable_overflow_checks(&ii.attrs); - - SawImplItem(saw_impl_item(&ii.node)).hash(self.st); - hash_span!(self, ii.span); - hash_attrs!(self, &ii.attrs); - visit::walk_impl_item(self, ii) - } - - fn visit_struct_field(&mut self, s: &'tcx StructField) { - debug!("visit_struct_field: st={:?}", self.st); - SawStructField.hash(self.st); - hash_span!(self, s.span); - hash_attrs!(self, &s.attrs); - visit::walk_struct_field(self, s) - } - - fn visit_qpath(&mut self, qpath: &'tcx QPath, id: NodeId, span: Span) { - debug!("visit_qpath: st={:?}", self.st); - SawQPath.hash(self.st); - self.hash_discriminant(qpath); - visit::walk_qpath(self, qpath, id, span) - } - - fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { - debug!("visit_path: st={:?}", self.st); - hash_span!(self, path.span); - visit::walk_path(self, path) - } - - fn visit_def_mention(&mut self, def: Def) { - self.hash_def(def); - } - - fn visit_block(&mut self, b: &'tcx Block) { - debug!("visit_block: st={:?}", self.st); - SawBlock.hash(self.st); - hash_span!(self, b.span); - visit::walk_block(self, b) - } - - fn visit_pat(&mut self, p: &'tcx Pat) { - debug!("visit_pat: st={:?}", self.st); - SawPat(saw_pat(&p.node)).hash(self.st); - hash_span!(self, p.span); - visit::walk_pat(self, p) - } - - fn visit_local(&mut self, l: &'tcx Local) { - debug!("visit_local: st={:?}", self.st); - SawLocal.hash(self.st); - hash_attrs!(self, &l.attrs); - visit::walk_local(self, l) - // No need to hash span, we are hashing all component spans - } - - fn visit_arm(&mut self, a: &'tcx Arm) { - debug!("visit_arm: st={:?}", self.st); - SawArm.hash(self.st); - hash_attrs!(self, &a.attrs); - visit::walk_arm(self, a) - } - - fn visit_id(&mut self, id: NodeId) { - debug!("visit_id: id={} st={:?}", id, self.st); - self.hash_resolve(id) - } - - fn visit_vis(&mut self, v: &'tcx Visibility) { - debug!("visit_vis: st={:?}", self.st); - SawVis.hash(self.st); - self.hash_discriminant(v); - visit::walk_vis(self, v) - } - - fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) { - debug!("visit_associated_item_kind: st={:?}", self.st); - SawAssociatedItemKind(*kind).hash(self.st); - visit::walk_associated_item_kind(self, kind); - } - - fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) { - debug!("visit_associated_item_kind: st={:?}", self.st); - SawDefaultness(*defaultness).hash(self.st); - visit::walk_defaultness(self, defaultness); - } - - fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) { - debug!("visit_where_predicate: st={:?}", self.st); - SawWherePredicate.hash(self.st); - self.hash_discriminant(predicate); - // Ignoring span. Any important nested components should be visited. - visit::walk_where_predicate(self, predicate) - } - - fn visit_ty_param_bound(&mut self, bounds: &'tcx TyParamBound) { - debug!("visit_ty_param_bound: st={:?}", self.st); - SawTyParamBound.hash(self.st); - self.hash_discriminant(bounds); - // The TraitBoundModifier in TraitTyParamBound will be hash in - // visit_poly_trait_ref() - visit::walk_ty_param_bound(self, bounds) - } - - fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) { - debug!("visit_poly_trait_ref: st={:?}", self.st); - SawPolyTraitRef.hash(self.st); - m.hash(self.st); - visit::walk_poly_trait_ref(self, t, m) - } - - fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx PathSegment) { - debug!("visit_path_segment: st={:?}", self.st); - SawPathSegment.hash(self.st); - visit::walk_path_segment(self, path_span, path_segment) - } - - fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'tcx PathParameters) { - debug!("visit_path_parameters: st={:?}", self.st); - SawPathParameters.hash(self.st); - self.hash_discriminant(path_parameters); - visit::walk_path_parameters(self, path_span, path_parameters) - } - - fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) { - debug!("visit_assoc_type_binding: st={:?}", self.st); - SawAssocTypeBinding.hash(self.st); - hash_span!(self, type_binding.span); - visit::walk_assoc_type_binding(self, type_binding) - } - - fn visit_attribute(&mut self, _: &ast::Attribute) { - // We explicitly do not use this method, since doing that would - // implicitly impose an order on the attributes being hashed, while we - // explicitly don't want their order to matter - } - - fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) { - debug!("visit_macro_def: st={:?}", self.st); - SawMacroDef.hash(self.st); - hash_attrs!(self, ¯o_def.attrs); - for tt in macro_def.body.trees() { - self.hash_token_tree(&tt); - } - visit::walk_macro_def(self, macro_def) - } -} - -#[derive(Hash)] -pub enum DefHash { - SawDefId, - SawLabel, - SawPrimTy, - SawSelfTy, - SawErr, -} - -impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { - fn hash_resolve(&mut self, id: ast::NodeId) { - // Because whether or not a given id has an entry is dependent - // solely on expr variant etc, we don't need to hash whether - // or not an entry was present (we are already hashing what - // variant it is above when we visit the HIR). - - if let Some(traits) = self.tcx.trait_map.get(&id) { - debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st); - traits.len().hash(self.st); - - // The ordering of the candidates is not fixed. So we hash - // the def-ids and then sort them and hash the collection. - let mut candidates: Vec<_> = - traits.iter() - .map(|&TraitCandidate { def_id, import_id: _ }| { - self.compute_def_id_hash(def_id) - }) - .collect(); - candidates.sort(); - candidates.hash(self.st); - } - } - - fn hash_def_id(&mut self, def_id: DefId) { - self.compute_def_id_hash(def_id).hash(self.st); - } - - fn hash_def(&mut self, def: Def) { - match def { - // Crucial point: for all of these variants, the variant + - // add'l data that is added is always the same if the - // def-id is the same, so it suffices to hash the def-id - Def::Fn(..) | - Def::Mod(..) | - Def::Static(..) | - Def::Variant(..) | - Def::VariantCtor(..) | - Def::Enum(..) | - Def::TyAlias(..) | - Def::AssociatedTy(..) | - Def::TyParam(..) | - Def::Struct(..) | - Def::StructCtor(..) | - Def::Union(..) | - Def::Trait(..) | - Def::Method(..) | - Def::Const(..) | - Def::AssociatedConst(..) | - Def::Local(..) | - Def::Upvar(..) | - Def::Macro(..) => { - DefHash::SawDefId.hash(self.st); - self.hash_def_id(def.def_id()); - } - - Def::Label(..) => { - DefHash::SawLabel.hash(self.st); - // we don't encode the `id` because it always refers to something - // within this item, so if it changed, there would have to be other - // changes too - } - Def::PrimTy(ref prim_ty) => { - DefHash::SawPrimTy.hash(self.st); - prim_ty.hash(self.st); - } - Def::SelfTy(..) => { - DefHash::SawSelfTy.hash(self.st); - // the meaning of Self is always the same within a - // given context, so we don't need to hash the other - // fields - } - Def::Err => { - DefHash::SawErr.hash(self.st); - } - } - } - - pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) { - debug!("hash_attributes: st={:?}", self.st); - let indices = self.indices_sorted_by(attributes, |attr| attr.name()); - - for i in indices { - let attr = &attributes[i]; - match attr.name() { - Some(name) if IGNORED_ATTRIBUTES.contains(&&*name.as_str()) => continue, - _ => {} - }; - if !attr.is_sugared_doc { - SawAttribute(attr.style).hash(self.st); - for segment in &attr.path.segments { - SawIdent(segment.identifier.name.as_str()).hash(self.st); - } - for tt in attr.tokens.trees() { - self.hash_token_tree(&tt); - } - } - } - } - - fn indices_sorted_by<T, K, F>(&mut self, items: &[T], get_key: F) -> Vec<usize> - where K: Ord, - F: Fn(&T) -> K - { - let mut indices = Vec::with_capacity(items.len()); - indices.extend(0 .. items.len()); - indices.sort_by_key(|index| get_key(&items[*index])); - indices - } - - fn maybe_enable_overflow_checks(&mut self, item_attrs: &[ast::Attribute]) { - if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") { - self.overflow_checks_enabled = true; - } - } - - fn hash_token_tree(&mut self, tt: &tokenstream::TokenTree) { - self.hash_discriminant(tt); - match *tt { - tokenstream::TokenTree::Token(span, ref token) => { - hash_span!(self, span); - self.hash_token(token, span); - } - tokenstream::TokenTree::Delimited(span, ref delimited) => { - hash_span!(self, span); - delimited.delim.hash(self.st); - for sub_tt in delimited.stream().trees() { - self.hash_token_tree(&sub_tt); - } - } - } - } - - fn hash_token(&mut self, - token: &token::Token, - error_reporting_span: Span) { - self.hash_discriminant(token); - match *token { - token::Token::Eq | - token::Token::Lt | - token::Token::Le | - token::Token::EqEq | - token::Token::Ne | - token::Token::Ge | - token::Token::Gt | - token::Token::AndAnd | - token::Token::OrOr | - token::Token::Not | - token::Token::Tilde | - token::Token::At | - token::Token::Dot | - token::Token::DotDot | - token::Token::DotDotDot | - token::Token::Comma | - token::Token::Semi | - token::Token::Colon | - token::Token::ModSep | - token::Token::RArrow | - token::Token::LArrow | - token::Token::FatArrow | - token::Token::Pound | - token::Token::Dollar | - token::Token::Question | - token::Token::Underscore | - token::Token::Whitespace | - token::Token::Comment | - token::Token::Eof => {} - - token::Token::BinOp(bin_op_token) | - token::Token::BinOpEq(bin_op_token) => bin_op_token.hash(self.st), - - token::Token::OpenDelim(delim_token) | - token::Token::CloseDelim(delim_token) => delim_token.hash(self.st), - - token::Token::Literal(ref lit, ref opt_name) => { - self.hash_discriminant(lit); - match *lit { - token::Lit::Byte(val) | - token::Lit::Char(val) | - token::Lit::Integer(val) | - token::Lit::Float(val) | - token::Lit::Str_(val) | - token::Lit::ByteStr(val) => val.as_str().hash(self.st), - token::Lit::StrRaw(val, n) | - token::Lit::ByteStrRaw(val, n) => { - val.as_str().hash(self.st); - n.hash(self.st); - } - }; - opt_name.map(ast::Name::as_str).hash(self.st); - } - - token::Token::Ident(ident) | - token::Token::Lifetime(ident) | - token::Token::SubstNt(ident) => ident.name.as_str().hash(self.st), - - token::Token::Interpolated(ref non_terminal) => { - // FIXME(mw): This could be implemented properly. It's just a - // lot of work, since we would need to hash the AST - // in a stable way, in addition to the HIR. - // Since this is hardly used anywhere, just emit a - // warning for now. - if self.tcx.sess.opts.debugging_opts.incremental.is_some() { - let msg = format!("Quasi-quoting might make incremental \ - compilation very inefficient: {:?}", - non_terminal); - self.tcx.sess.span_warn(error_reporting_span, &msg[..]); - } - - non_terminal.hash(self.st); - } - - token::Token::DocComment(val) | - token::Token::Shebang(val) => val.as_str().hash(self.st), - } - } - - pub fn hash_crate_root_module(&mut self, krate: &'tcx Crate) { - let hir::Crate { - ref module, - ref attrs, - span, - - // These fields are handled separately: - exported_macros: _, - items: _, - trait_items: _, - impl_items: _, - bodies: _, - trait_impls: _, - trait_default_impl: _, - body_ids: _, - } = *krate; - - visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID); - // Crate attributes are not copied over to the root `Mod`, so hash them - // explicitly here. - hash_attrs!(self, attrs); - } -} diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 477777c975d..d10df17f858 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -22,7 +22,6 @@ #![feature(rustc_private)] #![feature(staged_api)] #![feature(rand)] -#![feature(core_intrinsics)] #![feature(conservative_impl_trait)] #![cfg_attr(stage0, feature(pub_restricted))] diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 2b945e0a3af..7d5887e699f 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -259,4 +259,10 @@ fn main() { println!("cargo:rustc-link-lib={}", stdcppname); } } + + // LLVM requires symbols from this library, but apparently they're not printeds + // during llvm-config? + if target.contains("windows") { + println!("cargo:rustc-link-lib=ole32"); + } } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 26c7a9166e6..32c9183ece9 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -1662,10 +1662,3 @@ extern "C" { pub fn LLVMRustUnsetComdat(V: ValueRef); pub fn LLVMRustSetModulePIELevel(M: ModuleRef); } - - -// LLVM requires symbols from this library, but apparently they're not printed -// during llvm-config? -#[cfg(windows)] -#[link(name = "ole32")] -extern "C" {} diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 71e97e4bfe0..c503b8c7fe0 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -25,6 +25,9 @@ impl<'tcx> CFG<'tcx> { &mut self.basic_blocks[blk] } + // llvm.org/PR32488 makes this function use an excess of stack space. Mark + // it as #[inline(never)] to keep rustc's stack use in check. + #[inline(never)] pub fn start_new_block(&mut self) -> BasicBlock { self.basic_blocks.push(BasicBlockData::new(None)) } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 05f30f039c8..966cb7ee8d8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -222,8 +222,10 @@ impl<'a> base::Resolver for Resolver<'a> { let name = unwrap_or!(attrs[i].name(), continue); if name == "derive" { - let result = attrs[i].parse_list(&self.session.parse_sess, - |parser| parser.parse_path(PathStyle::Mod)); + let result = attrs[i].parse_list(&self.session.parse_sess, |parser| { + parser.parse_path_allowing_meta(PathStyle::Mod) + }); + let mut traits = match result { Ok(traits) => traits, Err(mut e) => { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f2aa89ba4b6..3fd0ce45e36 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1149,8 +1149,32 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &trait_item.attrs, trait_item.span); } - ast::TraitItemKind::Const(_, None) | - ast::TraitItemKind::Type(..) | + ast::TraitItemKind::Type(ref _bounds, ref default_ty) => { + // FIXME do something with _bounds (for type refs) + let name = trait_item.ident.name.to_string(); + let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id)); + let sub_span = self.span.sub_span_after_keyword(trait_item.span, keywords::Type); + + if !self.span.filter_generated(sub_span, trait_item.span) { + self.dumper.typedef(TypeDefData { + span: sub_span.expect("No span found for assoc type"), + name: name, + id: trait_item.id, + qualname: qualname, + value: self.span.snippet(trait_item.span), + visibility: Visibility::Public, + parent: Some(trait_id), + docs: docs_for_attrs(&trait_item.attrs), + sig: None, + attributes: trait_item.attrs.clone(), + }.lower(self.tcx)); + } + + if let &Some(ref default_ty) = default_ty { + self.visit_ty(default_ty) + } + } + ast::TraitItemKind::Const(ref ty, None) => self.visit_ty(ty), ast::TraitItemKind::Macro(_) => {} } } @@ -1177,7 +1201,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &impl_item.attrs, impl_item.span); } - ast::ImplItemKind::Type(_) | + ast::ImplItemKind::Type(ref ty) => self.visit_ty(ty), ast::ImplItemKind::Macro(_) => {} } } @@ -1377,15 +1401,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, debug!("visit_expr {:?}", ex.node); self.process_macro_use(ex.span, ex.id); match ex.node { - ast::ExprKind::Call(ref _f, ref _args) => { - // Don't need to do anything for function calls, - // because just walking the callee path does what we want. - visit::walk_expr(self, ex); - } - ast::ExprKind::Path(_, ref path) => { - self.process_path(ex.id, path, None); - visit::walk_expr(self, ex); - } ast::ExprKind::Struct(ref path, ref fields, ref base) => { let hir_expr = self.save_ctxt.tcx.hir.expect_expr(ex.id); let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) { @@ -1483,6 +1498,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, self.visit_expr(element); self.nest_tables(count.id, |v| v.visit_expr(count)); } + // In particular, we take this branch for call and path expressions, + // where we'll index the idents involved just by continuing to walk. _ => { visit::walk_expr(self, ex) } @@ -1582,4 +1599,39 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, walk_list!(self, visit_ty, &l.ty); walk_list!(self, visit_expr, &l.init); } + + fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) { + match item.node { + ast::ForeignItemKind::Fn(ref decl, ref generics) => { + if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) { + down_cast_data!(fn_data, FunctionData, item.span); + if !self.span.filter_generated(Some(fn_data.span), item.span) { + self.dumper.function(fn_data.clone().lower(self.tcx)); + } + + self.nest_tables(item.id, |v| v.process_formals(&decl.inputs, + &fn_data.qualname)); + self.process_generic_params(generics, item.span, &fn_data.qualname, item.id); + } + + for arg in &decl.inputs { + self.visit_ty(&arg.ty); + } + + if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output { + self.visit_ty(&ret_ty); + } + } + ast::ForeignItemKind::Static(ref ty, _) => { + if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { + down_cast_data!(var_data, VariableData, item.span); + if !self.span.filter_generated(Some(var_data.span), item.span) { + self.dumper.variable(var_data.lower(self.tcx)); + } + } + + self.visit_ty(ty); + } + } + } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 1de9fbc8e49..44615071a56 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -120,6 +120,50 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result } + pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option<Data> { + let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + match item.node { + ast::ForeignItemKind::Fn(ref decl, ref generics) => { + let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); + filter!(self.span_utils, sub_span, item.span, None); + Some(Data::FunctionData(FunctionData { + id: item.id, + name: item.ident.to_string(), + qualname: qualname, + declaration: None, + span: sub_span.unwrap(), + scope: self.enclosing_scope(item.id), + value: make_signature(decl, generics), + visibility: From::from(&item.vis), + parent: None, + docs: docs_for_attrs(&item.attrs), + sig: self.sig_base_extern(item), + attributes: item.attrs.clone(), + })) + } + ast::ForeignItemKind::Static(ref ty, m) => { + let keyword = if m { keywords::Mut } else { keywords::Static }; + let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); + filter!(self.span_utils, sub_span, item.span, None); + Some(Data::VariableData(VariableData { + id: item.id, + kind: VariableKind::Static, + name: item.ident.to_string(), + qualname: qualname, + span: sub_span.unwrap(), + scope: self.enclosing_scope(item.id), + parent: None, + value: String::new(), + type_value: ty_to_string(ty), + visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), + sig: Some(self.sig_base_extern(item)), + attributes: item.attrs.clone(), + })) + } + } + } + pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> { match item.node { ast::ItemKind::Fn(ref decl, .., ref generics, _) => { @@ -751,6 +795,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } + fn sig_base_extern(&self, item: &ast::ForeignItem) -> Signature { + let text = self.span_utils.signature_string_for_span(item.span); + let name = item.ident.to_string(); + let ident_start = text.find(&name).expect("Name not in signature?"); + let ident_end = ident_start + name.len(); + Signature { + span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span }, + text: text, + ident_start: ident_start, + ident_end: ident_end, + defs: vec![], + refs: vec![], + } + } + #[inline] pub fn enclosing_scope(&self, id: NodeId) -> NodeId { self.tcx.hir.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID) diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index 8528482c785..63cfe591ce3 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -32,8 +32,7 @@ use syntax::ast; use {ModuleSource, ModuleTranslation}; -const PARTITION_REUSED: &'static str = "rustc_partition_reused"; -const PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; +use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED}; const MODULE: &'static str = "module"; const CFG: &'static str = "cfg"; @@ -62,9 +61,9 @@ struct AssertModuleSource<'a, 'tcx: 'a> { impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { fn check_attr(&self, attr: &ast::Attribute) { - let disposition = if attr.check_name(PARTITION_REUSED) { + let disposition = if attr.check_name(ATTR_PARTITION_REUSED) { Disposition::Reused - } else if attr.check_name(PARTITION_TRANSLATED) { + } else if attr.check_name(ATTR_PARTITION_TRANSLATED) { Disposition::Translated } else { return; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 6d17b2f0eed..12a1ffa2767 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -734,9 +734,10 @@ fn link_natively(sess: &Session, } { - let mut linker = trans.linker_info.to_linker(&mut cmd, &sess); + let mut linker = trans.linker_info.to_linker(cmd, &sess); link_args(&mut *linker, sess, crate_type, tmpdir, objects, out_filename, outputs, trans); + cmd = linker.finalize(); } cmd.args(&sess.target.target.options.late_link_args); for obj in &sess.target.target.options.post_link_objects { @@ -1021,38 +1022,18 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { } }); - let pair = sess.cstore.used_libraries().into_iter().filter(|l| { + let relevant_libs = sess.cstore.used_libraries().into_iter().filter(|l| { relevant_lib(sess, l) - }).partition(|lib| { - lib.kind == NativeLibraryKind::NativeStatic }); - let (staticlibs, others): (Vec<_>, Vec<_>) = pair; - - // Some platforms take hints about whether a library is static or dynamic. - // For those that support this, we ensure we pass the option if the library - // was flagged "static" (most defaults are dynamic) to ensure that if - // libfoo.a and libfoo.so both exist that the right one is chosen. - cmd.hint_static(); let search_path = archive_search_paths(sess); - for l in staticlibs { - // Here we explicitly ask that the entire archive is included into the - // result artifact. For more details see #15460, but the gist is that - // the linker will strip away any unused objects in the archive if we - // don't otherwise explicitly reference them. This can occur for - // libraries which are just providing bindings, libraries with generic - // functions, etc. - cmd.link_whole_staticlib(&l.name.as_str(), &search_path); - } - - cmd.hint_dynamic(); - - for lib in others { + for lib in relevant_libs { match lib.kind { NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()), - NativeLibraryKind::NativeStatic => bug!(), + NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(), + &search_path) } } } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 80801e8161c..a178d17a7c2 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx> LinkerInfo { } pub fn to_linker(&'a self, - cmd: &'a mut Command, + cmd: Command, sess: &'a Session) -> Box<Linker+'a> { if sess.target.target.options.is_like_msvc { Box::new(MsvcLinker { @@ -61,7 +61,8 @@ impl<'a, 'tcx> LinkerInfo { Box::new(GnuLinker { cmd: cmd, sess: sess, - info: self + info: self, + hinted_static: false, }) as Box<Linker> } } @@ -93,30 +94,49 @@ pub trait Linker { fn no_default_libraries(&mut self); fn build_dylib(&mut self, out_filename: &Path); fn args(&mut self, args: &[String]); - fn hint_static(&mut self); - fn hint_dynamic(&mut self); - 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); + // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?). + fn finalize(&mut self) -> Command; } pub struct GnuLinker<'a> { - cmd: &'a mut Command, + cmd: Command, sess: &'a Session, - info: &'a LinkerInfo + info: &'a LinkerInfo, + hinted_static: bool, // Keeps track of the current hinting mode. } impl<'a> GnuLinker<'a> { fn takes_hints(&self) -> bool { !self.sess.target.target.options.is_like_osx } + + // Some platforms take hints about whether a library is static or dynamic. + // For those that support this, we ensure we pass the option if the library + // was flagged "static" (most defaults are dynamic) to ensure that if + // libfoo.a and libfoo.so both exist that the right one is chosen. + fn hint_static(&mut self) { + if !self.takes_hints() { return } + if !self.hinted_static { + self.cmd.arg("-Wl,-Bstatic"); + self.hinted_static = true; + } + } + + fn hint_dynamic(&mut self) { + if !self.takes_hints() { return } + if self.hinted_static { + self.cmd.arg("-Wl,-Bdynamic"); + self.hinted_static = false; + } + } } impl<'a> Linker for GnuLinker<'a> { - fn link_dylib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); } - fn link_staticlib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); } - fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); } + fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); } + fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); } + fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); } fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); } fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); } @@ -125,14 +145,23 @@ impl<'a> Linker for GnuLinker<'a> { fn args(&mut self, args: &[String]) { self.cmd.args(args); } fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { + self.hint_dynamic(); self.cmd.arg("-l").arg(lib); } fn link_framework(&mut self, framework: &str) { + self.hint_dynamic(); self.cmd.arg("-framework").arg(framework); } + // Here we explicitly ask that the entire archive is included into the + // result artifact. For more details see #15460, but the gist is that + // the linker will strip away any unused objects in the archive if we + // don't otherwise explicitly reference them. This can occur for + // libraries which are just providing bindings, libraries with generic + // functions, etc. fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) { + self.hint_static(); let target = &self.sess.target.target; if !target.options.is_like_osx { self.cmd.arg("-Wl,--whole-archive") @@ -148,6 +177,7 @@ impl<'a> Linker for GnuLinker<'a> { } fn link_whole_rlib(&mut self, lib: &Path) { + self.hint_static(); if self.sess.target.target.options.is_like_osx { let mut v = OsString::from("-Wl,-force_load,"); v.push(lib); @@ -228,26 +258,6 @@ impl<'a> Linker for GnuLinker<'a> { } } - fn whole_archives(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,--whole-archive"); - } - - fn no_whole_archives(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,--no-whole-archive"); - } - - fn hint_static(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,-Bstatic"); - } - - fn hint_dynamic(&mut self) { - if !self.takes_hints() { return } - self.cmd.arg("-Wl,-Bdynamic"); - } - fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { // If we're compiling a dylib, then we let symbol visibility in object // files to take care of whether they're exported or not. @@ -311,10 +321,17 @@ impl<'a> Linker for GnuLinker<'a> { fn subsystem(&mut self, subsystem: &str) { self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem)); } + + fn finalize(&mut self) -> Command { + self.hint_dynamic(); // Reset to default before returning the composed command line. + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } } pub struct MsvcLinker<'a> { - cmd: &'a mut Command, + cmd: Command, sess: &'a Session, info: &'a LinkerInfo } @@ -416,22 +433,6 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/DEBUG"); } - fn whole_archives(&mut self) { - // hints not supported? - } - fn no_whole_archives(&mut self) { - // hints not supported? - } - - // On windows static libraries are of the form `foo.lib` and dynamic - // libraries are not linked against directly, but rather through their - // import libraries also called `foo.lib`. As a result there's no - // possibility for a native library to appear both dynamically and - // statically in the same folder so we don't have to worry about hints like - // we do on Unix platforms. - fn hint_static(&mut self) {} - fn hint_dynamic(&mut self) {} - // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to // export symbols from a dynamic library. When building a dynamic library, // however, we're going to want some symbols exported, so this function @@ -492,10 +493,16 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/ENTRY:mainCRTStartup"); } } + + fn finalize(&mut self) -> Command { + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } } pub struct EmLinker<'a> { - cmd: &'a mut Command, + cmd: Command, sess: &'a Session, info: &'a LinkerInfo } @@ -591,22 +598,6 @@ impl<'a> Linker for EmLinker<'a> { bug!("building dynamic library is unsupported on Emscripten") } - fn whole_archives(&mut self) { - // noop - } - - fn no_whole_archives(&mut self) { - // noop - } - - fn hint_static(&mut self) { - // noop - } - - fn hint_dynamic(&mut self) { - // noop - } - fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { let symbols = &self.info.exports[&crate_type]; @@ -640,6 +631,12 @@ impl<'a> Linker for EmLinker<'a> { fn subsystem(&mut self, _subsystem: &str) { // noop } + + fn finalize(&mut self) -> Command { + let mut cmd = Command::new(""); + ::std::mem::swap(&mut cmd, &mut self.cmd); + cmd + } } fn exported_symbols(scx: &SharedCrateContext, diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ec45c559363..d204703b775 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -50,7 +50,7 @@ use builder::Builder; use callee; use common::{C_bool, C_bytes_in_context, C_i32, C_uint}; use collector::{self, TransItemCollectionMode}; -use common::{C_struct_in_context, C_u64, C_undef}; +use common::{C_struct_in_context, C_u64, C_undef, C_array}; use common::CrateContext; use common::{type_is_zero_size, val_ty}; use common; @@ -1187,6 +1187,23 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + // Create the llvm.used variable + // This variable has type [N x i8*] and is stored in the llvm.metadata section + if !ccx.used_statics().borrow().is_empty() { + let name = CString::new("llvm.used").unwrap(); + let section = CString::new("llvm.metadata").unwrap(); + let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow()); + + unsafe { + let g = llvm::LLVMAddGlobal(ccx.llmod(), + val_ty(array).to_ref(), + name.as_ptr()); + llvm::LLVMSetInitializer(g, array); + llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); + llvm::LLVMSetSection(g, section.as_ptr()); + } + } + // Finalize debuginfo if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 0c3d211912a..daf1a1ba95f 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -276,6 +276,12 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::set_link_section(ccx, g, attrs); + if attr::contains_name(attrs, "used") { + // This static will be stored in the llvm.used variable which is an array of i8* + let cast = llvm::LLVMConstPointerCast(g, Type::i8p(ccx).to_ref()); + ccx.used_statics().borrow_mut().push(cast); + } + Ok(g) } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 73602dc420b..afb94f546ab 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -132,6 +132,10 @@ pub struct LocalCrateContext<'tcx> { /// to constants.) statics_to_rauw: RefCell<Vec<(ValueRef, ValueRef)>>, + /// Statics that will be placed in the llvm.used variable + /// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details + used_statics: RefCell<Vec<ValueRef>>, + lltypes: RefCell<FxHashMap<Ty<'tcx>, Type>>, llsizingtypes: RefCell<FxHashMap<Ty<'tcx>, Type>>, type_hashcodes: RefCell<FxHashMap<Ty<'tcx>, String>>, @@ -587,6 +591,7 @@ impl<'tcx> LocalCrateContext<'tcx> { impl_method_cache: RefCell::new(FxHashMap()), closure_bare_wrapper_cache: RefCell::new(FxHashMap()), statics_to_rauw: RefCell::new(Vec::new()), + used_statics: RefCell::new(Vec::new()), lltypes: RefCell::new(FxHashMap()), llsizingtypes: RefCell::new(FxHashMap()), type_hashcodes: RefCell::new(FxHashMap()), @@ -754,6 +759,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().statics_to_rauw } + pub fn used_statics<'a>(&'a self) -> &'a RefCell<Vec<ValueRef>> { + &self.local().used_statics + } + pub fn lltypes<'a>(&'a self) -> &'a RefCell<FxHashMap<Ty<'tcx>, Type>> { &self.local().lltypes } diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 226d40948c4..d69f31a4504 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -762,7 +762,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); let slot = bcx.alloca(llretty, "personalityslot"); self.llpersonalityslot = Some(slot); - Lifetime::Start.call(bcx, slot); slot } } @@ -794,6 +793,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.llfn); bcx.set_cleanup(llretval); let slot = self.get_personality_slot(&bcx); + Lifetime::Start.call(&bcx, slot); bcx.store(llretval, slot, None); bcx.br(target_bb); bcx.llbb() diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 67ee7ef5865..4b975d7b324 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -196,19 +196,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let field_ty = field.ty(tcx, substs); - if self.is_fn_ty(&field_ty, span) { - err.help(&format!("use `({0}.{1})(...)` if you \ - meant to call the function \ - stored in the `{1}` field", - expr_string, - item_name)); + if tcx.vis_is_accessible_from(field.vis, self.body_id) { + if self.is_fn_ty(&field_ty, span) { + err.help(&format!("use `({0}.{1})(...)` if you \ + meant to call the function \ + stored in the `{1}` field", + expr_string, + item_name)); + } else { + err.help(&format!("did you mean to write `{0}.{1}` \ + instead of `{0}.{1}(...)`?", + expr_string, + item_name)); + } + err.span_label(span, &"field, not a method"); } else { - err.help(&format!("did you mean to write `{0}.{1}` \ - instead of `{0}.{1}(...)`?", - expr_string, - item_name)); + err.span_label(span, &"private field, not a method"); } - err.span_label(span, &"field, not a method"); break; } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aaa3cf0f29e..c995b7e9284 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3884,7 +3884,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { element_ty } None => { - self.check_expr_has_type(&idx, self.tcx.types.err); let mut err = self.type_error_struct( expr.span, |actual| { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index f492ab12e3f..cc33bd8754d 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -184,9 +184,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // particularly for things like `String + &String`. let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); - let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], - Symbol::intern(name), trait_def_id, - lhs_expr) { + let return_ty = self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var], + Symbol::intern(name), trait_def_id, + lhs_expr); + + // see `NB` above + let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); + + let return_ty = match return_ty { Ok(return_ty) => return_ty, Err(()) => { // error types are considered "builtin" @@ -209,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty { if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) && - self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var], + self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty], Symbol::intern(name), trait_def_id, lhs_expr).is_ok() { err.note( @@ -240,7 +245,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(missing_trait) = missing_trait { if missing_trait == "std::ops::Add" && self.check_str_addition(expr, lhs_expr, lhs_ty, - rhs_expr, rhs_ty_var, &mut err) { + rhs_expr, rhs_ty, &mut err) { // This has nothing here because it means we did string // concatenation (e.g. "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted @@ -257,9 +262,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - // see `NB` above - self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); - (rhs_ty_var, return_ty) } @@ -268,12 +270,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, rhs_expr: &'gcx hir::Expr, - rhs_ty_var: Ty<'tcx>, + rhs_ty: Ty<'tcx>, mut err: &mut errors::DiagnosticBuilder) -> bool { // If this function returns true it means a note was printed, so we don't need // to print the normal "implementation of `std::ops::Add` might be missing" note let mut is_string_addition = false; - let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var); if let TyRef(_, l_ty) = lhs_ty.sty { if let TyRef(_, r_ty) = rhs_ty.sty { if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr { diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index 4b36072243c..33280fb931a 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -11,7 +11,6 @@ use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::lint; use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt}; @@ -53,12 +52,16 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { 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.hir.as_local_node_id(item1).unwrap(); - self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, - node_id, - self.tcx.span_of_impl(item1).unwrap(), - msg); + struct_span_err!(self.tcx.sess, + self.tcx.span_of_impl(item1).unwrap(), + E0592, + "duplicate definitions with name `{}`", + name) + .span_label(self.tcx.span_of_impl(item1).unwrap(), + &format!("duplicate definitions for `{}`", name)) + .span_label(self.tcx.span_of_impl(item2).unwrap(), + &format!("other definition for `{}`", name)) + .emit(); } } } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 117cfbabb52..1e687d63f58 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -16,10 +16,10 @@ //! of `fmt::Display`. Example usage: //! //! ```rust,ignore -//! use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle}; +//! use rustdoc::html::markdown::Markdown; //! //! let s = "My *markdown* _text_"; -//! let html = format!("{}", Markdown(s, MarkdownOutputStyle::Fancy)); +//! let html = format!("{}", Markdown(s)); //! // ... something using html //! ``` @@ -27,6 +27,7 @@ use std::ascii::AsciiExt; use std::cell::RefCell; +use std::collections::{HashMap, VecDeque}; use std::default::Default; use std::fmt::{self, Write}; use std::str; @@ -36,43 +37,23 @@ use syntax::codemap::Span; use html::render::derive_id; use html::toc::TocBuilder; use html::highlight; -use html::escape::Escape; use test; -use pulldown_cmark::{self, Event, Parser, Tag}; - -#[derive(Copy, Clone)] -pub enum MarkdownOutputStyle { - Compact, - Fancy, -} - -impl MarkdownOutputStyle { - pub fn is_compact(&self) -> bool { - match *self { - MarkdownOutputStyle::Compact => true, - _ => false, - } - } - - pub fn is_fancy(&self) -> bool { - match *self { - MarkdownOutputStyle::Fancy => true, - _ => false, - } - } -} +use pulldown_cmark::{html, Event, Tag, Parser}; +use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES}; /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. // The second parameter is whether we need a shorter version or not. -pub struct Markdown<'a>(pub &'a str, pub MarkdownOutputStyle); +pub struct Markdown<'a>(pub &'a str); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. pub struct MarkdownWithToc<'a>(pub &'a str); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. pub struct MarkdownHtml<'a>(pub &'a str); +/// A unit struct like `Markdown`, that renders only the first paragraph. +pub struct MarkdownSummaryLine<'a>(pub &'a str); /// Returns Some(code) if `s` is a line that should be stripped from /// documentation but used in example code. `code` is the portion of @@ -89,12 +70,21 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { } } -/// Returns a new string with all consecutive whitespace collapsed into -/// single spaces. +/// Convert chars from a title for an id. /// -/// Any leading or trailing whitespace will be trimmed. -fn collapse_whitespace(s: &str) -> String { - s.split_whitespace().collect::<Vec<_>>().join(" ") +/// "Hello, world!" -> "hello-world" +fn slugify(c: char) -> Option<char> { + if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } } // Information about the playground if a URL has been specified, containing an @@ -103,72 +93,50 @@ thread_local!(pub static PLAYGROUND: RefCell<Option<(Option<String>, String)>> = RefCell::new(None) }); -macro_rules! event_loop_break { - ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, $id:expr, - $($end_event:pat)|*) => {{ - fn inner(id: &mut Option<&mut String>, s: &str) { - if let Some(ref mut id) = *id { - id.push_str(s); - } +/// Adds syntax highlighting and playground Run buttons to rust code blocks. +struct CodeBlocks<'a, I: Iterator<Item = Event<'a>>> { + inner: I, +} + +impl<'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'a, I> { + fn new(iter: I) -> Self { + CodeBlocks { + inner: iter, } - while let Some(event) = $parser.next() { - match event { - $($end_event)|* => break, - Event::Text(ref s) => { - inner($id, s); - if $escape { - $buf.push_str(&format!("{}", Escape(s))); - } else { - $buf.push_str(s); - } - } - Event::SoftBreak | Event::HardBreak if !$buf.is_empty() => { - $buf.push(' '); - } - x => { - looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id); - } + } +} + +impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> { + type Item = Event<'a>; + + fn next(&mut self) -> Option<Self::Item> { + let event = self.inner.next(); + if let Some(Event::Start(Tag::CodeBlock(lang))) = event { + if !LangString::parse(&lang).rust { + return Some(Event::Start(Tag::CodeBlock(lang))); } + } else { + return event; } - }} -} -pub fn render(w: &mut fmt::Formatter, - s: &str, - print_toc: bool, - shorter: MarkdownOutputStyle) -> fmt::Result { - fn code_block(parser: &mut Parser, buffer: &mut String, lang: &str) { let mut origtext = String::new(); - while let Some(event) = parser.next() { + for event in &mut self.inner { match event { - Event::End(Tag::CodeBlock(_)) => break, + Event::End(Tag::CodeBlock(..)) => break, Event::Text(ref s) => { origtext.push_str(s); } _ => {} } } - let origtext = origtext.trim_left(); - debug!("docblock: ==============\n{:?}\n=======", origtext); - let lines = origtext.lines().filter(|l| { stripped_filtered_line(*l).is_none() }); let text = lines.collect::<Vec<&str>>().join("\n"); - let block_info = if lang.is_empty() { - LangString::all_false() - } else { - LangString::parse(lang) - }; - if !block_info.rust { - buffer.push_str(&format!("<pre><code class=\"language-{}\">{}</code></pre>", - lang, text)); - return - } PLAYGROUND.with(|play| { // insert newline to clearly separate it from the // previous block so we can shorten the html output - buffer.push('\n'); + let mut s = String::from("\n"); let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| { if url.is_empty() { return None; @@ -178,7 +146,7 @@ pub fn render(w: &mut fmt::Formatter, }).collect::<Vec<&str>>().join("\n"); let krate = krate.as_ref().map(|s| &**s); let test = test::maketest(&test, krate, false, - &Default::default()); + &Default::default()); let channel = if test.contains("#![feature(") { "&version=nightly" } else { @@ -207,271 +175,186 @@ pub fn render(w: &mut fmt::Formatter, url, test_escaped, channel )) }); - buffer.push_str(&highlight::render_with_highlighting( - &text, - Some("rust-example-rendered"), - None, - playground_button.as_ref().map(String::as_str))); - }); - } - - fn heading(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle, level: i32) { - let mut ret = String::new(); - let mut id = String::new(); - event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id), - Event::End(Tag::Header(_))); - ret = ret.trim_right().to_owned(); - - let id = id.chars().filter_map(|c| { - if c.is_alphanumeric() || c == '-' || c == '_' { - if c.is_ascii() { - Some(c.to_ascii_lowercase()) - } else { - Some(c) - } - } else if c.is_whitespace() && c.is_ascii() { - Some('-') - } else { - None - } - }).collect::<String>(); - - let id = derive_id(id); - - let sec = toc_builder.as_mut().map_or("".to_owned(), |builder| { - format!("{} ", builder.push(level as u32, ret.clone(), id.clone())) - }); - - // Render the HTML - buffer.push_str(&format!("<h{lvl} id=\"{id}\" class=\"section-header\">\ - <a href=\"#{id}\">{sec}{}</a></h{lvl}>", - ret, lvl = level, id = id, sec = sec)); - } - - fn inline_code(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code)); - buffer.push_str(&format!("<code>{}</code>", - Escape(&collapse_whitespace(content.trim_right())))); + s.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + playground_button.as_ref().map(String::as_str))); + Some(Event::Html(s.into())) + }) } +} - fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle, url: &str, mut title: String, - id: &mut Option<&mut String>) { - event_loop_break!(parser, toc_builder, shorter, title, true, id, - Event::End(Tag::Link(_, _))); - buffer.push_str(&format!("<a href=\"{}\">{}</a>", url, title)); - } +/// Make headings links with anchor ids and build up TOC. +struct HeadingLinks<'a, 'b, I: Iterator<Item = Event<'a>>> { + inner: I, + toc: Option<&'b mut TocBuilder>, + buf: VecDeque<Event<'a>>, +} - fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, id, - Event::End(Tag::Paragraph)); - buffer.push_str(&format!("<p>{}</p>", content.trim_right())); +impl<'a, 'b, I: Iterator<Item = Event<'a>>> HeadingLinks<'a, 'b, I> { + fn new(iter: I, toc: Option<&'b mut TocBuilder>) -> Self { + HeadingLinks { + inner: iter, + toc: toc, + buf: VecDeque::new(), + } } +} - fn table_cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle) { - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) | - Event::End(Tag::TableCell)); - buffer.push_str(&format!("<td>{}</td>", content.trim())); - } +impl<'a, 'b, I: Iterator<Item = Event<'a>>> Iterator for HeadingLinks<'a, 'b, I> { + type Item = Event<'a>; - fn table_row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle) { - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::TableHead) | - Event::End(Tag::Table(_)) | - Event::End(Tag::TableRow) => break, - Event::Start(Tag::TableCell) => { - table_cell(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); - } - } + fn next(&mut self) -> Option<Self::Item> { + if let Some(e) = self.buf.pop_front() { + return Some(e); } - buffer.push_str(&format!("<tr>{}</tr>", content)); - } - fn table_head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle) { - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break, - Event::Start(Tag::TableCell) => { - table_cell(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); + let event = self.inner.next(); + if let Some(Event::Start(Tag::Header(level))) = event { + let mut id = String::new(); + for event in &mut self.inner { + match event { + Event::End(Tag::Header(..)) => break, + Event::Text(ref text) => id.extend(text.chars().filter_map(slugify)), + _ => {}, } + self.buf.push_back(event); } - } - if !content.is_empty() { - buffer.push_str(&format!("<thead><tr>{}</tr></thead>", content.replace("td>", "th>"))); - } - } + let id = derive_id(id); - fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle) { - let mut content = String::new(); - let mut rows = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Table(_)) => break, - Event::Start(Tag::TableHead) => { - table_head(parser, &mut content, toc_builder, shorter); - } - Event::Start(Tag::TableRow) => { - table_row(parser, &mut rows, toc_builder, shorter); - } - _ => {} + if let Some(ref mut builder) = self.toc { + let mut html_header = String::new(); + html::push_html(&mut html_header, self.buf.iter().cloned()); + let sec = builder.push(level as u32, html_header, id.clone()); + self.buf.push_front(Event::InlineHtml(format!("{} ", sec).into())); } + + self.buf.push_back(Event::InlineHtml(format!("</a></h{}>", level).into())); + + let start_tags = format!("<h{level} id=\"{id}\" class=\"section-header\">\ + <a href=\"#{id}\">", + id = id, + level = level); + return Some(Event::InlineHtml(start_tags.into())); } - buffer.push_str(&format!("<table>{}{}</table>", - content, - if shorter.is_compact() || rows.is_empty() { - String::new() - } else { - format!("<tbody>{}</tbody>", rows) - })); + event } +} - fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle) { - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, true, &mut None, - Event::End(Tag::BlockQuote)); - buffer.push_str(&format!("<blockquote>{}</blockquote>", content.trim_right())); - } +/// Extracts just the first paragraph. +struct SummaryLine<'a, I: Iterator<Item = Event<'a>>> { + inner: I, + started: bool, + depth: u32, +} - fn list_item(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle) { - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::Item) => break, - Event::Text(ref s) => { - content.push_str(&format!("{}", Escape(s))); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); - } - } +impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> { + fn new(iter: I) -> Self { + SummaryLine { + inner: iter, + started: false, + depth: 0, } - buffer.push_str(&format!("<li>{}</li>", content)); } +} - fn list(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle) { - let mut content = String::new(); - while let Some(event) = parser.next() { - match event { - Event::End(Tag::List(_)) => break, - Event::Start(Tag::Item) => { - list_item(parser, &mut content, toc_builder, shorter); - } - x => { - looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None); - } - } +impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> { + type Item = Event<'a>; + + fn next(&mut self) -> Option<Self::Item> { + if self.started && self.depth == 0 { + return None; + } + if !self.started { + self.started = true; } - buffer.push_str(&format!("<ul>{}</ul>", content)); + let event = self.inner.next(); + match event { + Some(Event::Start(..)) => self.depth += 1, + Some(Event::End(..)) => self.depth -= 1, + _ => {} + } + event } +} - fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, false, id, - Event::End(Tag::Emphasis)); - buffer.push_str(&format!("<em>{}</em>", content)); - } +/// Moves all footnote definitions to the end and add back links to the +/// references. +struct Footnotes<'a, I: Iterator<Item = Event<'a>>> { + inner: I, + footnotes: HashMap<String, (Vec<Event<'a>>, u16)>, +} - fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>, - shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) { - let mut content = String::new(); - event_loop_break!(parser, toc_builder, shorter, content, false, id, - Event::End(Tag::Strong)); - buffer.push_str(&format!("<strong>{}</strong>", content)); +impl<'a, I: Iterator<Item = Event<'a>>> Footnotes<'a, I> { + fn new(iter: I) -> Self { + Footnotes { + inner: iter, + footnotes: HashMap::new(), + } } + fn get_entry(&mut self, key: &str) -> &mut (Vec<Event<'a>>, u16) { + let new_id = self.footnotes.keys().count() + 1; + let key = key.to_owned(); + self.footnotes.entry(key).or_insert((Vec::new(), new_id as u16)) + } +} - fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option<Event<'a>>, - toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle, - id: &mut Option<&mut String>) -> bool { - if let Some(event) = next_event { - match event { - Event::Start(Tag::CodeBlock(lang)) => { - code_block(parser, buffer, &*lang); - } - Event::Start(Tag::Header(level)) => { - heading(parser, buffer, toc_builder, shorter, level); - } - Event::Start(Tag::Code) => { - inline_code(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Paragraph) => { - paragraph(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Link(ref url, ref t)) => { - link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id); - } - Event::Start(Tag::Table(_)) => { - table(parser, buffer, toc_builder, shorter); - } - Event::Start(Tag::BlockQuote) => { - blockquote(parser, buffer, toc_builder, shorter); - } - Event::Start(Tag::List(_)) => { - list(parser, buffer, toc_builder, shorter); - } - Event::Start(Tag::Emphasis) => { - emphasis(parser, buffer, toc_builder, shorter, id); - } - Event::Start(Tag::Strong) => { - strong(parser, buffer, toc_builder, shorter, id); - } - Event::Html(h) | Event::InlineHtml(h) => { - buffer.push_str(&*h); +impl<'a, I: Iterator<Item = Event<'a>>> Iterator for Footnotes<'a, I> { + type Item = Event<'a>; + + fn next(&mut self) -> Option<Self::Item> { + loop { + match self.inner.next() { + Some(Event::FootnoteReference(ref reference)) => { + let entry = self.get_entry(&reference); + let reference = format!("<sup id=\"supref{0}\"><a href=\"#ref{0}\">{0}\ + </a></sup>", + (*entry).1); + return Some(Event::Html(reference.into())); + } + Some(Event::Start(Tag::FootnoteDefinition(def))) => { + let mut content = Vec::new(); + for event in &mut self.inner { + if let Event::End(Tag::FootnoteDefinition(..)) = event { + break; + } + content.push(event); + } + let entry = self.get_entry(&def); + (*entry).0 = content; + } + Some(e) => return Some(e), + None => { + if !self.footnotes.is_empty() { + let mut v: Vec<_> = self.footnotes.drain().map(|(_, x)| x).collect(); + v.sort_by(|a, b| a.1.cmp(&b.1)); + let mut ret = String::from("<div class=\"footnotes\"><hr><ol>"); + for (mut content, id) in v { + write!(ret, "<li id=\"ref{}\">", id).unwrap(); + let mut is_paragraph = false; + if let Some(&Event::End(Tag::Paragraph)) = content.last() { + content.pop(); + is_paragraph = true; + } + html::push_html(&mut ret, content.into_iter()); + write!(ret, + " <a href=\"#supref{}\" rev=\"footnote\">↩</a>", + id).unwrap(); + if is_paragraph { + ret.push_str("</p>"); + } + ret.push_str("</li>"); + } + ret.push_str("</ol></div>"); + return Some(Event::Html(ret.into())); + } else { + return None; + } } - _ => {} } - shorter.is_fancy() - } else { - false } } - - let mut toc_builder = if print_toc { - Some(TocBuilder::new()) - } else { - None - }; - let mut buffer = String::new(); - let mut parser = Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES); - loop { - let next_event = parser.next(); - if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter, &mut None) { - break - } - } - let mut ret = toc_builder.map_or(Ok(()), |builder| { - write!(w, "<nav id=\"TOC\">{}</nav>", builder.into_toc()) - }); - - if ret.is_ok() { - ret = w.write_str(&buffer); - } - ret } pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) { @@ -618,17 +501,45 @@ impl LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let Markdown(md, shorter) = *self; + let Markdown(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, shorter) + + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); + + let p = Parser::new_ext(md, opts); + + let mut s = String::with_capacity(md.len() * 3 / 2); + + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); + + fmt.write_str(&s) } } impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let MarkdownWithToc(md) = *self; - render(fmt, md, true, MarkdownOutputStyle::Fancy) + + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); + + let p = Parser::new_ext(md, opts); + + let mut s = String::with_capacity(md.len() * 3 / 2); + + let mut toc = TocBuilder::new(); + + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc))))); + + write!(fmt, "<nav id=\"TOC\">{}</nav>", toc.into_toc())?; + + fmt.write_str(&s) } } @@ -637,7 +548,41 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let MarkdownHtml(md) = *self; // This is actually common enough to special-case if md.is_empty() { return Ok(()) } - render(fmt, md, false, MarkdownOutputStyle::Fancy) + + let mut opts = Options::empty(); + opts.insert(OPTION_ENABLE_TABLES); + opts.insert(OPTION_ENABLE_FOOTNOTES); + + let p = Parser::new_ext(md, opts); + + // Treat inline HTML as plain text. + let p = p.map(|event| match event { + Event::Html(text) | Event::InlineHtml(text) => Event::Text(text), + _ => event + }); + + let mut s = String::with_capacity(md.len() * 3 / 2); + + html::push_html(&mut s, + Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None)))); + + fmt.write_str(&s) + } +} + +impl<'a> fmt::Display for MarkdownSummaryLine<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let MarkdownSummaryLine(md) = *self; + // This is actually common enough to special-case + if md.is_empty() { return Ok(()) } + + let p = Parser::new(md); + + let mut s = String::new(); + + html::push_html(&mut s, SummaryLine::new(p)); + + fmt.write_str(&s) } } @@ -659,14 +604,10 @@ pub fn plain_summary_line(md: &str) -> String { let next_event = next_event.unwrap(); let (ret, is_in) = match next_event { Event::Start(Tag::Paragraph) => (None, 1), - Event::Start(Tag::Link(_, ref t)) if !self.is_first => { - (Some(t.as_ref().to_owned()), 1) - } Event::Start(Tag::Code) => (Some("`".to_owned()), 1), Event::End(Tag::Code) => (Some("`".to_owned()), -1), Event::Start(Tag::Header(_)) => (None, 1), Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), - Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1), Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1), _ => (None, 0), }; @@ -697,7 +638,7 @@ pub fn plain_summary_line(md: &str) -> String { #[cfg(test)] mod tests { - use super::{LangString, Markdown, MarkdownHtml, MarkdownOutputStyle}; + use super::{LangString, Markdown, MarkdownHtml}; use super::plain_summary_line; use html::render::reset_ids; @@ -737,14 +678,14 @@ mod tests { #[test] fn issue_17736() { let markdown = "# title"; - format!("{}", Markdown(markdown, MarkdownOutputStyle::Fancy)); + format!("{}", Markdown(markdown)); reset_ids(true); } #[test] fn test_header() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); + let output = format!("{}", Markdown(input)); assert_eq!(output, expect, "original: {}", input); reset_ids(true); } @@ -766,7 +707,7 @@ mod tests { #[test] fn test_header_ids_multiple_blocks() { fn t(input: &str, expect: &str) { - let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy)); + let output = format!("{}", Markdown(input)); assert_eq!(output, expect, "original: {}", input); } @@ -797,6 +738,7 @@ mod tests { } t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); + t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); t("code `let x = i32;` ...", "code `let x = i32;` ..."); t("type `Type<'static>` ...", "type `Type<'static>` ..."); t("# top header", "top header"); @@ -810,7 +752,8 @@ mod tests { assert_eq!(output, expect, "original: {}", input); } - t("`Struct<'a, T>`", "<p><code>Struct<'a, T></code></p>"); - t("Struct<'a, T>", "<p>Struct<'a, T></p>"); + t("`Struct<'a, T>`", "<p><code>Struct<'a, T></code></p>\n"); + t("Struct<'a, T>", "<p>Struct<'a, T></p>\n"); + t("Struct<br>", "<p>Struct<br></p>\n"); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index f0b624105e3..1e1202f0400 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace}; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::format::fmt_impl_for_trait_page; use html::item_type::ItemType; -use html::markdown::{self, Markdown, MarkdownHtml, MarkdownOutputStyle}; +use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine}; use html::{highlight, layout}; /// A pair of name and its optional document. @@ -1651,7 +1651,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin format!("{}", &plain_summary_line(Some(s))) }; write!(w, "<div class='docblock'>{}</div>", - Markdown(&markdown, MarkdownOutputStyle::Fancy))?; + Markdown(&markdown))?; } Ok(()) } @@ -1684,8 +1684,7 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> { fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { if let Some(s) = get_doc_value(item) { write!(w, "<div class='docblock'>{}</div>", - Markdown(&format!("{}{}", md_render_assoc_item(item), s), - MarkdownOutputStyle::Fancy))?; + Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?; } Ok(()) } @@ -1873,8 +1872,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, </tr>", name = *myitem.name.as_ref().unwrap(), stab_docs = stab_docs, - docs = shorter(Some(&Markdown(doc_value, - MarkdownOutputStyle::Compact).to_string())), + docs = MarkdownSummaryLine(doc_value), class = myitem.type_(), stab = myitem.stability_class().unwrap_or("".to_string()), unsafety_flag = unsafety_flag, @@ -2904,7 +2902,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "</span>")?; write!(w, "</h3>\n")?; if let Some(ref dox) = i.impl_item.doc_value() { - write!(w, "<div class='docblock'>{}</div>", Markdown(dox, MarkdownOutputStyle::Fancy))?; + write!(w, "<div class='docblock'>{}</div>", Markdown(dox))?; } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 5cc0f03e1f6..5fadda030a4 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -25,7 +25,7 @@ use externalfiles::{ExternalHtml, LoadStringError, load_string}; use html::render::reset_ids; use html::escape::Escape; use html::markdown; -use html::markdown::{Markdown, MarkdownWithToc, MarkdownOutputStyle, find_testable_code}; +use html::markdown::{Markdown, MarkdownWithToc, find_testable_code}; use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `# ` or `%`. @@ -96,7 +96,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let rendered = if include_toc { format!("{}", MarkdownWithToc(text)) } else { - format!("{}", Markdown(text, MarkdownOutputStyle::Fancy)) + format!("{}", Markdown(text)) }; let err = write!( diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 4d94c308478..59fef8d2027 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -82,7 +82,7 @@ fn unindent(s: &str) -> String { }); if !lines.is_empty() { - let mut unindented = vec![ lines[0].trim().to_string() ]; + let mut unindented = vec![ lines[0].trim_left().to_string() ]; unindented.extend_from_slice(&lines[1..].iter().map(|&line| { if line.chars().all(|c| c.is_whitespace()) { line.to_string() @@ -160,4 +160,15 @@ mod unindent_tests { let r = unindent(&s); assert_eq!(r, "line1\nline2"); } + + #[test] + fn should_not_trim() { + let s = "\t line1 \n\t line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1 \nline2"); + + let s = " \tline1 \n \tline2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1 \nline2"); + } } diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 1cac11f668d..b3625386209 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -9,6 +9,20 @@ // except according to those terms. //! Operations on ASCII strings and characters. +//! +//! Most string operations in Rust act on UTF-8 strings. However, at times it +//! makes more sense to only consider the ASCII character set for a specific +//! operation. +//! +//! The [`AsciiExt`] trait provides methods that allow for character +//! operations that only act on the ASCII subset and leave non-ASCII characters +//! alone. +//! +//! The [`escape_default`] function provides an iterator over the bytes of an +//! escaped version of the character given. +//! +//! [`AsciiExt`]: trait.AsciiExt.html +//! [`escape_default`]: fn.escape_default.html #![stable(feature = "rust1", since = "1.0.0")] @@ -53,11 +67,11 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'a'; - /// let utf8 = '❤'; + /// let non_ascii = '❤'; /// let int_ascii = 97; /// /// assert!(ascii.is_ascii()); - /// assert!(!utf8.is_ascii()); + /// assert!(!non_ascii.is_ascii()); /// assert!(int_ascii.is_ascii()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -79,11 +93,11 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'a'; - /// let utf8 = '❤'; + /// let non_ascii = '❤'; /// let int_ascii = 97; /// /// assert_eq!('A', ascii.to_ascii_uppercase()); - /// assert_eq!('❤', utf8.to_ascii_uppercase()); + /// assert_eq!('❤', non_ascii.to_ascii_uppercase()); /// assert_eq!(65, int_ascii.to_ascii_uppercase()); /// ``` /// @@ -108,11 +122,11 @@ pub trait AsciiExt { /// use std::ascii::AsciiExt; /// /// let ascii = 'A'; - /// let utf8 = '❤'; + /// let non_ascii = '❤'; /// let int_ascii = 65; /// /// assert_eq!('a', ascii.to_ascii_lowercase()); - /// assert_eq!('❤', utf8.to_ascii_lowercase()); + /// assert_eq!('❤', non_ascii.to_ascii_lowercase()); /// assert_eq!(97, int_ascii.to_ascii_lowercase()); /// ``` /// @@ -934,8 +948,12 @@ impl AsciiExt for char { } } -/// An iterator over the escaped version of a byte, constructed via -/// `std::ascii::escape_default`. +/// An iterator over the escaped version of a byte. +/// +/// This `struct` is created by the [`escape_default`] function. See its +/// documentation for more. +/// +/// [`escape_default`]: fn.escape_default.html #[stable(feature = "rust1", since = "1.0.0")] pub struct EscapeDefault { range: Range<usize>, @@ -966,6 +984,38 @@ pub struct EscapeDefault { /// /// assert_eq!(b'\\', escaped.next().unwrap()); /// assert_eq!(b't', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\r'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'r', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\n'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'n', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\''); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'\'', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'"'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'"', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\\'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// +/// let mut escaped = ascii::escape_default(b'\x9d'); +/// +/// assert_eq!(b'\\', escaped.next().unwrap()); +/// assert_eq!(b'x', escaped.next().unwrap()); +/// assert_eq!(b'9', escaped.next().unwrap()); +/// assert_eq!(b'd', escaped.next().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn escape_default(c: u8) -> EscapeDefault { diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 57332170081..a06299eaefe 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -472,7 +472,7 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) } // Now we've done all our shifting. Return the value we grabbed earlier. - (retkey, retval, gap.into_bucket().into_table()) + (retkey, retval, gap.into_table()) } /// Perform robin hood bucket stealing at the given `bucket`. You must @@ -485,14 +485,14 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, mut key: K, mut val: V) -> FullBucketMut<'a, K, V> { - let start_index = bucket.index(); let size = bucket.table().size(); - // Save the *starting point*. - let mut bucket = bucket.stash(); + let raw_capacity = bucket.table().capacity(); // There can be at most `size - dib` buckets to displace, because // in the worst case, there are `size` elements and we already are // `displacement` buckets away from the initial one. - let idx_end = start_index + size - bucket.displacement(); + let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity; + // Save the *starting point*. + let mut bucket = bucket.stash(); loop { let (old_hash, old_key, old_val) = bucket.replace(hash, key, val); @@ -568,11 +568,8 @@ impl<K, V, S> HashMap<K, V, S> // The caller should ensure that invariants by Robin Hood Hashing hold // and that there's space in the underlying table. fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { - let raw_cap = self.raw_capacity(); let mut buckets = Bucket::new(&mut self.table, hash); - // note that buckets.index() keeps increasing - // even if the pointer wraps back to the first bucket. - let limit_bucket = buckets.index() + raw_cap; + let start_index = buckets.index(); loop { // We don't need to compare hashes for value swap. @@ -585,7 +582,7 @@ impl<K, V, S> HashMap<K, V, S> Full(b) => b.into_bucket(), }; buckets.next(); - debug_assert!(buckets.index() < limit_bucket); + debug_assert!(buckets.index() != start_index); } } } @@ -1244,24 +1241,25 @@ impl<K, V, S> HashMap<K, V, S> pub fn retain<F>(&mut self, mut f: F) where F: FnMut(&K, &mut V) -> bool { - if self.table.capacity() == 0 || self.table.size() == 0 { + if self.table.size() == 0 { return; } + let mut elems_left = self.table.size(); let mut bucket = Bucket::head_bucket(&mut self.table); bucket.prev(); - let tail = bucket.index(); - loop { + let start_index = bucket.index(); + while elems_left != 0 { bucket = match bucket.peek() { Full(mut full) => { + elems_left -= 1; let should_remove = { let (k, v) = full.read_mut(); !f(k, v) }; if should_remove { - let prev_idx = full.index(); let prev_raw = full.raw(); let (_, _, t) = pop_internal(full); - Bucket::new_from(prev_raw, prev_idx, t) + Bucket::new_from(prev_raw, t) } else { full.into_bucket() } @@ -1271,9 +1269,7 @@ impl<K, V, S> HashMap<K, V, S> } }; bucket.prev(); // reverse iteration - if bucket.index() == tail { - break; - } + debug_assert!(elems_left == 0 || bucket.index() != start_index); } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index da5fb1a4733..9623706548b 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -113,7 +113,7 @@ impl TaggedHashUintPtr { /// when the RawTable is created and is accessible with the `tag` and `set_tag` /// functions. pub struct RawTable<K, V> { - capacity: usize, + capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, @@ -125,10 +125,13 @@ pub struct RawTable<K, V> { unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {} unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {} +// An unsafe view of a RawTable bucket +// Valid indexes are within [0..table_capacity) pub struct RawBucket<K, V> { - hash: *mut HashUint, + hash_start: *mut HashUint, // We use *const to ensure covariance with respect to K and V - pair: *const (K, V), + pair_start: *const (K, V), + idx: usize, _marker: marker::PhantomData<(K, V)>, } @@ -141,7 +144,6 @@ impl<K, V> Clone for RawBucket<K, V> { pub struct Bucket<K, V, M> { raw: RawBucket<K, V>, - idx: usize, table: M, } @@ -154,13 +156,11 @@ impl<K, V, M: Copy> Clone for Bucket<K, V, M> { pub struct EmptyBucket<K, V, M> { raw: RawBucket<K, V>, - idx: usize, table: M, } pub struct FullBucket<K, V, M> { raw: RawBucket<K, V>, - idx: usize, table: M, } @@ -232,13 +232,17 @@ fn can_alias_safehash_as_hash() { assert_eq!(size_of::<SafeHash>(), size_of::<HashUint>()) } +// RawBucket methods are unsafe as it's possible to +// make a RawBucket point to invalid memory using safe code. impl<K, V> RawBucket<K, V> { - unsafe fn offset(self, count: isize) -> RawBucket<K, V> { - RawBucket { - hash: self.hash.offset(count), - pair: self.pair.offset(count), - _marker: marker::PhantomData, - } + unsafe fn hash(&self) -> *mut HashUint { + self.hash_start.offset(self.idx as isize) + } + unsafe fn pair(&self) -> *mut (K, V) { + self.pair_start.offset(self.idx as isize) as *mut (K, V) + } + unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) { + (self.hash(), self.pair()) } } @@ -258,7 +262,7 @@ impl<K, V, M> FullBucket<K, V, M> { } /// Get the raw index. pub fn index(&self) -> usize { - self.idx + self.raw.idx } /// Get the raw bucket. pub fn raw(&self) -> RawBucket<K, V> { @@ -280,7 +284,7 @@ impl<K, V, M> EmptyBucket<K, V, M> { impl<K, V, M> Bucket<K, V, M> { /// Get the raw index. pub fn index(&self) -> usize { - self.idx + self.raw.idx } /// get the table. pub fn into_table(self) -> M { @@ -331,12 +335,11 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> { Bucket::at_index(table, hash.inspect() as usize) } - pub fn new_from(r: RawBucket<K, V>, i: usize, t: M) + pub fn new_from(r: RawBucket<K, V>, t: M) -> Bucket<K, V, M> { Bucket { raw: r, - idx: i, table: t, } } @@ -346,18 +349,16 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> { // This is an uncommon case though, so avoid it in release builds. debug_assert!(table.capacity() > 0, "Table should have capacity at this point"); - let ib_index = ib_index & (table.capacity() - 1); + let ib_index = ib_index & table.capacity_mask; Bucket { - raw: unsafe { table.first_bucket_raw().offset(ib_index as isize) }, - idx: ib_index, + raw: table.raw_bucket_at(ib_index), table: table, } } pub fn first(table: M) -> Bucket<K, V, M> { Bucket { - raw: table.first_bucket_raw(), - idx: 0, + raw: table.raw_bucket_at(0), table: table, } } @@ -401,48 +402,30 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> { /// the appropriate types to call most of the other functions in /// this module. pub fn peek(self) -> BucketState<K, V, M> { - match unsafe { *self.raw.hash } { + match unsafe { *self.raw.hash() } { EMPTY_BUCKET => { Empty(EmptyBucket { raw: self.raw, - idx: self.idx, table: self.table, }) } _ => { Full(FullBucket { raw: self.raw, - idx: self.idx, table: self.table, }) } } } - /// Modifies the bucket pointer in place to make it point to the next slot. + /// Modifies the bucket in place to make it point to the next slot. pub fn next(&mut self) { - self.idx += 1; - let range = self.table.capacity(); - // This code is branchless thanks to a conditional move. - let dist = if self.idx & (range - 1) == 0 { - 1 - range as isize - } else { - 1 - }; - unsafe { - self.raw = self.raw.offset(dist); - } + self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask; } - /// Modifies the bucket pointer in place to make it point to the previous slot. + /// Modifies the bucket in place to make it point to the previous slot. pub fn prev(&mut self) { - let range = self.table.capacity(); - let new_idx = self.idx.wrapping_sub(1) & (range - 1); - let dist = (new_idx as isize).wrapping_sub(self.idx as isize); - self.idx = new_idx; - unsafe { - self.raw = self.raw.offset(dist); - } + self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask; } } @@ -458,7 +441,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> { pub fn into_bucket(self) -> Bucket<K, V, M> { Bucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -466,7 +448,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> { pub fn gap_peek(self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> { let gap = EmptyBucket { raw: self.raw, - idx: self.idx, table: (), }; @@ -494,15 +475,14 @@ impl<K, V, M> EmptyBucket<K, V, M> /// Use `make_hash` to construct a `SafeHash` to pass to this function. pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> { unsafe { - *self.raw.hash = hash.inspect(); - ptr::write(self.raw.pair as *mut (K, V), (key, value)); + *self.raw.hash() = hash.inspect(); + ptr::write(self.raw.pair(), (key, value)); self.table.borrow_table_mut().size += 1; } FullBucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -510,15 +490,14 @@ impl<K, V, M> EmptyBucket<K, V, M> /// Puts given key, remain value uninitialized. /// It is only used for inplacement insertion. pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket<K, V, M> { - *self.raw.hash = hash.inspect(); - let pair_mut = self.raw.pair as *mut (K, V); - ptr::write(&mut (*pair_mut).0, key); + *self.raw.hash() = hash.inspect(); + let pair_ptr = self.raw.pair(); + ptr::write(&mut (*pair_ptr).0, key); self.table.borrow_table_mut().size += 1; FullBucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -536,7 +515,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> { pub fn into_bucket(self) -> Bucket<K, V, M> { Bucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -546,7 +524,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> { pub fn stash(self) -> FullBucket<K, V, Self> { FullBucket { raw: self.raw, - idx: self.idx, table: self, } } @@ -560,17 +537,20 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> { // Calculates the distance one has to travel when going from // `hash mod capacity` onwards to `idx mod capacity`, wrapping around // if the destination is not reached before the end of the table. - (self.idx.wrapping_sub(self.hash().inspect() as usize)) & (self.table.capacity() - 1) + (self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask } #[inline] pub fn hash(&self) -> SafeHash { - unsafe { SafeHash { hash: *self.raw.hash } } + unsafe { SafeHash { hash: *self.raw.hash() } } } /// Gets references to the key and value at a given index. pub fn read(&self) -> (&K, &V) { - unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) + } } } @@ -586,11 +566,10 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> { self.table.size -= 1; unsafe { - *self.raw.hash = EMPTY_BUCKET; - let (k, v) = ptr::read(self.raw.pair); + *self.raw.hash() = EMPTY_BUCKET; + let (k, v) = ptr::read(self.raw.pair()); (EmptyBucket { raw: self.raw, - idx: self.idx, table: self.table, }, k, @@ -604,9 +583,9 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> { pub unsafe fn remove_key(&mut self) { self.table.size -= 1; - *self.raw.hash = EMPTY_BUCKET; - let pair_mut = self.raw.pair as *mut (K, V); - ptr::drop_in_place(&mut (*pair_mut).0); // only drop key + *self.raw.hash() = EMPTY_BUCKET; + let pair_ptr = self.raw.pair(); + ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key } } @@ -617,8 +596,8 @@ impl<K, V, M> FullBucket<K, V, M> { pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { unsafe { - let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h); - let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v)); + let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h); + let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v)); (old_hash, old_key, old_val) } @@ -630,8 +609,10 @@ impl<K, V, M> FullBucket<K, V, M> { /// Gets mutable references to the key and value at a given index. pub fn read_mut(&mut self) -> (&mut K, &mut V) { - let pair_mut = self.raw.pair as *mut (K, V); - unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&mut (*pair_ptr).0, &mut (*pair_ptr).1) + } } } @@ -644,7 +625,10 @@ impl<'t, K, V, M> FullBucket<K, V, M> /// in exchange for this, the returned references have a longer lifetime /// than the references returned by `read()`. pub fn into_refs(self) -> (&'t K, &'t V) { - unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) + } } } @@ -654,8 +638,10 @@ impl<'t, K, V, M> FullBucket<K, V, M> /// This works similarly to `into_refs`, exchanging a bucket state /// for mutable references into the table. pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { - let pair_mut = self.raw.pair as *mut (K, V); - unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&mut (*pair_ptr).0, &mut (*pair_ptr).1) + } } } @@ -667,22 +653,23 @@ impl<K, V, M> GapThenFull<K, V, M> &self.full } - pub fn into_bucket(self) -> Bucket<K, V, M> { - self.full.into_bucket() + pub fn into_table(self) -> M { + self.full.into_table() } pub fn shift(mut self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> { unsafe { - *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET); - ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1); + let (gap_hash, gap_pair) = self.gap.raw.hash_pair(); + let (full_hash, full_pair) = self.full.raw.hash_pair(); + *gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET); + ptr::copy_nonoverlapping(full_pair, gap_pair, 1); } - let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full; + let FullBucket { raw: prev_raw, .. } = self.full; match self.full.next().peek() { Full(bucket) => { self.gap.raw = prev_raw; - self.gap.idx = prev_idx; self.full = bucket; @@ -761,7 +748,7 @@ impl<K, V> RawTable<K, V> { if capacity == 0 { return RawTable { size: 0, - capacity: 0, + capacity_mask: capacity.wrapping_sub(1), hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), marker: marker::PhantomData, }; @@ -801,25 +788,27 @@ impl<K, V> RawTable<K, V> { let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; RawTable { - capacity: capacity, + capacity_mask: capacity.wrapping_sub(1), size: 0, hashes: TaggedHashUintPtr::new(hashes), marker: marker::PhantomData, } } - fn first_bucket_raw(&self) -> RawBucket<K, V> { - let hashes_size = self.capacity * size_of::<HashUint>(); - let pairs_size = self.capacity * size_of::<(K, V)>(); + fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> { + let hashes_size = self.capacity() * size_of::<HashUint>(); + let pairs_size = self.capacity() * size_of::<(K, V)>(); - let buffer = self.hashes.ptr() as *mut u8; let (pairs_offset, _, oflo) = calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); debug_assert!(!oflo, "capacity overflow"); + + let buffer = self.hashes.ptr() as *mut u8; unsafe { RawBucket { - hash: self.hashes.ptr(), - pair: buffer.offset(pairs_offset as isize) as *const _, + hash_start: buffer as *mut HashUint, + pair_start: buffer.offset(pairs_offset as isize) as *const (K, V), + idx: index, _marker: marker::PhantomData, } } @@ -837,7 +826,7 @@ impl<K, V> RawTable<K, V> { /// The hashtable's capacity, similar to a vector's. pub fn capacity(&self) -> usize { - self.capacity + self.capacity_mask.wrapping_add(1) } /// The number of elements ever `put` in the hashtable, minus the number @@ -848,8 +837,8 @@ impl<K, V> RawTable<K, V> { fn raw_buckets(&self) -> RawBuckets<K, V> { RawBuckets { - raw: self.first_bucket_raw(), - hashes_end: unsafe { self.hashes.ptr().offset(self.capacity as isize) }, + raw: self.raw_bucket_at(0), + elems_left: self.size, marker: marker::PhantomData, } } @@ -857,25 +846,23 @@ impl<K, V> RawTable<K, V> { pub fn iter(&self) -> Iter<K, V> { Iter { iter: self.raw_buckets(), - elems_left: self.size(), } } pub fn iter_mut(&mut self) -> IterMut<K, V> { IterMut { iter: self.raw_buckets(), - elems_left: self.size(), _marker: marker::PhantomData, } } pub fn into_iter(self) -> IntoIter<K, V> { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. IntoIter { iter: RawBuckets { raw: raw, - hashes_end: hashes_end, + elems_left: elems_left, marker: marker::PhantomData, }, table: self, @@ -883,12 +870,12 @@ impl<K, V> RawTable<K, V> { } pub fn drain(&mut self) -> Drain<K, V> { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. Drain { iter: RawBuckets { raw: raw, - hashes_end: hashes_end, + elems_left: elems_left, marker: marker::PhantomData, }, table: unsafe { Shared::new(self) }, @@ -900,18 +887,16 @@ impl<K, V> RawTable<K, V> { /// state and should only be used for dropping the table's remaining /// entries. It's used in the implementation of Drop. unsafe fn rev_drop_buckets(&mut self) { - let first_raw = self.first_bucket_raw(); - let mut raw = first_raw.offset(self.capacity as isize); + // initialize the raw bucket past the end of the table + let mut raw = self.raw_bucket_at(self.capacity()); let mut elems_left = self.size; while elems_left != 0 { - debug_assert!(raw.hash != first_raw.hash); + raw.idx -= 1; - raw = raw.offset(-1); - - if *raw.hash != EMPTY_BUCKET { + if *raw.hash() != EMPTY_BUCKET { elems_left -= 1; - ptr::drop_in_place(raw.pair as *mut (K, V)); + ptr::drop_in_place(raw.pair()); } } } @@ -931,7 +916,7 @@ impl<K, V> RawTable<K, V> { /// this interface is safe, it's not used outside this module. struct RawBuckets<'a, K, V> { raw: RawBucket<K, V>, - hashes_end: *mut HashUint, + elems_left: usize, // Strictly speaking, this should be &'a (K,V), but that would // require that K:'a, and we often use RawBuckets<'static...> for @@ -946,7 +931,7 @@ impl<'a, K, V> Clone for RawBuckets<'a, K, V> { fn clone(&self) -> RawBuckets<'a, K, V> { RawBuckets { raw: self.raw, - hashes_end: self.hashes_end, + elems_left: self.elems_left, marker: marker::PhantomData, } } @@ -957,25 +942,36 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { type Item = RawBucket<K, V>; fn next(&mut self) -> Option<RawBucket<K, V>> { - while self.raw.hash != self.hashes_end { + if self.elems_left == 0 { + return None; + } + + loop { unsafe { - // We are swapping out the pointer to a bucket and replacing - // it with the pointer to the next one. - let prev = ptr::replace(&mut self.raw, self.raw.offset(1)); - if *prev.hash != EMPTY_BUCKET { - return Some(prev); + let item = self.raw; + self.raw.idx += 1; + if *item.hash() != EMPTY_BUCKET { + self.elems_left -= 1; + return Some(item); } } } + } + + fn size_hint(&self) -> (usize, Option<usize>) { + (self.elems_left, Some(self.elems_left)) + } +} - None +impl<'a, K, V> ExactSizeIterator for RawBuckets<'a, K, V> { + fn len(&self) -> usize { + self.elems_left } } /// Iterator over shared references to entries in a table. pub struct Iter<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, - elems_left: usize, } unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {} @@ -986,16 +982,13 @@ impl<'a, K, V> Clone for Iter<'a, K, V> { fn clone(&self) -> Iter<'a, K, V> { Iter { iter: self.iter.clone(), - elems_left: self.elems_left, } } } - /// Iterator over mutable references to entries in a table. pub struct IterMut<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, - elems_left: usize, // To ensure invariance with respect to V _marker: marker::PhantomData<&'a mut V>, } @@ -1009,7 +1002,6 @@ impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> { pub fn iter(&self) -> Iter<K, V> { Iter { iter: self.iter.clone(), - elems_left: self.elems_left, } } } @@ -1027,7 +1019,6 @@ impl<K, V> IntoIter<K, V> { pub fn iter(&self) -> Iter<K, V> { Iter { iter: self.iter.clone(), - elems_left: self.table.size, } } } @@ -1044,11 +1035,8 @@ unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {} impl<'a, K, V> Drain<'a, K, V> { pub fn iter(&self) -> Iter<K, V> { - unsafe { - Iter { - iter: self.iter.clone(), - elems_left: (**self.table).size, - } + Iter { + iter: self.iter.clone(), } } } @@ -1057,19 +1045,20 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.iter.next().map(|bucket| { - self.elems_left -= 1; - unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) } + self.iter.next().map(|raw| unsafe { + let pair_ptr = raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) }) } fn size_hint(&self) -> (usize, Option<usize>) { - (self.elems_left, Some(self.elems_left)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { fn len(&self) -> usize { - self.elems_left + self.iter.len() } } @@ -1077,20 +1066,20 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.iter.next().map(|bucket| { - self.elems_left -= 1; - let pair_mut = bucket.pair as *mut (K, V); - unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) } + self.iter.next().map(|raw| unsafe { + let pair_ptr = raw.pair(); + (&(*pair_ptr).0, &mut (*pair_ptr).1) }) } fn size_hint(&self) -> (usize, Option<usize>) { - (self.elems_left, Some(self.elems_left)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { fn len(&self) -> usize { - self.elems_left + self.iter.len() } } @@ -1098,23 +1087,23 @@ impl<K, V> Iterator for IntoIter<K, V> { type Item = (SafeHash, K, V); fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|bucket| { + self.iter.next().map(|raw| { self.table.size -= 1; unsafe { - let (k, v) = ptr::read(bucket.pair); - (SafeHash { hash: *bucket.hash }, k, v) + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: *raw.hash() }, k, v) } }) } fn size_hint(&self) -> (usize, Option<usize>) { - let size = self.table.size(); - (size, Some(size)) + self.iter.size_hint() } } + impl<K, V> ExactSizeIterator for IntoIter<K, V> { fn len(&self) -> usize { - self.table.size() + self.iter().len() } } @@ -1123,23 +1112,21 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { #[inline] fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|bucket| { - unsafe { - (*self.table.as_mut_ptr()).size -= 1; - let (k, v) = ptr::read(bucket.pair); - (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v) - } + self.iter.next().map(|raw| unsafe { + (*self.table.as_mut_ptr()).size -= 1; + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v) }) } fn size_hint(&self) -> (usize, Option<usize>) { - let size = unsafe { (**self.table).size() }; - (size, Some(size)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { fn len(&self) -> usize { - unsafe { (**self.table).size() } + self.iter.len() } } @@ -1152,30 +1139,21 @@ impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { impl<K: Clone, V: Clone> Clone for RawTable<K, V> { fn clone(&self) -> RawTable<K, V> { unsafe { - let mut new_ht = RawTable::new_uninitialized(self.capacity()); - - { - let cap = self.capacity(); - let mut new_buckets = Bucket::first(&mut new_ht); - let mut buckets = Bucket::first(self); - while buckets.index() != cap { - match buckets.peek() { - Full(full) => { - let (h, k, v) = { - let (k, v) = full.read(); - (full.hash(), k.clone(), v.clone()) - }; - *new_buckets.raw.hash = h.inspect(); - ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v)); - } - Empty(..) => { - *new_buckets.raw.hash = EMPTY_BUCKET; - } - } - new_buckets.next(); - buckets.next(); + let cap = self.capacity(); + let mut new_ht = RawTable::new_uninitialized(cap); + + let mut new_buckets = new_ht.raw_bucket_at(0); + let mut buckets = self.raw_bucket_at(0); + while buckets.idx < cap { + *new_buckets.hash() = *buckets.hash(); + if *new_buckets.hash() != EMPTY_BUCKET { + let pair_ptr = buckets.pair(); + let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone()); + ptr::write(new_buckets.pair(), kv); } - }; + buckets.idx += 1; + new_buckets.idx += 1; + } new_ht.size = self.size(); @@ -1186,7 +1164,7 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> { unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> { fn drop(&mut self) { - if self.capacity == 0 { + if self.capacity() == 0 { return; } @@ -1202,8 +1180,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> { } } - let hashes_size = self.capacity * size_of::<HashUint>(); - let pairs_size = self.capacity * size_of::<(K, V)>(); + let hashes_size = self.capacity() * size_of::<HashUint>(); + let pairs_size = self.capacity() * size_of::<(K, V)>(); let (align, _, size, oflo) = calculate_allocation(hashes_size, align_of::<HashUint>(), pairs_size, diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index ca26dc9527c..6b1267d89b6 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1176,6 +1176,7 @@ impl AsInner<fs_imp::DirEntry> for DirEntry { /// This function currently corresponds to the `unlink` function on Unix /// and the `DeleteFile` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1212,6 +1213,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> { /// This function currently corresponds to the `stat` function on Unix /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1245,6 +1247,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { /// This function currently corresponds to the `lstat` function on Unix /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1287,6 +1290,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> { /// on Windows, `from` can be anything, but `to` must *not* be a directory. /// /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1330,6 +1334,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> /// `O_CLOEXEC` is set for returned file descriptors. /// On Windows, this function currently corresponds to `CopyFileEx`. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1366,6 +1371,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> { /// This function currently corresponds to the `link` function on Unix /// and the `CreateHardLink` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1424,6 +1430,7 @@ pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<( /// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1457,6 +1464,7 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { /// This function currently corresponds to the `realpath` function on Unix /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1489,6 +1497,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { /// This function currently corresponds to the `mkdir` function on Unix /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1522,6 +1531,7 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// This function currently corresponds to the `mkdir` function on Unix /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1562,6 +1572,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { /// This function currently corresponds to the `rmdir` function on Unix /// and the `RemoveDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1599,6 +1610,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> { /// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions /// on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1633,6 +1645,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> { /// This function currently corresponds to the `opendir` function on Unix /// and the `FindFirstFile` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1679,6 +1692,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> { /// This function currently corresponds to the `chmod` function on Unix /// and the `SetFileAttributes` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1726,9 +1740,9 @@ impl DirBuilder { } } - /// Indicate that directories create should be created recursively, creating - /// all parent directories if they do not exist with the same security and - /// permissions settings. + /// Indicates that directories should be created recursively, creating all + /// parent directories. Parents that do not exist are created with the same + /// security and permissions settings. /// /// This option defaults to `false`. /// @@ -1749,6 +1763,9 @@ impl DirBuilder { /// Create the specified directory with the options configured in this /// builder. /// + /// It is considered an error if the directory already exists unless + /// recursive mode is enabled. + /// /// # Examples /// /// ```no_run diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index f98a3a87b01..3b82412716e 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -21,12 +21,12 @@ use memchr; /// The `BufReader` struct adds buffering to any reader. /// /// It can be excessively inefficient to work directly with a [`Read`] instance. -/// For example, every call to [`read`] on [`TcpStream`] results in a system call. -/// A `BufReader` performs large, infrequent reads on the underlying [`Read`] -/// and maintains an in-memory buffer of the results. +/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] +/// results in a system call. A `BufReader` performs large, infrequent reads on +/// the underlying [`Read`] and maintains an in-memory buffer of the results. /// /// [`Read`]: ../../std/io/trait.Read.html -/// [`read`]: ../../std/net/struct.TcpStream.html#method.read +/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read /// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// /// # Examples @@ -261,9 +261,10 @@ impl<R: Seek> Seek for BufReader<R> { /// Wraps a writer and buffers its output. /// /// It can be excessively inefficient to work directly with something that -/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`] -/// results in a system call. A `BufWriter` keeps an in-memory buffer of data -/// and writes it to an underlying writer in large, infrequent batches. +/// implements [`Write`]. For example, every call to +/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A +/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying +/// writer in large, infrequent batches. /// /// The buffer will be written out when the writer is dropped. /// @@ -303,7 +304,7 @@ impl<R: Seek> Seek for BufReader<R> { /// the `stream` is dropped. /// /// [`Write`]: ../../std/io/trait.Write.html -/// [`write`]: ../../std/net/struct.TcpStream.html#method.write +/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write /// [`TcpStream`]: ../../std/net/struct.TcpStream.html #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter<W: Write> { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 8ebc5c0a8fe..cd096c115ba 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -21,7 +21,8 @@ //! 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<T>`]s. For -//! example, [`Read`] adds a [`read`] method, which we can use on `File`s: +//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on +//! `File`s: //! //! ``` //! use std::io; @@ -106,7 +107,7 @@ //! ``` //! //! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call -//! to [`write`]: +//! to [`write`][`Write::write`]: //! //! ``` //! use std::io; @@ -257,13 +258,13 @@ //! [`Vec<T>`]: ../vec/struct.Vec.html //! [`BufReader`]: struct.BufReader.html //! [`BufWriter`]: struct.BufWriter.html -//! [`write`]: trait.Write.html#tymethod.write +//! [`Write::write`]: trait.Write.html#tymethod.write //! [`io::stdout`]: fn.stdout.html //! [`println!`]: ../macro.println.html //! [`Lines`]: struct.Lines.html //! [`io::Result`]: type.Result.html //! [`?` operator]: ../../book/syntax-index.html -//! [`read`]: trait.Read.html#tymethod.read +//! [`Read::read`]: trait.Read.html#tymethod.read #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index cf119720e5a..bc315d54100 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -58,7 +58,7 @@ pub struct TcpStream(net_imp::TcpStream); /// /// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens /// for incoming TCP connections. These can be accepted by calling [`accept`] or by -/// iterating over the [`Incoming`] iterator returned by [`incoming`]. +/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`]. /// /// The socket will be closed when the value is dropped. /// @@ -68,7 +68,7 @@ pub struct TcpStream(net_imp::TcpStream); /// [`bind`]: #method.bind /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [`Incoming`]: ../../std/net/struct.Incoming.html -/// [`incoming`]: #method.incoming +/// [`TcpListener::incoming`]: #method.incoming /// /// # Examples /// diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index c71e0b2a703..86e661d7948 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -56,14 +56,14 @@ //! traits indicate fundamental properties of types. //! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various //! operations for both destructors and overloading `()`. -//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a -//! value. +//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly +//! dropping a value. //! * [`std::boxed`]::[`Box`], a way to allocate values on the heap. //! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines //! [`to_owned`], the generic method for creating an owned type from a //! borrowed type. -//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone`], -//! the method for producing a copy of a value. +//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines +//! [`clone`][`Clone::clone`], the method for producing a copy of a value. //! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The //! comparison traits, which implement the comparison operators and are often //! seen in trait bounds. @@ -117,8 +117,8 @@ //! [`ToOwned`]: ../borrow/trait.ToOwned.html //! [`ToString`]: ../string/trait.ToString.html //! [`Vec`]: ../vec/struct.Vec.html -//! [`clone`]: ../clone/trait.Clone.html#tymethod.clone -//! [`drop`]: ../mem/fn.drop.html +//! [`Clone::clone`]: ../clone/trait.Clone.html#tymethod.clone +//! [`mem::drop`]: ../mem/fn.drop.html //! [`std::borrow`]: ../borrow/index.html //! [`std::boxed`]: ../boxed/index.html //! [`std::clone`]: ../clone/index.html diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 7f1a00c707c..8cfd8fcd8c6 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1070,6 +1070,27 @@ pub fn exit(code: i32) -> ! { /// // execution never gets here /// } /// ``` +/// +/// The [`abort`] function terminates the process, so the destructor will not +/// get run on the example below: +/// +/// ```no_run +/// use std::process; +/// +/// struct HasDrop; +/// +/// impl Drop for HasDrop { +/// fn drop(&mut self) { +/// println!("This will never be printed!"); +/// } +/// } +/// +/// fn main() { +/// let _x = HasDrop; +/// process::abort(); +/// // the destructor implemented for HasDrop will never get run +/// } +/// ``` #[stable(feature = "process_abort", since = "1.17.0")] pub fn abort() -> ! { unsafe { ::sys::abort_internal() }; diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index 295a49d6a8e..a7b01e49d2b 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -50,12 +50,11 @@ struct BarrierState { generation_id: usize, } -/// A result returned from wait. +/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`] +/// have rendezvoused. /// -/// Currently this opaque structure only has one method, [`.is_leader`]. Only -/// one thread will receive a result that will return `true` from this function. -/// -/// [`.is_leader`]: #method.is_leader +/// [`wait`]: struct.Barrier.html#method.wait +/// [`Barrier`]: struct.Barrier.html /// /// # Examples /// diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 71dd94161c0..0da65a4f2e1 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -13,40 +13,50 @@ //! This module provides message-based communication over channels, concretely //! defined among three types: //! -//! * `Sender` -//! * `SyncSender` -//! * `Receiver` +//! * [`Sender`] +//! * [`SyncSender`] +//! * [`Receiver`] //! -//! A `Sender` or `SyncSender` is used to send data to a `Receiver`. Both +//! A [`Sender`] or [`SyncSender`] is used to send data to a [`Receiver`]. Both //! senders are clone-able (multi-producer) such that many threads can send //! simultaneously to one receiver (single-consumer). //! //! These channels come in two flavors: //! -//! 1. An asynchronous, infinitely buffered channel. The `channel()` function +//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function //! will return a `(Sender, Receiver)` tuple where all sends will be //! **asynchronous** (they never block). The channel conceptually has an //! infinite buffer. //! -//! 2. A synchronous, bounded channel. The `sync_channel()` function will return -//! a `(SyncSender, Receiver)` tuple where the storage for pending messages -//! is a pre-allocated buffer of a fixed size. All sends will be +//! 2. A synchronous, bounded channel. The [`sync_channel`] function will +//! return a `(SyncSender, Receiver)` tuple where the storage for pending +//! messages is a pre-allocated buffer of a fixed size. All sends will be //! **synchronous** by blocking until there is buffer space available. Note -//! that a bound of 0 is allowed, causing the channel to become a -//! "rendezvous" channel where each sender atomically hands off a message to -//! a receiver. +//! that a bound of 0 is allowed, causing the channel to become a "rendezvous" +//! channel where each sender atomically hands off a message to a receiver. +//! +//! [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html +//! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html +//! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html +//! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +//! [`channel`]: ../../../std/sync/mpsc/fn.channel.html +//! [`sync_channel`]: ../../../std/sync/mpsc/fn.sync_channel.html //! //! ## Disconnection //! -//! The send and receive operations on channels will all return a `Result` +//! The send and receive operations on channels will all return a [`Result`] //! indicating whether the operation succeeded or not. An unsuccessful operation //! is normally indicative of the other half of a channel having "hung up" by //! being dropped in its corresponding thread. //! //! Once half of a channel has been deallocated, most operations can no longer -//! continue to make progress, so `Err` will be returned. Many applications will -//! continue to `unwrap()` the results returned from this module, instigating a -//! propagation of failure among threads if one unexpectedly dies. +//! continue to make progress, so [`Err`] will be returned. Many applications +//! will continue to [`unwrap`] the results returned from this module, +//! instigating a propagation of failure among threads if one unexpectedly dies. +//! +//! [`Result`]: ../../../std/result/enum.Result.html +//! [`Err`]: ../../../std/result/enum.Result.html#variant.Err +//! [`unwrap`]: ../../../std/result/enum.Result.html#method.unwrap //! //! # Examples //! @@ -288,7 +298,31 @@ mod mpsc_queue; mod spsc_queue; /// The receiving-half of Rust's channel type. This half can only be owned by -/// one thread +/// one thread. +/// +/// Messages sent to the channel can be retrieved using [`recv`]. +/// +/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (send, recv) = channel(); +/// +/// thread::spawn(move || { +/// send.send("Hello world!").unwrap(); +/// thread::sleep(Duration::from_secs(2)); // block for two seconds +/// send.send("Delayed for 2 seconds").unwrap(); +/// }); +/// +/// println!("{}", recv.recv().unwrap()); // Received immediately +/// println!("Waiting..."); +/// println!("{}", recv.recv().unwrap()); // Received after 2 seconds +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Receiver<T> { inner: UnsafeCell<Flavor<T>>, @@ -302,9 +336,12 @@ unsafe impl<T: Send> Send for Receiver<T> { } #[stable(feature = "rust1", since = "1.0.0")] impl<T> !Sync for Receiver<T> { } -/// An iterator over messages on a receiver, this iterator will block -/// whenever `next` is called, waiting for a new message, and `None` will be -/// returned when the corresponding channel has hung up. +/// An iterator over messages on a receiver, this iterator will block whenever +/// [`next`] is called, waiting for a new message, and [`None`] will be returned +/// when the corresponding channel has hung up. +/// +/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next +/// [`None`]: ../../../std/option/enum.Option.html#variant.None #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, T: 'a> { @@ -312,11 +349,13 @@ pub struct Iter<'a, T: 'a> { } /// An iterator that attempts to yield all pending values for a receiver. -/// `None` will be returned when there are no pending values remaining or -/// if the corresponding channel has hung up. +/// [`None`] will be returned when there are no pending values remaining or if +/// the corresponding channel has hung up. /// /// This Iterator will never block the caller in order to wait for data to -/// become available. Instead, it will return `None`. +/// become available. Instead, it will return [`None`]. +/// +/// [`None`]: ../../../std/option/enum.Option.html#variant.None #[stable(feature = "receiver_try_iter", since = "1.15.0")] #[derive(Debug)] pub struct TryIter<'a, T: 'a> { @@ -324,8 +363,12 @@ pub struct TryIter<'a, T: 'a> { } /// An owning iterator over messages on a receiver, this iterator will block -/// whenever `next` is called, waiting for a new message, and `None` will be +/// whenever [`next`] is called, waiting for a new message, and [`None`] will be /// returned when the corresponding channel has hung up. +/// +/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next +/// [`None`]: ../../../std/option/enum.Option.html#variant.None +/// #[stable(feature = "receiver_into_iter", since = "1.1.0")] #[derive(Debug)] pub struct IntoIter<T> { @@ -334,6 +377,35 @@ pub struct IntoIter<T> { /// The sending-half of Rust's asynchronous channel type. This half can only be /// owned by one thread, but it can be cloned to send to other threads. +/// +/// Messages can be sent through this channel with [`send`]. +/// +/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// +/// # Examples +/// +/// ```rust +/// use std::sync::mpsc::channel; +/// use std::thread; +/// +/// let (sender, receiver) = channel(); +/// let sender2 = sender.clone(); +/// +/// // First thread owns sender +/// thread::spawn(move || { +/// sender.send(1).unwrap(); +/// }); +/// +/// // Second thread owns sender2 +/// thread::spawn(move || { +/// sender2.send(2).unwrap(); +/// }); +/// +/// let msg = receiver.recv().unwrap(); +/// let msg2 = receiver.recv().unwrap(); +/// +/// assert_eq!(3, msg + msg2); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Sender<T> { inner: UnsafeCell<Flavor<T>>, @@ -349,6 +421,10 @@ impl<T> !Sync for Sender<T> { } /// The sending-half of Rust's synchronous channel type. This half can only be /// owned by one thread, but it can be cloned to send to other threads. +/// +/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send +/// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send +/// #[stable(feature = "rust1", since = "1.0.0")] pub struct SyncSender<T> { inner: Arc<sync::Packet<T>>, @@ -360,25 +436,32 @@ unsafe impl<T: Send> Send for SyncSender<T> {} #[stable(feature = "rust1", since = "1.0.0")] impl<T> !Sync for SyncSender<T> {} -/// An error returned from the `send` function on channels. +/// An error returned from the [`send`] function on channels. /// -/// A `send` operation can only fail if the receiving end of a channel is +/// A [`send`] operation can only fail if the receiving end of a channel is /// disconnected, implying that the data could never be received. The error /// contains the data being sent as a payload so it can be recovered. +/// +/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T); -/// An error returned from the `recv` function on a `Receiver`. +/// An error returned from the [`recv`] function on a [`Receiver`]. /// -/// The `recv` operation can only fail if the sending half of a channel is +/// The [`recv`] operation can only fail if the sending half of a channel is /// disconnected, implying that no further messages will ever be received. +/// +/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv +/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RecvError; -/// This enumeration is the list of the possible reasons that `try_recv` could +/// This enumeration is the list of the possible reasons that [`try_recv`] could /// not return data when called. +/// +/// [`try_recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.try_recv #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum TryRecvError { @@ -393,8 +476,10 @@ pub enum TryRecvError { Disconnected, } -/// This enumeration is the list of possible errors that `recv_timeout` could +/// This enumeration is the list of possible errors that [`recv_timeout`] could /// not return data when called. +/// +/// [`recv_timeout`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv_timeout #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")] pub enum RecvTimeoutError { @@ -409,7 +494,9 @@ pub enum RecvTimeoutError { } /// This enumeration is the list of the possible error outcomes for the -/// `SyncSender::try_send` method. +/// [`SyncSender::try_send`] method. +/// +/// [`SyncSender::try_send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.try_send #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] pub enum TrySendError<T> { @@ -556,10 +643,13 @@ impl<T> Sender<T> { /// A successful send occurs when it is determined that the other end of /// the channel has not hung up already. An unsuccessful send would be one /// where the corresponding receiver has already been deallocated. Note - /// that a return value of `Err` means that the data will never be - /// received, but a return value of `Ok` does *not* mean that the data + /// that a return value of [`Err`] means that the data will never be + /// received, but a return value of [`Ok`] does *not* mean that the data /// will be received. It is possible for the corresponding receiver to - /// hang up immediately after this function returns `Ok`. + /// hang up immediately after this function returns [`Ok`]. + /// + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// [`Ok`]: ../../../std/result/enum.Result.html#variant.Ok /// /// This method will never block the current thread. /// @@ -702,9 +792,12 @@ impl<T> SyncSender<T> { /// time. If the buffer size is 0, however, it can be guaranteed that the /// receiver has indeed received the data if this function returns success. /// - /// This function will never panic, but it may return `Err` if the - /// `Receiver` has disconnected and is no longer able to receive + /// This function will never panic, but it may return [`Err`] if the + /// [`Receiver`] has disconnected and is no longer able to receive /// information. + /// + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html #[stable(feature = "rust1", since = "1.0.0")] pub fn send(&self, t: T) -> Result<(), SendError<T>> { self.inner.send(t).map_err(SendError) @@ -712,13 +805,16 @@ impl<T> SyncSender<T> { /// Attempts to send a value on this channel without blocking. /// - /// This method differs from `send` by returning immediately if the + /// This method differs from [`send`] by returning immediately if the /// channel's buffer is full or no receiver is waiting to acquire some - /// data. Compared with `send`, this function has two failure cases + /// data. Compared with [`send`], this function has two failure cases /// instead of one (one for disconnection, one for a full buffer). /// - /// See `SyncSender::send` for notes about guarantees of whether the + /// See [`SyncSender::send`] for notes about guarantees of whether the /// receiver has received the data or not if this function is successful. + /// + /// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send + /// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send #[stable(feature = "rust1", since = "1.0.0")] pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> { self.inner.try_send(t) @@ -819,15 +915,18 @@ impl<T> Receiver<T> { /// /// This function will always block the current thread if there is no data /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding `Sender`, then this receiver will wake up and + /// sent to the corresponding [`Sender`], then this receiver will wake up and /// return that message. /// - /// If the corresponding `Sender` has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return `Err` to + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to /// indicate that no more messages can ever be received on this channel. /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// + /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// /// # Examples /// /// ``` @@ -907,15 +1006,18 @@ impl<T> Receiver<T> { /// /// This function will always block the current thread if there is no data /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding `Sender`, then this receiver will wake up and + /// sent to the corresponding [`Sender`], then this receiver will wake up and /// return that message. /// - /// If the corresponding `Sender` has disconnected, or it disconnects while - /// this call is blocking, this call will wake up and return `Err` to + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to /// indicate that no more messages can ever be received on this channel. /// However, since channels are buffered, messages sent before the disconnect /// will still be properly received. /// + /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html + /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err + /// /// # Examples /// /// ```no_run @@ -993,7 +1095,29 @@ impl<T> Receiver<T> { } /// Returns an iterator that will block waiting for messages, but never - /// `panic!`. It will return `None` when the channel has hung up. + /// [`panic!`]. It will return [`None`] when the channel has hung up. + /// + /// [`panic!`]: ../../../std/macro.panic.html + /// [`None`]: ../../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ```rust + /// use std::sync::mpsc::channel; + /// use std::thread; + /// + /// let (send, recv) = channel(); + /// + /// thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// send.send(2u8).unwrap(); + /// send.send(3u8).unwrap(); + /// }); + /// + /// for x in recv.iter() { + /// println!("Got: {}", x); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<T> { Iter { rx: self } @@ -1001,8 +1125,10 @@ impl<T> Receiver<T> { /// Returns an iterator that will attempt to yield all pending values. /// It will return `None` if there are no more pending values or if the - /// channel has hung up. The iterator will never `panic!` or block the + /// channel has hung up. The iterator will never [`panic!`] or block the /// user by waiting for values. + /// + /// [`panic!`]: ../../../std/macro.panic.html #[stable(feature = "receiver_try_iter", since = "1.15.0")] pub fn try_iter(&self) -> TryIter<T> { TryIter { rx: self } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index d79be2944c9..f2c178a1ad5 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -30,7 +30,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// /// The mutexes in this module implement a strategy called "poisoning" where a /// mutex is considered poisoned whenever a thread panics while holding the -/// lock. Once a mutex is poisoned, all other threads are unable to access the +/// mutex. Once a mutex is poisoned, all other threads are unable to access the /// data by default as it is likely tainted (some invariant is not being /// upheld). /// @@ -115,7 +115,7 @@ pub struct Mutex<T: ?Sized> { // Note that this mutex is in a *box*, not inlined into the struct itself. // Once a native mutex has been used once, its address can never change (it // can't be moved). This mutex type can be safely moved at any time, so to - // ensure that the native mutex is used correctly we box the inner lock to + // ensure that the native mutex is used correctly we box the inner mutex to // give it a constant address. inner: Box<sys::Mutex>, poison: poison::Flag, @@ -183,7 +183,7 @@ impl<T: ?Sized> Mutex<T> { /// Acquires a mutex, blocking the current thread until it is able to do so. /// /// This function will block the local thread until it is available to acquire - /// the mutex. Upon returning, the thread is the only thread with the mutex + /// the mutex. Upon returning, the thread is the only thread with the lock /// held. An RAII guard is returned to allow scoped unlock of the lock. When /// the guard goes out of scope, the mutex will be unlocked. /// @@ -267,9 +267,9 @@ impl<T: ?Sized> Mutex<T> { } } - /// Determines whether the lock is poisoned. + /// Determines whether the mutex is poisoned. /// - /// If another thread is active, the lock can still become poisoned at any + /// If another thread is active, the mutex can still become poisoned at any /// time. You should not trust a `false` value for program correctness /// without additional synchronization. /// @@ -312,7 +312,7 @@ impl<T: ?Sized> Mutex<T> { #[stable(feature = "mutex_into_inner", since = "1.6.0")] pub fn into_inner(self) -> LockResult<T> where T: Sized { // We know statically that there are no outstanding references to - // `self` so there's no need to lock the inner lock. + // `self` so there's no need to lock the inner mutex. // // To get the inner value, we'd like to call `data.into_inner()`, // but because `Mutex` impl-s `Drop`, we can't move out of it, so @@ -353,7 +353,7 @@ impl<T: ?Sized> Mutex<T> { #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { // We know statically that there are no other references to `self`, so - // there's no need to lock the inner lock. + // there's no need to lock the inner mutex. let data = unsafe { &mut *self.data.get() }; poison::map_result(self.poison.borrow(), |_| data ) } diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 75aa72e3cff..296235e173d 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -73,13 +73,6 @@ pub trait IntoRawFd { } #[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for RawFd { - fn as_raw_fd(&self) -> RawFd { - *self - } -} - -#[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().raw() @@ -91,14 +84,6 @@ impl FromRawFd for fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for RawFd { - fn into_raw_fd(self) -> RawFd { - self - } -} - #[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawFd for fs::File { fn into_raw_fd(self) -> RawFd { diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index c57751a01d7..854d380d128 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -92,7 +92,7 @@ pub fn init() { #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))] unsafe fn reset_sigpipe() { - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0); + assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))] unsafe fn reset_sigpipe() {} diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 51e00fc1ab9..706256ff10e 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use cmp; use io; use libc::{self, c_int}; use mem; -use ptr; use sys::{cvt, cvt_r}; use sys::fd::FileDesc; @@ -80,16 +78,14 @@ pub fn read2(p1: AnonPipe, p1.set_nonblocking(true)?; p2.set_nonblocking(true)?; - let max = cmp::max(p1.raw(), p2.raw()); + let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; + fds[0].fd = p1.raw(); + fds[0].events = libc::POLLIN; + fds[1].fd = p2.raw(); + fds[1].events = libc::POLLIN; loop { - // wait for either pipe to become readable using `select` - cvt_r(|| unsafe { - let mut read: libc::fd_set = mem::zeroed(); - libc::FD_SET(p1.raw(), &mut read); - libc::FD_SET(p2.raw(), &mut read); - libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(), - ptr::null_mut()) - })?; + // wait for either pipe to become readable using `poll` + cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; // Read as much as we can from each pipe, ignoring EWOULDBLOCK or // EAGAIN. If we hit EOF, then this will happen because the underlying @@ -109,11 +105,11 @@ pub fn read2(p1: AnonPipe, } } }; - if read(&p1, v1)? { + if fds[0].revents != 0 && read(&p1, v1)? { p2.set_nonblocking(false)?; return p2.read_to_end(v2).map(|_| ()); } - if read(&p2, v2)? { + if fds[1].revents != 0 && read(&p2, v2)? { p1.set_nonblocking(false)?; return p1.read_to_end(v1).map(|_| ()); } diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index c63dd8a47ca..d6e2fed56be 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -144,7 +144,7 @@ pub trait OpenOptionsExt { /// `CreateFile`). /// /// If a _new_ file is created because it does not yet exist and - ///`.create(true)` or `.create_new(true)` are specified, the new file is + /// `.create(true)` or `.create_new(true)` are specified, the new file is /// given the attributes declared with `.attributes()`. /// /// If an _existing_ file is opened with `.create(true).truncate(true)`, its diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 1419a4af427..759f055c4b1 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -104,6 +104,7 @@ pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. /// /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. + /// /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx #[stable(feature = "windows_process_extensions", since = "1.16.0")] fn creation_flags(&mut self, flags: u32) -> &mut process::Command; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index edf928d6106..7ab6b82ada3 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -90,7 +90,7 @@ //! two ways: //! //! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] -//! function, and calling [`thread`] on the [`JoinHandle`]. +//! function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`]. //! * By requesting the current thread, using the [`thread::current`] function. //! //! The [`thread::current`] function is available even for threads not spawned @@ -151,14 +151,14 @@ //! [`Arc`]: ../../std/sync/struct.Arc.html //! [`spawn`]: ../../std/thread/fn.spawn.html //! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -//! [`thread`]: ../../std/thread/struct.JoinHandle.html#method.thread +//! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread //! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join //! [`Result`]: ../../std/result/enum.Result.html //! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok //! [`Err`]: ../../std/result/enum.Result.html#variant.Err //! [`panic!`]: ../../std/macro.panic.html //! [`Builder`]: ../../std/thread/struct.Builder.html -//! [`thread::current`]: ../../std/thread/fn.spawn.html +//! [`thread::current`]: ../../std/thread/fn.current.html //! [`Thread`]: ../../std/thread/struct.Thread.html //! [`park`]: ../../std/thread/fn.park.html //! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index c79040424f6..e7c5d8278d9 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -26,7 +26,8 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec return true; } - match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) { + match attr.parse_list(cx.parse_sess, + |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) { Ok(ref traits) if traits.is_empty() => { cx.span_warn(attr.span, "empty trait list in `derive`"); false diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 12d25ca4274..550f1160bed 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -292,9 +292,6 @@ declare_features! ( // Allows attributes on lifetime/type formal parameters in generics (RFC 1327) (active, generic_param_attrs, "1.11.0", Some(34761)), - // The #![windows_subsystem] attribute - (active, windows_subsystem, "1.14.0", Some(37499)), - // Allows #[link(..., cfg(..))] (active, link_cfg, "1.14.0", Some(37406)), @@ -337,11 +334,15 @@ declare_features! ( // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), + // Allows the `catch {...}` expression (active, catch_expr, "1.17.0", Some(31436)), // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), + + // Used to preserve symbols (see llvm.used) + (active, used, "1.18.0", Some(40289)), ); declare_features! ( @@ -408,7 +409,8 @@ declare_features! ( (accepted, static_recursion, "1.17.0", Some(29719)), // pub(restricted) visibilities (RFC 1422) (accepted, pub_restricted, "1.17.0", Some(32409)), - + // The #![windows_subsystem] attribute + (accepted, windows_subsystem, "1.18.0", Some(37499)), ); // If you change this, please modify src/doc/unstable-book as well. You must // move that documentation into the relevant place in the other docs, and @@ -748,6 +750,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "unwind_attributes", "#[unwind] is experimental", cfg_fn!(unwind_attributes))), + ("used", Whitelisted, Gated( + Stability::Unstable, "used", + "the `#[used]` attribute is an experimental feature", + cfg_fn!(used))), // used in resolve ("prelude_import", Whitelisted, Gated(Stability::Unstable, @@ -768,11 +774,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "unboxed_closures are still evolving", cfg_fn!(unboxed_closures))), - ("windows_subsystem", Whitelisted, Gated(Stability::Unstable, - "windows_subsystem", - "the windows subsystem attribute \ - is currently unstable", - cfg_fn!(windows_subsystem))), + ("windows_subsystem", Whitelisted, Ungated), ("proc_macro_attribute", Normal, Gated(Stability::Unstable, "proc_macro", diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 23fc1351426..43d21015a4f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -570,20 +570,33 @@ impl<'a> Parser<'a> { expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); - Err(self.fatal( - &(if expected.len() > 1 { - (format!("expected one of {}, found `{}`", - expect, - actual)) - } else if expected.is_empty() { - (format!("unexpected token: `{}`", - actual)) + let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let short_expect = if expected.len() > 6 { + format!("{} possible tokens", expected.len()) } else { - (format!("expected {}, found `{}`", - expect, - actual)) - })[..] - )) + expect.clone() + }; + (format!("expected one of {}, found `{}`", expect, actual), + (self.prev_span.next_point(), format!("expected one of {} here", short_expect))) + } else if expected.is_empty() { + (format!("unexpected token: `{}`", actual), + (self.prev_span, "unexpected token after this".to_string())) + } else { + (format!("expected {}, found `{}`", expect, actual), + (self.prev_span.next_point(), format!("expected {} here", expect))) + }; + let mut err = self.fatal(&msg_exp); + let sp = if self.token == token::Token::Eof { + // This is EOF, don't want to point at the following char, but rather the last token + self.prev_span + } else { + label_sp + }; + err.span_label(sp, &label_exp); + if !sp.source_equal(&self.span) { + err.span_label(self.span, &"unexpected token"); + } + Err(err) } } @@ -1773,6 +1786,26 @@ impl<'a> Parser<'a> { }) } + /// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat. + /// This is used when parsing derive macro paths in `#[derive]` attributes. + pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { + let meta_ident = match self.token { + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref meta) => match meta.node { + ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)), + _ => None, + }, + _ => None, + }, + _ => None, + }; + if let Some(ident) = meta_ident { + self.bump(); + return Ok(ast::Path::from_ident(self.prev_span, ident)); + } + self.parse_path(mode) + } + /// Examples: /// - `a::b<T,U>::c<V,W>` /// - `a::b<T,U>::c(V) -> W` @@ -4667,25 +4700,30 @@ impl<'a> Parser<'a> { }) } - fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) { - match *visa { - Visibility::Inherited => (), + fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) { + if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) { + err.emit(); + } + } + + fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> { + match *vis { + Visibility::Inherited => Ok(()), _ => { let is_macro_rules: bool = match self.token { token::Ident(sid) => sid.name == Symbol::intern("macro_rules"), _ => false, }; if is_macro_rules { - self.diagnostic().struct_span_err(span, "can't qualify macro_rules \ - invocation with `pub`") - .help("did you mean #[macro_export]?") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); + err.help("did you mean #[macro_export]?"); + Err(err) } else { - self.diagnostic().struct_span_err(span, "can't qualify macro \ - invocation with `pub`") - .help("try adjusting the macro to put `pub` \ - inside the invocation") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro invocation with `pub`"); + err.help("try adjusting the macro to put `pub` inside the invocation"); + Err(err) } } } @@ -4696,14 +4734,36 @@ impl<'a> Parser<'a> { -> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if self.token.is_path_start() { - // method macro. + // Method macro. let prev_span = self.prev_span; - self.complain_if_pub_macro(&vis, prev_span); + // Before complaining about trying to set a macro as `pub`, + // check if `!` comes after the path. + let err = self.complain_if_pub_macro_diag(&vis, prev_span); let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; + let bang_err = self.expect(&token::Not); + if let Err(mut err) = err { + if let Err(mut bang_err) = bang_err { + // Given this code `pub path(`, it seems like this is not setting the + // visibility of a macro invocation, but rather a mistyped method declaration. + // Create a diagnostic pointing out that `fn` is missing. + // + // x | pub path(&self) { + // | ^ missing `fn` for method declaration + + err.cancel(); + bang_err.cancel(); + // pub path( + // ^^ `sp` below will point to this + let sp = prev_span.between(self.prev_span); + err = self.diagnostic() + .struct_span_err(sp, "missing `fn` for method declaration"); + err.span_label(sp, &"missing `fn`"); + } + return Err(err); + } // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 58750158931..15111bbba0a 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -43,6 +43,8 @@ use std::{mem, ptr, slice, vec}; use serialize::{Encodable, Decodable, Encoder, Decoder}; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; /// An owned smart pointer. #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct P<T: ?Sized> { @@ -215,3 +217,13 @@ impl<T: Decodable> Decodable for P<[T]> { })) } } + +impl<CTX, T> HashStable<CTX> for P<T> + where T: ?Sized + HashStable<CTX> +{ + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut CTX, + hasher: &mut StableHasher<W>) { + (**self).hash_stable(hcx, hasher); + } +} diff --git a/src/libsyntax/util/rc_slice.rs b/src/libsyntax/util/rc_slice.rs index 195fb23f9d8..2d9fd7aa875 100644 --- a/src/libsyntax/util/rc_slice.rs +++ b/src/libsyntax/util/rc_slice.rs @@ -12,6 +12,9 @@ use std::fmt; use std::ops::Deref; use std::rc::Rc; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; + #[derive(Clone)] pub struct RcSlice<T> { data: Rc<Box<[T]>>, @@ -41,3 +44,13 @@ impl<T: fmt::Debug> fmt::Debug for RcSlice<T> { fmt::Debug::fmt(self.deref(), f) } } + +impl<CTX, T> HashStable<CTX> for RcSlice<T> + where T: HashStable<CTX> +{ + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut CTX, + hasher: &mut StableHasher<W>) { + (**self).hash_stable(hcx, hasher); + } +} diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 947192a0a23..9b88b9f7696 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -83,7 +83,13 @@ impl Span { /// Returns a new span representing just the end-point of this span pub fn end_point(self) -> Span { let lo = cmp::max(self.hi.0 - 1, self.lo.0); - Span { lo: BytePos(lo), hi: self.hi, ctxt: self.ctxt } + Span { lo: BytePos(lo), ..self } + } + + /// Returns a new span representing the next character after the end-point of this span + pub fn next_point(self) -> Span { + let lo = cmp::max(self.hi.0, self.lo.0 + 1); + Span { lo: BytePos(lo), hi: BytePos(lo + 1), ..self } } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. @@ -183,6 +189,30 @@ impl Span { Span { hi: end.hi, ..self } } } + + pub fn between(self, end: Span) -> Span { + Span { + lo: self.hi, + hi: end.lo, + ctxt: if end.ctxt == SyntaxContext::empty() { + end.ctxt + } else { + self.ctxt + } + } + } + + pub fn until(self, end: Span) -> Span { + Span { + lo: self.lo, + hi: end.lo, + ctxt: if end.ctxt == SyntaxContext::empty() { + end.ctxt + } else { + self.ctxt + } + } + } } #[derive(Clone, Debug)] diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 077d57a9da3..f04394f7166 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -39,8 +39,10 @@ pub trait Stats { /// /// Note: this method sacrifices performance at the altar of accuracy /// Depends on IEEE-754 arithmetic guarantees. See proof of correctness at: - /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates"] - /// (http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps) + /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric + /// Predicates"][paper] + /// + /// [paper]: http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps fn sum(&self) -> f64; /// Minimum value of the samples. diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index ed3d5212bf2..9b8099d55a0 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -35,7 +35,8 @@ fn main() { } else if target.contains("dragonfly") { println!("cargo:rustc-link-lib=gcc_pic"); } else if target.contains("windows-gnu") { - println!("cargo:rustc-link-lib=gcc_eh"); + println!("cargo:rustc-link-lib=static-nobundle=gcc_eh"); + println!("cargo:rustc-link-lib=static-nobundle=pthread"); } else if target.contains("fuchsia") { println!("cargo:rustc-link-lib=unwind"); } diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 7fa2ce650fd..d4d52322ada 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -17,6 +17,7 @@ #![feature(cfg_target_vendor)] #![feature(staged_api)] #![feature(unwind_attributes)] +#![feature(static_nobundle)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs new file mode 100644 index 00000000000..e0de64b26df --- /dev/null +++ b/src/test/codegen/personality_lifetimes.rs @@ -0,0 +1,41 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-msvc + +// compile-flags: -O -C no-prepopulate-passes + +#![crate_type="lib"] + +struct S; + +impl Drop for S { + fn drop(&mut self) { + } +} + +fn might_unwind() { +} + +// CHECK-LABEL: @test +#[no_mangle] +pub fn test() { + let _s = S; + // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just + // in the first one. + // CHECK-LABEL: cleanup: + // CHECK: bitcast{{.*}}personalityslot + // CHECK-NEXT: call void @llvm.lifetime.start + // CHECK-LABEL: cleanup1: + // CHECK: bitcast{{.*}}personalityslot + // CHECK-NEXT: call void @llvm.lifetime.start + might_unwind(); + might_unwind(); +} diff --git a/src/test/compile-fail/feature-gate-used.rs b/src/test/compile-fail/feature-gate-used.rs new file mode 100644 index 00000000000..68679d7dac8 --- /dev/null +++ b/src/test/compile-fail/feature-gate-used.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[used] +fn foo() {} +//~^^ ERROR the `#[used]` attribute is an experimental feature + +fn main() {} diff --git a/src/test/compile-fail/issue-40610.rs b/src/test/compile-fail/issue-40610.rs new file mode 100644 index 00000000000..aec20b4ad87 --- /dev/null +++ b/src/test/compile-fail/issue-40610.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn f(_: &[f32]) {} + +fn main() { + () + f(&[1.0]); + //~^ ERROR binary operation `+` cannot be applied to type `()` +} diff --git a/src/test/compile-fail/issue-40861.rs b/src/test/compile-fail/issue-40861.rs new file mode 100644 index 00000000000..e525b3954f5 --- /dev/null +++ b/src/test/compile-fail/issue-40861.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn f(_: &[f32]) {} + +fn main() { + ()[f(&[1.0])]; + //~^ ERROR cannot index a value of type `()` +} diff --git a/src/test/compile-fail/windows-subsystem-invalid.rs b/src/test/compile-fail/windows-subsystem-invalid.rs index e0003440719..7772cfd6a2c 100644 --- a/src/test/compile-fail/windows-subsystem-invalid.rs +++ b/src/test/compile-fail/windows-subsystem-invalid.rs @@ -10,7 +10,6 @@ // 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/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs index 37b66601e70..e2fee1d1895 100644 --- a/src/test/parse-fail/match-refactor-to-expr.rs +++ b/src/test/parse-fail/match-refactor-to-expr.rs @@ -14,7 +14,9 @@ fn main() { let foo = match //~ NOTE did you mean to remove this `match` keyword? Some(4).unwrap_or_else(5) - ; //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` + //~^ NOTE expected one of `.`, `?`, `{`, or an operator here + ; //~ NOTE unexpected token + //~^ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` println!("{}", foo) } diff --git a/src/test/run-make/multiple-emits/Makefile b/src/test/run-make/multiple-emits/Makefile new file mode 100644 index 00000000000..e126422835c --- /dev/null +++ b/src/test/run-make/multiple-emits/Makefile @@ -0,0 +1,7 @@ +-include ../tools.mk + +all: + $(RUSTC) foo.rs --emit=asm,llvm-ir -o $(TMPDIR)/out 2>&1 + rm $(TMPDIR)/out.ll $(TMPDIR)/out.s + $(RUSTC) foo.rs --emit=asm,llvm-ir -o $(TMPDIR)/out2.ext 2>&1 + rm $(TMPDIR)/out2.ll $(TMPDIR)/out2.s diff --git a/src/test/run-make/multiple-emits/foo.rs b/src/test/run-make/multiple-emits/foo.rs new file mode 100644 index 00000000000..8ae3d072362 --- /dev/null +++ b/src/test/run-make/multiple-emits/foo.rs @@ -0,0 +1,11 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() {} diff --git a/src/test/run-make/save-analysis-fail/foo.rs b/src/test/run-make/save-analysis-fail/foo.rs index e331f65abb7..a996aa4fad5 100644 --- a/src/test/run-make/save-analysis-fail/foo.rs +++ b/src/test/run-make/save-analysis-fail/foo.rs @@ -448,3 +448,8 @@ fn test_format_args() { print!("{0} + {} = {}", x, y); print!("x is {}, y is {1}, name is {n}", x, y, n = name); } + +extern { + static EXTERN_FOO: u8; + fn extern_foo(a: u8, b: i32) -> String; +} diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index e8b69729af6..3fe1479f5f2 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -11,6 +11,7 @@ #![ crate_name = "test" ] #![feature(box_syntax)] #![feature(rustc_private)] +#![feature(associated_type_defaults)] extern crate graphviz; // A simple rust project @@ -441,3 +442,19 @@ fn test_format_args() { print!("{0} + {} = {}", x, y); print!("x is {}, y is {1}, name is {n}", x, y, n = name); } + +struct FrameBuffer; + +struct SilenceGenerator; + +impl Iterator for SilenceGenerator { + type Item = FrameBuffer; + + fn next(&mut self) -> Option<Self::Item> { + panic!(); + } +} + +trait Foo { + type Bar = FrameBuffer; +} diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile new file mode 100644 index 00000000000..9d7aa30f874 --- /dev/null +++ b/src/test/run-make/used/Makefile @@ -0,0 +1,11 @@ +-include ../tools.mk + +ifdef IS_WINDOWS +# Do nothing on MSVC. +all: + exit 0 +else +all: + $(RUSTC) -C opt-level=3 --emit=obj used.rs + nm $(TMPDIR)/used.o | grep FOO +endif diff --git a/src/test/run-make/used/used.rs b/src/test/run-make/used/used.rs new file mode 100644 index 00000000000..186cd0fdf5e --- /dev/null +++ b/src/test/run-make/used/used.rs @@ -0,0 +1,17 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] +#![feature(used)] + +#[used] +static FOO: u32 = 0; + +static BAR: u32 = 0; diff --git a/src/test/run-make/windows-subsystem/console.rs b/src/test/run-make/windows-subsystem/console.rs index 3aedb0ecab7..ffad1e35ee6 100644 --- a/src/test/run-make/windows-subsystem/console.rs +++ b/src/test/run-make/windows-subsystem/console.rs @@ -8,7 +8,6 @@ // 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 index 5d875a5a1bf..33cbe320591 100644 --- a/src/test/run-make/windows-subsystem/windows.rs +++ b/src/test/run-make/windows-subsystem/windows.rs @@ -8,7 +8,6 @@ // 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/const-err.rs b/src/test/run-pass/const-err.rs index a1c9ff8a21e..f7f79356a0b 100644 --- a/src/test/run-pass/const-err.rs +++ b/src/test/run-pass/const-err.rs @@ -13,6 +13,10 @@ #![deny(const_err)] const X: *const u8 = b"" as _; +const Y: bool = 'A' == 'B'; +const Z: char = 'A'; +const W: bool = Z <= 'B'; + fn main() { let _ = ((-1 as i8) << 8 - 1) as f32; diff --git a/src/test/compile-fail/windows-subsystem-gated.rs b/src/test/run-pass/issue-40962.rs index 63f891a2af7..b35cfa12eab 100644 --- a/src/test/compile-fail/windows-subsystem-gated.rs +++ b/src/test/run-pass/issue-40962.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,9 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// gate-test-windows_subsystem +macro_rules! m { + ($i:meta) => { + #[derive($i)] + struct S; + } +} -#![windows_subsystem = "console"] -//~^ ERROR: the windows subsystem attribute is currently unstable +m!(Clone); fn main() {} diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs new file mode 100644 index 00000000000..f048b64d104 --- /dev/null +++ b/src/test/rustdoc/check-hard-break.rs @@ -0,0 +1,20 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +// ignore-tidy-end-whitespace + +// @has foo/fn.f.html +// @has - '<p>hard break:<br />' +// @has - 'after hard break</p>' +/// hard break: +/// after hard break +pub fn f() {} diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs new file mode 100644 index 00000000000..46542677857 --- /dev/null +++ b/src/test/rustdoc/check-rule-image-footnote.rs @@ -0,0 +1,44 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +// ignore-tidy-linelength + +// @has foo/fn.f.html +// @has - '<p>markdown test</p>' +// @has - '<p>this is a <a href="https://example.com" title="this is a title">link</a>.</p>' +// @has - '<hr />' +// @has - '<p>a footnote<sup id="supref1"><a href="#ref1">1</a></sup>.</p>' +// @has - '<p>another footnote<sup id="supref2"><a href="#ref2">2</a></sup>.</p>' +// @has - '<p><img src="https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png" alt="Rust" /></p>' +// @has - '<div class="footnotes"><hr><ol><li id="ref1">' +// @has - '<p>Thing <a href="#supref1" rev="footnote">↩</a></p></li><li id="ref2">' +// @has - '<p>Another Thing <a href="#supref2" rev="footnote">↩</a></p></li></ol></div>' +/// markdown test +/// +/// this is a [link]. +/// +/// [link]: https://example.com "this is a title" +/// +/// ----------- +/// +/// a footnote[^footnote]. +/// +/// another footnote[^footnotebis]. +/// +/// [^footnote]: Thing +/// +/// +/// [^footnotebis]: Another Thing +/// +/// +///  +pub fn f() {} diff --git a/src/test/rustdoc/test-lists.rs b/src/test/rustdoc/test-lists.rs new file mode 100644 index 00000000000..29f157e0425 --- /dev/null +++ b/src/test/rustdoc/test-lists.rs @@ -0,0 +1,36 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +// @has foo/fn.f.html +// @has - //ol/li "list" +// @has - //ol/li/ol/li "fooooo" +// @has - //ol/li/ol/li "x" +// @has - //ol/li "foo" +/// 1. list +/// 1. fooooo +/// 2. x +/// 2. foo +pub fn f() {} + +// @has foo/fn.foo2.html +// @has - //ul/li "normal list" +// @has - //ul/li/ul/li "sub list" +// @has - //ul/li/ul/li "new elem still same elem and again same elem!" +// @has - //ul/li "new big elem" +/// * normal list +/// * sub list +/// * new elem +/// still same elem +/// +/// and again same elem! +/// * new big elem +pub fn foo2() {} diff --git a/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs index 158d3606104..a72ad0351e3 100644 --- a/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs +++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs @@ -11,6 +11,6 @@ #![allow(dead_code)] trait C {} -impl C { fn f() {} } //~ ERROR duplicate definitions with name `f` +impl C { fn f() {} } impl C { fn f() {} } fn main() { } diff --git a/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr new file mode 100644 index 00000000000..7f1ab929c6f --- /dev/null +++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr @@ -0,0 +1,10 @@ +error[E0592]: duplicate definitions with name `f` + --> $DIR/coherence-overlapping-inherent-impl-trait.rs:14:10 + | +14 | impl C { fn f() {} } + | ^^^^^^^^^ duplicate definitions for `f` +15 | impl C { fn f() {} } + | --------- other definition for `f` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/inherent-overlap.rs b/src/test/ui/codemap_tests/overlapping_inherent_impls.rs index 18e77ddfd2c..a626b63b31b 100644 --- a/src/test/compile-fail/inherent-overlap.rs +++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.rs @@ -16,7 +16,7 @@ struct Foo; impl Foo { - fn id() {} //~ ERROR duplicate definitions + fn id() {} } impl Foo { @@ -26,7 +26,7 @@ impl Foo { struct Bar<T>(T); impl<T> Bar<T> { - fn bar(&self) {} //~ ERROR duplicate definitions + fn bar(&self) {} } impl Bar<u32> { @@ -36,7 +36,7 @@ impl Bar<u32> { struct Baz<T>(T); impl<T: Copy> Baz<T> { - fn baz(&self) {} //~ ERROR duplicate definitions + fn baz(&self) {} } impl<T> Baz<Vec<T>> { diff --git a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr new file mode 100644 index 00000000000..de8a24cf33f --- /dev/null +++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr @@ -0,0 +1,29 @@ +error[E0592]: duplicate definitions with name `id` + --> $DIR/overlapping_inherent_impls.rs:19:5 + | +19 | fn id() {} + | ^^^^^^^^^^ duplicate definitions for `id` +... +23 | fn id() {} + | ---------- other definition for `id` + +error[E0592]: duplicate definitions with name `bar` + --> $DIR/overlapping_inherent_impls.rs:29:5 + | +29 | fn bar(&self) {} + | ^^^^^^^^^^^^^^^^ duplicate definitions for `bar` +... +33 | fn bar(&self) {} + | ---------------- other definition for `bar` + +error[E0592]: duplicate definitions with name `baz` + --> $DIR/overlapping_inherent_impls.rs:39:5 + | +39 | fn baz(&self) {} + | ^^^^^^^^^^^^^^^^ duplicate definitions for `baz` +... +43 | fn baz(&self) {} + | ---------------- other definition for `baz` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index 6331fc5771f..d7c89355606 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -51,3 +51,9 @@ pub fn with_arg(z: Z, w: &Z) { let _ = &mut z.x; let _ = &mut w.x; } + +pub fn with_tuple() { + let mut y = 0; + let x = (&y,); + *x.0 = 1; +} diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index e1e229a8b05..2e98bc65e9e 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -90,5 +90,11 @@ error: cannot borrow immutable field `w.x` as mutable 52 | let _ = &mut w.x; | ^^^ cannot mutably borrow immutable field -error: aborting due to 11 previous errors +error: cannot assign to immutable borrowed content `*x.0` + --> $DIR/issue-39544.rs:58:5 + | +58 | *x.0 = 1; + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to 12 previous errors diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs new file mode 100644 index 00000000000..cf75929bae2 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -0,0 +1,21 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S; + +impl S { + pub hello_method(&self) { + println!("Hello"); + } +} + +fn main() { + S.hello_method(); +} diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr new file mode 100644 index 00000000000..460958027ad --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -0,0 +1,8 @@ +error: missing `fn` for method declaration + --> $DIR/issue-40006.rs:14:8 + | +14 | pub hello_method(&self) { + | ^ missing `fn` + +error: aborting due to previous error + diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 5be23d8ca48..849787e383f 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -14,13 +14,16 @@ error: expected one of `,`, `.`, `?`, or an operator, found `;` --> $DIR/token-error-correct-3.rs:23:35 | 23 | callback(path.as_ref(); //~ NOTE: unclosed delimiter - | ^ + | ^ expected one of `,`, `.`, `?`, or an operator here error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:29:9 | +25 | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types + | - expected one of `.`, `;`, `?`, `}`, or an operator here +... 29 | } else { //~ ERROR: incorrect close delimiter: `}` - | ^ + | ^ unexpected token error[E0425]: cannot find function `is_directory` in this scope --> $DIR/token-error-correct-3.rs:21:13 diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 248a923efaf..226fa6469bc 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -32,7 +32,7 @@ error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `f --> $DIR/token-error-correct.rs:14:13 | 14 | foo(bar(; - | ^ + | ^ expected one of 18 possible tokens here error: expected expression, found `)` --> $DIR/token-error-correct.rs:23:1 diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index c79db54eaef..98183e2f082 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -2,19 +2,19 @@ error: expected one of `:` or `@`, found `<` --> $DIR/issue-34264.rs:11:14 | 11 | fn foo(Option<i32>, String) {} - | ^ + | ^ expected one of `:` or `@` here error: expected one of `:` or `@`, found `)` --> $DIR/issue-34264.rs:11:27 | 11 | fn foo(Option<i32>, String) {} - | ^ + | ^ expected one of `:` or `@` here error: expected one of `:` or `@`, found `,` --> $DIR/issue-34264.rs:12:9 | 12 | fn bar(x, y: usize) {} - | ^ + | ^ expected one of `:` or `@` here error[E0061]: this function takes 2 parameters but 3 parameters were supplied --> $DIR/issue-34264.rs:16:9 diff --git a/src/test/ui/suggestions/confuse-field-and-method/private-field.rs b/src/test/ui/suggestions/confuse-field-and-method/private-field.rs new file mode 100644 index 00000000000..94cf38fb32f --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/private-field.rs @@ -0,0 +1,29 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub mod animal { + pub struct Dog { + pub age: usize, + dog_age: usize, + } + + impl Dog { + pub fn new(age: usize) -> Dog { + Dog { age: age, dog_age: age * 7 } + } + } +} + +fn main() { + let dog = animal::Dog::new(3); + let dog_age = dog.dog_age(); + //let dog_age = dog.dog_age; + println!("{}", dog_age); +} diff --git a/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr b/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr new file mode 100644 index 00000000000..d07885915d2 --- /dev/null +++ b/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr @@ -0,0 +1,8 @@ +error: no method named `dog_age` found for type `animal::Dog` in the current scope + --> $DIR/private-field.rs:26:23 + | +26 | let dog_age = dog.dog_age(); + | ^^^^^^^ private field, not a method + +error: aborting due to previous error + diff --git a/src/test/parse-fail/bounds-obj-parens.rs b/src/test/ui/token/bounds-obj-parens.rs index ad59d4a52d7..02c119cf727 100644 --- a/src/test/parse-fail/bounds-obj-parens.rs +++ b/src/test/ui/token/bounds-obj-parens.rs @@ -12,4 +12,6 @@ type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK (but see #39318) -FAIL //~ ERROR +FAIL +//~^ ERROR +//~| ERROR diff --git a/src/test/ui/token/bounds-obj-parens.stderr b/src/test/ui/token/bounds-obj-parens.stderr new file mode 100644 index 00000000000..4d60be15eca --- /dev/null +++ b/src/test/ui/token/bounds-obj-parens.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found `<eof>` + --> $DIR/bounds-obj-parens.rs:15:1 + | +15 | FAIL + | ^^^^ expected one of `!` or `::` here + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-10636-2.rs b/src/test/ui/token/issue-10636-2.rs index beaf9e5059f..93759123618 100644 --- a/src/test/compile-fail/issue-10636-2.rs +++ b/src/test/ui/token/issue-10636-2.rs @@ -14,5 +14,7 @@ pub fn trace_option(option: Option<isize>) { option.map(|some| 42; //~ NOTE: unclosed delimiter //~^ ERROR: expected one of + //~| NOTE: expected one of + //~| NOTE: unexpected token } //~ ERROR: incorrect close delimiter //~^ ERROR: expected expression, found `)` diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr new file mode 100644 index 00000000000..b0bae1248b9 --- /dev/null +++ b/src/test/ui/token/issue-10636-2.stderr @@ -0,0 +1,28 @@ +error: incorrect close delimiter: `}` + --> $DIR/issue-10636-2.rs:19:1 + | +19 | } //~ ERROR: incorrect close delimiter + | ^ + | +note: unclosed delimiter + --> $DIR/issue-10636-2.rs:15:15 + | +15 | option.map(|some| 42; //~ NOTE: unclosed delimiter + | ^ + +error: expected one of `,`, `.`, `?`, or an operator, found `;` + --> $DIR/issue-10636-2.rs:15:25 + | +15 | option.map(|some| 42; //~ NOTE: unclosed delimiter + | ^ expected one of `,`, `.`, `?`, or an operator here + +error: expected expression, found `)` + --> $DIR/issue-10636-2.rs:19:1 + | +19 | } //~ ERROR: incorrect close delimiter + | ^ + +error: main function not found + +error: aborting due to 4 previous errors + diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/ui/token/macro-incomplete-parse.rs index c2ac99d1f6a..47374fc3c60 100644 --- a/src/test/compile-fail/macro-incomplete-parse.rs +++ b/src/test/ui/token/macro-incomplete-parse.rs @@ -20,6 +20,8 @@ macro_rules! ignored_item { macro_rules! ignored_expr { () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator here + //~| NOTE unexpected token 2 ) } diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr new file mode 100644 index 00000000000..f23d97586b8 --- /dev/null +++ b/src/test/ui/token/macro-incomplete-parse.stderr @@ -0,0 +1,32 @@ +error: macro expansion ignores token `,` and any following + --> $DIR/macro-incomplete-parse.rs:17:9 + | +17 | , //~ ERROR macro expansion ignores token `,` + | ^ + | +note: caused by the macro expansion here; the usage of `ignored_item!` is likely invalid in item context + --> $DIR/macro-incomplete-parse.rs:32:1 + | +32 | ignored_item!(); //~ NOTE caused by the macro expansion here + | ^^^^^^^^^^^^^^^^ + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/macro-incomplete-parse.rs:22:14 + | +22 | () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + | ^ expected one of `.`, `;`, `?`, `}`, or an operator here + +error: macro expansion ignores token `,` and any following + --> $DIR/macro-incomplete-parse.rs:29:14 + | +29 | () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` + | ^ + | +note: caused by the macro expansion here; the usage of `ignored_pat!` is likely invalid in pattern context + --> $DIR/macro-incomplete-parse.rs:37:9 + | +37 | ignored_pat!() => (), //~ NOTE caused by the macro expansion here + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/ui/token/trailing-plus-in-bounds.rs index 4a2e6d5bdcd..2bb2c97790c 100644 --- a/src/test/parse-fail/trailing-plus-in-bounds.rs +++ b/src/test/ui/token/trailing-plus-in-bounds.rs @@ -16,4 +16,6 @@ fn main() { let x: Box<Debug+> = box 3 as Box<Debug+>; // Trailing `+` is OK } -FAIL //~ ERROR +FAIL +//~^ ERROR +//~| ERROR diff --git a/src/test/ui/token/trailing-plus-in-bounds.stderr b/src/test/ui/token/trailing-plus-in-bounds.stderr new file mode 100644 index 00000000000..c765a434b8a --- /dev/null +++ b/src/test/ui/token/trailing-plus-in-bounds.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found `<eof>` + --> $DIR/trailing-plus-in-bounds.rs:19:1 + | +19 | FAIL + | ^^^^ expected one of `!` or `::` here + +error: aborting due to previous error + diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 5db2ad83a0a..efadde99227 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -24,7 +24,7 @@ use std::path::PathBuf; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle, PLAYGROUND}; +use rustdoc::html::markdown::{Markdown, PLAYGROUND}; use rustc_serialize::json; enum OutputFormat { @@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter { // Description rendered as markdown. match info.description { - Some(ref desc) => write!(output, "{}", Markdown(desc, MarkdownOutputStyle::Fancy))?, + Some(ref desc) => write!(output, "{}", Markdown(desc))?, None => write!(output, "<p>No description.</p>\n")?, } diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 3808c05c6b9..0dbf0d4316a 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -75,7 +75,7 @@ const EXCEPTION_PATHS: &'static [&'static str] = &[ "src/libtest", // Probably should defer to unstable std::sys APIs // std testing crates, ok for now at least - "src/libcoretest", + "src/libcore/tests", // non-std crates "src/test", diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 2233f8c3529..012301299e0 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -110,6 +110,7 @@ pub fn check(path: &Path, bad: &mut bool) { let skip_cr = contents.contains("ignore-tidy-cr"); let skip_tab = contents.contains("ignore-tidy-tab"); let skip_length = contents.contains("ignore-tidy-linelength"); + let skip_end_whitespace = contents.contains("ignore-tidy-end-whitespace"); for (i, line) in contents.split("\n").enumerate() { let mut err = |msg: &str| { println!("{}:{}: {}", file.display(), i + 1, msg); @@ -122,7 +123,7 @@ pub fn check(path: &Path, bad: &mut bool) { if line.contains("\t") && !skip_tab { err("tab character"); } - if line.ends_with(" ") || line.ends_with("\t") { + if !skip_end_whitespace && (line.ends_with(" ") || line.ends_with("\t")) { err("trailing whitespace"); } if line.contains("\r") && !skip_cr { |
