From 87fc2e3a7ea7b1cc0b11ad4259acbd976b982356 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 9 Dec 2024 19:35:02 +0100 Subject: [PATCH 01/10] Use newly added exceptions to non default branch warning --- triagebot.toml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index c5dbd538f6c22..b7939710cab06 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -984,12 +984,20 @@ cc = ["@Zalathar"] cc = ["@kobzol"] [assign] -warn_non_default_branch = true +warn_non_default_branch.enable = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ "jyn514", ] +[[assign.warn_non_default_branch.exceptions]] +title = "[beta" +branch = "beta" + +[[assign.warn_non_default_branch.exceptions]] +title = "[stable" +branch = "stable" + [assign.adhoc_groups] compiler = [ "@BoxyUwU", From 3b057796264e637b31c28809322028a32d22ae6f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 16 Nov 2024 20:18:02 +0000 Subject: [PATCH 02/10] Add feature gate, not working yet --- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + .../src/traits/dyn_compatibility.rs | 59 +++++++++++++++---- .../feature-gate-async-fn-in-dyn-trait.rs | 14 +++++ .../feature-gate-async-fn-in-dyn-trait.stderr | 48 +++++++++++++++ 5 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs create mode 100644 tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 93a605e197ce9..0454d30787506 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -390,6 +390,8 @@ declare_features! ( (unstable, associated_type_defaults, "1.2.0", Some(29661)), /// Allows `async || body` closures. (unstable, async_closure, "1.37.0", Some(62290)), + /// Allows async functions to be called from `dyn Trait`. + (incomplete, async_fn_in_dyn_trait, "CURRENT_RUSTC_VERSION", Some(133119)), /// Allows `#[track_caller]` on async functions. (unstable, async_fn_track_caller, "1.73.0", Some(110011)), /// Allows `for await` loops. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d30b17c9cd8dd..9b499c716039b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -461,6 +461,7 @@ symbols! { async_drop_slice, async_drop_surface_drop_in_place, async_fn, + async_fn_in_dyn_trait, async_fn_in_trait, async_fn_kind_helper, async_fn_kind_upvars, diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index c9297027519d7..d2abd881c4591 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -11,6 +11,7 @@ use rustc_abi::BackendRepr; use rustc_errors::FatalError; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt, @@ -901,23 +902,59 @@ fn contains_illegal_impl_trait_in_trait<'tcx>( fn_def_id: DefId, ty: ty::Binder<'tcx, Ty<'tcx>>, ) -> Option { - // This would be caught below, but rendering the error as a separate - // `async-specific` message is better. + let ty = tcx.liberate_late_bound_regions(fn_def_id, ty); + if tcx.asyncness(fn_def_id).is_async() { - return Some(MethodViolationCode::AsyncFn); + // FIXME(async_fn_in_dyn_trait): Think of a better way to unify these code paths + // to issue an appropriate feature suggestion when users try to use AFIDT. + // Obviously we must only do this once AFIDT is finished enough to actually be usable. + if tcx.features().async_fn_in_dyn_trait() { + let ty::Alias(ty::Projection, proj) = *ty.kind() else { + bug!("expected async fn in trait to return an RPITIT"); + }; + assert!(tcx.is_impl_trait_in_trait(proj.def_id)); + + // FIXME(async_fn_in_dyn_trait): We should check that this bound is legal too, + // and stop relying on `async fn` in the definition. + for bound in tcx.item_bounds(proj.def_id).instantiate(tcx, proj.args) { + if let Some(violation) = bound + .visit_with(&mut IllegalRpititVisitor { tcx, allowed: Some(proj) }) + .break_value() + { + return Some(violation); + } + } + + None + } else { + // Rendering the error as a separate `async-specific` message is better. + Some(MethodViolationCode::AsyncFn) + } + } else { + ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value() } +} + +struct IllegalRpititVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + allowed: Option>, +} + +impl<'tcx> TypeVisitor> for IllegalRpititVisitor<'tcx> { + type Result = ControlFlow; - // FIXME(RPITIT): Perhaps we should use a visitor here? - ty.skip_binder().walk().find_map(|arg| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Projection, proj) = ty.kind() - && tcx.is_impl_trait_in_trait(proj.def_id) + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + if let ty::Alias(ty::Projection, proj) = *ty.kind() + && Some(proj) != self.allowed + && self.tcx.is_impl_trait_in_trait(proj.def_id) { - Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id))) + ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait( + self.tcx.def_span(proj.def_id), + )) } else { - None + ty.super_visit_with(self) } - }) + } } pub(crate) fn provide(providers: &mut Providers) { diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs new file mode 100644 index 0000000000000..d9ff45f57ecba --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs @@ -0,0 +1,14 @@ +//@ edition: 2021 + +trait Foo { + async fn bar(&self); +} + +async fn takes_dyn_trait(x: &dyn Foo) { + //~^ ERROR the trait `Foo` cannot be made into an object + x.bar().await; + //~^ ERROR the trait `Foo` cannot be made into an object + //~| ERROR the trait `Foo` cannot be made into an object +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr new file mode 100644 index 0000000000000..f78fc422410be --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr @@ -0,0 +1,48 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:7:30 + | +LL | async fn takes_dyn_trait(x: &dyn Foo) { + | ^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | async fn bar(&self); + | ^^^ ...because method `bar` is `async` + = help: consider moving `bar` to another trait + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:7 + | +LL | x.bar().await; + | ^^^ `Foo` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | async fn bar(&self); + | ^^^ ...because method `bar` is `async` + = help: consider moving `bar` to another trait + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:5 + | +LL | x.bar().await; + | ^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | async fn bar(&self); + | ^^^ ...because method `bar` is `async` + = help: consider moving `bar` to another trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0038`. From a7fa4cbcb498b80b126a954b5944f19a11e28dec Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 16 Nov 2024 20:18:13 +0000 Subject: [PATCH 03/10] Implement projection and shim for AFIDT --- compiler/rustc_middle/src/ty/instance.rs | 37 ++++---- compiler/rustc_middle/src/ty/mod.rs | 1 + .../ty/return_position_impl_trait_in_trait.rs | 95 +++++++++++++++++++ compiler/rustc_mir_transform/src/shim.rs | 56 ++++++++++- compiler/rustc_monomorphize/src/lib.rs | 5 +- .../src/traits/project.rs | 58 ++++++++++- .../src/traits/select/confirmation.rs | 74 +++++++++++++++ compiler/rustc_ty_utils/src/abi.rs | 26 +++++ .../ui/async-await/dyn/auxiliary/block-on.rs | 20 ++++ .../ui/async-await/dyn/mut-is-pointer-like.rs | 40 ++++++++ .../dyn/mut-is-pointer-like.run.stdout | 1 + .../dyn/mut-is-pointer-like.stderr | 11 +++ tests/ui/async-await/dyn/works.rs | 32 +++++++ tests/ui/async-await/dyn/works.run.stdout | 1 + tests/ui/async-await/dyn/works.stderr | 11 +++ tests/ui/async-await/dyn/wrong-size.rs | 23 +++++ tests/ui/async-await/dyn/wrong-size.stderr | 21 ++++ 17 files changed, 490 insertions(+), 22 deletions(-) create mode 100644 compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs create mode 100644 tests/ui/async-await/dyn/auxiliary/block-on.rs create mode 100644 tests/ui/async-await/dyn/mut-is-pointer-like.rs create mode 100644 tests/ui/async-await/dyn/mut-is-pointer-like.run.stdout create mode 100644 tests/ui/async-await/dyn/mut-is-pointer-like.stderr create mode 100644 tests/ui/async-await/dyn/works.rs create mode 100644 tests/ui/async-await/dyn/works.run.stdout create mode 100644 tests/ui/async-await/dyn/works.stderr create mode 100644 tests/ui/async-await/dyn/wrong-size.rs create mode 100644 tests/ui/async-await/dyn/wrong-size.stderr diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 65c909e70f626..1dd564d979859 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -677,23 +677,26 @@ impl<'tcx> Instance<'tcx> { // // 1) The underlying method expects a caller location parameter // in the ABI - if resolved.def.requires_caller_location(tcx) - // 2) The caller location parameter comes from having `#[track_caller]` - // on the implementation, and *not* on the trait method. - && !tcx.should_inherit_track_caller(def) - // If the method implementation comes from the trait definition itself - // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`), - // then we don't need to generate a shim. This check is needed because - // `should_inherit_track_caller` returns `false` if our method - // implementation comes from the trait block, and not an impl block - && !matches!( - tcx.opt_associated_item(def), - Some(ty::AssocItem { - container: ty::AssocItemContainer::Trait, - .. - }) - ) - { + let needs_track_caller_shim = resolved.def.requires_caller_location(tcx) + // 2) The caller location parameter comes from having `#[track_caller]` + // on the implementation, and *not* on the trait method. + && !tcx.should_inherit_track_caller(def) + // If the method implementation comes from the trait definition itself + // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`), + // then we don't need to generate a shim. This check is needed because + // `should_inherit_track_caller` returns `false` if our method + // implementation comes from the trait block, and not an impl block + && !matches!( + tcx.opt_associated_item(def), + Some(ty::AssocItem { + container: ty::AssocItemContainer::Trait, + .. + }) + ); + // We also need to generate a shim if this is an AFIT. + let needs_rpitit_shim = + tcx.return_position_impl_trait_in_trait_shim_data(def).is_some(); + if needs_track_caller_shim || needs_rpitit_shim { if tcx.is_closure_like(def) { debug!( " => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 70e0568b2025b..80b11892a4281 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -146,6 +146,7 @@ mod opaque_types; mod parameterized; mod predicate; mod region; +mod return_position_impl_trait_in_trait; mod rvalue_scopes; mod structural_impls; #[allow(hidden_glob_reexports)] diff --git a/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs b/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs new file mode 100644 index 0000000000000..21c605f8296d1 --- /dev/null +++ b/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs @@ -0,0 +1,95 @@ +use rustc_hir::def_id::DefId; + +use crate::ty::{self, ExistentialPredicateStableCmpExt, TyCtxt}; + +impl<'tcx> TyCtxt<'tcx> { + /// Given a `def_id` of a trait or impl method, compute whether that method needs to + /// have an RPITIT shim applied to it for it to be object safe. If so, return the + /// `def_id` of the RPITIT, and also the args of trait method that returns the RPITIT. + /// + /// NOTE that these args are not, in general, the same as than the RPITIT's args. They + /// are a subset of those args, since they do not include the late-bound lifetimes of + /// the RPITIT. Depending on the context, these will need to be dealt with in different + /// ways -- in codegen, it's okay to fill them with ReErased. + pub fn return_position_impl_trait_in_trait_shim_data( + self, + def_id: DefId, + ) -> Option<(DefId, ty::EarlyBinder<'tcx, ty::GenericArgsRef<'tcx>>)> { + let assoc_item = self.opt_associated_item(def_id)?; + + let (trait_item_def_id, opt_impl_def_id) = match assoc_item.container { + ty::AssocItemContainer::Impl => { + (assoc_item.trait_item_def_id?, Some(self.parent(def_id))) + } + ty::AssocItemContainer::Trait => (def_id, None), + }; + + let sig = self.fn_sig(trait_item_def_id); + + // Check if the trait returns an RPITIT. + let ty::Alias(ty::Projection, ty::AliasTy { def_id, .. }) = + *sig.skip_binder().skip_binder().output().kind() + else { + return None; + }; + if !self.is_impl_trait_in_trait(def_id) { + return None; + } + + let args = if let Some(impl_def_id) = opt_impl_def_id { + // Rebase the args from the RPITIT onto the impl trait ref, so we can later + // substitute them with the method args of the *impl* method, since that's + // the instance we're building a vtable shim for. + ty::GenericArgs::identity_for_item(self, trait_item_def_id).rebase_onto( + self, + self.parent(trait_item_def_id), + self.impl_trait_ref(impl_def_id) + .expect("expected impl trait ref from parent of impl item") + .instantiate_identity() + .args, + ) + } else { + // This is when we have a default trait implementation. + ty::GenericArgs::identity_for_item(self, trait_item_def_id) + }; + + Some((def_id, ty::EarlyBinder::bind(args))) + } + + /// Given a `DefId` of an RPITIT and its args, return the existential predicates + /// that corresponds to the RPITIT's bounds with the self type erased. + pub fn item_bounds_to_existential_predicates( + self, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> &'tcx ty::List> { + let mut bounds: Vec<_> = self + .item_super_predicates(def_id) + .iter_instantiated(self, args) + .filter_map(|clause| { + clause + .kind() + .map_bound(|clause| match clause { + ty::ClauseKind::Trait(trait_pred) => Some(ty::ExistentialPredicate::Trait( + ty::ExistentialTraitRef::erase_self_ty(self, trait_pred.trait_ref), + )), + ty::ClauseKind::Projection(projection_pred) => { + Some(ty::ExistentialPredicate::Projection( + ty::ExistentialProjection::erase_self_ty(self, projection_pred), + )) + } + ty::ClauseKind::TypeOutlives(_) => { + // Type outlives bounds don't really turn into anything, + // since we must use an intersection region for the `dyn*`'s + // region anyways. + None + } + _ => unreachable!("unexpected clause in item bounds: {clause:?}"), + }) + .transpose() + }) + .collect(); + bounds.sort_by(|a, b| a.skip_binder().stable_cmp(self, &b.skip_binder())); + self.mk_poly_existential_predicates(&bounds) + } +} diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index b8383e734e2ba..722da3c420dc9 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -9,6 +9,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; use rustc_middle::query::Providers; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{ self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, GenericArgs, Ty, TyCtxt, }; @@ -710,6 +711,13 @@ fn build_call_shim<'tcx>( }; let def_id = instance.def_id(); + + let rpitit_shim = if let ty::InstanceKind::ReifyShim(..) = instance { + tcx.return_position_impl_trait_in_trait_shim_data(def_id) + } else { + None + }; + let sig = tcx.fn_sig(def_id); let sig = sig.map_bound(|sig| tcx.instantiate_bound_regions_with_erased(sig)); @@ -765,9 +773,34 @@ fn build_call_shim<'tcx>( let mut local_decls = local_decls_for_sig(&sig, span); let source_info = SourceInfo::outermost(span); + let mut destination = Place::return_place(); + if let Some((rpitit_def_id, fn_args)) = rpitit_shim { + let rpitit_args = + fn_args.instantiate_identity().extend_to(tcx, rpitit_def_id, |param, _| { + match param.kind { + ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), + ty::GenericParamDefKind::Type { .. } + | ty::GenericParamDefKind::Const { .. } => { + unreachable!("rpitit should have no addition ty/ct") + } + } + }); + let dyn_star_ty = Ty::new_dynamic( + tcx, + tcx.item_bounds_to_existential_predicates(rpitit_def_id, rpitit_args), + tcx.lifetimes.re_erased, + ty::DynStar, + ); + destination = local_decls.push(local_decls[RETURN_PLACE].clone()).into(); + local_decls[RETURN_PLACE].ty = dyn_star_ty; + let mut inputs_and_output = sig.inputs_and_output.to_vec(); + *inputs_and_output.last_mut().unwrap() = dyn_star_ty; + sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output); + } + let rcvr_place = || { assert!(rcvr_adjustment.is_some()); - Place::from(Local::new(1 + 0)) + Place::from(Local::new(1)) }; let mut statements = vec![]; @@ -854,7 +887,7 @@ fn build_call_shim<'tcx>( TerminatorKind::Call { func: callee, args, - destination: Place::return_place(), + destination, target: Some(BasicBlock::new(1)), unwind: if let Some(Adjustment::RefMut) = rcvr_adjustment { UnwindAction::Cleanup(BasicBlock::new(3)) @@ -882,7 +915,24 @@ fn build_call_shim<'tcx>( ); } // BB #1/#2 - return - block(&mut blocks, vec![], TerminatorKind::Return, false); + // NOTE: If this is an RPITIT in dyn, we also want to coerce + // the return type of the function into a `dyn*`. + let stmts = if rpitit_shim.is_some() { + vec![Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + Place::return_place(), + Rvalue::Cast( + CastKind::PointerCoercion(PointerCoercion::DynStar, CoercionSource::Implicit), + Operand::Move(destination), + sig.output(), + ), + ))), + }] + } else { + vec![] + }; + block(&mut blocks, stmts, TerminatorKind::Return, false); if let Some(Adjustment::RefMut) = rcvr_adjustment { // BB #3 - drop if closure panics block( diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index caae54cd55914..714b64b3a231c 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -42,7 +42,10 @@ fn custom_coerce_unsize_info<'tcx>( .. })) => Ok(tcx.coerce_unsized_info(impl_def_id)?.custom_kind.unwrap()), impl_source => { - bug!("invalid `CoerceUnsized` impl_source: {:?}", impl_source); + bug!( + "invalid `CoerceUnsized` from {source_ty} to {target_ty}: impl_source: {:?}", + impl_source + ); } } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 49c34550f8e03..9b8317fda7569 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -7,8 +7,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_infer::infer::{DefineOpaqueTypes, RegionVariableOrigin}; use rustc_infer::traits::{ObligationCauseCode, PredicateObligations}; use rustc_middle::traits::select::OverflowError; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData}; @@ -18,6 +18,7 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; +use thin_vec::thin_vec; use tracing::{debug, instrument}; use super::{ @@ -61,6 +62,9 @@ enum ProjectionCandidate<'tcx> { /// Bounds specified on an object type Object(ty::PolyProjectionPredicate<'tcx>), + /// Built-in bound for a dyn async fn in trait + ObjectRpitit, + /// From an "impl" (or a "pseudo-impl" returned by select) Select(Selection<'tcx>), } @@ -827,6 +831,17 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( env_predicates, false, ); + + // `dyn Trait` automagically project their AFITs to `dyn* Future`. + if tcx.is_impl_trait_in_trait(obligation.predicate.def_id) + && let Some(out_trait_def_id) = data.principal_def_id() + && let rpitit_trait_def_id = tcx.parent(obligation.predicate.def_id) + && tcx + .supertrait_def_ids(out_trait_def_id) + .any(|trait_def_id| trait_def_id == rpitit_trait_def_id) + { + candidate_set.push_candidate(ProjectionCandidate::ObjectRpitit); + } } #[instrument( @@ -1247,6 +1262,8 @@ fn confirm_candidate<'cx, 'tcx>( ProjectionCandidate::Select(impl_source) => { confirm_select_candidate(selcx, obligation, impl_source) } + + ProjectionCandidate::ObjectRpitit => confirm_object_rpitit_candidate(selcx, obligation), }; // When checking for cycle during evaluation, we compare predicates with @@ -2034,6 +2051,45 @@ fn confirm_impl_candidate<'cx, 'tcx>( } } +fn confirm_object_rpitit_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTermObligation<'tcx>, +) -> Progress<'tcx> { + let tcx = selcx.tcx(); + let mut obligations = thin_vec![]; + + // Compute an intersection lifetime for all the input components of this GAT. + let intersection = + selcx.infcx.next_region_var(RegionVariableOrigin::MiscVariable(obligation.cause.span)); + for component in obligation.predicate.args { + match component.unpack() { + ty::GenericArgKind::Lifetime(lt) => { + obligations.push(obligation.with(tcx, ty::OutlivesPredicate(lt, intersection))); + } + ty::GenericArgKind::Type(ty) => { + obligations.push(obligation.with(tcx, ty::OutlivesPredicate(ty, intersection))); + } + ty::GenericArgKind::Const(_ct) => { + // Consts have no outlives... + } + } + } + + Progress { + term: Ty::new_dynamic( + tcx, + tcx.item_bounds_to_existential_predicates( + obligation.predicate.def_id, + obligation.predicate.args, + ), + intersection, + ty::DynStar, + ) + .into(), + obligations, + } +} + // Get obligations corresponding to the predicates from the where-clause of the // associated type itself. fn assoc_ty_own_obligations<'cx, 'tcx>( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2fbe2e1e323be..3664121ac4b8c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -19,6 +19,7 @@ use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; use rustc_middle::ty::{self, GenericArgsRef, ToPolyTraitRef, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; +use rustc_type_ir::elaborate; use tracing::{debug, instrument}; use super::SelectionCandidate::{self, *}; @@ -624,6 +625,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for assoc_type in assoc_types { let defs: &ty::Generics = tcx.generics_of(assoc_type); + // When `async_fn_in_dyn_trait` is enabled, we don't need to check the + // RPITIT for compatibility, since it's not provided by the user. + if tcx.features().async_fn_in_dyn_trait() && tcx.is_impl_trait_in_trait(assoc_type) { + continue; + } + if !defs.own_params.is_empty() { tcx.dcx().span_delayed_bug( obligation.cause.span, @@ -1175,6 +1182,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::ClauseKind::TypeOutlives(outlives).upcast(tcx), )); + // Require that all AFIT will return something that can be coerced into `dyn*` + // -- a shim will be responsible for doing the actual coercion to `dyn*`. + if let Some(principal) = data.principal() { + for supertrait in + elaborate::supertraits(tcx, principal.with_self_ty(tcx, source)) + { + if tcx.is_trait_alias(supertrait.def_id()) { + continue; + } + + for &assoc_item in tcx.associated_item_def_ids(supertrait.def_id()) { + if !tcx.is_impl_trait_in_trait(assoc_item) { + continue; + } + + let pointer_like_goal = pointer_like_goal_for_rpitit( + tcx, + supertrait, + assoc_item, + &obligation.cause, + ); + + nested.push(predicate_to_obligation(pointer_like_goal.upcast(tcx))); + } + } + } + ImplSource::Builtin(BuiltinImplSource::Misc, nested) } @@ -1280,3 +1314,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } } + +/// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures) +/// implements the `PointerLike` trait, which is a requirement for the RPITIT to be +/// coercible to `dyn* Future`, which is itself a requirement for the RPITIT's parent +/// trait to be coercible to `dyn Trait`. +/// +/// We do this given a supertrait's substitutions, and then augment the substitutions +/// with bound variables to compute the goal universally. Given that `PointerLike` has +/// no region requirements (at least for the built-in pointer types), this shouldn't +/// *really* matter, but it is the best choice for soundness. +fn pointer_like_goal_for_rpitit<'tcx>( + tcx: TyCtxt<'tcx>, + supertrait: ty::PolyTraitRef<'tcx>, + rpitit_item: DefId, + cause: &ObligationCause<'tcx>, +) -> ty::PolyTraitRef<'tcx> { + let mut bound_vars = supertrait.bound_vars().to_vec(); + + let args = supertrait.skip_binder().args.extend_to(tcx, rpitit_item, |arg, _| match arg.kind { + ty::GenericParamDefKind::Lifetime => { + let kind = ty::BoundRegionKind::Named(arg.def_id, tcx.item_name(arg.def_id)); + bound_vars.push(ty::BoundVariableKind::Region(kind)); + ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind, + }) + .into() + } + ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => { + unreachable!() + } + }); + + ty::Binder::bind_with_vars( + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::PointerLike, Some(cause.span)), [ + Ty::new_projection_from_args(tcx, rpitit_item, args), + ]), + tcx.mk_bound_variable_kinds(&bound_vars), + ) +} diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index ae6d697794fe5..b63534880d1c4 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -48,12 +48,38 @@ fn fn_sig_for_fn_abi<'tcx>( let mut sig = tcx .instantiate_bound_regions_with_erased(tcx.fn_sig(def_id).instantiate(tcx, args)); + // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. if let ty::InstanceKind::VTableShim(..) = instance.def { let mut inputs_and_output = sig.inputs_and_output.to_vec(); inputs_and_output[0] = Ty::new_mut_ptr(tcx, inputs_and_output[0]); sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output); } + // Modify `fn() -> impl Future` to `fn() -> dyn* Future`. + if let ty::InstanceKind::ReifyShim(def_id, _) = instance.def + && let Some((rpitit_def_id, fn_args)) = + tcx.return_position_impl_trait_in_trait_shim_data(def_id) + { + let fn_args = fn_args.instantiate(tcx, args); + let rpitit_args = + fn_args.extend_to(tcx, rpitit_def_id, |param, _| match param.kind { + ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), + ty::GenericParamDefKind::Type { .. } + | ty::GenericParamDefKind::Const { .. } => { + unreachable!("rpitit should have no addition ty/ct") + } + }); + let dyn_star_ty = Ty::new_dynamic( + tcx, + tcx.item_bounds_to_existential_predicates(rpitit_def_id, rpitit_args), + tcx.lifetimes.re_erased, + ty::DynStar, + ); + let mut inputs_and_output = sig.inputs_and_output.to_vec(); + *inputs_and_output.last_mut().unwrap() = dyn_star_ty; + sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output); + } + sig } ty::Closure(def_id, args) => { diff --git a/tests/ui/async-await/dyn/auxiliary/block-on.rs b/tests/ui/async-await/dyn/auxiliary/block-on.rs new file mode 100644 index 0000000000000..dcb710fc97c97 --- /dev/null +++ b/tests/ui/async-await/dyn/auxiliary/block-on.rs @@ -0,0 +1,20 @@ +//@ edition: 2021 + +#![feature(async_closure, noop_waker)] + +use std::future::Future; +use std::pin::pin; +use std::task::*; + +pub fn block_on(fut: impl Future) -> T { + let mut fut = pin!(fut); + // Poll loop, just to test the future... + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match unsafe { fut.as_mut().poll(ctx) } { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} diff --git a/tests/ui/async-await/dyn/mut-is-pointer-like.rs b/tests/ui/async-await/dyn/mut-is-pointer-like.rs new file mode 100644 index 0000000000000..93e8281164ce9 --- /dev/null +++ b/tests/ui/async-await/dyn/mut-is-pointer-like.rs @@ -0,0 +1,40 @@ +//@ aux-build:block-on.rs +//@ edition: 2021 +//@ run-pass +//@ check-run-results + +#![allow(refining_impl_trait)] +#![feature(async_fn_in_dyn_trait)] +//~^ WARN the feature `async_fn_in_dyn_trait` is incomplete + +extern crate block_on; + +use std::future::Future; +use std::pin::Pin; + +trait AsyncTrait { + type Output; + + async fn async_dispatch(self: Pin<&mut Self>) -> Self::Output; +} + +impl AsyncTrait for F +where + F: Future, +{ + type Output = F::Output; + + fn async_dispatch(self: Pin<&mut Self>) -> Pin<&mut Self> { + self + } +} + +fn main() { + block_on::block_on(async { + let f = std::pin::pin!(async { + println!("hello, world"); + }); + let x: Pin<&mut dyn AsyncTrait> = f; + x.async_dispatch().await; + }); +} diff --git a/tests/ui/async-await/dyn/mut-is-pointer-like.run.stdout b/tests/ui/async-await/dyn/mut-is-pointer-like.run.stdout new file mode 100644 index 0000000000000..4b5fa63702dd9 --- /dev/null +++ b/tests/ui/async-await/dyn/mut-is-pointer-like.run.stdout @@ -0,0 +1 @@ +hello, world diff --git a/tests/ui/async-await/dyn/mut-is-pointer-like.stderr b/tests/ui/async-await/dyn/mut-is-pointer-like.stderr new file mode 100644 index 0000000000000..7c72ce43cf05a --- /dev/null +++ b/tests/ui/async-await/dyn/mut-is-pointer-like.stderr @@ -0,0 +1,11 @@ +warning: the feature `async_fn_in_dyn_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/mut-is-pointer-like.rs:7:12 + | +LL | #![feature(async_fn_in_dyn_trait)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #133119 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/dyn/works.rs b/tests/ui/async-await/dyn/works.rs new file mode 100644 index 0000000000000..0732a3ee2f263 --- /dev/null +++ b/tests/ui/async-await/dyn/works.rs @@ -0,0 +1,32 @@ +//@ aux-build:block-on.rs +//@ edition: 2021 +//@ run-pass +//@ check-run-results + +#![allow(refining_impl_trait)] +#![feature(async_fn_in_dyn_trait)] +//~^ WARN the feature `async_fn_in_dyn_trait` is incomplete + +extern crate block_on; + +use std::pin::Pin; +use std::future::Future; + +trait AsyncTrait { + async fn async_dispatch(&self); +} + +impl AsyncTrait for &'static str { + fn async_dispatch(&self) -> Pin>> { + Box::pin(async move { + println!("message from the aether: {self}"); + }) + } +} + +fn main() { + block_on::block_on(async { + let x: &dyn AsyncTrait = &"hello, world!"; + x.async_dispatch().await; + }); +} diff --git a/tests/ui/async-await/dyn/works.run.stdout b/tests/ui/async-await/dyn/works.run.stdout new file mode 100644 index 0000000000000..7b45a504e60c7 --- /dev/null +++ b/tests/ui/async-await/dyn/works.run.stdout @@ -0,0 +1 @@ +message from the aether: hello, world! diff --git a/tests/ui/async-await/dyn/works.stderr b/tests/ui/async-await/dyn/works.stderr new file mode 100644 index 0000000000000..2c7db7c32f59f --- /dev/null +++ b/tests/ui/async-await/dyn/works.stderr @@ -0,0 +1,11 @@ +warning: the feature `async_fn_in_dyn_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/works.rs:7:12 + | +LL | #![feature(async_fn_in_dyn_trait)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #133119 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/async-await/dyn/wrong-size.rs b/tests/ui/async-await/dyn/wrong-size.rs new file mode 100644 index 0000000000000..ac15dd2606767 --- /dev/null +++ b/tests/ui/async-await/dyn/wrong-size.rs @@ -0,0 +1,23 @@ +//@ edition: 2021 + +#![feature(async_fn_in_dyn_trait)] +//~^ WARN the feature `async_fn_in_dyn_trait` is incomplete + +use std::future::Future; + +trait AsyncTrait { + async fn async_dispatch(&self); +} + +impl AsyncTrait for &'static str { + fn async_dispatch(&self) -> impl Future { + async move { + // The implementor must box the future... + } + } +} + +fn main() { + let x: &dyn AsyncTrait = &"hello, world!"; + //~^ ERROR `impl Future` needs to have the same ABI as a pointer +} diff --git a/tests/ui/async-await/dyn/wrong-size.stderr b/tests/ui/async-await/dyn/wrong-size.stderr new file mode 100644 index 0000000000000..0202b5f240977 --- /dev/null +++ b/tests/ui/async-await/dyn/wrong-size.stderr @@ -0,0 +1,21 @@ +warning: the feature `async_fn_in_dyn_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/wrong-size.rs:3:12 + | +LL | #![feature(async_fn_in_dyn_trait)] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #133119 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `impl Future` needs to have the same ABI as a pointer + --> $DIR/wrong-size.rs:21:30 + | +LL | let x: &dyn AsyncTrait = &"hello, world!"; + | ^^^^^^^^^^^^^^^^ `impl Future` needs to be a pointer-like type + | + = help: the trait `for<'a> PointerLike` is not implemented for `impl Future` + = note: required for the cast from `&&'static str` to `&dyn AsyncTrait` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. From 57e8a1c9c3b753f3a96a124149ca1ba07f0db483 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 10 Dec 2024 17:20:54 +0000 Subject: [PATCH 04/10] Don't check RPITITs that are Self:Sized for PointerLike --- .../src/traits/select/confirmation.rs | 5 +++++ .../in-trait/sized-rpits-dont-need-pointer-like.rs | 13 +++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/ui/impl-trait/in-trait/sized-rpits-dont-need-pointer-like.rs diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3664121ac4b8c..962b6b94fa625 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1197,6 +1197,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { continue; } + // RPITITs with `Self: Sized` don't need to be checked. + if tcx.generics_require_sized_self(assoc_item) { + continue; + } + let pointer_like_goal = pointer_like_goal_for_rpitit( tcx, supertrait, diff --git a/tests/ui/impl-trait/in-trait/sized-rpits-dont-need-pointer-like.rs b/tests/ui/impl-trait/in-trait/sized-rpits-dont-need-pointer-like.rs new file mode 100644 index 0000000000000..80850a2639fbd --- /dev/null +++ b/tests/ui/impl-trait/in-trait/sized-rpits-dont-need-pointer-like.rs @@ -0,0 +1,13 @@ +//@ check-pass + +// Make sure that we don't enforce that an RPIT that has `where Self: Sized` is pointer-like. + +trait Foo { + fn foo() -> impl Sized where Self: Sized {} +} + +impl Foo for () {} + +fn main() { + let x: &dyn Foo = &(); +} From 78f3946ffd44aff5c57baf4192d9adbd70c3f576 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Wed, 20 Nov 2024 22:03:20 +0800 Subject: [PATCH 05/10] ABI checks: add support for loongarch LoongArch psABI[^1] specifies that LSX vector types are passed via general-purpose registers, while LASX vector types are passed indirectly through the stack. This patch addresses the following warnings: ``` warning: this function call uses a SIMD vector type that is not currently supported with the chosen ABI --> .../library/core/src/../../stdarch/crates/core_arch/src/loongarch64/lsx/generated.rs:3695:5 | 3695 | __lsx_vreplgr2vr_b(a) | ^^^^^^^^^^^^^^^^^^^^^ function called here | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116558 = note: `#[warn(abi_unsupported_vector_types)]` on by default ``` [^1]: /~https://github.com/loongson/la-abi-specs/blob/release/lapcs.adoc --- compiler/rustc_target/src/target_features.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 3a1306072658d..c89045c93e304 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -611,6 +611,8 @@ const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(512, "hvx-length64b"),*/ (1024, "hvx-length128b")]; const MIPS_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "msa")]; const CSKY_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[(128, "vdspv1")]; +const LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = + &[(128, "lsx"), (256, "lasx")]; impl super::spec::Target { pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] { @@ -638,7 +640,7 @@ impl super::spec::Target { "aarch64" | "arm64ec" => AARCH64_FEATURES_FOR_CORRECT_VECTOR_ABI, "arm" => ARM_FEATURES_FOR_CORRECT_VECTOR_ABI, "powerpc" | "powerpc64" => POWERPC_FEATURES_FOR_CORRECT_VECTOR_ABI, - "loongarch64" => &[], // on-stack ABI, so we complain about all by-val vectors + "loongarch64" => LOONGARCH_FEATURES_FOR_CORRECT_VECTOR_ABI, "riscv32" | "riscv64" => RISCV_FEATURES_FOR_CORRECT_VECTOR_ABI, "wasm32" | "wasm64" => WASM_FEATURES_FOR_CORRECT_VECTOR_ABI, "s390x" => S390X_FEATURES_FOR_CORRECT_VECTOR_ABI, From f39e813c0fa227d8e885011024a5daef943178e0 Mon Sep 17 00:00:00 2001 From: Steven Grady Date: Wed, 11 Dec 2024 16:35:43 -0800 Subject: [PATCH 06/10] Bump Fuchsia --- src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh index 969389f92f7d7..7027c93857c3c 100755 --- a/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh +++ b/src/ci/docker/host-x86_64/x86_64-fuchsia/build-fuchsia.sh @@ -35,7 +35,7 @@ PICK_REFS=() # commit hash of fuchsia.git and some other repos in the "monorepo" checkout, in # addition to versions of prebuilts. It should be bumped regularly by the # Fuchsia team – we aim for every 1-2 months. -INTEGRATION_SHA=9f632bb7446d5a6af2998f1a0ebdb4b8ea2f4511 +INTEGRATION_SHA=bb38af4e3d45e490531b71fc52a460003141d032 checkout=fuchsia jiri=.jiri_root/bin/jiri From f7c6a2cf11eb075ea56b54c48756ee55d0b2aeb1 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 12 Dec 2024 20:54:33 +1100 Subject: [PATCH 07/10] Fix our `llvm::Bool` typedef to be signed, to match `LLVMBool` In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`, but our Rust-side typedef was using `c_uint` instead. Signed and unsigned integers have the same ABI on most platforms, but that isn't universally true, so we should prefer to be consistent with LLVM. --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 8b4523bd252b3..d62632d143168 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -17,7 +17,9 @@ use super::debuginfo::{ DebugEmissionKind, DebugNameTableKind, }; -pub type Bool = c_uint; +/// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`, +/// which has a different ABI from Rust or C++ `bool`. +pub type Bool = c_int; pub const True: Bool = 1 as Bool; pub const False: Bool = 0 as Bool; From 50fac072815e576ca955b0f53fb52236d2f671f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Thu, 12 Dec 2024 19:23:38 +0800 Subject: [PATCH 08/10] Revert "Rollup merge of #134123 - Zalathar:json-output, r=jieyouxu,clubby789" This reverts commit c42c248009747366e646a3ad1ce6e8f815ea7db2, reversing changes made to 0f1b827881d20ba08f72d692ccd3ff97a0e25851. --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 93f8091299fa4..4419b11ac1971 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2261,7 +2261,7 @@ pub fn stream_cargo( Ok(msg) => { if builder.config.json_output { // Forward JSON to stdout. - println!("{line}"); + eprintln!("{line}"); } cb(msg) } From 3c3512cf8ceea2e0aed9c2bab32b3b8b0ed68c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Thu, 12 Dec 2024 19:24:01 +0800 Subject: [PATCH 09/10] Revert "Rollup merge of #134040 - clubby789:bootstrap-eprintln, r=jieyouxu" This reverts commit b282774aaf0aa05b4a9855d973b67e7e424c2136, reversing changes made to e0f3db0056288a06b1ae36cdd70741a4e0b3584a. --- src/bootstrap/src/bin/main.rs | 20 +++---- src/bootstrap/src/bin/rustc.rs | 2 +- src/bootstrap/src/core/build_steps/check.rs | 2 +- src/bootstrap/src/core/build_steps/compile.rs | 10 ++-- src/bootstrap/src/core/build_steps/dist.rs | 2 +- src/bootstrap/src/core/build_steps/format.rs | 6 +- src/bootstrap/src/core/build_steps/setup.rs | 46 +++++++------- src/bootstrap/src/core/build_steps/suggest.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 6 +- src/bootstrap/src/core/builder/cargo.rs | 2 +- src/bootstrap/src/core/builder/mod.rs | 14 ++--- src/bootstrap/src/core/config/config.rs | 60 +++++++++---------- src/bootstrap/src/core/config/flags.rs | 4 +- src/bootstrap/src/core/download.rs | 26 ++++---- src/bootstrap/src/core/sanity.rs | 4 +- src/bootstrap/src/lib.rs | 28 ++++----- src/bootstrap/src/utils/cc_detect.rs | 10 ++-- src/bootstrap/src/utils/helpers.rs | 6 +- src/bootstrap/src/utils/metrics.rs | 2 +- src/bootstrap/src/utils/render_tests.rs | 50 ++++++++-------- src/bootstrap/src/utils/tarball.rs | 2 +- src/tools/compiletest/src/compute_diff.rs | 2 +- src/tools/compiletest/src/debuggers.rs | 6 +- src/tools/compiletest/src/lib.rs | 10 ++-- src/tools/compiletest/src/runtest.rs | 52 ++++++++-------- .../compiletest/src/runtest/codegen_units.rs | 22 +++---- .../compiletest/src/runtest/debuginfo.rs | 10 ++-- .../compiletest/src/runtest/incremental.rs | 2 +- src/tools/compiletest/src/runtest/mir_opt.rs | 2 +- .../compiletest/src/runtest/rustdoc_json.rs | 2 +- src/tools/compiletest/src/runtest/ui.rs | 4 +- src/tools/compiletest/src/util.rs | 2 +- 32 files changed, 207 insertions(+), 211 deletions(-) diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 74dfe2e7ec80f..ee813de1c9e26 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -48,9 +48,9 @@ fn main() { err => { drop(err); if let Ok(pid) = pid { - eprintln!("WARNING: build directory locked by process {pid}, waiting for lock"); + println!("WARNING: build directory locked by process {pid}, waiting for lock"); } else { - eprintln!("WARNING: build directory locked, waiting for lock"); + println!("WARNING: build directory locked, waiting for lock"); } let mut lock = t!(build_lock.write()); t!(lock.write(process::id().to_string().as_ref())); @@ -70,13 +70,13 @@ fn main() { // changelog warning, not the `x.py setup` message. let suggest_setup = config.config.is_none() && !matches!(config.cmd, Subcommand::Setup { .. }); if suggest_setup { - eprintln!("WARNING: you have not made a `config.toml`"); - eprintln!( + println!("WARNING: you have not made a `config.toml`"); + println!( "HELP: consider running `./x.py setup` or copying `config.example.toml` by running \ `cp config.example.toml config.toml`" ); } else if let Some(suggestion) = &changelog_suggestion { - eprintln!("{suggestion}"); + println!("{suggestion}"); } let pre_commit = config.src.join(".git").join("hooks").join("pre-commit"); @@ -86,13 +86,13 @@ fn main() { Build::new(config).build(); if suggest_setup { - eprintln!("WARNING: you have not made a `config.toml`"); - eprintln!( + println!("WARNING: you have not made a `config.toml`"); + println!( "HELP: consider running `./x.py setup` or copying `config.example.toml` by running \ `cp config.example.toml config.toml`" ); } else if let Some(suggestion) = &changelog_suggestion { - eprintln!("{suggestion}"); + println!("{suggestion}"); } // Give a warning if the pre-commit script is in pre-commit and not pre-push. @@ -102,14 +102,14 @@ fn main() { if fs::read_to_string(pre_commit).is_ok_and(|contents| { contents.contains("/~https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570") }) { - eprintln!( + println!( "WARNING: You have the pre-push script installed to .git/hooks/pre-commit. \ Consider moving it to .git/hooks/pre-push instead, which runs less often." ); } if suggest_setup || changelog_suggestion.is_some() { - eprintln!("NOTE: this message was printed twice to make it more likely to be seen"); + println!("NOTE: this message was printed twice to make it more likely to be seen"); } if dump_bootstrap_shims { diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index e57ed488f973e..88595ff7e5198 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -306,7 +306,7 @@ fn main() { // should run on success, after this block. } if verbose > 0 { - eprintln!("\nDid not run successfully: {status}\n{cmd:?}\n-------------"); + println!("\nDid not run successfully: {status}\n{cmd:?}\n-------------"); } if let Some(mut on_fail) = on_fail { diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 2af2e83db8f76..d46c0ab7fefcf 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -287,7 +287,7 @@ impl Step for CodegenBackend { fn run(self, builder: &Builder<'_>) { // FIXME: remove once /~https://github.com/rust-lang/rust/issues/112393 is resolved if builder.build.config.vendor && self.backend == "gcc" { - eprintln!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled."); + println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled."); return; } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 4419b11ac1971..0cacd6e4f37ac 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1611,7 +1611,7 @@ impl Step for Sysroot { let sysroot = sysroot_dir(compiler.stage); builder - .verbose(|| eprintln!("Removing sysroot {} to avoid caching bugs", sysroot.display())); + .verbose(|| println!("Removing sysroot {} to avoid caching bugs", sysroot.display())); let _ = fs::remove_dir_all(&sysroot); t!(fs::create_dir_all(&sysroot)); @@ -1681,7 +1681,7 @@ impl Step for Sysroot { return true; } if !filtered_files.iter().all(|f| f != path.file_name().unwrap()) { - builder.verbose_than(1, || eprintln!("ignoring {}", path.display())); + builder.verbose_than(1, || println!("ignoring {}", path.display())); false } else { true @@ -2240,7 +2240,7 @@ pub fn stream_cargo( cargo.arg(arg); } - builder.verbose(|| eprintln!("running: {cargo:?}")); + builder.verbose(|| println!("running: {cargo:?}")); if builder.config.dry_run() { return true; @@ -2261,12 +2261,12 @@ pub fn stream_cargo( Ok(msg) => { if builder.config.json_output { // Forward JSON to stdout. - eprintln!("{line}"); + println!("{line}"); } cb(msg) } // If this was informational, just print it out and continue - Err(_) => eprintln!("{line}"), + Err(_) => println!("{line}"), } } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 57fce206f954b..0c739115165ec 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2080,7 +2080,7 @@ fn maybe_install_llvm( { let mut cmd = command(llvm_config); cmd.arg("--libfiles"); - builder.verbose(|| eprintln!("running {cmd:?}")); + builder.verbose(|| println!("running {cmd:?}")); let files = cmd.run_capture_stdout(builder).stdout(); let build_llvm_out = &builder.llvm_out(builder.config.build); let target_llvm_out = &builder.llvm_out(target); diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index d32e06d8748ac..29a96f7767281 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -107,10 +107,10 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) { if let Some(adjective) = adjective { format!("{adjective} ") } else { String::new() }; if len <= 10 { for path in paths { - eprintln!("fmt: {verb} {adjective}file {path}"); + println!("fmt: {verb} {adjective}file {path}"); } } else { - eprintln!("fmt: {verb} {len} {adjective}files"); + println!("fmt: {verb} {len} {adjective}files"); } } @@ -199,7 +199,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { match get_modified_rs_files(build) { Ok(Some(files)) => { if files.is_empty() { - eprintln!("fmt info: No modified files detected for formatting."); + println!("fmt info: No modified files detected for formatting."); return; } diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 175e9982cc14e..7ed01f25c94b2 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -134,7 +134,7 @@ impl Step for Profile { t!(fs::remove_file(path)); } _ => { - eprintln!("Exiting."); + println!("Exiting."); crate::exit!(1); } } @@ -184,15 +184,15 @@ pub fn setup(config: &Config, profile: Profile) { Profile::Dist => &["dist", "build"], }; - eprintln!(); + println!(); - eprintln!("To get started, try one of the following commands:"); + println!("To get started, try one of the following commands:"); for cmd in suggestions { - eprintln!("- `x.py {cmd}`"); + println!("- `x.py {cmd}`"); } if profile != Profile::Dist { - eprintln!( + println!( "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html" ); } @@ -224,7 +224,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) { t!(fs::write(path, settings)); let include_path = profile.include_path(&config.src); - eprintln!("`x.py` will now use the configuration at {}", include_path.display()); + println!("`x.py` will now use the configuration at {}", include_path.display()); } /// Creates a toolchain link for stage1 using `rustup` @@ -256,7 +256,7 @@ impl Step for Link { } if !rustup_installed(builder) { - eprintln!("WARNING: `rustup` is not installed; Skipping `stage1` toolchain linking."); + println!("WARNING: `rustup` is not installed; Skipping `stage1` toolchain linking."); return; } @@ -296,7 +296,7 @@ fn attempt_toolchain_link(builder: &Builder<'_>, stage_path: &str) { } if try_link_toolchain(builder, stage_path) { - eprintln!( + println!( "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain" ); } else { @@ -321,14 +321,14 @@ fn toolchain_is_linked(builder: &Builder<'_>) -> bool { return false; } // The toolchain has already been linked. - eprintln!( + println!( "`stage1` toolchain already linked; not attempting to link `stage1` toolchain" ); } None => { // In this case, we don't know if the `stage1` toolchain has been linked; // but `rustup` failed, so let's not go any further. - eprintln!( + println!( "`rustup` failed to list current toolchains; not attempting to link `stage1` toolchain" ); } @@ -389,12 +389,12 @@ pub fn interactive_path() -> io::Result { input.parse() } - eprintln!("Welcome to the Rust project! What do you want to do with x.py?"); + println!("Welcome to the Rust project! What do you want to do with x.py?"); for ((letter, _), profile) in abbrev_all() { - eprintln!("{}) {}: {}", letter, profile, profile.purpose()); + println!("{}) {}: {}", letter, profile, profile.purpose()); } let template = loop { - eprint!( + print!( "Please choose one ({}): ", abbrev_all().map(|((l, _), _)| l).collect::>().join("/") ); @@ -428,7 +428,7 @@ enum PromptResult { fn prompt_user(prompt: &str) -> io::Result> { let mut input = String::new(); loop { - eprint!("{prompt} "); + print!("{prompt} "); io::stdout().flush()?; input.clear(); io::stdin().read_line(&mut input)?; @@ -490,7 +490,7 @@ fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result< return Ok(()); } - eprintln!( + println!( "\nRust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality. If you'd like, x.py can install a git hook for you that will automatically run `test tidy` before pushing your code to ensure your code is up to par. If you decide later that this behavior is @@ -498,7 +498,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks." ); if prompt_user("Would you like to install the git hook?: [y/N]")? != Some(PromptResult::Yes) { - eprintln!("Ok, skipping installation!"); + println!("Ok, skipping installation!"); return Ok(()); } if !hooks_dir.exists() { @@ -515,7 +515,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks." ); return Err(e); } - Ok(_) => eprintln!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"), + Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"), }; Ok(()) } @@ -541,7 +541,7 @@ Select which editor you would like to set up [default: None]: "; let mut input = String::new(); loop { - eprint!("{}", prompt_str); + print!("{}", prompt_str); io::stdout().flush()?; input.clear(); io::stdin().read_line(&mut input)?; @@ -656,7 +656,7 @@ impl Step for Editor { if let Some(editor_kind) = editor_kind { while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {} } else { - eprintln!("Ok, skipping editor setup!"); + println!("Ok, skipping editor setup!"); } } Err(e) => eprintln!("Could not determine the editor: {e}"), @@ -689,7 +689,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu mismatched_settings = Some(false); } } - eprintln!( + println!( "\nx.py can automatically install the recommended `{settings_filename}` file for rustc development" ); @@ -708,7 +708,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu Some(PromptResult::Yes) => true, Some(PromptResult::Print) => false, _ => { - eprintln!("Ok, skipping settings!"); + println!("Ok, skipping settings!"); return Ok(true); } }; @@ -735,9 +735,9 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu _ => "Created", }; fs::write(&settings_path, editor.settings_template())?; - eprintln!("{verb} `{}`", settings_filename); + println!("{verb} `{}`", settings_filename); } else { - eprintln!("\n{}", editor.settings_template()); + println!("\n{}", editor.settings_template()); } Ok(should_create) } diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index 7b2d9fff8f5f0..ba9b1b2fc3317 100644 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -66,6 +66,6 @@ pub fn suggest(builder: &Builder<'_>, run: bool) { build.build(); } } else { - eprintln!("HELP: consider using the `--run` flag to automatically run suggested tests"); + println!("HELP: consider using the `--run` flag to automatically run suggested tests"); } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 380626952b25f..30fdea7e19e51 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -471,11 +471,11 @@ impl Miri { // We re-use the `cargo` from above. cargo.arg("--print-sysroot"); - builder.verbose(|| eprintln!("running: {cargo:?}")); + builder.verbose(|| println!("running: {cargo:?}")); let stdout = cargo.run_capture_stdout(builder).stdout(); // Output is "\n". let sysroot = stdout.trim_end(); - builder.verbose(|| eprintln!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); + builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); PathBuf::from(sysroot) } } @@ -2488,7 +2488,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> } } - builder.verbose(|| eprintln!("doc tests for: {}", markdown.display())); + builder.verbose(|| println!("doc tests for: {}", markdown.display())); let mut cmd = builder.rustdoc_cmd(compiler); builder.add_rust_test_threads(&mut cmd); // allow for unstable options such as new editions diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 38abca8b8da17..77f6edaabb248 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -523,7 +523,7 @@ impl Builder<'_> { let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8"); if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) { - eprintln!("using sysroot {sysroot_str}"); + println!("using sysroot {sysroot_str}"); } let mut rustflags = Rustflags::new(target); diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index ffe3e053e7247..026c26479d355 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -392,14 +392,14 @@ impl StepDescription { fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool { if builder.config.skip.iter().any(|e| pathset.has(e, builder.kind)) { if !matches!(builder.config.dry_run, DryRun::SelfCheck) { - eprintln!("Skipping {pathset:?} because it is excluded"); + println!("Skipping {pathset:?} because it is excluded"); } return true; } if !builder.config.skip.is_empty() && !matches!(builder.config.dry_run, DryRun::SelfCheck) { builder.verbose(|| { - eprintln!( + println!( "{:?} not skipped for {:?} -- not in {:?}", pathset, self.name, builder.config.skip ) @@ -1437,11 +1437,11 @@ impl<'a> Builder<'a> { panic!("{}", out); } if let Some(out) = self.cache.get(&step) { - self.verbose_than(1, || eprintln!("{}c {:?}", " ".repeat(stack.len()), step)); + self.verbose_than(1, || println!("{}c {:?}", " ".repeat(stack.len()), step)); return out; } - self.verbose_than(1, || eprintln!("{}> {:?}", " ".repeat(stack.len()), step)); + self.verbose_than(1, || println!("{}> {:?}", " ".repeat(stack.len()), step)); stack.push(Box::new(step.clone())); } @@ -1462,7 +1462,7 @@ impl<'a> Builder<'a> { let step_string = format!("{step:?}"); let brace_index = step_string.find('{').unwrap_or(0); let type_string = type_name::(); - eprintln!( + println!( "[TIMING] {} {} -- {}.{:03}", &type_string.strip_prefix("bootstrap::").unwrap_or(type_string), &step_string[brace_index..], @@ -1479,9 +1479,7 @@ impl<'a> Builder<'a> { let cur_step = stack.pop().expect("step stack empty"); assert_eq!(cur_step.downcast_ref(), Some(&step)); } - self.verbose_than(1, || { - eprintln!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step) - }); + self.verbose_than(1, || println!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step)); self.cache.put(step, out.clone()); out } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 002b990bb5280..c6800aedca971 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1299,7 +1299,7 @@ impl Config { .map(|change_id| change_id.inner.map(crate::find_recent_config_change_ids)) { if !changes.is_empty() { - eprintln!( + println!( "WARNING: There have been changes to x.py since you last updated:\n{}", crate::human_readable_changes(&changes) ); @@ -1565,7 +1565,7 @@ impl Config { } if cargo_clippy.is_some() && rustc.is_none() { - eprintln!( + println!( "WARNING: Using `build.cargo-clippy` without `build.rustc` usually fails due to toolchain conflict." ); } @@ -1852,7 +1852,7 @@ impl Config { // FIXME: Remove this option at the end of 2024. if parallel_compiler.is_some() { - eprintln!( + println!( "WARNING: The `rust.parallel-compiler` option is deprecated and does nothing. The parallel compiler (with one thread) is now the default" ); } @@ -1884,7 +1884,7 @@ impl Config { if available_backends.contains(&backend) { panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'."); } else { - eprintln!("HELP: '{s}' for 'rust.codegen-backends' might fail. \ + println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \ Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ In this case, it would be referred to as '{backend}'."); } @@ -1913,7 +1913,7 @@ impl Config { // tests may fail due to using a different channel than the one used by the compiler during tests. if let Some(commit) = &config.download_rustc_commit { if is_user_configured_rust_channel { - eprintln!( + println!( "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel." ); @@ -2003,10 +2003,10 @@ impl Config { if config.llvm_from_ci { let warn = |option: &str| { - eprintln!( + println!( "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build." ); - eprintln!( + println!( "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false." ); }; @@ -2025,12 +2025,12 @@ impl Config { // if they've chosen a different value. if libzstd.is_some() { - eprintln!( + println!( "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \ like almost all `llvm.*` options, will be ignored and set by the LLVM CI \ artifacts builder config." ); - eprintln!( + println!( "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false." ); } @@ -2099,7 +2099,7 @@ impl Config { if available_backends.contains(&backend) { panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'."); } else { - eprintln!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ + println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ In this case, it would be referred to as '{backend}'."); } @@ -2315,7 +2315,7 @@ impl Config { if self.dry_run() { return Ok(()); } - self.verbose(|| eprintln!("running: {cmd:?}")); + self.verbose(|| println!("running: {cmd:?}")); build_helper::util::try_run(cmd, self.is_verbose()) } @@ -2490,7 +2490,7 @@ impl Config { // This happens when LLVM submodule is updated in CI, we should disable ci-rustc without an error // to not break CI. For non-CI environments, we should return an error. if CiEnv::is_ci() { - eprintln!("WARNING: LLVM submodule has changes, `download-rustc` will be disabled."); + println!("WARNING: LLVM submodule has changes, `download-rustc` will be disabled."); return None; } else { panic!("ERROR: LLVM submodule has changes, `download-rustc` can't be used."); @@ -2501,8 +2501,8 @@ impl Config { let ci_config_toml = match self.get_builder_toml("ci-rustc") { Ok(ci_config_toml) => ci_config_toml, Err(e) if e.to_string().contains("unknown field") => { - eprintln!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled."); - eprintln!("HELP: Consider rebasing to a newer commit if available."); + println!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled."); + println!("HELP: Consider rebasing to a newer commit if available."); return None; }, Err(e) => { @@ -2527,7 +2527,7 @@ impl Config { .is_some_and(|s| s == "1" || s == "true"); if disable_ci_rustc_if_incompatible && res.is_err() { - eprintln!("WARNING: download-rustc is disabled with `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` env."); + println!("WARNING: download-rustc is disabled with `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` env."); return None; } @@ -2712,7 +2712,7 @@ impl Config { return; } - eprintln!("Updating submodule {relative_path}"); + println!("Updating submodule {relative_path}"); self.check_run( helpers::git(Some(&self.src)) .run_always() @@ -2835,7 +2835,7 @@ impl Config { Some(StringOrBool::Bool(true)) => false, Some(StringOrBool::String(s)) if s == "if-unchanged" => { if !self.rust_info.is_managed_git_subrepository() { - eprintln!( + println!( "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources." ); crate::exit!(1); @@ -2868,10 +2868,10 @@ impl Config { if if_unchanged { return None; } - eprintln!("ERROR: could not find commit hash for downloading rustc"); - eprintln!("HELP: maybe your repository history is too shallow?"); - eprintln!("HELP: consider setting `rust.download-rustc=false` in config.toml"); - eprintln!("HELP: or fetch enough history to include one upstream commit"); + println!("ERROR: could not find commit hash for downloading rustc"); + println!("HELP: maybe your repository history is too shallow?"); + println!("HELP: consider setting `rust.download-rustc=false` in config.toml"); + println!("HELP: or fetch enough history to include one upstream commit"); crate::exit!(1); } }; @@ -2910,7 +2910,7 @@ impl Config { let if_unchanged = || { if self.rust_info.is_from_tarball() { // Git is needed for running "if-unchanged" logic. - eprintln!( + println!( "WARNING: 'if-unchanged' has no effect on tarball sources; ignoring `download-ci-llvm`." ); return false; @@ -2959,10 +2959,10 @@ impl Config { // Only commits merged by bors will have CI artifacts. let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap(); if commit.is_empty() { - eprintln!("error: could not find commit hash for downloading components from CI"); - eprintln!("help: maybe your repository history is too shallow?"); - eprintln!("help: consider disabling `{option_name}`"); - eprintln!("help: or fetch enough history to include one upstream commit"); + println!("error: could not find commit hash for downloading components from CI"); + println!("help: maybe your repository history is too shallow?"); + println!("help: consider disabling `{option_name}`"); + println!("help: or fetch enough history to include one upstream commit"); crate::exit!(1); } @@ -2974,14 +2974,14 @@ impl Config { if has_changes { if if_unchanged { if self.is_verbose() { - eprintln!( + println!( "warning: saw changes to one of {modified_paths:?} since {commit}; \ ignoring `{option_name}`" ); } return None; } - eprintln!( + println!( "warning: `{option_name}` is enabled, but there are changes to one of {modified_paths:?}" ); } @@ -3018,7 +3018,7 @@ pub(crate) fn check_incompatible_options_for_ci_llvm( ($current:expr, $expected:expr) => { if let Some(current) = &$current { if Some(current) != $expected.as_ref() { - eprintln!( + println!( "WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \ Current value: {:?}, Expected value(s): {}{:?}", stringify!($expected).replace("_", "-"), @@ -3123,7 +3123,7 @@ fn check_incompatible_options_for_ci_rustc( ($current:expr, $expected:expr, $config_section:expr) => { if let Some(current) = &$current { if Some(current) != $expected.as_ref() { - eprintln!( + println!( "WARNING: `{}` has no effect with `rust.download-rustc`. \ Current value: {:?}, Expected value(s): {}{:?}", format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")), diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 66b9f5ed84e64..bfeb811508c04 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -196,12 +196,12 @@ impl Flags { if let Ok(HelpVerboseOnly { help: true, verbose: 1.., cmd: subcommand }) = HelpVerboseOnly::try_parse_from(normalize_args(args)) { - eprintln!("NOTE: updating submodules before printing available paths"); + println!("NOTE: updating submodules before printing available paths"); let config = Config::parse(Self::parse(&[String::from("build")])); let build = Build::new(config); let paths = Builder::get_help(&build, subcommand); if let Some(s) = paths { - eprintln!("{s}"); + println!("{s}"); } else { panic!("No paths available for subcommand `{}`", subcommand.as_str()); } diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 05b91c518cf4d..db35e6907e661 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -77,7 +77,7 @@ impl Config { if self.dry_run() && !cmd.run_always { return true; } - self.verbose(|| eprintln!("running: {cmd:?}")); + self.verbose(|| println!("running: {cmd:?}")); check_run(cmd, self.is_verbose()) } @@ -144,7 +144,7 @@ impl Config { /// Please see for more information fn fix_bin_or_dylib(&self, fname: &Path) { assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true)); - eprintln!("attempting to patch {}", fname.display()); + println!("attempting to patch {}", fname.display()); // Only build `.nix-deps` once. static NIX_DEPS_DIR: OnceLock = OnceLock::new(); @@ -206,7 +206,7 @@ impl Config { } fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) { - self.verbose(|| eprintln!("download {url}")); + self.verbose(|| println!("download {url}")); // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/. let tempfile = self.tempdir().join(dest_path.file_name().unwrap()); // While bootstrap itself only supports http and https downloads, downstream forks might @@ -226,7 +226,7 @@ impl Config { } fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) { - eprintln!("downloading {url}"); + println!("downloading {url}"); // Try curl. If that fails and we are on windows, fallback to PowerShell. // options should be kept in sync with // src/bootstrap/src/core/download.rs @@ -341,7 +341,7 @@ impl Config { short_path = short_path.strip_prefix(pattern).unwrap_or(short_path); let dst_path = dst.join(short_path); self.verbose(|| { - eprintln!("extracting {} to {}", original_path.display(), dst.display()) + println!("extracting {} to {}", original_path.display(), dst.display()) }); if !t!(member.unpack_in(dst)) { panic!("path traversal attack ??"); @@ -365,7 +365,7 @@ impl Config { pub(crate) fn verify(&self, path: &Path, expected: &str) -> bool { use sha2::Digest; - self.verbose(|| eprintln!("verifying {}", path.display())); + self.verbose(|| println!("verifying {}", path.display())); if self.dry_run() { return false; @@ -391,7 +391,7 @@ impl Config { let verified = checksum == expected; if !verified { - eprintln!( + println!( "invalid checksum: \n\ found: {checksum}\n\ expected: {expected}", @@ -421,7 +421,7 @@ enum DownloadSource { /// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions. impl Config { pub(crate) fn download_clippy(&self) -> PathBuf { - self.verbose(|| eprintln!("downloading stage0 clippy artifacts")); + self.verbose(|| println!("downloading stage0 clippy artifacts")); let date = &self.stage0_metadata.compiler.date; let version = &self.stage0_metadata.compiler.version; @@ -518,7 +518,7 @@ impl Config { } pub(crate) fn download_ci_rustc(&self, commit: &str) { - self.verbose(|| eprintln!("using downloaded stage2 artifacts from CI (commit {commit})")); + self.verbose(|| println!("using downloaded stage2 artifacts from CI (commit {commit})")); let version = self.artifact_version_part(commit); // download-rustc doesn't need its own cargo, it can just use beta's. But it does need the @@ -539,7 +539,7 @@ impl Config { #[cfg(not(feature = "bootstrap-self-test"))] pub(crate) fn download_beta_toolchain(&self) { - self.verbose(|| eprintln!("downloading stage0 beta artifacts")); + self.verbose(|| println!("downloading stage0 beta artifacts")); let date = &self.stage0_metadata.compiler.date; let version = &self.stage0_metadata.compiler.version; @@ -677,7 +677,7 @@ impl Config { return; } else { self.verbose(|| { - eprintln!( + println!( "ignoring cached file {} due to failed verification", tarball.display() ) @@ -776,10 +776,10 @@ download-rustc = false t!(check_incompatible_options_for_ci_llvm(current_config_toml, ci_config_toml)); } Err(e) if e.to_string().contains("unknown field") => { - eprintln!( + println!( "WARNING: CI LLVM has some fields that are no longer supported in bootstrap; download-ci-llvm will be disabled." ); - eprintln!("HELP: Consider rebasing to a newer commit if available."); + println!("HELP: Consider rebasing to a newer commit if available."); } Err(e) => { eprintln!("ERROR: Failed to parse CI LLVM config.toml: {e}"); diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 71e7f40f0320a..dcf68cbeeda71 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -237,11 +237,11 @@ than building it. stage0_supported_target_list.intersection(&missing_targets_hashset).collect(); if !duplicated_targets.is_empty() { - eprintln!( + println!( "Following targets supported from the stage0 compiler, please remove them from STAGE0_MISSING_TARGETS list." ); for duplicated_target in duplicated_targets { - eprintln!(" {duplicated_target}"); + println!(" {duplicated_target}"); } std::process::exit(1); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 5f778223d7dac..0ecf61ffcd903 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -406,11 +406,11 @@ impl Build { .unwrap() .trim(); if local_release.split('.').take(2).eq(version.split('.').take(2)) { - build.verbose(|| eprintln!("auto-detected local-rebuild {local_release}")); + build.verbose(|| println!("auto-detected local-rebuild {local_release}")); build.local_rebuild = true; } - build.verbose(|| eprintln!("finding compilers")); + build.verbose(|| println!("finding compilers")); utils::cc_detect::find(&build); // When running `setup`, the profile is about to change, so any requirements we have now may // be different on the next invocation. Don't check for them until the next time x.py is @@ -418,7 +418,7 @@ impl Build { // // Similarly, for `setup` we don't actually need submodules or cargo metadata. if !matches!(build.config.cmd, Subcommand::Setup { .. }) { - build.verbose(|| eprintln!("running sanity check")); + build.verbose(|| println!("running sanity check")); crate::core::sanity::check(&mut build); // Make sure we update these before gathering metadata so we don't get an error about missing @@ -436,7 +436,7 @@ impl Build { // Now, update all existing submodules. build.update_existing_submodules(); - build.verbose(|| eprintln!("learning about cargo")); + build.verbose(|| println!("learning about cargo")); crate::core::metadata::build(&mut build); } @@ -605,7 +605,7 @@ impl Build { let stamp = dir.join(".stamp"); let mut cleared = false; if mtime(&stamp) < mtime(input) { - self.verbose(|| eprintln!("Dirty - {}", dir.display())); + self.verbose(|| println!("Dirty - {}", dir.display())); let _ = fs::remove_dir_all(dir); cleared = true; } else if stamp.exists() { @@ -890,7 +890,7 @@ impl Build { let executed_at = std::panic::Location::caller(); self.verbose(|| { - eprintln!("running: {command:?} (created at {created_at}, executed at {executed_at})") + println!("running: {command:?} (created at {created_at}, executed at {executed_at})") }); let cmd = command.as_command_mut(); @@ -947,7 +947,7 @@ Executed at: {executed_at}"#, let fail = |message: &str, output: CommandOutput| -> ! { if self.is_verbose() { - eprintln!("{message}"); + println!("{message}"); } else { let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present()); // If the command captures output, the user would not see any indication that @@ -957,16 +957,16 @@ Executed at: {executed_at}"#, if let Some(stdout) = output.stdout_if_present().take_if(|s| !s.trim().is_empty()) { - eprintln!("STDOUT:\n{stdout}\n"); + println!("STDOUT:\n{stdout}\n"); } if let Some(stderr) = output.stderr_if_present().take_if(|s| !s.trim().is_empty()) { - eprintln!("STDERR:\n{stderr}\n"); + println!("STDERR:\n{stderr}\n"); } - eprintln!("Command {command:?} has failed. Rerun with -v to see more details."); + println!("Command {command:?} has failed. Rerun with -v to see more details."); } else { - eprintln!("Command has failed. Rerun with -v to see more details."); + println!("Command has failed. Rerun with -v to see more details."); } } exit!(1); @@ -1011,7 +1011,7 @@ Executed at: {executed_at}"#, match self.config.dry_run { DryRun::SelfCheck => (), DryRun::Disabled | DryRun::UserSelected => { - eprintln!("{msg}"); + println!("{msg}"); } } } @@ -1666,7 +1666,7 @@ Executed at: {executed_at}"#, if self.config.dry_run() { return; } - self.verbose_than(1, || eprintln!("Copy/Link {src:?} to {dst:?}")); + self.verbose_than(1, || println!("Copy/Link {src:?} to {dst:?}")); if src == dst { return; } @@ -1775,7 +1775,7 @@ Executed at: {executed_at}"#, return; } let dst = dstdir.join(src.file_name().unwrap()); - self.verbose_than(1, || eprintln!("Install {src:?} to {dst:?}")); + self.verbose_than(1, || println!("Install {src:?} to {dst:?}")); t!(fs::create_dir_all(dstdir)); if !src.exists() { panic!("ERROR: File \"{}\" not found!", src.display()); diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index e8d5b60948aa8..0df0046945220 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -155,15 +155,15 @@ pub fn find_target(build: &Build, target: TargetSelection) { build.cxx.borrow_mut().insert(target, compiler); } - build.verbose(|| eprintln!("CC_{} = {:?}", target.triple, build.cc(target))); - build.verbose(|| eprintln!("CFLAGS_{} = {cflags:?}", target.triple)); + build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target))); + build.verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple)); if let Ok(cxx) = build.cxx(target) { let cxxflags = build.cflags(target, GitRepo::Rustc, CLang::Cxx); - build.verbose(|| eprintln!("CXX_{} = {cxx:?}", target.triple)); - build.verbose(|| eprintln!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); + build.verbose(|| println!("CXX_{} = {cxx:?}", target.triple)); + build.verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); } if let Some(ar) = ar { - build.verbose(|| eprintln!("AR_{} = {ar:?}", target.triple)); + build.verbose(|| println!("AR_{} = {ar:?}", target.triple)); build.ar.borrow_mut().insert(target, ar); } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index c0d52fd343059..923cc2dfc28ce 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -135,7 +135,7 @@ impl Drop for TimeIt { fn drop(&mut self) { let time = self.1.elapsed(); if !self.0 { - eprintln!("\tfinished in {}.{:03} seconds", time.as_secs(), time.subsec_millis()); + println!("\tfinished in {}.{:03} seconds", time.as_secs(), time.subsec_millis()); } } } @@ -267,12 +267,12 @@ pub fn check_run(cmd: &mut BootstrapCommand, print_cmd_on_fail: bool) -> bool { let status = match cmd.as_command_mut().status() { Ok(status) => status, Err(e) => { - eprintln!("failed to execute command: {cmd:?}\nERROR: {e}"); + println!("failed to execute command: {cmd:?}\nERROR: {e}"); return false; } }; if !status.success() && print_cmd_on_fail { - eprintln!( + println!( "\n\ncommand did not execute successfully: {cmd:?}\n\ expected success, got: {status}\n\n" ); diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs index 06d3add6281f8..b51fd490535a3 100644 --- a/src/bootstrap/src/utils/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -185,7 +185,7 @@ impl BuildMetrics { if version.format_version == CURRENT_FORMAT_VERSION { t!(serde_json::from_slice::(&contents)).invocations } else { - eprintln!( + println!( "WARNING: overriding existing build/metrics.json, as it's not \ compatible with build metrics format version {CURRENT_FORMAT_VERSION}." ); diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 7a3ec61c6da0a..eb2c8254dc0f4 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -56,7 +56,7 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> let cmd = cmd.as_command_mut(); cmd.stdout(Stdio::piped()); - builder.verbose(|| eprintln!("running: {cmd:?}")); + builder.verbose(|| println!("running: {cmd:?}")); let mut process = cmd.spawn().unwrap(); @@ -71,7 +71,7 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> let result = process.wait_with_output().unwrap(); if !result.status.success() && builder.is_verbose() { - eprintln!( + println!( "\n\ncommand did not execute successfully: {cmd:?}\n\ expected success, got: {}", result.status @@ -135,9 +135,7 @@ impl<'a> Renderer<'a> { if self.up_to_date_tests > 0 { let n = self.up_to_date_tests; let s = if n > 1 { "s" } else { "" }; - eprintln!( - "help: ignored {n} up-to-date test{s}; use `--force-rerun` to prevent this\n" - ); + println!("help: ignored {n} up-to-date test{s}; use `--force-rerun` to prevent this\n"); } } @@ -187,12 +185,12 @@ impl<'a> Renderer<'a> { } fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) { - eprint!("test {} ... ", test.name); - self.builder.colored_stderr(|stdout| outcome.write_long(stdout)).unwrap(); + print!("test {} ... ", test.name); + self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); if let Some(exec_time) = test.exec_time { - eprint!(" ({exec_time:.2?})"); + print!(" ({exec_time:.2?})"); } - eprintln!(); + println!(); } fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, test: &TestOutcome) { @@ -200,45 +198,45 @@ impl<'a> Renderer<'a> { if let Some(total) = self.tests_count { let total = total.to_string(); let executed = format!("{:>width$}", self.executed_tests - 1, width = total.len()); - eprint!(" {executed}/{total}"); + print!(" {executed}/{total}"); } - eprintln!(); + println!(); self.terse_tests_in_line = 0; } self.terse_tests_in_line += 1; - self.builder.colored_stderr(|stdout| outcome.write_short(stdout, &test.name)).unwrap(); + self.builder.colored_stdout(|stdout| outcome.write_short(stdout, &test.name)).unwrap(); let _ = std::io::stdout().flush(); } fn render_suite_outcome(&self, outcome: Outcome<'_>, suite: &SuiteOutcome) { // The terse output doesn't end with a newline, so we need to add it ourselves. if !self.builder.config.verbose_tests { - eprintln!(); + println!(); } if !self.failures.is_empty() { - eprintln!("\nfailures:\n"); + println!("\nfailures:\n"); for failure in &self.failures { if failure.stdout.is_some() || failure.message.is_some() { - eprintln!("---- {} stdout ----", failure.name); + println!("---- {} stdout ----", failure.name); if let Some(stdout) = &failure.stdout { - eprintln!("{stdout}"); + println!("{stdout}"); } if let Some(message) = &failure.message { - eprintln!("NOTE: {message}"); + println!("NOTE: {message}"); } } } - eprintln!("\nfailures:"); + println!("\nfailures:"); for failure in &self.failures { - eprintln!(" {}", failure.name); + println!(" {}", failure.name); } } if !self.benches.is_empty() { - eprintln!("\nbenchmarks:"); + println!("\nbenchmarks:"); let mut rows = Vec::new(); for bench in &self.benches { @@ -253,13 +251,13 @@ impl<'a> Renderer<'a> { let max_1 = rows.iter().map(|r| r.1.len()).max().unwrap_or(0); let max_2 = rows.iter().map(|r| r.2.len()).max().unwrap_or(0); for row in &rows { - eprintln!(" {:max_1$} {:>max_2$}", row.0, row.1, row.2); + println!(" {:max_1$} {:>max_2$}", row.0, row.1, row.2); } } - eprint!("\ntest result: "); - self.builder.colored_stderr(|stdout| outcome.write_long(stdout)).unwrap(); - eprintln!( + print!("\ntest result: "); + self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); + println!( ". {} passed; {} failed; {} ignored; {} measured; {} filtered out{time}\n", suite.passed, suite.failed, @@ -276,7 +274,7 @@ impl<'a> Renderer<'a> { fn render_message(&mut self, message: Message) { match message { Message::Suite(SuiteMessage::Started { test_count }) => { - eprintln!("\nrunning {test_count} tests"); + println!("\nrunning {test_count} tests"); self.executed_tests = 0; self.terse_tests_in_line = 0; self.tests_count = Some(test_count); @@ -316,7 +314,7 @@ impl<'a> Renderer<'a> { self.failures.push(outcome); } Message::Test(TestMessage::Timeout { name }) => { - eprintln!("test {name} has been running for a long time"); + println!("test {name} has been running for a long time"); } Message::Test(TestMessage::Started) => {} // Not useful } diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index f60498a4872c4..3c6c7a7fa180a 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -344,7 +344,7 @@ impl<'a> Tarball<'a> { // For `x install` tarball files aren't needed, so we can speed up the process by not producing them. let compression_profile = if self.builder.kind == Kind::Install { self.builder.verbose(|| { - eprintln!("Forcing dist.compression-profile = 'no-op' for `x install`.") + println!("Forcing dist.compression-profile = 'no-op' for `x install`.") }); // "no-op" indicates that the rust-installer won't produce compressed tarball sources. "no-op" diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs index 3ace6c5b6d717..92c80c27de03b 100644 --- a/src/tools/compiletest/src/compute_diff.rs +++ b/src/tools/compiletest/src/compute_diff.rs @@ -144,7 +144,7 @@ where } if !wrote_data { - eprintln!("note: diff is identical to nightly rustdoc"); + println!("note: diff is identical to nightly rustdoc"); assert!(diff_output.metadata().unwrap().len() == 0); return false; } else if verbose { diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs index e75c8a5993e53..b605bc813f195 100644 --- a/src/tools/compiletest/src/debuggers.rs +++ b/src/tools/compiletest/src/debuggers.rs @@ -20,7 +20,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option> { } if config.remote_test_client.is_some() && !config.target.contains("android") { - eprintln!( + println!( "WARNING: debuginfo tests are not available when \ testing with remote" ); @@ -28,7 +28,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option> { } if config.target.contains("android") { - eprintln!( + println!( "{} debug-info test uses tcp 5039 port.\ please reserve it", config.target @@ -50,7 +50,7 @@ pub(crate) fn configure_lldb(config: &Config) -> Option> { config.lldb_python_dir.as_ref()?; if let Some(350) = config.lldb_version { - eprintln!( + println!( "WARNING: The used version of LLDB (350) has a \ known issue that breaks debuginfo tests. See \ issue #32520 for more information. Skipping all \ diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 9acb7d393b461..a5a166af33b6d 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -188,8 +188,8 @@ pub fn parse_config(args: Vec) -> Config { let (argv0, args_) = args.split_first().unwrap(); if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - eprintln!("{}", opts.usage(&message)); - eprintln!(); + println!("{}", opts.usage(&message)); + println!(); panic!() } @@ -200,8 +200,8 @@ pub fn parse_config(args: Vec) -> Config { if matches.opt_present("h") || matches.opt_present("help") { let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - eprintln!("{}", opts.usage(&message)); - eprintln!(); + println!("{}", opts.usage(&message)); + println!(); panic!() } @@ -508,7 +508,7 @@ pub fn run_tests(config: Arc) { // easy to miss which tests failed, and as such fail to reproduce // the failure locally. - eprintln!( + println!( "Some tests failed in compiletest suite={}{} mode={} host={} target={}", config.suite, config diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ca746ed8c55c4..7b11bf3b1219c 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -131,7 +131,7 @@ pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) { if config.verbose { // We're going to be dumping a lot of info. Start on a new line. - eprintln!("\n"); + print!("\n\n"); } debug!("running {:?}", testpaths.file.display()); let mut props = TestProps::from_file(&testpaths.file, revision, &config); @@ -353,7 +353,7 @@ impl<'test> TestCx<'test> { { self.error(&format!("{} test did not emit an error", self.config.mode)); if self.config.mode == crate::common::Mode::Ui { - eprintln!("note: by default, ui tests are expected not to compile"); + println!("note: by default, ui tests are expected not to compile"); } proc_res.fatal(None, || ()); }; @@ -774,20 +774,20 @@ impl<'test> TestCx<'test> { unexpected.len(), not_found.len() )); - eprintln!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline); + println!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline); if !unexpected.is_empty() { - eprintln!("{}", "--- unexpected errors (from JSON output) ---".green()); + println!("{}", "--- unexpected errors (from JSON output) ---".green()); for error in &unexpected { - eprintln!("{}", error.render_for_expected()); + println!("{}", error.render_for_expected()); } - eprintln!("{}", "---".green()); + println!("{}", "---".green()); } if !not_found.is_empty() { - eprintln!("{}", "--- not found errors (from test file) ---".red()); + println!("{}", "--- not found errors (from test file) ---".red()); for error in ¬_found { - eprintln!("{}", error.render_for_expected()); + println!("{}", error.render_for_expected()); } - eprintln!("{}", "---\n".red()); + println!("{}", "---\n".red()); } panic!("errors differ from expected"); } @@ -1876,18 +1876,18 @@ impl<'test> TestCx<'test> { fn maybe_dump_to_stdout(&self, out: &str, err: &str) { if self.config.verbose { - eprintln!("------stdout------------------------------"); - eprintln!("{}", out); - eprintln!("------stderr------------------------------"); - eprintln!("{}", err); - eprintln!("------------------------------------------"); + println!("------stdout------------------------------"); + println!("{}", out); + println!("------stderr------------------------------"); + println!("{}", err); + println!("------------------------------------------"); } } fn error(&self, err: &str) { match self.revision { - Some(rev) => eprintln!("\nerror in revision `{}`: {}", rev, err), - None => eprintln!("\nerror: {}", err), + Some(rev) => println!("\nerror in revision `{}`: {}", rev, err), + None => println!("\nerror: {}", err), } } @@ -1972,7 +1972,7 @@ impl<'test> TestCx<'test> { if !self.config.has_html_tidy { return; } - eprintln!("info: generating a diff against nightly rustdoc"); + println!("info: generating a diff against nightly rustdoc"); let suffix = self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly"); @@ -2082,7 +2082,7 @@ impl<'test> TestCx<'test> { .output() .unwrap(); assert!(output.status.success()); - eprintln!("{}", String::from_utf8_lossy(&output.stdout)); + println!("{}", String::from_utf8_lossy(&output.stdout)); eprintln!("{}", String::from_utf8_lossy(&output.stderr)); } else { use colored::Colorize; @@ -2496,7 +2496,7 @@ impl<'test> TestCx<'test> { )"# ) .replace_all(&output, |caps: &Captures<'_>| { - eprintln!("{}", &caps[0]); + println!("{}", &caps[0]); caps[0].replace(r"\", "/") }) .replace("\r\n", "\n") @@ -2601,14 +2601,14 @@ impl<'test> TestCx<'test> { if let Err(err) = fs::write(&actual_path, &actual) { self.fatal(&format!("failed to write {stream} to `{actual_path:?}`: {err}",)); } - eprintln!("Saved the actual {stream} to {actual_path:?}"); + println!("Saved the actual {stream} to {actual_path:?}"); let expected_path = expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream); if !self.config.bless { if expected.is_empty() { - eprintln!("normalized {}:\n{}\n", stream, actual); + println!("normalized {}:\n{}\n", stream, actual); } else { self.show_diff( stream, @@ -2631,10 +2631,10 @@ impl<'test> TestCx<'test> { if let Err(err) = fs::write(&expected_path, &actual) { self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}")); } - eprintln!("Blessing the {stream} of {test_name} in {expected_path:?}"); + println!("Blessing the {stream} of {test_name} in {expected_path:?}"); } - eprintln!("\nThe actual {0} differed from the expected {0}.", stream); + println!("\nThe actual {0} differed from the expected {0}.", stream); if self.config.bless { 0 } else { 1 } } @@ -2783,7 +2783,7 @@ impl<'test> TestCx<'test> { fs::create_dir_all(&incremental_dir).unwrap(); if self.config.verbose { - eprintln!("init_incremental_test: incremental_dir={}", incremental_dir.display()); + println!("init_incremental_test: incremental_dir={}", incremental_dir.display()); } } @@ -2841,7 +2841,7 @@ impl ProcRes { } } - eprintln!( + println!( "status: {}\ncommand: {}\n{}\n{}\n", self.status, self.cmdline, @@ -2852,7 +2852,7 @@ impl ProcRes { pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! { if let Some(e) = err { - eprintln!("\nerror: {}", e); + println!("\nerror: {}", e); } self.print_info(); on_failure(); diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs index 6acd140183d47..6c866cbef21ab 100644 --- a/src/tools/compiletest/src/runtest/codegen_units.rs +++ b/src/tools/compiletest/src/runtest/codegen_units.rs @@ -64,13 +64,13 @@ impl TestCx<'_> { if !missing.is_empty() { missing.sort(); - eprintln!("\nThese items should have been contained but were not:\n"); + println!("\nThese items should have been contained but were not:\n"); for item in &missing { - eprintln!("{}", item); + println!("{}", item); } - eprintln!("\n"); + println!("\n"); } if !unexpected.is_empty() { @@ -80,24 +80,24 @@ impl TestCx<'_> { sorted }; - eprintln!("\nThese items were contained but should not have been:\n"); + println!("\nThese items were contained but should not have been:\n"); for item in sorted { - eprintln!("{}", item); + println!("{}", item); } - eprintln!("\n"); + println!("\n"); } if !wrong_cgus.is_empty() { wrong_cgus.sort_by_key(|pair| pair.0.name.clone()); - eprintln!("\nThe following items were assigned to wrong codegen units:\n"); + println!("\nThe following items were assigned to wrong codegen units:\n"); for &(ref expected_item, ref actual_item) in &wrong_cgus { - eprintln!("{}", expected_item.name); - eprintln!(" expected: {}", codegen_units_to_str(&expected_item.codegen_units)); - eprintln!(" actual: {}", codegen_units_to_str(&actual_item.codegen_units)); - eprintln!(); + println!("{}", expected_item.name); + println!(" expected: {}", codegen_units_to_str(&expected_item.codegen_units)); + println!(" actual: {}", codegen_units_to_str(&actual_item.codegen_units)); + println!(); } } diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index 7322e730e53f8..c621c22ac993c 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -260,7 +260,7 @@ impl TestCx<'_> { cmdline, }; if adb.kill().is_err() { - eprintln!("Adb process is already finished."); + println!("Adb process is already finished."); } } else { let rust_src_root = @@ -275,7 +275,7 @@ impl TestCx<'_> { match self.config.gdb_version { Some(version) => { - eprintln!("NOTE: compiletest thinks it is using GDB version {}", version); + println!("NOTE: compiletest thinks it is using GDB version {}", version); if version > extract_gdb_version("7.4").unwrap() { // Add the directory containing the pretty printers to @@ -297,7 +297,7 @@ impl TestCx<'_> { } } _ => { - eprintln!( + println!( "NOTE: compiletest does not know which version of \ GDB it is using" ); @@ -392,10 +392,10 @@ impl TestCx<'_> { match self.config.lldb_version { Some(ref version) => { - eprintln!("NOTE: compiletest thinks it is using LLDB version {}", version); + println!("NOTE: compiletest thinks it is using LLDB version {}", version); } _ => { - eprintln!( + println!( "NOTE: compiletest does not know which version of \ LLDB it is using" ); diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs index 4f26786129bde..591aff0defeb0 100644 --- a/src/tools/compiletest/src/runtest/incremental.rs +++ b/src/tools/compiletest/src/runtest/incremental.rs @@ -30,7 +30,7 @@ impl TestCx<'_> { assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir"); if self.config.verbose { - eprint!("revision={:?} props={:#?}", revision, self.props); + print!("revision={:?} props={:#?}", revision, self.props); } if revision.starts_with("cpass") { diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs index 64a2addaa28d3..d1ec00357449d 100644 --- a/src/tools/compiletest/src/runtest/mir_opt.rs +++ b/src/tools/compiletest/src/runtest/mir_opt.rs @@ -89,7 +89,7 @@ impl TestCx<'_> { } let expected_string = fs::read_to_string(&expected_file).unwrap(); if dumped_string != expected_string { - eprint!("{}", write_diff(&expected_string, &dumped_string, 3)); + print!("{}", write_diff(&expected_string, &dumped_string, 3)); panic!( "Actual MIR output differs from expected MIR output {}", expected_file.display() diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs index 84376d346af34..31fdb0a5d13bd 100644 --- a/src/tools/compiletest/src/runtest/rustdoc_json.rs +++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs @@ -29,7 +29,7 @@ impl TestCx<'_> { if !res.status.success() { self.fatal_proc_rec_with_ctx("jsondocck failed!", &res, |_| { - eprintln!("Rustdoc Output:"); + println!("Rustdoc Output:"); proc_res.print_info(); }) } diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index bc860bf18c741..172b1e32aad3b 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -109,10 +109,10 @@ impl TestCx<'_> { } if errors > 0 { - eprintln!("To update references, rerun the tests and pass the `--bless` flag"); + println!("To update references, rerun the tests and pass the `--bless` flag"); let relative_path_to_file = self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap()); - eprintln!( + println!( "To only update this specific test, also pass `--test-args {}`", relative_path_to_file.display(), ); diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 7b50e62c29bb8..bff02f1db9f02 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -30,7 +30,7 @@ fn path_div() -> &'static str { pub fn logv(config: &Config, s: String) { debug!("{}", s); if config.verbose { - eprintln!("{}", s); + println!("{}", s); } } From 86a4a2786f285c5872d0eb9044386c00f7c12847 Mon Sep 17 00:00:00 2001 From: klensy Date: Thu, 12 Dec 2024 19:01:28 +0300 Subject: [PATCH 10/10] fix self shadowed self compare --- src/librustdoc/html/render/search_index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index cfb62c3ca1640..91b31f31ab192 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -201,7 +201,7 @@ pub(crate) fn build_index( // exported from this same module). It's also likely to Do // What I Mean, since if a re-export changes the name, it might // also be a change in semantic meaning. - .filter(|fqp| fqp.last() == fqp.last()); + .filter(|this_fqp| this_fqp.last() == fqp.last()); Some(insert_into_map( itemid_to_pathid, ItemId::DefId(defid),