Skip to content

Rollup of 5 pull requests #127788

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 63 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
#![allow(rustc::untranslatable_diagnostic)]

use either::Either;
use hir::ClosureKind;
use hir::{ClosureKind, Path};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
@@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
use rustc_middle::bug;
use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::VarDebugInfoContents;
use rustc_middle::mir::{
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
@@ -546,7 +547,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
self.suggest_cloning(err, ty, expr, None, Some(move_spans));
}
}
if let Some(pat) = finder.pat {

self.suggest_ref_for_dbg_args(expr, place, move_span, err);

// it's useless to suggest inserting `ref` when the span don't comes from local code
if let Some(pat) = finder.pat
&& !move_span.is_dummy()
&& !self.infcx.tcx.sess.source_map().is_imported(move_span)
{
*in_pattern = true;
let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
if let Some(pat) = finder.parent_pat {
@@ -561,6 +569,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
}
}

// for dbg!(x) which may take ownership, suggest dbg!(&x) instead
// but here we actually do not check whether the macro name is `dbg!`
// so that we may extend the scope a bit larger to cover more cases
fn suggest_ref_for_dbg_args(
&self,
body: &hir::Expr<'_>,
place: &Place<'tcx>,
move_span: Span,
err: &mut Diag<'infcx>,
) {
let var_info = self.body.var_debug_info.iter().find(|info| match info.value {
VarDebugInfoContents::Place(ref p) => p == place,
_ => false,
});
let arg_name = if let Some(var_info) = var_info {
var_info.name
} else {
return;
};
struct MatchArgFinder {
expr_span: Span,
match_arg_span: Option<Span>,
arg_name: Symbol,
}
impl Visitor<'_> for MatchArgFinder {
fn visit_expr(&mut self, e: &hir::Expr<'_>) {
// dbg! is expanded into a match pattern, we need to find the right argument span
if let hir::ExprKind::Match(expr, ..) = &e.kind
&& let hir::ExprKind::Path(hir::QPath::Resolved(
_,
path @ Path { segments: [seg], .. },
)) = &expr.kind
&& seg.ident.name == self.arg_name
&& self.expr_span.source_callsite().contains(expr.span)
{
self.match_arg_span = Some(path.span);
}
hir::intravisit::walk_expr(self, e);
}
}

let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
finder.visit_expr(body);
if let Some(macro_arg_span) = finder.match_arg_span {
err.span_suggestion_verbose(
macro_arg_span.shrink_to_lo(),
"consider borrowing instead of transferring ownership",
"&",
Applicability::MachineApplicable,
);
}
}

fn report_use_of_uninitialized(
&self,
mpi: MovePathIndex,
Original file line number Diff line number Diff line change
@@ -3810,6 +3810,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
{
if let Some(where_pred) = where_pred.as_trait_clause()
&& let Some(failed_pred) = failed_pred.as_trait_clause()
&& where_pred.def_id() == failed_pred.def_id()
{
self.enter_forall(where_pred, |where_pred| {
let failed_pred = self.instantiate_binder_with_fresh_vars(
6 changes: 3 additions & 3 deletions library/core/src/num/f128.rs
Original file line number Diff line number Diff line change
@@ -170,15 +170,15 @@ impl f128 {
/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon
/// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
#[unstable(feature = "f128", issue = "116909")]
pub const EPSILON: f128 = 1.92592994438723585305597794258492731e-34_f128;
pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128;

/// Smallest finite `f128` value.
///
/// Equal to &minus;[`MAX`].
///
/// [`MAX`]: f128::MAX
#[unstable(feature = "f128", issue = "116909")]
pub const MIN: f128 = -1.18973149535723176508575932662800701e+4932_f128;
pub const MIN: f128 = -1.18973149535723176508575932662800702e+4932_f128;
/// Smallest positive normal `f128` value.
///
/// Equal to 2<sup>[`MIN_EXP`]&nbsp;&minus;&nbsp;1</sup>.
@@ -194,7 +194,7 @@ impl f128 {
/// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS
/// [`MAX_EXP`]: f128::MAX_EXP
#[unstable(feature = "f128", issue = "116909")]
pub const MAX: f128 = 1.18973149535723176508575932662800701e+4932_f128;
pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128;

/// One greater than the minimum possible normal power of 2 exponent.
///
26 changes: 9 additions & 17 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ use std::fs;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::process::Stdio;
use std::str;

use serde_derive::Deserialize;
@@ -695,10 +695,10 @@ fn copy_sanitizers(
|| target == "x86_64-apple-ios"
{
// Update the library’s install name to reflect that it has been renamed.
apple_darwin_update_library_name(&dst, &format!("@rpath/{}", &runtime.name));
apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", &runtime.name));
// Upon renaming the install name, the code signature of the file will invalidate,
// so we will sign it again.
apple_darwin_sign_file(&dst);
apple_darwin_sign_file(builder, &dst);
}

target_deps.push(dst);
@@ -707,25 +707,17 @@ fn copy_sanitizers(
target_deps
}

fn apple_darwin_update_library_name(library_path: &Path, new_name: &str) {
let status = Command::new("install_name_tool")
.arg("-id")
.arg(new_name)
.arg(library_path)
.status()
.expect("failed to execute `install_name_tool`");
assert!(status.success());
fn apple_darwin_update_library_name(builder: &Builder<'_>, library_path: &Path, new_name: &str) {
command("install_name_tool").arg("-id").arg(new_name).arg(library_path).run(builder);
}

fn apple_darwin_sign_file(file_path: &Path) {
let status = Command::new("codesign")
fn apple_darwin_sign_file(builder: &Builder<'_>, file_path: &Path) {
command("codesign")
.arg("-f") // Force to rewrite the existing signature
.arg("-s")
.arg("-")
.arg(file_path)
.status()
.expect("failed to execute `codesign`");
assert!(status.success());
.run(builder);
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -1171,7 +1163,7 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
if builder.config.llvm_profile_generate && target.is_msvc() {
if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl {
// Add clang's runtime library directory to the search path
let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display()));
}
}
3 changes: 2 additions & 1 deletion src/bootstrap/src/core/build_steps/llvm.rs
Original file line number Diff line number Diff line change
@@ -125,6 +125,7 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L
static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
generate_smart_stamp_hash(
builder,
&builder.config.src.join("src/llvm-project"),
builder.in_tree_llvm_info.sha().unwrap_or_default(),
)
@@ -912,7 +913,7 @@ impl Step for Lld {
if let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref() {
// Find clang's runtime library directory and push that as a search path to the
// cmake linker flags.
let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path);
let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path);
ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display()));
}
}
60 changes: 28 additions & 32 deletions src/bootstrap/src/core/build_steps/setup.rs
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::t;
use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY;
use crate::utils::exec::command;
use crate::utils::helpers::{self, hex_encode};
use crate::Config;
use sha2::Digest;
@@ -16,7 +17,6 @@ use std::fmt::Write as _;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf, MAIN_SEPARATOR_STR};
use std::process::Command;
use std::str::FromStr;
use std::{fmt, fs, io};

@@ -266,20 +266,16 @@ impl Step for Link {
}
let stage_path =
["build", config.build.rustc_target_arg(), "stage1"].join(MAIN_SEPARATOR_STR);
if !rustup_installed() {
if !rustup_installed(builder) {
eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
} else if stage_dir_exists(&stage_path[..]) && !config.dry_run() {
attempt_toolchain_link(&stage_path[..]);
attempt_toolchain_link(builder, &stage_path[..]);
}
}
}

fn rustup_installed() -> bool {
Command::new("rustup")
.arg("--version")
.stdout(std::process::Stdio::null())
.output()
.map_or(false, |output| output.status.success())
fn rustup_installed(builder: &Builder<'_>) -> bool {
command("rustup").capture_stdout().arg("--version").run(builder).is_success()
}

fn stage_dir_exists(stage_path: &str) -> bool {
@@ -289,8 +285,8 @@ fn stage_dir_exists(stage_path: &str) -> bool {
}
}

fn attempt_toolchain_link(stage_path: &str) {
if toolchain_is_linked() {
fn attempt_toolchain_link(builder: &Builder<'_>, stage_path: &str) {
if toolchain_is_linked(builder) {
return;
}

@@ -301,7 +297,7 @@ fn attempt_toolchain_link(stage_path: &str) {
return;
}

if try_link_toolchain(stage_path) {
if try_link_toolchain(builder, stage_path) {
println!(
"Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
);
@@ -315,22 +311,24 @@ fn attempt_toolchain_link(stage_path: &str) {
}
}

fn toolchain_is_linked() -> bool {
match Command::new("rustup")
fn toolchain_is_linked(builder: &Builder<'_>) -> bool {
match command("rustup")
.capture_stdout()
.allow_failure()
.args(["toolchain", "list"])
.stdout(std::process::Stdio::piped())
.output()
.run(builder)
.stdout_if_ok()
{
Ok(toolchain_list) => {
if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") {
Some(toolchain_list) => {
if !toolchain_list.contains("stage1") {
return false;
}
// The toolchain has already been linked.
println!(
"`stage1` toolchain already linked; not attempting to link `stage1` toolchain"
);
}
Err(_) => {
None => {
// In this case, we don't know if the `stage1` toolchain has been linked;
// but `rustup` failed, so let's not go any further.
println!(
@@ -341,12 +339,12 @@ fn toolchain_is_linked() -> bool {
true
}

fn try_link_toolchain(stage_path: &str) -> bool {
Command::new("rustup")
.stdout(std::process::Stdio::null())
fn try_link_toolchain(builder: &Builder<'_>, stage_path: &str) -> bool {
command("rustup")
.capture_stdout()
.args(["toolchain", "link", "stage1", stage_path])
.output()
.map_or(false, |output| output.status.success())
.run(builder)
.is_success()
}

fn ensure_stage1_toolchain_placeholder_exists(stage_path: &str) -> bool {
@@ -476,20 +474,18 @@ impl Step for Hook {
if config.dry_run() {
return;
}
t!(install_git_hook_maybe(config));
t!(install_git_hook_maybe(builder, config));
}
}

// install a git hook to automatically run tidy, if they want
fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result<()> {
let git = helpers::git(Some(&config.src))
.capture()
.args(["rev-parse", "--git-common-dir"])
.as_command_mut()
.output()
.map(|output| {
assert!(output.status.success(), "failed to run `git`");
PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
})?;
.run(builder)
.stdout();
let git = PathBuf::from(git.trim());
let hooks_dir = git.join("hooks");
let dst = hooks_dir.join("pre-push");
if dst.exists() {
18 changes: 6 additions & 12 deletions src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ use std::ffi::OsString;
use std::fs;
use std::iter;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

use clap_complete::shells;

@@ -169,12 +168,8 @@ You can skip linkcheck with --skip src/tools/linkchecker"
}
}

fn check_if_tidy_is_installed() -> bool {
Command::new("tidy")
.arg("--version")
.stdout(Stdio::null())
.status()
.map_or(false, |status| status.success())
fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool {
command("tidy").capture_stdout().allow_failure().arg("--version").run(builder).is_success()
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -188,16 +183,17 @@ impl Step for HtmlCheck {
const ONLY_HOSTS: bool = true;

fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
let run = run.path("src/tools/html-checker");
run.lazy_default_condition(Box::new(check_if_tidy_is_installed))
run.lazy_default_condition(Box::new(|| check_if_tidy_is_installed(builder)))
}

fn make_run(run: RunConfig<'_>) {
run.builder.ensure(HtmlCheck { target: run.target });
}

fn run(self, builder: &Builder<'_>) {
if !check_if_tidy_is_installed() {
if !check_if_tidy_is_installed(builder) {
eprintln!("not running HTML-check tool because `tidy` is missing");
eprintln!(
"You need the HTML tidy tool https://www.html-tidy.org/, this tool is *not* part of the rust project and needs to be installed separately, for example via your package manager."
@@ -2099,9 +2095,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
let git_config = builder.config.git_config();
cmd.arg("--git-repository").arg(git_config.git_repository);
cmd.arg("--nightly-branch").arg(git_config.nightly_branch);

// FIXME: Move CiEnv back to bootstrap, it is only used here anyway
builder.ci_env.force_coloring_in_ci(cmd.as_command_mut());
cmd.force_coloring_in_ci(builder.ci_env);

#[cfg(feature = "build-metrics")]
builder.metrics.begin_test_suite(
100 changes: 33 additions & 67 deletions src/bootstrap/src/core/build_steps/toolstate.rs
Original file line number Diff line number Diff line change
@@ -99,24 +99,16 @@ fn print_error(tool: &str, submodule: &str) {
crate::exit!(3);
}

fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
fn check_changed_files(builder: &Builder<'_>, toolstates: &HashMap<Box<str>, ToolState>) {
// Changed files
let output = helpers::git(None)
.capture()
.arg("diff")
.arg("--name-status")
.arg("HEAD")
.arg("HEAD^")
.as_command_mut()
.output();
let output = match output {
Ok(o) => o,
Err(e) => {
eprintln!("Failed to get changed files: {e:?}");
crate::exit!(1);
}
};

let output = t!(String::from_utf8(output.stdout));
.run(builder)
.stdout();

for (tool, submodule) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) {
let changed = output.lines().any(|l| l.starts_with('M') && l.ends_with(submodule));
@@ -186,8 +178,8 @@ impl Step for ToolStateCheck {
crate::exit!(1);
}

check_changed_files(&toolstates);
checkout_toolstate_repo();
check_changed_files(builder, &toolstates);
checkout_toolstate_repo(builder);
let old_toolstate = read_old_toolstate();

for (tool, _) in STABLE_TOOLS.iter() {
@@ -231,7 +223,7 @@ impl Step for ToolStateCheck {
}

if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() {
commit_toolstate_change(&toolstates);
commit_toolstate_change(builder, &toolstates);
}
}

@@ -315,55 +307,34 @@ fn toolstate_repo() -> String {
const TOOLSTATE_DIR: &str = "rust-toolstate";

/// Checks out the toolstate repo into `TOOLSTATE_DIR`.
fn checkout_toolstate_repo() {
fn checkout_toolstate_repo(builder: &Builder<'_>) {
if let Ok(token) = env::var("TOOLSTATE_REPO_ACCESS_TOKEN") {
prepare_toolstate_config(&token);
prepare_toolstate_config(builder, &token);
}
if Path::new(TOOLSTATE_DIR).exists() {
eprintln!("Cleaning old toolstate directory...");
t!(fs::remove_dir_all(TOOLSTATE_DIR));
}

let status = helpers::git(None)
helpers::git(None)
.arg("clone")
.arg("--depth=1")
.arg(toolstate_repo())
.arg(TOOLSTATE_DIR)
.as_command_mut()
.status();
let success = match status {
Ok(s) => s.success(),
Err(_) => false,
};
if !success {
panic!("git clone unsuccessful (status: {status:?})");
}
.run(builder);
}

/// Sets up config and authentication for modifying the toolstate repo.
fn prepare_toolstate_config(token: &str) {
fn git_config(key: &str, value: &str) {
let status = helpers::git(None)
.arg("config")
.arg("--global")
.arg(key)
.arg(value)
.as_command_mut()
.status();
let success = match status {
Ok(s) => s.success(),
Err(_) => false,
};
if !success {
panic!("git config key={key} value={value} failed (status: {status:?})");
}
fn prepare_toolstate_config(builder: &Builder<'_>, token: &str) {
fn git_config(builder: &Builder<'_>, key: &str, value: &str) {
helpers::git(None).arg("config").arg("--global").arg(key).arg(value).run(builder);
}

// If changing anything here, then please check that `src/ci/publish_toolstate.sh` is up to date
// as well.
git_config("user.email", "7378925+rust-toolstate-update@users.noreply.github.com");
git_config("user.name", "Rust Toolstate Update");
git_config("credential.helper", "store");
git_config(builder, "user.email", "7378925+rust-toolstate-update@users.noreply.github.com");
git_config(builder, "user.name", "Rust Toolstate Update");
git_config(builder, "credential.helper", "store");

let credential = format!("https://{token}:x-oauth-basic@github.com\n",);
let git_credential_path = PathBuf::from(t!(env::var("HOME"))).join(".git-credentials");
@@ -403,55 +374,51 @@ fn read_old_toolstate() -> Vec<RepoState> {
///
/// * See <https://help.github.com/articles/about-commit-email-addresses/>
/// if a private email by GitHub is wanted.
fn commit_toolstate_change(current_toolstate: &ToolstateData) {
fn commit_toolstate_change(builder: &Builder<'_>, current_toolstate: &ToolstateData) {
let message = format!("({} CI update)", OS.expect("linux/windows only"));
let mut success = false;
for _ in 1..=5 {
// Upload the test results (the new commit-to-toolstate mapping) to the toolstate repo.
// This does *not* change the "current toolstate"; that only happens post-landing
// via `src/ci/docker/publish_toolstate.sh`.
publish_test_results(current_toolstate);
publish_test_results(builder, current_toolstate);

// `git commit` failing means nothing to commit.
let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR)))
let status = helpers::git(Some(Path::new(TOOLSTATE_DIR)))
.allow_failure()
.arg("commit")
.arg("-a")
.arg("-m")
.arg(&message)
.as_command_mut()
.status());
if !status.success() {
.run(builder);
if !status.is_success() {
success = true;
break;
}

let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR)))
let status = helpers::git(Some(Path::new(TOOLSTATE_DIR)))
.allow_failure()
.arg("push")
.arg("origin")
.arg("master")
.as_command_mut()
.status());
.run(builder);
// If we successfully push, exit.
if status.success() {
if status.is_success() {
success = true;
break;
}
eprintln!("Sleeping for 3 seconds before retrying push");
std::thread::sleep(std::time::Duration::from_secs(3));
let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR)))
helpers::git(Some(Path::new(TOOLSTATE_DIR)))
.arg("fetch")
.arg("origin")
.arg("master")
.as_command_mut()
.status());
assert!(status.success());
let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR)))
.run(builder);
helpers::git(Some(Path::new(TOOLSTATE_DIR)))
.arg("reset")
.arg("--hard")
.arg("origin/master")
.as_command_mut()
.status());
assert!(status.success());
.run(builder);
}

if !success {
@@ -464,9 +431,8 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) {
/// These results will later be promoted to `latest.json` by the
/// `publish_toolstate.py` script if the PR passes all tests and is merged to
/// master.
fn publish_test_results(current_toolstate: &ToolstateData) {
let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").as_command_mut().output());
let commit = t!(String::from_utf8(commit.stdout));
fn publish_test_results(builder: &Builder<'_>, current_toolstate: &ToolstateData) {
let commit = helpers::git(None).capture().arg("rev-parse").arg("HEAD").run(builder).stdout();

let toolstate_serialized = t!(serde_json::to_string(&current_toolstate));

2 changes: 1 addition & 1 deletion src/bootstrap/src/core/builder.rs
Original file line number Diff line number Diff line change
@@ -2108,7 +2108,7 @@ impl<'a> Builder<'a> {
// Try to use a sysroot-relative bindir, in case it was configured absolutely.
cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative());

self.ci_env.force_coloring_in_ci(cargo.as_command_mut());
cargo.force_coloring_in_ci(self.ci_env);

// When we build Rust dylibs they're all intended for intermediate
// usage, so make sure we pass the -Cprefer-dynamic flag instead of
78 changes: 45 additions & 33 deletions src/bootstrap/src/lib.rs
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ use std::fmt::Display;
use std::fs::{self, File};
use std::io;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::process::Command;
use std::str;
use std::sync::OnceLock;
use std::time::SystemTime;
@@ -36,7 +36,7 @@ use utils::channel::GitInfo;
use utils::helpers::hex_encode;

use crate::core::builder;
use crate::core::builder::Kind;
use crate::core::builder::{Builder, Kind};
use crate::core::config::{flags, LldMode};
use crate::core::config::{DryRun, Target};
use crate::core::config::{LlvmLibunwind, TargetSelection};
@@ -489,18 +489,29 @@ impl Build {
return;
}

let submodule_git = || helpers::git(Some(&absolute_path));
// Submodule updating actually happens during in the dry run mode. We need to make sure that
// all the git commands below are actually executed, because some follow-up code
// in bootstrap might depend on the submodules being checked out. Furthermore, not all
// the command executions below work with an empty output (produced during dry run).
// Therefore, all commands below are marked with `run_always()`, so that they also run in
// dry run mode.
let submodule_git = || {
let mut cmd = helpers::git(Some(&absolute_path)).capture_stdout();
cmd.run_always();
cmd
};

// Determine commit checked out in submodule.
let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]).as_command_mut());
let checked_out_hash = submodule_git().args(["rev-parse", "HEAD"]).run(self).stdout();
let checked_out_hash = checked_out_hash.trim_end();
// Determine commit that the submodule *should* have.
let recorded = output(
helpers::git(Some(&self.src))
.args(["ls-tree", "HEAD"])
.arg(relative_path)
.as_command_mut(),
);
let recorded = helpers::git(Some(&self.src))
.capture_stdout()
.run_always()
.args(["ls-tree", "HEAD"])
.arg(relative_path)
.run(self)
.stdout();
let actual_hash = recorded
.split_whitespace()
.nth(2)
@@ -513,6 +524,7 @@ impl Build {

println!("Updating submodule {}", relative_path.display());
helpers::git(Some(&self.src))
.run_always()
.args(["submodule", "-q", "sync"])
.arg(relative_path)
.run(self);
@@ -521,21 +533,16 @@ impl Build {
let update = |progress: bool| {
// Git is buggy and will try to fetch submodules from the tracking branch for *this* repository,
// even though that has no relation to the upstream for the submodule.
let current_branch = {
let output = helpers::git(Some(&self.src))
.args(["symbolic-ref", "--short", "HEAD"])
.as_command_mut()
.stderr(Stdio::inherit())
.output();
let output = t!(output);
if output.status.success() {
Some(String::from_utf8(output.stdout).unwrap().trim().to_owned())
} else {
None
}
};
let current_branch = helpers::git(Some(&self.src))
.capture_stdout()
.run_always()
.args(["symbolic-ref", "--short", "HEAD"])
.run(self)
.stdout_if_ok()
.map(|s| s.trim().to_owned());

let mut git = helpers::git(Some(&self.src));
let mut git = helpers::git(Some(&self.src)).allow_failure();
git.run_always();
if let Some(branch) = current_branch {
// If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name.
// This syntax isn't accepted by `branch.{branch}`. Strip it.
@@ -549,8 +556,7 @@ impl Build {
git.arg(relative_path);
git
};
// NOTE: doesn't use `try_run` because this shouldn't print an error if it fails.
if !update(true).as_command_mut().status().map_or(false, |status| status.success()) {
if !update(true).run(self).is_success() {
update(false).run(self);
}

@@ -1946,22 +1952,28 @@ fn envify(s: &str) -> String {
///
/// In case of errors during `git` command execution (e.g., in tarball sources), default values
/// are used to prevent panics.
pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String {
pub fn generate_smart_stamp_hash(
builder: &Builder<'_>,
dir: &Path,
additional_input: &str,
) -> String {
let diff = helpers::git(Some(dir))
.capture_stdout()
.allow_failure()
.arg("diff")
.as_command_mut()
.output()
.map(|o| String::from_utf8(o.stdout).unwrap_or_default())
.run(builder)
.stdout_if_ok()
.unwrap_or_default();

let status = helpers::git(Some(dir))
.capture_stdout()
.allow_failure()
.arg("status")
.arg("--porcelain")
.arg("-z")
.arg("--untracked-files=normal")
.as_command_mut()
.output()
.map(|o| String::from_utf8(o.stdout).unwrap_or_default())
.run(builder)
.stdout_if_ok()
.unwrap_or_default();

let mut hasher = sha2::Sha256::new();
13 changes: 13 additions & 0 deletions src/bootstrap/src/utils/exec.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::Build;
use build_helper::ci::CiEnv;
use build_helper::drop_bomb::DropBomb;
use std::ffi::OsStr;
use std::fmt::{Debug, Formatter};
@@ -171,6 +172,18 @@ impl BootstrapCommand {
pub fn get_created_location(&self) -> std::panic::Location<'static> {
self.drop_bomb.get_created_location()
}

/// If in a CI environment, forces the command to run with colors.
pub fn force_coloring_in_ci(&mut self, ci_env: CiEnv) {
if ci_env != CiEnv::None {
// Due to use of stamp/docker, the output stream of bootstrap is not
// a TTY in CI, so coloring is by-default turned off.
// The explicit `TERM=xterm` environment is needed for
// `--color always` to actually work. This env var was lost when
// compiling through the Makefile. Very strange.
self.env("TERM", "xterm").args(["--color", "always"]);
}
}
}

impl Debug for BootstrapCommand {
6 changes: 3 additions & 3 deletions src/bootstrap/src/utils/helpers.rs
Original file line number Diff line number Diff line change
@@ -338,13 +338,13 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {
/// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource
/// directory to the linker flags, otherwise there will be linker errors about the profiler runtime
/// missing. This function returns the path to that directory.
pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf {
pub fn get_clang_cl_resource_dir(builder: &Builder<'_>, clang_cl_path: &str) -> PathBuf {
// Similar to how LLVM does it, to find clang's library runtime directory:
// - we ask `clang-cl` to locate the `clang_rt.builtins` lib.
let mut builtins_locator = Command::new(clang_cl_path);
let mut builtins_locator = command(clang_cl_path);
builtins_locator.args(["/clang:-print-libgcc-file-name", "/clang:--rtlib=compiler-rt"]);

let clang_rt_builtins = output(&mut builtins_locator);
let clang_rt_builtins = builtins_locator.capture_stdout().run(builder).stdout();
let clang_rt_builtins = Path::new(clang_rt_builtins.trim());
assert!(
clang_rt_builtins.exists(),
14 changes: 7 additions & 7 deletions src/bootstrap/src/utils/tarball.rs
Original file line number Diff line number Diff line change
@@ -369,13 +369,13 @@ impl<'a> Tarball<'a> {
// gets the same timestamp.
if self.builder.rust_info().is_managed_git_subrepository() {
// %ct means committer date
let timestamp = helpers::output(
helpers::git(Some(&self.builder.src))
.arg("log")
.arg("-1")
.arg("--format=%ct")
.as_command_mut(),
);
let timestamp = helpers::git(Some(&self.builder.src))
.capture_stdout()
.arg("log")
.arg("-1")
.arg("--format=%ct")
.run(self.builder)
.stdout();
cmd.args(["--override-file-mtime", timestamp.trim()]);
}

2 changes: 1 addition & 1 deletion src/doc/book
Submodule book updated 47 files
+4 −4 .github/workflows/main.yml
+3 −0 book.toml
+1 −0 ci/dictionary.txt
+1 −1 listings/ch02-guessing-game-tutorial/listing-02-04/output.txt
+2 −2 listings/ch06-enums-and-pattern-matching/no-listing-07-cant-use-option-directly/output.txt
+2 −2 listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt
+1 −19 listings/ch10-generic-types-traits-and-lifetimes/listing-10-20/output.txt
+1 −3 listings/ch11-writing-automated-tests/listing-11-03/src/lib.rs
+0 −2 listings/ch11-writing-automated-tests/listing-11-05/src/lib.rs
+3 −2 listings/ch11-writing-automated-tests/listing-11-07/src/lib.rs
+2 −2 listings/ch11-writing-automated-tests/listing-11-10/output.txt
+2 −2 listings/ch11-writing-automated-tests/listing-11-10/src/lib.rs
+7 −4 listings/ch11-writing-automated-tests/listing-11-11/src/lib.rs
+5 −4 listings/ch11-writing-automated-tests/listing-11-12/src/lib.rs
+5 −4 listings/ch11-writing-automated-tests/listing-11-13/src/lib.rs
+2 −1 listings/ch11-writing-automated-tests/listing-11-13/tests/integration_test.rs
+1 −0 listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/output.txt
+3 −2 listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/src/lib.rs
+1 −2 listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/src/lib.rs
+11 −1 listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs
+2 −2 listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/output.txt
+19 −7 listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test/src/lib.rs
+5 −4 listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/src/lib.rs
+3 −2 listings/ch11-writing-automated-tests/no-listing-12-shared-test-code-problem/tests/integration_test.rs
+5 −4 listings/ch11-writing-automated-tests/no-listing-13-fix-shared-test-code-problem/src/lib.rs
+4 −2 listings/ch11-writing-automated-tests/no-listing-13-fix-shared-test-code-problem/tests/integration_test.rs
+5 −4 listings/ch11-writing-automated-tests/output-only-05-single-integration/src/lib.rs
+3 −2 listings/ch11-writing-automated-tests/output-only-05-single-integration/tests/integration_test.rs
+2 −0 listings/ch13-functional-features/listing-13-04/output.txt
+2 −0 listings/ch13-functional-features/listing-13-05/output.txt
+5 −0 listings/ch13-functional-features/listing-13-08/output.txt
+7 −3 listings/ch15-smart-pointers/listing-15-21/output.txt
+0 −4 listings/ch16-fearless-concurrency/listing-16-09/output.txt
+10 −0 listings/ch16-fearless-concurrency/listing-16-13/output.txt
+1 −1 listings/ch16-fearless-concurrency/listing-16-14/output.txt
+2 −0 listings/ch19-advanced-features/listing-19-05/output.txt
+6 −0 listings/ch20-web-server/listing-20-17/output.txt
+1 −1 listings/ch20-web-server/listing-20-22/output.txt
+1 −1 listings/ch20-web-server/no-listing-04-update-worker-definition/output.txt
+531 −358 nostarch/chapter11.md
+5 −1 packages/tools/src/bin/link2print.rs
+1 −1 rust-toolchain
+6 −5 src/ch11-00-testing.md
+52 −43 src/ch11-01-writing-tests.md
+14 −14 src/ch11-02-running-tests.md
+26 −31 src/ch11-03-test-organization.md
+1 −1 src/title-page.md
2 changes: 1 addition & 1 deletion src/doc/edition-guide
2 changes: 1 addition & 1 deletion src/doc/embedded-book
2 changes: 1 addition & 1 deletion src/doc/rust-by-example
14 changes: 0 additions & 14 deletions src/tools/build_helper/src/ci.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::process::Command;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum CiEnv {
/// Not a CI environment.
@@ -21,18 +19,6 @@ impl CiEnv {
pub fn is_ci() -> bool {
Self::current() != CiEnv::None
}

/// If in a CI environment, forces the command to run with colors.
pub fn force_coloring_in_ci(self, cmd: &mut Command) {
if self != CiEnv::None {
// Due to use of stamp/docker, the output stream of bootstrap is not
// a TTY in CI, so coloring is by-default turned off.
// The explicit `TERM=xterm` environment is needed for
// `--color always` to actually work. This env var was lost when
// compiling through the Makefile. Very strange.
cmd.env("TERM", "xterm").args(&["--color", "always"]);
}
}
}

pub mod gha {
20 changes: 0 additions & 20 deletions tests/crashes/126416.rs

This file was deleted.

68 changes: 68 additions & 0 deletions tests/ui/borrowck/dbg-issue-120327.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
fn s() -> String {
let a = String::new();
dbg!(a);
return a; //~ ERROR use of moved value:
}

fn m() -> String {
let a = String::new();
dbg!(1, 2, a, 1, 2);
return a; //~ ERROR use of moved value:
}

fn t(a: String) -> String {
let b: String = "".to_string();
dbg!(a, b);
return b; //~ ERROR use of moved value:
}

fn x(a: String) -> String {
let b: String = "".to_string();
dbg!(a, b);
return a; //~ ERROR use of moved value:
}

macro_rules! my_dbg {
() => {
eprintln!("[{}:{}:{}]", file!(), line!(), column!())
};
($val:expr $(,)?) => {
match $val {
tmp => {
eprintln!("[{}:{}:{}] {} = {:#?}",
file!(), line!(), column!(), stringify!($val), &tmp);
tmp
}
}
};
($($val:expr),+ $(,)?) => {
($(my_dbg!($val)),+,)
};
}

fn test_my_dbg() -> String {
let b: String = "".to_string();
my_dbg!(b, 1);
return b; //~ ERROR use of moved value:
}

fn test_not_macro() -> String {
let a = String::new();
let _b = match a {
tmp => {
eprintln!("dbg: {}", tmp);
tmp
}
};
return a; //~ ERROR use of moved value:
}

fn get_expr(_s: String) {}

fn test() {
let a: String = "".to_string();
let _res = get_expr(dbg!(a));
let _l = a.len(); //~ ERROR borrow of moved value
}

fn main() {}
117 changes: 117 additions & 0 deletions tests/ui/borrowck/dbg-issue-120327.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
error[E0382]: use of moved value: `a`
--> $DIR/dbg-issue-120327.rs:4:12
|
LL | let a = String::new();
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
LL | dbg!(a);
| ------- value moved here
LL | return a;
| ^ value used here after move
|
help: consider borrowing instead of transferring ownership
|
LL | dbg!(&a);
| +

error[E0382]: use of moved value: `a`
--> $DIR/dbg-issue-120327.rs:10:12
|
LL | let a = String::new();
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
LL | dbg!(1, 2, a, 1, 2);
| ------------------- value moved here
LL | return a;
| ^ value used here after move
|
help: consider borrowing instead of transferring ownership
|
LL | dbg!(1, 2, &a, 1, 2);
| +

error[E0382]: use of moved value: `b`
--> $DIR/dbg-issue-120327.rs:16:12
|
LL | let b: String = "".to_string();
| - move occurs because `b` has type `String`, which does not implement the `Copy` trait
LL | dbg!(a, b);
| ---------- value moved here
LL | return b;
| ^ value used here after move
|
help: consider borrowing instead of transferring ownership
|
LL | dbg!(a, &b);
| +

error[E0382]: use of moved value: `a`
--> $DIR/dbg-issue-120327.rs:22:12
|
LL | fn x(a: String) -> String {
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
LL | let b: String = "".to_string();
LL | dbg!(a, b);
| ---------- value moved here
LL | return a;
| ^ value used here after move
|
help: consider borrowing instead of transferring ownership
|
LL | dbg!(&a, b);
| +

error[E0382]: use of moved value: `b`
--> $DIR/dbg-issue-120327.rs:46:12
|
LL | tmp => {
| --- value moved here
...
LL | let b: String = "".to_string();
| - move occurs because `b` has type `String`, which does not implement the `Copy` trait
LL | my_dbg!(b, 1);
LL | return b;
| ^ value used here after move
|
help: consider borrowing instead of transferring ownership
|
LL | my_dbg!(&b, 1);
| +
help: borrow this binding in the pattern to avoid moving the value
|
LL | ref tmp => {
| +++

error[E0382]: use of moved value: `a`
--> $DIR/dbg-issue-120327.rs:57:12
|
LL | let a = String::new();
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
LL | let _b = match a {
LL | tmp => {
| --- value moved here
...
LL | return a;
| ^ value used here after move
|
help: borrow this binding in the pattern to avoid moving the value
|
LL | ref tmp => {
| +++

error[E0382]: borrow of moved value: `a`
--> $DIR/dbg-issue-120327.rs:65:14
|
LL | let a: String = "".to_string();
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
LL | let _res = get_expr(dbg!(a));
| ------- value moved here
LL | let _l = a.len();
| ^ value borrowed here after move
|
help: consider borrowing instead of transferring ownership
|
LL | let _res = get_expr(dbg!(&a));
| +

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0382`.
23 changes: 23 additions & 0 deletions tests/ui/methods/filter-relevant-fn-bounds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
trait Output<'a> {
type Type;
}

struct Wrapper;

impl Wrapper {
fn do_something_wrapper<O, F>(self, _: F)
//~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied
//~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied
where
F: for<'a> FnOnce(<F as Output<'a>>::Type),
//~^ ERROR the trait bound `F: Output<'_>` is not satisfied
//~| ERROR the trait bound `F: Output<'_>` is not satisfied
{
}
}

fn main() {
let mut wrapper = Wrapper;
wrapper.do_something_wrapper(|value| ());
//~^ ERROR expected a `FnOnce
}
74 changes: 74 additions & 0 deletions tests/ui/methods/filter-relevant-fn-bounds.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
--> $DIR/filter-relevant-fn-bounds.rs:8:5
|
LL | / fn do_something_wrapper<O, F>(self, _: F)
LL | |
LL | |
LL | | where
LL | | F: for<'a> FnOnce(<F as Output<'a>>::Type),
| |___________________________________________________^ the trait `for<'a> Output<'a>` is not implemented for `F`
|
help: consider further restricting this bound
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
| ++++++++++++++++++++

error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied
--> $DIR/filter-relevant-fn-bounds.rs:8:8
|
LL | fn do_something_wrapper<O, F>(self, _: F)
| ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F`
|
help: consider further restricting this bound
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>,
| ++++++++++++++++++++

error[E0277]: the trait bound `F: Output<'_>` is not satisfied
--> $DIR/filter-relevant-fn-bounds.rs:12:12
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
|
help: consider further restricting this bound
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
| ++++++++++++

error[E0277]: the trait bound `F: Output<'_>` is not satisfied
--> $DIR/filter-relevant-fn-bounds.rs:12:20
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F`
|
help: consider further restricting this bound
|
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>,
| ++++++++++++

error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
--> $DIR/filter-relevant-fn-bounds.rs:21:34
|
LL | wrapper.do_something_wrapper(|value| ());
| -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
| |
| required by a bound introduced by this call
|
= help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}`
help: this trait has no implementations, consider adding one
--> $DIR/filter-relevant-fn-bounds.rs:1:1
|
LL | trait Output<'a> {
| ^^^^^^^^^^^^^^^^
note: required by a bound in `Wrapper::do_something_wrapper`
--> $DIR/filter-relevant-fn-bounds.rs:12:12
|
LL | fn do_something_wrapper<O, F>(self, _: F)
| -------------------- required by a bound in this associated function
...
LL | F: for<'a> FnOnce(<F as Output<'a>>::Type),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper`

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
@@ -9,6 +9,10 @@ LL | let _ = dbg!(a);
| ^^^^^^^ value used here after move
|
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider borrowing instead of transferring ownership
|
LL | let _ = dbg!(&a);
| +

error: aborting due to 1 previous error