Auto merge of #145407 - Kobzol:rollup-g6yhx82, r=Kobzol

Rollup of 11 pull requests

Successful merges:

 - rust-lang/rust#137872 (Include whitespace in "remove |" suggestion and make it hidden)
 - rust-lang/rust#144631 (Fix test intrinsic-raw_eq-const-bad for big-endian)
 - rust-lang/rust#145233 (cfg_select: Support unbraced expressions)
 - rust-lang/rust#145261 (Improve tracing in bootstrap)
 - rust-lang/rust#145324 (Rename and document `ONLY_HOSTS` in bootstrap)
 - rust-lang/rust#145353 (bootstrap: Fix jemalloc 64K page support for aarch64 tools)
 - rust-lang/rust#145379 (bootstrap: Support passing `--timings` to cargo)
 - rust-lang/rust#145397 (Rust documentation, use `rustc-dev-guide` :3)
 - rust-lang/rust#145398 (Use `default_field_values` in `Resolver`)
 - rust-lang/rust#145401 (cleanup: Remove useless `[T].iter().last()`)
 - rust-lang/rust#145403 (Adjust error message grammar to be less awkward)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-08-14 23:30:10 +00:00
commit 3507a749b3
70 changed files with 976 additions and 813 deletions

View file

@ -1741,7 +1741,7 @@ fn deny_equality_constraints(
.map(|segment| segment.ident.name)
.zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name))
.all(|(a, b)| a == b)
&& let Some(potential_assoc) = full_path.segments.iter().last()
&& let Some(potential_assoc) = full_path.segments.last()
{
suggest(poly, potential_assoc, predicate);
}

View file

@ -518,7 +518,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
.with_span_help(
self.get_closure_bound_clause_span(*def_id),
"`Fn` and `FnMut` closures require captured values to be able to be \
consumed multiple times, but an `FnOnce` consume them only once",
consumed multiple times, but `FnOnce` closures may consume them only once",
)
}
_ => {

View file

@ -1113,7 +1113,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
.map(|snippet| {
debug_assert!(
!(sp.is_empty() && snippet.is_empty()),
"Span must not be empty and have no suggestion"
"Span `{sp:?}` must not be empty and have no suggestion"
);
Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }
})

View file

@ -146,7 +146,7 @@ impl<'ty> FieldInnerTy<'ty> {
};
let path = &ty_path.path;
let ty = path.segments.iter().last().unwrap();
let ty = path.segments.last().unwrap();
let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments else {
panic!("expected bracketed generic arguments");
};

View file

@ -862,8 +862,8 @@ parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up
parse_too_short_hex_escape = numeric character escape is too short
parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
.suggestion = remove the `{$token}`
parse_trailing_vert_not_allowed = a trailing `{$token}` is not allowed in an or-pattern
parse_trailing_vert_not_allowed_suggestion = remove the `{$token}`
parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
parse_trait_alias_cannot_be_const = trait aliases cannot be `const`

View file

@ -2661,7 +2661,7 @@ pub(crate) enum TopLevelOrPatternNotAllowedSugg {
parse_sugg_remove_leading_vert_in_pattern,
code = "",
applicability = "machine-applicable",
style = "verbose"
style = "tool-only"
)]
RemoveLeadingVert {
#[primary_span]
@ -2694,12 +2694,25 @@ pub(crate) struct UnexpectedVertVertInPattern {
pub start: Option<Span>,
}
#[derive(Subdiagnostic)]
#[suggestion(
parse_trailing_vert_not_allowed,
code = "",
applicability = "machine-applicable",
style = "tool-only"
)]
pub(crate) struct TrailingVertSuggestion {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_trailing_vert_not_allowed)]
pub(crate) struct TrailingVertNotAllowed {
#[primary_span]
#[suggestion(code = "", applicability = "machine-applicable", style = "verbose")]
pub span: Span,
#[subdiagnostic]
pub suggestion: TrailingVertSuggestion,
#[label(parse_label_while_parsing_or_pattern_here)]
pub start: Option<Span>,
pub token: Token,

View file

@ -1,11 +1,12 @@
use rustc_ast::token::Token;
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::util::classify;
use rustc_ast::{MetaItemInner, token};
use rustc_errors::PResult;
use rustc_span::Span;
use crate::exp;
use crate::parser::Parser;
use crate::parser::{AttrWrapper, ForceCollect, Parser, Restrictions, Trailing, UsePreAttrPos};
pub enum CfgSelectPredicate {
Cfg(MetaItemInner),
@ -23,19 +24,26 @@ pub struct CfgSelectBranches {
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
}
/// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where
/// the surrounding braces are stripped.
/// Parses a `TokenTree` consisting either of `{ /* ... */ }` (and strip the braces) or an
/// expression followed by a comma (and strip the comma).
fn parse_token_tree<'a>(p: &mut Parser<'a>) -> PResult<'a, TokenStream> {
// Generate an error if the `=>` is not followed by `{`.
if p.token != token::OpenBrace {
p.expect(exp!(OpenBrace))?;
if p.token == token::OpenBrace {
// Strip the outer '{' and '}'.
match p.parse_token_tree() {
TokenTree::Token(..) => unreachable!("because of the expect above"),
TokenTree::Delimited(.., tts) => return Ok(tts),
}
}
// Strip the outer '{' and '}'.
match p.parse_token_tree() {
TokenTree::Token(..) => unreachable!("because of the expect above"),
TokenTree::Delimited(.., tts) => Ok(tts),
let expr = p.collect_tokens(None, AttrWrapper::empty(), ForceCollect::Yes, |p, _| {
p.parse_expr_res(Restrictions::STMT_EXPR, AttrWrapper::empty())
.map(|(expr, _)| (expr, Trailing::No, UsePreAttrPos::No))
})?;
if !classify::expr_is_complete(&expr) && p.token != token::CloseBrace && p.token != token::Eof {
p.expect(exp!(Comma))?;
} else {
let _ = p.eat(exp!(Comma));
}
Ok(TokenStream::from_ast(&expr))
}
pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches> {

View file

@ -24,10 +24,10 @@ use crate::errors::{
GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
InclusiveRangeNoEnd, InvalidMutInPattern, ParenRangeSuggestion, PatternOnWrongSideOfAt,
RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, TopLevelOrPatternNotAllowed,
TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, UnexpectedExpressionInPattern,
UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
UnexpectedVertVertInPattern, WrapInParens,
TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, TrailingVertSuggestion,
UnexpectedExpressionInPattern, UnexpectedExpressionInPatternSugg, UnexpectedLifetimeInPattern,
UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, WrapInParens,
};
use crate::parser::expr::{DestructuredFloat, could_be_unclosed_char_literal};
use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
@ -267,10 +267,9 @@ impl<'a> Parser<'a> {
if let PatKind::Or(pats) = &pat.kind {
let span = pat.span;
let sub = if pats.len() == 1 {
Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert {
span: span.with_hi(span.lo() + BytePos(1)),
})
let sub = if let [_] = &pats[..] {
let span = span.with_hi(span.lo() + BytePos(1));
Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span })
} else {
Some(TopLevelOrPatternNotAllowedSugg::WrapInParens {
span,
@ -362,6 +361,9 @@ impl<'a> Parser<'a> {
self.dcx().emit_err(TrailingVertNotAllowed {
span: self.token.span,
start: lo,
suggestion: TrailingVertSuggestion {
span: self.prev_token.span.shrink_to_hi().with_hi(self.token.span.hi()),
},
token: self.token,
note_double_vert: self.token.kind == token::OrOr,
});

View file

@ -16,6 +16,7 @@
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(decl_macro)]
#![feature(default_field_values)]
#![feature(if_let_guard)]
#![feature(iter_intersperse)]
#![feature(rustc_attrs)]
@ -1075,7 +1076,7 @@ pub struct Resolver<'ra, 'tcx> {
/// Assert that we are in speculative resolution mode.
assert_speculative: bool,
prelude: Option<Module<'ra>>,
prelude: Option<Module<'ra>> = None,
extern_prelude: FxIndexMap<Macros20NormalizedIdent, ExternPreludeEntry<'ra>>,
/// N.B., this is used only for better diagnostics, not name resolution itself.
@ -1087,10 +1088,10 @@ pub struct Resolver<'ra, 'tcx> {
field_visibility_spans: FxHashMap<DefId, Vec<Span>>,
/// All imports known to succeed or fail.
determined_imports: Vec<Import<'ra>>,
determined_imports: Vec<Import<'ra>> = Vec::new(),
/// All non-determined imports.
indeterminate_imports: Vec<Import<'ra>>,
indeterminate_imports: Vec<Import<'ra>> = Vec::new(),
// Spans for local variables found during pattern resolution.
// Used for suggestions during error reporting.
@ -1141,19 +1142,19 @@ pub struct Resolver<'ra, 'tcx> {
/// Maps glob imports to the names of items actually imported.
glob_map: FxIndexMap<LocalDefId, FxIndexSet<Symbol>>,
glob_error: Option<ErrorGuaranteed>,
visibilities_for_hashing: Vec<(LocalDefId, Visibility)>,
glob_error: Option<ErrorGuaranteed> = None,
visibilities_for_hashing: Vec<(LocalDefId, Visibility)> = Vec::new(),
used_imports: FxHashSet<NodeId>,
maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
/// Privacy errors are delayed until the end in order to deduplicate them.
privacy_errors: Vec<PrivacyError<'ra>>,
privacy_errors: Vec<PrivacyError<'ra>> = Vec::new(),
/// Ambiguity errors are delayed for deduplication.
ambiguity_errors: Vec<AmbiguityError<'ra>>,
ambiguity_errors: Vec<AmbiguityError<'ra>> = Vec::new(),
/// `use` injections are delayed for better placement and deduplication.
use_injections: Vec<UseError<'tcx>>,
use_injections: Vec<UseError<'tcx>> = Vec::new(),
/// Crate-local macro expanded `macro_export` referred to by a module-relative path.
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>,
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(),
arenas: &'ra ResolverArenas<'ra>,
dummy_binding: NameBinding<'ra>,
@ -1205,9 +1206,9 @@ pub struct Resolver<'ra, 'tcx> {
/// Avoid duplicated errors for "name already defined".
name_already_seen: FxHashMap<Symbol, Span>,
potentially_unused_imports: Vec<Import<'ra>>,
potentially_unused_imports: Vec<Import<'ra>> = Vec::new(),
potentially_unnecessary_qualifications: Vec<UnnecessaryQualification<'ra>>,
potentially_unnecessary_qualifications: Vec<UnnecessaryQualification<'ra>> = Vec::new(),
/// Table for mapping struct IDs into struct constructor IDs,
/// it's not used during normal resolution, only for better error reporting.
@ -1216,7 +1217,7 @@ pub struct Resolver<'ra, 'tcx> {
lint_buffer: LintBuffer,
next_node_id: NodeId,
next_node_id: NodeId = CRATE_NODE_ID,
node_id_to_def_id: NodeMap<Feed<'tcx, LocalDefId>>,
@ -1234,17 +1235,17 @@ pub struct Resolver<'ra, 'tcx> {
item_generics_num_lifetimes: FxHashMap<LocalDefId, usize>,
delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
main_def: Option<MainDefinition>,
main_def: Option<MainDefinition> = None,
trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
/// A list of proc macro LocalDefIds, written out in the order in which
/// they are declared in the static array generated by proc_macro_harness.
proc_macros: Vec<LocalDefId>,
proc_macros: Vec<LocalDefId> = Vec::new(),
confused_type_with_std_module: FxIndexMap<Span, Span>,
/// Whether lifetime elision was successful.
lifetime_elision_allowed: FxHashSet<NodeId>,
/// Names of items that were stripped out via cfg with their corresponding cfg meta item.
stripped_cfg_items: Vec<StrippedCfgItem<NodeId>>,
stripped_cfg_items: Vec<StrippedCfgItem<NodeId>> = Vec::new(),
effective_visibilities: EffectiveVisibilities,
doc_link_resolutions: FxIndexMap<LocalDefId, DocLinkResMap>,
@ -1558,9 +1559,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
field_defaults: Default::default(),
field_visibility_spans: FxHashMap::default(),
determined_imports: Vec::new(),
indeterminate_imports: Vec::new(),
pat_span_map: Default::default(),
partial_res_map: Default::default(),
import_res_map: Default::default(),
@ -1579,16 +1577,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ast_transform_scopes: FxHashMap::default(),
glob_map: Default::default(),
glob_error: None,
visibilities_for_hashing: Default::default(),
used_imports: FxHashSet::default(),
maybe_unused_trait_imports: Default::default(),
privacy_errors: Vec::new(),
ambiguity_errors: Vec::new(),
use_injections: Vec::new(),
macro_expanded_macro_export_errors: BTreeSet::new(),
arenas,
dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT),
builtin_types_bindings: PrimTy::ALL
@ -1632,8 +1623,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
derive_data: Default::default(),
local_macro_def_scopes: FxHashMap::default(),
name_already_seen: FxHashMap::default(),
potentially_unused_imports: Vec::new(),
potentially_unnecessary_qualifications: Default::default(),
struct_constructors: Default::default(),
unused_macros: Default::default(),
unused_macro_rules: Default::default(),
@ -1643,16 +1632,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
builtin_attrs: Default::default(),
containers_deriving_copy: Default::default(),
lint_buffer: LintBuffer::default(),
next_node_id: CRATE_NODE_ID,
node_id_to_def_id,
disambiguator: DisambiguatorState::new(),
placeholder_field_indices: Default::default(),
invocation_parents,
legacy_const_generic_args: Default::default(),
item_generics_num_lifetimes: Default::default(),
main_def: Default::default(),
trait_impls: Default::default(),
proc_macros: Default::default(),
confused_type_with_std_module: Default::default(),
lifetime_elision_allowed: Default::default(),
stripped_cfg_items: Default::default(),
@ -1667,6 +1653,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
current_crate_outer_attr_insert_span,
mods_with_parse_errors: Default::default(),
impl_trait_names: Default::default(),
..
};
let root_parent_scope = ParentScope::module(graph_root, resolver.arenas);

View file

@ -223,13 +223,14 @@ pub macro assert_matches {
/// }
/// ```
///
/// The `cfg_select!` macro can also be used in expression position:
/// The `cfg_select!` macro can also be used in expression position, with or without braces on the
/// right-hand side:
///
/// ```
/// #![feature(cfg_select)]
///
/// let _some_string = cfg_select! {
/// unix => { "With great power comes great electricity bills" }
/// unix => "With great power comes great electricity bills",
/// _ => { "Behind every successful diet is an unwatched pizza" }
/// };
/// ```

View file

@ -11,21 +11,18 @@ dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "anstyle"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bitflags"
version = "2.6.0"
@ -47,6 +44,7 @@ version = "0.0.0"
dependencies = [
"build_helper",
"cc",
"chrono",
"clap",
"clap_complete",
"cmake",
@ -71,7 +69,6 @@ dependencies = [
"toml",
"tracing",
"tracing-chrome",
"tracing-forest",
"tracing-subscriber",
"walkdir",
"windows",
@ -112,6 +109,15 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
dependencies = [
"num-traits",
]
[[package]]
name = "clap"
version = "4.5.20"
@ -458,6 +464,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "objc2-core-foundation"
version = "0.3.1"
@ -775,26 +790,6 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.8"
@ -857,19 +852,6 @@ dependencies = [
"valuable",
]
[[package]]
name = "tracing-forest"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f"
dependencies = [
"ansi_term",
"smallvec",
"thiserror",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "tracing-log"
version = "0.2.0"

View file

@ -7,7 +7,7 @@ default-run = "bootstrap"
[features]
build-metrics = ["sysinfo"]
tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:tracing-forest"]
tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:chrono", "dep:tempfile"]
[lib]
path = "src/lib.rs"
@ -61,10 +61,11 @@ xz2 = "0.1"
sysinfo = { version = "0.37.0", default-features = false, optional = true, features = ["system"] }
# Dependencies needed by the `tracing` feature
chrono = { version = "0.4", default-features = false, optional = true, features = ["now", "std"] }
tracing = { version = "0.1", optional = true, features = ["attributes"] }
tracing-chrome = { version = "0.7", optional = true }
tracing-subscriber = { version = "0.3", optional = true, features = ["env-filter", "fmt", "registry", "std"] }
tracing-forest = { version = "0.1.6", optional = true, default-features = false, features = ["smallvec", "ansi", "env-filter"] }
tempfile = { version = "3.15.0", optional = true }
[target.'cfg(windows)'.dependencies.junction]
version = "1.0.0"

View file

@ -7,6 +7,7 @@
use std::fs::{self, OpenOptions};
use std::io::{self, BufRead, BufReader, IsTerminal, Write};
use std::path::Path;
use std::str::FromStr;
use std::time::Instant;
use std::{env, process};
@ -15,19 +16,16 @@ use bootstrap::{
Build, CONFIG_CHANGE_HISTORY, ChangeId, Config, Flags, Subcommand, debug,
find_recent_config_change_ids, human_readable_changes, t,
};
#[cfg(feature = "tracing")]
use tracing::instrument;
fn is_bootstrap_profiling_enabled() -> bool {
env::var("BOOTSTRAP_PROFILE").is_ok_and(|v| v == "1")
fn is_tracing_enabled() -> bool {
cfg!(feature = "tracing")
}
#[cfg_attr(feature = "tracing", instrument(level = "trace", name = "main"))]
fn main() {
#[cfg(feature = "tracing")]
let _guard = setup_tracing();
let guard = bootstrap::setup_tracing("BOOTSTRAP_TRACING");
let start_time = Instant::now();
let _start_time = Instant::now();
let args = env::args().skip(1).collect::<Vec<_>>();
@ -102,6 +100,35 @@ fn main() {
let dump_bootstrap_shims = config.dump_bootstrap_shims;
let out_dir = config.out.clone();
let tracing_enabled = is_tracing_enabled();
// Prepare a directory for tracing output
// Also store a symlink named "latest" to point to the latest tracing directory.
let tracing_dir = out_dir.join("bootstrap-trace").join(std::process::id().to_string());
let latest_trace_dir = tracing_dir.parent().unwrap().join("latest");
if tracing_enabled {
let _ = std::fs::remove_dir_all(&tracing_dir);
std::fs::create_dir_all(&tracing_dir).unwrap();
#[cfg(windows)]
let _ = std::fs::remove_dir(&latest_trace_dir);
#[cfg(not(windows))]
let _ = std::fs::remove_file(&latest_trace_dir);
#[cfg(not(windows))]
fn symlink_dir_inner(original: &Path, link: &Path) -> io::Result<()> {
use std::os::unix::fs;
fs::symlink(original, link)
}
#[cfg(windows)]
fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> {
junction::create(target, junction)
}
t!(symlink_dir_inner(&tracing_dir, &latest_trace_dir));
}
debug!("creating new build based on config");
let mut build = Build::new(config);
build.build();
@ -156,12 +183,13 @@ fn main() {
}
}
if is_bootstrap_profiling_enabled() {
build.report_summary(start_time);
}
#[cfg(feature = "tracing")]
build.report_step_graph();
{
build.report_summary(&tracing_dir.join("command-stats.txt"), _start_time);
build.report_step_graph(&tracing_dir);
guard.copy_to_dir(&tracing_dir);
eprintln!("Tracing/profiling output has been written to {}", latest_trace_dir.display());
}
}
fn check_version(config: &Config) -> Option<String> {
@ -219,37 +247,3 @@ fn check_version(config: &Config) -> Option<String> {
Some(msg)
}
// # Note on `tracing` usage in bootstrap
//
// Due to the conditional compilation via the `tracing` cargo feature, this means that `tracing`
// usages in bootstrap need to be also gated behind the `tracing` feature:
//
// - `tracing` macros with log levels (`trace!`, `debug!`, `warn!`, `info`, `error`) should not be
// used *directly*. You should use the wrapped `tracing` macros which gate the actual invocations
// behind `feature = "tracing"`.
// - `tracing`'s `#[instrument(..)]` macro will need to be gated like `#![cfg_attr(feature =
// "tracing", instrument(..))]`.
#[cfg(feature = "tracing")]
fn setup_tracing() -> impl Drop {
use tracing_forest::ForestLayer;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::layer::SubscriberExt;
let filter = EnvFilter::from_env("BOOTSTRAP_TRACING");
let mut chrome_layer = tracing_chrome::ChromeLayerBuilder::new().include_args(true);
// Writes the Chrome profile to trace-<unix-timestamp>.json if enabled
if !is_bootstrap_profiling_enabled() {
chrome_layer = chrome_layer.writer(io::sink());
}
let (chrome_layer, _guard) = chrome_layer.build();
let registry =
tracing_subscriber::registry().with(filter).with(ForestLayer::default()).with(chrome_layer);
tracing::subscriber::set_global_default(registry).unwrap();
_guard
}

View file

@ -172,7 +172,7 @@ impl Rustc {
impl Step for Rustc {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@ -324,7 +324,7 @@ pub struct CodegenBackend {
impl Step for CodegenBackend {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@ -410,7 +410,7 @@ macro_rules! tool_check_step {
impl Step for $name {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
/// Most of the tool-checks using this macro are run by default.
const DEFAULT: bool = true $( && $default )?;

View file

@ -256,7 +256,7 @@ impl Rustc {
impl Step for Rustc {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {

View file

@ -16,7 +16,7 @@ use std::{env, fs, str};
use serde_derive::Deserialize;
#[cfg(feature = "tracing")]
use tracing::{instrument, span};
use tracing::span;
use crate::core::build_steps::gcc::{Gcc, GccOutput, add_cg_gcc_cargo_flags};
use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts};
@ -104,7 +104,6 @@ impl Step for Std {
run.crate_or_deps("sysroot").path("library")
}
#[cfg_attr(feature = "tracing", instrument(level = "trace", name = "Std::make_run", skip_all))]
fn make_run(run: RunConfig<'_>) {
let crates = std_crates_for_run_make(&run);
let builder = run.builder;
@ -135,19 +134,6 @@ impl Step for Std {
/// This will build the standard library for a particular stage of the build
/// using the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = "Std::run",
skip_all,
fields(
target = ?self.target,
compiler = ?self.compiler,
force_recompile = self.force_recompile
),
),
)]
fn run(self, builder: &Builder<'_>) {
let target = self.target;
@ -717,19 +703,6 @@ impl Step for StdLink {
/// Note that this assumes that `compiler` has already generated the libstd
/// libraries for `target`, and this method will find them in the relevant
/// output directory.
#[cfg_attr(
feature = "tracing",
instrument(
level = "trace",
name = "StdLink::run",
skip_all,
fields(
compiler = ?self.compiler,
target_compiler = ?self.target_compiler,
target = ?self.target
),
),
)]
fn run(self, builder: &Builder<'_>) {
let compiler = self.compiler;
let target_compiler = self.target_compiler;
@ -895,15 +868,6 @@ impl Step for StartupObjects {
/// They don't require any library support as they're just plain old object
/// files, so we just use the nightly snapshot compiler to always build them (as
/// no other compilers are guaranteed to be available).
#[cfg_attr(
feature = "tracing",
instrument(
level = "trace",
name = "StartupObjects::run",
skip_all,
fields(compiler = ?self.compiler, target = ?self.target),
),
)]
fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> {
let for_compiler = self.compiler;
let target = self.target;
@ -995,7 +959,7 @@ impl Step for Rustc {
/// uplifting it from stage Y, causing the other stage to fail when attempting to link with
/// stage X which was never actually built.
type Output = u32;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@ -1033,15 +997,6 @@ impl Step for Rustc {
/// This will build the compiler for a particular stage of the build using
/// the `build_compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = "Rustc::run",
skip_all,
fields(previous_compiler = ?self.build_compiler, target = ?self.target),
),
)]
fn run(self, builder: &Builder<'_>) -> u32 {
let build_compiler = self.build_compiler;
let target = self.target;
@ -1397,6 +1352,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
// Build jemalloc on AArch64 with support for page sizes up to 64K
// See: https://github.com/rust-lang/rust/pull/135081
// See also the "JEMALLOC_SYS_WITH_LG_PAGE" setting in the tool build step.
if builder.config.jemalloc(target)
&& target.starts_with("aarch64")
&& env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none()
@ -1517,19 +1473,6 @@ impl Step for RustcLink {
}
/// Same as `std_link`, only for librustc
#[cfg_attr(
feature = "tracing",
instrument(
level = "trace",
name = "RustcLink::run",
skip_all,
fields(
compiler = ?self.compiler,
previous_stage_compiler = ?self.previous_stage_compiler,
target = ?self.target,
),
),
)]
fn run(self, builder: &Builder<'_>) {
let compiler = self.compiler;
let previous_stage_compiler = self.previous_stage_compiler;
@ -1559,7 +1502,7 @@ pub struct GccCodegenBackend {
impl Step for GccCodegenBackend {
type Output = GccCodegenBackendOutput;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("rustc_codegen_gcc").alias("cg_gcc")
@ -1571,17 +1514,6 @@ impl Step for GccCodegenBackend {
});
}
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = "GccCodegenBackend::run",
skip_all,
fields(
compilers = ?self.compilers,
),
),
)]
fn run(self, builder: &Builder<'_>) -> Self::Output {
let target = self.compilers.target();
let build_compiler = self.compilers.build_compiler();
@ -1644,7 +1576,7 @@ pub struct CraneliftCodegenBackend {
impl Step for CraneliftCodegenBackend {
type Output = BuildStamp;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("rustc_codegen_cranelift").alias("cg_clif")
@ -1656,17 +1588,6 @@ impl Step for CraneliftCodegenBackend {
});
}
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = "CraneliftCodegenBackend::run",
skip_all,
fields(
compilers = ?self.compilers,
),
),
)]
fn run(self, builder: &Builder<'_>) -> Self::Output {
let target = self.compilers.target();
let build_compiler = self.compilers.build_compiler();
@ -1841,15 +1762,6 @@ impl Step for Sysroot {
/// Returns the sysroot that `compiler` is supposed to use.
/// For the stage0 compiler, this is stage0-sysroot (because of the initial std build).
/// For all other stages, it's the same stage directory that the compiler lives in.
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = "Sysroot::run",
skip_all,
fields(compiler = ?self.compiler),
),
)]
fn run(self, builder: &Builder<'_>) -> PathBuf {
let compiler = self.compiler;
let host_dir = builder.out.join(compiler.host);
@ -2008,7 +1920,7 @@ pub struct Assemble {
impl Step for Assemble {
type Output = Compiler;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("compiler/rustc").path("compiler")
@ -2025,15 +1937,6 @@ impl Step for Assemble {
/// This will assemble a compiler in `build/$host/stage$stage`. The compiler
/// must have been previously produced by the `stage - 1` builder.build
/// compiler.
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = "Assemble::run",
skip_all,
fields(target_compiler = ?self.target_compiler),
),
)]
fn run(self, builder: &Builder<'_>) -> Compiler {
let target_compiler = self.target_compiler;
@ -2592,7 +2495,7 @@ pub fn stream_cargo(
let mut cmd = cargo.into_cmd();
#[cfg(feature = "tracing")]
let _run_span = crate::trace_cmd!(cmd);
let _run_span = crate::utils::tracing::trace_cmd(&cmd);
// Instruct Cargo to give us json messages on stdout, critically leaving
// stderr as piped so we can get those pretty colors.

View file

@ -140,7 +140,7 @@ pub struct RustcDocs {
impl Step for RustcDocs {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -402,7 +402,7 @@ pub struct Rustc {
impl Step for Rustc {
type Output = GeneratedTarball;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("rustc")
@ -794,7 +794,7 @@ pub struct RustcDev {
impl Step for RustcDev {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("rustc-dev")
@ -1024,7 +1024,7 @@ impl Step for Src {
/// The output path of the src installer tarball
type Output = GeneratedTarball;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("rust-src")
@ -1085,7 +1085,7 @@ impl Step for PlainSourceTarball {
/// Produces the location of the tarball generated
type Output = GeneratedTarball;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -1233,7 +1233,7 @@ pub struct Cargo {
impl Step for Cargo {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(run.builder, "cargo");
@ -1287,7 +1287,7 @@ pub struct RustAnalyzer {
impl Step for RustAnalyzer {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(run.builder, "rust-analyzer");
@ -1330,7 +1330,7 @@ pub struct Clippy {
impl Step for Clippy {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(run.builder, "clippy");
@ -1378,7 +1378,7 @@ pub struct Miri {
impl Step for Miri {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(run.builder, "miri");
@ -1428,7 +1428,7 @@ pub struct CraneliftCodegenBackend {
impl Step for CraneliftCodegenBackend {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
// We only want to build the cranelift backend in `x dist` if the backend was enabled
@ -1519,7 +1519,7 @@ pub struct Rustfmt {
impl Step for Rustfmt {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(run.builder, "rustfmt");
@ -1564,7 +1564,7 @@ pub struct Extended {
impl Step for Extended {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -2301,7 +2301,7 @@ pub struct LlvmTools {
impl Step for LlvmTools {
type Output = Option<GeneratedTarball>;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@ -2406,7 +2406,7 @@ pub struct LlvmBitcodeLinker {
impl Step for LlvmBitcodeLinker {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(run.builder, "llvm-bitcode-linker");
@ -2458,7 +2458,7 @@ pub struct RustDev {
impl Step for RustDev {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("rust-dev")
@ -2561,7 +2561,7 @@ pub struct Bootstrap {
impl Step for Bootstrap {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = false;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("bootstrap")
@ -2601,7 +2601,7 @@ pub struct BuildManifest {
impl Step for BuildManifest {
type Output = GeneratedTarball;
const DEFAULT: bool = false;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("build-manifest")
@ -2633,7 +2633,7 @@ pub struct ReproducibleArtifacts {
impl Step for ReproducibleArtifacts {
type Output = Option<GeneratedTarball>;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("reproducible-artifacts")

View file

@ -830,7 +830,7 @@ impl Rustc {
impl Step for Rustc {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -975,7 +975,7 @@ macro_rules! tool_doc {
impl Step for $tool {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -1139,7 +1139,7 @@ pub struct ErrorIndex {
impl Step for ErrorIndex {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -1181,7 +1181,7 @@ pub struct UnstableBookGen {
impl Step for UnstableBookGen {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -1248,7 +1248,7 @@ impl RustcBook {
impl Step for RustcBook {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;

View file

@ -47,7 +47,7 @@ impl GccOutput {
impl Step for Gcc {
type Output = GccOutput;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/gcc").alias("gcc")

View file

@ -163,7 +163,7 @@ macro_rules! install {
$($name:ident,
$condition_name: ident = $path_or_alias: literal,
$default_cond:expr,
only_hosts: $only_hosts:expr,
IS_HOST: $IS_HOST:expr,
$run_item:block $(, $c:ident)*;)+) => {
$(
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
@ -183,7 +183,7 @@ macro_rules! install {
impl Step for $name {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = $only_hosts;
const IS_HOST: bool = $IS_HOST;
$(const $c: bool = true;)*
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@ -206,11 +206,11 @@ macro_rules! install {
}
install!((self, builder, _config),
Docs, path = "src/doc", _config.docs, only_hosts: false, {
Docs, path = "src/doc", _config.docs, IS_HOST: false, {
let tarball = builder.ensure(dist::Docs { host: self.target }).expect("missing docs");
install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball);
};
Std, path = "library/std", true, only_hosts: false, {
Std, path = "library/std", true, IS_HOST: false, {
// `expect` should be safe, only None when host != build, but this
// only runs when host == build
let tarball = builder.ensure(dist::Std {
@ -219,13 +219,13 @@ install!((self, builder, _config),
}).expect("missing std");
install_sh(builder, "std", self.compiler.stage, Some(self.target), &tarball);
};
Cargo, alias = "cargo", Self::should_build(_config), only_hosts: true, {
Cargo, alias = "cargo", Self::should_build(_config), IS_HOST: true, {
let tarball = builder
.ensure(dist::Cargo { build_compiler: self.compiler, target: self.target })
.expect("missing cargo");
install_sh(builder, "cargo", self.compiler.stage, Some(self.target), &tarball);
};
RustAnalyzer, alias = "rust-analyzer", Self::should_build(_config), only_hosts: true, {
RustAnalyzer, alias = "rust-analyzer", Self::should_build(_config), IS_HOST: true, {
if let Some(tarball) =
builder.ensure(dist::RustAnalyzer { build_compiler: self.compiler, target: self.target })
{
@ -236,13 +236,13 @@ install!((self, builder, _config),
);
}
};
Clippy, alias = "clippy", Self::should_build(_config), only_hosts: true, {
Clippy, alias = "clippy", Self::should_build(_config), IS_HOST: true, {
let tarball = builder
.ensure(dist::Clippy { build_compiler: self.compiler, target: self.target })
.expect("missing clippy");
install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball);
};
Miri, alias = "miri", Self::should_build(_config), only_hosts: true, {
Miri, alias = "miri", Self::should_build(_config), IS_HOST: true, {
if let Some(tarball) = builder.ensure(dist::Miri { build_compiler: self.compiler, target: self.target }) {
install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball);
} else {
@ -252,7 +252,7 @@ install!((self, builder, _config),
);
}
};
LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.host_target), only_hosts: true, {
LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.host_target), IS_HOST: true, {
if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) {
install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
} else {
@ -261,7 +261,7 @@ install!((self, builder, _config),
);
}
};
Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, {
Rustfmt, alias = "rustfmt", Self::should_build(_config), IS_HOST: true, {
if let Some(tarball) = builder.ensure(dist::Rustfmt {
build_compiler: self.compiler,
target: self.target
@ -273,13 +273,13 @@ install!((self, builder, _config),
);
}
};
Rustc, path = "compiler/rustc", true, only_hosts: true, {
Rustc, path = "compiler/rustc", true, IS_HOST: true, {
let tarball = builder.ensure(dist::Rustc {
compiler: builder.compiler(builder.top_stage, self.target),
});
install_sh(builder, "rustc", self.compiler.stage, Some(self.target), &tarball);
};
RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), only_hosts: true, {
RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), IS_HOST: true, {
if let Some(tarball) = builder.ensure(dist::CraneliftCodegenBackend {
build_compiler: self.compiler,
target: self.target
@ -292,7 +292,7 @@ install!((self, builder, _config),
);
}
};
LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), only_hosts: true, {
LlvmBitcodeLinker, alias = "llvm-bitcode-linker", Self::should_build(_config), IS_HOST: true, {
if let Some(tarball) = builder.ensure(dist::LlvmBitcodeLinker { build_compiler: self.compiler, target: self.target }) {
install_sh(builder, "llvm-bitcode-linker", self.compiler.stage, Some(self.target), &tarball);
} else {
@ -311,7 +311,7 @@ pub struct Src {
impl Step for Src {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let config = &run.builder.config;

View file

@ -15,8 +15,6 @@ use std::sync::OnceLock;
use std::{env, fs};
use build_helper::git::PathFreshness;
#[cfg(feature = "tracing")]
use tracing::instrument;
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step, StepMetadata};
use crate::core::config::{Config, TargetSelection};
@ -255,7 +253,7 @@ pub struct Llvm {
impl Step for Llvm {
type Output = LlvmResult;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/llvm-project").path("src/llvm-project/llvm")
@ -266,15 +264,6 @@ impl Step for Llvm {
}
/// Compile LLVM for `target`.
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = "Llvm::run",
skip_all,
fields(target = ?self.target),
),
)]
fn run(self, builder: &Builder<'_>) -> LlvmResult {
let target = self.target;
let target_native = if self.target.starts_with("riscv") {
@ -908,7 +897,7 @@ pub struct Enzyme {
impl Step for Enzyme {
type Output = PathBuf;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/enzyme/enzyme")
@ -919,15 +908,6 @@ impl Step for Enzyme {
}
/// Compile Enzyme for `target`.
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = "Enzyme::run",
skip_all,
fields(target = ?self.target),
),
)]
fn run(self, builder: &Builder<'_>) -> PathBuf {
builder.require_submodule(
"src/tools/enzyme",
@ -1013,7 +993,7 @@ pub struct Lld {
impl Step for Lld {
type Output = PathBuf;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/llvm-project/lld")

View file

@ -22,7 +22,7 @@ pub struct BuildManifest;
impl Step for BuildManifest {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/build-manifest")
@ -61,7 +61,7 @@ pub struct BumpStage0;
impl Step for BumpStage0 {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/bump-stage0")
@ -83,7 +83,7 @@ pub struct ReplaceVersionPlaceholder;
impl Step for ReplaceVersionPlaceholder {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/replace-version-placeholder")
@ -107,7 +107,6 @@ pub struct Miri {
impl Step for Miri {
type Output = ();
const ONLY_HOSTS: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/miri")
@ -175,7 +174,7 @@ pub struct CollectLicenseMetadata;
impl Step for CollectLicenseMetadata {
type Output = PathBuf;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/collect-license-metadata")
@ -206,7 +205,7 @@ pub struct GenerateCopyright;
impl Step for GenerateCopyright {
type Output = Vec<PathBuf>;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/generate-copyright")
@ -270,7 +269,7 @@ pub struct GenerateWindowsSys;
impl Step for GenerateWindowsSys {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/generate-windows-sys")
@ -332,7 +331,7 @@ pub struct UnicodeTableGenerator;
impl Step for UnicodeTableGenerator {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/unicode-table-generator")
@ -354,7 +353,7 @@ pub struct FeaturesStatusDump;
impl Step for FeaturesStatusDump {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/features-status-dump")
@ -416,7 +415,7 @@ impl Step for CoverageDump {
type Output = ();
const DEFAULT: bool = false;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/coverage-dump")
@ -438,7 +437,7 @@ pub struct Rustfmt;
impl Step for Rustfmt {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rustfmt")

View file

@ -21,7 +21,6 @@ pub(crate) struct MirOptPanicAbortSyntheticTarget {
impl Step for MirOptPanicAbortSyntheticTarget {
type Output = TargetSelection;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.never()

View file

@ -10,8 +10,6 @@ use std::path::{Path, PathBuf};
use std::{env, fs, iter};
use build_helper::exit;
#[cfg(feature = "tracing")]
use tracing::instrument;
use crate::core::build_steps::compile::{Std, run_cargo};
use crate::core::build_steps::doc::DocumentationFormat;
@ -51,7 +49,7 @@ pub struct CrateBootstrap {
impl Step for CrateBootstrap {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@ -109,7 +107,7 @@ pub struct Linkcheck {
impl Step for Linkcheck {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = true;
/// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
@ -189,7 +187,7 @@ pub struct HtmlCheck {
impl Step for HtmlCheck {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -236,7 +234,7 @@ pub struct Cargotest {
impl Step for Cargotest {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/cargotest")
@ -313,7 +311,7 @@ impl Cargo {
impl Step for Cargo {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path(Self::CRATE_PATH)
@ -410,7 +408,7 @@ pub struct RustAnalyzer {
impl Step for RustAnalyzer {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@ -469,7 +467,7 @@ pub struct Rustfmt {
impl Step for Rustfmt {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rustfmt")
@ -561,7 +559,6 @@ impl Miri {
impl Step for Miri {
type Output = ();
const ONLY_HOSTS: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/miri")
@ -681,7 +678,6 @@ pub struct CargoMiri {
impl Step for CargoMiri {
type Output = ();
const ONLY_HOSTS: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/miri/cargo-miri")
@ -760,10 +756,6 @@ impl Step for CompiletestTest {
}
/// Runs `cargo test` for compiletest.
#[cfg_attr(
feature = "tracing",
instrument(level = "debug", name = "CompiletestTest::run", skip_all)
)]
fn run(self, builder: &Builder<'_>) {
let host = self.host;
@ -811,7 +803,7 @@ pub struct Clippy {
impl Step for Clippy {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@ -911,7 +903,7 @@ pub struct RustdocTheme {
impl Step for RustdocTheme {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rustdoc-themes")
@ -948,7 +940,7 @@ pub struct RustdocJSStd {
impl Step for RustdocJSStd {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = run.builder.config.nodejs.is_some();
@ -1008,7 +1000,7 @@ pub struct RustdocJSNotStd {
impl Step for RustdocJSNotStd {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = run.builder.config.nodejs.is_some();
@ -1063,7 +1055,7 @@ pub struct RustdocGUI {
impl Step for RustdocGUI {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -1156,7 +1148,7 @@ pub struct Tidy;
impl Step for Tidy {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
/// Runs the `tidy` tool.
///
@ -1274,7 +1266,7 @@ macro_rules! test {
mode: $mode:expr,
suite: $suite:expr,
default: $default:expr
$( , only_hosts: $only_hosts:expr )? // default: false
$( , IS_HOST: $IS_HOST:expr )? // default: false
$( , compare_mode: $compare_mode:expr )? // default: None
$( , )? // optional trailing comma
}
@ -1289,10 +1281,10 @@ macro_rules! test {
impl Step for $name {
type Output = ();
const DEFAULT: bool = $default;
const ONLY_HOSTS: bool = (const {
const IS_HOST: bool = (const {
#[allow(unused_assignments, unused_mut)]
let mut value = false;
$( value = $only_hosts; )?
$( value = $IS_HOST; )?
value
});
@ -1340,7 +1332,7 @@ pub struct CrateRunMakeSupport {
impl Step for CrateRunMakeSupport {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/run-make-support")
@ -1377,7 +1369,7 @@ pub struct CrateBuildHelper {
impl Step for CrateBuildHelper {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/build_helper")
@ -1445,7 +1437,7 @@ test!(UiFullDeps {
mode: "ui",
suite: "ui-fulldeps",
default: true,
only_hosts: true,
IS_HOST: true,
});
test!(Rustdoc {
@ -1453,14 +1445,14 @@ test!(Rustdoc {
mode: "rustdoc",
suite: "rustdoc",
default: true,
only_hosts: true,
IS_HOST: true,
});
test!(RustdocUi {
path: "tests/rustdoc-ui",
mode: "ui",
suite: "rustdoc-ui",
default: true,
only_hosts: true,
IS_HOST: true,
});
test!(RustdocJson {
@ -1468,7 +1460,7 @@ test!(RustdocJson {
mode: "rustdoc-json",
suite: "rustdoc-json",
default: true,
only_hosts: true,
IS_HOST: true,
});
test!(Pretty {
@ -1476,7 +1468,7 @@ test!(Pretty {
mode: "pretty",
suite: "pretty",
default: true,
only_hosts: true,
IS_HOST: true,
});
test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true });
@ -1507,7 +1499,7 @@ impl Step for Coverage {
type Output = ();
const DEFAULT: bool = true;
/// Compiletest will automatically skip the "coverage-run" tests if necessary.
const ONLY_HOSTS: bool = false;
const IS_HOST: bool = false;
fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
// Support various invocation styles, including:
@ -1586,7 +1578,7 @@ test!(CoverageRunRustdoc {
mode: "coverage-run",
suite: "coverage-run-rustdoc",
default: true,
only_hosts: true,
IS_HOST: true,
});
// For the mir-opt suite we do not use macros, as we need custom behavior when blessing.
@ -1599,7 +1591,6 @@ pub struct MirOpt {
impl Step for MirOpt {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.suite_path("tests/mir-opt")
@ -2276,7 +2267,7 @@ struct BookTest {
impl Step for BookTest {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.never()
@ -2442,7 +2433,7 @@ macro_rules! test_book {
impl Step for $name {
type Output = ();
const DEFAULT: bool = $default;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path($path)
@ -2502,7 +2493,7 @@ pub struct ErrorIndex {
impl Step for ErrorIndex {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
// Also add `error-index` here since that is what appears in the error message
@ -2598,7 +2589,7 @@ pub struct CrateLibrustc {
impl Step for CrateLibrustc {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.crate_or_deps("rustc-main").path("compiler")
@ -2883,7 +2874,7 @@ pub struct CrateRustdoc {
impl Step for CrateRustdoc {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.paths(&["src/librustdoc", "src/tools/rustdoc"])
@ -2975,7 +2966,7 @@ pub struct CrateRustdocJsonTypes {
impl Step for CrateRustdocJsonTypes {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/rustdoc-json-types")
@ -3164,7 +3155,7 @@ pub struct Bootstrap;
impl Step for Bootstrap {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
/// Tests the build system itself.
fn run(self, builder: &Builder<'_>) {
@ -3234,7 +3225,7 @@ pub struct TierCheck {
impl Step for TierCheck {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/tier-check")
@ -3288,7 +3279,7 @@ pub struct LintDocs {
impl Step for LintDocs {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/lint-docs")
@ -3314,7 +3305,7 @@ pub struct RustInstaller;
impl Step for RustInstaller {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = true;
/// Ensure the version placeholder replacement tool builds
@ -3434,7 +3425,7 @@ pub struct CodegenCranelift {
impl Step for CodegenCranelift {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.paths(&["compiler/rustc_codegen_cranelift"])
@ -3562,7 +3553,7 @@ pub struct CodegenGCC {
impl Step for CodegenGCC {
type Output = ();
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.paths(&["compiler/rustc_codegen_gcc"])
@ -3695,7 +3686,7 @@ pub struct TestFloatParse {
impl Step for TestFloatParse {
type Output = ();
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@ -3761,7 +3752,7 @@ pub struct CollectLicenseMetadata;
impl Step for CollectLicenseMetadata {
type Output = PathBuf;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/collect-license-metadata")

View file

@ -13,9 +13,6 @@ use std::ffi::OsStr;
use std::path::PathBuf;
use std::{env, fs};
#[cfg(feature = "tracing")]
use tracing::instrument;
use crate::core::build_steps::compile::is_lto_stage;
use crate::core::build_steps::toolstate::ToolState;
use crate::core::build_steps::{compile, llvm};
@ -229,6 +226,14 @@ pub fn prepare_tool_cargo(
// own copy
cargo.env("LZMA_API_STATIC", "1");
// Build jemalloc on AArch64 with support for page sizes up to 64K
// See: https://github.com/rust-lang/rust/pull/135081
// Note that `miri` always uses jemalloc. As such, there is no checking of the jemalloc build flag.
// See also the "JEMALLOC_SYS_WITH_LG_PAGE" setting in the compile build step.
if target.starts_with("aarch64") && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() {
cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16");
}
// CFG_RELEASE is needed by rustfmt (and possibly other tools) which
// import rustc-ap-rustc_attr which requires this to be set for the
// `#[cfg(version(...))]` attribute.
@ -415,14 +420,6 @@ macro_rules! bootstrap_tool {
});
}
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = $tool_name,
skip_all,
),
)]
fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
$(
for submodule in $submodules {
@ -687,7 +684,7 @@ impl Step for Rustdoc {
type Output = PathBuf;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rustdoc").path("src/librustdoc")
@ -809,7 +806,7 @@ impl Cargo {
impl Step for Cargo {
type Output = ToolBuildResult;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -885,7 +882,7 @@ impl LldWrapper {
impl Step for LldWrapper {
type Output = BuiltLldWrapper;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/lld-wrapper")
@ -901,15 +898,6 @@ impl Step for LldWrapper {
});
}
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = "LldWrapper::run",
skip_all,
fields(build_compiler = ?self.build_compiler),
),
)]
fn run(self, builder: &Builder<'_>) -> Self::Output {
let lld_dir = builder.ensure(llvm::Lld { target: self.target });
let tool = builder.ensure(ToolBuild {
@ -986,7 +974,7 @@ impl WasmComponentLd {
impl Step for WasmComponentLd {
type Output = ToolBuildResult;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/wasm-component-ld")
@ -1002,15 +990,6 @@ impl Step for WasmComponentLd {
});
}
#[cfg_attr(
feature = "tracing",
instrument(
level = "debug",
name = "WasmComponentLd::run",
skip_all,
fields(build_compiler = ?self.build_compiler),
),
)]
fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
builder.ensure(ToolBuild {
build_compiler: self.build_compiler,
@ -1049,7 +1028,7 @@ impl RustAnalyzer {
impl Step for RustAnalyzer {
type Output = ToolBuildResult;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -1102,7 +1081,7 @@ impl Step for RustAnalyzerProcMacroSrv {
type Output = ToolBuildResult;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -1192,7 +1171,7 @@ impl LlvmBitcodeLinker {
impl Step for LlvmBitcodeLinker {
type Output = ToolBuildResult;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
@ -1207,10 +1186,6 @@ impl Step for LlvmBitcodeLinker {
});
}
#[cfg_attr(
feature = "tracing",
instrument(level = "debug", name = "LlvmBitcodeLinker::run", skip_all)
)]
fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
builder.ensure(ToolBuild {
build_compiler: self.build_compiler,
@ -1246,7 +1221,7 @@ pub enum LibcxxVersion {
impl Step for LibcxxVersionTool {
type Output = LibcxxVersion;
const DEFAULT: bool = false;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.never()
@ -1407,7 +1382,7 @@ macro_rules! tool_rustc_extended {
impl Step for $name {
type Output = ToolBuildResult;
const DEFAULT: bool = true; // Overridden by `should_run_tool_build_step`
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
should_run_extended_rustc_tool(
@ -1575,7 +1550,7 @@ impl TestFloatParse {
impl Step for TestFloatParse {
type Output = ToolBuildResult;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
const DEFAULT: bool = false;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {

View file

@ -53,7 +53,7 @@ pub(crate) struct Vendor {
impl Step for Vendor {
type Output = VendorOutput;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
const IS_HOST: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("placeholder").default_condition(true)

View file

@ -499,6 +499,10 @@ impl Builder<'_> {
build_stamp::clear_if_dirty(self, &out_dir, &backend);
}
if self.config.cmd.timings() {
cargo.arg("--timings");
}
if cmd_kind == Kind::Doc {
let my_out = match mode {
// This is the intended out directory for compiler documentation.

View file

@ -100,8 +100,13 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
/// by `Step::should_run`.
const DEFAULT: bool = false;
/// If true, then this rule should be skipped if --target was specified, but --host was not
const ONLY_HOSTS: bool = false;
/// If this value is true, then the values of `run.target` passed to the `make_run` function of
/// this Step will be determined based on the `--host` flag.
/// If this value is false, then they will be determined based on the `--target` flag.
///
/// A corollary of the above is that if this is set to true, then the step will be skipped if
/// `--target` was specified, but `--host` was explicitly set to '' (empty string).
const IS_HOST: bool = false;
/// Primary function to implement `Step` logic.
///
@ -298,7 +303,7 @@ pub fn crate_description(crates: &[impl AsRef<str>]) -> String {
struct StepDescription {
default: bool,
only_hosts: bool,
is_host: bool,
should_run: fn(ShouldRun<'_>) -> ShouldRun<'_>,
make_run: fn(RunConfig<'_>),
name: &'static str,
@ -500,7 +505,7 @@ impl StepDescription {
fn from<S: Step>(kind: Kind) -> StepDescription {
StepDescription {
default: S::DEFAULT,
only_hosts: S::ONLY_HOSTS,
is_host: S::IS_HOST,
should_run: S::should_run,
make_run: S::make_run,
name: std::any::type_name::<S>(),
@ -516,7 +521,7 @@ impl StepDescription {
}
// Determine the targets participating in this rule.
let targets = if self.only_hosts { &builder.hosts } else { &builder.targets };
let targets = if self.is_host { &builder.hosts } else { &builder.targets };
for target in targets {
let run = RunConfig { builder, paths: pathsets.clone(), target: *target };
@ -951,6 +956,9 @@ impl Step for Libdir {
}
}
#[cfg(feature = "tracing")]
pub const STEP_SPAN_TARGET: &str = "STEP";
impl<'a> Builder<'a> {
fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
macro_rules! describe {
@ -1271,7 +1279,7 @@ impl<'a> Builder<'a> {
pub fn new(build: &Build) -> Builder<'_> {
let paths = &build.config.paths;
let (kind, paths) = match build.config.cmd {
Subcommand::Build => (Kind::Build, &paths[..]),
Subcommand::Build { .. } => (Kind::Build, &paths[..]),
Subcommand::Check { .. } => (Kind::Check, &paths[..]),
Subcommand::Clippy { .. } => (Kind::Clippy, &paths[..]),
Subcommand::Fix => (Kind::Fix, &paths[..]),
@ -1680,8 +1688,6 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s
panic!("{}", out);
}
if let Some(out) = self.cache.get(&step) {
self.verbose_than(1, || println!("{}c {:?}", " ".repeat(stack.len()), step));
#[cfg(feature = "tracing")]
{
if let Some(parent) = stack.last() {
@ -1691,7 +1697,6 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s
}
return out;
}
self.verbose_than(1, || println!("{}> {:?}", " ".repeat(stack.len()), step));
#[cfg(feature = "tracing")]
{
@ -1706,10 +1711,29 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s
#[cfg(feature = "build-metrics")]
self.metrics.enter_step(&step, self);
if self.config.print_step_timings && !self.config.dry_run() {
println!("[TIMING:start] {}", pretty_print_step(&step));
}
let (out, dur) = {
let start = Instant::now();
let zero = Duration::new(0, 0);
let parent = self.time_spent_on_dependencies.replace(zero);
#[cfg(feature = "tracing")]
let _span = {
// Keep the target and field names synchronized with `setup_tracing`.
let span = tracing::info_span!(
target: STEP_SPAN_TARGET,
// We cannot use a dynamic name here, so instead we record the actual step name
// in the step_name field.
"step",
step_name = pretty_step_name::<S>(),
args = step_debug_args(&step)
);
span.entered()
};
let out = step.clone().run(self);
let dur = start.elapsed();
let deps = self.time_spent_on_dependencies.replace(parent + dur);
@ -1717,13 +1741,9 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s
};
if self.config.print_step_timings && !self.config.dry_run() {
let step_string = format!("{step:?}");
let brace_index = step_string.find('{').unwrap_or(0);
let type_string = type_name::<S>();
println!(
"[TIMING] {} {} -- {}.{:03}",
&type_string.strip_prefix("bootstrap::").unwrap_or(type_string),
&step_string[brace_index..],
"[TIMING:end] {} -- {}.{:03}",
pretty_print_step(&step),
dur.as_secs(),
dur.subsec_millis()
);
@ -1737,7 +1757,6 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s
let cur_step = stack.pop().expect("step stack empty");
assert_eq!(cur_step.downcast_ref(), Some(&step));
}
self.verbose_than(1, || println!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step));
self.cache.put(step, out.clone());
out
}
@ -1810,6 +1829,25 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s
}
}
/// Return qualified step name, e.g. `compile::Rustc`.
pub fn pretty_step_name<S: Step>() -> String {
// Normalize step type path to only keep the module and the type name
let path = type_name::<S>().rsplit("::").take(2).collect::<Vec<_>>();
path.into_iter().rev().collect::<Vec<_>>().join("::")
}
/// Renders `step` using its `Debug` implementation and extract the field arguments out of it.
fn step_debug_args<S: Step>(step: &S) -> String {
let step_dbg_repr = format!("{step:?}");
let brace_start = step_dbg_repr.find('{').unwrap_or(0);
let brace_end = step_dbg_repr.rfind('}').unwrap_or(step_dbg_repr.len());
step_dbg_repr[brace_start + 1..brace_end - 1].trim().to_string()
}
fn pretty_print_step<S: Step>(step: &S) -> String {
format!("{} {{ {} }}", pretty_step_name::<S>(), step_debug_args(step))
}
impl<'a> AsRef<ExecutionContext> for Builder<'a> {
fn as_ref(&self) -> &ExecutionContext {
self.exec_ctx()

View file

@ -1342,7 +1342,7 @@ impl Config {
Subcommand::Doc { .. } => {
flags_stage.or(build_doc_stage).unwrap_or(if download_rustc { 2 } else { 1 })
}
Subcommand::Build => {
Subcommand::Build { .. } => {
flags_stage.or(build_build_stage).unwrap_or(if download_rustc { 2 } else { 1 })
}
Subcommand::Test { .. } | Subcommand::Miri { .. } => {
@ -1363,7 +1363,7 @@ impl Config {
// Now check that the selected stage makes sense, and if not, print a warning and end
match (config.stage, &config.cmd) {
(0, Subcommand::Build) => {
(0, Subcommand::Build { .. }) => {
eprintln!("ERROR: cannot build anything on stage 0. Use at least stage 1.");
exit!(1);
}
@ -1396,7 +1396,7 @@ impl Config {
Subcommand::Test { .. }
| Subcommand::Miri { .. }
| Subcommand::Doc { .. }
| Subcommand::Build
| Subcommand::Build { .. }
| Subcommand::Bench { .. }
| Subcommand::Dist
| Subcommand::Install => {

View file

@ -241,7 +241,7 @@ fn normalize_args(args: &[String]) -> Vec<String> {
it.collect()
}
#[derive(Debug, Clone, Default, clap::Subcommand)]
#[derive(Debug, Clone, clap::Subcommand)]
pub enum Subcommand {
#[command(aliases = ["b"], long_about = "\n
Arguments:
@ -256,8 +256,11 @@ pub enum Subcommand {
./x.py build --stage 0
./x.py build ")]
/// Compile either the compiler or libraries
#[default]
Build,
Build {
#[arg(long)]
/// Pass `--timings` to Cargo to get crate build timings
timings: bool,
},
#[command(aliases = ["c"], long_about = "\n
Arguments:
This subcommand accepts a number of paths to directories to the crates
@ -269,6 +272,9 @@ pub enum Subcommand {
#[arg(long)]
/// Check all targets
all_targets: bool,
#[arg(long)]
/// Pass `--timings` to Cargo to get crate build timings
timings: bool,
},
/// Run Clippy (uses rustup/cargo-installed clippy binary)
#[command(long_about = "\n
@ -494,11 +500,17 @@ Arguments:
Perf(PerfArgs),
}
impl Default for Subcommand {
fn default() -> Self {
Subcommand::Build { timings: false }
}
}
impl Subcommand {
pub fn kind(&self) -> Kind {
match self {
Subcommand::Bench { .. } => Kind::Bench,
Subcommand::Build => Kind::Build,
Subcommand::Build { .. } => Kind::Build,
Subcommand::Check { .. } => Kind::Check,
Subcommand::Clippy { .. } => Kind::Clippy,
Subcommand::Doc { .. } => Kind::Doc,
@ -626,6 +638,13 @@ impl Subcommand {
}
}
pub fn timings(&self) -> bool {
match *self {
Subcommand::Build { timings, .. } | Subcommand::Check { timings, .. } => timings,
_ => false,
}
}
pub fn vendor_versioned_dirs(&self) -> bool {
match *self {
Subcommand::Vendor { versioned_dirs, .. } => versioned_dirs,

View file

@ -37,14 +37,14 @@ use crate::core::builder;
use crate::core::builder::Kind;
use crate::core::config::{DryRun, LldMode, LlvmLibunwind, TargetSelection, flags};
use crate::utils::exec::{BootstrapCommand, command};
use crate::utils::helpers::{
self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo, symlink_dir,
};
use crate::utils::helpers::{self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo};
mod core;
mod utils;
pub use core::builder::PathSet;
#[cfg(feature = "tracing")]
pub use core::builder::STEP_SPAN_TARGET;
pub use core::config::flags::{Flags, Subcommand};
pub use core::config::{ChangeId, Config};
@ -53,7 +53,9 @@ use tracing::{instrument, span};
pub use utils::change_tracker::{
CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes,
};
pub use utils::helpers::PanicTracker;
pub use utils::helpers::{PanicTracker, symlink_dir};
#[cfg(feature = "tracing")]
pub use utils::tracing::setup_tracing;
use crate::core::build_steps::vendor::VENDOR_DIR;
@ -2005,13 +2007,13 @@ to download LLVM rather than building it.
&self.config.exec_ctx
}
pub fn report_summary(&self, start_time: Instant) {
self.config.exec_ctx.profiler().report_summary(start_time);
pub fn report_summary(&self, path: &Path, start_time: Instant) {
self.config.exec_ctx.profiler().report_summary(path, start_time);
}
#[cfg(feature = "tracing")]
pub fn report_step_graph(self) {
self.step_graph.into_inner().store_to_dot_files();
pub fn report_step_graph(self, directory: &Path) {
self.step_graph.into_inner().store_to_dot_files(directory);
}
}

View file

@ -15,7 +15,6 @@ use std::hash::Hash;
use std::io::{BufWriter, Write};
use std::panic::Location;
use std::path::Path;
use std::process;
use std::process::{
Child, ChildStderr, ChildStdout, Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio,
};
@ -26,10 +25,8 @@ use build_helper::ci::CiEnv;
use build_helper::drop_bomb::DropBomb;
use build_helper::exit;
use crate::PathBuf;
use crate::core::config::DryRun;
#[cfg(feature = "tracing")]
use crate::trace_cmd;
use crate::{PathBuf, t};
/// What should be done when the command fails.
#[derive(Debug, Copy, Clone)]
@ -77,9 +74,17 @@ pub struct CommandFingerprint {
}
impl CommandFingerprint {
#[cfg(feature = "tracing")]
pub(crate) fn program_name(&self) -> String {
Path::new(&self.program)
.file_name()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|| "<unknown command>".to_string())
}
/// Helper method to format both Command and BootstrapCommand as a short execution line,
/// without all the other details (e.g. environment variables).
pub fn format_short_cmd(&self) -> String {
pub(crate) fn format_short_cmd(&self) -> String {
use std::fmt::Write;
let mut cmd = self.program.to_string_lossy().to_string();
@ -121,17 +126,9 @@ impl CommandProfiler {
entry.traces.push(ExecutionTrace::CacheHit);
}
pub fn report_summary(&self, start_time: Instant) {
let pid = process::id();
let filename = format!("bootstrap-profile-{pid}.txt");
let file = match File::create(&filename) {
Ok(f) => f,
Err(e) => {
eprintln!("Failed to create profiler output file: {e}");
return;
}
};
/// Report summary of executed commands file at the specified `path`.
pub fn report_summary(&self, path: &Path, start_time: Instant) {
let file = t!(File::create(path));
let mut writer = BufWriter::new(file);
let stats = self.stats.lock().unwrap();
@ -221,8 +218,6 @@ impl CommandProfiler {
writeln!(writer, "Total cache hits: {total_cache_hits}").unwrap();
writeln!(writer, "Estimated time saved due to cache hits: {total_saved_duration:.2?}")
.unwrap();
println!("Command profiler report saved to {filename}");
}
}
@ -686,9 +681,6 @@ impl ExecutionContext {
) -> DeferredCommand<'a> {
let fingerprint = command.fingerprint();
#[cfg(feature = "tracing")]
let span_guard = trace_cmd!(command);
if let Some(cached_output) = self.command_cache.get(&fingerprint) {
command.mark_as_executed();
self.verbose(|| println!("Cache hit: {command:?}"));
@ -696,6 +688,9 @@ impl ExecutionContext {
return DeferredCommand { state: CommandState::Cached(cached_output) };
}
#[cfg(feature = "tracing")]
let span_guard = crate::utils::tracing::trace_cmd(command);
let created_at = command.get_created_location();
let executed_at = std::panic::Location::caller();
@ -779,7 +774,7 @@ impl ExecutionContext {
}
#[cfg(feature = "tracing")]
let span_guard = trace_cmd!(command);
let span_guard = crate::utils::tracing::trace_cmd(command);
let start_time = Instant::now();
let fingerprint = command.fingerprint();

View file

@ -1,8 +1,10 @@
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use std::io::BufWriter;
use std::path::Path;
use crate::core::builder::{AnyDebug, Step};
use crate::core::builder::{AnyDebug, Step, pretty_step_name};
use crate::t;
/// Records the executed steps and their dependencies in a directed graph,
/// which can then be rendered into a DOT file for visualization.
@ -41,13 +43,7 @@ impl StepGraph {
metadata.get_target()
)
} else {
let type_name = std::any::type_name::<S>();
type_name
.strip_prefix("bootstrap::core::")
.unwrap_or(type_name)
.strip_prefix("build_steps::")
.unwrap_or(type_name)
.to_string()
pretty_step_name::<S>()
};
let node = Node { label, tooltip: node_key.clone() };
@ -80,10 +76,10 @@ impl StepGraph {
}
}
pub fn store_to_dot_files(self) {
pub fn store_to_dot_files(self, directory: &Path) {
for (key, graph) in self.graphs.into_iter() {
let filename = format!("bootstrap-steps{key}.dot");
graph.render(&filename).unwrap();
let filename = directory.join(format!("step-graph{key}.dot"));
t!(graph.render(&filename));
}
}
}
@ -147,7 +143,7 @@ impl DotGraph {
self.key_to_index.get(key).copied()
}
fn render(&self, path: &str) -> std::io::Result<()> {
fn render(&self, path: &Path) -> std::io::Result<()> {
use std::io::Write;
let mut file = BufWriter::new(std::fs::File::create(path)?);

View file

@ -48,17 +48,369 @@ macro_rules! error {
}
}
#[macro_export]
macro_rules! trace_cmd {
($cmd:expr) => {
{
::tracing::span!(
target: "COMMAND",
::tracing::Level::TRACE,
"executing command",
cmd = $cmd.fingerprint().format_short_cmd(),
full_cmd = ?$cmd
).entered()
}
};
#[cfg(feature = "tracing")]
const COMMAND_SPAN_TARGET: &str = "COMMAND";
#[cfg(feature = "tracing")]
pub fn trace_cmd(command: &crate::BootstrapCommand) -> tracing::span::EnteredSpan {
let fingerprint = command.fingerprint();
let location = command.get_created_location();
let location = format!("{}:{}", location.file(), location.line());
tracing::span!(
target: COMMAND_SPAN_TARGET,
tracing::Level::TRACE,
"cmd",
cmd_name = fingerprint.program_name().to_string(),
cmd = fingerprint.format_short_cmd(),
full_cmd = ?command,
location
)
.entered()
}
// # Note on `tracing` usage in bootstrap
//
// Due to the conditional compilation via the `tracing` cargo feature, this means that `tracing`
// usages in bootstrap need to be also gated behind the `tracing` feature:
//
// - `tracing` macros with log levels (`trace!`, `debug!`, `warn!`, `info`, `error`) should not be
// used *directly*. You should use the wrapped `tracing` macros which gate the actual invocations
// behind `feature = "tracing"`.
// - `tracing`'s `#[instrument(..)]` macro will need to be gated like `#![cfg_attr(feature =
// "tracing", instrument(..))]`.
#[cfg(feature = "tracing")]
mod inner {
use std::fmt::Debug;
use std::fs::File;
use std::io::Write;
use std::sync::atomic::Ordering;
use chrono::{DateTime, Utc};
use tracing::field::{Field, Visit};
use tracing::{Event, Id, Level, Subscriber};
use tracing_subscriber::layer::{Context, SubscriberExt};
use tracing_subscriber::registry::{LookupSpan, SpanRef};
use tracing_subscriber::{EnvFilter, Layer};
use crate::STEP_SPAN_TARGET;
use crate::utils::tracing::COMMAND_SPAN_TARGET;
pub fn setup_tracing(env_name: &str) -> TracingGuard {
let filter = EnvFilter::from_env(env_name);
let registry = tracing_subscriber::registry().with(filter).with(TracingPrinter::default());
// When we're creating this layer, we do not yet know the location of the tracing output
// directory, because it is stored in the output directory determined after Config is parsed,
// but we already want to make tracing calls during (and before) config parsing.
// So we store the output into a temporary file, and then move it to the tracing directory
// before bootstrap ends.
let tempdir = tempfile::TempDir::new().expect("Cannot create temporary directory");
let chrome_tracing_path = tempdir.path().join("bootstrap-trace.json");
let file = std::io::BufWriter::new(File::create(&chrome_tracing_path).unwrap());
let chrome_layer = tracing_chrome::ChromeLayerBuilder::new()
.writer(file)
.include_args(true)
.name_fn(Box::new(|event_or_span| match event_or_span {
tracing_chrome::EventOrSpan::Event(e) => e.metadata().name().to_string(),
tracing_chrome::EventOrSpan::Span(s) => {
if s.metadata().target() == STEP_SPAN_TARGET
&& let Some(extension) = s.extensions().get::<StepNameExtension>()
{
extension.0.clone()
} else if s.metadata().target() == COMMAND_SPAN_TARGET
&& let Some(extension) = s.extensions().get::<CommandNameExtension>()
{
extension.0.clone()
} else {
s.metadata().name().to_string()
}
}
}));
let (chrome_layer, guard) = chrome_layer.build();
tracing::subscriber::set_global_default(registry.with(chrome_layer)).unwrap();
TracingGuard { guard, _tempdir: tempdir, chrome_tracing_path }
}
pub struct TracingGuard {
guard: tracing_chrome::FlushGuard,
_tempdir: tempfile::TempDir,
chrome_tracing_path: std::path::PathBuf,
}
impl TracingGuard {
pub fn copy_to_dir(self, dir: &std::path::Path) {
drop(self.guard);
std::fs::rename(&self.chrome_tracing_path, dir.join("chrome-trace.json")).unwrap();
}
}
/// Visitor that extracts both known and unknown field values from events and spans.
#[derive(Default)]
struct FieldValues {
/// Main event message
message: Option<String>,
/// Name of a recorded psna
step_name: Option<String>,
/// Short name of an executed command
cmd_name: Option<String>,
/// The rest of arbitrary event/span fields
fields: Vec<(&'static str, String)>,
}
impl Visit for FieldValues {
/// Record fields if possible using `record_str`, to avoid rendering simple strings with
/// their `Debug` representation, which adds extra quotes.
fn record_str(&mut self, field: &Field, value: &str) {
match field.name() {
"step_name" => {
self.step_name = Some(value.to_string());
}
"cmd_name" => {
self.cmd_name = Some(value.to_string());
}
name => {
self.fields.push((name, value.to_string()));
}
}
}
fn record_debug(&mut self, field: &Field, value: &dyn Debug) {
let formatted = format!("{value:?}");
match field.name() {
"message" => {
self.message = Some(formatted);
}
name => {
self.fields.push((name, formatted));
}
}
}
}
#[derive(Copy, Clone)]
enum SpanAction {
Enter,
}
/// Holds the name of a step span, stored in `tracing_subscriber`'s extensions.
struct StepNameExtension(String);
/// Holds the name of a command span, stored in `tracing_subscriber`'s extensions.
struct CommandNameExtension(String);
#[derive(Default)]
struct TracingPrinter {
indent: std::sync::atomic::AtomicU32,
span_values: std::sync::Mutex<std::collections::HashMap<tracing::Id, FieldValues>>,
}
impl TracingPrinter {
fn format_header<W: Write>(
&self,
writer: &mut W,
time: DateTime<Utc>,
level: &Level,
) -> std::io::Result<()> {
// Use a fixed-width timestamp without date, that shouldn't be very important
let timestamp = time.format("%H:%M:%S.%3f");
write!(writer, "{timestamp} ")?;
// Make sure that levels are aligned to the same number of characters, in order not to
// break the layout
write!(writer, "{level:>5} ")?;
write!(writer, "{}", " ".repeat(self.indent.load(Ordering::Relaxed) as usize))
}
fn write_event<W: Write>(&self, writer: &mut W, event: &Event<'_>) -> std::io::Result<()> {
let now = Utc::now();
self.format_header(writer, now, event.metadata().level())?;
let mut field_values = FieldValues::default();
event.record(&mut field_values);
if let Some(msg) = &field_values.message {
write!(writer, "{msg}")?;
}
if !field_values.fields.is_empty() {
if field_values.message.is_some() {
write!(writer, " ")?;
}
write!(writer, "[")?;
for (index, (name, value)) in field_values.fields.iter().enumerate() {
write!(writer, "{name} = {value}")?;
if index < field_values.fields.len() - 1 {
write!(writer, ", ")?;
}
}
write!(writer, "]")?;
}
write_location(writer, event.metadata())?;
writeln!(writer)?;
Ok(())
}
fn write_span<W: Write, S>(
&self,
writer: &mut W,
span: SpanRef<'_, S>,
field_values: Option<&FieldValues>,
action: SpanAction,
) -> std::io::Result<()>
where
S: for<'lookup> LookupSpan<'lookup>,
{
let now = Utc::now();
self.format_header(writer, now, span.metadata().level())?;
match action {
SpanAction::Enter => {
write!(writer, "> ")?;
}
}
fn write_fields<'a, I: IntoIterator<Item = &'a (&'a str, String)>, W: Write>(
writer: &mut W,
iter: I,
) -> std::io::Result<()> {
let items = iter.into_iter().collect::<Vec<_>>();
if !items.is_empty() {
write!(writer, " [")?;
for (index, (name, value)) in items.iter().enumerate() {
write!(writer, "{name} = {value}")?;
if index < items.len() - 1 {
write!(writer, ", ")?;
}
}
write!(writer, "]")?;
}
Ok(())
}
// We handle steps specially. We instrument them dynamically in `Builder::ensure`,
// and we want to have custom name for each step span. But tracing doesn't allow setting
// dynamic span names. So we detect step spans here and override their name.
match span.metadata().target() {
// Executed step
STEP_SPAN_TARGET => {
let name =
field_values.and_then(|v| v.step_name.as_deref()).unwrap_or(span.name());
write!(writer, "{name}")?;
// There should be only one more field called `args`
if let Some(values) = field_values {
let field = &values.fields[0];
write!(writer, " {{{}}}", field.1)?;
}
write_location(writer, span.metadata())?;
}
// Executed command
COMMAND_SPAN_TARGET => {
write!(writer, "{}", span.name())?;
if let Some(values) = field_values {
write_fields(
writer,
values.fields.iter().filter(|(name, _)| *name != "location"),
)?;
write!(
writer,
" ({})",
values.fields.iter().find(|(name, _)| *name == "location").unwrap().1
)?;
}
}
// Other span
_ => {
write!(writer, "{}", span.name())?;
if let Some(values) = field_values {
write_fields(writer, values.fields.iter())?;
}
write_location(writer, span.metadata())?;
}
}
writeln!(writer)?;
Ok(())
}
}
fn write_location<W: Write>(
writer: &mut W,
metadata: &'static tracing::Metadata<'static>,
) -> std::io::Result<()> {
use std::path::{Path, PathBuf};
if let Some(filename) = metadata.file() {
// Keep only the module name and file name to make it shorter
let filename: PathBuf = Path::new(filename)
.components()
// Take last two path components
.rev()
.take(2)
.collect::<Vec<_>>()
.into_iter()
.rev()
.collect();
write!(writer, " ({}", filename.display())?;
if let Some(line) = metadata.line() {
write!(writer, ":{line}")?;
}
write!(writer, ")")?;
}
Ok(())
}
impl<S> Layer<S> for TracingPrinter
where
S: Subscriber,
S: for<'lookup> LookupSpan<'lookup>,
{
fn on_new_span(&self, attrs: &tracing::span::Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
// Record value of span fields
// Note that we do not implement changing values of span fields after they are created.
// For that we would also need to implement the `on_record` method
let mut field_values = FieldValues::default();
attrs.record(&mut field_values);
// We need to propagate the actual name of the span to the Chrome layer below, because
// it cannot access field values. We do that through extensions.
if attrs.metadata().target() == STEP_SPAN_TARGET
&& let Some(step_name) = field_values.step_name.clone()
{
ctx.span(id).unwrap().extensions_mut().insert(StepNameExtension(step_name));
} else if attrs.metadata().target() == COMMAND_SPAN_TARGET
&& let Some(cmd_name) = field_values.cmd_name.clone()
{
ctx.span(id).unwrap().extensions_mut().insert(CommandNameExtension(cmd_name));
}
self.span_values.lock().unwrap().insert(id.clone(), field_values);
}
fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
let mut writer = std::io::stderr().lock();
self.write_event(&mut writer, event).unwrap();
}
fn on_enter(&self, id: &Id, ctx: Context<'_, S>) {
if let Some(span) = ctx.span(id) {
let mut writer = std::io::stderr().lock();
let values = self.span_values.lock().unwrap();
let values = values.get(id);
self.write_span(&mut writer, span, values, SpanAction::Enter).unwrap();
}
self.indent.fetch_add(1, Ordering::Relaxed);
}
fn on_exit(&self, _id: &Id, _ctx: Context<'_, S>) {
self.indent.fetch_sub(1, Ordering::Relaxed);
}
}
}
#[cfg(feature = "tracing")]
pub use inner::setup_tracing;

View file

@ -172,9 +172,9 @@ unsafe Rust. It's also sometimes called "the 'nomicon."
[The Unstable Book](unstable-book/index.html) has documentation for unstable
features.
### The `rustc` Contribution Guide
### The `rustc` Development Guide
[The `rustc` Guide](https://rustc-dev-guide.rust-lang.org/)
[The `rustc-dev-guide`](https://rustc-dev-guide.rust-lang.org/)
documents how the compiler works and how to contribute to it. This is useful if
you want to build or modify the Rust compiler from source (e.g. to target
something non-standard).

View file

@ -1,120 +1,100 @@
# Debugging bootstrap
There are two main ways to debug bootstrap itself. The first is through println logging, and the second is through the `tracing` feature.
> FIXME: this section should be expanded
There are two main ways of debugging (and profiling bootstrap). The first is through println logging, and the second is through the `tracing` feature.
## `println` logging
Bootstrap has extensive unstructured logging. Most of it is gated behind the `--verbose` flag (pass `-vv` for even more detail).
If you want to know which `Step` ran a command, you could invoke bootstrap like so:
If you want to see verbose output of executed Cargo commands and other kinds of detailed logs, pass `-v` or `-vv` when invoking bootstrap. Note that the logs are unstructured and may be overwhelming.
```
$ ./x dist rustc --dry-run -vv
learning about cargo
running: RUSTC_BOOTSTRAP="1" "/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "metadata" "--format-version" "1" "--no-deps" "--manifest-path" "/home/jyn/src/rust2/Cargo.toml" (failure_mode=Exit) (created at src/bootstrap/src/core/metadata.rs:81:25, executed at src/bootstrap/src/core/metadata.rs:92:50)
running: RUSTC_BOOTSTRAP="1" "/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "metadata" "--format-version" "1" "--no-deps" "--manifest-path" "/home/jyn/src/rust2/library/Cargo.toml" (failure_mode=Exit) (created at src/bootstrap/src/core/metadata.rs:81:25, executed at src/bootstrap/src/core/metadata.rs:92:50)
> Assemble { target_compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu } }
> Libdir { compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu }, target: x86_64-unknown-linux-gnu }
> Sysroot { compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu }, force_recompile: false }
Removing sysroot /home/jyn/src/rust2/build/tmp-dry-run/x86_64-unknown-linux-gnu/stage1 to avoid caching bugs
< Sysroot { compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu }, force_recompile: false }
< Libdir { compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu }, target: x86_64-unknown-linux-gnu }
...
```
This will go through all the recursive dependency calculations, where `Step`s internally call `builder.ensure()`, without actually running cargo or the compiler.
In some cases, even this may not be enough logging (if so, please add more!). In that case, you can omit `--dry-run`, which will show the normal output inline with the debug logging:
```
c Sysroot { compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu }, force_recompile: false }
using sysroot /home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage0-sysroot
Building stage0 library artifacts (x86_64-unknown-linux-gnu)
running: cd "/home/jyn/src/rust2" && env ... RUSTC_VERBOSE="2" RUSTC_WRAPPER="/home/jyn/src/rust2/build/bootstrap/debug/rustc" "/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "build" "--target" "x86_64-unknown-linux-gnu" "-Zbinary-dep-depinfo" "-Zroot-dir=/home/jyn/src/rust2" "-v" "-v" "--manifest-path" "/home/jyn/src/rust2/library/sysroot/Cargo.toml" "--message-format" "json-render-diagnostics"
0.293440230s INFO prepare_target{force=false package_id=sysroot v0.0.0 (/home/jyn/src/rust2/library/sysroot) target="sysroot"}: cargo::core::compiler::fingerprint: fingerprint error for sysroot v0.0.0 (/home/jyn/src/rust2/library/sysroot)/Build/TargetInner { name_inferred: true, ..: lib_target("sysroot", ["lib"], "/home/jyn/src/rust2/library/sysroot/src/lib.rs", Edition2021) }
...
```
In most cases this should not be necessary.
TODO: we should convert all this to structured logging so it's easier to control precisely.
## `tracing` in bootstrap
Bootstrap has conditional [`tracing`][tracing] setup to provide structured logging.
Bootstrap has a conditional `tracing` feature, which provides the following features:
- It enables structured logging using [`tracing`][tracing] events and spans.
- It generates a [Chrome trace file] that can be used to visualize the hierarchy and durations of executed steps and commands.
- You can open the generated `chrome-trace.json` file using Chrome, on the `chrome://tracing` tab, or e.g. using [Perfetto].
- It generates [GraphViz] graphs that visualize the dependencies between executed steps.
- You can open the generated `step-graph-*.dot` file using e.g. [xdot] to visualize the step graph, or use e.g. `dot -Tsvg` to convert the GraphViz file to an SVG file.
- It generates a command execution summary, which shows which commands were executed, how many of their executions were cached, and what commands were the slowest to run.
- The generated `command-stats.txt` file is in a simple human-readable format.
The structured logs will be written to standard error output (`stderr`), while the other outputs will be stored in files in the `<build-dir>/bootstrap-trace/<pid>` directory. For convenience, bootstrap will also create a symlink to the latest generated trace output directory at `<build-dir>/bootstrap-trace/latest`.
> Note that if you execute bootstrap with `--dry-run`, the tracing output directory might change. Bootstrap will always print a path where the tracing output files were stored at the end of its execution.
[tracing]: https://docs.rs/tracing/0.1.41/tracing/index.html
[Chrome trace file]: https://www.chromium.org/developers/how-tos/trace-event-profiling-tool/
[Perfetto]: https://ui.perfetto.dev/
[GraphViz]: https://graphviz.org/doc/info/lang.html
[xdot]: https://github.com/jrfonseca/xdot.py
### Enabling `tracing` output
Bootstrap will conditionally build `tracing` support and enable `tracing` output if the `BOOTSTRAP_TRACING` env var is set.
To enable the conditional `tracing` feature, run bootstrap with the `BOOTSTRAP_TRACING` environment variable.
#### Basic usage
Example basic usage[^just-trace]:
[^just-trace]: It is not recommended to use *just* `BOOTSTRAP_TRACING=TRACE` because that will dump *everything* at `TRACE` level, including logs intentionally gated behind custom targets as they are too verbose even for `TRACE` level by default.
[tracing_subscriber filter]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html
```bash
$ BOOTSTRAP_TRACING=bootstrap=TRACE ./x build library --stage 1
$ BOOTSTRAP_TRACING=trace ./x build library --stage 1
```
Example output[^unstable]:
```
$ BOOTSTRAP_TRACING=bootstrap=TRACE ./x check src/bootstrap/
$ BOOTSTRAP_TRACING=trace ./x build library --stage 1 --dry-run
Building bootstrap
Compiling bootstrap v0.0.0 (/home/joe/repos/rust/src/bootstrap)
Finished `dev` profile [unoptimized] target(s) in 2.74s
DEBUG bootstrap parsing flags
bootstrap::core::config::flags::Flags::parse args=["check", "src/bootstrap/"]
DEBUG bootstrap parsing config based on flags
DEBUG bootstrap creating new build based on config
bootstrap::Build::build
TRACE bootstrap setting up job management
TRACE bootstrap downloading rustfmt early
bootstrap::handling hardcoded subcommands (Format, Suggest, Perf)
DEBUG bootstrap not a hardcoded subcommand; returning to normal handling, cmd=Check { all_targets: false }
DEBUG bootstrap handling subcommand normally
bootstrap::executing real run
bootstrap::(1) executing dry-run sanity-check
bootstrap::(2) executing actual run
Checking stage0 library artifacts (x86_64-unknown-linux-gnu)
Finished `release` profile [optimized + debuginfo] target(s) in 0.04s
Checking stage0 compiler artifacts {rustc-main, rustc_abi, rustc_arena, rustc_ast, rustc_ast_ir, rustc_ast_lowering, rustc_ast_passes, rustc_ast_pretty, rustc_attr_data_structures, rustc_attr_parsing, rustc_baked_icu_data, rustc_borrowck, rustc_builtin_macros, rustc_codegen_llvm, rustc_codegen_ssa, rustc_const_eval, rustc_data_structures, rustc_driver, rustc_driver_impl, rustc_error_codes, rustc_error_messages, rustc_errors, rustc_expand, rustc_feature, rustc_fluent_macro, rustc_fs_util, rustc_graphviz, rustc_hir, rustc_hir_analysis, rustc_hir_pretty, rustc_hir_typeck, rustc_incremental, rustc_index, rustc_index_macros, rustc_infer, rustc_interface, rustc_lexer, rustc_lint, rustc_lint_defs, rustc_llvm, rustc_log, rustc_macros, rustc_metadata, rustc_middle, rustc_mir_build, rustc_mir_dataflow, rustc_mir_transform, rustc_monomorphize, rustc_next_trait_solver, rustc_parse, rustc_parse_format, rustc_passes, rustc_pattern_analysis, rustc_privacy, rustc_query_impl, rustc_query_system, rustc_resolve, rustc_sanitizers, rustc_serialize, rustc_session, rustc_smir, rustc_span, rustc_symbol_mangling, rustc_target, rustc_trait_selection, rustc_traits, rustc_transmute, rustc_ty_utils, rustc_type_ir, rustc_type_ir_macros, stable_mir} (x86_64-unknown-linux-gnu)
Finished `release` profile [optimized + debuginfo] target(s) in 0.23s
Checking stage0 bootstrap artifacts (x86_64-unknown-linux-gnu)
Checking bootstrap v0.0.0 (/home/joe/repos/rust/src/bootstrap)
Finished `release` profile [optimized + debuginfo] target(s) in 0.64s
DEBUG bootstrap checking for postponed test failures from `test --no-fail-fast`
Build completed successfully in 0:00:08
```
#### Controlling tracing output
The env var `BOOTSTRAP_TRACING` accepts a [`tracing` env-filter][tracing-env-filter].
There are two orthogonal ways to control which kind of tracing logs you want:
1. You can specify the log **level**, e.g. `DEBUG` or `TRACE`.
2. You can also control the log **target**, e.g. `bootstrap` or `bootstrap::core::config` vs custom targets like `CONFIG_HANDLING`.
- Custom targets are used to limit what is output when `BOOTSTRAP_TRACING=bootstrap=TRACE` is used, as they can be too verbose even for `TRACE` level by default. Currently used custom targets:
- `CONFIG_HANDLING`
The `TRACE` filter will enable *all* `trace` level or less verbose level tracing output.
You can of course combine them (custom target logs are typically gated behind `TRACE` log level additionally):
```bash
$ BOOTSTRAP_TRACING=CONFIG_HANDLING=TRACE ./x build library --stage 1
Finished `dev` profile [unoptimized] target(s) in 0.05s
15:56:52.477 INFO > tool::LibcxxVersionTool {target: x86_64-unknown-linux-gnu} (builder/mod.rs:1715)
15:56:52.575 INFO > compile::Assemble {target_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }} (builder/mod.rs:1715)
15:56:52.575 INFO > tool::Compiletest {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu} (builder/mod.rs:1715)
15:56:52.576 INFO > tool::ToolBuild {build_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu, tool: "compiletest", path: "src/tools/compiletest", mode: ToolBootstrap, source_type: InTree, extra_features: [], allow_features: "internal_output_capture", cargo_args: [], artifact_kind: Binary} (builder/mod.rs:1715)
15:56:52.576 INFO > builder::Libdir {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu} (builder/mod.rs:1715)
15:56:52.576 INFO > compile::Sysroot {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, force_recompile: false} (builder/mod.rs:1715)
15:56:52.578 INFO > compile::Assemble {target_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }} (builder/mod.rs:1715)
15:56:52.578 INFO > tool::Compiletest {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu} (builder/mod.rs:1715)
15:56:52.578 INFO > tool::ToolBuild {build_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu, tool: "compiletest", path: "src/tools/compiletest", mode: ToolBootstrap, source_type: InTree, extra_features: [], allow_features: "internal_output_capture", cargo_args: [], artifact_kind: Binary} (builder/mod.rs:1715)
15:56:52.578 INFO > builder::Libdir {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu} (builder/mod.rs:1715)
15:56:52.578 INFO > compile::Sysroot {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, force_recompile: false} (builder/mod.rs:1715)
Finished `release` profile [optimized] target(s) in 0.11s
Tracing/profiling output has been written to <src-root>/build/bootstrap-trace/latest
Build completed successfully in 0:00:00
```
[^unstable]: This output is always subject to further changes.
#### Controlling tracing output
The environment variable `BOOTSTRAP_TRACING` accepts a [`tracing_subscriber` filter][tracing-env-filter]. If you set `BOOTSTRAP_TRACING=trace`, you will enable all logs, but that can be overwhelming. You can thus use the filter to reduce the amount of data logged.
There are two orthogonal ways to control which kind of tracing logs you want:
1. You can specify the log **level**, e.g. `debug` or `trace`.
- If you select a level, all events/spans with an equal or higher priority level will be shown.
2. You can also control the log **target**, e.g. `bootstrap` or `bootstrap::core::config` or a custom target like `CONFIG_HANDLING` or `STEP`.
- Custom targets are used to limit what kinds of spans you are interested in, as the `BOOTSTRAP_TRACING=trace` output can be quite verbose. Currently, you can use the following custom targets:
- `CONFIG_HANDLING`: show spans related to config handling
- `STEP`: show all executed steps. Note that executed commands have `info` event level.
- `COMMAND`: show all executed commands. Note that executed commands have `trace` event level.
You can of course combine them (custom target logs are typically gated behind `TRACE` log level additionally):
```bash
$ BOOTSTRAP_TRACING=CONFIG_HANDLING=trace,STEP=info,COMMAND=trace ./x build library --stage 1
```
[tracing-env-filter]: https://docs.rs/tracing-subscriber/0.3.19/tracing_subscriber/filter/struct.EnvFilter.html
Note that the level that you specify using `BOOTSTRAP_TRACING` also has an effect on the spans that will be recorded in the Chrome trace file.
##### FIXME(#96176): specific tracing for `compiler()` vs `compiler_for()`
The additional targets `COMPILER` and `COMPILER_FOR` are used to help trace what
@ -123,12 +103,6 @@ if [#96176][cleanup-compiler-for] is resolved.
[cleanup-compiler-for]: https://github.com/rust-lang/rust/issues/96176
### Rendering step graph
When you run bootstrap with the `BOOTSTRAP_TRACING` environment variable configured, bootstrap will automatically output a DOT file that shows all executed steps and their dependencies. The files will have a prefix `bootstrap-steps`. You can use e.g. `xdot` to visualize the file or e.g. `dot -Tsvg` to convert the DOT file to a SVG file.
A separate DOT file will be outputted for dry-run and non-dry-run execution.
### Using `tracing` in bootstrap
Both `tracing::*` macros and the `tracing::instrument` proc-macro attribute need to be gated behind `tracing` feature. Examples:
@ -149,15 +123,6 @@ impl Step for Foo {
todo!()
}
#[cfg_attr(
feature = "tracing",
instrument(
level = "trace",
name = "Foo::run",
skip_all,
fields(compiler = ?builder.compiler),
),
)]
fn run(self, builder: &Builder<'_>) -> Self::Output {
trace!(?run, "entered Foo::run");
@ -172,21 +137,6 @@ For `#[instrument]`, it's recommended to:
- Explicitly pick an instrumentation name via `name = ".."` to distinguish between e.g. `run` of different steps.
- Take care to not cause diverging behavior via tracing, e.g. building extra things only when tracing infra is enabled.
### Profiling bootstrap
You can set the `BOOTSTRAP_PROFILE=1` environment variable to enable command execution profiling during bootstrap. This generates:
* A Chrome trace file (for visualization in `chrome://tracing` or [Perfetto](https://ui.perfetto.dev)) if tracing is enabled via `BOOTSTRAP_TRACING=COMMAND=trace`
* A plain-text summary file, `bootstrap-profile-{pid}.txt`, listing all commands sorted by execution time (slowest first), along with cache hits and working directories
Note: the `.txt` report is always generated when `BOOTSTRAP_PROFILE=1` is set — tracing is not required.
Example usage:
```bash
$ BOOTSTRAP_PROFILE=1 BOOTSTRAP_TRACING=COMMAND=trace ./x build library
```
### rust-analyzer integration?
Unfortunately, because bootstrap is a `rust-analyzer.linkedProjects`, you can't ask r-a to check/build bootstrap itself with `tracing` feature enabled to get relevant completions, due to lack of support as described in <https://github.com/rust-lang/rust-analyzer/issues/8521>.

View file

@ -97,6 +97,7 @@ complete -c x -n "__fish_x_using_subcommand build" -l llvm-profile-use -d 'use P
complete -c x -n "__fish_x_using_subcommand build" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
complete -c x -n "__fish_x_using_subcommand build" -l set -d 'override options in bootstrap.toml' -r -f
complete -c x -n "__fish_x_using_subcommand build" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}"
complete -c x -n "__fish_x_using_subcommand build" -l timings -d 'Pass `--timings` to Cargo to get crate build timings'
complete -c x -n "__fish_x_using_subcommand build" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
complete -c x -n "__fish_x_using_subcommand build" -s i -l incremental -d 'use incremental compilation'
complete -c x -n "__fish_x_using_subcommand build" -l include-default-paths -d 'include default paths in addition to the provided ones'
@ -133,6 +134,7 @@ complete -c x -n "__fish_x_using_subcommand check" -l reproducible-artifact -d '
complete -c x -n "__fish_x_using_subcommand check" -l set -d 'override options in bootstrap.toml' -r -f
complete -c x -n "__fish_x_using_subcommand check" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}"
complete -c x -n "__fish_x_using_subcommand check" -l all-targets -d 'Check all targets'
complete -c x -n "__fish_x_using_subcommand check" -l timings -d 'Pass `--timings` to Cargo to get crate build timings'
complete -c x -n "__fish_x_using_subcommand check" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
complete -c x -n "__fish_x_using_subcommand check" -s i -l incremental -d 'use incremental compilation'
complete -c x -n "__fish_x_using_subcommand check" -l include-default-paths -d 'include default paths in addition to the provided ones'

View file

@ -102,6 +102,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
[CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
[CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml')
[CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not')
[CompletionResult]::new('--timings', '--timings', [CompletionResultType]::ParameterName, 'Pass `--timings` to Cargo to get crate build timings')
[CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
[CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')
@ -145,6 +146,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
[CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml')
[CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not')
[CompletionResult]::new('--all-targets', '--all-targets', [CompletionResultType]::ParameterName, 'Check all targets')
[CompletionResult]::new('--timings', '--timings', [CompletionResultType]::ParameterName, 'Pass `--timings` to Cargo to get crate build timings')
[CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
[CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')

View file

@ -97,6 +97,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand build" -l llvm-profile-use -d
complete -c x.py -n "__fish_x.py_using_subcommand build" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
complete -c x.py -n "__fish_x.py_using_subcommand build" -l set -d 'override options in bootstrap.toml' -r -f
complete -c x.py -n "__fish_x.py_using_subcommand build" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}"
complete -c x.py -n "__fish_x.py_using_subcommand build" -l timings -d 'Pass `--timings` to Cargo to get crate build timings'
complete -c x.py -n "__fish_x.py_using_subcommand build" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
complete -c x.py -n "__fish_x.py_using_subcommand build" -s i -l incremental -d 'use incremental compilation'
complete -c x.py -n "__fish_x.py_using_subcommand build" -l include-default-paths -d 'include default paths in addition to the provided ones'
@ -133,6 +134,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand check" -l reproducible-artifac
complete -c x.py -n "__fish_x.py_using_subcommand check" -l set -d 'override options in bootstrap.toml' -r -f
complete -c x.py -n "__fish_x.py_using_subcommand check" -l ci -d 'Make bootstrap to behave as it\'s running on the CI environment or not' -r -f -a "{true\t'',false\t''}"
complete -c x.py -n "__fish_x.py_using_subcommand check" -l all-targets -d 'Check all targets'
complete -c x.py -n "__fish_x.py_using_subcommand check" -l timings -d 'Pass `--timings` to Cargo to get crate build timings'
complete -c x.py -n "__fish_x.py_using_subcommand check" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
complete -c x.py -n "__fish_x.py_using_subcommand check" -s i -l incremental -d 'use incremental compilation'
complete -c x.py -n "__fish_x.py_using_subcommand check" -l include-default-paths -d 'include default paths in addition to the provided ones'

View file

@ -102,6 +102,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
[CompletionResult]::new('--reproducible-artifact', '--reproducible-artifact', [CompletionResultType]::ParameterName, 'Additional reproducible artifacts that should be added to the reproducible artifacts archive')
[CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml')
[CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not')
[CompletionResult]::new('--timings', '--timings', [CompletionResultType]::ParameterName, 'Pass `--timings` to Cargo to get crate build timings')
[CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
[CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')
@ -145,6 +146,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
[CompletionResult]::new('--set', '--set', [CompletionResultType]::ParameterName, 'override options in bootstrap.toml')
[CompletionResult]::new('--ci', '--ci', [CompletionResultType]::ParameterName, 'Make bootstrap to behave as it''s running on the CI environment or not')
[CompletionResult]::new('--all-targets', '--all-targets', [CompletionResultType]::ParameterName, 'Check all targets')
[CompletionResult]::new('--timings', '--timings', [CompletionResultType]::ParameterName, 'Pass `--timings` to Cargo to get crate build timings')
[CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
[CompletionResult]::new('--verbose', '--verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)')
[CompletionResult]::new('-i', '-i', [CompletionResultType]::ParameterName, 'use incremental compilation')

View file

@ -458,7 +458,7 @@ _x.py() {
return 0
;;
x.py__build)
opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
opts="-v -i -j -h --timings --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@ -644,7 +644,7 @@ _x.py() {
return 0
;;
x.py__check)
opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
opts="-v -i -j -h --all-targets --timings --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0

View file

@ -90,6 +90,7 @@ _arguments "${_arguments_options[@]}" : \
'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \
'*--set=[override options in bootstrap.toml]:section.option=value:' \
'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \
'--timings[Pass \`--timings\` to Cargo to get crate build timings]' \
'*-v[use verbose output (-vv for very verbose)]' \
'*--verbose[use verbose output (-vv for very verbose)]' \
'-i[use incremental compilation]' \
@ -135,6 +136,7 @@ _arguments "${_arguments_options[@]}" : \
'*--set=[override options in bootstrap.toml]:section.option=value:' \
'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \
'--all-targets[Check all targets]' \
'--timings[Pass \`--timings\` to Cargo to get crate build timings]' \
'*-v[use verbose output (-vv for very verbose)]' \
'*--verbose[use verbose output (-vv for very verbose)]' \
'-i[use incremental compilation]' \

View file

@ -458,7 +458,7 @@ _x() {
return 0
;;
x__build)
opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
opts="-v -i -j -h --timings --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@ -644,7 +644,7 @@ _x() {
return 0
;;
x__check)
opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
opts="-v -i -j -h --all-targets --timings --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --dump-bootstrap-shims --stage --keep-stage --keep-stage-std --src --jobs --warnings --json-output --compile-time-deps --color --bypass-bootstrap-lock --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --skip-stage0-validation --reproducible-artifact --set --ci --skip-std-check-if-no-download-rustc --help [PATHS]... [ARGS]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0

View file

@ -90,6 +90,7 @@ _arguments "${_arguments_options[@]}" : \
'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT:_default' \
'*--set=[override options in bootstrap.toml]:section.option=value:' \
'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \
'--timings[Pass \`--timings\` to Cargo to get crate build timings]' \
'*-v[use verbose output (-vv for very verbose)]' \
'*--verbose[use verbose output (-vv for very verbose)]' \
'-i[use incremental compilation]' \
@ -135,6 +136,7 @@ _arguments "${_arguments_options[@]}" : \
'*--set=[override options in bootstrap.toml]:section.option=value:' \
'--ci=[Make bootstrap to behave as it'\''s running on the CI environment or not]:bool:(true false)' \
'--all-targets[Check all targets]' \
'--timings[Pass \`--timings\` to Cargo to get crate build timings]' \
'*-v[use verbose output (-vv for very verbose)]' \
'*--verbose[use verbose output (-vv for very verbose)]' \
'-i[use incremental compilation]' \

View file

@ -10,7 +10,7 @@ LL | Box::new(|| x)
| |
| captured by this `Fn` closure
|
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
help: consider cloning the value if the performance cost is acceptable
|
LL | Box::new(|| x.clone())

View file

@ -12,7 +12,7 @@ LL | let _h = to_fn_once(move || -> isize { *bar });
| |
| `bar` is moved here
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/borrowck-move-by-capture.rs:3:37
|
LL | fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }

View file

@ -13,7 +13,7 @@ LL |
LL | self.b;
| ^^^^^^ `self.b` is moved here
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/issue-103624.rs:7:36
|
LL | async fn spawn_blocking<T>(f: impl (Fn() -> T) + Send + Sync + 'static) -> T {

View file

@ -10,7 +10,7 @@ LL |
LL | let _foo: String = val;
| ^^^ move occurs because `val` has type `String`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/issue-87456-point-to-closure.rs:3:24
|
LL | fn take_mut(_val: impl FnMut()) {}

View file

@ -10,7 +10,7 @@ LL | y.into_iter();
| |
| move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:5:28
|
LL | fn call<F>(f: F) where F : Fn() {

View file

@ -1,5 +1,6 @@
//@ dont-require-annotations: NOTE
//@ normalize-stderr: "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)"
//@ normalize-stderr: "([[:xdigit:]]{2}\s){4}(__\s){4}\s+│\s+([?|\.]){4}\W{4}" -> "HEX_DUMP"
type Field1 = i32;
type Field2 = f32;

View file

@ -1,21 +1,21 @@
error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
--> $DIR/union-const-eval-field.rs:29:37
--> $DIR/union-const-eval-field.rs:30:37
|
LL | const FIELD3: Field3 = unsafe { UNION.field3 };
| ^^^^^^^^^^^^ evaluation of `read_field3::FIELD3` failed here
|
= note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
00 00 80 3f __ __ __ __ │ ...?░░░░
HEX_DUMP
}
note: erroneous constant encountered
--> $DIR/union-const-eval-field.rs:31:5
--> $DIR/union-const-eval-field.rs:32:5
|
LL | FIELD3
| ^^^^^^
note: erroneous constant encountered
--> $DIR/union-const-eval-field.rs:31:5
--> $DIR/union-const-eval-field.rs:32:5
|
LL | FIELD3
| ^^^^^^

View file

@ -1,3 +1,4 @@
//@ normalize-stderr: "[[:xdigit:]]{2} __ ([[:xdigit:]]{2}\s){2}" -> "HEX_DUMP"
#![feature(core_intrinsics)]
const RAW_EQ_PADDING: bool = unsafe {

View file

@ -1,15 +1,15 @@
error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory
--> $DIR/intrinsic-raw_eq-const-bad.rs:4:5
--> $DIR/intrinsic-raw_eq-const-bad.rs:5:5
|
LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_PADDING` failed here
|
= note: the raw bytes of the constant (size: 4, align: 2) {
01 __ 02 00 │ .░..
HEX_DUMP │ .░..
}
error[E0080]: unable to turn pointer into integer
--> $DIR/intrinsic-raw_eq-const-bad.rs:9:5
--> $DIR/intrinsic-raw_eq-const-bad.rs:10:5
|
LL | std::intrinsics::raw_eq(&(&0), &(&1))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_PTR` failed here
@ -18,7 +18,7 @@ LL | std::intrinsics::raw_eq(&(&0), &(&1))
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
error[E0080]: accessing memory with alignment 1, but alignment 4 is required
--> $DIR/intrinsic-raw_eq-const-bad.rs:16:5
--> $DIR/intrinsic-raw_eq-const-bad.rs:17:5
|
LL | std::intrinsics::raw_eq(aref, aref)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `RAW_EQ_NOT_ALIGNED` failed here

View file

@ -10,7 +10,7 @@ LL | id(Box::new(|| *v))
| |
| captured by this `FnMut` closure
|
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
help: if `T` implemented `Clone`, you could clone the value
--> $DIR/issue-4335.rs:5:10
|

View file

@ -8,10 +8,42 @@ fn print() {
});
}
fn arm_rhs_must_be_in_braces() -> i32 {
fn print_2() {
println!(cfg_select! {
unix => "unix",
_ => "not unix",
});
}
fn arm_rhs_expr_1() -> i32 {
cfg_select! {
true => 1
//~^ ERROR: expected `{`, found `1`
}
}
fn arm_rhs_expr_2() -> i32 {
cfg_select! {
true => 1,
false => 2
}
}
fn arm_rhs_expr_3() -> i32 {
cfg_select! {
true => 1,
false => 2,
true => { 42 }
false => -1 as i32,
true => 2 + 2,
false => "",
true => if true { 42 } else { 84 }
false => if true { 42 } else { 84 },
true => return 42,
false => loop {}
true => (1, 2),
false => (1, 2,),
true => todo!(),
false => println!("hello"),
}
}

View file

@ -1,11 +1,5 @@
error: expected `{`, found `1`
--> $DIR/cfg_select.rs:13:17
|
LL | true => 1
| ^ expected `{`
warning: unreachable predicate
--> $DIR/cfg_select.rs:20:5
--> $DIR/cfg_select.rs:52:5
|
LL | _ => {}
| - always matches
@ -13,7 +7,7 @@ LL | true => {}
| ^^^^ this predicate is never reached
error: none of the predicates in this `cfg_select` evaluated to true
--> $DIR/cfg_select.rs:24:1
--> $DIR/cfg_select.rs:56:1
|
LL | / cfg_select! {
LL | |
@ -22,10 +16,10 @@ LL | | }
| |_^
error: none of the predicates in this `cfg_select` evaluated to true
--> $DIR/cfg_select.rs:29:1
--> $DIR/cfg_select.rs:61:1
|
LL | cfg_select! {}
| ^^^^^^^^^^^^^^
error: aborting due to 3 previous errors; 1 warning emitted
error: aborting due to 2 previous errors; 1 warning emitted

View file

@ -10,7 +10,7 @@ LL | let _f = to_fn(|| test(i));
| |
| captured by this `Fn` closure
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:3:33
|
LL | fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }

View file

@ -10,7 +10,7 @@ LL | expect_fn(|| drop(x.0));
| |
| captured by this `Fn` closure
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/issue-52663-span-decl-captured-variable.rs:1:33
|
LL | fn expect_fn<F>(f: F) where F : Fn() {

View file

@ -0,0 +1,18 @@
// In this regression test we check that a trailing `|` in an or-pattern just
// before the `if` token of a `match` guard will receive parser recovery with
// an appropriate error message.
//@ run-rustfix
#![allow(dead_code)]
enum E { A, B }
fn main() {
match E::A {
E::A |
E::B //~ ERROR a trailing `|` is not allowed in an or-pattern
if true => {
let _recovery_witness: i32 = 0i32; //~ ERROR mismatched types
}
_ => {}
}
}

View file

@ -1,6 +1,8 @@
// In this regression test we check that a trailing `|` in an or-pattern just
// before the `if` token of a `match` guard will receive parser recovery with
// an appropriate error message.
//@ run-rustfix
#![allow(dead_code)]
enum E { A, B }
@ -9,7 +11,8 @@ fn main() {
E::A |
E::B | //~ ERROR a trailing `|` is not allowed in an or-pattern
if true => {
let recovery_witness: bool = 0; //~ ERROR mismatched types
let _recovery_witness: i32 = 0u32; //~ ERROR mismatched types
}
_ => {}
}
}

View file

@ -1,24 +1,24 @@
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/issue-64879-trailing-before-guard.rs:10:14
--> $DIR/issue-64879-trailing-before-guard.rs:12:14
|
LL | E::A |
| ---- while parsing this or-pattern starting here
LL | E::B |
| ^
|
help: remove the `|`
|
LL - E::B |
LL + E::B
|
error[E0308]: mismatched types
--> $DIR/issue-64879-trailing-before-guard.rs:12:42
--> $DIR/issue-64879-trailing-before-guard.rs:14:42
|
LL | let _recovery_witness: i32 = 0u32;
| --- ^^^^ expected `i32`, found `u32`
| |
| expected due to this
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL - let _recovery_witness: i32 = 0u32;
LL + let _recovery_witness: i32 = 0i32;
|
LL | let recovery_witness: bool = 0;
| ---- ^ expected `bool`, found integer
| |
| expected due to this
error: aborting due to 2 previous errors

View file

@ -23,26 +23,26 @@ fn leading() {
#[cfg(false)]
fn trailing() {
let ( A ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
let (a ,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern
let ( A | B ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
let [ A | B ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
let S { f: B }; //~ ERROR a trailing `|` is not allowed in an or-pattern
let ( A | B ): E; //~ ERROR unexpected token `||` in pattern
let ( A ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
let (a,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern
let ( A | B ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
let [ A | B ]: [E; 1]; //~ ERROR a trailing `|` is not allowed in an or-pattern
let S { f: B }; //~ ERROR a trailing `|` is not allowed in an or-pattern
let ( A | B ): E; //~ ERROR unexpected token `||` in pattern
//~^ ERROR a trailing `|` is not allowed in an or-pattern
match A {
A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
A | B => {} //~ ERROR unexpected token `||` in pattern
A => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
A => {} //~ ERROR a trailing `||` is not allowed in an or-pattern
A | B => {} //~ ERROR unexpected token `||` in pattern
//~^ ERROR a trailing `|` is not allowed in an or-pattern
| A | B => {}
| A | B => {}
//~^ ERROR a trailing `|` is not allowed in an or-pattern
}
// These test trailing-vert in `let` bindings, but they also test that we don't emit a
// duplicate suggestion that would confuse rustfix.
let a : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
let a = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
let a ; //~ ERROR a trailing `|` is not allowed in an or-pattern
let a : u8 = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
let a = 0; //~ ERROR a trailing `|` is not allowed in an or-pattern
let a ; //~ ERROR a trailing `|` is not allowed in an or-pattern
}

View file

@ -32,7 +32,7 @@ fn trailing() {
//~^ ERROR a trailing `|` is not allowed in an or-pattern
match A {
A | => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
A || => {} //~ ERROR a trailing `|` is not allowed in an or-pattern
A || => {} //~ ERROR a trailing `||` is not allowed in an or-pattern
A || B | => {} //~ ERROR unexpected token `||` in pattern
//~^ ERROR a trailing `|` is not allowed in an or-pattern
| A | B | => {}

View file

@ -3,12 +3,6 @@ error: function parameters require top-level or-patterns in parentheses
|
LL | fn fun1( | A: E) {}
| ^^^
|
help: remove the `|`
|
LL - fn fun1( | A: E) {}
LL + fn fun1( A: E) {}
|
error: unexpected `||` before function parameter
--> $DIR/remove-leading-vert.rs:12:14
@ -78,12 +72,6 @@ LL | let ( A | ): E;
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - let ( A | ): E;
LL + let ( A ): E;
|
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:27:12
@ -92,12 +80,6 @@ LL | let (a |,): (E,);
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - let (a |,): (E,);
LL + let (a ,): (E,);
|
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:28:17
@ -106,12 +88,6 @@ LL | let ( A | B | ): E;
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - let ( A | B | ): E;
LL + let ( A | B ): E;
|
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:29:17
@ -120,12 +96,6 @@ LL | let [ A | B | ]: [E; 1];
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - let [ A | B | ]: [E; 1];
LL + let [ A | B ]: [E; 1];
|
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:30:18
@ -134,12 +104,6 @@ LL | let S { f: B | };
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - let S { f: B | };
LL + let S { f: B };
|
error: unexpected token `||` in pattern
--> $DIR/remove-leading-vert.rs:31:13
@ -162,12 +126,6 @@ LL | let ( A || B | ): E;
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - let ( A || B | ): E;
LL + let ( A || B ): E;
|
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:34:11
@ -176,14 +134,8 @@ LL | A | => {}
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - A | => {}
LL + A => {}
|
error: a trailing `|` is not allowed in an or-pattern
error: a trailing `||` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:35:11
|
LL | A || => {}
@ -192,11 +144,6 @@ LL | A || => {}
| while parsing this or-pattern starting here
|
= note: alternatives in or-patterns are separated with `|`, not `||`
help: remove the `||`
|
LL - A || => {}
LL + A => {}
|
error: unexpected token `||` in pattern
--> $DIR/remove-leading-vert.rs:36:11
@ -219,12 +166,6 @@ LL | A || B | => {}
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - A || B | => {}
LL + A || B => {}
|
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:38:17
@ -233,12 +174,6 @@ LL | | A | B | => {}
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - | A | B | => {}
LL + | A | B => {}
|
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:45:11
@ -247,12 +182,6 @@ LL | let a | : u8 = 0;
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - let a | : u8 = 0;
LL + let a : u8 = 0;
|
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:46:11
@ -261,12 +190,6 @@ LL | let a | = 0;
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - let a | = 0;
LL + let a = 0;
|
error: a trailing `|` is not allowed in an or-pattern
--> $DIR/remove-leading-vert.rs:47:11
@ -275,12 +198,6 @@ LL | let a | ;
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - let a | ;
LL + let a ;
|
error: aborting due to 21 previous errors

View file

@ -5,12 +5,6 @@ LL | ! |
| - ^
| |
| while parsing this or-pattern starting here
|
help: remove the `|`
|
LL - ! |
LL + !
|
error: a never pattern is always unreachable
--> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:10:20

View file

@ -44,7 +44,7 @@ LL |
LL | foo(f);
| ^ move occurs because `f` has type `{closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 52:58}`, which does not implement the `Copy` trait
|
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
help: consider cloning the value if the performance cost is acceptable
|
LL | foo(f.clone());

View file

@ -12,7 +12,7 @@ LL | let X(_t) = x;
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:13:18
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -37,7 +37,7 @@ LL | if let Either::One(_t) = e { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:13:18
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -62,7 +62,7 @@ LL | while let Either::One(_t) = e { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:13:18
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -90,7 +90,7 @@ LL | Either::One(_t)
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:13:18
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -118,7 +118,7 @@ LL | Either::One(_t) => (),
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:13:18
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -143,7 +143,7 @@ LL | let X(mut _t) = x;
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:13:18
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -168,7 +168,7 @@ LL | if let Either::One(mut _t) = em { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:13:18
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -193,7 +193,7 @@ LL | while let Either::One(mut _t) = em { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:13:18
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -221,7 +221,7 @@ LL | Either::One(mut _t)
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:13:18
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -249,7 +249,7 @@ LL | Either::One(mut _t) => (),
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:13:18
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -273,7 +273,7 @@ LL | let X(_t) = x;
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:39:22
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -298,7 +298,7 @@ LL | if let Either::One(_t) = e { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:39:22
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -323,7 +323,7 @@ LL | while let Either::One(_t) = e { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:39:22
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -351,7 +351,7 @@ LL | Either::One(_t)
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:39:22
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -379,7 +379,7 @@ LL | Either::One(_t) => (),
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:39:22
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -404,7 +404,7 @@ LL | let X(mut _t) = x;
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:39:22
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -429,7 +429,7 @@ LL | if let Either::One(mut _t) = em { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:39:22
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -454,7 +454,7 @@ LL | while let Either::One(mut _t) = em { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:39:22
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -482,7 +482,7 @@ LL | Either::One(mut _t)
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:39:22
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -510,7 +510,7 @@ LL | Either::One(mut _t) => (),
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:39:22
|
LL | fn consume_fn<F: Fn()>(_f: F) { }
@ -534,7 +534,7 @@ LL | let X(_t) = x;
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:50:29
|
LL | fn method_consume_fn<F: Fn()>(&self, _f: F) { }
@ -559,7 +559,7 @@ LL | if let Either::One(_t) = e { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:50:29
|
LL | fn method_consume_fn<F: Fn()>(&self, _f: F) { }
@ -584,7 +584,7 @@ LL | while let Either::One(_t) = e { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:50:29
|
LL | fn method_consume_fn<F: Fn()>(&self, _f: F) { }
@ -612,7 +612,7 @@ LL | Either::One(_t)
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:50:29
|
LL | fn method_consume_fn<F: Fn()>(&self, _f: F) { }
@ -640,7 +640,7 @@ LL | Either::One(_t) => (),
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:50:29
|
LL | fn method_consume_fn<F: Fn()>(&self, _f: F) { }
@ -665,7 +665,7 @@ LL | let X(mut _t) = x;
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:50:29
|
LL | fn method_consume_fn<F: Fn()>(&self, _f: F) { }
@ -690,7 +690,7 @@ LL | if let Either::One(mut _t) = em { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:50:29
|
LL | fn method_consume_fn<F: Fn()>(&self, _f: F) { }
@ -715,7 +715,7 @@ LL | while let Either::One(mut _t) = em { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:50:29
|
LL | fn method_consume_fn<F: Fn()>(&self, _f: F) { }
@ -743,7 +743,7 @@ LL | Either::One(mut _t)
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:50:29
|
LL | fn method_consume_fn<F: Fn()>(&self, _f: F) { }
@ -771,7 +771,7 @@ LL | Either::One(mut _t) => (),
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:50:29
|
LL | fn method_consume_fn<F: Fn()>(&self, _f: F) { }
@ -795,7 +795,7 @@ LL | let X(_t) = x;
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
@ -820,7 +820,7 @@ LL | if let Either::One(_t) = e { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
@ -845,7 +845,7 @@ LL | while let Either::One(_t) = e { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
@ -873,7 +873,7 @@ LL | Either::One(_t)
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
@ -901,7 +901,7 @@ LL | Either::One(_t) => (),
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
@ -926,7 +926,7 @@ LL | let X(mut _t) = x;
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
@ -951,7 +951,7 @@ LL | if let Either::One(mut _t) = em { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
@ -976,7 +976,7 @@ LL | while let Either::One(mut _t) = em { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
@ -1004,7 +1004,7 @@ LL | Either::One(mut _t)
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
@ -1032,7 +1032,7 @@ LL | Either::One(mut _t) => (),
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }
@ -1060,7 +1060,7 @@ LL | Either::One(mut _t) => (),
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/move-into-closure.rs:25:21
|
LL | fn consume_fnmut<F: FnMut()>(_f: F) { }

View file

@ -14,7 +14,7 @@ LL |
LL | var = Some(NotCopyable);
| --- variable moved due to use in closure
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/option-content-move2.rs:5:12
|
LL | fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
@ -44,7 +44,7 @@ LL |
LL | var = Some(NotCopyableButCloneable);
| --- variable moved due to use in closure
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/option-content-move2.rs:5:12
|
LL | fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}

View file

@ -9,7 +9,7 @@ LL | move || {
LL | let x = var;
| ^^^ move occurs because `var` has type `NotCopyable`, which does not implement the `Copy` trait
|
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
note: if `NotCopyable` implemented `Clone`, you could clone the value
--> $DIR/option-content-move3.rs:2:1
|
@ -38,7 +38,7 @@ LL | move || {
LL | let x = var;
| --- variable moved due to use in closure
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/option-content-move3.rs:6:12
|
LL | fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}
@ -63,7 +63,7 @@ LL | move || {
LL | let x = var;
| ^^^ move occurs because `var` has type `NotCopyableButCloneable`, which does not implement the `Copy` trait
|
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
= help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
help: consider borrowing here
|
LL | let x = &var;
@ -84,7 +84,7 @@ LL | move || {
LL | let x = var;
| --- variable moved due to use in closure
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/option-content-move3.rs:6:12
|
LL | fn func<F: FnMut() -> H, H: FnMut()>(_: F) {}

View file

@ -10,7 +10,7 @@ LL | let f = to_fn(|| drop(x));
| |
| captured by this `Fn` closure
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/unboxed-closure-illegal-move.rs:7:33
|
LL | fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
@ -32,7 +32,7 @@ LL | let f = to_fn_mut(|| drop(x));
| |
| captured by this `FnMut` closure
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/unboxed-closure-illegal-move.rs:8:37
|
LL | fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
@ -54,7 +54,7 @@ LL | let f = to_fn(move || drop(x));
| |
| captured by this `Fn` closure
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/unboxed-closure-illegal-move.rs:7:33
|
LL | fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
@ -72,7 +72,7 @@ LL | let f = to_fn_mut(move || drop(x));
| |
| captured by this `FnMut` closure
|
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but `FnOnce` closures may consume them only once
--> $DIR/unboxed-closure-illegal-move.rs:8:37
|
LL | fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }