Merge from rustc
This commit is contained in:
commit
3942cdf1bf
535 changed files with 2707 additions and 2616 deletions
|
|
@ -13,6 +13,7 @@ import tarfile
|
|||
import tempfile
|
||||
|
||||
from time import time
|
||||
from multiprocessing import Pool, cpu_count
|
||||
|
||||
try:
|
||||
import lzma
|
||||
|
|
@ -27,6 +28,20 @@ if platform_is_win32():
|
|||
else:
|
||||
EXE_SUFFIX = ""
|
||||
|
||||
def get_cpus():
|
||||
if hasattr(os, "sched_getaffinity"):
|
||||
return len(os.sched_getaffinity(0))
|
||||
if hasattr(os, "cpu_count"):
|
||||
cpus = os.cpu_count()
|
||||
if cpus is not None:
|
||||
return cpus
|
||||
try:
|
||||
return cpu_count()
|
||||
except NotImplementedError:
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
def get(base, url, path, checksums, verbose=False):
|
||||
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
|
||||
temp_path = temp_file.name
|
||||
|
|
@ -42,23 +57,23 @@ def get(base, url, path, checksums, verbose=False):
|
|||
if os.path.exists(path):
|
||||
if verify(path, sha256, False):
|
||||
if verbose:
|
||||
print("using already-download file", path)
|
||||
print("using already-download file", path, file=sys.stderr)
|
||||
return
|
||||
else:
|
||||
if verbose:
|
||||
print("ignoring already-download file",
|
||||
path, "due to failed verification")
|
||||
path, "due to failed verification", file=sys.stderr)
|
||||
os.unlink(path)
|
||||
download(temp_path, "{}/{}".format(base, url), True, verbose)
|
||||
if not verify(temp_path, sha256, verbose):
|
||||
raise RuntimeError("failed verification")
|
||||
if verbose:
|
||||
print("moving {} to {}".format(temp_path, path))
|
||||
print("moving {} to {}".format(temp_path, path), file=sys.stderr)
|
||||
shutil.move(temp_path, path)
|
||||
finally:
|
||||
if os.path.isfile(temp_path):
|
||||
if verbose:
|
||||
print("removing", temp_path)
|
||||
print("removing", temp_path, file=sys.stderr)
|
||||
os.unlink(temp_path)
|
||||
|
||||
|
||||
|
|
@ -68,7 +83,7 @@ def download(path, url, probably_big, verbose):
|
|||
_download(path, url, probably_big, verbose, True)
|
||||
return
|
||||
except RuntimeError:
|
||||
print("\nspurious failure, trying again")
|
||||
print("\nspurious failure, trying again", file=sys.stderr)
|
||||
_download(path, url, probably_big, verbose, False)
|
||||
|
||||
|
||||
|
|
@ -79,7 +94,7 @@ def _download(path, url, probably_big, verbose, exception):
|
|||
# - If we are on win32 fallback to powershell
|
||||
# - Otherwise raise the error if appropriate
|
||||
if probably_big or verbose:
|
||||
print("downloading {}".format(url))
|
||||
print("downloading {}".format(url), file=sys.stderr)
|
||||
|
||||
try:
|
||||
if probably_big or verbose:
|
||||
|
|
@ -115,20 +130,20 @@ def _download(path, url, probably_big, verbose, exception):
|
|||
def verify(path, expected, verbose):
|
||||
"""Check if the sha256 sum of the given path is valid"""
|
||||
if verbose:
|
||||
print("verifying", path)
|
||||
print("verifying", path, file=sys.stderr)
|
||||
with open(path, "rb") as source:
|
||||
found = hashlib.sha256(source.read()).hexdigest()
|
||||
verified = found == expected
|
||||
if not verified:
|
||||
print("invalid checksum:\n"
|
||||
" found: {}\n"
|
||||
" expected: {}".format(found, expected))
|
||||
" expected: {}".format(found, expected), file=sys.stderr)
|
||||
return verified
|
||||
|
||||
|
||||
def unpack(tarball, tarball_suffix, dst, verbose=False, match=None):
|
||||
"""Unpack the given tarball file"""
|
||||
print("extracting", tarball)
|
||||
print("extracting", tarball, file=sys.stderr)
|
||||
fname = os.path.basename(tarball).replace(tarball_suffix, "")
|
||||
with contextlib.closing(tarfile.open(tarball)) as tar:
|
||||
for member in tar.getnames():
|
||||
|
|
@ -141,7 +156,7 @@ def unpack(tarball, tarball_suffix, dst, verbose=False, match=None):
|
|||
|
||||
dst_path = os.path.join(dst, name)
|
||||
if verbose:
|
||||
print(" extracting", member)
|
||||
print(" extracting", member, file=sys.stderr)
|
||||
tar.extract(member, dst)
|
||||
src_path = os.path.join(dst, member)
|
||||
if os.path.isdir(src_path) and os.path.exists(dst_path):
|
||||
|
|
@ -153,7 +168,7 @@ def unpack(tarball, tarball_suffix, dst, verbose=False, match=None):
|
|||
def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs):
|
||||
"""Run a child program in a new process"""
|
||||
if verbose:
|
||||
print("running: " + ' '.join(args))
|
||||
print("running: " + ' '.join(args), file=sys.stderr)
|
||||
sys.stdout.flush()
|
||||
# Ensure that the .exe is used on Windows just in case a Linux ELF has been
|
||||
# compiled in the same directory.
|
||||
|
|
@ -193,8 +208,8 @@ def require(cmd, exit=True, exception=False):
|
|||
if exception:
|
||||
raise
|
||||
elif exit:
|
||||
print("error: unable to run `{}`: {}".format(' '.join(cmd), exc))
|
||||
print("Please make sure it's installed and in the path.")
|
||||
print("error: unable to run `{}`: {}".format(' '.join(cmd), exc), file=sys.stderr)
|
||||
print("Please make sure it's installed and in the path.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
return None
|
||||
|
||||
|
|
@ -218,8 +233,8 @@ def default_build_triple(verbose):
|
|||
|
||||
if sys.platform == 'darwin':
|
||||
if verbose:
|
||||
print("not using rustc detection as it is unreliable on macOS")
|
||||
print("falling back to auto-detect")
|
||||
print("not using rustc detection as it is unreliable on macOS", file=sys.stderr)
|
||||
print("falling back to auto-detect", file=sys.stderr)
|
||||
else:
|
||||
try:
|
||||
version = subprocess.check_output(["rustc", "--version", "--verbose"],
|
||||
|
|
@ -228,12 +243,14 @@ def default_build_triple(verbose):
|
|||
host = next(x for x in version.split('\n') if x.startswith("host: "))
|
||||
triple = host.split("host: ")[1]
|
||||
if verbose:
|
||||
print("detected default triple {} from pre-installed rustc".format(triple))
|
||||
print("detected default triple {} from pre-installed rustc".format(triple),
|
||||
file=sys.stderr)
|
||||
return triple
|
||||
except Exception as e:
|
||||
if verbose:
|
||||
print("pre-installed rustc not detected: {}".format(e))
|
||||
print("falling back to auto-detect")
|
||||
print("pre-installed rustc not detected: {}".format(e),
|
||||
file=sys.stderr)
|
||||
print("falling back to auto-detect", file=sys.stderr)
|
||||
|
||||
required = not platform_is_win32()
|
||||
ostype = require(["uname", "-s"], exit=required)
|
||||
|
|
@ -404,6 +421,48 @@ class Stage0Toolchain:
|
|||
return self.version + "-" + self.date
|
||||
|
||||
|
||||
class DownloadInfo:
|
||||
"""A helper class that can be pickled into a parallel subprocess"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
base_download_url,
|
||||
download_path,
|
||||
bin_root,
|
||||
tarball_path,
|
||||
tarball_suffix,
|
||||
checksums_sha256,
|
||||
pattern,
|
||||
verbose,
|
||||
):
|
||||
self.base_download_url = base_download_url
|
||||
self.download_path = download_path
|
||||
self.bin_root = bin_root
|
||||
self.tarball_path = tarball_path
|
||||
self.tarball_suffix = tarball_suffix
|
||||
self.checksums_sha256 = checksums_sha256
|
||||
self.pattern = pattern
|
||||
self.verbose = verbose
|
||||
|
||||
def download_component(download_info):
|
||||
if not os.path.exists(download_info.tarball_path):
|
||||
get(
|
||||
download_info.base_download_url,
|
||||
download_info.download_path,
|
||||
download_info.tarball_path,
|
||||
download_info.checksums_sha256,
|
||||
verbose=download_info.verbose,
|
||||
)
|
||||
|
||||
def unpack_component(download_info):
|
||||
unpack(
|
||||
download_info.tarball_path,
|
||||
download_info.tarball_suffix,
|
||||
download_info.bin_root,
|
||||
match=download_info.pattern,
|
||||
verbose=download_info.verbose,
|
||||
)
|
||||
|
||||
class RustBuild(object):
|
||||
"""Provide all the methods required to build Rust"""
|
||||
def __init__(self):
|
||||
|
|
@ -458,17 +517,53 @@ class RustBuild(object):
|
|||
)
|
||||
run_powershell([script])
|
||||
shutil.rmtree(bin_root)
|
||||
|
||||
key = self.stage0_compiler.date
|
||||
cache_dst = os.path.join(self.build_dir, "cache")
|
||||
rustc_cache = os.path.join(cache_dst, key)
|
||||
if not os.path.exists(rustc_cache):
|
||||
os.makedirs(rustc_cache)
|
||||
|
||||
tarball_suffix = '.tar.gz' if lzma is None else '.tar.xz'
|
||||
filename = "rust-std-{}-{}{}".format(
|
||||
rustc_channel, self.build, tarball_suffix)
|
||||
pattern = "rust-std-{}".format(self.build)
|
||||
self._download_component_helper(filename, pattern, tarball_suffix)
|
||||
filename = "rustc-{}-{}{}".format(rustc_channel, self.build,
|
||||
tarball_suffix)
|
||||
self._download_component_helper(filename, "rustc", tarball_suffix)
|
||||
filename = "cargo-{}-{}{}".format(rustc_channel, self.build,
|
||||
tarball_suffix)
|
||||
self._download_component_helper(filename, "cargo", tarball_suffix)
|
||||
|
||||
toolchain_suffix = "{}-{}{}".format(rustc_channel, self.build, tarball_suffix)
|
||||
|
||||
tarballs_to_download = [
|
||||
("rust-std-{}".format(toolchain_suffix), "rust-std-{}".format(self.build)),
|
||||
("rustc-{}".format(toolchain_suffix), "rustc"),
|
||||
("cargo-{}".format(toolchain_suffix), "cargo"),
|
||||
]
|
||||
|
||||
tarballs_download_info = [
|
||||
DownloadInfo(
|
||||
base_download_url=self.download_url,
|
||||
download_path="dist/{}/{}".format(self.stage0_compiler.date, filename),
|
||||
bin_root=self.bin_root(),
|
||||
tarball_path=os.path.join(rustc_cache, filename),
|
||||
tarball_suffix=tarball_suffix,
|
||||
checksums_sha256=self.checksums_sha256,
|
||||
pattern=pattern,
|
||||
verbose=self.verbose,
|
||||
)
|
||||
for filename, pattern in tarballs_to_download
|
||||
]
|
||||
|
||||
# Download the components serially to show the progress bars properly.
|
||||
for download_info in tarballs_download_info:
|
||||
download_component(download_info)
|
||||
|
||||
# Unpack the tarballs in parallle.
|
||||
# In Python 2.7, Pool cannot be used as a context manager.
|
||||
pool_size = min(len(tarballs_download_info), get_cpus())
|
||||
if self.verbose:
|
||||
print('Choosing a pool size of', pool_size, 'for the unpacking of the tarballs')
|
||||
p = Pool(pool_size)
|
||||
try:
|
||||
p.map(unpack_component, tarballs_download_info)
|
||||
finally:
|
||||
p.close()
|
||||
p.join()
|
||||
|
||||
if self.should_fix_bins_and_dylibs():
|
||||
self.fix_bin_or_dylib("{}/bin/cargo".format(bin_root))
|
||||
|
||||
|
|
@ -484,13 +579,9 @@ class RustBuild(object):
|
|||
rust_stamp.write(key)
|
||||
|
||||
def _download_component_helper(
|
||||
self, filename, pattern, tarball_suffix,
|
||||
self, filename, pattern, tarball_suffix, rustc_cache,
|
||||
):
|
||||
key = self.stage0_compiler.date
|
||||
cache_dst = os.path.join(self.build_dir, "cache")
|
||||
rustc_cache = os.path.join(cache_dst, key)
|
||||
if not os.path.exists(rustc_cache):
|
||||
os.makedirs(rustc_cache)
|
||||
|
||||
tarball = os.path.join(rustc_cache, filename)
|
||||
if not os.path.exists(tarball):
|
||||
|
|
@ -545,7 +636,7 @@ class RustBuild(object):
|
|||
|
||||
answer = self._should_fix_bins_and_dylibs = get_answer()
|
||||
if answer:
|
||||
print("info: You seem to be using Nix.")
|
||||
print("info: You seem to be using Nix.", file=sys.stderr)
|
||||
return answer
|
||||
|
||||
def fix_bin_or_dylib(self, fname):
|
||||
|
|
@ -558,7 +649,7 @@ class RustBuild(object):
|
|||
Please see https://nixos.org/patchelf.html for more information
|
||||
"""
|
||||
assert self._should_fix_bins_and_dylibs is True
|
||||
print("attempting to patch", fname)
|
||||
print("attempting to patch", fname, file=sys.stderr)
|
||||
|
||||
# Only build `.nix-deps` once.
|
||||
nix_deps_dir = self.nix_deps_dir
|
||||
|
|
@ -591,7 +682,7 @@ class RustBuild(object):
|
|||
"nix-build", "-E", nix_expr, "-o", nix_deps_dir,
|
||||
])
|
||||
except subprocess.CalledProcessError as reason:
|
||||
print("warning: failed to call nix-build:", reason)
|
||||
print("warning: failed to call nix-build:", reason, file=sys.stderr)
|
||||
return
|
||||
self.nix_deps_dir = nix_deps_dir
|
||||
|
||||
|
|
@ -611,7 +702,7 @@ class RustBuild(object):
|
|||
try:
|
||||
subprocess.check_output([patchelf] + patchelf_args + [fname])
|
||||
except subprocess.CalledProcessError as reason:
|
||||
print("warning: failed to call patchelf:", reason)
|
||||
print("warning: failed to call patchelf:", reason, file=sys.stderr)
|
||||
return
|
||||
|
||||
def rustc_stamp(self):
|
||||
|
|
@ -755,7 +846,7 @@ class RustBuild(object):
|
|||
if "GITHUB_ACTIONS" in env:
|
||||
print("::group::Building bootstrap")
|
||||
else:
|
||||
print("Building bootstrap")
|
||||
print("Building bootstrap", file=sys.stderr)
|
||||
build_dir = os.path.join(self.build_dir, "bootstrap")
|
||||
if self.clean and os.path.exists(build_dir):
|
||||
shutil.rmtree(build_dir)
|
||||
|
|
@ -849,9 +940,12 @@ class RustBuild(object):
|
|||
if 'SUDO_USER' in os.environ and not self.use_vendored_sources:
|
||||
if os.getuid() == 0:
|
||||
self.use_vendored_sources = True
|
||||
print('info: looks like you\'re trying to run this command as root')
|
||||
print(' and so in order to preserve your $HOME this will now')
|
||||
print(' use vendored sources by default.')
|
||||
print('info: looks like you\'re trying to run this command as root',
|
||||
file=sys.stderr)
|
||||
print(' and so in order to preserve your $HOME this will now',
|
||||
file=sys.stderr)
|
||||
print(' use vendored sources by default.',
|
||||
file=sys.stderr)
|
||||
|
||||
cargo_dir = os.path.join(self.rust_root, '.cargo')
|
||||
if self.use_vendored_sources:
|
||||
|
|
@ -861,14 +955,18 @@ class RustBuild(object):
|
|||
"--sync ./src/tools/rust-analyzer/Cargo.toml " \
|
||||
"--sync ./compiler/rustc_codegen_cranelift/Cargo.toml " \
|
||||
"--sync ./src/bootstrap/Cargo.toml "
|
||||
print('error: vendoring required, but vendor directory does not exist.')
|
||||
print('error: vendoring required, but vendor directory does not exist.',
|
||||
file=sys.stderr)
|
||||
print(' Run `cargo vendor {}` to initialize the '
|
||||
'vendor directory.'.format(sync_dirs))
|
||||
print('Alternatively, use the pre-vendored `rustc-src` dist component.')
|
||||
'vendor directory.'.format(sync_dirs),
|
||||
file=sys.stderr)
|
||||
print('Alternatively, use the pre-vendored `rustc-src` dist component.',
|
||||
file=sys.stderr)
|
||||
raise Exception("{} not found".format(vendor_dir))
|
||||
|
||||
if not os.path.exists(cargo_dir):
|
||||
print('error: vendoring required, but .cargo/config does not exist.')
|
||||
print('error: vendoring required, but .cargo/config does not exist.',
|
||||
file=sys.stderr)
|
||||
raise Exception("{} not found".format(cargo_dir))
|
||||
else:
|
||||
if os.path.exists(cargo_dir):
|
||||
|
|
@ -978,7 +1076,7 @@ def main():
|
|||
print(
|
||||
"info: Downloading and building bootstrap before processing --help command.\n"
|
||||
" See src/bootstrap/README.md for help with common commands."
|
||||
)
|
||||
, file=sys.stderr)
|
||||
|
||||
exit_code = 0
|
||||
success_word = "successfully"
|
||||
|
|
@ -989,11 +1087,12 @@ def main():
|
|||
exit_code = error.code
|
||||
else:
|
||||
exit_code = 1
|
||||
print(error)
|
||||
print(error, file=sys.stderr)
|
||||
success_word = "unsuccessfully"
|
||||
|
||||
if not help_triggered:
|
||||
print("Build completed", success_word, "in", format_build_time(time() - start_time))
|
||||
print("Build completed", success_word, "in", format_build_time(time() - start_time),
|
||||
file=sys.stderr)
|
||||
sys.exit(exit_code)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -634,6 +634,14 @@ impl Kind {
|
|||
Kind::Suggest => "suggest",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_description(&self) -> &'static str {
|
||||
match self {
|
||||
Kind::Test => "Testing",
|
||||
Kind::Bench => "Benchmarking",
|
||||
_ => panic!("not a test command: {}!", self.as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Builder<'a> {
|
||||
|
|
@ -695,7 +703,6 @@ impl<'a> Builder<'a> {
|
|||
crate::toolstate::ToolStateCheck,
|
||||
test::ExpandYamlAnchors,
|
||||
test::Tidy,
|
||||
test::TidySelfTest,
|
||||
test::Ui,
|
||||
test::RunPassValgrind,
|
||||
test::MirOpt,
|
||||
|
|
@ -711,11 +718,9 @@ impl<'a> Builder<'a> {
|
|||
test::CrateLibrustc,
|
||||
test::CrateRustdoc,
|
||||
test::CrateRustdocJsonTypes,
|
||||
test::CrateJsonDocLint,
|
||||
test::SuggestTestsCrate,
|
||||
test::CrateBootstrap,
|
||||
test::Linkcheck,
|
||||
test::TierCheck,
|
||||
test::ReplacePlaceholderTest,
|
||||
test::Cargotest,
|
||||
test::Cargo,
|
||||
test::RustAnalyzer,
|
||||
|
|
|
|||
|
|
@ -578,7 +578,6 @@ mod dist {
|
|||
compiler: Compiler { host, stage: 0 },
|
||||
target: host,
|
||||
mode: Mode::Std,
|
||||
test_kind: test::TestKind::Test,
|
||||
crates: vec![INTERNER.intern_str("std")],
|
||||
},]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1309,7 +1309,7 @@ impl Config {
|
|||
if config.llvm_from_ci {
|
||||
let triple = &config.build.triple;
|
||||
let ci_llvm_bin = config.ci_llvm_root().join("bin");
|
||||
let mut build_target = config
|
||||
let build_target = config
|
||||
.target_config
|
||||
.entry(config.build)
|
||||
.or_insert_with(|| Target::from_triple(&triple));
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ impl Config {
|
|||
is_nixos && !Path::new("/lib").exists()
|
||||
});
|
||||
if val {
|
||||
println!("info: You seem to be using Nix.");
|
||||
eprintln!("info: You seem to be using Nix.");
|
||||
}
|
||||
val
|
||||
}
|
||||
|
|
@ -226,7 +226,7 @@ impl Config {
|
|||
curl.stdout(Stdio::from(f));
|
||||
if !self.check_run(&mut curl) {
|
||||
if self.build.contains("windows-msvc") {
|
||||
println!("Fallback to PowerShell");
|
||||
eprintln!("Fallback to PowerShell");
|
||||
for _ in 0..3 {
|
||||
if self.try_run(Command::new("PowerShell.exe").args(&[
|
||||
"/nologo",
|
||||
|
|
@ -239,7 +239,7 @@ impl Config {
|
|||
])) {
|
||||
return;
|
||||
}
|
||||
println!("\nspurious failure, trying again");
|
||||
eprintln!("\nspurious failure, trying again");
|
||||
}
|
||||
}
|
||||
if !help_on_error.is_empty() {
|
||||
|
|
@ -250,7 +250,7 @@ impl Config {
|
|||
}
|
||||
|
||||
fn unpack(&self, tarball: &Path, dst: &Path, pattern: &str) {
|
||||
println!("extracting {} to {}", tarball.display(), dst.display());
|
||||
eprintln!("extracting {} to {}", tarball.display(), dst.display());
|
||||
if !dst.exists() {
|
||||
t!(fs::create_dir_all(dst));
|
||||
}
|
||||
|
|
@ -541,7 +541,18 @@ impl Config {
|
|||
None
|
||||
};
|
||||
|
||||
self.download_file(&format!("{base_url}/{url}"), &tarball, "");
|
||||
let mut help_on_error = "";
|
||||
if destination == "ci-rustc" {
|
||||
help_on_error = "error: failed to download pre-built rustc from CI
|
||||
|
||||
note: old builds get deleted after a certain time
|
||||
help: if trying to compile an old commit of rustc, disable `download-rustc` in config.toml:
|
||||
|
||||
[rust]
|
||||
download-rustc = false
|
||||
";
|
||||
}
|
||||
self.download_file(&format!("{base_url}/{url}"), &tarball, help_on_error);
|
||||
if let Some(sha256) = checksum {
|
||||
if !self.verify(&tarball, sha256) {
|
||||
panic!("failed to verify {}", tarball.display());
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ struct Crate {
|
|||
name: Interned<String>,
|
||||
deps: HashSet<Interned<String>>,
|
||||
path: PathBuf,
|
||||
has_lib: bool,
|
||||
}
|
||||
|
||||
impl Crate {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use serde_derive::Deserialize;
|
|||
|
||||
use crate::cache::INTERNER;
|
||||
use crate::util::output;
|
||||
use crate::{Build, Crate};
|
||||
use crate::{t, Build, Crate};
|
||||
|
||||
/// For more information, see the output of
|
||||
/// <https://doc.rust-lang.org/nightly/cargo/commands/cargo-metadata.html>
|
||||
|
|
@ -22,6 +22,7 @@ struct Package {
|
|||
source: Option<String>,
|
||||
manifest_path: String,
|
||||
dependencies: Vec<Dependency>,
|
||||
targets: Vec<Target>,
|
||||
}
|
||||
|
||||
/// For more information, see the output of
|
||||
|
|
@ -32,6 +33,11 @@ struct Dependency {
|
|||
source: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Target {
|
||||
kind: Vec<String>,
|
||||
}
|
||||
|
||||
/// Collects and stores package metadata of each workspace members into `build`,
|
||||
/// by executing `cargo metadata` commands.
|
||||
pub fn build(build: &mut Build) {
|
||||
|
|
@ -46,11 +52,16 @@ pub fn build(build: &mut Build) {
|
|||
.filter(|dep| dep.source.is_none())
|
||||
.map(|dep| INTERNER.intern_string(dep.name))
|
||||
.collect();
|
||||
let krate = Crate { name, deps, path };
|
||||
let has_lib = package.targets.iter().any(|t| t.kind.iter().any(|k| k == "lib"));
|
||||
let krate = Crate { name, deps, path, has_lib };
|
||||
let relative_path = krate.local_path(build);
|
||||
build.crates.insert(name, krate);
|
||||
let existing_path = build.crate_paths.insert(relative_path, name);
|
||||
assert!(existing_path.is_none(), "multiple crates with the same path");
|
||||
assert!(
|
||||
existing_path.is_none(),
|
||||
"multiple crates with the same path: {}",
|
||||
existing_path.unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +71,7 @@ pub fn build(build: &mut Build) {
|
|||
/// Note that `src/tools/cargo` is no longer a workspace member but we still
|
||||
/// treat it as one here, by invoking an additional `cargo metadata` command.
|
||||
fn workspace_members(build: &Build) -> impl Iterator<Item = Package> {
|
||||
let cmd_metadata = |manifest_path| {
|
||||
let collect_metadata = |manifest_path| {
|
||||
let mut cargo = Command::new(&build.initial_cargo);
|
||||
cargo
|
||||
.arg("metadata")
|
||||
|
|
@ -68,21 +79,20 @@ fn workspace_members(build: &Build) -> impl Iterator<Item = Package> {
|
|||
.arg("1")
|
||||
.arg("--no-deps")
|
||||
.arg("--manifest-path")
|
||||
.arg(manifest_path);
|
||||
cargo
|
||||
.arg(build.src.join(manifest_path));
|
||||
let metadata_output = output(&mut cargo);
|
||||
let Output { packages, .. } = t!(serde_json::from_str(&metadata_output));
|
||||
packages
|
||||
};
|
||||
|
||||
// Collects `metadata.packages` from the root workspace.
|
||||
let root_manifest_path = build.src.join("Cargo.toml");
|
||||
let root_output = output(&mut cmd_metadata(&root_manifest_path));
|
||||
let Output { packages, .. } = serde_json::from_str(&root_output).unwrap();
|
||||
|
||||
// Collects `metadata.packages` from src/tools/cargo separately.
|
||||
let cargo_manifest_path = build.src.join("src/tools/cargo/Cargo.toml");
|
||||
let cargo_output = output(&mut cmd_metadata(&cargo_manifest_path));
|
||||
let Output { packages: cargo_packages, .. } = serde_json::from_str(&cargo_output).unwrap();
|
||||
// Collects `metadata.packages` from all workspaces.
|
||||
let packages = collect_metadata("Cargo.toml");
|
||||
let cargo_packages = collect_metadata("src/tools/cargo/Cargo.toml");
|
||||
let ra_packages = collect_metadata("src/tools/rust-analyzer/Cargo.toml");
|
||||
let bootstrap_packages = collect_metadata("src/bootstrap/Cargo.toml");
|
||||
|
||||
// We only care about the root package from `src/tool/cargo` workspace.
|
||||
let cargo_package = cargo_packages.into_iter().find(|pkg| pkg.name == "cargo").into_iter();
|
||||
packages.into_iter().chain(cargo_package)
|
||||
|
||||
packages.into_iter().chain(cargo_package).chain(ra_packages).chain(bootstrap_packages)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use std::process::{Command, Stdio};
|
|||
use crate::builder::crate_description;
|
||||
use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
|
||||
use crate::cache::Interned;
|
||||
use crate::cache::INTERNER;
|
||||
use crate::compile;
|
||||
use crate::config::TargetSelection;
|
||||
use crate::dist;
|
||||
|
|
@ -27,44 +28,6 @@ use crate::{envify, CLang, DocTests, GitRepo, Mode};
|
|||
|
||||
const ADB_TEST_DIR: &str = "/data/local/tmp/work";
|
||||
|
||||
/// The two modes of the test runner; tests or benchmarks.
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)]
|
||||
pub enum TestKind {
|
||||
/// Run `cargo test`.
|
||||
Test,
|
||||
/// Run `cargo bench`.
|
||||
Bench,
|
||||
}
|
||||
|
||||
impl From<Kind> for TestKind {
|
||||
fn from(kind: Kind) -> Self {
|
||||
match kind {
|
||||
Kind::Test => TestKind::Test,
|
||||
Kind::Bench => TestKind::Bench,
|
||||
_ => panic!("unexpected kind in crate: {:?}", kind),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TestKind {
|
||||
// Return the cargo subcommand for this test kind
|
||||
fn subcommand(self) -> &'static str {
|
||||
match self {
|
||||
TestKind::Test => "test",
|
||||
TestKind::Bench => "bench",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Kind> for TestKind {
|
||||
fn into(self) -> Kind {
|
||||
match self {
|
||||
TestKind::Test => Kind::Test,
|
||||
TestKind::Bench => Kind::Bench,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool {
|
||||
if !builder.fail_fast {
|
||||
if !builder.try_run(cmd) {
|
||||
|
|
@ -92,26 +55,37 @@ fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool {
|
|||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct CrateJsonDocLint {
|
||||
pub struct CrateBootstrap {
|
||||
path: Interned<PathBuf>,
|
||||
host: TargetSelection,
|
||||
}
|
||||
|
||||
impl Step for CrateJsonDocLint {
|
||||
impl Step for CrateBootstrap {
|
||||
type Output = ();
|
||||
const ONLY_HOSTS: bool = true;
|
||||
const DEFAULT: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/tools/jsondoclint")
|
||||
.path("src/tools/suggest-tests")
|
||||
.path("src/tools/replace-version-placeholder")
|
||||
.alias("tidyselftest")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(CrateJsonDocLint { host: run.target });
|
||||
for path in run.paths {
|
||||
let path = INTERNER.intern_path(path.assert_single_path().path.clone());
|
||||
run.builder.ensure(CrateBootstrap { host: run.target, path });
|
||||
}
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let bootstrap_host = builder.config.build;
|
||||
let compiler = builder.compiler(0, bootstrap_host);
|
||||
let mut path = self.path.to_str().unwrap();
|
||||
if path == "tidyselftest" {
|
||||
path = "src/tools/tidy";
|
||||
}
|
||||
|
||||
let cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
|
|
@ -119,47 +93,18 @@ impl Step for CrateJsonDocLint {
|
|||
Mode::ToolBootstrap,
|
||||
bootstrap_host,
|
||||
"test",
|
||||
"src/tools/jsondoclint",
|
||||
path,
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct SuggestTestsCrate {
|
||||
host: TargetSelection,
|
||||
}
|
||||
|
||||
impl Step for SuggestTestsCrate {
|
||||
type Output = ();
|
||||
const ONLY_HOSTS: bool = true;
|
||||
const DEFAULT: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/tools/suggest-tests")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(SuggestTestsCrate { host: run.target });
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let bootstrap_host = builder.config.build;
|
||||
let compiler = builder.compiler(0, bootstrap_host);
|
||||
|
||||
let suggest_tests = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
Mode::ToolBootstrap,
|
||||
builder.info(&format!(
|
||||
"{} {} stage0 ({})",
|
||||
builder.kind.test_description(),
|
||||
path,
|
||||
bootstrap_host,
|
||||
"test",
|
||||
"src/tools/suggest-tests",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
add_flags_and_try_run_tests(builder, &mut suggest_tests.into());
|
||||
));
|
||||
let crate_name = path.rsplit_once('/').unwrap().1;
|
||||
run_cargo_test(cargo, &[], &[], crate_name, compiler, bootstrap_host, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +153,11 @@ You can skip linkcheck with --exclude src/tools/linkchecker"
|
|||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
run_cargo_test(cargo, &[], &[], "linkchecker", compiler, bootstrap_host, builder);
|
||||
|
||||
if builder.doc_tests == DocTests::No {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build all the default documentation.
|
||||
builder.default_doc(&[]);
|
||||
|
|
@ -344,7 +293,7 @@ impl Step for Cargo {
|
|||
let compiler = builder.compiler(self.stage, self.host);
|
||||
|
||||
builder.ensure(tool::Cargo { compiler, target: self.host });
|
||||
let mut cargo = tool::prepare_tool_cargo(
|
||||
let cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
Mode::ToolRustc,
|
||||
|
|
@ -355,10 +304,8 @@ impl Step for Cargo {
|
|||
&[],
|
||||
);
|
||||
|
||||
if !builder.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
}
|
||||
cargo.arg("--").args(builder.config.cmd.test_args());
|
||||
// NOTE: can't use `run_cargo_test` because we need to overwrite `PATH`
|
||||
let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", compiler, self.host, builder);
|
||||
|
||||
// Don't run cross-compile tests, we may not have cross-compiled libstd libs
|
||||
// available.
|
||||
|
|
@ -366,10 +313,10 @@ impl Step for Cargo {
|
|||
// Forcibly disable tests using nightly features since any changes to
|
||||
// those features won't be able to land.
|
||||
cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
|
||||
|
||||
cargo.env("PATH", &path_for_cargo(builder, compiler));
|
||||
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
let _time = util::timeit(&builder);
|
||||
add_flags_and_try_run_tests(builder, &mut cargo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -426,9 +373,7 @@ impl Step for RustAnalyzer {
|
|||
cargo.env("SKIP_SLOW_TESTS", "1");
|
||||
|
||||
cargo.add_rustc_lib_path(builder, compiler);
|
||||
cargo.arg("--").args(builder.config.cmd.test_args());
|
||||
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
run_cargo_test(cargo, &[], &[], "rust-analyzer", compiler, host, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -471,17 +416,13 @@ impl Step for Rustfmt {
|
|||
&[],
|
||||
);
|
||||
|
||||
if !builder.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
}
|
||||
|
||||
let dir = testdir(builder, compiler.host);
|
||||
t!(fs::create_dir_all(&dir));
|
||||
cargo.env("RUSTFMT_TEST_DIR", dir);
|
||||
|
||||
cargo.add_rustc_lib_path(builder, compiler);
|
||||
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
run_cargo_test(cargo, &[], &[], "rustfmt", compiler, host, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -527,12 +468,9 @@ impl Step for RustDemangler {
|
|||
t!(fs::create_dir_all(&dir));
|
||||
|
||||
cargo.env("RUST_DEMANGLER_DRIVER_PATH", rust_demangler);
|
||||
|
||||
cargo.arg("--").args(builder.config.cmd.test_args());
|
||||
|
||||
cargo.add_rustc_lib_path(builder, compiler);
|
||||
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
run_cargo_test(cargo, &[], &[], "rust-demangler", compiler, host, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -655,10 +593,6 @@ impl Step for Miri {
|
|||
);
|
||||
cargo.add_rustc_lib_path(builder, compiler);
|
||||
|
||||
if !builder.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
}
|
||||
|
||||
// miri tests need to know about the stage sysroot
|
||||
cargo.env("MIRI_SYSROOT", &miri_sysroot);
|
||||
cargo.env("MIRI_HOST_SYSROOT", sysroot);
|
||||
|
|
@ -670,13 +604,14 @@ impl Step for Miri {
|
|||
|
||||
// Set the target.
|
||||
cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
|
||||
// Forward test filters.
|
||||
cargo.arg("--").args(builder.config.cmd.test_args());
|
||||
|
||||
// This can NOT be `add_flags_and_try_run_tests` since the Miri test runner
|
||||
// does not understand those flags!
|
||||
let mut cargo = Command::from(cargo);
|
||||
builder.run(&mut cargo);
|
||||
// This can NOT be `run_cargo_test` since the Miri test runner
|
||||
// does not understand the flags added by `add_flags_and_try_run_test`.
|
||||
let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
|
||||
{
|
||||
let _time = util::timeit(&builder);
|
||||
builder.run(&mut cargo);
|
||||
}
|
||||
|
||||
// # Run `cargo miri test`.
|
||||
// This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures
|
||||
|
|
@ -709,6 +644,7 @@ impl Step for Miri {
|
|||
cargo.env("RUST_BACKTRACE", "1");
|
||||
|
||||
let mut cargo = Command::from(cargo);
|
||||
let _time = util::timeit(&builder);
|
||||
builder.run(&mut cargo);
|
||||
}
|
||||
}
|
||||
|
|
@ -748,8 +684,7 @@ impl Step for CompiletestTest {
|
|||
&[],
|
||||
);
|
||||
cargo.allow_features("test");
|
||||
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
run_cargo_test(cargo, &[], &[], "compiletest", compiler, host, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -792,20 +727,15 @@ impl Step for Clippy {
|
|||
&[],
|
||||
);
|
||||
|
||||
if !builder.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
}
|
||||
|
||||
cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
|
||||
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
|
||||
let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
|
||||
cargo.env("HOST_LIBS", host_libs);
|
||||
|
||||
cargo.arg("--").args(builder.config.cmd.test_args());
|
||||
|
||||
cargo.add_rustc_lib_path(builder, compiler);
|
||||
let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
|
||||
|
||||
if builder.try_run(&mut cargo.into()) {
|
||||
if builder.try_run(&mut cargo) {
|
||||
// The tests succeeded; nothing to do.
|
||||
return;
|
||||
}
|
||||
|
|
@ -1203,40 +1133,6 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy`
|
|||
}
|
||||
}
|
||||
|
||||
/// Runs tidy's own tests.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct TidySelfTest;
|
||||
|
||||
impl Step for TidySelfTest {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.alias("tidyselftest")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(TidySelfTest);
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let bootstrap_host = builder.config.build;
|
||||
let compiler = builder.compiler(0, bootstrap_host);
|
||||
let cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
Mode::ToolBootstrap,
|
||||
bootstrap_host,
|
||||
"test",
|
||||
"src/tools/tidy",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ExpandYamlAnchors;
|
||||
|
||||
|
|
@ -2111,7 +2007,6 @@ impl Step for RustcGuide {
|
|||
pub struct CrateLibrustc {
|
||||
compiler: Compiler,
|
||||
target: TargetSelection,
|
||||
test_kind: TestKind,
|
||||
crates: Vec<Interned<String>>,
|
||||
}
|
||||
|
||||
|
|
@ -2133,9 +2028,8 @@ impl Step for CrateLibrustc {
|
|||
.iter()
|
||||
.map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
|
||||
.collect();
|
||||
let test_kind = builder.kind.into();
|
||||
|
||||
builder.ensure(CrateLibrustc { compiler, target: run.target, test_kind, crates });
|
||||
builder.ensure(CrateLibrustc { compiler, target: run.target, crates });
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
|
|
@ -2143,18 +2037,106 @@ impl Step for CrateLibrustc {
|
|||
compiler: self.compiler,
|
||||
target: self.target,
|
||||
mode: Mode::Rustc,
|
||||
test_kind: self.test_kind,
|
||||
crates: self.crates,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a `cargo test` subcommand, add the appropriate flags and run it.
|
||||
///
|
||||
/// Returns whether the test succeeded.
|
||||
fn run_cargo_test(
|
||||
cargo: impl Into<Command>,
|
||||
libtest_args: &[&str],
|
||||
crates: &[Interned<String>],
|
||||
primary_crate: &str,
|
||||
compiler: Compiler,
|
||||
target: TargetSelection,
|
||||
builder: &Builder<'_>,
|
||||
) -> bool {
|
||||
let mut cargo =
|
||||
prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder);
|
||||
let _time = util::timeit(&builder);
|
||||
add_flags_and_try_run_tests(builder, &mut cargo)
|
||||
}
|
||||
|
||||
/// Given a `cargo test` subcommand, pass it the appropriate test flags given a `builder`.
|
||||
fn prepare_cargo_test(
|
||||
cargo: impl Into<Command>,
|
||||
libtest_args: &[&str],
|
||||
crates: &[Interned<String>],
|
||||
primary_crate: &str,
|
||||
compiler: Compiler,
|
||||
target: TargetSelection,
|
||||
builder: &Builder<'_>,
|
||||
) -> Command {
|
||||
let mut cargo = cargo.into();
|
||||
|
||||
// Pass in some standard flags then iterate over the graph we've discovered
|
||||
// in `cargo metadata` with the maps above and figure out what `-p`
|
||||
// arguments need to get passed.
|
||||
if builder.kind == Kind::Test && !builder.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
}
|
||||
match builder.doc_tests {
|
||||
DocTests::Only => {
|
||||
cargo.arg("--doc");
|
||||
}
|
||||
DocTests::No => {
|
||||
let krate = &builder
|
||||
.crates
|
||||
.get(&INTERNER.intern_str(primary_crate))
|
||||
.unwrap_or_else(|| panic!("missing crate {primary_crate}"));
|
||||
if krate.has_lib {
|
||||
cargo.arg("--lib");
|
||||
}
|
||||
cargo.args(&["--bins", "--examples", "--tests", "--benches"]);
|
||||
}
|
||||
DocTests::Yes => {}
|
||||
}
|
||||
|
||||
for &krate in crates {
|
||||
cargo.arg("-p").arg(krate);
|
||||
}
|
||||
|
||||
cargo.arg("--").args(&builder.config.cmd.test_args()).args(libtest_args);
|
||||
if !builder.config.verbose_tests {
|
||||
cargo.arg("--quiet");
|
||||
}
|
||||
|
||||
// The tests are going to run with the *target* libraries, so we need to
|
||||
// ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
|
||||
//
|
||||
// Note that to run the compiler we need to run with the *host* libraries,
|
||||
// but our wrapper scripts arrange for that to be the case anyway.
|
||||
let mut dylib_path = dylib_path();
|
||||
dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
|
||||
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
|
||||
|
||||
if target.contains("emscripten") {
|
||||
cargo.env(
|
||||
format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
|
||||
builder.config.nodejs.as_ref().expect("nodejs not configured"),
|
||||
);
|
||||
} else if target.starts_with("wasm32") {
|
||||
let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
|
||||
let runner = format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
|
||||
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
|
||||
} else if builder.remote_tested(target) {
|
||||
cargo.env(
|
||||
format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
|
||||
format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
|
||||
);
|
||||
}
|
||||
|
||||
cargo
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Crate {
|
||||
pub compiler: Compiler,
|
||||
pub target: TargetSelection,
|
||||
pub mode: Mode,
|
||||
pub test_kind: TestKind,
|
||||
pub crates: Vec<Interned<String>>,
|
||||
}
|
||||
|
||||
|
|
@ -2170,14 +2152,13 @@ impl Step for Crate {
|
|||
let builder = run.builder;
|
||||
let host = run.build_triple();
|
||||
let compiler = builder.compiler_for(builder.top_stage, host, host);
|
||||
let test_kind = builder.kind.into();
|
||||
let crates = run
|
||||
.paths
|
||||
.iter()
|
||||
.map(|p| builder.crate_paths[&p.assert_single_path().path].clone())
|
||||
.collect();
|
||||
|
||||
builder.ensure(Crate { compiler, target: run.target, mode: Mode::Std, test_kind, crates });
|
||||
builder.ensure(Crate { compiler, target: run.target, mode: Mode::Std, crates });
|
||||
}
|
||||
|
||||
/// Runs all unit tests plus documentation tests for a given crate defined
|
||||
|
|
@ -2192,7 +2173,6 @@ impl Step for Crate {
|
|||
let compiler = self.compiler;
|
||||
let target = self.target;
|
||||
let mode = self.mode;
|
||||
let test_kind = self.test_kind;
|
||||
|
||||
builder.ensure(compile::Std::new(compiler, target));
|
||||
builder.ensure(RemoteCopyLibs { compiler, target });
|
||||
|
|
@ -2204,7 +2184,7 @@ impl Step for Crate {
|
|||
let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
|
||||
|
||||
let mut cargo =
|
||||
builder.cargo(compiler, mode, SourceType::InTree, target, test_kind.subcommand());
|
||||
builder.cargo(compiler, mode, SourceType::InTree, target, builder.kind.as_str());
|
||||
match mode {
|
||||
Mode::Std => {
|
||||
compile::std_cargo(builder, target, compiler.stage, &mut cargo);
|
||||
|
|
@ -2215,69 +2195,14 @@ impl Step for Crate {
|
|||
_ => panic!("can only test libraries"),
|
||||
};
|
||||
|
||||
// Build up the base `cargo test` command.
|
||||
//
|
||||
// Pass in some standard flags then iterate over the graph we've discovered
|
||||
// in `cargo metadata` with the maps above and figure out what `-p`
|
||||
// arguments need to get passed.
|
||||
if test_kind.subcommand() == "test" && !builder.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
}
|
||||
match builder.doc_tests {
|
||||
DocTests::Only => {
|
||||
cargo.arg("--doc");
|
||||
}
|
||||
DocTests::No => {
|
||||
cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
|
||||
}
|
||||
DocTests::Yes => {}
|
||||
}
|
||||
|
||||
for krate in &self.crates {
|
||||
cargo.arg("-p").arg(krate);
|
||||
}
|
||||
|
||||
// The tests are going to run with the *target* libraries, so we need to
|
||||
// ensure that those libraries show up in the LD_LIBRARY_PATH equivalent.
|
||||
//
|
||||
// Note that to run the compiler we need to run with the *host* libraries,
|
||||
// but our wrapper scripts arrange for that to be the case anyway.
|
||||
let mut dylib_path = dylib_path();
|
||||
dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target)));
|
||||
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
|
||||
|
||||
cargo.arg("--");
|
||||
cargo.args(&builder.config.cmd.test_args());
|
||||
|
||||
cargo.arg("-Z").arg("unstable-options");
|
||||
cargo.arg("--format").arg("json");
|
||||
|
||||
if target.contains("emscripten") {
|
||||
cargo.env(
|
||||
format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
|
||||
builder.config.nodejs.as_ref().expect("nodejs not configured"),
|
||||
);
|
||||
} else if target.starts_with("wasm32") {
|
||||
let node = builder.config.nodejs.as_ref().expect("nodejs not configured");
|
||||
let runner =
|
||||
format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display());
|
||||
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner);
|
||||
} else if builder.remote_tested(target) {
|
||||
cargo.env(
|
||||
format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)),
|
||||
format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()),
|
||||
);
|
||||
}
|
||||
|
||||
let _guard = builder.msg(
|
||||
test_kind,
|
||||
builder.kind,
|
||||
compiler.stage,
|
||||
crate_description(&self.crates),
|
||||
compiler.host,
|
||||
target,
|
||||
);
|
||||
let _time = util::timeit(&builder);
|
||||
crate::render_tests::try_run_tests(builder, &mut cargo.into());
|
||||
run_cargo_test(cargo, &[], &self.crates, &self.crates[0], compiler, target, builder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2285,7 +2210,6 @@ impl Step for Crate {
|
|||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct CrateRustdoc {
|
||||
host: TargetSelection,
|
||||
test_kind: TestKind,
|
||||
}
|
||||
|
||||
impl Step for CrateRustdoc {
|
||||
|
|
@ -2300,13 +2224,10 @@ impl Step for CrateRustdoc {
|
|||
fn make_run(run: RunConfig<'_>) {
|
||||
let builder = run.builder;
|
||||
|
||||
let test_kind = builder.kind.into();
|
||||
|
||||
builder.ensure(CrateRustdoc { host: run.target, test_kind });
|
||||
builder.ensure(CrateRustdoc { host: run.target });
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let test_kind = self.test_kind;
|
||||
let target = self.host;
|
||||
|
||||
let compiler = if builder.download_rustc() {
|
||||
|
|
@ -2325,29 +2246,11 @@ impl Step for CrateRustdoc {
|
|||
compiler,
|
||||
Mode::ToolRustc,
|
||||
target,
|
||||
test_kind.subcommand(),
|
||||
builder.kind.as_str(),
|
||||
"src/tools/rustdoc",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
if test_kind.subcommand() == "test" && !builder.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
}
|
||||
match builder.doc_tests {
|
||||
DocTests::Only => {
|
||||
cargo.arg("--doc");
|
||||
}
|
||||
DocTests::No => {
|
||||
cargo.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
|
||||
}
|
||||
DocTests::Yes => {}
|
||||
}
|
||||
|
||||
cargo.arg("-p").arg("rustdoc:0.0.0");
|
||||
|
||||
cargo.arg("--");
|
||||
cargo.args(&builder.config.cmd.test_args());
|
||||
|
||||
if self.host.contains("musl") {
|
||||
cargo.arg("'-Ctarget-feature=-crt-static'");
|
||||
}
|
||||
|
|
@ -2387,22 +2290,22 @@ impl Step for CrateRustdoc {
|
|||
dylib_path.insert(0, PathBuf::from(&*libdir));
|
||||
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
|
||||
|
||||
if !builder.config.verbose_tests {
|
||||
cargo.arg("--quiet");
|
||||
}
|
||||
|
||||
let _guard = builder.msg(test_kind, compiler.stage, "rustdoc", compiler.host, target);
|
||||
|
||||
let _time = util::timeit(&builder);
|
||||
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
let _guard = builder.msg(builder.kind, compiler.stage, "rustdoc", compiler.host, target);
|
||||
run_cargo_test(
|
||||
cargo,
|
||||
&[],
|
||||
&[INTERNER.intern_str("rustdoc:0.0.0")],
|
||||
"rustdoc",
|
||||
compiler,
|
||||
target,
|
||||
builder,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct CrateRustdocJsonTypes {
|
||||
host: TargetSelection,
|
||||
test_kind: TestKind,
|
||||
}
|
||||
|
||||
impl Step for CrateRustdocJsonTypes {
|
||||
|
|
@ -2417,13 +2320,10 @@ impl Step for CrateRustdocJsonTypes {
|
|||
fn make_run(run: RunConfig<'_>) {
|
||||
let builder = run.builder;
|
||||
|
||||
let test_kind = builder.kind.into();
|
||||
|
||||
builder.ensure(CrateRustdocJsonTypes { host: run.target, test_kind });
|
||||
builder.ensure(CrateRustdocJsonTypes { host: run.target });
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let test_kind = self.test_kind;
|
||||
let target = self.host;
|
||||
|
||||
// Use the previous stage compiler to reuse the artifacts that are
|
||||
|
|
@ -2433,34 +2333,35 @@ impl Step for CrateRustdocJsonTypes {
|
|||
let compiler = builder.compiler_for(builder.top_stage, target, target);
|
||||
builder.ensure(compile::Rustc::new(compiler, target));
|
||||
|
||||
let mut cargo = tool::prepare_tool_cargo(
|
||||
let cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
Mode::ToolRustc,
|
||||
target,
|
||||
test_kind.subcommand(),
|
||||
builder.kind.as_str(),
|
||||
"src/rustdoc-json-types",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
if test_kind.subcommand() == "test" && !builder.fail_fast {
|
||||
cargo.arg("--no-fail-fast");
|
||||
}
|
||||
|
||||
cargo.arg("-p").arg("rustdoc-json-types");
|
||||
|
||||
cargo.arg("--");
|
||||
cargo.args(&builder.config.cmd.test_args());
|
||||
|
||||
if self.host.contains("musl") {
|
||||
cargo.arg("'-Ctarget-feature=-crt-static'");
|
||||
}
|
||||
// FIXME: this looks very wrong, libtest doesn't accept `-C` arguments and the quotes are fishy.
|
||||
let libtest_args = if self.host.contains("musl") {
|
||||
["'-Ctarget-feature=-crt-static'"].as_slice()
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
|
||||
let _guard =
|
||||
builder.msg(test_kind, compiler.stage, "rustdoc-json-types", compiler.host, target);
|
||||
let _time = util::timeit(&builder);
|
||||
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
builder.msg(builder.kind, compiler.stage, "rustdoc-json-types", compiler.host, target);
|
||||
run_cargo_test(
|
||||
cargo,
|
||||
libtest_args,
|
||||
&[INTERNER.intern_str("rustdoc-json-types")],
|
||||
"rustdoc-json-types",
|
||||
compiler,
|
||||
target,
|
||||
builder,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2598,13 +2499,15 @@ impl Step for Bootstrap {
|
|||
check_bootstrap.arg("bootstrap_test.py").current_dir(builder.src.join("src/bootstrap/"));
|
||||
try_run(builder, &mut check_bootstrap);
|
||||
|
||||
let host = builder.config.build;
|
||||
let compiler = builder.compiler(0, host);
|
||||
let mut cmd = Command::new(&builder.initial_cargo);
|
||||
cmd.arg("test")
|
||||
.current_dir(builder.src.join("src/bootstrap"))
|
||||
.env("RUSTFLAGS", "-Cdebuginfo=2")
|
||||
.env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
|
||||
.env("RUSTC_BOOTSTRAP", "1")
|
||||
.env("RUSTDOC", builder.rustdoc(builder.compiler(0, builder.build.build)))
|
||||
.env("RUSTDOC", builder.rustdoc(compiler))
|
||||
.env("RUSTC", &builder.initial_rustc);
|
||||
if let Some(flags) = option_env!("RUSTFLAGS") {
|
||||
// Use the same rustc flags for testing as for "normal" compilation,
|
||||
|
|
@ -2612,24 +2515,9 @@ impl Step for Bootstrap {
|
|||
// https://github.com/rust-lang/rust/issues/49215
|
||||
cmd.env("RUSTFLAGS", flags);
|
||||
}
|
||||
if !builder.fail_fast {
|
||||
cmd.arg("--no-fail-fast");
|
||||
}
|
||||
match builder.doc_tests {
|
||||
DocTests::Only => {
|
||||
cmd.arg("--doc");
|
||||
}
|
||||
DocTests::No => {
|
||||
cmd.args(&["--lib", "--bins", "--examples", "--tests", "--benches"]);
|
||||
}
|
||||
DocTests::Yes => {}
|
||||
}
|
||||
|
||||
cmd.arg("--").args(&builder.config.cmd.test_args());
|
||||
// rustbuild tests are racy on directory creation so just run them one at a time.
|
||||
// Since there's not many this shouldn't be a problem.
|
||||
cmd.arg("--test-threads=1");
|
||||
add_flags_and_try_run_tests(builder, &mut cmd);
|
||||
run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", compiler, host, builder);
|
||||
}
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
|
|
@ -2685,43 +2573,6 @@ impl Step for TierCheck {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ReplacePlaceholderTest;
|
||||
|
||||
impl Step for ReplacePlaceholderTest {
|
||||
type Output = ();
|
||||
const ONLY_HOSTS: bool = true;
|
||||
const DEFAULT: bool = true;
|
||||
|
||||
/// Ensure the version placeholder replacement tool builds
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
builder.info("build check for version replacement placeholder");
|
||||
|
||||
// Test the version placeholder replacement tool itself.
|
||||
let bootstrap_host = builder.config.build;
|
||||
let compiler = builder.compiler(0, bootstrap_host);
|
||||
let cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
Mode::ToolBootstrap,
|
||||
bootstrap_host,
|
||||
"test",
|
||||
"src/tools/replace-version-placeholder",
|
||||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
add_flags_and_try_run_tests(builder, &mut cargo.into());
|
||||
}
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/tools/replace-version-placeholder")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(Self);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct LintDocs {
|
||||
pub compiler: Compiler,
|
||||
|
|
@ -2779,7 +2630,7 @@ impl Step for RustInstaller {
|
|||
SourceType::InTree,
|
||||
&[],
|
||||
);
|
||||
try_run(builder, &mut cargo.into());
|
||||
run_cargo_test(cargo, &[], &[], "installer", compiler, bootstrap_host, builder);
|
||||
|
||||
// We currently don't support running the test.sh script outside linux(?) environments.
|
||||
// Eventually this should likely migrate to #[test]s in rust-installer proper rather than a
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ pub fn prepare_tool_cargo(
|
|||
mode: Mode,
|
||||
target: TargetSelection,
|
||||
command: &'static str,
|
||||
path: &'static str,
|
||||
path: &str,
|
||||
source_type: SourceType,
|
||||
extra_features: &[String],
|
||||
) -> CargoCommand {
|
||||
|
|
|
|||
|
|
@ -1529,7 +1529,9 @@ fn maybe_expand_private_type_alias<'tcx>(
|
|||
let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
|
||||
// Substitute private type aliases
|
||||
let def_id = def_id.as_local()?;
|
||||
let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id()) {
|
||||
let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id())
|
||||
&& !cx.current_type_aliases.contains_key(&def_id.to_def_id())
|
||||
{
|
||||
&cx.tcx.hir().expect_item(def_id).kind
|
||||
} else {
|
||||
return None;
|
||||
|
|
@ -1609,7 +1611,7 @@ fn maybe_expand_private_type_alias<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
Some(cx.enter_alias(substs, |cx| clean_ty(ty, cx)))
|
||||
Some(cx.enter_alias(substs, def_id.to_def_id(), |cx| clean_ty(ty, cx)))
|
||||
}
|
||||
|
||||
pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
|
||||
|
|
@ -1700,7 +1702,7 @@ fn normalize<'tcx>(
|
|||
pub(crate) fn clean_middle_ty<'tcx>(
|
||||
bound_ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
def_id: Option<DefId>,
|
||||
parent_def_id: Option<DefId>,
|
||||
) -> Type {
|
||||
let bound_ty = normalize(cx, bound_ty).unwrap_or(bound_ty);
|
||||
match *bound_ty.skip_binder().kind() {
|
||||
|
|
@ -1830,7 +1832,9 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||
Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None)).collect())
|
||||
}
|
||||
|
||||
ty::Alias(ty::Projection, ref data) => clean_projection(bound_ty.rebind(*data), cx, def_id),
|
||||
ty::Alias(ty::Projection, ref data) => {
|
||||
clean_projection(bound_ty.rebind(*data), cx, parent_def_id)
|
||||
}
|
||||
|
||||
ty::Param(ref p) => {
|
||||
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
|
||||
|
|
@ -1841,15 +1845,30 @@ pub(crate) fn clean_middle_ty<'tcx>(
|
|||
}
|
||||
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
|
||||
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
|
||||
// by looking up the bounds associated with the def_id.
|
||||
let bounds = cx
|
||||
.tcx
|
||||
.explicit_item_bounds(def_id)
|
||||
.subst_iter_copied(cx.tcx, substs)
|
||||
.map(|(bound, _)| bound)
|
||||
.collect::<Vec<_>>();
|
||||
clean_middle_opaque_bounds(cx, bounds)
|
||||
// If it's already in the same alias, don't get an infinite loop.
|
||||
if cx.current_type_aliases.contains_key(&def_id) {
|
||||
let path =
|
||||
external_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(substs));
|
||||
Type::Path { path }
|
||||
} else {
|
||||
*cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
|
||||
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
|
||||
// by looking up the bounds associated with the def_id.
|
||||
let bounds = cx
|
||||
.tcx
|
||||
.explicit_item_bounds(def_id)
|
||||
.subst_iter_copied(cx.tcx, substs)
|
||||
.map(|(bound, _)| bound)
|
||||
.collect::<Vec<_>>();
|
||||
let ty = clean_middle_opaque_bounds(cx, bounds);
|
||||
if let Some(count) = cx.current_type_aliases.get_mut(&def_id) {
|
||||
*count -= 1;
|
||||
if *count == 0 {
|
||||
cx.current_type_aliases.remove(&def_id);
|
||||
}
|
||||
}
|
||||
ty
|
||||
}
|
||||
}
|
||||
|
||||
ty::Closure(..) => panic!("Closure"),
|
||||
|
|
@ -2229,13 +2248,17 @@ fn clean_maybe_renamed_item<'tcx>(
|
|||
generics: clean_generics(ty.generics, cx),
|
||||
}),
|
||||
ItemKind::TyAlias(hir_ty, generics) => {
|
||||
*cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
|
||||
let rustdoc_ty = clean_ty(hir_ty, cx);
|
||||
let ty = clean_middle_ty(ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)), cx, None);
|
||||
TypedefItem(Box::new(Typedef {
|
||||
type_: rustdoc_ty,
|
||||
generics: clean_generics(generics, cx),
|
||||
item_type: Some(ty),
|
||||
}))
|
||||
let generics = clean_generics(generics, cx);
|
||||
if let Some(count) = cx.current_type_aliases.get_mut(&def_id) {
|
||||
*count -= 1;
|
||||
if *count == 0 {
|
||||
cx.current_type_aliases.remove(&def_id);
|
||||
}
|
||||
}
|
||||
TypedefItem(Box::new(Typedef { type_: rustdoc_ty, generics, item_type: Some(ty) }))
|
||||
}
|
||||
ItemKind::Enum(ref def, generics) => EnumItem(Enum {
|
||||
variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use arrayvec::ArrayVec;
|
|||
use thin_vec::ThinVec;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
|
||||
use rustc_const_eval::const_eval::is_unstable_const_fn;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
|
@ -711,6 +712,78 @@ impl Item {
|
|||
};
|
||||
Some(tcx.visibility(def_id))
|
||||
}
|
||||
|
||||
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec<String> {
|
||||
const ALLOWED_ATTRIBUTES: &[Symbol] =
|
||||
&[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
|
||||
|
||||
use rustc_abi::IntegerType;
|
||||
use rustc_middle::ty::ReprFlags;
|
||||
|
||||
let mut attrs: Vec<String> = self
|
||||
.attrs
|
||||
.other_attrs
|
||||
.iter()
|
||||
.filter_map(|attr| {
|
||||
if keep_as_is {
|
||||
Some(pprust::attribute_to_string(attr))
|
||||
} else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
|
||||
Some(
|
||||
pprust::attribute_to_string(attr)
|
||||
.replace("\\\n", "")
|
||||
.replace('\n', "")
|
||||
.replace(" ", " "),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if let Some(def_id) = self.item_id.as_def_id() &&
|
||||
!def_id.is_local() &&
|
||||
// This check is needed because `adt_def` will panic if not a compatible type otherwise...
|
||||
matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union)
|
||||
{
|
||||
let repr = tcx.adt_def(def_id).repr();
|
||||
let mut out = Vec::new();
|
||||
if repr.flags.contains(ReprFlags::IS_C) {
|
||||
out.push("C");
|
||||
}
|
||||
if repr.flags.contains(ReprFlags::IS_TRANSPARENT) {
|
||||
out.push("transparent");
|
||||
}
|
||||
if repr.flags.contains(ReprFlags::IS_SIMD) {
|
||||
out.push("simd");
|
||||
}
|
||||
let pack_s;
|
||||
if let Some(pack) = repr.pack {
|
||||
pack_s = format!("packed({})", pack.bytes());
|
||||
out.push(&pack_s);
|
||||
}
|
||||
let align_s;
|
||||
if let Some(align) = repr.align {
|
||||
align_s = format!("align({})", align.bytes());
|
||||
out.push(&align_s);
|
||||
}
|
||||
let int_s;
|
||||
if let Some(int) = repr.int {
|
||||
int_s = match int {
|
||||
IntegerType::Pointer(is_signed) => {
|
||||
format!("{}size", if is_signed { 'i' } else { 'u' })
|
||||
}
|
||||
IntegerType::Fixed(size, is_signed) => {
|
||||
format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
|
||||
}
|
||||
};
|
||||
out.push(&int_s);
|
||||
}
|
||||
if out.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
attrs.push(format!("#[repr({})]", out.join(", ")));
|
||||
}
|
||||
attrs
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ pub(crate) struct DocContext<'tcx> {
|
|||
// for expanding type aliases at the HIR level:
|
||||
/// Table `DefId` of type, lifetime, or const parameter -> substituted type, lifetime, or const
|
||||
pub(crate) substs: DefIdMap<clean::SubstParam>,
|
||||
pub(crate) current_type_aliases: DefIdMap<usize>,
|
||||
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
|
||||
pub(crate) impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
|
||||
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
|
||||
|
|
@ -82,13 +83,25 @@ impl<'tcx> DocContext<'tcx> {
|
|||
|
||||
/// Call the closure with the given parameters set as
|
||||
/// the substitutions for a type alias' RHS.
|
||||
pub(crate) fn enter_alias<F, R>(&mut self, substs: DefIdMap<clean::SubstParam>, f: F) -> R
|
||||
pub(crate) fn enter_alias<F, R>(
|
||||
&mut self,
|
||||
substs: DefIdMap<clean::SubstParam>,
|
||||
def_id: DefId,
|
||||
f: F,
|
||||
) -> R
|
||||
where
|
||||
F: FnOnce(&mut Self) -> R,
|
||||
{
|
||||
let old_substs = mem::replace(&mut self.substs, substs);
|
||||
*self.current_type_aliases.entry(def_id).or_insert(0) += 1;
|
||||
let r = f(self);
|
||||
self.substs = old_substs;
|
||||
if let Some(count) = self.current_type_aliases.get_mut(&def_id) {
|
||||
*count -= 1;
|
||||
if *count == 0 {
|
||||
self.current_type_aliases.remove(&def_id);
|
||||
}
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
|
|
@ -327,6 +340,7 @@ pub(crate) fn run_global_ctxt(
|
|||
external_traits: Default::default(),
|
||||
active_extern_traits: Default::default(),
|
||||
substs: Default::default(),
|
||||
current_type_aliases: Default::default(),
|
||||
impl_trait_bounds: Default::default(),
|
||||
generated_synthetics: Default::default(),
|
||||
auto_traits,
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ use std::str;
|
|||
use std::string::ToString;
|
||||
|
||||
use askama::Template;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
|
@ -849,10 +848,10 @@ fn assoc_method(
|
|||
let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
|
||||
header_len += 4;
|
||||
let indent_str = " ";
|
||||
write!(w, "{}", render_attributes_in_pre(meth, indent_str));
|
||||
write!(w, "{}", render_attributes_in_pre(meth, indent_str, tcx));
|
||||
(4, indent_str, Ending::NoNewline)
|
||||
} else {
|
||||
render_attributes_in_code(w, meth);
|
||||
render_attributes_in_code(w, meth, tcx);
|
||||
(0, "", Ending::Newline)
|
||||
};
|
||||
w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
|
||||
|
|
@ -1021,36 +1020,15 @@ fn render_assoc_item(
|
|||
}
|
||||
}
|
||||
|
||||
const ALLOWED_ATTRIBUTES: &[Symbol] =
|
||||
&[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
|
||||
|
||||
fn attributes(it: &clean::Item) -> Vec<String> {
|
||||
it.attrs
|
||||
.other_attrs
|
||||
.iter()
|
||||
.filter_map(|attr| {
|
||||
if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
|
||||
Some(
|
||||
pprust::attribute_to_string(attr)
|
||||
.replace("\\\n", "")
|
||||
.replace('\n', "")
|
||||
.replace(" ", " "),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
// When an attribute is rendered inside a `<pre>` tag, it is formatted using
|
||||
// a whitespace prefix and newline.
|
||||
fn render_attributes_in_pre<'a>(
|
||||
fn render_attributes_in_pre<'a, 'b: 'a>(
|
||||
it: &'a clean::Item,
|
||||
prefix: &'a str,
|
||||
) -> impl fmt::Display + Captures<'a> {
|
||||
tcx: TyCtxt<'b>,
|
||||
) -> impl fmt::Display + Captures<'a> + Captures<'b> {
|
||||
crate::html::format::display_fn(move |f| {
|
||||
for a in attributes(it) {
|
||||
for a in it.attributes(tcx, false) {
|
||||
writeln!(f, "{}{}", prefix, a)?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -1059,8 +1037,8 @@ fn render_attributes_in_pre<'a>(
|
|||
|
||||
// When an attribute is rendered inside a <code> tag, it is formatted using
|
||||
// a div to produce a newline after it.
|
||||
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
|
||||
for a in attributes(it) {
|
||||
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item, tcx: TyCtxt<'_>) {
|
||||
for a in it.attributes(tcx, false) {
|
||||
write!(w, "<div class=\"code-attribute\">{}</div>", a);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -548,7 +548,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
|
|||
w,
|
||||
"{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \
|
||||
{name}{generics}{decl}{notable_traits}{where_clause}",
|
||||
attrs = render_attributes_in_pre(it, ""),
|
||||
attrs = render_attributes_in_pre(it, "", tcx),
|
||||
vis = visibility,
|
||||
constness = constness,
|
||||
asyncness = asyncness,
|
||||
|
|
@ -589,7 +589,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
|
|||
it.name.unwrap(),
|
||||
t.generics.print(cx),
|
||||
bounds,
|
||||
attrs = render_attributes_in_pre(it, ""),
|
||||
attrs = render_attributes_in_pre(it, "", tcx),
|
||||
);
|
||||
|
||||
if !t.generics.where_predicates.is_empty() {
|
||||
|
|
@ -1063,7 +1063,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &
|
|||
t.generics.print(cx),
|
||||
print_where_clause(&t.generics, cx, 0, Ending::Newline),
|
||||
bounds(&t.bounds, true, cx),
|
||||
attrs = render_attributes_in_pre(it, ""),
|
||||
attrs = render_attributes_in_pre(it, "", cx.tcx()),
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -1085,7 +1085,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl
|
|||
t.generics.print(cx),
|
||||
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
|
||||
bounds = bounds(&t.bounds, false, cx),
|
||||
attrs = render_attributes_in_pre(it, ""),
|
||||
attrs = render_attributes_in_pre(it, "", cx.tcx()),
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -1109,7 +1109,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
|
|||
t.generics.print(cx),
|
||||
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
|
||||
type_ = t.type_.print(cx),
|
||||
attrs = render_attributes_in_pre(it, ""),
|
||||
attrs = render_attributes_in_pre(it, "", cx.tcx()),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
@ -1168,7 +1168,8 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean:
|
|||
&'b self,
|
||||
) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
|
||||
display_fn(move |f| {
|
||||
let v = render_attributes_in_pre(self.it, "");
|
||||
let tcx = self.cx.borrow().tcx();
|
||||
let v = render_attributes_in_pre(self.it, "", tcx);
|
||||
write!(f, "{v}")
|
||||
})
|
||||
}
|
||||
|
|
@ -1244,13 +1245,13 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
|
|||
let tcx = cx.tcx();
|
||||
let count_variants = e.variants().count();
|
||||
wrap_item(w, |mut w| {
|
||||
render_attributes_in_code(w, it, tcx);
|
||||
write!(
|
||||
w,
|
||||
"{attrs}{}enum {}{}",
|
||||
"{}enum {}{}",
|
||||
visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
|
||||
it.name.unwrap(),
|
||||
e.generics.print(cx),
|
||||
attrs = render_attributes_in_pre(it, ""),
|
||||
);
|
||||
if !print_where_clause_and_check(w, &e.generics, cx) {
|
||||
// If there wasn't a `where` clause, we add a whitespace.
|
||||
|
|
@ -1445,7 +1446,7 @@ fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
|
|||
fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
|
||||
wrap_item(w, |w| {
|
||||
let tcx = cx.tcx();
|
||||
render_attributes_in_code(w, it);
|
||||
render_attributes_in_code(w, it, tcx);
|
||||
|
||||
write!(
|
||||
w,
|
||||
|
|
@ -1492,7 +1493,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
|
|||
|
||||
fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it);
|
||||
render_attributes_in_code(w, it, cx.tcx());
|
||||
render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
|
||||
});
|
||||
|
||||
|
|
@ -1542,7 +1543,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
|
|||
|
||||
fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it);
|
||||
render_attributes_in_code(w, it, cx.tcx());
|
||||
write!(
|
||||
w,
|
||||
"{vis}static {mutability}{name}: {typ}",
|
||||
|
|
@ -1558,7 +1559,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
|
|||
fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
|
||||
wrap_item(w, |w| {
|
||||
w.write_str("extern {\n");
|
||||
render_attributes_in_code(w, it);
|
||||
render_attributes_in_code(w, it, cx.tcx());
|
||||
write!(
|
||||
w,
|
||||
" {}type {};\n}}",
|
||||
|
|
|
|||
|
|
@ -41,12 +41,7 @@ impl JsonRenderer<'_> {
|
|||
})
|
||||
.collect();
|
||||
let docs = item.attrs.collapsed_doc_value();
|
||||
let attrs = item
|
||||
.attrs
|
||||
.other_attrs
|
||||
.iter()
|
||||
.map(rustc_ast_pretty::pprust::attribute_to_string)
|
||||
.collect();
|
||||
let attrs = item.attributes(self.tcx, true);
|
||||
let span = item.span(self.tcx);
|
||||
let visibility = item.visibility(self.tcx);
|
||||
let clean::Item { name, item_id, .. } = item;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ extern crate tracing;
|
|||
// Dependencies listed in Cargo.toml do not need `extern crate`.
|
||||
|
||||
extern crate pulldown_cmark;
|
||||
extern crate rustc_abi;
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_ast_pretty;
|
||||
extern crate rustc_attr;
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ fn ident_difference_expr_with_base_location(
|
|||
| (AssignOp(_, _, _), AssignOp(_, _, _))
|
||||
| (Assign(_, _, _), Assign(_, _, _))
|
||||
| (TryBlock(_), TryBlock(_))
|
||||
| (Await(_), Await(_))
|
||||
| (Await(_, _), Await(_, _))
|
||||
| (Async(_, _), Async(_, _))
|
||||
| (Block(_, _), Block(_, _))
|
||||
| (Closure(_), Closure(_))
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
|||
(Paren(l), _) => eq_expr(l, r),
|
||||
(_, Paren(r)) => eq_expr(l, r),
|
||||
(Err, Err) => true,
|
||||
(Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r),
|
||||
(Try(l), Try(r)) | (Await(l, _), Await(r, _)) => eq_expr(l, r),
|
||||
(Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)),
|
||||
(Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
|
||||
(Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),
|
||||
|
|
|
|||
|
|
@ -5,22 +5,22 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
|
|||
| ^^^^ future returned by `private_future` is not `Send`
|
||||
|
|
||||
note: future is not `Send` as this value is used across an await
|
||||
--> $DIR/future_not_send.rs:8:19
|
||||
--> $DIR/future_not_send.rs:8:20
|
||||
|
|
||||
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
|
||||
| -- has type `std::rc::Rc<[u8]>` which is not `Send`
|
||||
LL | async { true }.await
|
||||
| ^^^^^^ await occurs here, with `rc` maybe used later
|
||||
| ^^^^^ await occurs here, with `rc` maybe used later
|
||||
LL | }
|
||||
| - `rc` is later dropped here
|
||||
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
|
||||
note: future is not `Send` as this value is used across an await
|
||||
--> $DIR/future_not_send.rs:8:19
|
||||
--> $DIR/future_not_send.rs:8:20
|
||||
|
|
||||
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
|
||||
| ---- has type `&std::cell::Cell<usize>` which is not `Send`
|
||||
LL | async { true }.await
|
||||
| ^^^^^^ await occurs here, with `cell` maybe used later
|
||||
| ^^^^^ await occurs here, with `cell` maybe used later
|
||||
LL | }
|
||||
| - `cell` is later dropped here
|
||||
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
|
||||
|
|
@ -33,12 +33,12 @@ LL | pub async fn public_future(rc: Rc<[u8]>) {
|
|||
| ^ future returned by `public_future` is not `Send`
|
||||
|
|
||||
note: future is not `Send` as this value is used across an await
|
||||
--> $DIR/future_not_send.rs:12:19
|
||||
--> $DIR/future_not_send.rs:12:20
|
||||
|
|
||||
LL | pub async fn public_future(rc: Rc<[u8]>) {
|
||||
| -- has type `std::rc::Rc<[u8]>` which is not `Send`
|
||||
LL | async { true }.await;
|
||||
| ^^^^^^ await occurs here, with `rc` maybe used later
|
||||
| ^^^^^ await occurs here, with `rc` maybe used later
|
||||
LL | }
|
||||
| - `rc` is later dropped here
|
||||
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
|
||||
|
|
@ -82,12 +82,12 @@ LL | async fn private_future(&self) -> usize {
|
|||
| ^^^^^ future returned by `private_future` is not `Send`
|
||||
|
|
||||
note: future is not `Send` as this value is used across an await
|
||||
--> $DIR/future_not_send.rs:35:23
|
||||
--> $DIR/future_not_send.rs:35:24
|
||||
|
|
||||
LL | async fn private_future(&self) -> usize {
|
||||
| ----- has type `&Dummy` which is not `Send`
|
||||
LL | async { true }.await;
|
||||
| ^^^^^^ await occurs here, with `&self` maybe used later
|
||||
| ^^^^^ await occurs here, with `&self` maybe used later
|
||||
LL | self.rc.len()
|
||||
LL | }
|
||||
| - `&self` is later dropped here
|
||||
|
|
@ -100,12 +100,12 @@ LL | pub async fn public_future(&self) {
|
|||
| ^ future returned by `public_future` is not `Send`
|
||||
|
|
||||
note: future is not `Send` as this value is used across an await
|
||||
--> $DIR/future_not_send.rs:40:30
|
||||
--> $DIR/future_not_send.rs:40:31
|
||||
|
|
||||
LL | pub async fn public_future(&self) {
|
||||
| ----- has type `&Dummy` which is not `Send`
|
||||
LL | self.private_future().await;
|
||||
| ^^^^^^ await occurs here, with `&self` maybe used later
|
||||
| ^^^^^ await occurs here, with `&self` maybe used later
|
||||
LL | }
|
||||
| - `&self` is later dropped here
|
||||
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
|
||||
|
|
@ -117,12 +117,12 @@ LL | async fn generic_future<T>(t: T) -> T
|
|||
| ^ future returned by `generic_future` is not `Send`
|
||||
|
|
||||
note: future is not `Send` as this value is used across an await
|
||||
--> $DIR/future_not_send.rs:54:19
|
||||
--> $DIR/future_not_send.rs:54:20
|
||||
|
|
||||
LL | let rt = &t;
|
||||
| -- has type `&T` which is not `Send`
|
||||
LL | async { true }.await;
|
||||
| ^^^^^^ await occurs here, with `rt` maybe used later
|
||||
| ^^^^^ await occurs here, with `rt` maybe used later
|
||||
LL | t
|
||||
LL | }
|
||||
| - `rt` is later dropped here
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@ fn main() {
|
|||
// Also not assigning directly as that's array initialization, not assignment.
|
||||
let zst_val = [1u8; 0];
|
||||
unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) };
|
||||
//~^ERROR: memory access failed: null pointer is a dangling pointer
|
||||
//~^ERROR: dereferencing pointer failed: null pointer is a dangling pointer
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
|
||||
error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
|
||||
--> $DIR/null_pointer_write_zst.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ impl ChainItemKind {
|
|||
let span = mk_sp(nested.span.hi(), field.span.hi());
|
||||
(kind, span)
|
||||
}
|
||||
ast::ExprKind::Await(ref nested) => {
|
||||
ast::ExprKind::Await(ref nested, _) => {
|
||||
let span = mk_sp(nested.span.hi(), expr.span.hi());
|
||||
(ChainItemKind::Await, span)
|
||||
}
|
||||
|
|
@ -459,7 +459,7 @@ impl Chain {
|
|||
ast::ExprKind::MethodCall(ref call) => Some(Self::convert_try(&call.receiver, context)),
|
||||
ast::ExprKind::Field(ref subexpr, _)
|
||||
| ast::ExprKind::Try(ref subexpr)
|
||||
| ast::ExprKind::Await(ref subexpr) => Some(Self::convert_try(subexpr, context)),
|
||||
| ast::ExprKind::Await(ref subexpr, _) => Some(Self::convert_try(subexpr, context)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ pub(crate) fn format_expr(
|
|||
ast::ExprKind::Try(..)
|
||||
| ast::ExprKind::Field(..)
|
||||
| ast::ExprKind::MethodCall(..)
|
||||
| ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
|
||||
| ast::ExprKind::Await(_, _) => rewrite_chain(expr, context, shape),
|
||||
ast::ExprKind::MacCall(ref mac) => {
|
||||
rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
|
||||
wrap_str(
|
||||
|
|
@ -1889,7 +1889,7 @@ impl<'ast> RhsAssignKind<'ast> {
|
|||
ast::ExprKind::Try(..)
|
||||
| ast::ExprKind::Field(..)
|
||||
| ast::ExprKind::MethodCall(..)
|
||||
| ast::ExprKind::Await(_)
|
||||
| ast::ExprKind::Await(_, _)
|
||||
)
|
||||
}
|
||||
_ => false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue