diff options
| author | bors <bors@rust-lang.org> | 2025-08-09 08:57:23 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-08-09 08:57:23 +0000 |
| commit | ca77504943887037504c7fc0b9bf06dab3910373 (patch) | |
| tree | b2dd467a8b474bcb28c72ddbc3648aee15374b33 /compiler | |
| parent | 2de2456fb7b2b55cb104bb03f30edd145c6015a3 (diff) | |
| parent | d88a309114fa72fa667b5b8078624c8d17035f91 (diff) | |
Auto merge of #145142 - Zalathar:rollup-oi6s8kg, r=Zalathar
Rollup of 23 pull requests
Successful merges:
- rust-lang/rust#141658 (rustdoc search: prefer stable items in search results)
- rust-lang/rust#141828 (Add diagnostic explaining STATUS_STACK_BUFFER_OVERRUN not only being used for stack buffer overruns if link.exe exits with that exit code)
- rust-lang/rust#144823 (coverage: Extract HIR-related helper code out of the main module)
- rust-lang/rust#144883 (Remove unneeded `drop_in_place` calls)
- rust-lang/rust#144923 (Move several more float tests to floats/mod.rs)
- rust-lang/rust#144988 (Add annotations to the graphviz region graph on region origins)
- rust-lang/rust#145010 (Couple of minor abi handling cleanups)
- rust-lang/rust#145017 (Explicitly disable vector feature on s390x baseline of bad-reg test)
- rust-lang/rust#145027 (Optimize `char::is_alphanumeric`)
- rust-lang/rust#145050 (add member constraints tests)
- rust-lang/rust#145073 (update enzyme submodule to handle llvm 21)
- rust-lang/rust#145080 (Escape diff strings in MIR dataflow graphviz)
- rust-lang/rust#145082 (Fix some bad formatting in `-Zmacro-stats` output.)
- rust-lang/rust#145083 (Fix cross-compilation of Cargo)
- rust-lang/rust#145096 (Fix wasm target build with atomics feature)
- rust-lang/rust#145097 (remove unnecessary `TypeFoldable` impls)
- rust-lang/rust#145100 (Rank doc aliases lower than equivalently matched items)
- rust-lang/rust#145103 (rustc_metadata: remove unused private trait impls)
- rust-lang/rust#145115 (defer opaque type errors, generally greatly reduce tainting)
- rust-lang/rust#145119 (rustc_public: fix missing parenthesis in pretty discriminant)
- rust-lang/rust#145124 (Recover `for PAT = EXPR {}`)
- rust-lang/rust#145132 (Refactor map_unit_fn lint)
- rust-lang/rust#145134 (Reduce indirect assoc parent queries)
r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
43 files changed, 373 insertions, 413 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 34bed375cb9..b67dba3af96 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -51,7 +51,7 @@ mod conflict_errors; mod explain_borrow; mod move_errors; mod mutability_errors; -mod opaque_suggestions; +mod opaque_types; mod region_errors; pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo}; diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs index 7192a889adc..83fe4a9f98f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs +++ b/compiler/rustc_borrowck/src/diagnostics/opaque_types.rs @@ -18,9 +18,28 @@ use rustc_trait_selection::errors::impl_trait_overcapture_suggestion; use crate::MirBorrowckCtxt; use crate::borrow_set::BorrowData; use crate::consumers::RegionInferenceContext; +use crate::region_infer::opaque_types::DeferredOpaqueTypeError; use crate::type_check::Locations; impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { + pub(crate) fn report_opaque_type_errors(&mut self, errors: Vec<DeferredOpaqueTypeError<'tcx>>) { + if errors.is_empty() { + return; + } + let mut guar = None; + for error in errors { + guar = Some(match error { + DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err) => err.report(self.infcx), + DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(err) => { + self.infcx.dcx().emit_err(err) + } + }); + } + let guar = guar.unwrap(); + self.root_cx.set_tainted_by_errors(guar); + self.infcx.set_tainted_by_errors(guar); + } + /// Try to note when an opaque is involved in a borrowck error and that /// opaque captures lifetimes due to edition 2024. // FIXME: This code is otherwise somewhat general, and could easily be adapted diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index b130cf8ed27..2b74f1a48f7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -92,9 +92,6 @@ impl<'tcx> RegionErrors<'tcx> { ) -> impl Iterator<Item = (RegionErrorKind<'tcx>, ErrorGuaranteed)> { self.0.into_iter() } - pub(crate) fn has_errors(&self) -> Option<ErrorGuaranteed> { - self.0.get(0).map(|x| x.1) - } } impl std::fmt::Debug for RegionErrors<'_> { diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index aaaf2f45c86..e168b819a8d 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -157,7 +157,7 @@ fn region_definitions<'tcx>( for info in var_infos.iter() { let origin = match info.origin { RegionVariableOrigin::Nll(origin) => origin, - _ => NllRegionVariableOrigin::Existential { from_forall: false }, + _ => NllRegionVariableOrigin::Existential { from_forall: false, name: None }, }; let definition = RegionDefinition { origin, universe: info.universe, external_name: None }; @@ -216,22 +216,11 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>( placeholder_index_to_region: _, liveness_constraints, mut outlives_constraints, - mut member_constraints, + member_constraints, universe_causes, type_tests, } = constraints; - if let Some(guar) = universal_regions.tainted_by_errors() { - debug!("Universal regions tainted by errors; removing constraints!"); - // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all - // outlives bounds that we may end up checking. - outlives_constraints = Default::default(); - member_constraints = Default::default(); - - // Also taint the entire scope. - infcx.set_tainted_by_errors(guar); - } - let fr_static = universal_regions.fr_static; let compute_sccs = |constraints: &OutlivesConstraintSet<'tcx>, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 752ff8e6f58..d76d6a04e6e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -375,7 +375,7 @@ fn do_mir_borrowck<'tcx>( polonius_context, ); - regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values); + let opaque_type_errors = regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values); // Dump MIR results into a file, if that is enabled. This lets us // write unit-tests, as well as helping with debugging. @@ -471,7 +471,11 @@ fn do_mir_borrowck<'tcx>( }; // Compute and report region errors, if any. - mbcx.report_region_errors(nll_errors); + if nll_errors.is_empty() { + mbcx.report_opaque_type_errors(opaque_type_errors); + } else { + mbcx.report_region_errors(nll_errors); + } let (mut flow_analysis, flow_entry_states) = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index ca6092e70d2..8608a8a3a66 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -148,11 +148,6 @@ pub(crate) fn compute_regions<'tcx>( let (closure_region_requirements, nll_errors) = regioncx.solve(infcx, body, polonius_output.clone()); - if let Some(guar) = nll_errors.has_errors() { - // Suppress unhelpful extra errors in `infer_opaque_types`. - infcx.set_tainted_by_errors(guar); - } - NllOutput { regioncx, polonius_input: polonius_facts.map(Box::new), diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs index a3e29982e90..b2f67c43125 100644 --- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -41,7 +41,22 @@ fn render_region_vid<'tcx>( "".to_string() }; - format!("{:?}{universe_str}{external_name_str}", rvid) + let extra_info = match regioncx.region_definition(rvid).origin { + NllRegionVariableOrigin::FreeRegion => "".to_string(), + NllRegionVariableOrigin::Placeholder(p) => match p.bound.kind { + ty::BoundRegionKind::Named(def_id) => { + format!(" (for<{}>)", tcx.item_name(def_id)) + } + ty::BoundRegionKind::ClosureEnv | ty::BoundRegionKind::Anon => " (for<'_>)".to_string(), + ty::BoundRegionKind::NamedAnon(_) => { + bug!("only used for pretty printing") + } + }, + NllRegionVariableOrigin::Existential { name: Some(name), .. } => format!(" (ex<{name}>)"), + NllRegionVariableOrigin::Existential { .. } => format!(" (ex<'_>)"), + }; + + format!("{:?}{universe_str}{external_name_str}{extra_info}", rvid) } impl<'tcx> RegionInferenceContext<'tcx> { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f1320048533..dbd245214a2 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -44,7 +44,7 @@ use crate::{ mod dump_mir; mod graphviz; -mod opaque_types; +pub(crate) mod opaque_types; mod reverse_sccs; pub(crate) mod values; @@ -1940,9 +1940,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { // and here we prefer to blame the source (the y = x statement). let blame_source = match from_region_origin { NllRegionVariableOrigin::FreeRegion - | NllRegionVariableOrigin::Existential { from_forall: false } => true, + | NllRegionVariableOrigin::Existential { from_forall: false, name: _ } => true, NllRegionVariableOrigin::Placeholder(_) - | NllRegionVariableOrigin::Existential { from_forall: true } => false, + | NllRegionVariableOrigin::Existential { from_forall: true, name: _ } => false, }; // To pick a constraint to blame, we organize constraints by how interesting we expect them diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 6270e6d9a60..23c4554aa15 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -6,7 +6,9 @@ use rustc_middle::ty::{ TypeVisitableExt, fold_regions, }; use rustc_span::Span; -use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid; +use rustc_trait_selection::opaque_types::{ + InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid, +}; use tracing::{debug, instrument}; use super::RegionInferenceContext; @@ -14,6 +16,11 @@ use crate::BorrowCheckRootCtxt; use crate::session_diagnostics::LifetimeMismatchOpaqueParam; use crate::universal_regions::RegionClassification; +pub(crate) enum DeferredOpaqueTypeError<'tcx> { + InvalidOpaqueTypeArgs(InvalidOpaqueTypeArgs<'tcx>), + LifetimeMismatchOpaqueParam(LifetimeMismatchOpaqueParam<'tcx>), +} + impl<'tcx> RegionInferenceContext<'tcx> { /// Resolve any opaque types that were encountered while borrow checking /// this item. This is then used to get the type in the `type_of` query. @@ -58,13 +65,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// [rustc-dev-guide chapter]: /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html - #[instrument(level = "debug", skip(self, root_cx, infcx), ret)] + #[instrument(level = "debug", skip(self, root_cx, infcx))] pub(crate) fn infer_opaque_types( &self, root_cx: &mut BorrowCheckRootCtxt<'tcx>, infcx: &InferCtxt<'tcx>, opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, - ) { + ) -> Vec<DeferredOpaqueTypeError<'tcx>> { + let mut errors = Vec::new(); let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> = FxIndexMap::default(); @@ -124,8 +132,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); debug!(?concrete_type); - let ty = - infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type); + let ty = match infcx + .infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type) + { + Ok(ty) => ty, + Err(err) => { + errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err)); + continue; + } + }; // Sometimes, when the hidden type is an inference variable, it can happen that // the hidden type becomes the opaque type itself. In this case, this was an opaque @@ -149,25 +164,27 @@ impl<'tcx> RegionInferenceContext<'tcx> { // non-region parameters. This is necessary because within the new solver we perform // various query operations modulo regions, and thus could unsoundly select some impls // that don't hold. - if !ty.references_error() - && let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert( - infcx.tcx.erase_regions(opaque_type_key), - (opaque_type_key, concrete_type.span), - ) - && let Some((arg1, arg2)) = std::iter::zip( - prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), - opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), - ) - .find(|(arg1, arg2)| arg1 != arg2) + if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert( + infcx.tcx.erase_regions(opaque_type_key), + (opaque_type_key, concrete_type.span), + ) && let Some((arg1, arg2)) = std::iter::zip( + prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), + opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), + ) + .find(|(arg1, arg2)| arg1 != arg2) { - infcx.dcx().emit_err(LifetimeMismatchOpaqueParam { - arg: arg1, - prev: arg2, - span: prev_span, - prev_span: concrete_type.span, - }); + errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam( + LifetimeMismatchOpaqueParam { + arg: arg1, + prev: arg2, + span: prev_span, + prev_span: concrete_type.span, + }, + )); } } + + errors } /// Map the regions in the type to named regions. This is similar to what @@ -260,19 +277,13 @@ impl<'tcx> InferCtxt<'tcx> { &self, opaque_type_key: OpaqueTypeKey<'tcx>, instantiated_ty: OpaqueHiddenType<'tcx>, - ) -> Ty<'tcx> { - if let Some(e) = self.tainted_by_errors() { - return Ty::new_error(self.tcx, e); - } - - if let Err(err) = check_opaque_type_parameter_valid( + ) -> Result<Ty<'tcx>, InvalidOpaqueTypeArgs<'tcx>> { + check_opaque_type_parameter_valid( self, opaque_type_key, instantiated_ty.span, DefiningScopeKind::MirBorrowck, - ) { - return Ty::new_error(self.tcx, err.report(self)); - } + )?; let definition_ty = instantiated_ty .remap_generic_params_to_declaration_params( @@ -282,10 +293,7 @@ impl<'tcx> InferCtxt<'tcx> { ) .ty; - if let Err(e) = definition_ty.error_reported() { - return Ty::new_error(self.tcx, e); - } - - definition_ty + definition_ty.error_reported()?; + Ok(definition_ty) } } diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index ff92b4168a8..100d30704b9 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -66,7 +66,7 @@ impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> { T: TypeFoldable<TyCtxt<'tcx>>, F: Fn() -> RegionCtxt, { - let origin = NllRegionVariableOrigin::Existential { from_forall: false }; + let origin = NllRegionVariableOrigin::Existential { from_forall: false, name: None }; fold_regions(self.infcx.tcx, value, |_region, _depth| { self.infcx.next_nll_region_var(origin, || region_ctxt_fn()) }) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 148d0de3bab..c3aa205d5aa 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -182,6 +182,17 @@ pub(crate) fn type_check<'tcx>( ) }); + // In case type check encountered an error region, we suppress unhelpful extra + // errors in by clearing out all outlives bounds that we may end up checking. + if let Some(guar) = universal_region_relations.universal_regions.encountered_re_error() { + debug!("encountered an error region; removing constraints!"); + constraints.outlives_constraints = Default::default(); + constraints.member_constraints = Default::default(); + constraints.type_tests = Default::default(); + root_cx.set_tainted_by_errors(guar); + infcx.set_tainted_by_errors(guar); + } + MirTypeckResults { constraints, universal_region_relations, diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index bb72d1d52f3..393adafea0b 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -249,7 +249,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { from_forall: bool, name: Option<Symbol>, ) -> ty::Region<'tcx> { - let origin = NllRegionVariableOrigin::Existential { from_forall }; + let origin = NllRegionVariableOrigin::Existential { name, from_forall }; let reg_var = self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name)); diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 240c9a5223b..296a2735533 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -217,7 +217,7 @@ struct UniversalRegionIndices<'tcx> { /// Whether we've encountered an error region. If we have, cancel all /// outlives errors, as they are likely bogus. - pub tainted_by_errors: Cell<Option<ErrorGuaranteed>>, + pub encountered_re_error: Cell<Option<ErrorGuaranteed>>, } #[derive(Debug, PartialEq)] @@ -442,8 +442,8 @@ impl<'tcx> UniversalRegions<'tcx> { self.fr_fn_body } - pub(crate) fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> { - self.indices.tainted_by_errors.get() + pub(crate) fn encountered_re_error(&self) -> Option<ErrorGuaranteed> { + self.indices.encountered_re_error.get() } } @@ -706,7 +706,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { UniversalRegionIndices { indices: global_mapping.chain(arg_mapping).collect(), fr_static, - tainted_by_errors: Cell::new(None), + encountered_re_error: Cell::new(None), } } @@ -916,7 +916,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> { match r.kind() { ty::ReVar(..) => r.as_var(), ty::ReError(guar) => { - self.tainted_by_errors.set(Some(guar)); + self.encountered_re_error.set(Some(guar)); // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if // errors are being emitted and 2) it leaves the happy path unaffected. diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 36ad5ede7c2..3ca070acc9d 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -180,6 +180,10 @@ codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented y codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error} +codegen_ssa_link_exe_status_stack_buffer_overrun = 0xc0000409 is `STATUS_STACK_BUFFER_OVERRUN` + .abort_note = this may have been caused by a program abort and not a stack buffer overrun + .event_log_note = consider checking the Application Event Log for Windows Error Reporting events to see the fail fast error code + codegen_ssa_link_exe_unexpected_error = `link.exe` returned an unexpected error codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 6e21f54587f..3ec0d900994 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -880,6 +880,14 @@ fn link_natively( windows_registry::find_tool(&sess.target.arch, "link.exe").is_some(); sess.dcx().emit_note(errors::LinkExeUnexpectedError); + + // STATUS_STACK_BUFFER_OVERRUN is also used for fast abnormal program termination, e.g. abort(). + // Emit a special diagnostic to let people know that this most likely doesn't indicate a stack buffer overrun. + const STATUS_STACK_BUFFER_OVERRUN: i32 = 0xc0000409u32 as _; + if code == STATUS_STACK_BUFFER_OVERRUN { + sess.dcx().emit_note(errors::LinkExeStatusStackBufferOverrun); + } + if is_vs_installed && has_linker { // the linker is broken sess.dcx().emit_note(errors::RepairVSBuildTools); diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index af4adcd1954..7ac830bcda9 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -550,6 +550,18 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> { #[diag(codegen_ssa_link_exe_unexpected_error)] pub(crate) struct LinkExeUnexpectedError; +pub(crate) struct LinkExeStatusStackBufferOverrun; + +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for LinkExeStatusStackBufferOverrun { + fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { + let mut diag = + Diag::new(dcx, level, fluent::codegen_ssa_link_exe_status_stack_buffer_overrun); + diag.note(fluent::codegen_ssa_abort_note); + diag.note(fluent::codegen_ssa_event_log_note); + diag + } +} + #[derive(Diagnostic)] #[diag(codegen_ssa_repair_vs_build_tools)] pub(crate) struct RepairVSBuildTools; diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 522409a5ee5..8dd13da4fa7 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -517,8 +517,7 @@ pub(super) fn explicit_predicates_of<'tcx>( projection.args == trait_identity_args // FIXME(return_type_notation): This check should be more robust && !tcx.is_impl_trait_in_trait(projection.def_id) - && tcx.associated_item(projection.def_id).container_id(tcx) - == def_id.to_def_id() + && tcx.parent(projection.def_id) == def_id.to_def_id() } else { false } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 3e446b7c656..93b82acf621 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -755,7 +755,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let limit = if candidates.len() == 5 { 5 } else { 4 }; for (index, &item) in candidates.iter().take(limit).enumerate() { - let impl_ = tcx.impl_of_assoc(item).unwrap(); + let impl_ = tcx.parent(item); let note_span = if item.is_local() { Some(tcx.def_span(item)) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 7379df7c7c7..a2afdc45fa8 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -484,6 +484,7 @@ pub enum NllRegionVariableOrigin { Placeholder(ty::PlaceholderRegion), Existential { + name: Option<Symbol>, /// If this is true, then this variable was created to represent a lifetime /// bound in a `for` binder. For example, it might have been created to /// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8dec8069bc7..8bbd0e61492 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -371,7 +371,7 @@ fn print_macro_stats(ecx: &ExtCtxt<'_>) { // The name won't abut or overlap with the uses value, but it does // overlap with the empty part of the uses column. Shrink the width // of the uses column to account for the excess name length. - uses_w = uses_with_underscores.len() + 1 + uses_w -= name.len() - name_w; }; _ = writeln!( diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index 7c39d8917ce..1d92cfbc039 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -62,8 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived { // Look for manual implementations of `Default`. let Some(default_def_id) = cx.tcx.get_diagnostic_item(sym::Default) else { return }; let hir::ImplItemKind::Fn(_sig, body_id) = impl_item.kind else { return }; - let assoc = cx.tcx.associated_item(impl_item.owner_id); - let parent = assoc.container_id(cx.tcx); + let parent = cx.tcx.parent(impl_item.owner_id.to_def_id()); if find_attr!(cx.tcx.get_all_attrs(parent), AttributeKind::AutomaticallyDerived(..)) { // We don't care about what `#[derive(Default)]` produces in this lint. return; diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ac6147b1631..73e69a1791a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -902,9 +902,8 @@ pub(crate) struct MappingToUnit { pub argument_label: Span, #[label(lint_map_label)] pub map_label: Span, - #[suggestion(style = "verbose", code = "{replace}", applicability = "maybe-incorrect")] + #[suggestion(style = "verbose", code = "for_each", applicability = "maybe-incorrect")] pub suggestion: Span, - pub replace: String, } // internal.rs diff --git a/compiler/rustc_lint/src/map_unit_fn.rs b/compiler/rustc_lint/src/map_unit_fn.rs index 34210137bde..18a947dc1ee 100644 --- a/compiler/rustc_lint/src/map_unit_fn.rs +++ b/compiler/rustc_lint/src/map_unit_fn.rs @@ -1,6 +1,7 @@ -use rustc_hir::{Expr, ExprKind, HirId, Stmt, StmtKind}; -use rustc_middle::ty::{self, Ty}; +use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; +use rustc_middle::ty::{self}; use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::sym; use crate::lints::MappingToUnit; use crate::{LateContext, LateLintPass, LintContext}; @@ -39,58 +40,43 @@ declare_lint_pass!(MapUnitFn => [MAP_UNIT_FN]); impl<'tcx> LateLintPass<'tcx> for MapUnitFn { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) { - if stmt.span.from_expansion() { + let StmtKind::Semi(expr) = stmt.kind else { return; - } - - if let StmtKind::Semi(expr) = stmt.kind - && let ExprKind::MethodCall(path, receiver, args, span) = expr.kind + }; + let ExprKind::MethodCall(path, receiver, [arg], span) = expr.kind else { + return; + }; + if path.ident.name != sym::map + || stmt.span.from_expansion() + || receiver.span.from_expansion() + || arg.span.from_expansion() + || !is_impl_slice(cx, receiver) + || !cx + .typeck_results() + .type_dependent_def_id(expr.hir_id) + .is_some_and(|id| cx.tcx.is_diagnostic_item(sym::IteratorMap, id)) { - if path.ident.name.as_str() == "map" { - if receiver.span.from_expansion() - || args.iter().any(|e| e.span.from_expansion()) - || !is_impl_slice(cx, receiver) - || !is_diagnostic_name(cx, expr.hir_id, "IteratorMap") - { - return; - } - let arg_ty = cx.typeck_results().expr_ty(&args[0]); - let default_span = args[0].span; - if let ty::FnDef(id, _) = arg_ty.kind() { - let fn_ty = cx.tcx.fn_sig(id).skip_binder(); - let ret_ty = fn_ty.output().skip_binder(); - if is_unit_type(ret_ty) { - cx.emit_span_lint( - MAP_UNIT_FN, - span, - MappingToUnit { - function_label: cx.tcx.span_of_impl(*id).unwrap_or(default_span), - argument_label: args[0].span, - map_label: span, - suggestion: path.ident.span, - replace: "for_each".to_string(), - }, - ) - } - } else if let ty::Closure(id, subs) = arg_ty.kind() { - let cl_ty = subs.as_closure().sig(); - let ret_ty = cl_ty.output().skip_binder(); - if is_unit_type(ret_ty) { - cx.emit_span_lint( - MAP_UNIT_FN, - span, - MappingToUnit { - function_label: cx.tcx.span_of_impl(*id).unwrap_or(default_span), - argument_label: args[0].span, - map_label: span, - suggestion: path.ident.span, - replace: "for_each".to_string(), - }, - ) - } - } - } + return; } + let (id, sig) = match *cx.typeck_results().expr_ty(arg).kind() { + ty::Closure(id, subs) => (id, subs.as_closure().sig()), + ty::FnDef(id, _) => (id, cx.tcx.fn_sig(id).skip_binder()), + _ => return, + }; + let ret_ty = sig.output().skip_binder(); + if !(ret_ty.is_unit() || ret_ty.is_never()) { + return; + } + cx.emit_span_lint( + MAP_UNIT_FN, + span, + MappingToUnit { + function_label: cx.tcx.span_of_impl(id).unwrap_or(arg.span), + argument_label: arg.span, + map_label: span, + suggestion: path.ident.span, + }, + ); } } @@ -102,18 +88,3 @@ fn is_impl_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } false } - -fn is_unit_type(ty: Ty<'_>) -> bool { - ty.is_unit() || ty.is_never() -} - -fn is_diagnostic_name(cx: &LateContext<'_>, id: HirId, name: &str) -> bool { - if let Some(def_id) = cx.typeck_results().type_dependent_def_id(id) - && let Some(item) = cx.tcx.get_diagnostic_name(def_id) - { - if item.as_str() == name { - return true; - } - } - false -} diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 0f3896fd9be..df95ed602cd 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -75,24 +75,6 @@ impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> ProcessQueryValue<' } impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> - ProcessQueryValue<'tcx, ty::EarlyBinder<'tcx, &'tcx [T]>> - for Option<DecodeIterator<'a, 'tcx, T>> -{ - #[inline(always)] - fn process_decoded( - self, - tcx: TyCtxt<'tcx>, - err: impl Fn() -> !, - ) -> ty::EarlyBinder<'tcx, &'tcx [T]> { - ty::EarlyBinder::bind(if let Some(iter) = self { - tcx.arena.alloc_from_iter(iter) - } else { - err() - }) - } -} - -impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> ProcessQueryValue<'tcx, Option<&'tcx [T]>> for Option<DecodeIterator<'a, 'tcx, T>> { #[inline(always)] diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs index d632e65104a..34180001f80 100644 --- a/compiler/rustc_metadata/src/rmeta/parameterized.rs +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -6,7 +6,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::ty::{Binder, EarlyBinder}; use rustc_span::Symbol; -use crate::rmeta::{LazyArray, LazyTable, LazyValue}; +use crate::rmeta::{LazyArray, LazyValue}; pub(crate) trait ParameterizedOverTcx: 'static { type Value<'tcx>; @@ -48,10 +48,6 @@ impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> { type Value<'tcx> = LazyArray<T::Value<'tcx>>; } -impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for LazyTable<I, T> { - type Value<'tcx> = LazyTable<I, T::Value<'tcx>>; -} - macro_rules! trivially_parameterized_over_tcx { ($($ty:ty),+ $(,)?) => { $( @@ -154,7 +150,6 @@ parameterized_over_tcx! { rustc_middle::mir::CoroutineLayout, rustc_middle::mir::interpret::ConstAllocation, rustc_middle::ty::Clause, - rustc_middle::ty::ClauseKind, rustc_middle::ty::Const, rustc_middle::ty::ConstConditions, rustc_middle::ty::FnSig, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 28f406fbc96..0671aa20399 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -66,22 +66,6 @@ pub(super) trait FixedSizeEncoding: IsDefault { fn write_to_bytes(self, b: &mut Self::ByteArray); } -/// This implementation is not used generically, but for reading/writing -/// concrete `u32` fields in `Lazy*` structures, which may be zero. -impl FixedSizeEncoding for u32 { - type ByteArray = [u8; 4]; - - #[inline] - fn from_bytes(b: &[u8; 4]) -> Self { - Self::from_le_bytes(*b) - } - - #[inline] - fn write_to_bytes(self, b: &mut [u8; 4]) { - *b = self.to_le_bytes(); - } -} - impl FixedSizeEncoding for u64 { type ByteArray = [u8; 8]; @@ -175,14 +159,6 @@ fixed_size_enum! { } fixed_size_enum! { - ty::ImplPolarity { - ( Positive ) - ( Negative ) - ( Reservation ) - } -} - -fixed_size_enum! { hir::Constness { ( NotConst ) ( Const ) @@ -306,45 +282,6 @@ impl FixedSizeEncoding for bool { } } -impl FixedSizeEncoding for Option<bool> { - type ByteArray = [u8; 1]; - - #[inline] - fn from_bytes(b: &[u8; 1]) -> Self { - match b[0] { - 0 => Some(false), - 1 => Some(true), - 2 => None, - _ => unreachable!(), - } - } - - #[inline] - fn write_to_bytes(self, b: &mut [u8; 1]) { - debug_assert!(!self.is_default()); - b[0] = match self { - Some(false) => 0, - Some(true) => 1, - None => 2, - }; - } -} - -impl FixedSizeEncoding for UnusedGenericParams { - type ByteArray = [u8; 4]; - - #[inline] - fn from_bytes(b: &[u8; 4]) -> Self { - let x: u32 = u32::from_bytes(b); - UnusedGenericParams::from_bits(x) - } - - #[inline] - fn write_to_bytes(self, b: &mut [u8; 4]) { - self.bits().write_to_bytes(b); - } -} - // NOTE(eddyb) there could be an impl for `usize`, which would enable a more // generic `LazyValue<T>` impl, but in the general case we might not need / want // to fit every `usize` in `u32`. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8c0277055cd..73e1661106e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1031,6 +1031,8 @@ pub struct ParamEnvAnd<'tcx, T> { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] #[derive(TypeVisitable, TypeFoldable)] pub struct TypingEnv<'tcx> { + #[type_foldable(identity)] + #[type_visitable(ignore)] pub typing_mode: TypingMode<'tcx>, pub param_env: ParamEnv<'tcx>, } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index a7d5422a3d7..f86a15a8f92 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -800,6 +800,7 @@ where let re = regex!("\t?\u{001f}([+-])"); let raw_diff = format!("{:#?}", DebugDiffWithAdapter { new, old, ctxt }); + let raw_diff = dot::escape_html(&raw_diff); // Replace newlines in the `Debug` output with `<br/>` let raw_diff = raw_diff.replace('\n', r#"<br align="left"/>"#); diff --git a/compiler/rustc_mir_transform/src/coverage/hir_info.rs b/compiler/rustc_mir_transform/src/coverage/hir_info.rs new file mode 100644 index 00000000000..28fdc52b06c --- /dev/null +++ b/compiler/rustc_mir_transform/src/coverage/hir_info.rs @@ -0,0 +1,128 @@ +use rustc_hir as hir; +use rustc_hir::intravisit::{Visitor, walk_expr}; +use rustc_middle::hir::nested_filter; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; +use rustc_span::def_id::LocalDefId; + +/// Function information extracted from HIR by the coverage instrumentor. +#[derive(Debug)] +pub(crate) struct ExtractedHirInfo { + pub(crate) function_source_hash: u64, + pub(crate) is_async_fn: bool, + /// The span of the function's signature, if available. + /// Must have the same context and filename as the body span. + pub(crate) fn_sig_span: Option<Span>, + pub(crate) body_span: Span, + /// "Holes" are regions within the function body (or its expansions) that + /// should not be included in coverage spans for this function + /// (e.g. closures and nested items). + pub(crate) hole_spans: Vec<Span>, +} + +pub(crate) fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHirInfo { + // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back + // to HIR for it. + + // HACK: For synthetic MIR bodies (async closures), use the def id of the HIR body. + if tcx.is_synthetic_mir(def_id) { + return extract_hir_info(tcx, tcx.local_parent(def_id)); + } + + let hir_node = tcx.hir_node_by_def_id(def_id); + let fn_body_id = hir_node.body_id().expect("HIR node is a function with body"); + let hir_body = tcx.hir_body(fn_body_id); + + let maybe_fn_sig = hir_node.fn_sig(); + let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async()); + + let mut body_span = hir_body.value.span; + + use hir::{Closure, Expr, ExprKind, Node}; + // Unexpand a closure's body span back to the context of its declaration. + // This helps with closure bodies that consist of just a single bang-macro, + // and also with closure bodies produced by async desugaring. + if let Node::Expr(&Expr { kind: ExprKind::Closure(&Closure { fn_decl_span, .. }), .. }) = + hir_node + { + body_span = body_span.find_ancestor_in_same_ctxt(fn_decl_span).unwrap_or(body_span); + } + + // The actual signature span is only used if it has the same context and + // filename as the body, and precedes the body. + let fn_sig_span = maybe_fn_sig.map(|fn_sig| fn_sig.span).filter(|&fn_sig_span| { + let source_map = tcx.sess.source_map(); + let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo()); + + fn_sig_span.eq_ctxt(body_span) + && fn_sig_span.hi() <= body_span.lo() + && file_idx(fn_sig_span) == file_idx(body_span) + }); + + let function_source_hash = hash_mir_source(tcx, hir_body); + + let hole_spans = extract_hole_spans_from_hir(tcx, hir_body); + + ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span, hole_spans } +} + +fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> u64 { + let owner = hir_body.id().hir_id.owner; + tcx.hir_owner_nodes(owner) + .opt_hash_including_bodies + .expect("hash should be present when coverage instrumentation is enabled") + .to_smaller_hash() + .as_u64() +} + +fn extract_hole_spans_from_hir<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &hir::Body<'tcx>) -> Vec<Span> { + struct HolesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + hole_spans: Vec<Span>, + } + + impl<'tcx> Visitor<'tcx> for HolesVisitor<'tcx> { + /// We have special handling for nested items, but we still want to + /// traverse into nested bodies of things that are not considered items, + /// such as "anon consts" (e.g. array lengths). + type NestedFilter = nested_filter::OnlyBodies; + + fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { + self.tcx + } + + /// We override `visit_nested_item` instead of `visit_item` because we + /// only need the item's span, not the item itself. + fn visit_nested_item(&mut self, id: hir::ItemId) -> Self::Result { + let span = self.tcx.def_span(id.owner_id.def_id); + self.visit_hole_span(span); + // Having visited this item, we don't care about its children, + // so don't call `walk_item`. + } + + // We override `visit_expr` instead of the more specific expression + // visitors, so that we have direct access to the expression span. + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + match expr.kind { + hir::ExprKind::Closure(_) | hir::ExprKind::ConstBlock(_) => { + self.visit_hole_span(expr.span); + // Having visited this expression, we don't care about its + // children, so don't call `walk_expr`. + } + + // For other expressions, recursively visit as normal. + _ => walk_expr(self, expr), + } + } + } + impl HolesVisitor<'_> { + fn visit_hole_span(&mut self, hole_span: Span) { + self.hole_spans.push(hole_span); + } + } + + let mut visitor = HolesVisitor { tcx, hole_spans: vec![] }; + + visitor.visit_body(hir_body); + visitor.hole_spans +} diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 399978b5915..46fe7c40826 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -4,8 +4,8 @@ use rustc_middle::mir::{self, BasicBlock, StatementKind}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; -use crate::coverage::ExtractedHirInfo; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::hir_info::ExtractedHirInfo; use crate::coverage::spans::extract_refined_covspans; use crate::coverage::unexpand::unexpand_into_body_span; diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index f6945a95a7c..47a87a2e94d 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -1,26 +1,22 @@ -mod counters; -mod graph; -mod mappings; -pub(super) mod query; -mod spans; -#[cfg(test)] -mod tests; -mod unexpand; - -use rustc_hir as hir; -use rustc_hir::intravisit::{Visitor, walk_expr}; -use rustc_middle::hir::nested_filter; use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo, Mapping, MappingKind}; use rustc_middle::mir::{self, BasicBlock, Statement, StatementKind, TerminatorKind}; use rustc_middle::ty::TyCtxt; -use rustc_span::Span; -use rustc_span::def_id::LocalDefId; use tracing::{debug, debug_span, trace}; use crate::coverage::counters::BcbCountersData; use crate::coverage::graph::CoverageGraph; use crate::coverage::mappings::ExtractedMappings; +mod counters; +mod graph; +mod hir_info; +mod mappings; +pub(super) mod query; +mod spans; +#[cfg(test)] +mod tests; +mod unexpand; + /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen /// to construct the coverage map. @@ -67,7 +63,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: let def_id = mir_body.source.def_id(); let _span = debug_span!("instrument_function_for_coverage", ?def_id).entered(); - let hir_info = extract_hir_info(tcx, def_id.expect_local()); + let hir_info = hir_info::extract_hir_info(tcx, def_id.expect_local()); // Build the coverage graph, which is a simplified view of the MIR control-flow // graph that ignores some details not relevant to coverage instrumentation. @@ -147,122 +143,3 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb let statement = Statement::new(source_info, StatementKind::Coverage(counter_kind)); data.statements.insert(0, statement); } - -/// Function information extracted from HIR by the coverage instrumentor. -#[derive(Debug)] -struct ExtractedHirInfo { - function_source_hash: u64, - is_async_fn: bool, - /// The span of the function's signature, if available. - /// Must have the same context and filename as the body span. - fn_sig_span: Option<Span>, - body_span: Span, - /// "Holes" are regions within the function body (or its expansions) that - /// should not be included in coverage spans for this function - /// (e.g. closures and nested items). - hole_spans: Vec<Span>, -} - -fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHirInfo { - // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back - // to HIR for it. - - // HACK: For synthetic MIR bodies (async closures), use the def id of the HIR body. - if tcx.is_synthetic_mir(def_id) { - return extract_hir_info(tcx, tcx.local_parent(def_id)); - } - - let hir_node = tcx.hir_node_by_def_id(def_id); - let fn_body_id = hir_node.body_id().expect("HIR node is a function with body"); - let hir_body = tcx.hir_body(fn_body_id); - - let maybe_fn_sig = hir_node.fn_sig(); - let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async()); - - let mut body_span = hir_body.value.span; - - use hir::{Closure, Expr, ExprKind, Node}; - // Unexpand a closure's body span back to the context of its declaration. - // This helps with closure bodies that consist of just a single bang-macro, - // and also with closure bodies produced by async desugaring. - if let Node::Expr(&Expr { kind: ExprKind::Closure(&Closure { fn_decl_span, .. }), .. }) = - hir_node - { - body_span = body_span.find_ancestor_in_same_ctxt(fn_decl_span).unwrap_or(body_span); - } - - // The actual signature span is only used if it has the same context and - // filename as the body, and precedes the body. - let fn_sig_span = maybe_fn_sig.map(|fn_sig| fn_sig.span).filter(|&fn_sig_span| { - let source_map = tcx.sess.source_map(); - let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo()); - - fn_sig_span.eq_ctxt(body_span) - && fn_sig_span.hi() <= body_span.lo() - && file_idx(fn_sig_span) == file_idx(body_span) - }); - - let function_source_hash = hash_mir_source(tcx, hir_body); - - let hole_spans = extract_hole_spans_from_hir(tcx, hir_body); - - ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span, hole_spans } -} - -fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> u64 { - // FIXME(cjgillot) Stop hashing HIR manually here. - let owner = hir_body.id().hir_id.owner; - tcx.hir_owner_nodes(owner).opt_hash_including_bodies.unwrap().to_smaller_hash().as_u64() -} - -fn extract_hole_spans_from_hir<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &hir::Body<'tcx>) -> Vec<Span> { - struct HolesVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - hole_spans: Vec<Span>, - } - - impl<'tcx> Visitor<'tcx> for HolesVisitor<'tcx> { - /// We have special handling for nested items, but we still want to - /// traverse into nested bodies of things that are not considered items, - /// such as "anon consts" (e.g. array lengths). - type NestedFilter = nested_filter::OnlyBodies; - - fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { - self.tcx - } - - /// We override `visit_nested_item` instead of `visit_item` because we - /// only need the item's span, not the item itself. - fn visit_nested_item(&mut self, id: hir::ItemId) -> Self::Result { - let span = self.tcx.def_span(id.owner_id.def_id); - self.visit_hole_span(span); - // Having visited this item, we don't care about its children, - // so don't call `walk_item`. - } - - // We override `visit_expr` instead of the more specific expression - // visitors, so that we have direct access to the expression span. - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - match expr.kind { - hir::ExprKind::Closure(_) | hir::ExprKind::ConstBlock(_) => { - self.visit_hole_span(expr.span); - // Having visited this expression, we don't care about its - // children, so don't call `walk_expr`. - } - - // For other expressions, recursively visit as normal. - _ => walk_expr(self, expr), - } - } - } - impl HolesVisitor<'_> { - fn visit_hole_span(&mut self, hole_span: Span) { - self.hole_spans.push(hole_span); - } - } - - let mut visitor = HolesVisitor { tcx, hole_spans: vec![] }; - - visitor.visit_body(hir_body); - visitor.hole_spans -} diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 0ee42abb195..ae9459dee84 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -7,8 +7,9 @@ use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span}; use tracing::instrument; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::hir_info::ExtractedHirInfo; use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir}; -use crate::coverage::{ExtractedHirInfo, mappings, unexpand}; +use crate::coverage::{mappings, unexpand}; mod from_mir; diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 43f80508e4a..6c2dfc59da2 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -4,7 +4,13 @@ //! useful because (unlike MIR building) it runs after type checking, so it can make use of //! `TypingMode::PostAnalysis` to provide more precise type information, especially about opaque //! types. +//! +//! When we're optimizing, we also remove calls to `drop_in_place<T>` when `T` isn't `needs_drop`, +//! as those are essentially equivalent to `Drop` terminators. While the compiler doesn't insert +//! them automatically, preferring the built-in instead, they're common in generic code (such as +//! `Vec::truncate`) so removing them from things like inlined `Vec<u8>` is helpful. +use rustc_hir::LangItem; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use tracing::{debug, trace}; @@ -21,15 +27,26 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops { let mut should_simplify = false; for block in body.basic_blocks.as_mut() { let terminator = block.terminator_mut(); - if let TerminatorKind::Drop { place, target, .. } = terminator.kind { - let ty = place.ty(&body.local_decls, tcx); - if ty.ty.needs_drop(tcx, typing_env) { - continue; + let (ty, target) = match terminator.kind { + TerminatorKind::Drop { place, target, .. } => { + (place.ty(&body.local_decls, tcx).ty, target) + } + TerminatorKind::Call { ref func, target: Some(target), .. } + if tcx.sess.mir_opt_level() > 0 + && let Some((def_id, generics)) = func.const_fn_def() + && tcx.is_lang_item(def_id, LangItem::DropInPlace) => + { + (generics.type_at(0), target) } - debug!("SUCCESS: replacing `drop` with goto({:?})", target); - terminator.kind = TerminatorKind::Goto { target }; - should_simplify = true; + _ => continue, + }; + + if ty.needs_drop(tcx, typing_env) { + continue; } + debug!("SUCCESS: replacing `drop` with goto({:?})", target); + terminator.kind = TerminatorKind::Goto { target }; + should_simplify = true; } // if we applied optimizations, we potentially have some cfg to cleanup to diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 7059ffbf375..aaf1b6c05bf 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -642,7 +642,7 @@ parse_missing_for_in_trait_impl = missing `for` in a trait impl .suggestion = add `for` here parse_missing_in_in_for_loop = missing `in` in `for` loop - .use_in_not_of = try using `in` here instead + .use_in = try using `in` here instead .add_in = try adding `in` here parse_missing_let_before_mut = missing keyword diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 48ff0394d46..ddb2c545c78 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -585,14 +585,13 @@ pub(crate) struct MissingInInForLoop { #[derive(Subdiagnostic)] pub(crate) enum MissingInInForLoopSub { + // User wrote `for pat of expr {}` // Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect - #[suggestion( - parse_use_in_not_of, - style = "verbose", - applicability = "maybe-incorrect", - code = "in" - )] + #[suggestion(parse_use_in, style = "verbose", applicability = "maybe-incorrect", code = "in")] InNotOf(#[primary_span] Span), + // User wrote `for pat = expr {}` + #[suggestion(parse_use_in, style = "verbose", applicability = "maybe-incorrect", code = "in")] + InNotEq(#[primary_span] Span), #[suggestion(parse_add_in, style = "verbose", applicability = "maybe-incorrect", code = " in ")] AddIn(#[primary_span] Span), } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 35b987cf50f..cbf6b78431c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3028,6 +3028,8 @@ impl<'a> Parser<'a> { let span = self.token.span; self.bump(); (span, errors::MissingInInForLoopSub::InNotOf) + } else if self.eat(exp!(Eq)) { + (self.prev_token.span, errors::MissingInInForLoopSub::InNotEq) } else { (self.prev_token.span.between(self.token.span), errors::MissingInInForLoopSub::AddIn) }; diff --git a/compiler/rustc_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs index 3183c020772..9dd1ce4de0e 100644 --- a/compiler/rustc_public/src/mir/pretty.rs +++ b/compiler/rustc_public/src/mir/pretty.rs @@ -100,7 +100,7 @@ fn pretty_statement<W: Write>(writer: &mut W, statement: &StatementKind) -> io:: writeln!(writer, "{INDENT}FakeRead({cause:?}, {place:?});") } StatementKind::SetDiscriminant { place, variant_index } => { - writeln!(writer, "{INDENT}discriminant({place:?} = {};", variant_index.to_index()) + writeln!(writer, "{INDENT}discriminant({place:?}) = {};", variant_index.to_index()) } StatementKind::Deinit(place) => writeln!(writer, "Deinit({place:?};"), StatementKind::StorageLive(local) => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5462ed38dd3..acbed7a9eed 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -280,6 +280,7 @@ symbols! { IterPeekable, Iterator, IteratorItem, + IteratorMap, Layout, Left, LinkedList, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 129d0963a75..8f0f6d0bf26 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -653,7 +653,6 @@ impl<T> Trait<T> for X { ) ); let impl_comparison = matches!(cause_code, ObligationCauseCode::CompareImplItem { .. }); - let assoc = tcx.associated_item(proj_ty.def_id); if impl_comparison { // We do not want to suggest calling functions when the reason of the // type error is a comparison of an `impl` with its `trait`. @@ -661,7 +660,7 @@ impl<T> Trait<T> for X { let point_at_assoc_fn = if callable_scope && self.point_at_methods_that_satisfy_associated_type( diag, - assoc.container_id(tcx), + tcx.parent(proj_ty.def_id), current_method_ident, proj_ty.def_id, values.expected, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index af2e000e340..89d1dd8cf23 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -39,7 +39,7 @@ fn fn_sig_for_fn_abi<'tcx>( tcx.thread_local_ptr_ty(instance.def_id()), false, hir::Safety::Safe, - rustc_abi::ExternAbi::Unadjusted, + rustc_abi::ExternAbi::Rust, ); } @@ -268,20 +268,21 @@ fn fn_abi_of_instance<'tcx>( } // Handle safe Rust thin and wide pointers. -fn adjust_for_rust_scalar<'tcx>( +fn arg_attrs_for_rust_scalar<'tcx>( cx: LayoutCx<'tcx>, - attrs: &mut ArgAttributes, scalar: Scalar, layout: TyAndLayout<'tcx>, offset: Size, is_return: bool, drop_target_pointee: Option<Ty<'tcx>>, -) { +) -> ArgAttributes { + let mut attrs = ArgAttributes::new(); + // Booleans are always a noundef i1 that needs to be zero-extended. if scalar.is_bool() { attrs.ext(ArgExtension::Zext); attrs.set(ArgAttribute::NoUndef); - return; + return attrs; } if !scalar.is_uninit_valid() { @@ -289,7 +290,7 @@ fn adjust_for_rust_scalar<'tcx>( } // Only pointer types handled below. - let Scalar::Initialized { value: Pointer(_), valid_range } = scalar else { return }; + let Scalar::Initialized { value: Pointer(_), valid_range } = scalar else { return attrs }; // Set `nonnull` if the validity range excludes zero, or for the argument to `drop_in_place`, // which must be nonnull per its documented safety requirements. @@ -358,6 +359,8 @@ fn adjust_for_rust_scalar<'tcx>( } } } + + attrs } /// Ensure that the ABI makes basic sense. @@ -471,9 +474,10 @@ fn fn_abi_new_uncached<'tcx>( let (caller_location, determined_fn_def_id, is_virtual_call) = if let Some(instance) = instance { let is_virtual_call = matches!(instance.def, ty::InstanceKind::Virtual(..)); + let is_tls_shim_call = matches!(instance.def, ty::InstanceKind::ThreadLocalShim(_)); ( instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty()), - if is_virtual_call { None } else { Some(instance.def_id()) }, + if is_virtual_call || is_tls_shim_call { None } else { Some(instance.def_id()) }, is_virtual_call, ) } else { @@ -530,17 +534,7 @@ fn fn_abi_new_uncached<'tcx>( }; let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| { - let mut attrs = ArgAttributes::new(); - adjust_for_rust_scalar( - *cx, - &mut attrs, - scalar, - *layout, - offset, - is_return, - drop_target_pointee, - ); - attrs + arg_attrs_for_rust_scalar(*cx, scalar, *layout, offset, is_return, drop_target_pointee) }); if arg.layout.is_zst() { @@ -563,6 +557,7 @@ fn fn_abi_new_uncached<'tcx>( c_variadic: sig.c_variadic, fixed_count: inputs.len() as u32, conv, + // FIXME return false for tls shim can_unwind: fn_can_unwind( tcx, // Since `#[rustc_nounwind]` can change unwinding, we cannot infer unwinding by `fn_def_id` for a virtual call. @@ -575,8 +570,9 @@ fn fn_abi_new_uncached<'tcx>( &mut fn_abi, sig.abi, // If this is a virtual call, we cannot pass the `fn_def_id`, as it might call other - // functions from vtable. Internally, `deduced_param_attrs` attempts to infer attributes by - // visit the function body. + // functions from vtable. And for a tls shim, passing the `fn_def_id` would refer to + // the underlying static. Internally, `deduced_param_attrs` attempts to infer attributes + // by visit the function body. determined_fn_def_id, ); debug!("fn_abi_new_uncached = {:?}", fn_abi); diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index c66a83662d7..0cb8d8902c6 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -199,7 +199,6 @@ impl<I: Interner> CanonicalVarKind<I> { /// usize or f32). In order to faithfully reproduce a type, we need to /// know what set of types a given type variable can be unified with. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 4be38d4e702..70a8509b513 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -92,15 +92,10 @@ rustc_index::newtype_index! { /// An inference variable for a const, for use in const generics. #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext))] pub enum InferConst { /// Infer the value of the const. - Var( - #[type_foldable(identity)] - #[type_visitable(ignore)] - ConstVid, - ), + Var(ConstVid), /// A fresh const variable. See `infer::freshen` for more details. Fresh(u32), } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index b4873c8c71c..e6462a97f8a 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,7 +1,6 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; -use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::fold::TypeFoldable; use crate::inherent::*; @@ -20,7 +19,6 @@ use crate::{self as ty, Interner}; /// If neither of these functions are available, feel free to reach out to /// t-types for help. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) |
