diff --git a/README.md b/README.md index f387b4be6008f..dbb5bf9ce38d6 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Read ["Installing Rust"] from [The Book]. 3. Build and install: ```sh - $ ./x.py build && sudo ./x.py dist --install + $ ./x.py build && sudo ./x.py install ``` > ***Note:*** Install locations can be adjusted by copying the config file @@ -43,7 +43,7 @@ Read ["Installing Rust"] from [The Book]. > adjusting the `prefix` option under `[install]`. Various other options are > also supported, and are documented in the config file. - When complete, `sudo ./x.py dist --install` will place several programs into + When complete, `sudo ./x.py install` will place several programs into `/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the API-documentation tool. This install does not include [Cargo], Rust's package manager, which you may also want to build. @@ -96,7 +96,7 @@ build. 4. Navigate to Rust's source code (or clone it), then build it: ```sh - $ ./x.py build && ./x.py dist --install + $ ./x.py build && ./x.py install ``` #### MSVC diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index bfba1a0dede24..40f9ac489b91a 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -40,7 +40,8 @@ def get(url, path, verbose=False): return else: if verbose: - print("ignoring already-download file " + path + " due to failed verification") + print("ignoring already-download file " + + path + " due to failed verification") os.unlink(path) download(temp_path, url, True, verbose) if not verify(temp_path, sha_path, verbose): @@ -100,8 +101,8 @@ def verify(path, sha_path, verbose): verified = found == expected if not verified: print("invalid checksum:\n" - " found: {}\n" - " expected: {}".format(found, expected)) + " found: {}\n" + " expected: {}".format(found, expected)) return verified @@ -127,13 +128,14 @@ def unpack(tarball, dst, verbose=False, match=None): shutil.move(tp, fp) shutil.rmtree(os.path.join(dst, fname)) -def run(args, verbose=False, exception=False, cwd=None): + +def run(args, verbose=False, exception=False): if verbose: print("running: " + ' '.join(args)) sys.stdout.flush() # Use Popen here instead of call() as it apparently allows powershell on # Windows to not lock up waiting for input presumably. - ret = subprocess.Popen(args, cwd=cwd) + ret = subprocess.Popen(args) code = ret.wait() if code != 0: err = "failed to run: " + ' '.join(args) @@ -141,6 +143,7 @@ def run(args, verbose=False, exception=False, cwd=None): raise RuntimeError(err) sys.exit(err) + def stage0_data(rust_root): nightlies = os.path.join(rust_root, "src/stage0.txt") data = {} @@ -153,11 +156,13 @@ def stage0_data(rust_root): data[a] = b return data + def format_build_time(duration): return str(datetime.timedelta(seconds=int(duration))) class RustBuild(object): + def download_stage0(self): cache_dst = os.path.join(self.build_dir, "cache") rustc_cache = os.path.join(cache_dst, self.stage0_date()) @@ -172,11 +177,13 @@ def download_stage0(self): self.print_what_it_means_to_bootstrap() if os.path.exists(self.bin_root()): shutil.rmtree(self.bin_root()) - filename = "rust-std-{}-{}.tar.gz".format(rustc_channel, self.build) + filename = "rust-std-{}-{}.tar.gz".format( + rustc_channel, self.build) url = self._download_url + "/dist/" + self.stage0_date() tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): - get("{}/{}".format(url, filename), tarball, verbose=self.verbose) + get("{}/{}".format(url, filename), + tarball, verbose=self.verbose) unpack(tarball, self.bin_root(), match="rust-std-" + self.build, verbose=self.verbose) @@ -185,20 +192,25 @@ def download_stage0(self): url = self._download_url + "/dist/" + self.stage0_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="rustc", verbose=self.verbose) + get("{}/{}".format(url, filename), + tarball, verbose=self.verbose) + unpack(tarball, self.bin_root(), + match="rustc", verbose=self.verbose) self.fix_executable(self.bin_root() + "/bin/rustc") self.fix_executable(self.bin_root() + "/bin/rustdoc") with open(self.rustc_stamp(), 'w') as f: f.write(self.stage0_date()) if "pc-windows-gnu" in self.build: - filename = "rust-mingw-{}-{}.tar.gz".format(rustc_channel, self.build) + filename = "rust-mingw-{}-{}.tar.gz".format( + rustc_channel, self.build) url = self._download_url + "/dist/" + self.stage0_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) + 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()): @@ -207,8 +219,10 @@ def download_stage0(self): url = self._download_url + "/dist/" + self.stage0_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="cargo", verbose=self.verbose) + get("{}/{}".format(url, filename), + tarball, verbose=self.verbose) + unpack(tarball, self.bin_root(), + match="cargo", verbose=self.verbose) self.fix_executable(self.bin_root() + "/bin/cargo") with open(self.cargo_stamp(), 'w') as f: f.write(self.stage0_date()) @@ -218,7 +232,8 @@ def fix_executable(self, fname): default_encoding = sys.getdefaultencoding() try: - ostype = subprocess.check_output(['uname', '-s']).strip().decode(default_encoding) + ostype = subprocess.check_output( + ['uname', '-s']).strip().decode(default_encoding) except (subprocess.CalledProcessError, WindowsError): return @@ -234,7 +249,8 @@ def fix_executable(self, fname): print("info: you seem to be running NixOS. Attempting to patch " + fname) try: - interpreter = subprocess.check_output(["patchelf", "--print-interpreter", fname]) + interpreter = subprocess.check_output( + ["patchelf", "--print-interpreter", fname]) interpreter = interpreter.strip().decode(default_encoding) except subprocess.CalledProcessError as e: print("warning: failed to call patchelf: %s" % e) @@ -243,7 +259,8 @@ def fix_executable(self, fname): loader = interpreter.split("/")[-1] try: - ldd_output = subprocess.check_output(['ldd', '/run/current-system/sw/bin/sh']) + ldd_output = subprocess.check_output( + ['ldd', '/run/current-system/sw/bin/sh']) ldd_output = ldd_output.strip().decode(default_encoding) except subprocess.CalledProcessError as e: print("warning: unable to call ldd: %s" % e) @@ -261,7 +278,8 @@ def fix_executable(self, fname): correct_interpreter = loader_path + loader try: - subprocess.check_output(["patchelf", "--set-interpreter", correct_interpreter, fname]) + subprocess.check_output( + ["patchelf", "--set-interpreter", correct_interpreter, fname]) except subprocess.CalledProcessError as e: print("warning: failed to call patchelf: %s" % e) return @@ -371,16 +389,16 @@ def build_bootstrap(self): env["CARGO_TARGET_DIR"] = build_dir env["RUSTC"] = self.rustc() env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ - (os.pathsep + env["LD_LIBRARY_PATH"]) \ - if "LD_LIBRARY_PATH" in env else "" + (os.pathsep + env["LD_LIBRARY_PATH"]) \ + if "LD_LIBRARY_PATH" in env else "" env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ - (os.pathsep + env["DYLD_LIBRARY_PATH"]) \ - if "DYLD_LIBRARY_PATH" in env else "" + (os.pathsep + env["DYLD_LIBRARY_PATH"]) \ + if "DYLD_LIBRARY_PATH" in env else "" env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ - (os.pathsep + env["LIBRARY_PATH"]) \ - if "LIBRARY_PATH" in env else "" + (os.pathsep + env["LIBRARY_PATH"]) \ + if "LIBRARY_PATH" in env else "" env["PATH"] = os.path.join(self.bin_root(), "bin") + \ - os.pathsep + env["PATH"] + os.pathsep + env["PATH"] if not os.path.isfile(self.cargo()): raise Exception("no cargo executable found at `%s`" % self.cargo()) args = [self.cargo(), "build", "--manifest-path", @@ -389,23 +407,13 @@ def build_bootstrap(self): args.append("--locked") if self.use_vendored_sources: args.append("--frozen") - self.run(args, env) - - def run(self, args, env=None, cwd=None): - proc = subprocess.Popen(args, env=env, cwd=cwd) - ret = proc.wait() - if ret != 0: - sys.exit(ret) + self.run(args, env=env) - def output(self, args, env=None, cwd=None): - default_encoding = sys.getdefaultencoding() - proc = subprocess.Popen(args, stdout=subprocess.PIPE, env=env, cwd=cwd) - (out, err) = proc.communicate() + def run(self, args, **kwargs): + proc = subprocess.Popen(args, **kwargs) ret = proc.wait() if ret != 0: - print(out) sys.exit(ret) - return out.decode(default_encoding) def build_triple(self): default_encoding = sys.getdefaultencoding() @@ -416,8 +424,10 @@ def build_triple(self): if config: return config try: - ostype = subprocess.check_output(['uname', '-s']).strip().decode(default_encoding) - cputype = subprocess.check_output(['uname', '-m']).strip().decode(default_encoding) + ostype = subprocess.check_output( + ['uname', '-s']).strip().decode(default_encoding) + cputype = subprocess.check_output( + ['uname', '-m']).strip().decode(default_encoding) except (subprocess.CalledProcessError, OSError): if sys.platform == 'win32': return 'x86_64-pc-windows-msvc' @@ -429,7 +439,8 @@ def build_triple(self): # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. if ostype == 'Linux': - os_from_sp = subprocess.check_output(['uname', '-o']).strip().decode(default_encoding) + os_from_sp = subprocess.check_output( + ['uname', '-o']).strip().decode(default_encoding) if os_from_sp == 'Android': ostype = 'linux-android' else: @@ -453,7 +464,7 @@ def build_triple(self): # must be used instead. try: cputype = subprocess.check_output(['isainfo', - '-k']).strip().decode(default_encoding) + '-k']).strip().decode(default_encoding) except (subprocess.CalledProcessError, OSError): err = "isainfo not found" if self.verbose: @@ -546,51 +557,29 @@ def build_triple(self): def update_submodules(self): if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \ - self.get_toml('submodules') == "false" or \ - self.get_mk('CFG_DISABLE_MANAGE_SUBMODULES') == "1": + self.get_toml('submodules') == "false" or \ + self.get_mk('CFG_DISABLE_MANAGE_SUBMODULES') == "1": return - print('Updating submodules') - output = self.output(["git", "submodule", "status"], cwd=self.rust_root) - submodules = [] - for line in output.splitlines(): - # NOTE `git submodule status` output looks like this: - # - # -5066b7dcab7e700844b0e2ba71b8af9dc627a59b src/liblibc - # +b37ef24aa82d2be3a3cc0fe89bf82292f4ca181c src/compiler-rt (remotes/origin/..) - # e058ca661692a8d01f8cf9d35939dfe3105ce968 src/jemalloc (3.6.0-533-ge058ca6) - # - # The first character can be '-', '+' or ' ' and denotes the - # `State` of the submodule Right next to this character is the - # SHA-1 of the submodule HEAD And after that comes the path to the - # submodule - path = line[1:].split(' ')[1] - submodules.append([path, line[0]]) - - self.run(["git", "submodule", "sync"], cwd=self.rust_root) - - for submod in submodules: - path, status = submod - if path.endswith('llvm') and \ - (self.get_toml('llvm-config') or self.get_mk('CFG_LLVM_ROOT')): - continue - if path.endswith('jemalloc') and \ - (self.get_toml('jemalloc') or self.get_mk('CFG_JEMALLOC_ROOT')): - continue - submod_path = os.path.join(self.rust_root, path) - - if status == ' ': - self.run(["git", "reset", "--hard"], cwd=submod_path) - self.run(["git", "clean", "-fdx"], cwd=submod_path) - elif status == '+': - self.run(["git", "submodule", "update", path], cwd=self.rust_root) - self.run(["git", "reset", "--hard"], cwd=submod_path) - self.run(["git", "clean", "-fdx"], cwd=submod_path) - elif status == '-': - self.run(["git", "submodule", "init", path], cwd=self.rust_root) - self.run(["git", "submodule", "update", path], cwd=self.rust_root) - else: - raise ValueError('unknown submodule status: ' + status) + default_encoding = sys.getdefaultencoding() + self.run(["git", "submodule", "-q", "sync"], cwd=self.rust_root) + submodules = [s.split(' ', 1)[1] for s in subprocess.check_output( + ["git", "config", "--file", os.path.join(self.rust_root, ".gitmodules"), + "--get-regexp", "path"] + ).decode(default_encoding).splitlines()] + submodules = [module for module in submodules + if not ((module.endswith("llvm") and + (self.get_toml('llvm-config') or self.get_mk('CFG_LLVM_ROOT'))) or + (module.endswith("jemalloc") and + (self.get_toml('jemalloc') or self.get_mk('CFG_JEMALLOC_ROOT')))) + ] + self.run(["git", "submodule", "update", + "--init"] + submodules, cwd=self.rust_root) + self.run(["git", "submodule", "-q", "foreach", "git", + "reset", "-q", "--hard"], cwd=self.rust_root) + self.run(["git", "submodule", "-q", "foreach", "git", + "clean", "-qdfx"], cwd=self.rust_root) + def bootstrap(): parser = argparse.ArgumentParser(description='Build rust') @@ -638,7 +627,7 @@ def bootstrap(): if rb.use_vendored_sources: if not os.path.exists('.cargo'): os.makedirs('.cargo') - with open('.cargo/config','w') as f: + with open('.cargo/config', 'w') as f: f.write(""" [source.crates-io] replace-with = 'vendored-sources' @@ -676,15 +665,18 @@ def bootstrap(): env["BUILD"] = rb.build env["SRC"] = rb.rust_root env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) - rb.run(args, env) + rb.run(args, env=env) + def main(): start_time = time() - help_triggered = ('-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1) + help_triggered = ( + '-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1) try: bootstrap() if not help_triggered: - print("Build completed successfully in %s" % format_build_time(time() - start_time)) + 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 @@ -692,7 +684,8 @@ def main(): exit_code = 1 print(e) if not help_triggered: - print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) + print("Build completed unsuccessfully in %s" % + format_build_time(time() - start_time)) sys.exit(exit_code) if __name__ == '__main__': diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 95cca96f7fcc0..0eb6c4c82c4dd 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -314,3 +314,9 @@ # Note that this address should not contain a trailing slash as file names will # be appended to it. #upload-addr = "https://example.com/folder" + +# Whether to build a plain source tarball to upload +# We disable that on Windows not to override the one already uploaded on S3 +# as the one built on Windows will contain backslashes in paths causing problems +# on linux +#src-tarball = true diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 511f2c9e80ec7..94189d7eb92fd 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -30,11 +30,11 @@ use {Build, Compiler, Mode}; use channel; use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe}; -fn pkgname(build: &Build, component: &str) -> String { +pub fn pkgname(build: &Build, component: &str) -> String { if component == "cargo" { format!("{}-{}", component, build.cargo_package_vers()) } else if component == "rls" { - format!("{}-{}", component, build.package_vers(&build.release_num("rls"))) + format!("{}-{}", component, build.rls_package_vers()) } else { assert!(component.starts_with("rust")); format!("{}-{}", component, build.rust_package_vers()) @@ -369,38 +369,7 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { t!(fs::remove_dir_all(&image)); } -const CARGO_VENDOR_VERSION: &'static str = "0.1.4"; - -/// Creates the `rust-src` installer component and the plain source tarball -pub fn rust_src(build: &Build) { - if !build.config.rust_dist_src { - return - } - - println!("Dist src"); - - // Make sure that the root folder of tarball has the correct name - let plain_name = format!("rustc-{}-src", build.rust_package_vers()); - let plain_dst_src = tmpdir(build).join(&plain_name); - let _ = fs::remove_dir_all(&plain_dst_src); - t!(fs::create_dir_all(&plain_dst_src)); - - // This is the set of root paths which will become part of the source package - let src_files = [ - "COPYRIGHT", - "LICENSE-APACHE", - "LICENSE-MIT", - "CONTRIBUTING.md", - "README.md", - "RELEASES.md", - "configure", - "x.py", - ]; - let src_dirs = [ - "man", - "src", - ]; - +fn copy_src_dirs(build: &Build, src_dirs: &[&str], dst_dir: &Path) { let filter_fn = move |path: &Path| { let spath = match path.to_str() { Some(path) => path, @@ -429,60 +398,16 @@ pub fn rust_src(build: &Build) { }; // Copy the directories using our filter - for item in &src_dirs { - let dst = &plain_dst_src.join(item); - t!(fs::create_dir(dst)); + for item in src_dirs { + let dst = &dst_dir.join(item); + t!(fs::create_dir_all(dst)); cp_filtered(&build.src.join(item), dst, &filter_fn); } - // Copy the files normally - for item in &src_files { - copy(&build.src.join(item), &plain_dst_src.join(item)); - } - - // If we're building from git sources, we need to vendor a complete distribution. - if build.src_is_git { - // Get cargo-vendor installed, if it isn't already. - let mut has_cargo_vendor = false; - let mut cmd = Command::new(&build.cargo); - for line in output(cmd.arg("install").arg("--list")).lines() { - has_cargo_vendor |= line.starts_with("cargo-vendor "); - } - if !has_cargo_vendor { - let mut cmd = Command::new(&build.cargo); - cmd.arg("install") - .arg("--force") - .arg("--debug") - .arg("--vers").arg(CARGO_VENDOR_VERSION) - .arg("cargo-vendor") - .env("RUSTC", &build.rustc); - build.run(&mut cmd); - } - - // Vendor all Cargo dependencies - let mut cmd = Command::new(&build.cargo); - cmd.arg("vendor") - .current_dir(&plain_dst_src.join("src")); - build.run(&mut cmd); - } - - // Create the version file - write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes()); - - // Create plain source tarball - let mut tarball = rust_src_location(build); - tarball.set_extension(""); // strip .gz - tarball.set_extension(""); // strip .tar - if let Some(dir) = tarball.parent() { - t!(fs::create_dir_all(dir)); - } - let mut cmd = rust_installer(build); - cmd.arg("tarball") - .arg("--input").arg(&plain_name) - .arg("--output").arg(&tarball) - .arg("--work-dir=.") - .current_dir(tmpdir(build)); - build.run(&mut cmd); +} +/// Creates the `rust-src` installer component +pub fn rust_src(build: &Build) { + println!("Dist src"); let name = pkgname(build, "rust-src"); let image = tmpdir(build).join(format!("{}-image", name)); @@ -516,11 +441,7 @@ pub fn rust_src(build: &Build) { "src/rustc/libc_shim", ]; - for item in &std_src_dirs { - let dst = &dst_src.join(item); - t!(fs::create_dir_all(dst)); - cp_r(&plain_dst_src.join(item), dst); - } + copy_src_dirs(build, &std_src_dirs[..], &dst_src); // Create source tarball in rust-installer format let mut cmd = rust_installer(build); @@ -537,7 +458,86 @@ pub fn rust_src(build: &Build) { build.run(&mut cmd); t!(fs::remove_dir_all(&image)); - t!(fs::remove_dir_all(&plain_dst_src)); +} + +const CARGO_VENDOR_VERSION: &'static str = "0.1.4"; + +/// Creates the plain source tarball +pub fn plain_source_tarball(build: &Build) { + println!("Create plain source tarball"); + + // Make sure that the root folder of tarball has the correct name + let plain_name = format!("{}-src", pkgname(build, "rustc")); + let plain_dst_src = tmpdir(build).join(&plain_name); + let _ = fs::remove_dir_all(&plain_dst_src); + t!(fs::create_dir_all(&plain_dst_src)); + + // This is the set of root paths which will become part of the source package + let src_files = [ + "COPYRIGHT", + "LICENSE-APACHE", + "LICENSE-MIT", + "CONTRIBUTING.md", + "README.md", + "RELEASES.md", + "configure", + "x.py", + ]; + let src_dirs = [ + "man", + "src", + ]; + + copy_src_dirs(build, &src_dirs[..], &plain_dst_src); + + // Copy the files normally + for item in &src_files { + copy(&build.src.join(item), &plain_dst_src.join(item)); + } + + // Create the version file + write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes()); + + // If we're building from git sources, we need to vendor a complete distribution. + if build.src_is_git { + // Get cargo-vendor installed, if it isn't already. + let mut has_cargo_vendor = false; + let mut cmd = Command::new(&build.cargo); + for line in output(cmd.arg("install").arg("--list")).lines() { + has_cargo_vendor |= line.starts_with("cargo-vendor "); + } + if !has_cargo_vendor { + let mut cmd = Command::new(&build.cargo); + cmd.arg("install") + .arg("--force") + .arg("--debug") + .arg("--vers").arg(CARGO_VENDOR_VERSION) + .arg("cargo-vendor") + .env("RUSTC", &build.rustc); + build.run(&mut cmd); + } + + // Vendor all Cargo dependencies + let mut cmd = Command::new(&build.cargo); + cmd.arg("vendor") + .current_dir(&plain_dst_src.join("src")); + build.run(&mut cmd); + } + + // Create plain source tarball + let mut tarball = rust_src_location(build); + tarball.set_extension(""); // strip .gz + tarball.set_extension(""); // strip .tar + if let Some(dir) = tarball.parent() { + t!(fs::create_dir_all(dir)); + } + let mut cmd = rust_installer(build); + cmd.arg("tarball") + .arg("--input").arg(&plain_name) + .arg("--output").arg(&tarball) + .arg("--work-dir=.") + .current_dir(tmpdir(build)); + build.run(&mut cmd); } fn install(src: &Path, dstdir: &Path, perms: u32) { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index a1466d68a135a..fe4e18ab622cd 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -69,7 +69,9 @@ pub enum Subcommand { Clean, Dist { paths: Vec, - install: bool, + }, + Install { + paths: Vec, }, } @@ -85,7 +87,8 @@ Subcommands: bench Build and run some benchmarks doc Build documentation clean Clean out build directories - dist Build and/or install distribution artifacts + dist Build distribution artifacts + install Install distribution artifacts To learn more about a subcommand, run `./x.py -h`"); @@ -125,7 +128,8 @@ To learn more about a subcommand, run `./x.py -h`"); || (s == "bench") || (s == "doc") || (s == "clean") - || (s == "dist")); + || (s == "dist") + || (s == "install")); let subcommand = match possible_subcommands.first() { Some(s) => s, None => { @@ -139,7 +143,6 @@ To learn more about a subcommand, run `./x.py -h`"); 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"); }, _ => { }, }; @@ -281,7 +284,11 @@ Arguments: "dist" => { Subcommand::Dist { paths: paths, - install: matches.opt_present("install"), + } + } + "install" => { + Subcommand::Install { + paths: paths, } } _ => { diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index dce0b1670e181..21e21628dc947 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -19,7 +19,7 @@ use std::path::{Path, PathBuf, Component}; use std::process::Command; use Build; -use dist::{sanitize_sh, tmpdir}; +use dist::{pkgname, sanitize_sh, tmpdir}; pub struct Installer<'a> { build: &'a Build, @@ -29,6 +29,13 @@ pub struct Installer<'a> { bindir: PathBuf, libdir: PathBuf, mandir: PathBuf, + empty_dir: PathBuf, +} + +impl<'a> Drop for Installer<'a> { + fn drop(&mut self) { + t!(fs::remove_dir_all(&self.empty_dir)); + } } impl<'a> Installer<'a> { @@ -61,6 +68,10 @@ impl<'a> Installer<'a> { let libdir = add_destdir(&libdir, &destdir); let mandir = add_destdir(&mandir, &destdir); + let empty_dir = build.out.join("tmp/empty_dir"); + + t!(fs::create_dir_all(&empty_dir)); + Installer { build, prefix, @@ -69,52 +80,49 @@ impl<'a> Installer<'a> { bindir, libdir, mandir, + empty_dir, } } - /// Installs everything. - pub fn install(&self, stage: u32, host: &str) { - let empty_dir = self.build.out.join("tmp/empty_dir"); - t!(fs::create_dir_all(&empty_dir)); - - if self.build.config.docs { - self.install_sh("docs", "rust-docs", &self.build.rust_package_vers(), - stage, Some(host), &empty_dir); - } + pub fn install_docs(&self, stage: u32, host: &str) { + self.install_sh("docs", "rust-docs", stage, Some(host)); + } + pub fn install_std(&self, stage: u32) { for target in self.build.config.target.iter() { - self.install_sh("std", "rust-std", &self.build.rust_package_vers(), - stage, Some(target), &empty_dir); + self.install_sh("std", "rust-std", stage, Some(target)); } + } - if self.build.config.extended { - self.install_sh("cargo", "cargo", &self.build.cargo_package_vers(), - stage, Some(host), &empty_dir); - self.install_sh("rls", "rls", &self.build.rls_package_vers(), - stage, Some(host), &empty_dir); - self.install_sh("analysis", "rust-analysis", &self.build.rust_package_vers(), - stage, Some(host), &empty_dir); - self.install_sh("src", "rust-src", &self.build.rust_package_vers(), - stage, None, &empty_dir); - } + pub fn install_cargo(&self, stage: u32, host: &str) { + self.install_sh("cargo", "cargo", stage, Some(host)); + } - self.install_sh("rustc", "rustc", &self.build.rust_package_vers(), - stage, Some(host), &empty_dir); + pub fn install_rls(&self, stage: u32, host: &str) { + self.install_sh("rls", "rls", stage, Some(host)); + } + + pub fn install_analysis(&self, stage: u32, host: &str) { + self.install_sh("analysis", "rust-analysis", stage, Some(host)); + } - t!(fs::remove_dir_all(&empty_dir)); + pub fn install_src(&self, stage: u32) { + self.install_sh("src", "rust-src", stage, None); + } + pub fn install_rustc(&self, stage: u32, host: &str) { + self.install_sh("rustc", "rustc", stage, Some(host)); } - fn install_sh(&self, package: &str, name: &str, version: &str, - stage: u32, host: Option<&str>, empty_dir: &Path) { + fn install_sh(&self, package: &str, name: &str, stage: u32, host: Option<&str>) { println!("Install {} stage{} ({:?})", package, stage, host); let package_name = if let Some(host) = host { - format!("{}-{}-{}", name, version, host) + format!("{}-{}", pkgname(self.build, name), host) } else { - format!("{}-{}", name, version) + pkgname(self.build, name) }; let mut cmd = Command::new("sh"); - cmd.current_dir(empty_dir) + cmd.current_dir(&self.empty_dir) .arg(sanitize_sh(&tmpdir(self.build).join(&package_name).join("install.sh"))) .arg(format!("--prefix={}", sanitize_sh(&self.prefix))) .arg(format!("--sysconfdir={}", sanitize_sh(&self.sysconfdir))) diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index a5df741e2bfc8..47c792a510b1b 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -69,7 +69,7 @@ distcheck: $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) $(Q)$(BOOTSTRAP) test distcheck $(BOOTSTRAP_ARGS) install: - $(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS) + $(Q)$(BOOTSTRAP) install $(BOOTSTRAP_ARGS) tidy: $(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS) prepare: diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 57915446e1d1a..db7a9aed91a23 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -734,6 +734,13 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { dist::mingw(build, s.target) } }); + rules.dist("dist-plain-source-tarball", "src") + .default(build.config.rust_dist_src) + .host(true) + .only_build(true) + .only_host_build(true) + .dep(move |s| tool_rust_installer(build, s)) + .run(move |_| dist::plain_source_tarball(build)); rules.dist("dist-src", "src") .default(true) .host(true) @@ -759,9 +766,6 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("tool-rls")) .dep(move |s| tool_rust_installer(build, s)) .run(move |s| dist::rls(build, s.stage, s.target)); - rules.dist("install", "path/to/nowhere") - .dep(|s| s.name("default:dist")) - .run(move |s| install::Installer::new(build).install(s.stage, s.target)); rules.dist("dist-cargo", "cargo") .host(true) .only_host_build(true) @@ -789,6 +793,47 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(move |s| s.name("tool-build-manifest").target(&build.config.build).stage(0)) .run(move |_| dist::hash_and_sign(build)); + rules.install("install-docs", "src/doc") + .default(build.config.docs) + .only_host_build(true) + .dep(|s| s.name("dist-docs")) + .run(move |s| install::Installer::new(build).install_docs(s.stage, s.target)); + rules.install("install-std", "src/libstd") + .default(true) + .only_host_build(true) + .dep(|s| s.name("dist-std")) + .run(move |s| install::Installer::new(build).install_std(s.stage)); + rules.install("install-cargo", "cargo") + .default(build.config.extended) + .host(true) + .only_host_build(true) + .dep(|s| s.name("dist-cargo")) + .run(move |s| install::Installer::new(build).install_cargo(s.stage, s.target)); + rules.install("install-rls", "rls") + .default(build.config.extended) + .host(true) + .only_host_build(true) + .dep(|s| s.name("dist-rls")) + .run(move |s| install::Installer::new(build).install_rls(s.stage, s.target)); + rules.install("install-analysis", "analysis") + .default(build.config.extended) + .only_host_build(true) + .dep(|s| s.name("dist-analysis")) + .run(move |s| install::Installer::new(build).install_analysis(s.stage, s.target)); + rules.install("install-src", "src") + .default(build.config.extended) + .host(true) + .only_build(true) + .only_host_build(true) + .dep(|s| s.name("dist-src")) + .run(move |s| install::Installer::new(build).install_src(s.stage)); + rules.install("install-rustc", "src/librustc") + .default(true) + .host(true) + .only_host_build(true) + .dep(|s| s.name("dist-rustc")) + .run(move |s| install::Installer::new(build).install_rustc(s.stage, s.target)); + rules.verify(); return rules; @@ -902,6 +947,7 @@ enum Kind { Bench, Dist, Doc, + Install, } impl<'a> Rule<'a> { @@ -1033,6 +1079,12 @@ impl<'a> Rules<'a> { self.rule(name, path, Kind::Dist) } + /// Same as `build`, but for `Kind::Install`. + fn install<'b>(&'b mut self, name: &'a str, path: &'a str) + -> RuleBuilder<'a, 'b> { + self.rule(name, path, Kind::Install) + } + fn rule<'b>(&'b mut self, name: &'a str, path: &'a str, @@ -1073,6 +1125,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? "test" => Kind::Test, "bench" => Kind::Bench, "dist" => Kind::Dist, + "install" => Kind::Install, _ => return None, }; let rules = self.rules.values().filter(|r| r.kind == kind); @@ -1122,13 +1175,8 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]), Subcommand::Bench { ref paths, test_args: _ } => (Kind::Bench, &paths[..]), - Subcommand::Dist { ref paths, install } => { - if install { - return vec![self.sbuild.name("install")] - } else { - (Kind::Dist, &paths[..]) - } - } + Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]), + Subcommand::Install { ref paths } => (Kind::Install, &paths[..]), Subcommand::Clean => panic!(), }; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 9d5ba2c8f9501..e7c8d3285c8fe 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -40,6 +40,7 @@ use std::cmp; use std::default::Default as StdDefault; use std::mem; use std::fmt; +use std::cell::{Ref, RefCell}; use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; @@ -61,8 +62,8 @@ pub struct LintStore { lints: Vec<(&'static Lint, bool)>, /// Trait objects for each lint pass. - /// This is only `None` while iterating over the objects. See the definition - /// of run_lints. + /// This is only `None` while performing a lint pass. See the definition + /// of `LintSession::new`. early_passes: Option>, late_passes: Option>, @@ -70,7 +71,7 @@ pub struct LintStore { by_name: FxHashMap, /// Current levels of each lint, and where they were set. - levels: FxHashMap, + levels: LintLevels, /// Map of registered lint groups to what lints they expand to. The bool /// is true if the lint group was added by a plugin. @@ -79,11 +80,36 @@ pub struct LintStore { /// Extra info for future incompatibility lints, descibing the /// issue or RFC that caused the incompatibility. future_incompatible: FxHashMap, +} + + +#[derive(Default)] +struct LintLevels { + /// Current levels of each lint, and where they were set. + levels: FxHashMap, /// Maximum level a lint can be lint_cap: Option, } + +pub struct LintSession<'a, PassObject> { + /// Reference to the store of registered lints. + lints: Ref<'a, LintStore>, + + /// The current lint levels. + levels: LintLevels, + + /// When recursing into an attributed node of the ast which modifies lint + /// levels, this stack keeps track of the previous lint levels of whatever + /// was modified. + stack: Vec<(LintId, LevelSource)>, + + /// Trait objects for each lint pass. + passes: Option>, +} + + /// When you call `add_lint` on the session, you wind up storing one /// of these, which records a "potential lint" at a particular point. #[derive(PartialEq, RustcEncodable, RustcDecodable)] @@ -157,34 +183,15 @@ enum FindLintError { } impl LintStore { - fn get_level_source(&self, lint: LintId) -> LevelSource { - match self.levels.get(&lint) { - Some(&s) => s, - None => (Allow, Default), - } - } - - fn set_level(&mut self, lint: LintId, mut lvlsrc: LevelSource) { - if let Some(cap) = self.lint_cap { - lvlsrc.0 = cmp::min(lvlsrc.0, cap); - } - if lvlsrc.0 == Allow { - self.levels.remove(&lint); - } else { - self.levels.insert(lint, lvlsrc); - } - } - pub fn new() -> LintStore { LintStore { lints: vec![], early_passes: Some(vec![]), late_passes: Some(vec![]), by_name: FxHashMap(), - levels: FxHashMap(), + levels: LintLevels::default(), future_incompatible: FxHashMap(), lint_groups: FxHashMap(), - lint_cap: None, } } @@ -236,9 +243,7 @@ impl LintStore { } } - if lint.default_level != Allow { - self.levels.insert(id, (lint.default_level, Default)); - } + self.levels.set(id, (lint.default_level, Default)); } } @@ -310,7 +315,7 @@ impl LintStore { let lint_flag_val = Symbol::intern(&lint_name); match self.find_lint(&lint_name[..], sess, None) { - Ok(lint_id) => self.set_level(lint_id, (level, CommandLine(lint_flag_val))), + Ok(lint_id) => self.levels.set(lint_id, (level, CommandLine(lint_flag_val))), Err(FindLintError::Removed) => { } Err(_) => { match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone())) @@ -318,10 +323,9 @@ impl LintStore { Vec>>() .get(&lint_name[..]) { Some(v) => { - v.iter() - .map(|lint_id: &LintId| - self.set_level(*lint_id, (level, CommandLine(lint_flag_val)))) - .collect::>(); + for lint_id in v { + self.levels.set(*lint_id, (level, CommandLine(lint_flag_val))); + } } None => { // The lint or lint group doesn't exist. @@ -333,15 +337,73 @@ impl LintStore { } } - self.lint_cap = sess.opts.lint_cap; + self.levels.set_lint_cap(sess.opts.lint_cap); + } +} + + +impl LintLevels { + fn get_source(&self, lint: LintId) -> LevelSource { + match self.levels.get(&lint) { + Some(&s) => s, + None => (Allow, Default), + } + } + + fn set(&mut self, lint: LintId, mut lvlsrc: LevelSource) { if let Some(cap) = self.lint_cap { - for level in self.levels.iter_mut().map(|p| &mut (p.1).0) { - *level = cmp::min(*level, cap); + lvlsrc.0 = cmp::min(lvlsrc.0, cap); + } + if lvlsrc.0 == Allow { + self.levels.remove(&lint); + } else { + self.levels.insert(lint, lvlsrc); + } + } + + fn set_lint_cap(&mut self, lint_cap: Option) { + self.lint_cap = lint_cap; + if let Some(cap) = lint_cap { + for (_, level) in &mut self.levels { + level.0 = cmp::min(level.0, cap); } } } } + +impl<'a, PassObject: LintPassObject> LintSession<'a, PassObject> { + /// Creates a new `LintSession`, by moving out the `LintStore`'s initial + /// lint levels and pass objects. These can be restored using the `restore` + /// method. + fn new(store: &'a RefCell) -> LintSession<'a, PassObject> { + let mut s = store.borrow_mut(); + let levels = mem::replace(&mut s.levels, LintLevels::default()); + let passes = PassObject::take_passes(&mut *s); + drop(s); + LintSession { + lints: store.borrow(), + stack: Vec::new(), + levels, + passes, + } + } + + /// Restores the levels back to the original lint store. + fn restore(self, store: &RefCell) { + drop(self.lints); + let mut s = store.borrow_mut(); + s.levels = self.levels; + PassObject::restore_passes(&mut *s, self.passes); + } + + fn get_source(&self, lint_id: LintId) -> LevelSource { + self.levels.get_source(lint_id) + } +} + + + /// Context for lint checking after type checking. pub struct LateContext<'a, 'tcx: 'a> { /// Type context we're checking in. @@ -356,13 +418,8 @@ pub struct LateContext<'a, 'tcx: 'a> { /// Items accessible from the crate being checked. pub access_levels: &'a AccessLevels, - /// The store of registered lints. - lints: LintStore, - - /// When recursing into an attributed node of the ast which modifies lint - /// levels, this stack keeps track of the previous lint levels of whatever - /// was modified. - level_stack: Vec<(LintId, LevelSource)>, + /// The store of registered lints and the lint levels. + lint_sess: LintSession<'tcx, LateLintPassObject>, } /// Context for lint checking of the AST, after expansion, before lowering to @@ -374,24 +431,19 @@ pub struct EarlyContext<'a> { /// The crate being checked. pub krate: &'a ast::Crate, - /// The store of registered lints. - lints: LintStore, - - /// When recursing into an attributed node of the ast which modifies lint - /// levels, this stack keeps track of the previous lint levels of whatever - /// was modified. - level_stack: Vec<(LintId, LevelSource)>, + /// The store of registered lints and the lint levels. + lint_sess: LintSession<'a, EarlyLintPassObject>, } /// Convenience macro for calling a `LintPass` method on every pass in the context. macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({ // Move the vector of passes out of `$cx` so that we can // iterate over it mutably while passing `$cx` to the methods. - let mut passes = $cx.mut_lints().$ps.take().unwrap(); + let mut passes = $cx.lint_sess_mut().passes.take().unwrap(); for obj in &mut passes { obj.$f($cx, $($args),*); } - $cx.mut_lints().$ps = Some(passes); + $cx.lint_sess_mut().passes = Some(passes); }) } /// Parse the lint attributes into a vector, with `Err`s for malformed lint @@ -522,25 +574,55 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, err } + +pub trait LintPassObject: Sized { + fn take_passes(store: &mut LintStore) -> Option>; + fn restore_passes(store: &mut LintStore, passes: Option>); +} + +impl LintPassObject for EarlyLintPassObject { + fn take_passes(store: &mut LintStore) -> Option> { + store.early_passes.take() + } + + fn restore_passes(store: &mut LintStore, passes: Option>) { + store.early_passes = passes; + } +} + +impl LintPassObject for LateLintPassObject { + fn take_passes(store: &mut LintStore) -> Option> { + store.late_passes.take() + } + + fn restore_passes(store: &mut LintStore, passes: Option>) { + store.late_passes = passes; + } +} + + pub trait LintContext<'tcx>: Sized { + type PassObject: LintPassObject; + fn sess(&self) -> &Session; fn lints(&self) -> &LintStore; - fn mut_lints(&mut self) -> &mut LintStore; - fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)>; + fn lint_sess(&self) -> &LintSession<'tcx, Self::PassObject>; + fn lint_sess_mut(&mut self) -> &mut LintSession<'tcx, Self::PassObject>; fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]); fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]); /// Get the level of `lint` at the current position of the lint /// traversal. fn current_level(&self, lint: &'static Lint) -> Level { - self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl) + self.lint_sess().get_source(LintId::of(lint)).0 } fn level_src(&self, lint: &'static Lint) -> Option { - self.lints().levels.get(&LintId::of(lint)).map(|ls| match ls { + let ref levels = self.lint_sess().levels; + levels.levels.get(&LintId::of(lint)).map(|ls| match ls { &(Warn, _) => { let lint_id = LintId::of(builtin::WARNINGS); - let warn_src = self.lints().get_level_source(lint_id); + let warn_src = levels.get_source(lint_id); if warn_src.0 != Warn { warn_src } else { @@ -674,7 +756,7 @@ pub trait LintContext<'tcx>: Sized { let lint_attr_name = result.expect("lint attribute should be well-formed").0; for (lint_id, level, span) in v { - let (now, now_source) = self.lints().get_level_source(lint_id); + let (now, now_source) = self.lint_sess().get_source(lint_id); if now == Forbid && level != Forbid { let lint_name = lint_id.to_string(); let mut diag_builder = struct_span_err!(self.sess(), span, E0453, @@ -693,10 +775,10 @@ pub trait LintContext<'tcx>: Sized { } }.emit() } else if now != level { - let src = self.lints().get_level_source(lint_id).1; - self.level_stack().push((lint_id, (now, src))); + let cx = self.lint_sess_mut(); + cx.stack.push((lint_id, (now, now_source))); pushed += 1; - self.mut_lints().set_level(lint_id, (level, Node(lint_attr_name, span))); + cx.levels.set(lint_id, (level, Node(lint_attr_name, span))); } } } @@ -706,9 +788,10 @@ pub trait LintContext<'tcx>: Sized { self.exit_attrs(attrs); // rollback + let cx = self.lint_sess_mut(); for _ in 0..pushed { - let (lint, lvlsrc) = self.level_stack().pop().unwrap(); - self.mut_lints().set_level(lint, lvlsrc); + let (lint, lvlsrc) = cx.stack.pop().unwrap(); + cx.levels.set(lint, lvlsrc); } } } @@ -717,35 +800,32 @@ pub trait LintContext<'tcx>: Sized { impl<'a> EarlyContext<'a> { fn new(sess: &'a Session, krate: &'a ast::Crate) -> EarlyContext<'a> { - // We want to own the lint store, so move it out of the session. Remember - // to put it back later... - let lint_store = mem::replace(&mut *sess.lint_store.borrow_mut(), - LintStore::new()); EarlyContext { sess: sess, krate: krate, - lints: lint_store, - level_stack: vec![], + lint_sess: LintSession::new(&sess.lint_store), } } } impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> { + type PassObject = LateLintPassObject; + /// Get the overall compiler `Session` object. fn sess(&self) -> &Session { &self.tcx.sess } fn lints(&self) -> &LintStore { - &self.lints + &*self.lint_sess.lints } - fn mut_lints(&mut self) -> &mut LintStore { - &mut self.lints + fn lint_sess(&self) -> &LintSession<'tcx, Self::PassObject> { + &self.lint_sess } - fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> { - &mut self.level_stack + fn lint_sess_mut(&mut self) -> &mut LintSession<'tcx, Self::PassObject> { + &mut self.lint_sess } fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { @@ -760,21 +840,23 @@ impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> { } impl<'a> LintContext<'a> for EarlyContext<'a> { + type PassObject = EarlyLintPassObject; + /// Get the overall compiler `Session` object. fn sess(&self) -> &Session { &self.sess } fn lints(&self) -> &LintStore { - &self.lints + &*self.lint_sess.lints } - fn mut_lints(&mut self) -> &mut LintStore { - &mut self.lints + fn lint_sess(&self) -> &LintSession<'a, Self::PassObject> { + &self.lint_sess } - fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> { - &mut self.level_stack + fn lint_sess_mut(&mut self) -> &mut LintSession<'a, Self::PassObject> { + &mut self.lint_sess } fn enter_attrs(&mut self, attrs: &'a [ast::Attribute]) { @@ -1191,7 +1273,7 @@ fn check_lint_name_attribute(cx: &LateContext, attr: &ast::Attribute) { continue; } Ok((lint_name, _, span)) => { - match check_lint_name(&cx.lints, &lint_name.as_str()) { + match check_lint_name(&cx.lint_sess.lints, &lint_name.as_str()) { CheckLintNameResult::Ok => (), CheckLintNameResult::Warning(ref msg) => { cx.span_lint(builtin::RENAMED_AND_REMOVED_LINTS, @@ -1246,15 +1328,12 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let krate = tcx.hir.krate(); - // We want to own the lint store, so move it out of the session. - let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), LintStore::new()); let mut cx = LateContext { tcx: tcx, tables: &ty::TypeckTables::empty(), krate: krate, access_levels: access_levels, - lints: lint_store, - level_stack: vec![], + lint_sess: LintSession::new(&tcx.sess.lint_store), }; // Visit the whole crate. @@ -1278,8 +1357,8 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } } - // Put the lint store back in the session. - mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints); + // Put the lint store levels and passes back in the session. + cx.lint_sess.restore(&tcx.sess.lint_store); } pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { @@ -1302,8 +1381,8 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { run_lints!(cx, check_crate_post, early_passes, krate); }); - // Put the lint store back in the session. - mem::replace(&mut *sess.lint_store.borrow_mut(), cx.lints); + // Put the lint store levels and passes back in the session. + cx.lint_sess.restore(&sess.lint_store); // If we missed any lints added to the session, then there's a bug somewhere // in the iteration code. diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f7c20542cbf2e..6ee5f24e99641 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1002,7 +1002,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { .span_suggestion(err.span, &format!("to force the closure to take ownership of {} \ (and any other referenced variables), \ - use the `move` keyword, as shown:", + use the `move` keyword", cmt_path_or_string), suggestion) .emit(); diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 861880aa265ec..07c6fa236661d 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -203,6 +203,18 @@ impl Diagnostic { /// Prints out a message with a suggested edit of the code. /// + /// In case of short messages and a simple suggestion, + /// rustc displays it as a label like + /// + /// "try adding parentheses: `(tup.0).1`" + /// + /// The message + /// * should not end in any punctuation (a `:` is added automatically) + /// * should not be a question + /// * should not contain any parts like "the following", "as shown" + /// * may look like "to do xyz, use" or "to do xyz, use abc" + /// * may contain a name of a function, variable or type, but not whole expressions + /// /// See `diagnostic::CodeSuggestion` for more information. pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { self.suggestions.push(CodeSuggestion { diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index a9645f9ab7bb2..24e5040f2a234 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -46,7 +46,7 @@ impl Emitter for EmitterWriter { // don't display multiline suggestions as labels sugg.substitution_parts[0].substitutions[0].find('\n').is_none() { let substitution = &sugg.substitution_parts[0].substitutions[0]; - let msg = format!("help: {} `{}`", sugg.msg, substitution); + let msg = format!("help: {}: `{}`", sugg.msg, substitution); primary_span.push_span_label(sugg.substitution_spans().next().unwrap(), msg); } else { // if there are multiple suggestions, print them all in full diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 6ea666e21dcdd..d37cb48b8c1f9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2307,13 +2307,15 @@ impl<'a> Resolver<'a> { .map(|suggestion| import_candidate_to_paths(&suggestion)).collect::>(); enum_candidates.sort(); for (sp, variant_path, enum_path) in enum_candidates { - let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?", - variant_path, - enum_path); if sp == DUMMY_SP { + let msg = format!("there is an enum variant `{}`, \ + try using `{}`?", + variant_path, + enum_path); err.help(&msg); } else { - err.span_help(sp, &msg); + err.span_suggestion(span, "you can try using the variant's enum", + enum_path); } } } @@ -2322,18 +2324,20 @@ impl<'a> Resolver<'a> { let self_is_available = this.self_value_is_available(path[0].ctxt, span); match candidate { AssocSuggestion::Field => { - err.span_label(span, format!("did you mean `self.{}`?", path_str)); + err.span_suggestion(span, "try", + format!("self.{}", path_str)); if !self_is_available { err.span_label(span, format!("`self` value is only available in \ methods with `self` parameter")); } } AssocSuggestion::MethodWithSelf if self_is_available => { - err.span_label(span, format!("did you mean `self.{}(...)`?", - path_str)); + err.span_suggestion(span, "try", + format!("self.{}", path_str)); } AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => { - err.span_label(span, format!("did you mean `Self::{}`?", path_str)); + err.span_suggestion(span, "try", + format!("Self::{}", path_str)); } } return err; diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 231d30cd2a22d..96783ba0cde64 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -649,9 +649,10 @@ impl<'a> Resolver<'a> { if let Some(suggestion) = suggestion { if suggestion != name { if let MacroKind::Bang = kind { - err.help(&format!("did you mean `{}!`?", suggestion)); + err.span_suggestion(span, "you could try the macro", + format!("{}!", suggestion)); } else { - err.help(&format!("did you mean `{}`?", suggestion)); + err.span_suggestion(span, "try", suggestion.to_string()); } } else { err.help("have you added the `#[macro_use]` on the module/import?"); diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 72ce7d3b5ed71..408837d0e82e3 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -276,7 +276,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) { Ok(s) => { err.span_suggestion(self.cast_span, - "try casting to a reference instead:", + "try casting to a reference instead", format!("&{}{}", mtstr, s)); } Err(_) => { @@ -295,7 +295,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) { Ok(s) => { err.span_suggestion(self.cast_span, - "try casting to a `Box` instead:", + "try casting to a `Box` instead", format!("Box<{}>", s)); } Err(_) => span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr), diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 59cb61d9b97f0..2c33bcb3a050a 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -290,7 +290,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { from a string reference. String concatenation \ appends the string on the right to the string \ on the left and may require reallocation. This \ - requires ownership of the string on the left."), suggestion); + requires ownership of the string on the left"), suggestion); is_string_addition = true; } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index a208f530602a5..d3da32304aa04 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -84,6 +84,12 @@ impl TTMacroExpander for MacroRulesMacroExpander { } } +fn trace_macros_note(cx: &mut ExtCtxt, sp: Span, message: String) { + let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp); + let mut values: &mut Vec = cx.expansions.entry(sp).or_insert_with(Vec::new); + values.push(message); +} + /// Given `lhses` and `rhses`, this is the new macro we create fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, sp: Span, @@ -93,9 +99,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, rhses: &[quoted::TokenTree]) -> Box { if cx.trace_macros() { - let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp); - let mut values: &mut Vec = cx.expansions.entry(sp).or_insert_with(Vec::new); - values.push(format!("expands to `{}! {{ {} }}`", name, arg)); + trace_macros_note(cx, sp, format!("expanding `{}! {{ {} }}`", name, arg)); } // Which arm's failure should we report? (the one furthest along) @@ -117,6 +121,11 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt, }; // rhs has holes ( `$id` and `$(...)` that need filled) let tts = transcribe(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs); + + if cx.trace_macros() { + trace_macros_note(cx, sp, format!("to `{}`", tts)); + } + let directory = Directory { path: cx.current_expansion.module.directory.clone(), ownership: cx.current_expansion.directory_ownership, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4741f896d3cc0..963942a016f73 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1507,7 +1507,7 @@ impl<'a> Parser<'a> { s.print_bounds(" +", &bounds)?; s.pclose() }); - err.span_suggestion(sum_span, "try adding parentheses:", sum_with_parens); + err.span_suggestion(sum_span, "try adding parentheses", sum_with_parens); } TyKind::Ptr(..) | TyKind::BareFn(..) => { err.span_label(sum_span, "perhaps you forgot parentheses?"); @@ -5180,7 +5180,7 @@ impl<'a> Parser<'a> { `pub(in path::to::module)`: visible only on the specified path"##; let path = self.parse_path(PathStyle::Mod)?; let path_span = self.prev_span; - let help_msg = format!("make this visible only to module `{}` with `in`:", path); + let help_msg = format!("make this visible only to module `{}` with `in`", path); self.expect(&token::CloseDelim(token::Paren))?; // `)` let mut err = self.span_fatal_help(path_span, msg, suggestion); err.span_suggestion(path_span, &help_msg, format!("in {}", path)); diff --git a/src/test/run-pass/auxiliary/issue_42007_s.rs b/src/test/run-pass/auxiliary/issue_42007_s.rs new file mode 100644 index 0000000000000..b965e916f98f0 --- /dev/null +++ b/src/test/run-pass/auxiliary/issue_42007_s.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[repr(u8)] +pub enum E { + B = 1 as u8, +} \ No newline at end of file diff --git a/src/test/run-pass/issue-42007.rs b/src/test/run-pass/issue-42007.rs new file mode 100644 index 0000000000000..cc7e3bc372cc6 --- /dev/null +++ b/src/test/run-pass/issue-42007.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue_42007_s.rs + +extern crate issue_42007_s; + +enum I { + E(issue_42007_s::E), +} + +fn main() {} diff --git a/src/test/ui-fulldeps/auxiliary/attr_proc_macro.rs b/src/test/ui-fulldeps/auxiliary/attr_proc_macro.rs new file mode 100644 index 0000000000000..db0c19e96f821 --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/attr_proc_macro.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn attr_proc_macro(_: TokenStream, input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/ui-fulldeps/auxiliary/bang_proc_macro.rs b/src/test/ui-fulldeps/auxiliary/bang_proc_macro.rs new file mode 100644 index 0000000000000..89ac11b309d75 --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/bang_proc_macro.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro] +pub fn bang_proc_macro(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/ui-fulldeps/auxiliary/derive-clona.rs b/src/test/ui-fulldeps/auxiliary/derive-clona.rs new file mode 100644 index 0000000000000..719fbdb15ef2a --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/derive-clona.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(Clona)] +pub fn derive_clonea(input: TokenStream) -> TokenStream { + "".parse().unwrap() +} diff --git a/src/test/ui-fulldeps/auxiliary/derive-foo.rs b/src/test/ui-fulldeps/auxiliary/derive-foo.rs new file mode 100644 index 0000000000000..64dcf72ba2029 --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/derive-foo.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(FooWithLongName)] +pub fn derive_foo(input: TokenStream) -> TokenStream { + "".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs b/src/test/ui-fulldeps/resolve-error.rs similarity index 86% rename from src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs rename to src/test/ui-fulldeps/resolve-error.rs index ddd8631f02e62..8efcd8081feac 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs +++ b/src/test/ui-fulldeps/resolve-error.rs @@ -36,12 +36,10 @@ macro_rules! attr_proc_mac { #[derive(FooWithLongNan)] //~^ ERROR cannot find derive macro `FooWithLongNan` in this scope -//~^^ HELP did you mean `FooWithLongName`? struct Foo; #[attr_proc_macra] //~^ ERROR cannot find attribute macro `attr_proc_macra` in this scope -//~^^ HELP did you mean `attr_proc_macro`? struct Bar; #[FooWithLongNan] @@ -50,12 +48,10 @@ struct Asdf; #[derive(Dlone)] //~^ ERROR cannot find derive macro `Dlone` in this scope -//~^^ HELP did you mean `Clone`? struct A; #[derive(Dlona)] //~^ ERROR cannot find derive macro `Dlona` in this scope -//~^^ HELP did you mean `Clona`? struct B; #[derive(attr_proc_macra)] @@ -65,16 +61,13 @@ struct C; fn main() { FooWithLongNama!(); //~^ ERROR cannot find macro `FooWithLongNama!` in this scope - //~^^ HELP did you mean `FooWithLongNam!`? attr_proc_macra!(); //~^ ERROR cannot find macro `attr_proc_macra!` in this scope - //~^^ HELP did you mean `attr_proc_mac!`? Dlona!(); //~^ ERROR cannot find macro `Dlona!` in this scope bang_proc_macrp!(); //~^ ERROR cannot find macro `bang_proc_macrp!` in this scope - //~^^ HELP did you mean `bang_proc_macro!`? } diff --git a/src/test/ui-fulldeps/resolve-error.stderr b/src/test/ui-fulldeps/resolve-error.stderr new file mode 100644 index 0000000000000..be7ebae70adf5 --- /dev/null +++ b/src/test/ui-fulldeps/resolve-error.stderr @@ -0,0 +1,62 @@ +error: cannot find derive macro `FooWithLongNan` in this scope + --> $DIR/resolve-error.rs:37:10 + | +37 | #[derive(FooWithLongNan)] + | ^^^^^^^^^^^^^^ help: try: `FooWithLongName` + +error: cannot find attribute macro `attr_proc_macra` in this scope + --> $DIR/resolve-error.rs:41:3 + | +41 | #[attr_proc_macra] + | ^^^^^^^^^^^^^^^ help: try: `attr_proc_macro` + +error: cannot find attribute macro `FooWithLongNan` in this scope + --> $DIR/resolve-error.rs:45:3 + | +45 | #[FooWithLongNan] + | ^^^^^^^^^^^^^^ + +error: cannot find derive macro `Dlone` in this scope + --> $DIR/resolve-error.rs:49:10 + | +49 | #[derive(Dlone)] + | ^^^^^ help: try: `Clone` + +error: cannot find derive macro `Dlona` in this scope + --> $DIR/resolve-error.rs:53:10 + | +53 | #[derive(Dlona)] + | ^^^^^ help: try: `Clona` + +error: cannot find derive macro `attr_proc_macra` in this scope + --> $DIR/resolve-error.rs:57:10 + | +57 | #[derive(attr_proc_macra)] + | ^^^^^^^^^^^^^^^ + +error: cannot find macro `FooWithLongNama!` in this scope + --> $DIR/resolve-error.rs:62:5 + | +62 | FooWithLongNama!(); + | ^^^^^^^^^^^^^^^ help: you could try the macro: `FooWithLongNam!` + +error: cannot find macro `attr_proc_macra!` in this scope + --> $DIR/resolve-error.rs:65:5 + | +65 | attr_proc_macra!(); + | ^^^^^^^^^^^^^^^ help: you could try the macro: `attr_proc_mac!` + +error: cannot find macro `Dlona!` in this scope + --> $DIR/resolve-error.rs:68:5 + | +68 | Dlona!(); + | ^^^^^ + +error: cannot find macro `bang_proc_macrp!` in this scope + --> $DIR/resolve-error.rs:71:5 + | +71 | bang_proc_macrp!(); + | ^^^^^^^^^^^^^^^ help: you could try the macro: `bang_proc_macro!` + +error: aborting due to 10 previous errors + diff --git a/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs b/src/test/ui/cast-to-unsized-trait-object-suggestion.rs similarity index 77% rename from src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs rename to src/test/ui/cast-to-unsized-trait-object-suggestion.rs index d18746cdf0ba5..3693fd11d4837 100644 --- a/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs +++ b/src/test/ui/cast-to-unsized-trait-object-suggestion.rs @@ -11,10 +11,6 @@ fn main() { &1 as Send; //~^ ERROR cast to unsized type - //~| HELP try casting to a reference instead: - //~| SUGGESTION &1 as &Send; Box::new(1) as Send; //~^ ERROR cast to unsized type - //~| HELP try casting to a `Box` instead: - //~| SUGGESTION Box::new(1) as Box; } diff --git a/src/test/ui/cast-to-unsized-trait-object-suggestion.stderr b/src/test/ui/cast-to-unsized-trait-object-suggestion.stderr new file mode 100644 index 0000000000000..6aa062e42238a --- /dev/null +++ b/src/test/ui/cast-to-unsized-trait-object-suggestion.stderr @@ -0,0 +1,18 @@ +error: cast to unsized type: `&{integer}` as `std::marker::Send` + --> $DIR/cast-to-unsized-trait-object-suggestion.rs:12:5 + | +12 | &1 as Send; + | ^^^^^^---- + | | + | help: try casting to a reference instead: `&Send` + +error: cast to unsized type: `std::boxed::Box<{integer}>` as `std::marker::Send` + --> $DIR/cast-to-unsized-trait-object-suggestion.rs:14:5 + | +14 | Box::new(1) as Send; + | ^^^^^^^^^^^^^^^---- + | | + | help: try casting to a `Box` instead: `Box` + +error: aborting due to 2 previous errors + diff --git a/src/test/compile-fail/issue-35675.rs b/src/test/ui/issue-35675.rs similarity index 100% rename from src/test/compile-fail/issue-35675.rs rename to src/test/ui/issue-35675.rs diff --git a/src/test/ui/issue-35675.stderr b/src/test/ui/issue-35675.stderr new file mode 100644 index 0000000000000..c6738e0964a1a --- /dev/null +++ b/src/test/ui/issue-35675.stderr @@ -0,0 +1,65 @@ +error[E0412]: cannot find type `Apple` in this scope + --> $DIR/issue-35675.rs:20:29 + | +20 | fn should_return_fruit() -> Apple { + | ^^^^^ + | | + | not found in this scope + | help: you can try using the variant's enum: `Fruit` + +error[E0425]: cannot find function `Apple` in this scope + --> $DIR/issue-35675.rs:23:5 + | +23 | Apple(5) + | ^^^^^ not found in this scope + | +help: possible candidate is found in another module, you can import it into scope + | use Fruit::Apple; + +error[E0573]: expected type, found variant `Fruit::Apple` + --> $DIR/issue-35675.rs:28:33 + | +28 | fn should_return_fruit_too() -> Fruit::Apple { + | ^^^^^^^^^^^^ + | | + | not a type + | help: you can try using the variant's enum: `Fruit` + +error[E0425]: cannot find function `Apple` in this scope + --> $DIR/issue-35675.rs:31:5 + | +31 | Apple(5) + | ^^^^^ not found in this scope + | +help: possible candidate is found in another module, you can import it into scope + | use Fruit::Apple; + +error[E0573]: expected type, found variant `Ok` + --> $DIR/issue-35675.rs:36:13 + | +36 | fn foo() -> Ok { + | ^^ not a type + | + = help: there is an enum variant `std::prelude::v1::Ok`, try using `std::prelude::v1`? + = help: there is an enum variant `std::prelude::v1::Result::Ok`, try using `std::prelude::v1::Result`? + +error[E0412]: cannot find type `Variant3` in this scope + --> $DIR/issue-35675.rs:44:13 + | +44 | fn bar() -> Variant3 { + | ^^^^^^^^ + | | + | not found in this scope + | help: you can try using the variant's enum: `x::Enum` + +error[E0573]: expected type, found variant `Some` + --> $DIR/issue-35675.rs:49:13 + | +49 | fn qux() -> Some { + | ^^^^ not a type + | + = help: there is an enum variant `std::option::Option::Some`, try using `std::option::Option`? + = help: there is an enum variant `std::prelude::v1::Some`, try using `std::prelude::v1`? + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr b/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr index de110ac12b703..26f150811b7db 100644 --- a/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr +++ b/src/test/ui/issue-40402-ref-hints/issue-40402-1.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of indexed content 19 | let e = f.v[0]; | ^^^^^^ | | - | help: consider using a reference instead `&f.v[0]` + | help: consider using a reference instead: `&f.v[0]` | cannot move out of indexed content error: aborting due to previous error diff --git a/src/test/compile-fail/macro-name-typo.rs b/src/test/ui/macros/macro-name-typo.rs similarity index 93% rename from src/test/compile-fail/macro-name-typo.rs rename to src/test/ui/macros/macro-name-typo.rs index 4840205fee4c3..7489d92dc2411 100644 --- a/src/test/compile-fail/macro-name-typo.rs +++ b/src/test/ui/macros/macro-name-typo.rs @@ -11,5 +11,4 @@ fn main() { printlx!("oh noes!"); //~^ ERROR cannot find macro - //~^^ HELP did you mean `println!`? } diff --git a/src/test/ui/macros/macro-name-typo.stderr b/src/test/ui/macros/macro-name-typo.stderr new file mode 100644 index 0000000000000..7c83250fe8ada --- /dev/null +++ b/src/test/ui/macros/macro-name-typo.stderr @@ -0,0 +1,8 @@ +error: cannot find macro `printlx!` in this scope + --> $DIR/macro-name-typo.rs:12:5 + | +12 | printlx!("oh noes!"); + | ^^^^^^^ help: you could try the macro: `println!` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/macro_undefined.rs b/src/test/ui/macros/macro_undefined.rs similarity index 87% rename from src/test/compile-fail/macro_undefined.rs rename to src/test/ui/macros/macro_undefined.rs index 00c8d44f30602..ac3c356b54999 100644 --- a/src/test/compile-fail/macro_undefined.rs +++ b/src/test/ui/macros/macro_undefined.rs @@ -20,8 +20,6 @@ mod m { fn main() { k!(); //~^ ERROR cannot find macro `k!` in this scope - //~^^ HELP did you mean `kl!`? kl!(); //~^ ERROR cannot find macro `kl!` in this scope - //~^^ HELP have you added the `#[macro_use]` on the module/import? } diff --git a/src/test/ui/macros/macro_undefined.stderr b/src/test/ui/macros/macro_undefined.stderr new file mode 100644 index 0000000000000..b88829c2e23e0 --- /dev/null +++ b/src/test/ui/macros/macro_undefined.stderr @@ -0,0 +1,16 @@ +error: cannot find macro `kl!` in this scope + --> $DIR/macro_undefined.rs:23:5 + | +23 | kl!(); + | ^^ + | + = help: have you added the `#[macro_use]` on the module/import? + +error: cannot find macro `k!` in this scope + --> $DIR/macro_undefined.rs:21:5 + | +21 | k!(); + | ^ help: you could try the macro: `kl!` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/macros/trace-macro.stderr b/src/test/ui/macros/trace-macro.stderr index 09117a4ca7404..6cf3b0bd35d5e 100644 --- a/src/test/ui/macros/trace-macro.stderr +++ b/src/test/ui/macros/trace-macro.stderr @@ -4,6 +4,9 @@ note: trace_macro 14 | println!("Hello, World!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expands to `println! { "Hello, World!" }` - = note: expands to `print! { concat ! ( "Hello, World!" , "/n" ) }` + = note: expanding `println! { "Hello, World!" }` + = note: to `print ! ( concat ! ( "Hello, World!" , "/n" ) )` + = note: expanding `print! { concat ! ( "Hello, World!" , "/n" ) }` + = note: to `$crate :: io :: _print ( format_args ! ( concat ! ( "Hello, World!" , "/n" ) ) + )` diff --git a/src/test/ui/resolve-error.stderr b/src/test/ui/resolve-error.stderr new file mode 100644 index 0000000000000..be7ebae70adf5 --- /dev/null +++ b/src/test/ui/resolve-error.stderr @@ -0,0 +1,62 @@ +error: cannot find derive macro `FooWithLongNan` in this scope + --> $DIR/resolve-error.rs:37:10 + | +37 | #[derive(FooWithLongNan)] + | ^^^^^^^^^^^^^^ help: try: `FooWithLongName` + +error: cannot find attribute macro `attr_proc_macra` in this scope + --> $DIR/resolve-error.rs:41:3 + | +41 | #[attr_proc_macra] + | ^^^^^^^^^^^^^^^ help: try: `attr_proc_macro` + +error: cannot find attribute macro `FooWithLongNan` in this scope + --> $DIR/resolve-error.rs:45:3 + | +45 | #[FooWithLongNan] + | ^^^^^^^^^^^^^^ + +error: cannot find derive macro `Dlone` in this scope + --> $DIR/resolve-error.rs:49:10 + | +49 | #[derive(Dlone)] + | ^^^^^ help: try: `Clone` + +error: cannot find derive macro `Dlona` in this scope + --> $DIR/resolve-error.rs:53:10 + | +53 | #[derive(Dlona)] + | ^^^^^ help: try: `Clona` + +error: cannot find derive macro `attr_proc_macra` in this scope + --> $DIR/resolve-error.rs:57:10 + | +57 | #[derive(attr_proc_macra)] + | ^^^^^^^^^^^^^^^ + +error: cannot find macro `FooWithLongNama!` in this scope + --> $DIR/resolve-error.rs:62:5 + | +62 | FooWithLongNama!(); + | ^^^^^^^^^^^^^^^ help: you could try the macro: `FooWithLongNam!` + +error: cannot find macro `attr_proc_macra!` in this scope + --> $DIR/resolve-error.rs:65:5 + | +65 | attr_proc_macra!(); + | ^^^^^^^^^^^^^^^ help: you could try the macro: `attr_proc_mac!` + +error: cannot find macro `Dlona!` in this scope + --> $DIR/resolve-error.rs:68:5 + | +68 | Dlona!(); + | ^^^^^ + +error: cannot find macro `bang_proc_macrp!` in this scope + --> $DIR/resolve-error.rs:71:5 + | +71 | bang_proc_macrp!(); + | ^^^^^^^^^^^^^^^ help: you could try the macro: `bang_proc_macro!` + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/resolve/issue-14254.stderr b/src/test/ui/resolve/issue-14254.stderr index 18eb2fabdacb5..3b5f3e4c36a04 100644 --- a/src/test/ui/resolve/issue-14254.stderr +++ b/src/test/ui/resolve/issue-14254.stderr @@ -2,7 +2,7 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:29:9 | 29 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ help: try: `self.baz` error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:32:9 @@ -14,19 +14,19 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:40:9 | 40 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ help: try: `self.baz` error[E0425]: cannot find value `x` in this scope --> $DIR/issue-14254.rs:43:9 | 43 | x; - | ^ did you mean `self.x`? + | ^ help: try: `self.x` error[E0425]: cannot find value `y` in this scope --> $DIR/issue-14254.rs:46:9 | 46 | y; - | ^ did you mean `self.y`? + | ^ help: try: `self.y` error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:49:9 @@ -38,7 +38,7 @@ error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:52:9 | 52 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ help: try: `Self::bah` error[E0425]: cannot find value `b` in this scope --> $DIR/issue-14254.rs:55:9 @@ -50,19 +50,19 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:63:9 | 63 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ help: try: `self.baz` error[E0425]: cannot find value `x` in this scope --> $DIR/issue-14254.rs:66:9 | 66 | x; - | ^ did you mean `self.x`? + | ^ help: try: `self.x` error[E0425]: cannot find value `y` in this scope --> $DIR/issue-14254.rs:69:9 | 69 | y; - | ^ did you mean `self.y`? + | ^ help: try: `self.y` error[E0425]: cannot find value `a` in this scope --> $DIR/issue-14254.rs:72:9 @@ -74,7 +74,7 @@ error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:75:9 | 75 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ help: try: `Self::bah` error[E0425]: cannot find value `b` in this scope --> $DIR/issue-14254.rs:78:9 @@ -86,61 +86,61 @@ error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:86:9 | 86 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ help: try: `self.baz` error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:89:9 | 89 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ help: try: `Self::bah` error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:97:9 | 97 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ help: try: `self.baz` error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:100:9 | 100 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ help: try: `Self::bah` error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:108:9 | 108 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ help: try: `self.baz` error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:111:9 | 111 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ help: try: `Self::bah` error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:119:9 | 119 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ help: try: `self.baz` error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:122:9 | 122 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ help: try: `Self::bah` error[E0425]: cannot find function `baz` in this scope --> $DIR/issue-14254.rs:130:9 | 130 | baz(); - | ^^^ did you mean `self.baz(...)`? + | ^^^ help: try: `self.baz` error[E0425]: cannot find value `bah` in this scope --> $DIR/issue-14254.rs:133:9 | 133 | bah; - | ^^^ did you mean `Self::bah`? + | ^^^ help: try: `Self::bah` error: main function not found diff --git a/src/test/ui/resolve/issue-2356.stderr b/src/test/ui/resolve/issue-2356.stderr index 039887d8da65f..9c683f4418972 100644 --- a/src/test/ui/resolve/issue-2356.stderr +++ b/src/test/ui/resolve/issue-2356.stderr @@ -8,13 +8,13 @@ error[E0425]: cannot find function `clone` in this scope --> $DIR/issue-2356.rs:35:5 | 35 | clone(); - | ^^^^^ did you mean `self.clone(...)`? + | ^^^^^ help: try: `self.clone` error[E0425]: cannot find function `default` in this scope --> $DIR/issue-2356.rs:43:5 | 43 | default(); - | ^^^^^^^ did you mean `Self::default`? + | ^^^^^^^ help: try: `Self::default` error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:52:5 @@ -22,14 +22,14 @@ error[E0425]: cannot find value `whiskers` in this scope 52 | whiskers -= other; | ^^^^^^^^ | | - | did you mean `self.whiskers`? + | help: try: `self.whiskers` | `self` value is only available in methods with `self` parameter error[E0425]: cannot find function `shave` in this scope --> $DIR/issue-2356.rs:57:5 | 57 | shave(4); - | ^^^^^ did you mean `Self::shave`? + | ^^^^^ help: try: `Self::shave` error[E0425]: cannot find function `purr` in this scope --> $DIR/issue-2356.rs:60:5 @@ -83,7 +83,7 @@ error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:104:5 | 104 | whiskers = 0; - | ^^^^^^^^ did you mean `self.whiskers`? + | ^^^^^^^^ help: try: `self.whiskers` error[E0425]: cannot find value `whiskers` in this scope --> $DIR/issue-2356.rs:110:5 @@ -91,7 +91,7 @@ error[E0425]: cannot find value `whiskers` in this scope 110 | whiskers = 4; | ^^^^^^^^ | | - | did you mean `self.whiskers`? + | help: try: `self.whiskers` | `self` value is only available in methods with `self` parameter error[E0425]: cannot find function `purr_louder` in this scope diff --git a/src/test/ui/resolve/resolve-assoc-suggestions.stderr b/src/test/ui/resolve/resolve-assoc-suggestions.stderr index 7975c168de7d4..77aa545e2ad6b 100644 --- a/src/test/ui/resolve/resolve-assoc-suggestions.stderr +++ b/src/test/ui/resolve/resolve-assoc-suggestions.stderr @@ -14,13 +14,13 @@ error[E0425]: cannot find value `field` in this scope --> $DIR/resolve-assoc-suggestions.rs:32:9 | 32 | field; - | ^^^^^ did you mean `self.field`? + | ^^^^^ help: try: `self.field` error[E0412]: cannot find type `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:36:16 | 36 | let _: Type; - | ^^^^ did you mean `Self::Type`? + | ^^^^ help: try: `Self::Type` error[E0531]: cannot find tuple struct/variant `Type` in this scope --> $DIR/resolve-assoc-suggestions.rs:39:13 @@ -50,7 +50,7 @@ error[E0425]: cannot find value `method` in this scope --> $DIR/resolve-assoc-suggestions.rs:52:9 | 52 | method; - | ^^^^^^ did you mean `self.method(...)`? + | ^^^^^^ help: try: `self.method` error: aborting due to 9 previous errors diff --git a/src/test/ui/resolve/resolve-speculative-adjustment.stderr b/src/test/ui/resolve/resolve-speculative-adjustment.stderr index e7df8140bc577..3e1b075679a50 100644 --- a/src/test/ui/resolve/resolve-speculative-adjustment.stderr +++ b/src/test/ui/resolve/resolve-speculative-adjustment.stderr @@ -14,13 +14,13 @@ error[E0425]: cannot find value `field` in this scope --> $DIR/resolve-speculative-adjustment.rs:35:9 | 35 | field; - | ^^^^^ did you mean `self.field`? + | ^^^^^ help: try: `self.field` error[E0425]: cannot find function `method` in this scope --> $DIR/resolve-speculative-adjustment.rs:38:9 | 38 | method(); - | ^^^^^^ did you mean `self.method(...)`? + | ^^^^^^ help: try: `self.method` error: aborting due to 4 previous errors diff --git a/src/test/ui/resolve/unresolved_static_type_field.stderr b/src/test/ui/resolve/unresolved_static_type_field.stderr index 5fbaf66e014af..e598851e3628e 100644 --- a/src/test/ui/resolve/unresolved_static_type_field.stderr +++ b/src/test/ui/resolve/unresolved_static_type_field.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find value `cx` in this scope 19 | f(cx); | ^^ | | - | did you mean `self.cx`? + | help: try: `self.cx` | `self` value is only available in methods with `self` parameter error: aborting due to previous error diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index cd3a41b037c79..e8b3c6629bd53 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&'static str` 12 | let x = "Hello " + "World!"; | ^^^^^^^^^^^^^^^^^^^ `+` can't be used to concatenate two `&str` strings | -help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left. +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | let x = "Hello ".to_owned() + "World!"; error[E0369]: binary operation `+` cannot be applied to type `World` diff --git a/src/test/ui/span/suggestion-non-ascii.stderr b/src/test/ui/span/suggestion-non-ascii.stderr index 91e629c44b073..48db5026c9e51 100644 --- a/src/test/ui/span/suggestion-non-ascii.stderr +++ b/src/test/ui/span/suggestion-non-ascii.stderr @@ -2,7 +2,7 @@ error: cannot index a value of type `({integer},)` --> $DIR/suggestion-non-ascii.rs:14:21 | 14 | println!("☃{}", tup[0]); - | ^^^^^^ help: to access tuple elements, use `tup.0` + | ^^^^^^ help: to access tuple elements, use: `tup.0` error: aborting due to previous error diff --git a/src/test/ui/suggestions/tuple-float-index.stderr b/src/test/ui/suggestions/tuple-float-index.stderr index 8a121b1453662..4b1be26c86b0e 100644 --- a/src/test/ui/suggestions/tuple-float-index.stderr +++ b/src/test/ui/suggestions/tuple-float-index.stderr @@ -5,7 +5,7 @@ error: unexpected token: `1.1` | ------------^^^ | | | | | unexpected token - | help: try parenthesizing the first index `((1, (2, 3)).1).1` + | help: try parenthesizing the first index: `((1, (2, 3)).1).1` error: aborting due to previous error