diff options
| author | bors <bors@rust-lang.org> | 2024-03-26 11:50:27 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-03-26 11:50:27 +0000 |
| commit | 2e198d04ee1ccd20926701c4da7403d2c6bca7b3 (patch) | |
| tree | 516054cbab817a3ae4ba709db47420054c52aee0 /compiler | |
| parent | 78d556e28d4e4d60b45bd183c22748967731abb9 (diff) | |
| parent | 89a36c03850a404d8d3a4b869cb85293e1f9a978 (diff) | |
| download | rust-2e198d04ee1ccd20926701c4da7403d2c6bca7b3.tar.gz rust-2e198d04ee1ccd20926701c4da7403d2c6bca7b3.zip | |
Auto merge of #3419 - RalfJung:rustup, r=RalfJung
Rustup https://github.com/rust-lang/rust/pull/123081 landed so hopefully this works now.
Diffstat (limited to 'compiler')
31 files changed, 484 insertions, 304 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 54c516c960c..599f7dd18c3 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -95,9 +95,11 @@ pub struct RegionInferenceContext<'tcx> { /// visible from this index. scc_universes: IndexVec<ConstraintSccIndex, ty::UniverseIndex>, - /// Contains a "representative" from each SCC. This will be the - /// minimal RegionVid belonging to that universe. It is used as a - /// kind of hacky way to manage checking outlives relationships, + /// Contains the "representative" region of each SCC. + /// It is defined as the one with the minimal RegionVid, favoring + /// free regions, then placeholders, then existential regions. + /// + /// It is a hacky way to manage checking regions for equality, /// since we can 'canonicalize' each region to the representative /// of its SCC and be sure that -- if they have the same repr -- /// they *must* be equal (though not having the same repr does not @@ -481,8 +483,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { scc_universes } - /// For each SCC, we compute a unique `RegionVid` (in fact, the - /// minimal one that belongs to the SCC). See + /// For each SCC, we compute a unique `RegionVid`. See the /// `scc_representatives` field of `RegionInferenceContext` for /// more details. fn compute_scc_representatives( @@ -490,13 +491,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { definitions: &IndexSlice<RegionVid, RegionDefinition<'tcx>>, ) -> IndexVec<ConstraintSccIndex, ty::RegionVid> { let num_sccs = constraints_scc.num_sccs(); - let next_region_vid = definitions.next_index(); - let mut scc_representatives = IndexVec::from_elem_n(next_region_vid, num_sccs); - - for region_vid in definitions.indices() { - let scc = constraints_scc.scc(region_vid); - let prev_min = scc_representatives[scc]; - scc_representatives[scc] = region_vid.min(prev_min); + let mut scc_representatives = IndexVec::from_elem_n(RegionVid::MAX, num_sccs); + + // Iterate over all RegionVids *in-order* and pick the least RegionVid as the + // representative of its SCC. This naturally prefers free regions over others. + for (vid, def) in definitions.iter_enumerated() { + let repr = &mut scc_representatives[constraints_scc.scc(vid)]; + if *repr == ty::RegionVid::MAX { + *repr = vid; + } else if matches!(def.origin, NllRegionVariableOrigin::Placeholder(_)) + && matches!(definitions[*repr].origin, NllRegionVariableOrigin::Existential { .. }) + { + // Pick placeholders over existentials even if they have a greater RegionVid. + *repr = vid; + } } scc_representatives diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d5875a226fe..63b80445817 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,15 +1,14 @@ -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; -use rustc_infer::infer::InferCtxt; use rustc_infer::infer::TyCtxtInferExt as _; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_macros::extension; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::RegionVid; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_span::Span; @@ -18,76 +17,19 @@ use rustc_trait_selection::traits::ObligationCtxt; use crate::session_diagnostics::LifetimeMismatchOpaqueParam; use crate::session_diagnostics::NonGenericOpaqueTypeParam; +use crate::universal_regions::RegionClassification; use super::RegionInferenceContext; impl<'tcx> RegionInferenceContext<'tcx> { - fn universal_name(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> { - let scc = self.constraint_sccs.scc(vid); - self.scc_values - .universal_regions_outlived_by(scc) - .find_map(|lb| self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)) - } - - fn generic_arg_to_region(&self, arg: ty::GenericArg<'tcx>) -> Option<RegionVid> { - let region = arg.as_region()?; - - if let ty::RePlaceholder(..) = region.kind() { - None - } else { - Some(self.to_region_vid(region)) - } - } - - /// Check that all opaque types have the same region parameters if they have the same - /// 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. - fn check_unique( - &self, - infcx: &InferCtxt<'tcx>, - opaque_ty_decls: &FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, - ) { - for (i, (a, a_ty)) in opaque_ty_decls.iter().enumerate() { - for (b, b_ty) in opaque_ty_decls.iter().skip(i + 1) { - if a.def_id != b.def_id { - continue; - } - // Non-lifetime params differ -> ok - if infcx.tcx.erase_regions(a.args) != infcx.tcx.erase_regions(b.args) { - continue; - } - trace!(?a, ?b); - for (a, b) in a.args.iter().zip(b.args) { - trace!(?a, ?b); - let Some(r1) = self.generic_arg_to_region(a) else { - continue; - }; - let Some(r2) = self.generic_arg_to_region(b) else { - continue; - }; - if self.eval_equal(r1, r2) { - continue; - } - - infcx.dcx().emit_err(LifetimeMismatchOpaqueParam { - arg: self.universal_name(r1).unwrap().into(), - prev: self.universal_name(r2).unwrap().into(), - span: a_ty.span, - prev_span: b_ty.span, - }); - } - } - } - } - /// 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. /// /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`. /// This is lowered to give HIR something like /// - /// type f<'a>::_Return<'_a> = impl Sized + '_a; - /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x } + /// type f<'a>::_Return<'_x> = impl Sized + '_x; + /// fn f<'a>(x: &'a i32) -> f<'a>::_Return<'a> { x } /// /// When checking the return type record the type from the return and the /// type used in the return value. In this case they might be `_Return<'1>` @@ -95,118 +37,102 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// Once we to this method, we have completed region inference and want to /// call `infer_opaque_definition_from_instantiation` to get the inferred - /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation` + /// type of `_Return<'_x>`. `infer_opaque_definition_from_instantiation` /// compares lifetimes directly, so we need to map the inference variables /// back to concrete lifetimes: `'static`, `ReEarlyParam` or `ReLateParam`. /// - /// First we map all the lifetimes in the concrete type to an equal - /// universal region that occurs in the concrete type's args, in this case - /// this would result in `&'1 i32`. We only consider regions in the args + /// First we map the regions in the the generic parameters `_Return<'1>` to + /// their `external_name` giving `_Return<'a>`. This step is a bit involved. + /// See the [rustc-dev-guide chapter] for more info. + /// + /// Then we map all the lifetimes in the concrete type to an equal + /// universal region that occurs in the opaque type's args, in this case + /// this would result in `&'a i32`. We only consider regions in the args /// in case there is an equal region that does not. For example, this should /// be allowed: /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }` /// - /// Then we map the regions in both the type and the generic parameters to their - /// `external_name` giving `concrete_type = &'a i32`, - /// `args = ['static, 'a]`. This will then allow - /// `infer_opaque_definition_from_instantiation` to determine that - /// `_Return<'_a> = &'_a i32`. + /// This will then allow `infer_opaque_definition_from_instantiation` to + /// determine that `_Return<'_x> = &'_x i32`. /// /// There's a slight complication around closures. Given /// `fn f<'a: 'a>() { || {} }` the closure's type is something like /// `f::<'a>::{{closure}}`. The region parameter from f is essentially /// ignored by type checking so ends up being inferred to an empty region. /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, - /// which has no `external_name` in which case we use `'empty` as the + /// which has no `external_name` in which case we use `'{erased}` as the /// region to pass to `infer_opaque_definition_from_instantiation`. + /// + /// [rustc-dev-guide chapter]: + /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html #[instrument(level = "debug", skip(self, infcx), ret)] pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'tcx>, opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, ) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> { - self.check_unique(infcx, &opaque_ty_decls); - let mut result: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> = FxIndexMap::default(); - - let member_constraints: FxIndexMap<_, _> = self - .member_constraints - .all_indices() - .map(|ci| (self.member_constraints[ci].key, ci)) - .collect(); - debug!(?member_constraints); + let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> = + FxIndexMap::default(); for (opaque_type_key, concrete_type) in opaque_ty_decls { - let args = opaque_type_key.args; - debug!(?concrete_type, ?args); + debug!(?opaque_type_key, ?concrete_type); - let mut arg_regions = vec![self.universal_regions.fr_static]; + let mut arg_regions: Vec<(ty::RegionVid, ty::Region<'_>)> = + vec![(self.universal_regions.fr_static, infcx.tcx.lifetimes.re_static)]; - let to_universal_region = |vid, arg_regions: &mut Vec<_>| match self.universal_name(vid) - { - Some(region) => { - let vid = self.universal_regions.to_region_vid(region); - arg_regions.push(vid); - region - } - None => { - arg_regions.push(vid); - ty::Region::new_error_with_message( - infcx.tcx, - concrete_type.span, - "opaque type with non-universal region args", - ) - } - }; + let opaque_type_key = + opaque_type_key.fold_captured_lifetime_args(infcx.tcx, |region| { + // Use the SCC representative instead of directly using `region`. + // See [rustc-dev-guide chapter] § "Strict lifetime equality". + let scc = self.constraint_sccs.scc(region.as_var()); + let vid = self.scc_representatives[scc]; + let named = match self.definitions[vid].origin { + // Iterate over all universal regions in a consistent order and find the + // *first* equal region. This makes sure that equal lifetimes will have + // the same name and simplifies subsequent handling. + // See [rustc-dev-guide chapter] § "Semantic lifetime equality". + NllRegionVariableOrigin::FreeRegion => self + .universal_regions + .universal_regions() + .filter(|&ur| { + // See [rustc-dev-guide chapter] § "Closure restrictions". + !matches!( + self.universal_regions.region_classification(ur), + Some(RegionClassification::External) + ) + }) + .find(|&ur| self.universal_region_relations.equal(vid, ur)) + .map(|ur| self.definitions[ur].external_name.unwrap()), + NllRegionVariableOrigin::Placeholder(placeholder) => { + Some(ty::Region::new_placeholder(infcx.tcx, placeholder)) + } + NllRegionVariableOrigin::Existential { .. } => None, + } + .unwrap_or_else(|| { + ty::Region::new_error_with_message( + infcx.tcx, + concrete_type.span, + "opaque type with non-universal region args", + ) + }); - // Start by inserting universal regions from the member_constraint choice regions. - // This will ensure they get precedence when folding the regions in the concrete type. - if let Some(&ci) = member_constraints.get(&opaque_type_key) { - for &vid in self.member_constraints.choice_regions(ci) { - to_universal_region(vid, &mut arg_regions); - } - } - debug!(?arg_regions); - - // Next, insert universal regions from args, so we can translate regions that appear - // in them but are not subject to member constraints, for instance closure args. - let universal_args = infcx.tcx.fold_regions(args, |region, _| { - if let ty::RePlaceholder(..) = region.kind() { - // Higher kinded regions don't need remapping, they don't refer to anything outside of this the args. - return region; - } - let vid = self.to_region_vid(region); - to_universal_region(vid, &mut arg_regions) - }); - debug!(?universal_args); - debug!(?arg_regions); - - // Deduplicate the set of regions while keeping the chosen order. - let arg_regions = arg_regions.into_iter().collect::<FxIndexSet<_>>(); - debug!(?arg_regions); - - let universal_concrete_type = - infcx.tcx.fold_regions(concrete_type, |region, _| match *region { - ty::ReVar(vid) => arg_regions - .iter() - .find(|ur_vid| self.eval_equal(vid, **ur_vid)) - .and_then(|ur_vid| self.definitions[*ur_vid].external_name) - .unwrap_or(infcx.tcx.lifetimes.re_erased), - ty::RePlaceholder(_) => ty::Region::new_error_with_message( - infcx.tcx, - concrete_type.span, - "hidden type contains placeholders, we don't support higher kinded opaques yet", - ), - _ => region, + arg_regions.push((vid, named)); + named }); - debug!(?universal_concrete_type); + debug!(?opaque_type_key, ?arg_regions); + + let concrete_type = infcx.tcx.fold_regions(concrete_type, |region, _| { + arg_regions + .iter() + .find(|&&(arg_vid, _)| self.eval_equal(region.as_var(), arg_vid)) + .map(|&(_, arg_named)| arg_named) + .unwrap_or(infcx.tcx.lifetimes.re_erased) + }); + debug!(?concrete_type); - let opaque_type_key = - OpaqueTypeKey { def_id: opaque_type_key.def_id, args: universal_args }; - let ty = infcx.infer_opaque_definition_from_instantiation( - opaque_type_key, - universal_concrete_type, - ); + let ty = + infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type); // Sometimes two opaque types are the same only after we remap the generic parameters // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)` // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that @@ -234,6 +160,29 @@ impl<'tcx> RegionInferenceContext<'tcx> { OpaqueHiddenType { ty, span: concrete_type.span }, ); } + + // Check that all opaque types have the same region parameters if they have the same + // 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) + { + infcx.dcx().emit_err(LifetimeMismatchOpaqueParam { + arg: arg1, + prev: arg2, + span: prev_span, + prev_span: concrete_type.span, + }); + } } result } @@ -422,42 +371,46 @@ fn check_opaque_type_well_formed<'tcx>( } } -fn check_opaque_type_parameter_valid( - tcx: TyCtxt<'_>, - opaque_type_key: OpaqueTypeKey<'_>, +/// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter]. +/// +/// [rustc-dev-guide chapter]: +/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html +fn check_opaque_type_parameter_valid<'tcx>( + tcx: TyCtxt<'tcx>, + opaque_type_key: OpaqueTypeKey<'tcx>, span: Span, ) -> Result<(), ErrorGuaranteed> { - let opaque_ty_hir = tcx.hir().expect_item(opaque_type_key.def_id); - let (parent, is_ty_alias) = match opaque_ty_hir.expect_opaque_ty().origin { - OpaqueTyOrigin::TyAlias { parent, .. } => (parent, true), - OpaqueTyOrigin::AsyncFn(parent) | OpaqueTyOrigin::FnReturn(parent) => (parent, false), - }; - - let parent_generics = tcx.generics_of(parent); + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); - // Only check the parent generics, which will ignore any of the - // duplicated lifetime args that come from reifying late-bounds. - for (i, arg) in opaque_type_key.args.iter().take(parent_generics.count()).enumerate() { + for (i, arg) in opaque_type_key.iter_captured_args(tcx) { let arg_is_param = match arg.unpack() { GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - GenericArgKind::Lifetime(lt) if is_ty_alias => { + GenericArgKind::Lifetime(lt) => { matches!(*lt, ty::ReEarlyParam(_) | ty::ReLateParam(_)) + || (lt.is_static() && opaque_env.param_equal_static(i)) } - // FIXME(#113916): we can't currently check for unique lifetime params, - // see that issue for more. We will also have to ignore unused lifetime - // params for RPIT, but that's comparatively trivial ✨ - GenericArgKind::Lifetime(_) => continue, GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)), }; if arg_is_param { - seen_params.entry(arg).or_default().push(i); + // Register if the same lifetime appears multiple times in the generic args. + // There is an exception when the opaque type *requires* the lifetimes to be equal. + // See [rustc-dev-guide chapter] § "An exception to uniqueness rule". + let seen_where = seen_params.entry(arg).or_default(); + if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) { + seen_where.push(i); + } } else { // Prevent `fn foo() -> Foo<u32>` from being defining. - let opaque_param = parent_generics.param_at(i, tcx); + let opaque_param = opaque_generics.param_at(i, tcx); let kind = opaque_param.kind.descr(); + if let Err(guar) = opaque_env.param_is_error(i) { + return Err(guar); + } + return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam { ty: arg, kind, @@ -469,10 +422,10 @@ fn check_opaque_type_parameter_valid( for (_, indices) in seen_params { if indices.len() > 1 { - let descr = parent_generics.param_at(indices[0], tcx).kind.descr(); + let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); let spans: Vec<_> = indices .into_iter() - .map(|i| tcx.def_span(parent_generics.param_at(i, tcx).def_id)) + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) .collect(); #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] @@ -486,3 +439,91 @@ fn check_opaque_type_parameter_valid( Ok(()) } + +/// Computes if an opaque type requires a lifetime parameter to be equal to +/// another one or to the `'static` lifetime. +/// These requirements are derived from the explicit and implied bounds. +struct LazyOpaqueTyEnv<'tcx> { + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + + /// Equal parameters will have the same name. Computed Lazily. + /// Example: + /// `type Opaque<'a: 'static, 'b: 'c, 'c: 'b> = impl Sized;` + /// Identity args: `['a, 'b, 'c]` + /// Canonical args: `['static, 'b, 'b]` + canonical_args: std::cell::OnceCell<ty::GenericArgsRef<'tcx>>, +} + +impl<'tcx> LazyOpaqueTyEnv<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { + Self { tcx, def_id, canonical_args: std::cell::OnceCell::new() } + } + + pub fn param_equal_static(&self, param_index: usize) -> bool { + self.get_canonical_args()[param_index].expect_region().is_static() + } + + pub fn params_equal(&self, param1: usize, param2: usize) -> bool { + let canonical_args = self.get_canonical_args(); + canonical_args[param1] == canonical_args[param2] + } + + pub fn param_is_error(&self, param_index: usize) -> Result<(), ErrorGuaranteed> { + self.get_canonical_args()[param_index].error_reported() + } + + fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> { + use rustc_hir as hir; + use rustc_infer::infer::outlives::env::OutlivesEnvironment; + use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; + + if let Some(&canonical_args) = self.canonical_args.get() { + return canonical_args; + } + + let &Self { tcx, def_id, .. } = self; + let origin = tcx.opaque_type_origin(def_id); + let parent = match origin { + hir::OpaqueTyOrigin::FnReturn(parent) + | hir::OpaqueTyOrigin::AsyncFn(parent) + | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent, + }; + let param_env = tcx.param_env(parent); + let args = GenericArgs::identity_for_item(tcx, parent).extend_to( + tcx, + def_id.to_def_id(), + |param, _| { + tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into() + }, + ); + + let infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + + let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| { + tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds"); + Default::default() + }); + let implied_bounds = infcx.implied_bounds_tys(param_env, parent, &wf_tys); + let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + + let mut seen = vec![tcx.lifetimes.re_static]; + let canonical_args = tcx.fold_regions(args, |r1, _| { + if r1.is_error() { + r1 + } else if let Some(&r2) = seen.iter().find(|&&r2| { + let free_regions = outlives_env.free_region_map(); + free_regions.sub_free_regions(tcx, r1, r2) + && free_regions.sub_free_regions(tcx, r2, r1) + }) { + r2 + } else { + seen.push(r1); + r1 + } + }); + self.canonical_args.set(canonical_args).unwrap(); + canonical_args + } +} diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index eeb944702a7..f94001de357 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -1,6 +1,5 @@ use crate::constraints::ConstraintSccIndex; use crate::RegionInferenceContext; -use itertools::Itertools; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::vec_graph::VecGraph; use rustc_data_structures::graph::WithSuccessors; @@ -48,16 +47,16 @@ impl RegionInferenceContext<'_> { .universal_regions .universal_regions() .map(|region| (self.constraint_sccs.scc(region), region)) - .collect_vec(); + .collect::<Vec<_>>(); paired_scc_regions.sort(); let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect(); let mut scc_regions = FxIndexMap::default(); let mut start = 0; - for (scc, group) in &paired_scc_regions.into_iter().group_by(|(scc, _)| *scc) { - let group_size = group.count(); - scc_regions.insert(scc, start..start + group_size); - start += group_size; + for chunk in paired_scc_regions.chunk_by(|&(scc1, _), &(scc2, _)| scc1 == scc2) { + let (scc, _) = chunk[0]; + scc_regions.insert(scc, start..start + chunk.len()); + start += chunk.len(); } self.rev_scc_graph = Some(ReverseSccGraph { graph, scc_regions, universal_regions }); diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 86d20599a2a..7553e3ee04f 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -164,6 +164,13 @@ impl UniversalRegionRelations<'_> { self.outlives.contains(fr1, fr2) } + /// Returns `true` if fr1 is known to equal fr2. + /// + /// This will only ever be true for universally quantified regions. + pub(crate) fn equal(&self, fr1: RegionVid, fr2: RegionVid) -> bool { + self.outlives.contains(fr1, fr2) && self.outlives.contains(fr2, fr1) + } + /// Returns a vector of free regions `x` such that `fr1: x` is /// known to hold. pub(crate) fn regions_outlived_by(&self, fr1: RegionVid) -> Vec<RegionVid> { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a206aac0467..b72dccb2ebd 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -229,6 +229,22 @@ pub(crate) fn type_check<'mir, 'tcx>( ); } + // Convert all regions to nll vars. + let (opaque_type_key, hidden_type) = + infcx.tcx.fold_regions((opaque_type_key, hidden_type), |region, _| { + match region.kind() { + ty::ReVar(_) => region, + ty::RePlaceholder(placeholder) => checker + .borrowck_context + .constraints + .placeholder_region(infcx, placeholder), + _ => ty::Region::new_var( + infcx.tcx, + checker.borrowck_context.universal_regions.to_region_vid(region), + ), + } + }); + (opaque_type_key, hidden_type) }) .collect(); diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 9b360fb3036..f4e10f7dd19 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -41,21 +41,6 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR # missing features # ================ -# requires stack unwinding -# FIXME add needs-unwind to these tests -rm -r tests/run-make/libtest-junit -rm tests/ui/asm/may_unwind.rs -rm tests/ui/stable-mir-print/basic_function.rs - -# extra warning about -Cpanic=abort for proc macros -rm tests/ui/proc-macro/crt-static.rs -rm tests/ui/proc-macro/proc-macro-deprecated-attr.rs -rm tests/ui/proc-macro/quote-debug.rs -rm tests/ui/proc-macro/no-missing-docs.rs -rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs -rm tests/ui/proc-macro/allowed-signatures.rs -rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs - # vendor intrinsics rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant" rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic @@ -154,7 +139,6 @@ rm tests/ui/codegen/subtyping-enforces-type-equality.rs # assert_assignable bug # ====================== rm tests/ui/backtrace.rs # TODO warning rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue -rm tests/ui/async-await/async-closures/once.rs # FIXME bug in the rustc FnAbi calculation code rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index a5a5ae73d77..1a32958d362 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout, }; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_session::config::OptLevel; use rustc_span::Span; use rustc_symbol_mangling::typeid::{ kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance, @@ -551,6 +552,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { layout: TyAndLayout<'tcx>, offset: Size, ) { + if bx.cx.sess().opts.optimize == OptLevel::No { + // Don't emit metadata we're not going to use + return; + } + if !scalar.is_uninit_valid() { bx.noundef_metadata(load); } @@ -667,6 +673,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { return; } + if self.cx.sess().opts.optimize == OptLevel::No { + // Don't emit metadata we're not going to use + return; + } + unsafe { let llty = self.cx.val_ty(load); let v = [ @@ -1630,7 +1641,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } let typeid = if let Some(instance) = instance { - typeid_for_instance(self.tcx, &instance, options) + typeid_for_instance(self.tcx, instance, options) } else { typeid_for_fnabi(self.tcx, fn_abi, options) }; @@ -1678,7 +1689,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } let kcfi_typeid = if let Some(instance) = instance { - kcfi_typeid_for_instance(self.tcx, &instance, options) + kcfi_typeid_for_instance(self.tcx, instance, options) } else { kcfi_typeid_for_fnabi(self.tcx, fn_abi, options) }; diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 78c0725a637..1a2498c75a7 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -141,17 +141,17 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { if self.tcx.sess.is_sanitizer_cfi_enabled() { if let Some(instance) = instance { - let typeid = typeid_for_instance(self.tcx, &instance, TypeIdOptions::empty()); + let typeid = typeid_for_instance(self.tcx, instance, TypeIdOptions::empty()); self.set_type_metadata(llfn, typeid); let typeid = - typeid_for_instance(self.tcx, &instance, TypeIdOptions::GENERALIZE_POINTERS); + typeid_for_instance(self.tcx, instance, TypeIdOptions::GENERALIZE_POINTERS); self.add_type_metadata(llfn, typeid); let typeid = - typeid_for_instance(self.tcx, &instance, TypeIdOptions::NORMALIZE_INTEGERS); + typeid_for_instance(self.tcx, instance, TypeIdOptions::NORMALIZE_INTEGERS); self.add_type_metadata(llfn, typeid); let typeid = typeid_for_instance( self.tcx, - &instance, + instance, TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS, ); self.add_type_metadata(llfn, typeid); @@ -182,7 +182,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } if let Some(instance) = instance { - let kcfi_typeid = kcfi_typeid_for_instance(self.tcx, &instance, options); + let kcfi_typeid = kcfi_typeid_for_instance(self.tcx, instance, options); self.set_kcfi_type_metadata(llfn, kcfi_typeid); } else { let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 4eda4c2f08c..b7bcaac3b18 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -592,7 +592,7 @@ fn produce_final_output_artifacts( .unwrap() .to_owned(); - if crate_output.outputs.contains_key(&output_type) { + if crate_output.outputs.contains_explicit_name(&output_type) { // 2) Multiple codegen units, with `--emit foo=some_name`. We have // no good solution for this case, so warn the user. sess.dcx().emit_warn(errors::IgnoringEmitPath { extension }); diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 0046190d20c..d6aae60c338 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -146,6 +146,8 @@ const_eval_intern_kind = {$kind -> *[other] {""} } +const_eval_interrupted = compilation was interrupted + const_eval_invalid_align_details = invalid align passed to `{$name}`: {$align} is {$err_kind -> [not_power_of_two] not a power of 2 diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 5a1c7cc4209..098a6201c4e 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -1,3 +1,5 @@ +use std::sync::atomic::Ordering::Relaxed; + use either::{Left, Right}; use rustc_hir::def::DefKind; @@ -22,6 +24,7 @@ use crate::interpret::{ InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, }; +use crate::CTRL_C_RECEIVED; // Returns a pointer to where the result lives #[instrument(level = "trace", skip(ecx, body))] @@ -79,7 +82,11 @@ fn eval_body_using_ecx<'mir, 'tcx, R: InterpretationResult<'tcx>>( ecx.storage_live_for_always_live_locals()?; // The main interpreter loop. - while ecx.step()? {} + while ecx.step()? { + if CTRL_C_RECEIVED.load(Relaxed) { + throw_exhaust!(Interrupted); + } + } // Intern the result intern_const_alloc_recursive(ecx, intern_kind, &ret)?; diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index cc32640408b..5c46ec799f1 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -884,6 +884,7 @@ impl ReportErrorExt for ResourceExhaustionInfo { ResourceExhaustionInfo::StackFrameLimitReached => const_eval_stack_frame_limit_reached, ResourceExhaustionInfo::MemoryExhausted => const_eval_memory_exhausted, ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full, + ResourceExhaustionInfo::Interrupted => const_eval_interrupted, } } fn add_args<G: EmissionGuarantee>(self, _: &mut Diag<'_, G>) {} diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 633caf8d092..50420aaec04 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -32,6 +32,8 @@ pub mod interpret; pub mod transform; pub mod util; +use std::sync::atomic::AtomicBool; + pub use errors::ReportErrorExt; use rustc_middle::{ty, util::Providers}; @@ -58,3 +60,8 @@ pub fn provide(providers: &mut Providers) { util::check_validity_requirement(tcx, init_kind, param_env_and_ty) }; } + +/// `rustc_driver::main` installs a handler that will set this to `true` if +/// the compiler has been sent a request to shut down, such as by a Ctrl-C. +/// This static lives here because it is only read by the interpreter. +pub static CTRL_C_RECEIVED: AtomicBool = AtomicBool::new(false); diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index fcc0afd3488..e4fb13822f8 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +ctrlc = "3.4.4" rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_passes = { path = "../rustc_ast_passes" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 716e31080dd..b4007aeb8d7 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -19,6 +19,7 @@ extern crate tracing; use rustc_ast as ast; use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults}; +use rustc_const_eval::CTRL_C_RECEIVED; use rustc_data_structures::profiling::{ get_resident_set_size, print_time_passes_entry, TimePassesFormat, }; @@ -1518,6 +1519,22 @@ pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) { } } +/// Install our usual `ctrlc` handler, which sets [`rustc_const_eval::CTRL_C_RECEIVED`]. +/// Making this handler optional lets tools can install a different handler, if they wish. +pub fn install_ctrlc_handler() { + ctrlc::set_handler(move || { + // Indicate that we have been signaled to stop. If we were already signaled, exit + // immediately. In our interpreter loop we try to consult this value often, but if for + // whatever reason we don't get to that check or the cleanup we do upon finding that + // this bool has become true takes a long time, the exit here will promptly exit the + // process on the second Ctrl-C. + if CTRL_C_RECEIVED.swap(true, Ordering::Relaxed) { + std::process::exit(1); + } + }) + .expect("Unable to install ctrlc handler"); +} + pub fn main() -> ! { let start_time = Instant::now(); let start_rss = get_resident_set_size(); @@ -1528,6 +1545,8 @@ pub fn main() -> ! { signal_handler::install(); let mut callbacks = TimePassesCallbacks::default(); let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ()); + install_ctrlc_handler(); + let exit_code = catch_with_exit_code(|| { RunCompiler::new(&args::raw_args(&early_dcx)?, &mut callbacks) .set_using_internal_features(using_internal_features) diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 27a26cfe474..ee3436805ca 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -793,12 +793,20 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fd: &'tcx hir::FnDecl<'tcx>, body_id: hir::BodyId, _: Span, - _: LocalDefId, + def_id: LocalDefId, ) { let output = match fd.output { hir::FnRetTy::DefaultReturn(_) => None, hir::FnRetTy::Return(ty) => Some(ty), }; + if let Some(ty) = output + && let hir::TyKind::InferDelegation(sig_id, _) = ty.kind + { + let bound_vars: Vec<_> = + self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect(); + let hir_id = self.tcx.local_def_id_to_hir_id(def_id); + self.map.late_bound_vars.insert(hir_id, bound_vars); + } self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure)); intravisit::walk_fn_kind(self, fk); self.visit_nested_body(body_id) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index b865bf976b5..a119ea450b4 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2492,13 +2492,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_ty: Option<&hir::Ty<'_>>, ) -> ty::PolyFnSig<'tcx> { let tcx = self.tcx(); - let bound_vars = if let hir::FnRetTy::Return(ret_ty) = decl.output - && let hir::TyKind::InferDelegation(sig_id, _) = ret_ty.kind - { - tcx.fn_sig(sig_id).skip_binder().bound_vars() - } else { - tcx.late_bound_vars(hir_id) - }; + let bound_vars = tcx.late_bound_vars(hir_id); debug!(?bound_vars); // We proactively collect all the inferred type params to emit a single error per fn def. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7ecd380ebeb..4dc60f7c6da 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -919,8 +919,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, E0533, expected); return Ty::new_error(tcx, e); } - Res::SelfCtor(..) - | Res::Def( + Res::SelfCtor(def_id) => { + if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind() + && adt_def.is_struct() + && let Some((CtorKind::Const, _)) = adt_def.non_enum_variant().ctor + { + // Ok, we allow unit struct ctors in patterns only. + } else { + let e = report_unexpected_variant_res( + tcx, + res, + qpath, + pat.span, + E0533, + "unit struct", + ); + return Ty::new_error(tcx, e); + } + } + Res::Def( DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::AssocConst diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index d78ec8c0dd3..9fae32a49c7 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -73,10 +73,10 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { self.inlined_check_id(id); debug!("early context: enter_attrs({:?})", attrs); - lint_callback!(self, enter_lint_attrs, attrs); + lint_callback!(self, check_attributes, attrs); ensure_sufficient_stack(|| f(self)); debug!("early context: exit_attrs({:?})", attrs); - lint_callback!(self, exit_lint_attrs, attrs); + lint_callback!(self, check_attributes_post, attrs); self.context.builder.pop(push); } } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 384bd353d75..99207e3f315 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -15,7 +15,6 @@ //! for all lint attributes. use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore}; -use rustc_ast as ast; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::{join, Lrc}; use rustc_hir as hir; @@ -62,13 +61,13 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { let prev = self.context.last_node_with_lint_attrs; self.context.last_node_with_lint_attrs = id; debug!("late context: enter_attrs({:?})", attrs); - lint_callback!(self, enter_lint_attrs, attrs); + lint_callback!(self, check_attributes, attrs); for attr in attrs { lint_callback!(self, check_attribute, attr); } f(self); debug!("late context: exit_attrs({:?})", attrs); - lint_callback!(self, exit_lint_attrs, attrs); + lint_callback!(self, check_attributes_post, attrs); self.context.last_node_with_lint_attrs = prev; } @@ -310,10 +309,6 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas lint_callback!(self, check_path, p, id); hir_visit::walk_path(self, p); } - - fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) { - lint_callback!(self, check_attribute, attr); - } } // Combines multiple lint passes into a single pass, at runtime. Each diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 3e93cc0be6a..d8ba84eb7a1 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -41,13 +41,8 @@ macro_rules! late_lint_methods { fn check_variant(a: &'tcx rustc_hir::Variant<'tcx>); fn check_path(a: &rustc_hir::Path<'tcx>, b: rustc_hir::HirId); fn check_attribute(a: &'tcx rustc_ast::Attribute); - - /// Called when entering a syntax node that can have lint attributes such - /// as `#[allow(...)]`. Called with *all* the attributes of that node. - fn enter_lint_attrs(a: &'tcx [rustc_ast::Attribute]); - - /// Counterpart to `enter_lint_attrs`. - fn exit_lint_attrs(a: &'tcx [rustc_ast::Attribute]); + fn check_attributes(a: &'tcx [rustc_ast::Attribute]); + fn check_attributes_post(a: &'tcx [rustc_ast::Attribute]); ]); ) } @@ -162,16 +157,11 @@ macro_rules! early_lint_methods { fn check_impl_item(a: &rustc_ast::AssocItem); fn check_variant(a: &rustc_ast::Variant); fn check_attribute(a: &rustc_ast::Attribute); + fn check_attributes(a: &[rustc_ast::Attribute]); + fn check_attributes_post(a: &[rustc_ast::Attribute]); fn check_mac_def(a: &rustc_ast::MacroDef); fn check_mac(a: &rustc_ast::MacCall); - /// Called when entering a syntax node that can have lint attributes such - /// as `#[allow(...)]`. Called with *all* the attributes of that node. - fn enter_lint_attrs(a: &[rustc_ast::Attribute]); - - /// Counterpart to `enter_lint_attrs`. - fn exit_lint_attrs(a: &[rustc_ast::Attribute]); - fn enter_where_predicate(a: &rustc_ast::WherePredicate); fn exit_where_predicate(a: &rustc_ast::WherePredicate); ]); diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 751d6de83f9..c86970635a5 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -482,6 +482,8 @@ pub enum ResourceExhaustionInfo { MemoryExhausted, /// The address space (of the target) is full. AddressSpaceFull, + /// The compiler got an interrupt signal (a user ran out of patience). + Interrupted, } /// A trait for machine-specific errors (or other "machine stop" conditions). diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 65574f5702b..4fec5653a79 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -335,7 +335,7 @@ impl<'tcx> InstanceDef<'tcx> { fn fmt_instance( f: &mut fmt::Formatter<'_>, - instance: &Instance<'_>, + instance: Instance<'_>, type_length: Option<rustc_session::Limit>, ) -> fmt::Result { ty::tls::with(|tcx| { @@ -369,9 +369,9 @@ fn fmt_instance( } } -pub struct ShortInstance<'a, 'tcx>(pub &'a Instance<'tcx>, pub usize); +pub struct ShortInstance<'tcx>(pub Instance<'tcx>, pub usize); -impl<'a, 'tcx> fmt::Display for ShortInstance<'a, 'tcx> { +impl<'tcx> fmt::Display for ShortInstance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt_instance(f, self.0, Some(rustc_session::Limit(self.1))) } @@ -379,7 +379,7 @@ impl<'a, 'tcx> fmt::Display for ShortInstance<'a, 'tcx> { impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_instance(f, self, None) + fmt_instance(f, *self, None) } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6ce53ccc8cd..0be1a1ab39d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -832,6 +832,38 @@ pub struct OpaqueTypeKey<'tcx> { pub args: GenericArgsRef<'tcx>, } +impl<'tcx> OpaqueTypeKey<'tcx> { + pub fn iter_captured_args( + self, + tcx: TyCtxt<'tcx>, + ) -> impl Iterator<Item = (usize, GenericArg<'tcx>)> { + std::iter::zip(self.args, tcx.variances_of(self.def_id)).enumerate().filter_map( + |(i, (arg, v))| match (arg.unpack(), v) { + (_, ty::Invariant) => Some((i, arg)), + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None, + _ => bug!("unexpected opaque type arg variance"), + }, + ) + } + + pub fn fold_captured_lifetime_args( + self, + tcx: TyCtxt<'tcx>, + mut f: impl FnMut(Region<'tcx>) -> Region<'tcx>, + ) -> Self { + let Self { def_id, args } = self; + let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| { + match (arg.unpack(), v) { + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, + (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(), + _ => arg, + } + }); + let args = tcx.mk_args_from_iter(args); + Self { def_id, args } + } +} + #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] pub struct OpaqueHiddenType<'tcx> { /// The span of this particular definition of the opaque type. So diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 3f0a3a1a7bf..914b19efc7e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -804,7 +804,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } ty::Str => p!("str"), ty::Coroutine(did, args) => { - p!(write("{{")); + p!("{{"); let coroutine_kind = self.tcx().coroutine_kind(did).unwrap(); let should_print_movability = self.should_print_verbose() || matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)); @@ -818,9 +818,17 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { if !self.should_print_verbose() { p!(write("{}", coroutine_kind)); - // FIXME(eddyb) should use `def_span`. - if let Some(did) = did.as_local() { - let span = self.tcx().def_span(did); + if coroutine_kind.is_fn_like() { + // If we are printing an `async fn` coroutine type, then give the path + // of the fn, instead of its span, because that will in most cases be + // more helpful for the reader than just a source location. + // + // This will look like: + // {async fn body of some_fn()} + let did_of_the_fn_item = self.tcx().parent(did); + p!(" of ", print_def_path(did_of_the_fn_item, args), "()"); + } else if let Some(local_did) = did.as_local() { + let span = self.tcx().def_span(local_did); p!(write( "@{}", // This may end up in stderr diagnostics but it may also be emitted @@ -828,7 +836,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { self.tcx().sess.source_map().span_to_embeddable_string(span) )); } else { - p!(write("@"), print_def_path(did, args)); + p!("@", print_def_path(did, args)); } } else { p!(print_def_path(did, args)); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 78c0615b165..5f74841151c 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -165,7 +165,7 @@ impl<'tcx> Inliner<'tcx> { caller_body: &mut Body<'tcx>, callsite: &CallSite<'tcx>, ) -> Result<std::ops::Range<BasicBlock>, &'static str> { - self.check_mir_is_available(caller_body, &callsite.callee)?; + self.check_mir_is_available(caller_body, callsite.callee)?; let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id()); let cross_crate_inlinable = self.tcx.cross_crate_inlinable(callsite.callee.def_id()); @@ -298,7 +298,7 @@ impl<'tcx> Inliner<'tcx> { fn check_mir_is_available( &self, caller_body: &Body<'tcx>, - callee: &Instance<'tcx>, + callee: Instance<'tcx>, ) -> Result<(), &'static str> { let caller_def_id = caller_body.source.def_id(); let callee_def_id = callee.def_id(); @@ -354,7 +354,7 @@ impl<'tcx> Inliner<'tcx> { // If we know for sure that the function we're calling will itself try to // call us, then we avoid inlining that function. - if self.tcx.mir_callgraph_reachable((*callee, caller_def_id.expect_local())) { + if self.tcx.mir_callgraph_reachable((callee, caller_def_id.expect_local())) { return Err("caller might be reachable from callee (query cycle avoidance)"); } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index a51b1c34a1a..3285cbd0432 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -397,7 +397,7 @@ fn collect_items_rec<'tcx>( let instance = Instance::mono(tcx, def_id); // Sanity check whether this ended up being collected accidentally - debug_assert!(should_codegen_locally(tcx, &instance)); + debug_assert!(should_codegen_locally(tcx, instance)); let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() }; // Nested statics have no type. @@ -429,7 +429,7 @@ fn collect_items_rec<'tcx>( } MonoItem::Fn(instance) => { // Sanity check whether this ended up being collected accidentally - debug_assert!(should_codegen_locally(tcx, &instance)); + debug_assert!(should_codegen_locally(tcx, instance)); // Keep track of the monomorphization recursion depth recursion_depth_reset = Some(check_recursion_limit( @@ -474,7 +474,7 @@ fn collect_items_rec<'tcx>( } hir::InlineAsmOperand::SymStatic { path: _, def_id } => { let instance = Instance::mono(tcx, *def_id); - if should_codegen_locally(tcx, &instance) { + if should_codegen_locally(tcx, instance) { trace!("collecting static {:?}", def_id); used_items.push(dummy_spanned(MonoItem::Static(*def_id))); } @@ -557,7 +557,7 @@ fn collect_items_rec<'tcx>( /// If the type name is longer than before+after, it will be written to a file. fn shrunk_instance_name<'tcx>( tcx: TyCtxt<'tcx>, - instance: &Instance<'tcx>, + instance: Instance<'tcx>, ) -> (String, Option<PathBuf>) { let s = instance.to_string(); @@ -603,7 +603,7 @@ fn check_recursion_limit<'tcx>( if !recursion_limit.value_within_limit(adjusted_recursion_depth) { let def_span = tcx.def_span(def_id); let def_path_str = tcx.def_path_str(def_id); - let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance); + let (shrunk, written_to_path) = shrunk_instance_name(tcx, instance); let mut path = PathBuf::new(); let was_written = if let Some(written_to_path) = written_to_path { path = written_to_path; @@ -645,7 +645,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // // Bail out in these cases to avoid that bad user experience. if !tcx.type_length_limit().value_within_limit(type_length) { - let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance); + let (shrunk, written_to_path) = shrunk_instance_name(tcx, instance); let span = tcx.def_span(instance.def_id()); let mut path = PathBuf::new(); let was_written = if let Some(path2) = written_to_path { @@ -892,7 +892,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { if let ty::Closure(def_id, args) = *source_ty.kind() { let instance = Instance::resolve_closure(self.tcx, def_id, args, ty::ClosureKind::FnOnce); - if should_codegen_locally(self.tcx, &instance) { + if should_codegen_locally(self.tcx, instance) { self.used_items.push(create_fn_mono_item(self.tcx, instance, span)); } } else { @@ -902,7 +902,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { mir::Rvalue::ThreadLocalRef(def_id) => { assert!(self.tcx.is_thread_local_static(def_id)); let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, &instance) { + if should_codegen_locally(self.tcx, instance) { trace!("collecting thread-local static {:?}", def_id); self.used_items.push(respan(span, MonoItem::Static(def_id))); } @@ -929,7 +929,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let tcx = self.tcx; let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| { let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source))); - if should_codegen_locally(tcx, &instance) { + if should_codegen_locally(tcx, instance) { this.used_items.push(create_fn_mono_item(tcx, instance, source)); } }; @@ -962,7 +962,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { } mir::InlineAsmOperand::SymStatic { def_id } => { let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, &instance) { + if should_codegen_locally(self.tcx, instance) { trace!("collecting asm sym static {:?}", def_id); self.used_items.push(respan(source, MonoItem::Static(def_id))); } @@ -1051,7 +1051,7 @@ fn visit_instance_use<'tcx>( output: &mut MonoItems<'tcx>, ) { debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); - if !should_codegen_locally(tcx, &instance) { + if !should_codegen_locally(tcx, instance) { return; } if let ty::InstanceDef::Intrinsic(def_id) = instance.def { @@ -1063,13 +1063,13 @@ fn visit_instance_use<'tcx>( // codegen a call to that function without generating code for the function itself. let def_id = tcx.lang_items().get(LangItem::PanicNounwind).unwrap(); let panic_instance = Instance::mono(tcx, def_id); - if should_codegen_locally(tcx, &panic_instance) { + if should_codegen_locally(tcx, panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); } } else if tcx.has_attr(def_id, sym::rustc_intrinsic) { // Codegen the fallback body of intrinsics with fallback bodies let instance = ty::Instance::new(def_id, instance.args); - if should_codegen_locally(tcx, &instance) { + if should_codegen_locally(tcx, instance) { output.push(create_fn_mono_item(tcx, instance, source)); } } @@ -1107,7 +1107,7 @@ fn visit_instance_use<'tcx>( /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we /// can just link to the upstream crate and therefore don't need a mono item. -pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { +pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool { let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else { return true; }; @@ -1304,7 +1304,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( None } VtblEntry::Method(instance) => { - Some(*instance).filter(|instance| should_codegen_locally(tcx, instance)) + Some(*instance).filter(|instance| should_codegen_locally(tcx, *instance)) } }) .map(|item| create_fn_mono_item(tcx, item, source)); @@ -1321,7 +1321,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); let instance = Instance::mono(tcx, def_id); - if should_codegen_locally(tcx, &instance) { + if should_codegen_locally(tcx, instance) { trace!("collecting static {:?}", def_id); output.push(dummy_spanned(MonoItem::Static(def_id))); } @@ -1339,7 +1339,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt } } GlobalAlloc::Function(fn_instance) => { - if should_codegen_locally(tcx, &fn_instance) { + if should_codegen_locally(tcx, fn_instance) { trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); } @@ -1474,7 +1474,7 @@ fn visit_mentioned_item<'tcx>( if let ty::Closure(def_id, args) = *source_ty.kind() { let instance = Instance::resolve_closure(tcx, def_id, args, ty::ClosureKind::FnOnce); - if should_codegen_locally(tcx, &instance) { + if should_codegen_locally(tcx, instance) { output.push(create_fn_mono_item(tcx, instance, span)); } } else { @@ -1736,7 +1736,7 @@ fn create_mono_items_for_default_impls<'tcx>( let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args); let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); - if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance) { + if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) { output.push(mono_item); } } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 4ec842e8f85..9c4a6e69a3c 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -64,7 +64,7 @@ pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>( !instance.def_id().is_local() && tcx.is_compiler_builtins(LOCAL_CRATE) && tcx.codegen_fn_attrs(instance.def_id()).link_name.is_none() - && !should_codegen_locally(tcx, &instance) + && !should_codegen_locally(tcx, instance) } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index c2e604b02b3..90f2bab65b1 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -1,9 +1,14 @@ -// Finds items that are externally reachable, to determine which items -// need to have their metadata (and possibly their AST) serialized. -// All items that can be referred to through an exported name are -// reachable, and when a reachable thing is inline or generic, it -// makes all other generics or inline functions that it references -// reachable as well. +//! Finds local items that are externally reachable, which means that other crates need access to +//! their compiled machine code or their MIR. +//! +//! An item is "externally reachable" if it is relevant for other crates. This obviously includes +//! all public items. However, some of these items cannot be compiled to machine code (because they +//! are generic), and for some the machine code is not sufficient (because we want to cross-crate +//! inline them). These items "need cross-crate MIR". When a reachable function `f` needs +//! cross-crate MIR, then all the functions it calls also become reachable, as they will be +//! necessary to use the MIR of `f` from another crate. Furthermore, an item can become "externally +//! reachable" by having a `const`/`const fn` return a pointer to that item, so we also need to +//! recurse into reachable `const`/`const fn`. use hir::def_id::LocalDefIdSet; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -21,7 +26,9 @@ use rustc_privacy::DefIdVisitor; use rustc_session::config::CrateType; use rustc_target::spec::abi::Abi; -fn item_might_be_inlined(tcx: TyCtxt<'_>, def_id: DefId) -> bool { +/// Determines whether this item is recursive for reachability. See `is_recursively_reachable_local` +/// below for details. +fn recursively_reachable(tcx: TyCtxt<'_>, def_id: DefId) -> bool { tcx.generics_of(def_id).requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id) || tcx.is_const_fn(def_id) @@ -54,12 +61,20 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { let res = match expr.kind { hir::ExprKind::Path(ref qpath) => { + // This covers fn ptr casts but also "non-method" calls. Some(self.typeck_results().qpath_res(qpath, expr.hir_id)) } - hir::ExprKind::MethodCall(..) => self - .typeck_results() - .type_dependent_def(expr.hir_id) - .map(|(kind, def_id)| Res::Def(kind, def_id)), + hir::ExprKind::MethodCall(..) => { + // Method calls don't involve a full "path", so we need to determine the callee + // based on the receiver type. + // If this is a method call on a generic type, we might not be able to find the + // callee. That's why `reachable_set` also adds all potential callees for such + // calls, i.e. all trait impl items, to the reachable set. So here we only worry + // about the calls we can identify. + self.typeck_results() + .type_dependent_def(expr.hir_id) + .map(|(kind, def_id)| Res::Def(kind, def_id)) + } hir::ExprKind::Closure(&hir::Closure { def_id, .. }) => { self.reachable_symbols.insert(def_id); None @@ -96,16 +111,24 @@ impl<'tcx> ReachableContext<'tcx> { .expect("`ReachableContext::typeck_results` called outside of body") } - // Returns true if the given def ID represents a local item that is - // eligible for inlining and false otherwise. - fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool { + /// Returns true if the given def ID represents a local item that is recursive for reachability, + /// i.e. whether everything mentioned in here also needs to be considered reachable. + /// + /// There are two reasons why an item may be recursively reachable: + /// - It needs cross-crate MIR (see the module-level doc comment above). + /// - It is a `const` or `const fn`. This is *not* because we need the MIR to interpret them + /// (MIR for const-eval and MIR for codegen is separate, and MIR for const-eval is always + /// encoded). Instead, it is because `const fn` can create `fn()` pointers to other items + /// which end up in the evaluated result of the constant and can then be called from other + /// crates. Those items must be considered reachable. + fn is_recursively_reachable_local(&self, def_id: DefId) -> bool { let Some(def_id) = def_id.as_local() else { return false; }; match self.tcx.hir_node_by_def_id(def_id) { Node::Item(item) => match item.kind { - hir::ItemKind::Fn(..) => item_might_be_inlined(self.tcx, def_id.into()), + hir::ItemKind::Fn(..) => recursively_reachable(self.tcx, def_id.into()), _ => false, }, Node::TraitItem(trait_method) => match trait_method.kind { @@ -117,7 +140,7 @@ impl<'tcx> ReachableContext<'tcx> { Node::ImplItem(impl_item) => match impl_item.kind { hir::ImplItemKind::Const(..) => true, hir::ImplItemKind::Fn(..) => { - item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id()) + recursively_reachable(self.tcx, impl_item.hir_id().owner.to_def_id()) } hir::ImplItemKind::Type(_) => false, }, @@ -174,7 +197,7 @@ impl<'tcx> ReachableContext<'tcx> { Node::Item(item) => { match item.kind { hir::ItemKind::Fn(.., body) => { - if item_might_be_inlined(self.tcx, item.owner_id.into()) { + if recursively_reachable(self.tcx, item.owner_id.into()) { self.visit_nested_body(body); } } @@ -228,7 +251,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit_nested_body(body); } hir::ImplItemKind::Fn(_, body) => { - if item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id()) { + if recursively_reachable(self.tcx, impl_item.hir_id().owner.to_def_id()) { self.visit_nested_body(body) } } @@ -316,7 +339,7 @@ impl<'tcx> ReachableContext<'tcx> { self.worklist.push(def_id); } _ => { - if self.def_id_represents_local_inlined_item(def_id.to_def_id()) { + if self.is_recursively_reachable_local(def_id.to_def_id()) { self.worklist.push(def_id); } else { self.reachable_symbols.insert(def_id); @@ -394,6 +417,7 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) } +/// See module-level doc comment above. fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet { let effective_visibilities = &tcx.effective_visibilities(()); @@ -427,14 +451,16 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet { } } { - // Some methods from non-exported (completely private) trait impls still have to be - // reachable if they are called from inlinable code. Generally, it's not known until - // monomorphization if a specific trait impl item can be reachable or not. So, we - // conservatively mark all of them as reachable. + // As explained above, we have to mark all functions called from reachable + // `item_might_be_inlined` items as reachable. The issue is, when those functions are + // generic and call a trait method, we have no idea where that call goes! So, we + // conservatively mark all trait impl items as reachable. // FIXME: One possible strategy for pruning the reachable set is to avoid marking impl // items of non-exported traits (or maybe all local traits?) unless their respective // trait items are used from inlinable code through method call syntax or UFCS, or their // trait is a lang item. + // (But if you implement this, don't forget to take into account that vtables can also + // make trait methods reachable!) let crate_items = tcx.hir_crate_items(()); for id in crate_items.free_items() { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a88ae268e27..c06fe29c567 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -557,6 +557,11 @@ impl OutputTypes { self.0.contains_key(key) } + /// Returns `true` if user specified a name and not just produced type + pub fn contains_explicit_name(&self, key: &OutputType) -> bool { + self.0.get(key).map_or(false, |f| f.is_some()) + } + pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> { self.0.iter() } diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs index 3bf564a4a16..1d28d2b732f 100644 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ b/compiler/rustc_symbol_mangling/src/typeid.rs @@ -33,10 +33,10 @@ pub fn typeid_for_fnabi<'tcx>( /// Returns a type metadata identifier for the specified Instance. pub fn typeid_for_instance<'tcx>( tcx: TyCtxt<'tcx>, - instance: &Instance<'tcx>, + instance: Instance<'tcx>, options: TypeIdOptions, ) -> String { - typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options) + typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options) } /// Returns a KCFI type metadata identifier for the specified FnAbi. @@ -55,12 +55,12 @@ pub fn kcfi_typeid_for_fnabi<'tcx>( /// Returns a KCFI type metadata identifier for the specified Instance. pub fn kcfi_typeid_for_instance<'tcx>( tcx: TyCtxt<'tcx>, - instance: &Instance<'tcx>, + instance: Instance<'tcx>, options: TypeIdOptions, ) -> u32 { // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) let mut hash: XxHash64 = Default::default(); - hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, *instance, options).as_bytes()); + hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes()); hash.finish() as u32 } |
