diff options
430 files changed, 6695 insertions, 3066 deletions
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 1dc5b0e9d08..f4e409e0d49 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -6,8 +6,6 @@ on: schedule: # Run weekly - cron: '0 0 * * Sun' - # Re-bump deps every 4 hours - - cron: '0 */4 * * *' workflow_dispatch: # Needed so we can run it manually permissions: @@ -42,7 +40,7 @@ jobs: # Exit with error if open and S-waiting-on-bors if [[ "$STATE" == "OPEN" && "$WAITING_ON_BORS" == "true" ]]; then - gh run cancel ${{ github.run_id }} + exit 1 fi update: @@ -65,10 +63,7 @@ jobs: - name: cargo update # Remove first line that always just says "Updating crates.io index" - # If there are no changes, cancel the job here - run: | - cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log - git status --porcelain | grep -q Cargo.lock || gh run cancel ${{ github.run_id }} + run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log - name: upload Cargo.lock artifact for use in PR uses: actions/upload-artifact@v4 with: @@ -95,11 +90,11 @@ jobs: uses: actions/checkout@v4 - name: download Cargo.lock from update job - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: Cargo-lock - name: download cargo-update log from update job - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: cargo-updates @@ -134,14 +129,14 @@ jobs: # Exit with error if PR is closed STATE=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json state --jq '.state') if [[ "$STATE" != "OPEN" ]]; then - gh run cancel ${{ github.run_id }} + exit 1 fi gh pr edit cargo_update --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY - name: open new pull request - # Only run if there wasn't an existing PR and if this is the weekly run - if: steps.edit.outcome != 'success' && github.event.schedule == '0 0 * * Sun' + # Only run if there wasn't an existing PR + if: steps.edit.outcome != 'success' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh pr create --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY diff --git a/.mailmap b/.mailmap index 0d96f5f3d4f..93f5ca8157c 100644 --- a/.mailmap +++ b/.mailmap @@ -324,6 +324,7 @@ Katze <binary@benary.org> Keegan McAllister <mcallister.keegan@gmail.com> <kmcallister@mozilla.com> Kerem Kat <keremkat@gmail.com> Kevin Butler <haqkrs@gmail.com> +Kevin Reid <kpreid@switchb.org> <kpreid@google.com> Kevin Jiang <kwj2104@columbia.edu> Kornel Lesiński <kornel@geekhood.net> Krishna Sai Veera Reddy <veerareddy@email.arizona.edu> diff --git a/Cargo.lock b/Cargo.lock index 9163538765d..c4501d6e574 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3784,6 +3784,7 @@ dependencies = [ name = "rustc_driver_impl" version = "0.0.0" dependencies = [ + "ctrlc", "libc", "rustc_ast", "rustc_ast_lowering", diff --git a/INSTALL.md b/INSTALL.md index a23ea4f1eee..9619ec2ce5c 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -151,8 +151,8 @@ toolchain. directory and uncomment the line `MSYS2_PATH_TYPE=inherit`. You could install and use MSYS2's version of git instead with `pacman`, - however this is not recommended as it's excrutiatingly slow, and not frequently - tested for compatability. + however this is not recommended as it's excruciatingly slow, and not frequently + tested for compatibility. 3. Start a MINGW64 or MINGW32 shell (depending on whether you want 32-bit or 64-bit Rust) either from your start menu, or by running `mingw64.exe` diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 8bd8b6ac144..6eff70410cb 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -75,7 +75,7 @@ pub(crate) struct FixupContext { } /// The default amount of fixing is minimal fixing. Fixups should be turned on -/// in a targetted fashion where needed. +/// in a targeted fashion where needed. impl Default for FixupContext { fn default() -> Self { FixupContext { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 35bd7d37992..578369de4d6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -4,6 +4,7 @@ #![allow(rustc::untranslatable_diagnostic)] use either::Either; +use hir::ClosureKind; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan}; @@ -463,6 +464,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = move_spans { // We already suggest cloning for these cases in `explain_captures`. + } else if let UseSpans::ClosureUse { + closure_kind: + ClosureKind::Coroutine(CoroutineKind::Desugared(_, CoroutineSource::Block)), + args_span: _, + capture_kind_span: _, + path_span, + } = move_spans + { + self.suggest_cloning(err, ty, expr, path_span); } else if self.suggest_hoisting_call_outside_loop(err, expr) { // The place where the the type moves would be misleading to suggest clone. // #121466 @@ -621,7 +631,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } // FIXME: We make sure that this is a normal top-level binding, - // but we could suggest `todo!()` for all uninitalized bindings in the pattern pattern + // but we could suggest `todo!()` for all uninitialized bindings in the pattern pattern if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) = &ex.kind && let hir::PatKind::Binding(..) = pat.kind @@ -749,7 +759,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { true } - /// In a move error that occurs on a call wihtin a loop, we try to identify cases where cloning + /// In a move error that occurs on a call within a loop, we try to identify cases where cloning /// the value would lead to a logic error. We infer these cases by seeing if the moved value is /// part of the logic to break the loop, either through an explicit `break` or if the expression /// is part of a `while let`. @@ -950,7 +960,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { { // FIXME: We could check that the call's *parent* takes `&mut val` to make the // suggestion more targeted to the `mk_iter(val).next()` case. Maybe do that only to - // check for wheter to suggest `let value` or `let mut value`. + // check for whether to suggest `let value` or `let mut value`. let span = in_loop.span; if !finder.found_breaks.is_empty() 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/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..b0bdf4af097 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(); @@ -592,7 +608,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) } - // If the region is live at at least one location in the promoted MIR, + // If the region is live at least one location in the promoted MIR, // then add a liveness constraint to the main MIR for this region // at the location provided as an argument to this method // diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index dbb86df6811..abcdfabcaed 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -3,17 +3,22 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; -use rustc_expand::base::{check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path}; +use rustc_data_structures::sync::Lrc; +use rustc_expand::base::{ + check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, + resolve_path, +}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt}; use rustc_expand::base::{MacEager, MacResult, MacroExpanderResult}; use rustc_expand::module::DirOwnership; use rustc_parse::new_parser_from_file; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; +use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; use rustc_span::{Pos, Span}; - use smallvec::SmallVec; +use std::path::{Path, PathBuf}; use std::rc::Rc; // These macros all relate to the file system; they either return @@ -182,35 +187,26 @@ pub fn expand_include_str( tts: TokenStream, ) -> MacroExpanderResult<'static> { let sp = cx.with_def_site_ctxt(sp); - let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include_str!") else { + let ExpandResult::Ready(mac) = get_single_str_spanned_from_tts(cx, sp, tts, "include_str!") + else { return ExpandResult::Retry(()); }; - let file = match mac { - Ok(file) => file, + let (path, path_span) = match mac { + Ok(res) => res, Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; - let file = match resolve_path(&cx.sess, file.as_str(), sp) { - Ok(f) => f, - Err(err) => { - let guar = err.emit(); - return ExpandResult::Ready(DummyResult::any(sp, guar)); - } - }; - ExpandResult::Ready(match cx.source_map().load_binary_file(&file) { + ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) { Ok(bytes) => match std::str::from_utf8(&bytes) { Ok(src) => { let interned_src = Symbol::intern(src); MacEager::expr(cx.expr_str(sp, interned_src)) } Err(_) => { - let guar = cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display())); + let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file")); DummyResult::any(sp, guar) } }, - Err(e) => { - let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - DummyResult::any(sp, guar) - } + Err(dummy) => dummy, }) } @@ -220,28 +216,127 @@ pub fn expand_include_bytes( tts: TokenStream, ) -> MacroExpanderResult<'static> { let sp = cx.with_def_site_ctxt(sp); - let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else { + let ExpandResult::Ready(mac) = get_single_str_spanned_from_tts(cx, sp, tts, "include_bytes!") + else { return ExpandResult::Retry(()); }; - let file = match mac { - Ok(file) => file, + let (path, path_span) = match mac { + Ok(res) => res, Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; - let file = match resolve_path(&cx.sess, file.as_str(), sp) { - Ok(f) => f, + ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) { + Ok(bytes) => { + let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); + MacEager::expr(expr) + } + Err(dummy) => dummy, + }) +} + +fn load_binary_file( + cx: &mut ExtCtxt<'_>, + original_path: &Path, + macro_span: Span, + path_span: Span, +) -> Result<Lrc<[u8]>, Box<dyn MacResult>> { + let resolved_path = match resolve_path(&cx.sess, original_path, macro_span) { + Ok(path) => path, Err(err) => { let guar = err.emit(); - return ExpandResult::Ready(DummyResult::any(sp, guar)); + return Err(DummyResult::any(macro_span, guar)); } }; - ExpandResult::Ready(match cx.source_map().load_binary_file(&file) { - Ok(bytes) => { - let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); - MacEager::expr(expr) + match cx.source_map().load_binary_file(&resolved_path) { + Ok(data) => Ok(data), + Err(io_err) => { + let mut err = cx.dcx().struct_span_err( + macro_span, + format!("couldn't read `{}`: {io_err}", resolved_path.display()), + ); + + if original_path.is_relative() { + let source_map = cx.sess.source_map(); + let new_path = source_map + .span_to_filename(macro_span.source_callsite()) + .into_local_path() + .and_then(|src| find_path_suggestion(source_map, src.parent()?, original_path)) + .and_then(|path| path.into_os_string().into_string().ok()); + + if let Some(new_path) = new_path { + err.span_suggestion( + path_span, + "there is a file with the same name in a different directory", + format!("\"{}\"", new_path.replace('\\', "/").escape_debug()), + rustc_lint_defs::Applicability::MachineApplicable, + ); + } + } + let guar = err.emit(); + Err(DummyResult::any(macro_span, guar)) } - Err(e) => { - let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - DummyResult::any(sp, guar) + } +} + +fn find_path_suggestion( + source_map: &SourceMap, + base_dir: &Path, + wanted_path: &Path, +) -> Option<PathBuf> { + // Fix paths that assume they're relative to cargo manifest dir + let mut base_c = base_dir.components(); + let mut wanted_c = wanted_path.components(); + let mut without_base = None; + while let Some(wanted_next) = wanted_c.next() { + if wanted_c.as_path().file_name().is_none() { + break; } + // base_dir may be absolute + while let Some(base_next) = base_c.next() { + if base_next == wanted_next { + without_base = Some(wanted_c.as_path()); + break; + } + } + } + let root_absolute = without_base.into_iter().map(PathBuf::from); + + let base_dir_components = base_dir.components().count(); + // Avoid going all the way to the root dir + let max_parent_components = if base_dir.is_relative() { + base_dir_components + 1 + } else { + base_dir_components.saturating_sub(1) + }; + + // Try with additional leading ../ + let mut prefix = PathBuf::new(); + let add = std::iter::from_fn(|| { + prefix.push(".."); + Some(prefix.join(wanted_path)) }) + .take(max_parent_components.min(3)); + + // Try without leading directories + let mut trimmed_path = wanted_path; + let remove = std::iter::from_fn(|| { + let mut components = trimmed_path.components(); + let removed = components.next()?; + trimmed_path = components.as_path(); + let _ = trimmed_path.file_name()?; // ensure there is a file name left + Some([ + Some(trimmed_path.to_path_buf()), + (removed != std::path::Component::ParentDir) + .then(|| Path::new("..").join(trimmed_path)), + ]) + }) + .flatten() + .flatten() + .take(4); + + for new_path in root_absolute.chain(add).chain(remove) { + if source_map.file_exists(&base_dir.join(&new_path)) { + return Some(new_path); + } + } + None } diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index e308cf80284..8fdc1941de8 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -46,18 +46,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9515fcc42b6cb5137f76b84c1a6f819782d0cf12473d145d3bc5cd67eedc8bc2" +checksum = "6a535eb1cf5a6003197dc569320c40c1cb2d2f97ef5d5348eebf067f20957381" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad827c6071bfe6d22de1bc331296a29f9ddc506ff926d8415b435ec6a6efce0" +checksum = "11b5066db32cec1492573827183af2142d2d88fe85a83cfc9e73f0f63d3788d4" dependencies = [ "bumpalo", "cranelift-bforest", @@ -76,39 +76,39 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10e6b36237a9ca2ce2fb4cc7741d418a080afa1327402138412ef85d5367bef1" +checksum = "64942e5774308e835fbad4dd25f253105412c90324631910e1ec27963147bddb" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c36bf4bfb86898a94ccfa773a1f86e8a5346b1983ff72059bdd2db4600325251" +checksum = "c39c33db9a86dd6d8d04166a10c53deb477aeea3500eaaefca682e4eda9bb986" [[package]] name = "cranelift-control" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cbf36560e7a6bd1409ca91e7b43b2cc7ed8429f343d7605eadf9046e8fac0d0" +checksum = "4b7fc4937613aea3156a0538800a17bf56f345a5da2e79ae3df58488c93d867f" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a71e11061a75b1184c09bea97c026a88f08b59ade96a7bb1f259d4ea0df2e942" +checksum = "f85575e79a153ce1ddbfb7fe1813519b4bfe1eb200cc9c8353b45ad123ae4d36" [[package]] name = "cranelift-frontend" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af5d4da63143ee3485c7bcedde0a818727d737d1083484a0ceedb8950c89e495" +checksum = "bbc31d6c0ab2249fe0c21e988256b42f5f401ab2673b4fc40076c82a698bdfb9" dependencies = [ "cranelift-codegen", "log", @@ -118,15 +118,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "457a9832b089e26f5eea70dcf49bed8ec6edafed630ce7c83161f24d46ab8085" +checksum = "dc14f37e3314c0e4c53779c2f46753bf242efff76ee9473757a1fff3b495ad37" [[package]] name = "cranelift-jit" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0af95fe68d5a10919012c8db82b1d59820405b8001c8c6d05f94b08031334fa9" +checksum = "cfdd1942f3233176a68c285380dbc84ff0440246a1bce308611c0a385b56ab18" dependencies = [ "anyhow", "cranelift-codegen", @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b0b201fa10a4014062d4c56c307c8d18fdf9a84cb5279efe6080241f42c7a7" +checksum = "121b2b5a16912554a1b9aace75b9b21eca49f28e33cbfbad4786dd9bc5361a5c" dependencies = [ "anyhow", "cranelift-codegen", @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b490d579df1ce365e1ea359e24ed86d82289fa785153327c2f6a69a59a731e4" +checksum = "2ea5375f76ab31f9800a23fb2b440810286a6f669a3eb467cdd7ff255ea64268" dependencies = [ "cranelift-codegen", "libc", @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.105.2" +version = "0.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7e821ac6db471bcdbd004e5a4fa0d374f1046bd3a2ce278c332e0b0c01ca63" +checksum = "f34e04419ab41661e973d90a73aa7b12771455394dae7a69b101a9b7e7589db7" dependencies = [ "anyhow", "cranelift-codegen", @@ -392,9 +392,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.12" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "unicode-ident" @@ -410,9 +410,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "18.0.2" +version = "19.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33f4121cb29dda08139b2824a734dd095d83ce843f2d613a84eb580b9cfc17ac" +checksum = "2796e4b4989db62899d2117e1e0258b839d088c044591b14e3a0396e7b3ae53a" dependencies = [ "cfg-if", "libc", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index c0b9e27b179..d8a855b0383 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.105.2", default-features = false, features = ["std", "unwind", "all-arch"] } -cranelift-frontend = { version = "0.105.2" } -cranelift-module = { version = "0.105.2" } -cranelift-native = { version = "0.105.2" } -cranelift-jit = { version = "0.105.2", optional = true } -cranelift-object = { version = "0.105.2" } +cranelift-codegen = { version = "0.106.0", default-features = false, features = ["std", "unwind", "all-arch"] } +cranelift-frontend = { version = "0.106.0" } +cranelift-module = { version = "0.106.0" } +cranelift-native = { version = "0.106.0" } +cranelift-jit = { version = "0.106.0", optional = true } +cranelift-object = { version = "0.106.0" } target-lexicon = "0.12.0" gimli = { version = "0.28", default-features = false, features = ["write"]} object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } diff --git a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch index 5442c3cef9e..7cf7f86700e 100644 --- a/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0022-coretests-Disable-not-compiling-tests.patch @@ -39,6 +39,6 @@ index 42a26ae..5ac1042 100644 +#![cfg(test)] #![feature(alloc_layout_extra)] #![feature(array_chunks)] - #![feature(array_windows)] + #![feature(array_ptr_get)] -- 2.21.0 (Apple Git-122) diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index f3cd4cbe493..612fc61ec27 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-03-16" +channel = "nightly-2024-03-28" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs index 550f2051553..92defd21cd9 100644 --- a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs +++ b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs @@ -26,9 +26,10 @@ fn main() { codegen_backend_arg.push(cg_clif_dylib_path); args.push(codegen_backend_arg); } - if !passed_args.iter().any(|arg| { - arg == "--sysroot" || arg.to_str().is_some_and(|s| s.starts_with("--sysroot=")) - }) { + if !passed_args + .iter() + .any(|arg| arg == "--sysroot" || arg.to_str().is_some_and(|s| s.starts_with("--sysroot="))) + { args.push(OsString::from("--sysroot")); args.push(OsString::from(sysroot.to_str().unwrap())); } diff --git a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs index f7d1bdbc4c6..1cad312bb79 100644 --- a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs +++ b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs @@ -26,12 +26,18 @@ fn main() { codegen_backend_arg.push(cg_clif_dylib_path); args.push(codegen_backend_arg); } - if !passed_args.iter().any(|arg| { - arg == "--sysroot" || arg.to_str().is_some_and(|s| s.starts_with("--sysroot=")) - }) { + if !passed_args + .iter() + .any(|arg| arg == "--sysroot" || arg.to_str().is_some_and(|s| s.starts_with("--sysroot="))) + { args.push(OsString::from("--sysroot")); args.push(OsString::from(sysroot.to_str().unwrap())); } + if passed_args.is_empty() { + // Don't pass any arguments when the user didn't pass any arguments + // either to ensure the help message is shown. + args.clear(); + } args.extend(passed_args); let rustdoc = if let Some(rustdoc) = option_env!("RUSTDOC") { diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index f4e10f7dd19..f42a008dc0c 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -10,14 +10,6 @@ pushd rust command -v rg >/dev/null 2>&1 || cargo install ripgrep -# FIXME(rust-lang/rust#122196) fix stage0 rmake.rs run-make tests and remove -# this workaround -for test in $(ls tests/run-make); do - if [[ -e "tests/run-make/$test/rmake.rs" ]]; then - rm -r "tests/run-make/$test" - fi -done - # FIXME remove this workaround once ICE tests no longer emit an outdated nightly message for test in $(rg -i --files-with-matches "//@(\[.*\])? failure-status: 101" tests/ui); do echo "rm $test" @@ -42,7 +34,6 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR # ================ # 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 # exotic linkages @@ -59,12 +50,9 @@ rm -r tests/run-make/c-link-to-rust-va-list-fn # requires callee side vararg sup rm -r tests/run-pass-valgrind/unsized-locals # misc unimplemented things -rm tests/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and nearbyintf64 intrinsics rm tests/ui/target-feature/missing-plusminus.rs # error not implemented -rm -r tests/run-make/emit-named-files # requires full --emit support rm -r tests/run-make/repr128-dwarf # debuginfo test rm -r tests/run-make/split-debuginfo # same -rm -r tests/run-make/symbols-include-type-name # --emit=asm not supported rm -r tests/run-make/target-specs # i686 not supported by Cranelift rm -r tests/run-make/mismatching-target-triples # same rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly @@ -102,6 +90,17 @@ rm tests/ui/abi/stack-protector.rs # requires stack protector support rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific +# requires asm, llvm-ir and/or llvm-bc emit support +# ============================================= +rm -r tests/run-make/emit-named-files +rm -r tests/run-make/issue-30063 +rm -r tests/run-make/multiple-emits +rm -r tests/run-make/output-type-permutations +rm -r tests/run-make/emit-to-stdout +rm -r tests/run-make/compressed-debuginfo +rm -r tests/run-make/symbols-include-type-name + + # giving different but possibly correct results # ============================================= rm tests/ui/mir/mir_misc_casts.rs # depends on deduplication of constants @@ -109,35 +108,21 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same rm tests/ui/consts/issue-33537.rs # same rm tests/ui/consts/const-mut-refs-crate.rs # same -# rustdoc-clif passes extra args, suppressing the help message when no args are passed -rm -r tests/run-make/issue-88756-default-output - # doesn't work due to the way the rustc test suite is invoked. # should work when using ./x.py test the way it is intended # ============================================================ rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump +rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contains the standard library source # genuine bugs # ============ rm tests/incremental/spike-neg1.rs # errors out for some reason rm tests/incremental/spike-neg2.rs # same - -rm -r tests/run-make/issue-51671 # wrong filename given in case of --emit=obj -rm -r tests/run-make/issue-30063 # same -rm -r tests/run-make/multiple-emits # same -rm -r tests/run-make/output-type-permutations # same -rm -r tests/run-make/used # same -rm -r tests/run-make/no-alloc-shim -rm -r tests/run-make/emit-to-stdout -rm -r tests/run-make/compressed-debuginfo - rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported - -rm tests/ui/codegen/subtyping-enforces-type-equality.rs # assert_assignable bug with Coroutine's +rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort # bugs in the test suite # ====================== -rm tests/ui/backtrace.rs # TODO warning rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd @@ -160,6 +145,19 @@ index ea06b620c4c..b969d0009c6 100644 ifdef RUSTC_LINKER RUSTC := \$(RUSTC) -Clinker='\$(RUSTC_LINKER)' RUSTDOC := \$(RUSTDOC) -Clinker='\$(RUSTC_LINKER)' +diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs +index 9607ff02f96..b7d97caf9a2 100644 +--- a/src/tools/run-make-support/src/rustdoc.rs ++++ b/src/tools/run-make-support/src/rustdoc.rs +@@ -34,8 +34,6 @@ pub fn bare() -> Self { + /// Construct a \`rustdoc\` invocation with \`-L \$(TARGET_RPATH_DIR)\` set. + pub fn new() -> Self { + let mut cmd = setup_common(); +- let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap(); +- cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy())); + Self { cmd } + } + EOF echo "[TEST] rustc test suite" diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index b0af421008a..6363a0d59a4 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -222,17 +222,15 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ Spread(Vec<Option<CValue<'tcx>>>), } - let fn_abi = fx.fn_abi.take().unwrap(); - // FIXME implement variadics in cranelift - if fn_abi.c_variadic { + if fx.fn_abi.c_variadic { fx.tcx.dcx().span_fatal( fx.mir.span, "Defining variadic functions is not yet supported by Cranelift", ); } - let mut arg_abis_iter = fn_abi.args.iter(); + let mut arg_abis_iter = fx.fn_abi.args.iter(); let func_params = fx .mir @@ -279,7 +277,6 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ } assert!(arg_abis_iter.next().is_none(), "ArgAbi left behind"); - fx.fn_abi = Some(fn_abi); assert!(block_params_iter.next().is_none(), "arg_value left behind"); self::comments::add_locals_header_comment(fx); diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs index 0799a22c6e1..e0f399e616e 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs @@ -12,27 +12,15 @@ pub(super) fn codegen_return_param<'tcx>( ssa_analyzed: &rustc_index::IndexSlice<Local, crate::analyze::SsaKind>, block_params_iter: &mut impl Iterator<Item = Value>, ) -> CPlace<'tcx> { - let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode { + let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.ret.mode { PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => { - let is_ssa = - ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.as_ref().unwrap().ret.layout.ty); - ( - super::make_local_place( - fx, - RETURN_PLACE, - fx.fn_abi.as_ref().unwrap().ret.layout, - is_ssa, - ), - smallvec![], - ) + let is_ssa = ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.ret.layout.ty); + (super::make_local_place(fx, RETURN_PLACE, fx.fn_abi.ret.layout, is_ssa), smallvec![]) } PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { let ret_param = block_params_iter.next().unwrap(); assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type); - ( - CPlace::for_ptr(Pointer::new(ret_param), fx.fn_abi.as_ref().unwrap().ret.layout), - smallvec![ret_param], - ) + (CPlace::for_ptr(Pointer::new(ret_param), fx.fn_abi.ret.layout), smallvec![ret_param]) } PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") @@ -45,8 +33,8 @@ pub(super) fn codegen_return_param<'tcx>( Some(RETURN_PLACE), None, &ret_param, - &fx.fn_abi.as_ref().unwrap().ret.mode, - fx.fn_abi.as_ref().unwrap().ret.layout, + &fx.fn_abi.ret.mode, + fx.fn_abi.ret.layout, ); ret_place @@ -115,7 +103,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( /// Codegen a return instruction with the right return value(s) if any. pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) { - match fx.fn_abi.as_ref().unwrap().ret.mode { + match fx.fn_abi.ret.mode { PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { fx.bcx.ins().return_(&[]); } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index dbce6d165d2..b4ea4e10a3d 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use crate::constant::ConstantCx; -use crate::debuginfo::FunctionDebugContext; +use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; use crate::prelude::*; use crate::pretty_clif::CommentWriter; @@ -26,6 +26,7 @@ pub(crate) struct CodegenedFunction { pub(crate) fn codegen_fn<'tcx>( tcx: TyCtxt<'tcx>, cx: &mut crate::CodegenCx, + type_dbg: &mut TypeDebugContext<'tcx>, cached_func: Function, module: &mut dyn Module, instance: Instance<'tcx>, @@ -69,8 +70,10 @@ pub(crate) fn codegen_fn<'tcx>( let pointer_type = target_config.pointer_type(); let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance); + let fn_abi = RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty()); + let func_debug_cx = if let Some(debug_context) = &mut cx.debug_context { - Some(debug_context.define_function(tcx, &symbol_name, mir.span)) + Some(debug_context.define_function(tcx, type_dbg, instance, fn_abi, &symbol_name, mir.span)) } else { None }; @@ -87,7 +90,7 @@ pub(crate) fn codegen_fn<'tcx>( instance, symbol_name, mir, - fn_abi: Some(RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())), + fn_abi, bcx, block_map, @@ -95,7 +98,6 @@ pub(crate) fn codegen_fn<'tcx>( caller_location: None, // set by `codegen_fn_prelude` clif_comments, - last_source_file: None, next_ssa_var: 0, }; diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index a7c3d68ff8c..cf0b065414d 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -1,12 +1,9 @@ use cranelift_codegen::isa::TargetFrontendConfig; -use gimli::write::FileId; -use rustc_data_structures::sync::Lrc; use rustc_index::IndexVec; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, }; use rustc_span::source_map::Spanned; -use rustc_span::SourceFile; use rustc_target::abi::call::FnAbi; use rustc_target::abi::{Integer, Primitive}; use rustc_target::spec::{HasTargetSpec, Target}; @@ -294,7 +291,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { pub(crate) instance: Instance<'tcx>, pub(crate) symbol_name: String, pub(crate) mir: &'tcx Body<'tcx>, - pub(crate) fn_abi: Option<&'tcx FnAbi<'tcx, Ty<'tcx>>>, + pub(crate) fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, pub(crate) bcx: FunctionBuilder<'clif>, pub(crate) block_map: IndexVec<BasicBlock, Block>, @@ -305,11 +302,6 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { pub(crate) clif_comments: crate::pretty_clif::CommentWriter, - /// Last accessed source file and it's debuginfo file id. - /// - /// For optimization purposes only - pub(crate) last_source_file: Option<(Lrc<SourceFile>, FileId)>, - /// This should only be accessed by `CPlace::new_var`. pub(crate) next_ssa_var: u32, } @@ -419,25 +411,8 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) { if let Some(debug_context) = &mut self.cx.debug_context { - let (file, line, column) = - DebugContext::get_span_loc(self.tcx, self.mir.span, source_info.span); - - // add_source_file is very slow. - // Optimize for the common case of the current file not being changed. - let mut cached_file_id = None; - if let Some((ref last_source_file, last_file_id)) = self.last_source_file { - // If the allocations are not equal, the files may still be equal, but that - // doesn't matter, as this is just an optimization. - if rustc_data_structures::sync::Lrc::ptr_eq(last_source_file, &file) { - cached_file_id = Some(last_file_id); - } - } - - let file_id = if let Some(file_id) = cached_file_id { - file_id - } else { - debug_context.add_source_file(&file) - }; + let (file_id, line, column) = + debug_context.get_span_loc(self.tcx, self.mir.span, source_info.span); let source_loc = self.func_debug_cx.as_mut().unwrap().add_dbg_loc(file_id, line, column); diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index fc9b0f6ef02..635ed6c8e88 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -6,17 +6,16 @@ use cranelift_module::*; use rustc_data_structures::fx::FxHashSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{read_target_uint, AllocId, GlobalAlloc, Scalar}; -use rustc_middle::ty::ScalarInt; +use rustc_middle::ty::{Binder, ExistentialTraitRef, ScalarInt}; use crate::prelude::*; pub(crate) struct ConstantCx { todo: Vec<TodoItem>, - done: FxHashSet<DataId>, anon_allocs: FxHashMap<AllocId, DataId>, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] enum TodoItem { Alloc(AllocId), Static(DefId), @@ -24,19 +23,24 @@ enum TodoItem { impl ConstantCx { pub(crate) fn new() -> Self { - ConstantCx { todo: vec![], done: FxHashSet::default(), anon_allocs: FxHashMap::default() } + ConstantCx { todo: vec![], anon_allocs: FxHashMap::default() } } pub(crate) fn finalize(mut self, tcx: TyCtxt<'_>, module: &mut dyn Module) { define_all_allocs(tcx, module, &mut self); - self.done.clear(); } } -pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) { +pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) -> DataId { let mut constants_cx = ConstantCx::new(); constants_cx.todo.push(TodoItem::Static(def_id)); constants_cx.finalize(tcx, module); + + data_id_for_static( + tcx, module, def_id, false, + // For a declaration the stated mutability doesn't matter. + false, + ) } pub(crate) fn codegen_tls_ref<'tcx>( @@ -153,14 +157,12 @@ pub(crate) fn codegen_const_value<'tcx>( fx.bcx.ins().func_addr(fx.pointer_type, local_func_id) } GlobalAlloc::VTable(ty, trait_ref) => { - let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref)); - let alloc = fx.tcx.global_alloc(alloc_id).unwrap_memory(); - // FIXME: factor this common code with the `Memory` arm into a function? - let data_id = data_id_for_alloc_id( + let data_id = data_id_for_vtable( + fx.tcx, &mut fx.constants_cx, fx.module, - alloc_id, - alloc.inner().mutability, + ty, + trait_ref, ); let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); @@ -208,12 +210,8 @@ fn pointer_for_allocation<'tcx>( alloc_id: AllocId, ) -> crate::pointer::Pointer { let alloc = fx.tcx.global_alloc(alloc_id).unwrap_memory(); - let data_id = data_id_for_alloc_id( - &mut fx.constants_cx, - &mut *fx.module, - alloc_id, - alloc.inner().mutability, - ); + let data_id = + data_id_for_alloc_id(&mut fx.constants_cx, fx.module, alloc_id, alloc.inner().mutability); let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); if fx.clif_comments.enabled() { @@ -235,6 +233,17 @@ pub(crate) fn data_id_for_alloc_id( .or_insert_with(|| module.declare_anonymous_data(mutability.is_mut(), false).unwrap()) } +pub(crate) fn data_id_for_vtable<'tcx>( + tcx: TyCtxt<'tcx>, + cx: &mut ConstantCx, + module: &mut dyn Module, + ty: Ty<'tcx>, + trait_ref: Option<Binder<'tcx, ExistentialTraitRef<'tcx>>>, +) -> DataId { + let alloc_id = tcx.vtable_allocation((ty, trait_ref)); + data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not) +} + fn data_id_for_static( tcx: TyCtxt<'_>, module: &mut dyn Module, @@ -327,7 +336,12 @@ fn data_id_for_static( } fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut ConstantCx) { + let mut done = FxHashSet::default(); while let Some(todo_item) = cx.todo.pop() { + if !done.insert(todo_item) { + continue; + } + let (data_id, alloc, section_name) = match todo_item { TodoItem::Alloc(alloc_id) => { let alloc = match tcx.global_alloc(alloc_id) { @@ -358,10 +372,6 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant } }; - if cx.done.contains(&data_id) { - continue; - } - let mut data = DataDescription::new(); let alloc = alloc.inner(); data.set_align(alloc.align.bytes()); @@ -384,13 +394,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant } let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec(); - if bytes.is_empty() { - // FIXME(bytecodealliance/wasmtime#7918) cranelift-jit has a bug where it causes UB on - // empty data objects - data.define(Box::new([0])); - } else { - data.define(bytes.into_boxed_slice()); - } + data.define(bytes.into_boxed_slice()); for &(offset, prov) in alloc.provenance().ptrs().iter() { let alloc_id = prov.alloc_id(); @@ -418,8 +422,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability) } GlobalAlloc::VTable(ty, trait_ref) => { - let alloc_id = tcx.vtable_allocation((ty, trait_ref)); - data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not) + data_id_for_vtable(tcx, cx, module, ty, trait_ref) } GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) @@ -446,7 +449,6 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant } module.define_data(data_id, &data).unwrap(); - cx.done.insert(data_id); } assert!(cx.todo.is_empty(), "{:?}", cx.todo); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs index 81b819a5546..36af7d4450d 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs @@ -1,5 +1,6 @@ //! Write the debuginfo into an object file. +use cranelift_module::{DataId, FuncId}; use cranelift_object::ObjectProduct; use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer}; use gimli::{RunTimeEndian, SectionId}; @@ -8,6 +9,18 @@ use rustc_data_structures::fx::FxHashMap; use super::object::WriteDebugInfo; use super::DebugContext; +pub(super) fn address_for_func(func_id: FuncId) -> Address { + let symbol = func_id.as_u32(); + assert!(symbol & 1 << 31 == 0); + Address::Symbol { symbol: symbol as usize, addend: 0 } +} + +pub(super) fn address_for_data(data_id: DataId) -> Address { + let symbol = data_id.as_u32(); + assert!(symbol & 1 << 31 == 0); + Address::Symbol { symbol: (symbol | 1 << 31) as usize, addend: 0 } +} + impl DebugContext { pub(crate) fn emit(&mut self, product: &mut ObjectProduct) { let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone()); @@ -171,6 +184,7 @@ impl Writer for WriterRelocate { gimli::DW_EH_PE_pcrel => { let size = match eh_pe.format() { gimli::DW_EH_PE_sdata4 => 4, + gimli::DW_EH_PE_sdata8 => 8, _ => return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)), }; self.relocs.push(DebugReloc { diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index d1b21d0a0b6..380eba437c2 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -5,14 +5,12 @@ use std::path::{Component, Path}; use cranelift_codegen::binemit::CodeOffset; use cranelift_codegen::MachSrcLoc; -use gimli::write::{ - Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable, -}; -use rustc_data_structures::sync::Lrc; +use gimli::write::{AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable}; use rustc_span::{ FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm, }; +use crate::debuginfo::emit::address_for_func; use crate::debuginfo::FunctionDebugContext; use crate::prelude::*; @@ -60,10 +58,11 @@ fn make_file_info(hash: SourceFileHash) -> Option<FileInfo> { impl DebugContext { pub(crate) fn get_span_loc( + &mut self, tcx: TyCtxt<'_>, function_span: Span, span: Span, - ) -> (Lrc<SourceFile>, u64, u64) { + ) -> (FileId, u64, u64) { // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131 // In order to have a good line stepping behavior in debugger, we overwrite debug // locations of macro expansions with that of the outermost expansion site (when the macro is @@ -71,61 +70,66 @@ impl DebugContext { let span = tcx.collapsed_debuginfo(span, function_span); match tcx.sess.source_map().lookup_line(span.lo()) { Ok(SourceFileAndLine { sf: file, line }) => { + let file_id = self.add_source_file(&file); let line_pos = file.lines()[line]; let col = file.relative_position(span.lo()) - line_pos; - (file, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1) + (file_id, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1) } - Err(file) => (file, 0, 0), + Err(file) => (self.add_source_file(&file), 0, 0), } } pub(crate) fn add_source_file(&mut self, source_file: &SourceFile) -> FileId { - let line_program: &mut LineProgram = &mut self.dwarf.unit.line_program; - let line_strings: &mut LineStringTable = &mut self.dwarf.line_strings; - - match &source_file.name { - FileName::Real(path) => { - let (dir_path, file_name) = - split_path_dir_and_file(if self.should_remap_filepaths { - path.remapped_path_if_available() - } else { - path.local_path_if_available() - }); - let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str()); - let file_name = osstr_as_utf8_bytes(file_name); - - let dir_id = if !dir_name.is_empty() { - let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings); - line_program.add_directory(dir_name) - } else { - line_program.default_directory() - }; - let file_name = LineString::new(file_name, line_program.encoding(), line_strings); - - let info = make_file_info(source_file.src_hash); - - line_program.file_has_md5 &= info.is_some(); - line_program.add_file(file_name, dir_id, info) - } - // FIXME give more appropriate file names - filename => { - let dir_id = line_program.default_directory(); - let dummy_file_name = LineString::new( - filename - .display(if self.should_remap_filepaths { - FileNameDisplayPreference::Remapped + let cache_key = (source_file.stable_id, source_file.src_hash); + *self.created_files.entry(cache_key).or_insert_with(|| { + let line_program: &mut LineProgram = &mut self.dwarf.unit.line_program; + let line_strings: &mut LineStringTable = &mut self.dwarf.line_strings; + + match &source_file.name { + FileName::Real(path) => { + let (dir_path, file_name) = + split_path_dir_and_file(if self.should_remap_filepaths { + path.remapped_path_if_available() } else { - FileNameDisplayPreference::Local - }) - .to_string() - .into_bytes(), - line_program.encoding(), - line_strings, - ); - line_program.add_file(dummy_file_name, dir_id, None) + path.local_path_if_available() + }); + let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str()); + let file_name = osstr_as_utf8_bytes(file_name); + + let dir_id = if !dir_name.is_empty() { + let dir_name = + LineString::new(dir_name, line_program.encoding(), line_strings); + line_program.add_directory(dir_name) + } else { + line_program.default_directory() + }; + let file_name = + LineString::new(file_name, line_program.encoding(), line_strings); + + let info = make_file_info(source_file.src_hash); + + line_program.file_has_md5 &= info.is_some(); + line_program.add_file(file_name, dir_id, info) + } + filename => { + let dir_id = line_program.default_directory(); + let dummy_file_name = LineString::new( + filename + .display(if self.should_remap_filepaths { + FileNameDisplayPreference::Remapped + } else { + FileNameDisplayPreference::Local + }) + .to_string() + .into_bytes(), + line_program.encoding(), + line_strings, + ); + line_program.add_file(dummy_file_name, dir_id, None) + } } - } + }) } } @@ -138,7 +142,7 @@ impl FunctionDebugContext { pub(super) fn create_debug_lines( &mut self, debug_context: &mut DebugContext, - symbol: usize, + func_id: FuncId, context: &Context, ) -> CodeOffset { let create_row_for_span = @@ -151,11 +155,7 @@ impl FunctionDebugContext { debug_context.dwarf.unit.line_program.generate_row(); }; - debug_context - .dwarf - .unit - .line_program - .begin_sequence(Some(Address::Symbol { symbol, addend: 0 })); + debug_context.dwarf.unit.line_program.begin_sequence(Some(address_for_func(func_id))); let mut func_end = 0; @@ -178,10 +178,7 @@ impl FunctionDebugContext { assert_ne!(func_end, 0); let entry = debug_context.dwarf.unit.get_mut(self.entry_id); - entry.set( - gimli::DW_AT_low_pc, - AttributeValue::Address(Address::Symbol { symbol, addend: 0 }), - ); + entry.set(gimli::DW_AT_low_pc, AttributeValue::Address(address_for_func(func_id))); entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(func_end))); func_end diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 2d9c2ecdbc2..1bb0e590513 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -3,20 +3,29 @@ mod emit; mod line_info; mod object; +mod types; mod unwind; use cranelift_codegen::ir::Endianness; use cranelift_codegen::isa::TargetIsa; +use cranelift_module::DataId; use gimli::write::{ - Address, AttributeValue, DwarfUnit, FileId, LineProgram, LineString, Range, RangeList, - UnitEntryId, + Address, AttributeValue, DwarfUnit, Expression, FileId, LineProgram, LineString, Range, + RangeList, UnitEntryId, }; -use gimli::{Encoding, Format, LineEncoding, RunTimeEndian}; +use gimli::{AArch64, Encoding, Format, LineEncoding, Register, RiscV, RunTimeEndian, X86_64}; use indexmap::IndexSet; +use rustc_codegen_ssa::debuginfo::type_names; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::DefIdMap; use rustc_session::Session; +use rustc_span::{SourceFileHash, StableSourceFileId}; +use rustc_target::abi::call::FnAbi; pub(crate) use self::emit::{DebugReloc, DebugRelocName}; +pub(crate) use self::types::TypeDebugContext; pub(crate) use self::unwind::UnwindContext; +use crate::debuginfo::emit::{address_for_data, address_for_func}; use crate::prelude::*; pub(crate) fn producer(sess: &Session) -> String { @@ -28,6 +37,10 @@ pub(crate) struct DebugContext { dwarf: DwarfUnit, unit_range_list: RangeList, + created_files: FxHashMap<(StableSourceFileId, SourceFileHash), FileId>, + stack_pointer_register: Register, + namespace_map: DefIdMap<UnitEntryId>, + array_size_type: UnitEntryId, should_remap_filepaths: bool, } @@ -39,7 +52,7 @@ pub(crate) struct FunctionDebugContext { } impl DebugContext { - pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self { + pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, cgu_name: &str) -> Self { let encoding = Encoding { format: Format::Dwarf32, // FIXME this should be configurable @@ -60,6 +73,15 @@ impl DebugContext { Endianness::Big => RunTimeEndian::Big, }; + let stack_pointer_register = match isa.triple().architecture { + target_lexicon::Architecture::Aarch64(_) => AArch64::SP, + target_lexicon::Architecture::Riscv64(_) => RiscV::SP, + target_lexicon::Architecture::X86_64 | target_lexicon::Architecture::X86_64h => { + X86_64::RSP + } + _ => Register(u16::MAX), + }; + let mut dwarf = DwarfUnit::new(encoding); let should_remap_filepaths = tcx.sess.should_prefer_remapped_for_codegen(); @@ -95,7 +117,7 @@ impl DebugContext { dwarf.unit.line_program = line_program; { - let name = dwarf.strings.add(name); + let name = dwarf.strings.add(format!("{name}/@/{cgu_name}")); let comp_dir = dwarf.strings.add(comp_dir); let root = dwarf.unit.root(); @@ -103,41 +125,134 @@ impl DebugContext { root.set(gimli::DW_AT_producer, AttributeValue::StringRef(dwarf.strings.add(producer))); root.set(gimli::DW_AT_language, AttributeValue::Language(gimli::DW_LANG_Rust)); root.set(gimli::DW_AT_name, AttributeValue::StringRef(name)); + + // This will be replaced when emitting the debuginfo. It is only + // defined here to ensure that the order of the attributes matches + // rustc. + root.set(gimli::DW_AT_stmt_list, AttributeValue::Udata(0)); + root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir)); root.set(gimli::DW_AT_low_pc, AttributeValue::Address(Address::Constant(0))); } + let array_size_type = dwarf.unit.add(dwarf.unit.root(), gimli::DW_TAG_base_type); + let array_size_type_entry = dwarf.unit.get_mut(array_size_type); + array_size_type_entry.set( + gimli::DW_AT_name, + AttributeValue::StringRef(dwarf.strings.add("__ARRAY_SIZE_TYPE__")), + ); + array_size_type_entry + .set(gimli::DW_AT_encoding, AttributeValue::Encoding(gimli::DW_ATE_unsigned)); + array_size_type_entry.set( + gimli::DW_AT_byte_size, + AttributeValue::Udata(isa.frontend_config().pointer_bytes().into()), + ); + DebugContext { endian, dwarf, unit_range_list: RangeList(Vec::new()), + created_files: FxHashMap::default(), + stack_pointer_register, + namespace_map: DefIdMap::default(), + array_size_type, should_remap_filepaths, } } - pub(crate) fn define_function( + fn item_namespace(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> UnitEntryId { + if let Some(&scope) = self.namespace_map.get(&def_id) { + return scope; + } + + let def_key = tcx.def_key(def_id); + let parent_scope = def_key + .parent + .map(|parent| self.item_namespace(tcx, DefId { krate: def_id.krate, index: parent })) + .unwrap_or(self.dwarf.unit.root()); + + let namespace_name = { + let mut output = String::new(); + type_names::push_item_name(tcx, def_id, false, &mut output); + output + }; + let namespace_name_id = self.dwarf.strings.add(namespace_name); + + let scope = self.dwarf.unit.add(parent_scope, gimli::DW_TAG_namespace); + let scope_entry = self.dwarf.unit.get_mut(scope); + scope_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(namespace_name_id)); + + self.namespace_map.insert(def_id, scope); + scope + } + + pub(crate) fn define_function<'tcx>( &mut self, - tcx: TyCtxt<'_>, - name: &str, + tcx: TyCtxt<'tcx>, + type_dbg: &mut TypeDebugContext<'tcx>, + instance: Instance<'tcx>, + fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, + linkage_name: &str, function_span: Span, ) -> FunctionDebugContext { - let (file, line, column) = DebugContext::get_span_loc(tcx, function_span, function_span); + let (file_id, line, column) = self.get_span_loc(tcx, function_span, function_span); + + let scope = self.item_namespace(tcx, tcx.parent(instance.def_id())); + + let mut name = String::new(); + type_names::push_item_name(tcx, instance.def_id(), false, &mut name); - let file_id = self.add_source_file(&file); + // Find the enclosing function, in case this is a closure. + let enclosing_fn_def_id = tcx.typeck_root_def_id(instance.def_id()); - // FIXME: add to appropriate scope instead of root - let scope = self.dwarf.unit.root(); + // We look up the generics of the enclosing function and truncate the args + // to their length in order to cut off extra stuff that might be in there for + // closures or coroutines. + let generics = tcx.generics_of(enclosing_fn_def_id); + let args = instance.args.truncate_to(tcx, generics); + + type_names::push_generic_params( + tcx, + tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args), + enclosing_fn_def_id, + &mut name, + ); let entry_id = self.dwarf.unit.add(scope, gimli::DW_TAG_subprogram); let entry = self.dwarf.unit.get_mut(entry_id); + let linkage_name_id = + if name != linkage_name { Some(self.dwarf.strings.add(linkage_name)) } else { None }; let name_id = self.dwarf.strings.add(name); + + // These will be replaced in FunctionDebugContext::finalize. They are + // only defined here to ensure that the order of the attributes matches + // rustc. + entry.set(gimli::DW_AT_low_pc, AttributeValue::Udata(0)); + entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(0)); + + let mut frame_base_expr = Expression::new(); + frame_base_expr.op_reg(self.stack_pointer_register); + entry.set(gimli::DW_AT_frame_base, AttributeValue::Exprloc(frame_base_expr)); + + if let Some(linkage_name_id) = linkage_name_id { + entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(linkage_name_id)); + } // Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped. entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id)); - entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(name_id)); entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); - entry.set(gimli::DW_AT_decl_column, AttributeValue::Udata(column)); + + if !fn_abi.ret.is_ignore() { + let return_dw_ty = self.debug_type(tcx, type_dbg, fn_abi.ret.layout.ty); + let entry = self.dwarf.unit.get_mut(entry_id); + entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(return_dw_ty)); + } + + if tcx.is_reachable_non_generic(instance.def_id()) { + let entry = self.dwarf.unit.get_mut(entry_id); + entry.set(gimli::DW_AT_external, AttributeValue::FlagPresent); + } FunctionDebugContext { entry_id, @@ -145,6 +260,62 @@ impl DebugContext { source_loc_set: IndexSet::new(), } } + + // Adapted from https://github.com/rust-lang/rust/blob/10a7aa14fed9b528b74b0f098c4899c37c09a9c7/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs#L1288-L1346 + pub(crate) fn define_static<'tcx>( + &mut self, + tcx: TyCtxt<'tcx>, + type_dbg: &mut TypeDebugContext<'tcx>, + def_id: DefId, + data_id: DataId, + ) { + let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() }; + if nested { + return; + } + + let scope = self.item_namespace(tcx, tcx.parent(def_id)); + + let span = tcx.def_span(def_id); + let (file_id, line, _column) = self.get_span_loc(tcx, span, span); + + let static_type = Instance::mono(tcx, def_id).ty(tcx, ty::ParamEnv::reveal_all()); + let static_layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(static_type)).unwrap(); + // FIXME use the actual type layout + let type_id = self.debug_type(tcx, type_dbg, static_type); + + let name = tcx.item_name(def_id); + let linkage_name = tcx.symbol_name(Instance::mono(tcx, def_id)).name; + + let entry_id = self.dwarf.unit.add(scope, gimli::DW_TAG_variable); + let entry = self.dwarf.unit.get_mut(entry_id); + let linkage_name_id = if name.as_str() != linkage_name { + Some(self.dwarf.strings.add(linkage_name)) + } else { + None + }; + let name_id = self.dwarf.strings.add(name.as_str()); + + entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id)); + entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(type_id)); + + if tcx.is_reachable_non_generic(def_id) { + entry.set(gimli::DW_AT_external, AttributeValue::FlagPresent); + } + + entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); + entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); + + entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.pref.bytes())); + + let mut expr = Expression::new(); + expr.op_addr(address_for_data(data_id)); + entry.set(gimli::DW_AT_location, AttributeValue::Exprloc(expr)); + + if let Some(linkage_name_id) = linkage_name_id { + entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(linkage_name_id)); + } + } } impl FunctionDebugContext { @@ -154,21 +325,16 @@ impl FunctionDebugContext { func_id: FuncId, context: &Context, ) { - let symbol = func_id.as_u32() as usize; - - let end = self.create_debug_lines(debug_context, symbol, context); + let end = self.create_debug_lines(debug_context, func_id, context); - debug_context.unit_range_list.0.push(Range::StartLength { - begin: Address::Symbol { symbol, addend: 0 }, - length: u64::from(end), - }); + debug_context + .unit_range_list + .0 + .push(Range::StartLength { begin: address_for_func(func_id), length: u64::from(end) }); let func_entry = debug_context.dwarf.unit.get_mut(self.entry_id); // Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped. - func_entry.set( - gimli::DW_AT_low_pc, - AttributeValue::Address(Address::Symbol { symbol, addend: 0 }), - ); + func_entry.set(gimli::DW_AT_low_pc, AttributeValue::Address(address_for_func(func_id))); // Using Udata for DW_AT_high_pc requires at least DWARF4 func_entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(end))); } diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs index f1840a7bf73..27eabd8a0a6 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs @@ -1,4 +1,4 @@ -use cranelift_module::FuncId; +use cranelift_module::{DataId, FuncId}; use cranelift_object::ObjectProduct; use gimli::SectionId; use object::write::{Relocation, StandardSegment}; @@ -57,10 +57,13 @@ impl WriteDebugInfo for ObjectProduct { let (symbol, symbol_offset) = match reloc.name { DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0), DebugRelocName::Symbol(id) => { - let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap())); - self.object - .symbol_section_and_offset(symbol_id) - .expect("Debug reloc for undef sym???") + let id = id.try_into().unwrap(); + let symbol_id = if id & 1 << 31 == 0 { + self.function_symbol(FuncId::from_u32(id)) + } else { + self.data_symbol(DataId::from_u32(id & !(1 << 31))) + }; + self.object.symbol_section_and_offset(symbol_id).unwrap_or((symbol_id, 0)) } }; self.object diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs new file mode 100644 index 00000000000..7baf0a3868d --- /dev/null +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs @@ -0,0 +1,204 @@ +// Adapted from https://github.com/rust-lang/rust/blob/10a7aa14fed9b528b74b0f098c4899c37c09a9c7/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs + +use gimli::write::{AttributeValue, UnitEntryId}; +use rustc_codegen_ssa::debuginfo::type_names; +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +use crate::{has_ptr_meta, DebugContext, RevealAllLayoutCx}; + +#[derive(Default)] +pub(crate) struct TypeDebugContext<'tcx> { + type_map: FxHashMap<Ty<'tcx>, UnitEntryId>, +} + +/// Returns from the enclosing function if the type debuginfo node with the given +/// unique ID can be found in the type map. +macro_rules! return_if_type_created_in_meantime { + ($type_dbg:expr, $ty:expr) => { + if let Some(&type_id) = $type_dbg.type_map.get(&$ty) { + return type_id; + } + }; +} + +impl DebugContext { + pub(crate) fn debug_type<'tcx>( + &mut self, + tcx: TyCtxt<'tcx>, + type_dbg: &mut TypeDebugContext<'tcx>, + ty: Ty<'tcx>, + ) -> UnitEntryId { + if let Some(&type_id) = type_dbg.type_map.get(&ty) { + return type_id; + } + + let type_id = match ty.kind() { + ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { + self.basic_type(tcx, ty) + } + ty::Tuple(elems) if elems.is_empty() => self.basic_type(tcx, ty), + ty::Array(elem_ty, len) => self.array_type( + tcx, + type_dbg, + ty, + *elem_ty, + len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()), + ), + // ty::Slice(_) | ty::Str + // ty::Dynamic + // ty::Foreign + ty::RawPtr(pointee_type, _) | ty::Ref(_, pointee_type, _) => { + self.pointer_type(tcx, type_dbg, ty, *pointee_type) + } + // ty::Adt(def, args) if def.is_box() && args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) + // ty::FnDef(..) | ty::FnPtr(..) + // ty::Closure(..) + // ty::Adt(def, ..) + ty::Tuple(components) => self.tuple_type(tcx, type_dbg, ty, *components), + // ty::Param(_) + // FIXME implement remaining types and add unreachable!() to the fallback branch + _ => self.placeholder_for_type(tcx, type_dbg, ty), + }; + + type_dbg.type_map.insert(ty, type_id); + + type_id + } + + fn basic_type<'tcx>(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> UnitEntryId { + let (name, encoding) = match ty.kind() { + ty::Never => ("!", gimli::DW_ATE_unsigned), + ty::Tuple(elems) if elems.is_empty() => ("()", gimli::DW_ATE_unsigned), + ty::Bool => ("bool", gimli::DW_ATE_boolean), + ty::Char => ("char", gimli::DW_ATE_UTF), + ty::Int(int_ty) => (int_ty.name_str(), gimli::DW_ATE_signed), + ty::Uint(uint_ty) => (uint_ty.name_str(), gimli::DW_ATE_unsigned), + ty::Float(float_ty) => (float_ty.name_str(), gimli::DW_ATE_float), + _ => unreachable!(), + }; + + let type_id = self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_base_type); + let type_entry = self.dwarf.unit.get_mut(type_id); + type_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name))); + type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(encoding)); + type_entry.set( + gimli::DW_AT_byte_size, + AttributeValue::Udata(RevealAllLayoutCx(tcx).layout_of(ty).size.bytes()), + ); + + type_id + } + + fn array_type<'tcx>( + &mut self, + tcx: TyCtxt<'tcx>, + type_dbg: &mut TypeDebugContext<'tcx>, + array_ty: Ty<'tcx>, + elem_ty: Ty<'tcx>, + len: u64, + ) -> UnitEntryId { + let elem_dw_ty = self.debug_type(tcx, type_dbg, elem_ty); + + return_if_type_created_in_meantime!(type_dbg, array_ty); + + let array_type_id = self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_array_type); + let array_type_entry = self.dwarf.unit.get_mut(array_type_id); + array_type_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(elem_dw_ty)); + + let subrange_id = self.dwarf.unit.add(array_type_id, gimli::DW_TAG_subrange_type); + let subrange_entry = self.dwarf.unit.get_mut(subrange_id); + subrange_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(self.array_size_type)); + subrange_entry.set(gimli::DW_AT_lower_bound, AttributeValue::Udata(0)); + subrange_entry.set(gimli::DW_AT_count, AttributeValue::Udata(len)); + + array_type_id + } + + fn pointer_type<'tcx>( + &mut self, + tcx: TyCtxt<'tcx>, + type_dbg: &mut TypeDebugContext<'tcx>, + ptr_type: Ty<'tcx>, + pointee_type: Ty<'tcx>, + ) -> UnitEntryId { + let pointee_dw_ty = self.debug_type(tcx, type_dbg, pointee_type); + + return_if_type_created_in_meantime!(type_dbg, ptr_type); + + let name = type_names::compute_debuginfo_type_name(tcx, ptr_type, true); + + if !has_ptr_meta(tcx, ptr_type) { + let pointer_type_id = + self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_pointer_type); + let pointer_entry = self.dwarf.unit.get_mut(pointer_type_id); + pointer_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(pointee_dw_ty)); + pointer_entry + .set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name))); + + pointer_type_id + } else { + // FIXME implement debuginfo for fat pointers + self.placeholder_for_type(tcx, type_dbg, ptr_type) + } + } + + fn tuple_type<'tcx>( + &mut self, + tcx: TyCtxt<'tcx>, + type_dbg: &mut TypeDebugContext<'tcx>, + tuple_type: Ty<'tcx>, + components: &'tcx [Ty<'tcx>], + ) -> UnitEntryId { + let components = components + .into_iter() + .map(|&ty| (ty, self.debug_type(tcx, type_dbg, ty))) + .collect::<Vec<_>>(); + + return_if_type_created_in_meantime!(type_dbg, tuple_type); + + let name = type_names::compute_debuginfo_type_name(tcx, tuple_type, false); + let layout = RevealAllLayoutCx(tcx).layout_of(tuple_type); + + let tuple_type_id = + self.dwarf.unit.add(self.dwarf.unit.root(), gimli::DW_TAG_structure_type); + let tuple_entry = self.dwarf.unit.get_mut(tuple_type_id); + tuple_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name))); + tuple_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes())); + tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.pref.bytes())); + + for (i, (ty, dw_ty)) in components.into_iter().enumerate() { + let member_id = self.dwarf.unit.add(tuple_type_id, gimli::DW_TAG_member); + let member_entry = self.dwarf.unit.get_mut(member_id); + member_entry.set( + gimli::DW_AT_name, + AttributeValue::StringRef(self.dwarf.strings.add(format!("__{i}"))), + ); + member_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty)); + member_entry.set( + gimli::DW_AT_alignment, + AttributeValue::Udata(RevealAllLayoutCx(tcx).layout_of(ty).align.pref.bytes()), + ); + member_entry.set( + gimli::DW_AT_data_member_location, + AttributeValue::Udata(layout.fields.offset(i).bytes()), + ); + } + + tuple_type_id + } + + fn placeholder_for_type<'tcx>( + &mut self, + tcx: TyCtxt<'tcx>, + type_dbg: &mut TypeDebugContext<'tcx>, + ty: Ty<'tcx>, + ) -> UnitEntryId { + self.debug_type( + tcx, + type_dbg, + Ty::new_array(tcx, tcx.types.u8, RevealAllLayoutCx(tcx).layout_of(ty).size.bytes()), + ) + } +} diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index 35278e6fb29..96ab7a29205 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -3,9 +3,10 @@ use cranelift_codegen::ir::Endianness; use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa}; use cranelift_object::ObjectProduct; -use gimli::write::{Address, CieId, EhFrame, FrameTable, Section}; +use gimli::write::{CieId, EhFrame, FrameTable, Section}; use gimli::RunTimeEndian; +use super::emit::address_for_func; use super::object::WriteDebugInfo; use crate::prelude::*; @@ -47,11 +48,8 @@ impl UnwindContext { match unwind_info { UnwindInfo::SystemV(unwind_info) => { - self.frame_table.add_fde( - self.cie_id.unwrap(), - unwind_info - .to_fde(Address::Symbol { symbol: func_id.as_u32() as usize, addend: 0 }), - ); + self.frame_table + .add_fde(self.cie_id.unwrap(), unwind_info.to_fde(address_for_func(func_id))); } UnwindInfo::WindowsX64(_) => { // FIXME implement this diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 757082a5fed..75268341a4f 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -1,25 +1,29 @@ //! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a //! standalone executable. -use std::fs::File; -use std::path::PathBuf; +use std::fs::{self, File}; +use std::path::{Path, PathBuf}; use std::sync::Arc; use std::thread::JoinHandle; use cranelift_object::{ObjectBuilder, ObjectModule}; use rustc_codegen_ssa::assert_module_sources::CguReuse; +use rustc_codegen_ssa::back::link::ensure_removed; use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; use rustc_codegen_ssa::base::determine_cgu_reuse; +use rustc_codegen_ssa::errors as ssa_errors; use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_metadata::fs::copy_to_stdout; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; -use rustc_session::config::{DebugInfo, OutputFilenames, OutputType}; +use rustc_session::config::{DebugInfo, OutFileName, OutputFilenames, OutputType}; use rustc_session::Session; use crate::concurrency_limiter::{ConcurrencyLimiter, ConcurrencyLimiterToken}; +use crate::debuginfo::TypeDebugContext; use crate::global_asm::GlobalAsmConfig; use crate::{prelude::*, BackendConfig}; @@ -53,6 +57,7 @@ impl OngoingCodegen { pub(crate) fn join( self, sess: &Session, + outputs: &OutputFilenames, backend_config: &BackendConfig, ) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) { let mut work_products = FxIndexMap::default(); @@ -110,17 +115,183 @@ impl OngoingCodegen { sess.dcx().abort_if_errors(); - ( - CodegenResults { - modules, - allocator_module: self.allocator_module, - metadata_module: self.metadata_module, - metadata: self.metadata, - crate_info: self.crate_info, - }, - work_products, - ) + let codegen_results = CodegenResults { + modules, + allocator_module: self.allocator_module, + metadata_module: self.metadata_module, + metadata: self.metadata, + crate_info: self.crate_info, + }; + + produce_final_output_artifacts(sess, &codegen_results, outputs); + + (codegen_results, work_products) + } +} + +// Adapted from https://github.com/rust-lang/rust/blob/73476d49904751f8d90ce904e16dfbc278083d2c/compiler/rustc_codegen_ssa/src/back/write.rs#L547C1-L706C2 +fn produce_final_output_artifacts( + sess: &Session, + codegen_results: &CodegenResults, + crate_output: &OutputFilenames, +) { + let user_wants_bitcode = false; + let mut user_wants_objects = false; + + // Produce final compile outputs. + let copy_gracefully = |from: &Path, to: &OutFileName| match to { + OutFileName::Stdout => { + if let Err(e) = copy_to_stdout(from) { + sess.dcx().emit_err(ssa_errors::CopyPath::new(from, to.as_path(), e)); + } + } + OutFileName::Real(path) => { + if let Err(e) = fs::copy(from, path) { + sess.dcx().emit_err(ssa_errors::CopyPath::new(from, path, e)); + } + } + }; + + let copy_if_one_unit = |output_type: OutputType, keep_numbered: bool| { + if codegen_results.modules.len() == 1 { + // 1) Only one codegen unit. In this case it's no difficulty + // to copy `foo.0.x` to `foo.x`. + let module_name = Some(&codegen_results.modules[0].name[..]); + let path = crate_output.temp_path(output_type, module_name); + let output = crate_output.path(output_type); + if !output_type.is_text_output() && output.is_tty() { + sess.dcx() + .emit_err(ssa_errors::BinaryOutputToTty { shorthand: output_type.shorthand() }); + } else { + copy_gracefully(&path, &output); + } + if !sess.opts.cg.save_temps && !keep_numbered { + // The user just wants `foo.x`, not `foo.#module-name#.x`. + ensure_removed(sess.dcx(), &path); + } + } else { + let extension = crate_output + .temp_path(output_type, None) + .extension() + .unwrap() + .to_str() + .unwrap() + .to_owned(); + + 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(ssa_errors::IgnoringEmitPath { extension }); + } else if crate_output.single_output_file.is_some() { + // 3) Multiple codegen units, with `-o some_name`. We have + // no good solution for this case, so warn the user. + sess.dcx().emit_warn(ssa_errors::IgnoringOutput { extension }); + } else { + // 4) Multiple codegen units, but no explicit name. We + // just leave the `foo.0.x` files in place. + // (We don't have to do any work in this case.) + } + } + }; + + // Flag to indicate whether the user explicitly requested bitcode. + // Otherwise, we produced it only as a temporary output, and will need + // to get rid of it. + for output_type in crate_output.outputs.keys() { + match *output_type { + OutputType::Bitcode => { + // Cranelift doesn't have bitcode + // user_wants_bitcode = true; + // // Copy to .bc, but always keep the .0.bc. There is a later + // // check to figure out if we should delete .0.bc files, or keep + // // them for making an rlib. + // copy_if_one_unit(OutputType::Bitcode, true); + } + OutputType::LlvmAssembly => { + // Cranelift IR text already emitted during codegen + // copy_if_one_unit(OutputType::LlvmAssembly, false); + } + OutputType::Assembly => { + // Currently no support for emitting raw assembly files + // copy_if_one_unit(OutputType::Assembly, false); + } + OutputType::Object => { + user_wants_objects = true; + copy_if_one_unit(OutputType::Object, true); + } + OutputType::Mir | OutputType::Metadata | OutputType::Exe | OutputType::DepInfo => {} + } + } + + // Clean up unwanted temporary files. + + // We create the following files by default: + // - #crate#.#module-name#.bc + // - #crate#.#module-name#.o + // - #crate#.crate.metadata.bc + // - #crate#.crate.metadata.o + // - #crate#.o (linked from crate.##.o) + // - #crate#.bc (copied from crate.##.bc) + // We may create additional files if requested by the user (through + // `-C save-temps` or `--emit=` flags). + + if !sess.opts.cg.save_temps { + // Remove the temporary .#module-name#.o objects. If the user didn't + // explicitly request bitcode (with --emit=bc), and the bitcode is not + // needed for building an rlib, then we must remove .#module-name#.bc as + // well. + + // Specific rules for keeping .#module-name#.bc: + // - If the user requested bitcode (`user_wants_bitcode`), and + // codegen_units > 1, then keep it. + // - If the user requested bitcode but codegen_units == 1, then we + // can toss .#module-name#.bc because we copied it to .bc earlier. + // - If we're not building an rlib and the user didn't request + // bitcode, then delete .#module-name#.bc. + // If you change how this works, also update back::link::link_rlib, + // where .#module-name#.bc files are (maybe) deleted after making an + // rlib. + let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe); + + let keep_numbered_bitcode = user_wants_bitcode && sess.codegen_units().as_usize() > 1; + + let keep_numbered_objects = + needs_crate_object || (user_wants_objects && sess.codegen_units().as_usize() > 1); + + for module in codegen_results.modules.iter() { + if let Some(ref path) = module.object { + if !keep_numbered_objects { + ensure_removed(sess.dcx(), path); + } + } + + if let Some(ref path) = module.dwarf_object { + if !keep_numbered_objects { + ensure_removed(sess.dcx(), path); + } + } + + if let Some(ref path) = module.bytecode { + if !keep_numbered_bitcode { + ensure_removed(sess.dcx(), path); + } + } + } + + if !user_wants_bitcode { + if let Some(ref allocator_module) = codegen_results.allocator_module { + if let Some(ref path) = allocator_module.bytecode { + ensure_removed(sess.dcx(), path); + } + } + } } + + // We leave the following files around by default: + // - #crate#.o + // - #crate#.crate.metadata.o + // - #crate#.bc + // These are used in linking steps and will be cleaned up afterward. } fn make_module(sess: &Session, backend_config: &BackendConfig, name: String) -> ObjectModule { @@ -290,6 +461,7 @@ fn module_codegen( tcx.sess.opts.debuginfo != DebugInfo::None, cgu_name, ); + let mut type_dbg = TypeDebugContext::default(); super::predefine_mono_items(tcx, &mut module, &mono_items); let mut codegened_functions = vec![]; for (mono_item, _) in mono_items { @@ -298,6 +470,7 @@ fn module_codegen( let codegened_function = crate::base::codegen_fn( tcx, &mut cx, + &mut type_dbg, Function::new(), &mut module, inst, @@ -305,7 +478,10 @@ fn module_codegen( codegened_functions.push(codegened_function); } MonoItem::Static(def_id) => { - crate::constant::codegen_static(tcx, &mut module, def_id) + let data_id = crate::constant::codegen_static(tcx, &mut module, def_id); + if let Some(debug_context) = &mut cx.debug_context { + debug_context.define_static(tcx, &mut type_dbg, def_id, data_id); + } } MonoItem::GlobalAsm(item_id) => { crate::global_asm::codegen_global_asm_item( diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 6b2b946db02..6dbc3f19127 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -12,6 +12,7 @@ use rustc_middle::mir::mono::MonoItem; use rustc_session::Session; use rustc_span::Symbol; +use crate::debuginfo::TypeDebugContext; use crate::{prelude::*, BackendConfig}; use crate::{CodegenCx, CodegenMode}; @@ -229,7 +230,14 @@ pub(crate) fn codegen_and_compile_fn<'tcx>( crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name)); let cached_func = std::mem::replace(&mut cached_context.func, Function::new()); - let codegened_func = crate::base::codegen_fn(tcx, cx, cached_func, module, instance); + let codegened_func = crate::base::codegen_fn( + tcx, + cx, + &mut TypeDebugContext::default(), + cached_func, + module, + instance, + ); crate::base::compile_fn(cx, cached_context, module, codegened_func); }); diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 44650898de8..5a0cd3990f2 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::{InlineAsmOperand, ItemId}; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_session::config::{OutputFilenames, OutputType}; use rustc_target::asm::InlineAsmArch; @@ -32,18 +33,27 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: op_sp } => { match asm.operands[operand_idx].0 { InlineAsmOperand::Const { ref anon_const } => { - let const_value = - tcx.const_eval_poly(anon_const.def_id.to_def_id()).unwrap_or_else( - |_| span_bug!(op_sp, "asm const cannot be resolved"), - ); - let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); - let string = rustc_codegen_ssa::common::asm_const_to_str( - tcx, - op_sp, - const_value, - RevealAllLayoutCx(tcx).layout_of(ty), - ); - global_asm.push_str(&string); + match tcx.const_eval_poly(anon_const.def_id.to_def_id()) { + Ok(const_value) => { + let ty = tcx + .typeck_body(anon_const.body) + .node_type(anon_const.hir_id); + let string = rustc_codegen_ssa::common::asm_const_to_str( + tcx, + op_sp, + const_value, + RevealAllLayoutCx(tcx).layout_of(ty), + ); + global_asm.push_str(&string); + } + Err(ErrorHandled::Reported { .. }) => { + // An error has already been reported and compilation is + // guaranteed to fail if execution hits this path. + } + Err(ErrorHandled::TooGeneric(_)) => { + span_bug!(op_sp, "asm const cannot be resolved; too generic"); + } + } } InlineAsmOperand::SymFn { anon_const } => { if cfg!(not(feature = "inline_asm_sym")) { diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 25694af78f1..0b213ff8269 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -341,6 +341,8 @@ fn codegen_float_intrinsic_call<'tcx>( sym::roundf64 => ("round", 1, fx.tcx.types.f64, types::F64), sym::roundevenf32 => ("roundevenf", 1, fx.tcx.types.f32, types::F32), sym::roundevenf64 => ("roundeven", 1, fx.tcx.types.f64, types::F64), + sym::nearbyintf32 => ("nearbyintf", 1, fx.tcx.types.f32, types::F32), + sym::nearbyintf64 => ("nearbyint", 1, fx.tcx.types.f64, types::F64), sym::sinf32 => ("sinf", 1, fx.tcx.types.f32, types::F32), sym::sinf64 => ("sin", 1, fx.tcx.types.f64, types::F64), sym::cosf32 => ("cosf", 1, fx.tcx.types.f32, types::F32), @@ -392,6 +394,8 @@ fn codegen_float_intrinsic_call<'tcx>( | sym::ceilf64 | sym::truncf32 | sym::truncf64 + | sym::nearbyintf32 + | sym::nearbyintf64 | sym::sqrtf32 | sym::sqrtf64 => { let val = match intrinsic { @@ -399,6 +403,7 @@ fn codegen_float_intrinsic_call<'tcx>( sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]), sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]), sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]), + sym::nearbyintf32 | sym::nearbyintf64 => fx.bcx.ins().nearest(args[0]), sym::sqrtf32 | sym::sqrtf64 => fx.bcx.ins().sqrt(args[0]), _ => unreachable!(), }; diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index a59a39074f8..d0ab64a5584 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -148,7 +148,7 @@ impl CodegenCx { let unwind_context = UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot)); let debug_context = if debug_info && !tcx.sess.target.options.is_like_windows { - Some(DebugContext::new(tcx, isa)) + Some(DebugContext::new(tcx, isa, cgu_name.as_str())) } else { None }; @@ -233,12 +233,13 @@ impl CodegenBackend for CraneliftCodegenBackend { &self, ongoing_codegen: Box<dyn Any>, sess: &Session, - _outputs: &OutputFilenames, + outputs: &OutputFilenames, ) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) { - ongoing_codegen - .downcast::<driver::aot::OngoingCodegen>() - .unwrap() - .join(sess, self.config.borrow().as_ref().unwrap()) + ongoing_codegen.downcast::<driver::aot::OngoingCodegen>().unwrap().join( + sess, + outputs, + self.config.borrow().as_ref().unwrap(), + ) } fn link( diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index d2254d4c15e..86ebf37d105 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -2,7 +2,7 @@ //! //! See `rustc_codegen_ssa/src/meth.rs` for reference. -use crate::constant::data_id_for_alloc_id; +use crate::constant::data_id_for_vtable; use crate::prelude::*; pub(crate) fn vtable_memflags() -> MemFlags { @@ -92,12 +92,10 @@ pub(crate) fn get_vtable<'tcx>( ty: Ty<'tcx>, trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, ) -> Value { - let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref)); - let data_id = - data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, Mutability::Not); + let data_id = data_id_for_vtable(fx.tcx, &mut fx.constants_cx, fx.module, ty, trait_ref); let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func); if fx.clif_comments.enabled() { - fx.add_comment(local_data_id, format!("vtable: {:?}", alloc_id)); + fx.add_comment(local_data_id, "vtable"); } fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } 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/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index ee7ea342301..0fbc624389b 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -6,9 +6,8 @@ use crate::llvm; use itertools::Itertools as _; use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods}; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::mir; @@ -335,16 +334,9 @@ fn save_function_record( ); } -/// When finalizing the coverage map, `FunctionCoverage` only has the `CodeRegion`s and counters for -/// the functions that went through codegen; such as public functions and "used" functions -/// (functions referenced by other "used" or public items). Any other functions considered unused, -/// or "Unreachable", were still parsed and processed through the MIR stage, but were not -/// codegenned. (Note that `-Clink-dead-code` can force some unused code to be codegenned, but -/// that flag is known to cause other errors, when combined with `-C instrument-coverage`; and -/// `-Clink-dead-code` will not generate code for unused generic functions.) -/// -/// We can find the unused functions (including generic functions) by the set difference of all MIR -/// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`codegenned_and_inlined_items`). +/// Each CGU will normally only emit coverage metadata for the functions that it actually generates. +/// But since we don't want unused functions to disappear from coverage reports, we also scan for +/// functions that were instrumented but are not participating in codegen. /// /// These unused functions don't need to be codegenned, but we do need to add them to the function /// coverage map (in a single designated CGU) so that we still emit coverage mappings for them. @@ -354,75 +346,109 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); let tcx = cx.tcx; + let usage = prepare_usage_sets(tcx); + + let is_unused_fn = |def_id: LocalDefId| -> bool { + let def_id = def_id.to_def_id(); + + // To be eligible for "unused function" mappings, a definition must: + // - Be function-like + // - Not participate directly in codegen (or have lost all its coverage statements) + // - Not have any coverage statements inlined into codegenned functions + tcx.def_kind(def_id).is_fn_like() + && (!usage.all_mono_items.contains(&def_id) + || usage.missing_own_coverage.contains(&def_id)) + && !usage.used_via_inlining.contains(&def_id) + }; - let eligible_def_ids = tcx.mir_keys(()).iter().filter_map(|local_def_id| { - let def_id = local_def_id.to_def_id(); - let kind = tcx.def_kind(def_id); - // `mir_keys` will give us `DefId`s for all kinds of things, not - // just "functions", like consts, statics, etc. Filter those out. - if !matches!(kind, DefKind::Fn | DefKind::AssocFn | DefKind::Closure) { - return None; - } + // Scan for unused functions that were instrumented for coverage. + for def_id in tcx.mir_keys(()).iter().copied().filter(|&def_id| is_unused_fn(def_id)) { + // Get the coverage info from MIR, skipping functions that were never instrumented. + let body = tcx.optimized_mir(def_id); + let Some(function_coverage_info) = body.function_coverage_info.as_deref() else { continue }; // FIXME(79651): Consider trying to filter out dummy instantiations of // unused generic functions from library crates, because they can produce // "unused instantiation" in coverage reports even when they are actually // used by some downstream crate in the same binary. - Some(local_def_id.to_def_id()) - }); - - let codegenned_def_ids = codegenned_and_inlined_items(tcx); - - // For each `DefId` that should have coverage instrumentation but wasn't - // codegenned, add it to the function coverage map as an unused function. - for def_id in eligible_def_ids.filter(|id| !codegenned_def_ids.contains(id)) { - // Skip any function that didn't have coverage data added to it by the - // coverage instrumentor. - let body = tcx.instance_mir(ty::InstanceDef::Item(def_id)); - let Some(function_coverage_info) = body.function_coverage_info.as_deref() else { - continue; - }; - debug!("generating unused fn: {def_id:?}"); - let instance = declare_unused_fn(tcx, def_id); - add_unused_function_coverage(cx, instance, function_coverage_info); + add_unused_function_coverage(cx, def_id, function_coverage_info); } } -/// All items participating in code generation together with (instrumented) -/// items inlined into them. -fn codegenned_and_inlined_items(tcx: TyCtxt<'_>) -> DefIdSet { - let (items, cgus) = tcx.collect_and_partition_mono_items(()); - let mut visited = DefIdSet::default(); - let mut result = items.clone(); - - for cgu in cgus { - for item in cgu.items().keys() { - if let mir::mono::MonoItem::Fn(ref instance) = item { - let did = instance.def_id(); - if !visited.insert(did) { - continue; - } - let body = tcx.instance_mir(instance.def); - for block in body.basic_blocks.iter() { - for statement in &block.statements { - let mir::StatementKind::Coverage(_) = statement.kind else { continue }; - let scope = statement.source_info.scope; - if let Some(inlined) = scope.inlined_instance(&body.source_scopes) { - result.insert(inlined.def_id()); - } - } - } +struct UsageSets<'tcx> { + all_mono_items: &'tcx DefIdSet, + used_via_inlining: FxHashSet<DefId>, + missing_own_coverage: FxHashSet<DefId>, +} + +/// Prepare sets of definitions that are relevant to deciding whether something +/// is an "unused function" for coverage purposes. +fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> { + let (all_mono_items, cgus) = tcx.collect_and_partition_mono_items(()); + + // Obtain a MIR body for each function participating in codegen, via an + // arbitrary instance. + let mut def_ids_seen = FxHashSet::default(); + let def_and_mir_for_all_mono_fns = cgus + .iter() + .flat_map(|cgu| cgu.items().keys()) + .filter_map(|item| match item { + mir::mono::MonoItem::Fn(instance) => Some(instance), + mir::mono::MonoItem::Static(_) | mir::mono::MonoItem::GlobalAsm(_) => None, + }) + // We only need one arbitrary instance per definition. + .filter(move |instance| def_ids_seen.insert(instance.def_id())) + .map(|instance| { + // We don't care about the instance, just its underlying MIR. + let body = tcx.instance_mir(instance.def); + (instance.def_id(), body) + }); + + // Functions whose coverage statments were found inlined into other functions. + let mut used_via_inlining = FxHashSet::default(); + // Functions that were instrumented, but had all of their coverage statements + // removed by later MIR transforms (e.g. UnreachablePropagation). + let mut missing_own_coverage = FxHashSet::default(); + + for (def_id, body) in def_and_mir_for_all_mono_fns { + let mut saw_own_coverage = false; + + // Inspect every coverage statement in the function's MIR. + for stmt in body + .basic_blocks + .iter() + .flat_map(|block| &block.statements) + .filter(|stmt| matches!(stmt.kind, mir::StatementKind::Coverage(_))) + { + if let Some(inlined) = stmt.source_info.scope.inlined_instance(&body.source_scopes) { + // This coverage statement was inlined from another function. + used_via_inlining.insert(inlined.def_id()); + } else { + // Non-inlined coverage statements belong to the enclosing function. + saw_own_coverage = true; } } + + if !saw_own_coverage && body.function_coverage_info.is_some() { + missing_own_coverage.insert(def_id); + } } - result + UsageSets { all_mono_items, used_via_inlining, missing_own_coverage } } -fn declare_unused_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::Instance<'tcx> { - ty::Instance::new( +fn add_unused_function_coverage<'tcx>( + cx: &CodegenCx<'_, 'tcx>, + def_id: LocalDefId, + function_coverage_info: &'tcx mir::coverage::FunctionCoverageInfo, +) { + let tcx = cx.tcx; + let def_id = def_id.to_def_id(); + + // Make a dummy instance that fills in all generics with placeholders. + let instance = ty::Instance::new( def_id, ty::GenericArgs::for_item(tcx, def_id, |param, _| { if let ty::GenericParamDefKind::Lifetime = param.kind { @@ -431,14 +457,8 @@ fn declare_unused_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::Instance<'tc tcx.mk_param_from_def(param) } }), - ) -} + ); -fn add_unused_function_coverage<'tcx>( - cx: &CodegenCx<'_, 'tcx>, - instance: ty::Instance<'tcx>, - function_coverage_info: &'tcx mir::coverage::FunctionCoverageInfo, -) { // An unused function's mappings will automatically be rewritten to map to // zero, because none of its counters/expressions are marked as seen. let function_coverage = FunctionCoverageCollector::unused(instance, function_coverage_info); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index 4792b0798df..4edef14422e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -683,7 +683,8 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>( _ => unreachable!(), }; - let coroutine_layout = cx.tcx.optimized_mir(coroutine_def_id).coroutine_layout().unwrap(); + let coroutine_layout = + cx.tcx.coroutine_layout(coroutine_def_id, coroutine_args.kind_ty()).unwrap(); let common_upvar_names = cx.tcx.closure_saved_names_of_captured_variables(coroutine_def_id); let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 3dbe820b8ff..115d5187eaf 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -135,7 +135,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>( unique_type_id: UniqueTypeId<'tcx>, ) -> DINodeCreationResult<'ll> { let coroutine_type = unique_type_id.expect_ty(); - let &ty::Coroutine(coroutine_def_id, _) = coroutine_type.kind() else { + let &ty::Coroutine(coroutine_def_id, coroutine_args) = coroutine_type.kind() else { bug!("build_coroutine_di_node() called with non-coroutine type: `{:?}`", coroutine_type) }; @@ -158,8 +158,10 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>( DIFlags::FlagZero, ), |cx, coroutine_type_di_node| { - let coroutine_layout = - cx.tcx.optimized_mir(coroutine_def_id).coroutine_layout().unwrap(); + let coroutine_layout = cx + .tcx + .coroutine_layout(coroutine_def_id, coroutine_args.as_coroutine().kind_ty()) + .unwrap(); let Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, .. } = coroutine_type_and_layout.variants 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_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..4283ebc99d2 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)?; @@ -402,7 +409,7 @@ fn const_validate_mplace<'mir, 'tcx>( } }; ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode) - // Instead of just reporting the `InterpError` via the usual machinery, we give a more targetted + // Instead of just reporting the `InterpError` via the usual machinery, we give a more targeted // error about the validation failure. .map_err(|error| report_validation_error(&ecx, error, alloc_id))?; inner = true; 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_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 08e3e42a82e..378b168a50c 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -101,18 +101,17 @@ impl<'tcx> MirPass<'tcx> for Validator { } // Enforce that coroutine-closure layouts are identical. - if let Some(layout) = body.coroutine_layout() + if let Some(layout) = body.coroutine_layout_raw() && let Some(by_move_body) = body.coroutine_by_move_body() - && let Some(by_move_layout) = by_move_body.coroutine_layout() + && let Some(by_move_layout) = by_move_body.coroutine_layout_raw() { - if layout != by_move_layout { - // If this turns out not to be true, please let compiler-errors know. - // It is possible to support, but requires some changes to the layout - // computation code. + // FIXME(async_closures): We could do other validation here? + if layout.variant_fields.len() != by_move_layout.variant_fields.len() { cfg_checker.fail( Location::START, format!( - "Coroutine layout differs from by-move coroutine layout:\n\ + "Coroutine layout has different number of variant fields from \ + by-move coroutine layout:\n\ layout: {layout:#?}\n\ by_move_layout: {by_move_layout:#?}", ), @@ -715,13 +714,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // args of the coroutine. Otherwise, we prefer to use this body // since we may be in the process of computing this MIR in the // first place. - let gen_body = if def_id == self.caller_body.source.def_id() { - self.caller_body + let layout = if def_id == self.caller_body.source.def_id() { + // FIXME: This is not right for async closures. + self.caller_body.coroutine_layout_raw() } else { - self.tcx.optimized_mir(def_id) + self.tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) }; - let Some(layout) = gen_body.coroutine_layout() else { + let Some(layout) = layout else { self.fail( location, format!("No coroutine layout for {parent_ty:?}"), 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_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 30ee02ea3c0..b25dd8fe67b 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1252,21 +1252,18 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe // after macro expansion (that is, they are unhygienic). if !path.is_absolute() { let callsite = span.source_callsite(); - let mut result = match sess.source_map().span_to_filename(callsite) { - FileName::Real(name) => name - .into_local_path() - .expect("attempting to resolve a file path in an external file"), - FileName::DocTest(path, _) => path, - other => { - return Err(sess.dcx().create_err(errors::ResolveRelativePath { - span, - path: sess.source_map().filename_for_diagnostics(&other).to_string(), - })); - } + let source_map = sess.source_map(); + let Some(mut base_path) = source_map.span_to_filename(callsite).into_local_path() else { + return Err(sess.dcx().create_err(errors::ResolveRelativePath { + span, + path: source_map + .filename_for_diagnostics(&source_map.span_to_filename(callsite)) + .to_string(), + })); }; - result.pop(); - result.push(path); - Ok(result) + base_path.pop(); + base_path.push(path); + Ok(base_path) } else { Ok(path) } @@ -1379,6 +1376,15 @@ pub fn get_single_str_from_tts( tts: TokenStream, name: &str, ) -> ExpandResult<Result<Symbol, ErrorGuaranteed>, ()> { + get_single_str_spanned_from_tts(cx, span, tts, name).map(|res| res.map(|(s, _)| s)) +} + +pub fn get_single_str_spanned_from_tts( + cx: &mut ExtCtxt<'_>, + span: Span, + tts: TokenStream, + name: &str, +) -> ExpandResult<Result<(Symbol, Span), ErrorGuaranteed>, ()> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); @@ -1393,7 +1399,13 @@ pub fn get_single_str_from_tts( if p.token != token::Eof { cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); } - expr_to_string(cx, ret, "argument must be a string literal").map(|s| s.map(|(s, _)| s)) + expr_to_spanned_string(cx, ret, "argument must be a string literal").map(|res| { + res.map_err(|err| match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, + }) + .map(|(symbol, _style, span)| (symbol, span)) + }) } /// Extracts comma-separated expressions from `tts`. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index cc0ab05d422..a70d2ebbd62 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2289,21 +2289,15 @@ pub enum ImplItemKind<'hir> { Type(&'hir Ty<'hir>), } -/// Bind a type to an associated type (i.e., `A = Foo`). +/// An associated item binding. /// -/// Bindings like `A: Debug` are represented as a special type `A = -/// $::Debug` that is understood by the HIR ty lowering code. +/// ### Examples /// -/// FIXME(alexreg): why have a separate type for the binding case, -/// wouldn't it be better to make the `ty` field an enum like the -/// following? -/// -/// ```ignore (pseudo-rust) -/// enum TypeBindingKind { -/// Equals(...), -/// Binding(...), -/// } -/// ``` +/// * `Trait<A = Ty, B = Ty>` +/// * `Trait<G<Ty> = Ty>` +/// * `Trait<A: Bound>` +/// * `Trait<C = { Ct }>` (under feature `associated_const_equality`) +/// * `Trait<f(): Bound>` (under feature `return_type_notation`) #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct TypeBinding<'hir> { pub hir_id: HirId, @@ -2336,7 +2330,7 @@ impl<'hir> From<AnonConst> for Term<'hir> { pub enum TypeBindingKind<'hir> { /// E.g., `Foo<Bar: Send>`. Constraint { bounds: &'hir [GenericBound<'hir>] }, - /// E.g., `Foo<Bar = ()>`, `Foo<Bar = ()>` + /// E.g., `Foo<Bar = ()>`. Equality { term: Term<'hir> }, } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index dbf86f5cf74..5d97019416f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -199,6 +199,7 @@ language_item_table! { Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0); DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0); + DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0); DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None; Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 80be563686a..d9d36f5299b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -9,8 +9,85 @@ use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamNa use super::HirTyLowerer; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { + /// Prohibit or lint against *bare* trait object types depending on the edition. + /// + /// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`. + /// In edition 2021 and onward we emit a hard error for them. + pub(super) fn prohibit_or_lint_bare_trait_object_ty( + &self, + self_ty: &hir::Ty<'_>, + in_path: bool, + ) { + let tcx = self.tcx(); + + let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = + self_ty.kind + else { + return; + }; + + let needs_bracket = in_path + && !tcx + .sess + .source_map() + .span_to_prev_source(self_ty.span) + .ok() + .is_some_and(|s| s.trim_end().ends_with('<')); + + let is_global = poly_trait_ref.trait_ref.path.is_global(); + + let mut sugg = vec![( + self_ty.span.shrink_to_lo(), + format!( + "{}dyn {}", + if needs_bracket { "<" } else { "" }, + if is_global { "(" } else { "" }, + ), + )]; + + if is_global || needs_bracket { + sugg.push(( + self_ty.span.shrink_to_hi(), + format!( + "{}{}", + if is_global { ")" } else { "" }, + if needs_bracket { ">" } else { "" }, + ), + )); + } + + if self_ty.span.edition().at_least_rust_2021() { + let msg = "trait objects must include the `dyn` keyword"; + let label = "add `dyn` keyword before this trait"; + let mut diag = + rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg); + if self_ty.span.can_be_used_for_suggestions() + && !self.maybe_suggest_impl_trait(self_ty, &mut diag) + { + // FIXME: Only emit this suggestion if the trait is object safe. + diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable); + } + // Check if the impl trait that we are considering is an impl of a local trait. + self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag); + self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag); + diag.stash(self_ty.span, StashKey::TraitMissingMethod); + } else { + let msg = "trait objects without an explicit `dyn` are deprecated"; + tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| { + if self_ty.span.can_be_used_for_suggestions() { + lint.multipart_suggestion_verbose( + "if this is an object-safe trait, use `dyn`", + sugg, + Applicability::MachineApplicable, + ); + } + self.maybe_suggest_blanket_trait_impl(self_ty, lint); + }); + } + } + /// Make sure that we are in the condition to suggest the blanket implementation. - pub(super) fn maybe_lint_blanket_trait_impl<G: EmissionGuarantee>( + fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>( &self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_, G>, @@ -75,9 +152,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Make sure that we are in the condition to suggest `impl Trait`. - fn maybe_lint_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> bool { + fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> bool { let tcx = self.tcx(); let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id; + // FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>` + // and suggest `Trait0<Ty = impl Trait1>`. let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => { (sig, generics, None) @@ -186,71 +265,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { false } - pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) { - let tcx = self.tcx(); - if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) = - self_ty.kind - { - let needs_bracket = in_path - && !tcx - .sess - .source_map() - .span_to_prev_source(self_ty.span) - .ok() - .is_some_and(|s| s.trim_end().ends_with('<')); - - let is_global = poly_trait_ref.trait_ref.path.is_global(); - - let mut sugg = Vec::from_iter([( - self_ty.span.shrink_to_lo(), - format!( - "{}dyn {}", - if needs_bracket { "<" } else { "" }, - if is_global { "(" } else { "" }, - ), - )]); + fn maybe_suggest_assoc_ty_bound(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) { + let mut parents = self.tcx().hir().parent_iter(self_ty.hir_id); - if is_global || needs_bracket { - sugg.push(( - self_ty.span.shrink_to_hi(), - format!( - "{}{}", - if is_global { ")" } else { "" }, - if needs_bracket { ">" } else { "" }, - ), - )); + if let Some((_, hir::Node::TypeBinding(binding))) = parents.next() + && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(obj_ty) } = binding.kind + { + if let Some((_, hir::Node::TraitRef(..))) = parents.next() + && let Some((_, hir::Node::Ty(ty))) = parents.next() + && let hir::TyKind::TraitObject(..) = ty.kind + { + // Assoc ty bounds aren't permitted inside trait object types. + return; } - if self_ty.span.edition().at_least_rust_2021() { - let msg = "trait objects must include the `dyn` keyword"; - let label = "add `dyn` keyword before this trait"; - let mut diag = - rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg); - if self_ty.span.can_be_used_for_suggestions() - && !self.maybe_lint_impl_trait(self_ty, &mut diag) - { - diag.multipart_suggestion_verbose( - label, - sugg, - Applicability::MachineApplicable, - ); - } - // check if the impl trait that we are considering is a impl of a local trait - self.maybe_lint_blanket_trait_impl(self_ty, &mut diag); - diag.stash(self_ty.span, StashKey::TraitMissingMethod); + let lo = if binding.gen_args.span_ext.is_dummy() { + binding.ident.span } else { - let msg = "trait objects without an explicit `dyn` are deprecated"; - tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| { - if self_ty.span.can_be_used_for_suggestions() { - lint.multipart_suggestion_verbose( - "if this is an object-safe trait, use `dyn`", - sugg, - Applicability::MachineApplicable, - ); - } - self.maybe_lint_blanket_trait_impl(self_ty, lint); - }); + binding.gen_args.span_ext + }; + let hi = obj_ty.span; + + if !lo.eq_ctxt(hi) { + return; } + + diag.span_suggestion_verbose( + lo.between(hi), + "you might have meant to write a bound here", + ": ", + Applicability::MaybeIncorrect, + ); } } } 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 a119ea450b4..8886a78c6ec 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2212,6 +2212,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { try_emit("delegation with early bound generics"); } + // There is no way to instantiate `Self` param for caller if + // 1. callee is a trait method + // 2. delegation item isn't an associative item + if let DefKind::AssocFn = self.tcx().def_kind(sig_id) + && let DefKind::Fn = self.tcx().def_kind(self.item_def_id()) + && self.tcx().associated_item(sig_id).container + == ty::AssocItemContainer::TraitContainer + { + try_emit("delegation to a trait method from a free function"); + } + if self.tcx().asyncness(sig_id) == ty::Asyncness::Yes { try_emit("delegation to async functions"); } @@ -2339,12 +2350,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) } hir::TyKind::TraitObject(bounds, lifetime, repr) => { - self.maybe_lint_bare_trait(hir_ty, in_path); + self.prohibit_or_lint_bare_trait_object_ty(hir_ty, in_path); + let repr = match repr { TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn, TraitObjectSyntax::DynStar => ty::DynStar, }; - self.lower_trait_object_ty( hir_ty.span, hir_ty.hir_id, diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 3ec5894700f..b7786ec219c 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -101,8 +101,9 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::middle; +use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::util; use rustc_session::parse::feature_err; use rustc_span::{symbol::sym, Span}; @@ -186,7 +187,12 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { let def_kind = tcx.def_kind(item_def_id); match def_kind { DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id), - DefKind::Const => tcx.ensure().const_eval_poly(item_def_id.into()), + DefKind::Const if tcx.generics_of(item_def_id).params.is_empty() => { + let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty()); + let cid = GlobalId { instance, promoted: None }; + let param_env = ty::ParamEnv::reveal_all(); + tcx.ensure().eval_to_const_value_raw(param_env.and(cid)); + } _ => (), } }); diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 8077acea52e..d3bb22d715d 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -1,14 +1,14 @@ +use rustc_data_structures::fx::FxIndexMap; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_middle::ty::{self, Region, Ty, TyCtxt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::Span; use smallvec::smallvec; -use std::collections::BTreeMap; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred /// must be added to the struct header. pub(crate) type RequiredPredicates<'tcx> = - BTreeMap<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>, Span>; + FxIndexMap<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>, Span>; /// Given a requirement `T: 'a` or `'b: 'a`, deduce the /// outlives_component and add it to `required_predicates` diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 0ca958302f7..f7af438ad16 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -122,6 +122,10 @@ hir_typeck_return_stmt_outside_of_fn_body = .encl_body_label = the {$statement_kind} is part of this body... .encl_fn_label = ...not the enclosing function body +hir_typeck_rpit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions + +hir_typeck_rpit_change_return_type = you could change the return type to be a boxed trait object + hir_typeck_rustcall_incorrect_args = functions with the "rust-call" ABI must take a single non-self tuple argument diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 9b7db9e4c8e..2a2fd0a41a6 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -1,17 +1,13 @@ use crate::coercion::{AsCoercionSite, CoerceMany}; use crate::{Diverges, Expectation, FnCtxt, Needs}; use rustc_errors::{Applicability, Diag}; -use rustc_hir::{ - self as hir, - def::{CtorOf, DefKind, Res}, - ExprKind, PatKind, -}; +use rustc_hir::def::{CtorOf, DefKind, Res}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{self as hir, ExprKind, PatKind}; use rustc_hir_pretty::ty_to_string; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::traits::Obligation; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, }; @@ -91,10 +87,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let arm_ty = self.check_expr_with_expectation(arm.body, expected); all_arms_diverge &= self.diverges.get(); - - let opt_suggest_box_span = prior_arm.and_then(|(_, prior_arm_ty, _)| { - self.opt_suggest_box_span(prior_arm_ty, arm_ty, orig_expected) - }); + let tail_defines_return_position_impl_trait = + self.return_position_impl_trait_from_match_expectation(orig_expected); let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind { (Some(blk.hir_id), self.find_block_span(blk)) @@ -120,7 +114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scrut_span: scrut.span, source: match_src, prior_non_diverging_arms: prior_non_diverging_arms.clone(), - opt_suggest_box_span, + tail_defines_return_position_impl_trait, })), ), }; @@ -243,7 +237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let can_coerce_to_return_ty = match self.ret_coercion.as_ref() { Some(ret_coercion) => { let ret_ty = ret_coercion.borrow().expected_ty(); - let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); + let ret_ty = self.infcx.shallow_resolve(ret_ty); self.can_coerce(arm_ty, ret_ty) && prior_arm.map_or(true, |(_, ty, _)| self.can_coerce(ty, ret_ty)) // The match arms need to unify for the case of `impl Trait`. @@ -422,7 +416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else_expr: &'tcx hir::Expr<'tcx>, then_ty: Ty<'tcx>, else_ty: Ty<'tcx>, - opt_suggest_box_span: Option<Span>, + tail_defines_return_position_impl_trait: Option<LocalDefId>, ) -> ObligationCause<'tcx> { let mut outer_span = if self.tcx.sess.source_map().is_multiline(span) { // The `if`/`else` isn't in one line in the output, include some context to make it @@ -513,7 +507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { then_ty, else_ty, outer_span, - opt_suggest_box_span, + tail_defines_return_position_impl_trait, })), ) } @@ -593,96 +587,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// When we have a `match` as a tail expression in a `fn` with a returned `impl Trait` - /// we check if the different arms would work with boxed trait objects instead and - /// provide a structured suggestion in that case. - pub(crate) fn opt_suggest_box_span( + // Does the expectation of the match define an RPIT? + // (e.g. we're in the tail of a function body) + // + // Returns the `LocalDefId` of the RPIT, which is always identity-substituted. + pub fn return_position_impl_trait_from_match_expectation( &self, - first_ty: Ty<'tcx>, - second_ty: Ty<'tcx>, - orig_expected: Expectation<'tcx>, - ) -> Option<Span> { - // FIXME(compiler-errors): This really shouldn't need to be done during the - // "good" path of typeck, but here we are. - match orig_expected { - Expectation::ExpectHasType(expected) => { - let TypeVariableOrigin { - span, - kind: TypeVariableOriginKind::OpaqueTypeInference(rpit_def_id), - .. - } = self.type_var_origin(expected)? - else { - return None; - }; - - let Some(rpit_local_def_id) = rpit_def_id.as_local() else { - return None; - }; - if !matches!( - self.tcx.hir().expect_item(rpit_local_def_id).expect_opaque_ty().origin, - hir::OpaqueTyOrigin::FnReturn(..) - ) { - return None; - } - - let sig = self.body_fn_sig()?; - - let args = sig.output().walk().find_map(|arg| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) = *ty.kind() - && def_id == rpit_def_id - { - Some(args) - } else { - None - } - })?; - - if !self.can_coerce(first_ty, expected) || !self.can_coerce(second_ty, expected) { - return None; - } - - for ty in [first_ty, second_ty] { - for (clause, _) in self - .tcx - .explicit_item_super_predicates(rpit_def_id) - .iter_instantiated_copied(self.tcx, args) - { - let pred = clause.kind().rebind(match clause.kind().skip_binder() { - ty::ClauseKind::Trait(trait_pred) => { - assert!(matches!( - *trait_pred.trait_ref.self_ty().kind(), - ty::Alias(ty::Opaque, ty::AliasTy { def_id, args: alias_args, .. }) - if def_id == rpit_def_id && args == alias_args - )); - ty::ClauseKind::Trait(trait_pred.with_self_ty(self.tcx, ty)) - } - ty::ClauseKind::Projection(mut proj_pred) => { - assert!(matches!( - *proj_pred.projection_ty.self_ty().kind(), - ty::Alias(ty::Opaque, ty::AliasTy { def_id, args: alias_args, .. }) - if def_id == rpit_def_id && args == alias_args - )); - proj_pred = proj_pred.with_self_ty(self.tcx, ty); - ty::ClauseKind::Projection(proj_pred) - } - _ => continue, - }); - if !self.predicate_must_hold_modulo_regions(&Obligation::new( - self.tcx, - ObligationCause::misc(span, self.body_id), - self.param_env, - pred, - )) { - return None; - } - } - } - - Some(span) - } - _ => None, + expectation: Expectation<'tcx>, + ) -> Option<LocalDefId> { + let expected_ty = expectation.to_option(self)?; + let (def_id, args) = match *expected_ty.kind() { + // FIXME: Could also check that the RPIT is not defined + ty::Alias(ty::Opaque, alias_ty) => (alias_ty.def_id.as_local()?, alias_ty.args), + // FIXME(-Znext-solver): Remove this branch once `replace_opaque_types_with_infer` is gone. + ty::Infer(ty::TyVar(_)) => self + .inner + .borrow() + .iter_opaque_types() + .find(|(_, v)| v.ty == expected_ty) + .map(|(k, _)| (k.def_id, k.args))?, + _ => return None, + }; + let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = self.tcx.opaque_type_origin(def_id) + else { + return None; + }; + if &args[0..self.tcx.generics_of(parent_def_id).count()] + != ty::GenericArgs::identity_for_item(self.tcx, parent_def_id).as_slice() + { + return None; } + Some(def_id) } } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 40555bf14eb..36af5394015 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -848,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_vars, ); - let c_result = self.inh.infcx.canonicalize_response(result); + let c_result = self.infcx.canonicalize_response(result); self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); // Normalize only after registering in `user_provided_sigs`. diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 3328177634b..44b19318d5d 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -35,17 +35,18 @@ //! // and are then unable to coerce `&7i32` to `&mut i32`. //! ``` +use crate::errors::SuggestBoxingForReturnImplTrait; use crate::FnCtxt; use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Expr; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; -use rustc_infer::traits::TraitEngine; use rustc_infer::traits::TraitEngineExt as _; +use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause, TraitEngine}; use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_middle::lint::in_external_macro; use rustc_middle::traits::BuiltinImplSource; @@ -59,6 +60,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::DesugaringKind; +use rustc_span::{BytePos, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; @@ -1638,6 +1640,77 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { unsized_return = self.is_return_ty_definitely_unsized(fcx); } } + ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { + arm_span, + arm_ty, + prior_arm_ty, + ref prior_non_diverging_arms, + tail_defines_return_position_impl_trait: Some(rpit_def_id), + .. + }) => { + err = fcx.err_ctxt().report_mismatched_types( + cause, + expected, + found, + coercion_error, + ); + // Check that we're actually in the second or later arm + if prior_non_diverging_arms.len() > 0 { + self.suggest_boxing_tail_for_return_position_impl_trait( + fcx, + &mut err, + rpit_def_id, + arm_ty, + prior_arm_ty, + prior_non_diverging_arms + .iter() + .chain(std::iter::once(&arm_span)) + .copied(), + ); + } + } + ObligationCauseCode::IfExpression(box IfExpressionCause { + then_id, + else_id, + then_ty, + else_ty, + tail_defines_return_position_impl_trait: Some(rpit_def_id), + .. + }) => { + err = fcx.err_ctxt().report_mismatched_types( + cause, + expected, + found, + coercion_error, + ); + let then_span = fcx.find_block_span_from_hir_id(then_id); + let else_span = fcx.find_block_span_from_hir_id(else_id); + // don't suggest wrapping either blocks in `if .. {} else {}` + let is_empty_arm = |id| { + let hir::Node::Block(blk) = fcx.tcx.hir_node(id) else { + return false; + }; + if blk.expr.is_some() || !blk.stmts.is_empty() { + return false; + } + let Some((_, hir::Node::Expr(expr))) = + fcx.tcx.hir().parent_iter(id).nth(1) + else { + return false; + }; + matches!(expr.kind, hir::ExprKind::If(..)) + }; + if !is_empty_arm(then_id) && !is_empty_arm(else_id) { + self.suggest_boxing_tail_for_return_position_impl_trait( + fcx, + &mut err, + rpit_def_id, + then_ty, + else_ty, + [then_span, else_span].into_iter(), + ); + } + } _ => { err = fcx.err_ctxt().report_mismatched_types( cause, @@ -1677,6 +1750,70 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } + fn suggest_boxing_tail_for_return_position_impl_trait( + &self, + fcx: &FnCtxt<'_, 'tcx>, + err: &mut Diag<'_>, + rpit_def_id: LocalDefId, + a_ty: Ty<'tcx>, + b_ty: Ty<'tcx>, + arm_spans: impl Iterator<Item = Span>, + ) { + let compatible = |ty: Ty<'tcx>| { + fcx.probe(|_| { + let ocx = ObligationCtxt::new(fcx); + ocx.register_obligations( + fcx.tcx + .item_super_predicates(rpit_def_id) + .instantiate_identity_iter() + .filter_map(|clause| { + let predicate = clause + .kind() + .map_bound(|clause| match clause { + ty::ClauseKind::Trait(trait_pred) => Some( + ty::ClauseKind::Trait(trait_pred.with_self_ty(fcx.tcx, ty)), + ), + ty::ClauseKind::Projection(proj_pred) => { + Some(ty::ClauseKind::Projection( + proj_pred.with_self_ty(fcx.tcx, ty), + )) + } + _ => None, + }) + .transpose()?; + Some(Obligation::new( + fcx.tcx, + ObligationCause::dummy(), + fcx.param_env, + predicate, + )) + }), + ); + ocx.select_where_possible().is_empty() + }) + }; + + if !compatible(a_ty) || !compatible(b_ty) { + return; + } + + let rpid_def_span = fcx.tcx.def_span(rpit_def_id); + err.subdiagnostic( + fcx.tcx.dcx(), + SuggestBoxingForReturnImplTrait::ChangeReturnType { + start_sp: rpid_def_span.with_hi(rpid_def_span.lo() + BytePos(4)), + end_sp: rpid_def_span.shrink_to_hi(), + }, + ); + + let (starts, ends) = + arm_spans.map(|span| (span.shrink_to_lo(), span.shrink_to_hi())).unzip(); + err.subdiagnostic( + fcx.tcx.dcx(), + SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends }, + ); + } + fn note_unreachable_loop_return( &self, err: &mut Diag<'_>, diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index eee4ac5ad23..f9b2ec69730 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -621,3 +621,21 @@ pub struct NoteCallerChoosesTyForTyParam<'tcx> { pub ty_param_name: Symbol, pub found_ty: Ty<'tcx>, } + +#[derive(Subdiagnostic)] +pub enum SuggestBoxingForReturnImplTrait { + #[multipart_suggestion(hir_typeck_rpit_change_return_type, applicability = "maybe-incorrect")] + ChangeReturnType { + #[suggestion_part(code = "Box<dyn")] + start_sp: Span, + #[suggestion_part(code = ">")] + end_sp: Span, + }, + #[multipart_suggestion(hir_typeck_rpit_box_return_expr, applicability = "maybe-incorrect")] + BoxReturnExpr { + #[suggestion_part(code = "Box::new(")] + starts: Vec<Span>, + #[suggestion_part(code = ")")] + ends: Vec<Span>, + }, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f38f04fce43..d3e6eb124f7 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1088,7 +1088,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let else_ty = self.check_expr_with_expectation(else_expr, expected); let else_diverges = self.diverges.get(); - let opt_suggest_box_span = self.opt_suggest_box_span(then_ty, else_ty, orig_expected); + let tail_defines_return_position_impl_trait = + self.return_position_impl_trait_from_match_expectation(orig_expected); let if_cause = self.if_cause( sp, cond_expr.span, @@ -1096,7 +1097,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else_expr, then_ty, else_ty, - opt_suggest_box_span, + tail_defines_return_position_impl_trait, ); coerce.coerce(self, &if_cause, else_expr, else_ty); diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 140618e97cc..fe1e4e74973 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -347,7 +347,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> { .any(|n| roots_reachable_from_non_diverging.visited(n)); let infer_var_infos: UnordBag<_> = self - .inh .infer_var_info .borrow() .items() diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 8e0be7c7163..011607bacc6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -526,7 +526,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn resolve_rvalue_scopes(&self, def_id: DefId) { let scope_tree = self.tcx.region_scope_tree(def_id); let rvalue_scopes = { rvalue_scopes::resolve_rvalue_scopes(self, scope_tree, def_id) }; - let mut typeck_results = self.inh.typeck_results.borrow_mut(); + let mut typeck_results = self.typeck_results.borrow_mut(); typeck_results.rvalue_scopes = rvalue_scopes; } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index efa2862177e..74f27cfebbd 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -7,7 +7,7 @@ mod suggestions; use crate::coercion::DynamicCoerceMany; use crate::fallback::DivergingFallbackBehavior; use crate::fn_ctxt::checks::DivergingBlockBehavior; -use crate::{CoroutineTypes, Diverges, EnclosingBreakables, Inherited}; +use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt}; use hir::def_id::CRATE_DEF_ID; use rustc_errors::{DiagCtxt, ErrorGuaranteed}; use rustc_hir as hir; @@ -108,7 +108,7 @@ pub struct FnCtxt<'a, 'tcx> { pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>, - pub(super) inh: &'a Inherited<'tcx>, + pub(super) root_ctxt: &'a TypeckRootCtxt<'tcx>, pub(super) fallback_has_occurred: Cell<bool>, @@ -118,12 +118,12 @@ pub struct FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn new( - inh: &'a Inherited<'tcx>, + root_ctxt: &'a TypeckRootCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, ) -> FnCtxt<'a, 'tcx> { let (diverging_fallback_behavior, diverging_block_behavior) = - parse_never_type_options_attr(inh.tcx); + parse_never_type_options_attr(root_ctxt.tcx); FnCtxt { body_id, param_env, @@ -137,7 +137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { stack: Vec::new(), by_id: Default::default(), }), - inh, + root_ctxt, fallback_has_occurred: Cell::new(false), diverging_fallback_behavior, diverging_block_behavior, @@ -206,9 +206,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { - type Target = Inherited<'tcx>; + type Target = TypeckRootCtxt<'tcx>; fn deref(&self) -> &Self::Target { - self.inh + self.root_ctxt } } diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 1fa799dcec7..be5cd6e9d48 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -95,8 +95,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { Some(ref ty) => { let o_ty = self.fcx.lower_ty(ty); - let c_ty = - self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw)); + let c_ty = self.fcx.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw)); debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty); self.fcx .typeck_results diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 0b67b37df29..80fd4be53e1 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -31,7 +31,6 @@ pub mod expr_use_visitor; mod fallback; mod fn_ctxt; mod gather_locals; -mod inherited; mod intrinsicck; mod mem_categorization; mod method; @@ -39,11 +38,12 @@ mod op; mod pat; mod place_op; mod rvalue_scopes; +mod typeck_root_ctxt; mod upvar; mod writeback; pub use fn_ctxt::FnCtxt; -pub use inherited::Inherited; +pub use typeck_root_ctxt::TypeckRootCtxt; use crate::check::check_fn; use crate::coercion::DynamicCoerceMany; @@ -83,20 +83,6 @@ macro_rules! type_error_struct { }) } -/// If this `DefId` is a "primary tables entry", returns -/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`. -/// -/// If this function returns `Some`, then `typeck_results(def_id)` will -/// succeed; if it returns `None`, then `typeck_results(def_id)` may or -/// may not succeed. In some cases where this function returns `None` -/// (notably closures), `typeck_results(def_id)` would wind up -/// redirecting to the owning function. -fn primary_body_of( - node: Node<'_>, -) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { - Some((node.body_id()?, node.ty(), node.fn_sig())) -} - fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // Closures' typeck results come from their outermost function, // as they are part of the same "inference environment". @@ -106,7 +92,7 @@ fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } if let Some(def_id) = def_id.as_local() { - primary_body_of(tcx.hir_node_by_def_id(def_id)).is_some() + tcx.hir_node_by_def_id(def_id).body_id().is_some() } else { false } @@ -163,20 +149,20 @@ fn typeck_with_fallback<'tcx>( let span = tcx.hir().span(id); // Figure out what primary body this item has. - let (body_id, body_ty, fn_sig) = primary_body_of(node).unwrap_or_else(|| { + let body_id = node.body_id().unwrap_or_else(|| { span_bug!(span, "can't type-check body of {:?}", def_id); }); let body = tcx.hir().body(body_id); let param_env = tcx.param_env(def_id); - let inh = Inherited::new(tcx, def_id); + let root_ctxt = TypeckRootCtxt::new(tcx, def_id); if let Some(inspector) = inspector { - inh.infcx.attach_obligation_inspector(inspector); + root_ctxt.infcx.attach_obligation_inspector(inspector); } - let mut fcx = FnCtxt::new(&inh, param_env, def_id); + let mut fcx = FnCtxt::new(&root_ctxt, param_env, def_id); - if let Some(hir::FnSig { header, decl, .. }) = fn_sig { + if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() { let fn_sig = if decl.output.get_infer_ret_ty().is_some() { fcx.lowerer().lower_fn_ty(id, header.unsafety, header.abi, decl, None, None) } else { @@ -191,42 +177,7 @@ fn typeck_with_fallback<'tcx>( check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params); } else { - let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = body_ty { - Some(fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - })) - } else if let Node::AnonConst(_) = node { - match tcx.parent_hir_node(id) { - Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), .. }) - if anon_const.hir_id == id => - { - Some(fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - })) - } - Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. }) - | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => { - asm.operands.iter().find_map(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => { - // Inline assembly constants must be integers. - Some(fcx.next_int_var()) - } - hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => { - Some(fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span, - })) - } - _ => None, - }) - } - _ => None, - } - } else { - None - }; + let expected_type = infer_type_if_missing(&fcx, node); let expected_type = expected_type.unwrap_or_else(fallback); let expected_type = fcx.normalize(body.value.span, expected_type); @@ -296,6 +247,59 @@ fn typeck_with_fallback<'tcx>( typeck_results } +fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Option<Ty<'tcx>> { + let tcx = fcx.tcx; + let def_id = fcx.body_id; + let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = node.ty() { + if let Some(item) = tcx.opt_associated_item(def_id.into()) + && let ty::AssocKind::Const = item.kind + && let ty::ImplContainer = item.container + && let Some(trait_item) = item.trait_item_def_id + { + let args = + tcx.impl_trait_ref(item.container_id(tcx)).unwrap().instantiate_identity().args; + Some(tcx.type_of(trait_item).instantiate(tcx, args)) + } else { + Some(fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + })) + } + } else if let Node::AnonConst(_) = node { + let id = tcx.local_def_id_to_hir_id(def_id); + match tcx.parent_hir_node(id) { + Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), span, .. }) + if anon_const.hir_id == id => + { + Some(fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + })) + } + Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. }) + | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => { + asm.operands.iter().find_map(|(op, _op_sp)| match op { + hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => { + // Inline assembly constants must be integers. + Some(fcx.next_int_var()) + } + hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => { + Some(fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + })) + } + _ => None, + }) + } + _ => None, + } + } else { + None + }; + expected_type +} + /// When `check_fn` is invoked on a coroutine (i.e., a body that /// includes yield), it returns back some information about the yield /// points. diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index e9752d7a4a8..39d54f1a25e 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -81,7 +81,7 @@ pub struct NoMatchData<'tcx> { // A pared down enum describing just the places from which a method // candidate can arise. Used for error reporting only. -#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum CandidateSource { Impl(DefId), Trait(DefId /* trait id */), diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0dcde0cdecb..12f522d1adc 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -49,7 +49,6 @@ use std::borrow::Cow; use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope}; use super::{CandidateSource, MethodError, NoMatchData}; use rustc_hir::intravisit::Visitor; -use std::cmp::{self, Ordering}; use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -1186,7 +1185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect::<Vec<_>>(); if !inherent_impls_candidate.is_empty() { - inherent_impls_candidate.sort(); + inherent_impls_candidate.sort_by_key(|id| self.tcx.def_path_str(id)); inherent_impls_candidate.dedup(); // number of types to show at most @@ -1567,7 +1566,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sources: &mut Vec<CandidateSource>, sugg_span: Option<Span>, ) { - sources.sort(); + sources.sort_by_key(|source| match source { + CandidateSource::Trait(id) => (0, self.tcx.def_path_str(id)), + CandidateSource::Impl(id) => (1, self.tcx.def_path_str(id)), + }); sources.dedup(); // Dynamic limit to avoid hiding just one candidate, which is silly. let limit = if sources.len() == 5 { 5 } else { 4 }; @@ -2549,7 +2551,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }) .collect(); - preds.sort_by_key(|pred| (pred.def_id(), pred.self_ty())); + preds.sort_by_key(|pred| pred.trait_ref.to_string()); let def_ids = preds .iter() .filter_map(|pred| match pred.self_ty().kind() { @@ -2663,7 +2665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { traits.push(trait_pred.def_id()); } } - traits.sort(); + traits.sort_by_key(|id| self.tcx.def_path_str(id)); traits.dedup(); let len = traits.len(); @@ -2886,7 +2888,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> bool { if !valid_out_of_scope_traits.is_empty() { let mut candidates = valid_out_of_scope_traits; - candidates.sort(); + candidates.sort_by_key(|id| self.tcx.def_path_str(id)); candidates.dedup(); // `TryFrom` and `FromIterator` have no methods @@ -3212,8 +3214,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if !candidates.is_empty() { - // Sort from most relevant to least relevant. - candidates.sort_by_key(|&info| cmp::Reverse(info)); + // Sort local crate results before others + candidates + .sort_by_key(|&info| (!info.def_id.is_local(), self.tcx.def_path_str(info.def_id))); candidates.dedup(); let param_type = match rcvr_ty.kind() { @@ -3561,33 +3564,11 @@ pub enum SelfSource<'a> { MethodCall(&'a hir::Expr<'a> /* rcvr */), } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq, Eq)] pub struct TraitInfo { pub def_id: DefId, } -impl PartialEq for TraitInfo { - fn eq(&self, other: &TraitInfo) -> bool { - self.cmp(other) == Ordering::Equal - } -} -impl Eq for TraitInfo {} -impl PartialOrd for TraitInfo { - fn partial_cmp(&self, other: &TraitInfo) -> Option<Ordering> { - Some(self.cmp(other)) - } -} -impl Ord for TraitInfo { - fn cmp(&self, other: &TraitInfo) -> Ordering { - // Local crates are more important than remote ones (local: - // `cnum == 0`), and otherwise we throw in the defid for totality. - - let lhs = (other.def_id.krate, other.def_id); - let rhs = (self.def_id.krate, self.def_id); - lhs.cmp(&rhs) - } -} - /// Retrieves all traits in this crate and any dependent crates, /// and wraps them into `TraitInfo` for custom sorting. pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 4dc60f7c6da..861a00ce874 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -388,8 +388,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !pat_adjustments.is_empty() { debug!("default binding mode is now {:?}", def_bm); - self.inh - .typeck_results + self.typeck_results .borrow_mut() .pat_adjustments_mut() .insert(pat.hir_id, pat_adjustments); @@ -614,7 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => BindingMode::convert(ba), }; // ...and store it in a side table: - self.inh.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm); + self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm); debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); @@ -2002,8 +2001,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { let tcx = self.tcx; - // FIXME(deref_patterns): use `DerefPure` for soundness - // FIXME(deref_patterns): use `DerefMut` when required + // Register a `DerefPure` bound, which is required by all `deref!()` pats. + self.register_bound( + expected, + tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)), + self.misc(span), + ); // <expected as Deref>::Target let ty = Ty::new_projection( tcx, @@ -2013,6 +2016,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.normalize(span, ty); let ty = self.try_structurally_resolve_type(span, ty); self.check_pat(inner, ty, pat_info); + + // Check if the pattern has any `ref mut` bindings, which would require + // `DerefMut` to be emitted in MIR building instead of just `Deref`. + // We do this *after* checking the inner pattern, since we want to make + // sure to apply any match-ergonomics adjustments. + if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) { + self.register_bound( + expected, + tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)), + self.misc(span), + ); + } + expected } diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index b0950ed2800..e493e6a0a7e 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -16,7 +16,8 @@ use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, Trai use std::cell::RefCell; use std::ops::Deref; -/// Closures defined within the function. For example: +// Data shared between a "typeck root" and its nested bodies, +/// e.g. closures defined within the function. For example: /// ```ignore (illustrative) /// fn foo() { /// bar(move|| { ... }) @@ -24,8 +25,9 @@ use std::ops::Deref; /// ``` /// Here, the function `foo()` and the closure passed to /// `bar()` will each have their own `FnCtxt`, but they will -/// share the inherited fields. -pub struct Inherited<'tcx> { +/// share the inference context, will process obligations together, +/// can access each other's local types (scoping permitted), etc. +pub struct TypeckRootCtxt<'tcx> { pub(super) infcx: InferCtxt<'tcx>, pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>, @@ -65,14 +67,14 @@ pub struct Inherited<'tcx> { pub(super) infer_var_info: RefCell<UnordMap<ty::TyVid, ty::InferVarInfo>>, } -impl<'tcx> Deref for Inherited<'tcx> { +impl<'tcx> Deref for TypeckRootCtxt<'tcx> { type Target = InferCtxt<'tcx>; fn deref(&self) -> &Self::Target { &self.infcx } } -impl<'tcx> Inherited<'tcx> { +impl<'tcx> TypeckRootCtxt<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; @@ -83,7 +85,7 @@ impl<'tcx> Inherited<'tcx> { .build(); let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); - Inherited { + TypeckRootCtxt { typeck_results, fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(&infcx)), infcx, diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 521c65c6009..fdb6ab8f59b 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -270,9 +270,6 @@ infer_ril_introduced_by = requirement introduced by this return type infer_ril_introduced_here = `'static` requirement introduced here infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type -infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions - -infer_sbfrit_change_return_type = you could change the return type to be a boxed trait object infer_source_kind_closure_return = try giving this closure an explicit return type diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index d0b1f2848ff..6192eaf3c3a 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1263,24 +1263,6 @@ pub enum SuggestAccessingField<'a> { } #[derive(Subdiagnostic)] -pub enum SuggestBoxingForReturnImplTrait { - #[multipart_suggestion(infer_sbfrit_change_return_type, applicability = "maybe-incorrect")] - ChangeReturnType { - #[suggestion_part(code = "Box<dyn")] - start_sp: Span, - #[suggestion_part(code = ">")] - end_sp: Span, - }, - #[multipart_suggestion(infer_sbfrit_box_return_expr, applicability = "maybe-incorrect")] - BoxReturnExpr { - #[suggestion_part(code = "Box::new(")] - starts: Vec<Span>, - #[suggestion_part(code = ")")] - ends: Vec<Span>, - }, -} - -#[derive(Subdiagnostic)] #[multipart_suggestion(infer_stp_wrap_one, applicability = "maybe-incorrect")] pub struct SuggestTuplePatternOne { pub variant: String, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 82634f7308d..0911e4f5063 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -784,7 +784,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { prior_arm_ty, source, ref prior_non_diverging_arms, - opt_suggest_box_span, scrut_span, .. }) => match source { @@ -853,17 +852,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) { err.subdiagnostic(self.dcx(), subdiag); } - if let Some(ret_sp) = opt_suggest_box_span { - // Get return type span and point to it. - self.suggest_boxing_for_return_impl_trait( - err, - ret_sp, - prior_non_diverging_arms - .iter() - .chain(std::iter::once(&arm_span)) - .copied(), - ); - } } }, ObligationCauseCode::IfExpression(box IfExpressionCause { @@ -872,7 +860,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { then_ty, else_ty, outer_span, - opt_suggest_box_span, + .. }) => { let then_span = self.find_block_span_from_hir_id(then_id); let else_span = self.find_block_span_from_hir_id(else_id); @@ -890,30 +878,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) { err.subdiagnostic(self.dcx(), subdiag); } - // don't suggest wrapping either blocks in `if .. {} else {}` - let is_empty_arm = |id| { - let hir::Node::Block(blk) = self.tcx.hir_node(id) else { - return false; - }; - if blk.expr.is_some() || !blk.stmts.is_empty() { - return false; - } - let Some((_, hir::Node::Expr(expr))) = self.tcx.hir().parent_iter(id).nth(1) - else { - return false; - }; - matches!(expr.kind, hir::ExprKind::If(..)) - }; - if let Some(ret_sp) = opt_suggest_box_span - && !is_empty_arm(then_id) - && !is_empty_arm(else_id) - { - self.suggest_boxing_for_return_impl_trait( - err, - ret_sp, - [then_span, else_span].into_iter(), - ); - } } ObligationCauseCode::LetElse => { err.help("try adding a diverging expression, such as `return` or `panic!(..)`"); @@ -1074,7 +1038,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS) .name_all_regions(sig) .unwrap(); - let lts: Vec<String> = reg.into_values().map(|kind| kind.to_string()).collect(); + let lts: Vec<String> = + reg.into_items().map(|(_, kind)| kind.to_string()).into_sorted_stable_ord(); (if lts.is_empty() { String::new() } else { format!("for<{}> ", lts.join(", ")) }, sig) }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index e220c4d02a2..9a05fb1c30f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -19,9 +19,8 @@ use rustc_span::{sym, BytePos, Span}; use crate::errors::{ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, - FunctionPointerSuggestion, SuggestAccessingField, SuggestBoxingForReturnImplTrait, - SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, SuggestTuplePatternOne, - TypeErrorAdditionalDiags, + FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding, + SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags, }; use super::TypeErrCtxt; @@ -80,28 +79,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - pub(super) fn suggest_boxing_for_return_impl_trait( - &self, - err: &mut Diag<'_>, - return_sp: Span, - arm_spans: impl Iterator<Item = Span>, - ) { - let sugg = SuggestBoxingForReturnImplTrait::ChangeReturnType { - start_sp: return_sp.with_hi(return_sp.lo() + BytePos(4)), - end_sp: return_sp.shrink_to_hi(), - }; - err.subdiagnostic(self.dcx(), sugg); - - let mut starts = Vec::new(); - let mut ends = Vec::new(); - for span in arm_spans { - starts.push(span.shrink_to_lo()); - ends.push(span.shrink_to_hi()); - } - let sugg = SuggestBoxingForReturnImplTrait::BoxReturnExpr { starts, ends }; - err.subdiagnostic(self.dcx(), sugg); - } - pub(super) fn suggest_tuple_pattern( &self, cause: &ObligationCause<'tcx>, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index a3ff655b609..339c8ac10b3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -229,6 +229,15 @@ impl<'tcx> InferCtxtInner<'tcx> { .expect("region constraints already solved") .with_log(&mut self.undo_log) } + + // Iterates through the opaque type definitions without taking them; this holds the + // `InferCtxtInner` lock, so make sure to not do anything with `InferCtxt` side-effects + // while looping through this. + pub fn iter_opaque_types( + &self, + ) -> impl Iterator<Item = (ty::OpaqueTypeKey<'tcx>, ty::OpaqueHiddenType<'tcx>)> + '_ { + self.opaque_type_storage.opaque_types.iter().map(|(&k, v)| (k, v.hidden_type)) + } } pub struct InferCtxt<'tcx> { diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 02b8ded285f..01430e830e5 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -73,7 +73,7 @@ impl<'tcx> InferCtxt<'tcx> { // for opaque types, and then use that kind to fix the spans for type errors // that we see later on. let ty_var = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::OpaqueTypeInference(def_id), + kind: TypeVariableOriginKind::MiscVariable, span, }); obligations.extend( diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 3630b0f439f..55c6c92a584 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -47,7 +47,6 @@ pub enum TypeVariableOriginKind { MiscVariable, NormalizeProjectionType, TypeInference, - OpaqueTypeInference(DefId), TypeParameterDefinition(Symbol, DefId), /// One of the upvars or closure kind parameters in a `ClosureArgs` diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 656c7ffae19..da2fb490a36 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -10,7 +10,9 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::registry::Registry; use rustc_errors::{DiagCtxt, ErrorGuaranteed}; use rustc_lint::LintStore; + use rustc_middle::ty; +use rustc_middle::ty::CurrentGcx; use rustc_middle::util::Providers; use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; @@ -39,6 +41,7 @@ pub struct Compiler { pub sess: Session, pub codegen_backend: Box<dyn CodegenBackend>, pub(crate) override_queries: Option<fn(&Session, &mut Providers)>, + pub(crate) current_gcx: CurrentGcx, } /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. @@ -336,7 +339,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se util::run_in_thread_pool_with_globals( config.opts.edition, config.opts.unstable_opts.threads, - || { + |current_gcx| { crate::callbacks::setup_callbacks(); let early_dcx = EarlyDiagCtxt::new(config.opts.error_format); @@ -430,8 +433,12 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se } sess.lint_store = Some(Lrc::new(lint_store)); - let compiler = - Compiler { sess, codegen_backend, override_queries: config.override_queries }; + let compiler = Compiler { + sess, + codegen_backend, + override_queries: config.override_queries, + current_gcx, + }; rustc_span::set_source_map(compiler.sess.psess.clone_source_map(), move || { // There are two paths out of `f`. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 4b4c1d6cf67..d763a12f816 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -680,6 +680,7 @@ pub fn create_global_ctxt<'tcx>( incremental, ), providers.hooks, + compiler.current_gcx.clone(), ) }) }) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8a27e9a6453..3b78e6a43ab 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -315,30 +315,39 @@ fn test_search_paths_tracking_hash_different_order() { json_rendered: HumanReadableErrorType::Default(ColorConfig::Never), }; + let push = |opts: &mut Options, search_path| { + opts.search_paths.push(SearchPath::from_cli_opt( + "not-a-sysroot".as_ref(), + &opts.target_triple, + &early_dcx, + search_path, + )); + }; + // Reference - v1.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "native=abc")); - v1.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "crate=def")); - v1.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "dependency=ghi")); - v1.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "framework=jkl")); - v1.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "all=mno")); - - v2.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "native=abc")); - v2.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "dependency=ghi")); - v2.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "crate=def")); - v2.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "framework=jkl")); - v2.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "all=mno")); - - v3.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "crate=def")); - v3.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "framework=jkl")); - v3.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "native=abc")); - v3.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "dependency=ghi")); - v3.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "all=mno")); - - v4.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "all=mno")); - v4.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "native=abc")); - v4.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "crate=def")); - v4.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "dependency=ghi")); - v4.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "framework=jkl")); + push(&mut v1, "native=abc"); + push(&mut v1, "crate=def"); + push(&mut v1, "dependency=ghi"); + push(&mut v1, "framework=jkl"); + push(&mut v1, "all=mno"); + + push(&mut v2, "native=abc"); + push(&mut v2, "dependency=ghi"); + push(&mut v2, "crate=def"); + push(&mut v2, "framework=jkl"); + push(&mut v2, "all=mno"); + + push(&mut v3, "crate=def"); + push(&mut v3, "framework=jkl"); + push(&mut v3, "native=abc"); + push(&mut v3, "dependency=ghi"); + push(&mut v3, "all=mno"); + + push(&mut v4, "all=mno"); + push(&mut v4, "native=abc"); + push(&mut v4, "crate=def"); + push(&mut v4, "dependency=ghi"); + push(&mut v4, "framework=jkl"); assert_same_hash(&v1, &v2); assert_same_hash(&v1, &v3); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index d09f8d7d7cf..d0f04fccc48 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -5,6 +5,7 @@ use rustc_codegen_ssa::traits::CodegenBackend; #[cfg(parallel_compiler)] use rustc_data_structures::sync; use rustc_metadata::{load_symbol_from_dylib, DylibError}; +use rustc_middle::ty::CurrentGcx; use rustc_parse::validate_attr; use rustc_session as session; use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes}; @@ -64,7 +65,7 @@ fn init_stack_size() -> usize { }) } -pub(crate) fn run_in_thread_with_globals<F: FnOnce() -> R + Send, R: Send>( +pub(crate) fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>( edition: Edition, f: F, ) -> R { @@ -82,7 +83,9 @@ pub(crate) fn run_in_thread_with_globals<F: FnOnce() -> R + Send, R: Send>( // `unwrap` is ok here because `spawn_scoped` only panics if the thread // name contains null bytes. let r = builder - .spawn_scoped(s, move || rustc_span::create_session_globals_then(edition, f)) + .spawn_scoped(s, move || { + rustc_span::create_session_globals_then(edition, || f(CurrentGcx::new())) + }) .unwrap() .join(); @@ -94,7 +97,7 @@ pub(crate) fn run_in_thread_with_globals<F: FnOnce() -> R + Send, R: Send>( } #[cfg(not(parallel_compiler))] -pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( +pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>( edition: Edition, _threads: usize, f: F, @@ -103,7 +106,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( } #[cfg(parallel_compiler)] -pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( +pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>( edition: Edition, threads: usize, f: F, @@ -117,24 +120,34 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap()); if !sync::is_dyn_thread_safe() { - return run_in_thread_with_globals(edition, || { + return run_in_thread_with_globals(edition, |current_gcx| { // Register the thread for use with the `WorkerLocal` type. registry.register(); - f() + f(current_gcx) }); } + let current_gcx = FromDyn::from(CurrentGcx::new()); + let current_gcx2 = current_gcx.clone(); + let builder = rayon::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) .acquire_thread_handler(jobserver::acquire_thread) .release_thread_handler(jobserver::release_thread) .num_threads(threads) - .deadlock_handler(|| { + .deadlock_handler(move || { // On deadlock, creates a new thread and forwards information in thread // locals to it. The new thread runs the deadlock handler. - let query_map = - FromDyn::from(tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs())); + + // Get a `GlobalCtxt` reference from `CurrentGcx` as we cannot rely on having a + // `TyCtxt` TLS reference here. + let query_map = current_gcx2.access(|gcx| { + tls::enter_context(&tls::ImplicitCtxt::new(gcx), || { + tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs()) + }) + }); + let query_map = FromDyn::from(query_map); let registry = rayon_core::Registry::current(); thread::Builder::new() .name("rustc query cycle handler".to_string()) @@ -171,7 +184,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( }) }, // Run `f` on the first thread in the thread pool. - move |pool: &rayon::ThreadPool| pool.install(f), + move |pool: &rayon::ThreadPool| pool.install(|| f(current_gcx.into_inner())), ) .unwrap() }) diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 0b757f95a99..111a4fdcea1 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -865,7 +865,9 @@ trait UnusedDelimLint { (iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true) } - Match(ref head, ..) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { + Match(ref head, _, ast::MatchKind::Prefix) + if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => + { let left = e.span.lo() + rustc_span::BytePos(5); (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true) } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index f6ec410bfac..8ec1f5a99e7 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1992,7 +1992,11 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler( } } if (DiagnosticHandlerCallback) { +#if LLVM_VERSION_GE(19, 0) + DiagnosticHandlerCallback(&DI, DiagnosticHandlerContext); +#else DiagnosticHandlerCallback(DI, DiagnosticHandlerContext); +#endif return true; } return false; 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/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e4dce2bdc9e..02af55fbf0e 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -652,8 +652,9 @@ impl<'tcx> Body<'tcx> { self.coroutine.as_ref().and_then(|coroutine| coroutine.resume_ty) } + /// Prefer going through [`TyCtxt::coroutine_layout`] rather than using this directly. #[inline] - pub fn coroutine_layout(&self) -> Option<&CoroutineLayout<'tcx>> { + pub fn coroutine_layout_raw(&self) -> Option<&CoroutineLayout<'tcx>> { self.coroutine.as_ref().and_then(|coroutine| coroutine.coroutine_layout.as_ref()) } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f0499cf344f..41df2e3b587 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -126,7 +126,7 @@ fn dump_matched_mir_node<'tcx, F>( Some(promoted) => write!(file, "::{promoted:?}`")?, } writeln!(file, " {disambiguator} {pass_name}")?; - if let Some(ref layout) = body.coroutine_layout() { + if let Some(ref layout) = body.coroutine_layout_raw() { writeln!(file, "/* coroutine_layout = {layout:#?} */")?; } writeln!(file)?; diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 3b1d1a04d6f..9cbc4d10146 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -9,8 +9,7 @@ use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{GenericArg, GenericArgsRef}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, ModDefId, LOCAL_CRATE}; use rustc_hir::hir_id::{HirId, OwnerId}; -use rustc_query_system::query::DefIdCacheSelector; -use rustc_query_system::query::{DefaultCacheSelector, SingleCacheSelector, VecCacheSelector}; +use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi; @@ -22,7 +21,7 @@ pub struct LocalCrate; /// The `Key` trait controls what types can legally be used as the key /// for a query. pub trait Key: Sized { - // N.B. Most of the keys down below have `type CacheSelector = DefaultCacheSelector<Self>;`, + // N.B. Most of the keys down below have `type Cache<V> = DefaultCache<Self, V>;`, // it would be reasonable to use associated type defaults, to remove the duplication... // // ...But r-a doesn't support them yet and using a default here causes r-a to not infer @@ -30,7 +29,7 @@ pub trait Key: Sized { // type defaults, please restrain from using them here <3 // // r-a issue: <https://github.com/rust-lang/rust-analyzer/issues/13693> - type CacheSelector; + type Cache<V>; /// In the event that a cycle occurs, if no explicit span has been /// given for a query with key `self`, what span should we use? @@ -56,7 +55,7 @@ pub trait AsLocalKey: Key { } impl Key for () { - type CacheSelector = SingleCacheSelector; + type Cache<V> = SingleCache<V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -64,7 +63,7 @@ impl Key for () { } impl<'tcx> Key for ty::InstanceDef<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) @@ -81,7 +80,7 @@ impl<'tcx> AsLocalKey for ty::InstanceDef<'tcx> { } impl<'tcx> Key for ty::Instance<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) @@ -89,7 +88,7 @@ impl<'tcx> Key for ty::Instance<'tcx> { } impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.instance.default_span(tcx) @@ -97,7 +96,7 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { } impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -105,7 +104,7 @@ impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) { } impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -113,7 +112,7 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { } impl Key for CrateNum { - type CacheSelector = VecCacheSelector<Self>; + type Cache<V> = VecCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -130,7 +129,7 @@ impl AsLocalKey for CrateNum { } impl Key for OwnerId { - type CacheSelector = VecCacheSelector<Self>; + type Cache<V> = VecCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) @@ -142,7 +141,7 @@ impl Key for OwnerId { } impl Key for LocalDefId { - type CacheSelector = VecCacheSelector<Self>; + type Cache<V> = VecCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.to_def_id().default_span(tcx) @@ -154,7 +153,7 @@ impl Key for LocalDefId { } impl Key for DefId { - type CacheSelector = DefIdCacheSelector; + type Cache<V> = DefIdCache<V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(*self) @@ -176,7 +175,7 @@ impl AsLocalKey for DefId { } impl Key for LocalModDefId { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(*self) @@ -189,7 +188,7 @@ impl Key for LocalModDefId { } impl Key for ModDefId { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(*self) @@ -211,7 +210,7 @@ impl AsLocalKey for ModDefId { } impl Key for SimplifiedType { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -219,7 +218,7 @@ impl Key for SimplifiedType { } impl Key for (DefId, DefId) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) @@ -227,7 +226,7 @@ impl Key for (DefId, DefId) { } impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -235,7 +234,7 @@ impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) { } impl Key for (DefId, LocalDefId) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) @@ -243,7 +242,7 @@ impl Key for (DefId, LocalDefId) { } impl Key for (LocalDefId, DefId) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -251,7 +250,7 @@ impl Key for (LocalDefId, DefId) { } impl Key for (LocalDefId, LocalDefId) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -259,7 +258,7 @@ impl Key for (LocalDefId, LocalDefId) { } impl Key for (DefId, Ident) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0) @@ -272,7 +271,7 @@ impl Key for (DefId, Ident) { } impl Key for (LocalDefId, LocalDefId, Ident) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) @@ -280,7 +279,7 @@ impl Key for (LocalDefId, LocalDefId, Ident) { } impl Key for (CrateNum, DefId) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.1.default_span(tcx) @@ -297,7 +296,7 @@ impl AsLocalKey for (CrateNum, DefId) { } impl Key for (CrateNum, SimplifiedType) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -314,7 +313,7 @@ impl AsLocalKey for (CrateNum, SimplifiedType) { } impl Key for (DefId, SimplifiedType) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -322,7 +321,7 @@ impl Key for (DefId, SimplifiedType) { } impl<'tcx> Key for GenericArgsRef<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -330,7 +329,7 @@ impl<'tcx> Key for GenericArgsRef<'tcx> { } impl<'tcx> Key for (DefId, GenericArgsRef<'tcx>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -338,7 +337,7 @@ impl<'tcx> Key for (DefId, GenericArgsRef<'tcx>) { } impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { (self.0).def.default_span(tcx) @@ -346,7 +345,7 @@ impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) { } impl<'tcx> Key for (LocalDefId, DefId, GenericArgsRef<'tcx>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -354,7 +353,7 @@ impl<'tcx> Key for (LocalDefId, DefId, GenericArgsRef<'tcx>) { } impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.1.def_id) @@ -362,7 +361,7 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) { } impl<'tcx> Key for ty::PolyTraitRef<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) @@ -370,7 +369,7 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> { } impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.def_id()) @@ -378,7 +377,7 @@ impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> { } impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.def_span(self.0.def_id()) @@ -386,7 +385,7 @@ impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) { } impl<'tcx> Key for GenericArg<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -394,7 +393,7 @@ impl<'tcx> Key for GenericArg<'tcx> { } impl<'tcx> Key for ty::Const<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -402,7 +401,7 @@ impl<'tcx> Key for ty::Const<'tcx> { } impl<'tcx> Key for Ty<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -418,7 +417,7 @@ impl<'tcx> Key for Ty<'tcx> { } impl<'tcx> Key for TyAndLayout<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -426,7 +425,7 @@ impl<'tcx> Key for TyAndLayout<'tcx> { } impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -434,7 +433,7 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { } impl<'tcx> Key for &'tcx ty::List<ty::Clause<'tcx>> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -442,7 +441,7 @@ impl<'tcx> Key for &'tcx ty::List<ty::Clause<'tcx>> { } impl<'tcx> Key for ty::ParamEnv<'tcx> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -450,7 +449,7 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> { } impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.value.default_span(tcx) @@ -462,7 +461,7 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { } impl Key for Symbol { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -470,7 +469,7 @@ impl Key for Symbol { } impl Key for Option<Symbol> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -480,7 +479,7 @@ impl Key for Option<Symbol> { /// Canonical query goals correspond to abstract trait operations that /// are not tied to any crate in particular. impl<'tcx, T: Clone> Key for Canonical<'tcx, T> { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -488,7 +487,7 @@ impl<'tcx, T: Clone> Key for Canonical<'tcx, T> { } impl Key for (Symbol, u32, u32) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -496,7 +495,7 @@ impl Key for (Symbol, u32, u32) { } impl<'tcx> Key for (DefId, Ty<'tcx>, GenericArgsRef<'tcx>, ty::ParamEnv<'tcx>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -504,7 +503,7 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, GenericArgsRef<'tcx>, ty::ParamEnv<'tcx>) { } impl<'tcx> Key for (Ty<'tcx>, abi::VariantIdx) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -512,7 +511,7 @@ impl<'tcx> Key for (Ty<'tcx>, abi::VariantIdx) { } impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP @@ -520,7 +519,7 @@ impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) { } impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -528,7 +527,7 @@ impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) { } impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { self.0.default_span(tcx) @@ -536,7 +535,7 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) { } impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { DUMMY_SP @@ -544,7 +543,7 @@ impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { } impl Key for HirId { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.hir().span(*self) @@ -557,7 +556,7 @@ impl Key for HirId { } impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { - type CacheSelector = DefaultCacheSelector<Self>; + type Cache<V> = DefaultCache<Self, V>; // Just forward to `Ty<'tcx>` diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 38cfd11a016..5e4454db3e2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -73,7 +73,7 @@ use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate}; use rustc_index::IndexVec; use rustc_query_system::ich::StableHashingContext; -use rustc_query_system::query::{try_get_cached, CacheSelector, QueryCache, QueryMode, QueryState}; +use rustc_query_system::query::{try_get_cached, QueryCache, QueryMode, QueryState}; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::cstore::{CrateDepKind, CrateSource}; use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 8d88488e167..e3588a7afdc 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -336,9 +336,7 @@ macro_rules! define_callbacks { )) } - pub type Storage<'tcx> = < - <$($K)* as keys::Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>> - >::Cache; + pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>; // Ensure that keys grow no larger than 64 bytes #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index f684f83a261..b1162a34cda 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1018,7 +1018,7 @@ impl<'tcx> PatRangeBoundary<'tcx> { (Finite(mir::Const::Ty(a)), Finite(mir::Const::Ty(b))) if matches!(ty.kind(), ty::Uint(_) | ty::Char) => { - return Some(a.kind().cmp(&b.kind())); + return Some(a.to_valtree().cmp(&b.to_valtree())); } ( Finite(mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _)), diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index a04bd636622..efea2a66bb2 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -571,7 +571,8 @@ pub struct MatchExpressionArmCause<'tcx> { pub scrut_span: Span, pub source: hir::MatchSource, pub prior_non_diverging_arms: Vec<Span>, - pub opt_suggest_box_span: Option<Span>, + // Is the expectation of this match expression an RPIT? + pub tail_defines_return_position_impl_trait: Option<LocalDefId>, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -582,7 +583,8 @@ pub struct IfExpressionCause<'tcx> { pub then_ty: Ty<'tcx>, pub else_ty: Ty<'tcx>, pub outer_span: Option<Span>, - pub opt_suggest_box_span: Option<Span>, + // Is the expectation of this match expression an RPIT? + pub tail_defines_return_position_impl_trait: Option<LocalDefId>, } #[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index a7144316769..a7f1ba46b61 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -18,7 +18,6 @@ use rustc_span::symbol::sym; use rustc_target::abi::{ReprOptions, VariantIdx, FIRST_VARIANT}; use std::cell::RefCell; -use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use std::ops::Range; use std::str; @@ -102,20 +101,6 @@ pub struct AdtDefData { repr: ReprOptions, } -impl PartialOrd for AdtDefData { - fn partial_cmp(&self, other: &AdtDefData) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -/// There should be only one AdtDef for each `did`, therefore -/// it is fine to implement `Ord` only based on `did`. -impl Ord for AdtDefData { - fn cmp(&self, other: &AdtDefData) -> Ordering { - self.did.cmp(&other.did) - } -} - impl PartialEq for AdtDefData { #[inline] fn eq(&self, other: &Self) -> bool { @@ -180,7 +165,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for AdtDefData { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] pub struct AdtDef<'tcx>(pub Interned<'tcx, AdtDefData>); diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 0d621cd1cfd..3713883eb00 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -23,7 +23,7 @@ pub use valtree::*; pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>; /// Use this rather than `ConstData`, whenever possible. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>); @@ -52,7 +52,7 @@ impl<'tcx> ConstTy<TyCtxt<'tcx>> for Const<'tcx> { } /// Typed constant value. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable)] pub struct ConstData<'tcx> { pub ty: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 705987d92fe..ea02faca5f3 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::HashStable; /// An unevaluated (potentially generic) constant used in the type-system. -#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable)] #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct UnevaluatedConst<'tcx> { pub def: DefId, @@ -62,7 +62,7 @@ impl<'tcx> UnevaluatedConst<'tcx> { } } -#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] pub enum Expr<'tcx> { Binop(mir::BinOp, Const<'tcx>, Const<'tcx>), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3393f444843..188cb50849d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -32,6 +32,7 @@ use crate::ty::{ }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; +use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::intern::Interned; @@ -39,7 +40,7 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, WorkerLocal}; +use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, RwLock, WorkerLocal}; #[cfg(parallel_compiler)] use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordSet; @@ -723,6 +724,8 @@ pub struct GlobalCtxt<'tcx> { /// Stores memory for globals (statics/consts). pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>, + + current_gcx: CurrentGcx, } impl<'tcx> GlobalCtxt<'tcx> { @@ -733,6 +736,19 @@ impl<'tcx> GlobalCtxt<'tcx> { F: FnOnce(TyCtxt<'tcx>) -> R, { let icx = tls::ImplicitCtxt::new(self); + + // Reset `current_gcx` to `None` when we exit. + let _on_drop = defer(move || { + *self.current_gcx.value.write() = None; + }); + + // Set this `GlobalCtxt` as the current one. + { + let mut guard = self.current_gcx.value.write(); + assert!(guard.is_none(), "no `GlobalCtxt` is currently set"); + *guard = Some(self as *const _ as *const ()); + } + tls::enter_context(&icx, || f(icx.tcx)) } @@ -741,6 +757,39 @@ impl<'tcx> GlobalCtxt<'tcx> { } } +/// This is used to get a reference to a `GlobalCtxt` if one is available. +/// +/// This is needed to allow the deadlock handler access to `GlobalCtxt` to look for query cycles. +/// It cannot use the `TLV` global because that's only guaranteed to be defined on the thread +/// creating the `GlobalCtxt`. Other threads have access to the `TLV` only inside Rayon jobs, but +/// the deadlock handler is not called inside such a job. +#[derive(Clone)] +pub struct CurrentGcx { + /// This stores a pointer to a `GlobalCtxt`. This is set to `Some` inside `GlobalCtxt::enter` + /// and reset to `None` when that function returns or unwinds. + value: Lrc<RwLock<Option<*const ()>>>, +} + +#[cfg(parallel_compiler)] +unsafe impl DynSend for CurrentGcx {} +#[cfg(parallel_compiler)] +unsafe impl DynSync for CurrentGcx {} + +impl CurrentGcx { + pub fn new() -> Self { + Self { value: Lrc::new(RwLock::new(None)) } + } + + pub fn access<R>(&self, f: impl for<'tcx> FnOnce(&'tcx GlobalCtxt<'tcx>) -> R) -> R { + let read_guard = self.value.read(); + let gcx: *const GlobalCtxt<'_> = read_guard.unwrap() as *const _; + // SAFETY: We hold the read lock for the `GlobalCtxt` pointer. That prevents + // `GlobalCtxt::enter` from returning as it would first acquire the write lock. + // This ensures the `GlobalCtxt` is live during `f`. + f(unsafe { &*gcx }) + } +} + impl<'tcx> TyCtxt<'tcx> { /// Expects a body and returns its codegen attributes. /// @@ -859,6 +908,7 @@ impl<'tcx> TyCtxt<'tcx> { query_kinds: &'tcx [DepKindStruct<'tcx>], query_system: QuerySystem<'tcx>, hooks: crate::hooks::Providers, + current_gcx: CurrentGcx, ) -> GlobalCtxt<'tcx> { let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| { s.dcx().emit_fatal(err); @@ -893,6 +943,7 @@ impl<'tcx> TyCtxt<'tcx> { canonical_param_env_cache: Default::default(), data_layout, alloc_map: Lock::new(interpret::AllocMap::new()), + current_gcx, } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index b57d4f372a7..fd3bee16e26 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -2,8 +2,6 @@ use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitableExt}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; -use std::collections::BTreeMap; - pub use rustc_type_ir::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; /////////////////////////////////////////////////////////////////////////// @@ -254,12 +252,12 @@ impl<'tcx> TyCtxt<'tcx> { self, value: Binder<'tcx, T>, mut fld_r: F, - ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) + ) -> (T, FxIndexMap<ty::BoundRegion, ty::Region<'tcx>>) where F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>, T: TypeFoldable<TyCtxt<'tcx>>, { - let mut region_map = BTreeMap::new(); + let mut region_map = FxIndexMap::default(); let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br)); let value = self.instantiate_bound_regions_uncached(value, real_fld_r); (value, region_map) diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 02b58c035d4..19cef927faf 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -17,7 +17,6 @@ use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; use core::intrinsics; -use std::cmp::Ordering; use std::marker::PhantomData; use std::mem; use std::num::NonZero; @@ -68,7 +67,7 @@ const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; const CONST_TAG: usize = 0b10; -#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord, HashStable)] +#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, HashStable)] pub enum GenericArgKind<'tcx> { Lifetime(ty::Region<'tcx>), Type(Ty<'tcx>), @@ -100,18 +99,6 @@ impl<'tcx> GenericArgKind<'tcx> { } } -impl<'tcx> Ord for GenericArg<'tcx> { - fn cmp(&self, other: &GenericArg<'tcx>) -> Ordering { - self.unpack().cmp(&other.unpack()) - } -} - -impl<'tcx> PartialOrd for GenericArg<'tcx> { - fn partial_cmp(&self, other: &GenericArg<'tcx>) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - impl<'tcx> From<ty::Region<'tcx>> for GenericArg<'tcx> { #[inline] fn from(r: ty::Region<'tcx>) -> GenericArg<'tcx> { 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..66fee515ab2 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -60,6 +60,7 @@ pub use rustc_target::abi::{ReprFlags, ReprOptions}; pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx}; pub use vtable::*; +use std::assert_matches::assert_matches; use std::fmt::Debug; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; @@ -86,8 +87,8 @@ pub use self::consts::{ Const, ConstData, ConstInt, ConstKind, Expr, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ - tls, CtxtInterners, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, - TyCtxtFeed, + tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, + TyCtxt, TyCtxtFeed, }; pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams}; pub use self::list::List; @@ -214,7 +215,6 @@ pub struct ResolverAstLowering { pub next_node_id: ast::NodeId, pub node_id_to_def_id: NodeMap<LocalDefId>, - pub def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>, pub trait_map: NodeMap<Vec<hir::TraitCandidate>>, /// List functions and methods for which lifetime elision was successful. @@ -516,7 +516,7 @@ pub struct CReaderCacheKey { } /// Use this rather than `TyKind`, whenever possible. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_diagnostic_item = "Ty"] #[rustc_pass_by_value] pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>); @@ -701,7 +701,7 @@ const TAG_MASK: usize = 0b11; const TYPE_TAG: usize = 0b00; const CONST_TAG: usize = 0b01; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable)] pub enum TermKind<'tcx> { Ty(Ty<'tcx>), @@ -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 @@ -979,7 +1011,7 @@ impl PlaceholderLike for PlaceholderType { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] -#[derive(TyEncodable, TyDecodable, PartialOrd, Ord)] +#[derive(TyEncodable, TyDecodable)] pub struct BoundConst<'tcx> { pub var: BoundVar, pub ty: Ty<'tcx>, @@ -1826,8 +1858,40 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns layout of a coroutine. Layout might be unavailable if the /// coroutine is tainted by errors. - pub fn coroutine_layout(self, def_id: DefId) -> Option<&'tcx CoroutineLayout<'tcx>> { - self.optimized_mir(def_id).coroutine_layout() + /// + /// Takes `coroutine_kind` which can be acquired from the `CoroutineArgs::kind_ty`, + /// e.g. `args.as_coroutine().kind_ty()`. + pub fn coroutine_layout( + self, + def_id: DefId, + coroutine_kind_ty: Ty<'tcx>, + ) -> Option<&'tcx CoroutineLayout<'tcx>> { + let mir = self.optimized_mir(def_id); + // Regular coroutine + if coroutine_kind_ty.is_unit() { + mir.coroutine_layout_raw() + } else { + // If we have a `Coroutine` that comes from an coroutine-closure, + // then it may be a by-move or by-ref body. + let ty::Coroutine(_, identity_args) = + *self.type_of(def_id).instantiate_identity().kind() + else { + unreachable!(); + }; + let identity_kind_ty = identity_args.as_coroutine().kind_ty(); + // If the types differ, then we must be getting the by-move body of + // a by-ref coroutine. + if identity_kind_ty == coroutine_kind_ty { + mir.coroutine_layout_raw() + } else { + assert_matches!(coroutine_kind_ty.to_opt_closure_kind(), Some(ClosureKind::FnOnce)); + assert_matches!( + identity_kind_ty.to_opt_closure_kind(), + Some(ClosureKind::Fn | ClosureKind::FnMut) + ); + mir.coroutine_by_move_body().unwrap().coroutine_layout_raw() + } + } } /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements. diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index d3bc7dd22e7..05156dd5205 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -192,7 +192,7 @@ impl<'tcx> Clause<'tcx> { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum ExistentialPredicate<'tcx> { /// E.g., `Iterator`. @@ -336,7 +336,7 @@ impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> { /// /// Trait references also appear in object types like `Foo<U>`, but in /// that case the `Self` parameter is absent from the generic parameters. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct TraitRef<'tcx> { pub def_id: DefId, @@ -420,7 +420,7 @@ impl<'tcx> IntoDiagArg for TraitRef<'tcx> { /// ``` /// The generic parameters don't include the erased `Self`, only trait /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ExistentialTraitRef<'tcx> { pub def_id: DefId, @@ -476,7 +476,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { } /// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct ExistentialProjection<'tcx> { pub def_id: DefId, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 3f0a3a1a7bf..5ff98dc8c87 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -10,6 +10,7 @@ use crate::ty::{ use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; use rustc_hir::def_id::{DefIdMap, DefIdSet, ModDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -24,7 +25,6 @@ use rustc_target::spec::abi::Abi; use smallvec::SmallVec; use std::cell::Cell; -use std::collections::BTreeMap; use std::fmt::{self, Write as _}; use std::iter; use std::ops::{Deref, DerefMut}; @@ -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)); @@ -2529,7 +2537,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { struct RegionFolder<'a, 'tcx> { tcx: TyCtxt<'tcx>, current_index: ty::DebruijnIndex, - region_map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>>, + region_map: UnordMap<ty::BoundRegion, ty::Region<'tcx>>, name: &'a mut ( dyn FnMut( Option<ty::DebruijnIndex>, // Debruijn index of the folded late-bound region @@ -2606,7 +2614,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { pub fn name_all_regions<T>( &mut self, value: &ty::Binder<'tcx, T>, - ) -> Result<(T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>), fmt::Error> + ) -> Result<(T, UnordMap<ty::BoundRegion, ty::Region<'tcx>>), fmt::Error> where T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, { @@ -2683,7 +2691,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { write!(self, "{var:?}")?; } start_or_continue(self, "", "> "); - (value.clone().skip_binder(), BTreeMap::default()) + (value.clone().skip_binder(), UnordMap::default()) } else { let tcx = self.tcx; @@ -2755,7 +2763,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { tcx, current_index: ty::INNERMOST, name: &mut name, - region_map: BTreeMap::new(), + region_map: UnordMap::default(), }; let new_value = value.clone().skip_binder().fold_with(&mut folder); let region_map = folder.region_map; diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index c66b9864e46..867faf63261 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -14,7 +14,7 @@ use crate::ty::{self, BoundVar, TyCtxt, TypeFlags}; pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>; /// Use this rather than `RegionKind`, whenever possible. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); @@ -327,7 +327,7 @@ impl<'tcx> Deref for Region<'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct EarlyParamRegion { pub def_id: DefId, @@ -358,7 +358,7 @@ impl Atom for RegionVid { } } -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] +#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)] #[derive(HashStable)] /// The parameter representation of late-bound function parameters, "some region /// at least as big as the scope `fr.scope`". @@ -367,7 +367,7 @@ pub struct LateParamRegion { pub bound_region: BoundRegionKind, } -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, TyEncodable, TyDecodable, Copy)] +#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)] #[derive(HashStable)] pub enum BoundRegionKind { /// An anonymous region parameter for a given fn (&T) @@ -384,7 +384,7 @@ pub enum BoundRegionKind { BrEnv, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct BoundRegion { pub var: BoundVar, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c85ee140fa4..57a675e4453 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -694,7 +694,8 @@ impl<'tcx> CoroutineArgs<'tcx> { #[inline] pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> { // FIXME requires optimized MIR - FIRST_VARIANT..tcx.coroutine_layout(def_id).unwrap().variant_fields.next_index() + FIRST_VARIANT + ..tcx.coroutine_layout(def_id, tcx.types.unit).unwrap().variant_fields.next_index() } /// The discriminant for the given variant. Panics if the `variant_index` is @@ -754,7 +755,7 @@ impl<'tcx> CoroutineArgs<'tcx> { def_id: DefId, tcx: TyCtxt<'tcx>, ) -> impl Iterator<Item: Iterator<Item = Ty<'tcx>> + Captures<'tcx>> { - let layout = tcx.coroutine_layout(def_id).unwrap(); + let layout = tcx.coroutine_layout(def_id, self.kind_ty()).unwrap(); layout.variant_fields.iter().map(move |variant| { variant.iter().map(move |field| { ty::EarlyBinder::bind(layout.field_tys[*field].ty).instantiate(tcx, self.args) @@ -867,7 +868,7 @@ impl<'tcx> InlineConstArgs<'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum BoundVariableKind { Ty(BoundTyKind), @@ -907,7 +908,7 @@ impl BoundVariableKind { /// e.g., `liberate_late_bound_regions`). /// /// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(HashStable, Lift)] pub struct Binder<'tcx, T> { value: T, @@ -1108,7 +1109,7 @@ where /// * For a projection, this would be `<Ty as Trait<...>>::N<...>`. /// * For an inherent projection, this would be `Ty::N<...>`. /// * For an opaque type, there is no explicit syntax. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct AliasTy<'tcx> { /// The parameters of the associated or opaque item. @@ -1277,7 +1278,7 @@ pub struct GenSig<'tcx> { /// - `inputs`: is the list of arguments and their modes. /// - `output`: is the return type. /// - `c_variadic`: indicates whether this is a C-variadic function. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct FnSig<'tcx> { pub inputs_and_output: &'tcx List<Ty<'tcx>>, @@ -1402,14 +1403,14 @@ impl ParamConst { } } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct BoundTy { pub var: BoundVar, pub kind: BoundTyKind, } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable)] pub enum BoundTyKind { Anon, @@ -2660,7 +2661,7 @@ impl<'tcx> Ty<'tcx> { /// a miscompilation or unsoundness. /// /// When in doubt, use `VarianceDiagInfo::default()` -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum VarianceDiagInfo<'tcx> { /// No additional information - this is the default. /// We will not add any additional information to error messages. diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index d8541f4b25a..827b7e088ce 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -430,6 +430,31 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } + /// Does the pattern recursively contain a `ref mut` binding in it? + /// + /// This is used to determined whether a `deref` pattern should emit a `Deref` + /// or `DerefMut` call for its pattern scrutinee. + /// + /// This is computed from the typeck results since we want to make + /// sure to apply any match-ergonomics adjustments, which we cannot + /// determine from the HIR alone. + pub fn pat_has_ref_mut_binding(&self, pat: &'tcx hir::Pat<'tcx>) -> bool { + let mut has_ref_mut = false; + pat.walk(|pat| { + if let hir::PatKind::Binding(_, id, _, _) = pat.kind + && let Some(ty::BindByReference(ty::Mutability::Mut)) = + self.pat_binding_modes().get(id) + { + has_ref_mut = true; + // No need to continue recursing + false + } else { + true + } + }); + has_ref_mut + } + /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured /// by the closure. pub fn closure_min_captures_flattened( diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index f4f452d474f..6d083e66a9b 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1006,6 +1006,10 @@ struct Candidate<'pat, 'tcx> { /// If the candidate matches, bindings and ascriptions must be established. extra_data: PatternExtraData<'tcx>, + /// If we filled `self.subcandidate`, we store here the span of the or-pattern they came from. + // Invariant: it is `None` iff `subcandidates.is_empty()`. + or_span: Option<Span>, + /// The block before the `bindings` have been established. pre_binding_block: Option<BasicBlock>, /// The pre-binding block of the next candidate. @@ -1028,6 +1032,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { extra_data: flat_pat.extra_data, has_guard, subcandidates: Vec::new(), + or_span: None, otherwise_block: None, pre_binding_block: None, next_candidate_pre_binding_block: None, @@ -1106,7 +1111,10 @@ impl<'pat, 'tcx> TestCase<'pat, 'tcx> { #[derive(Debug, Clone)] pub(crate) struct MatchPair<'pat, 'tcx> { /// This place... - place: PlaceBuilder<'tcx>, + // This can be `None` if it referred to a non-captured place in a closure. + // Invariant: place.is_none() => test_case is Irrefutable + // In other words this must be `Some(_)` after simplification. + place: Option<Place<'tcx>>, /// ... must pass this test... // Invariant: after creation and simplification in `Candidate::new()`, this must not be @@ -1277,7 +1285,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // only generates a single switch. candidate.subcandidates = self.create_or_subcandidates(pats, candidate.has_guard); - candidate.match_pairs.pop(); + let first_match_pair = candidate.match_pairs.pop().unwrap(); + candidate.or_span = Some(first_match_pair.pattern.span); split_or_candidate = true; } } @@ -1287,8 +1296,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // At least one of the candidates has been split into subcandidates. // We need to change the candidate list to include those. let mut new_candidates = Vec::new(); - - for candidate in candidates { + for candidate in candidates.iter_mut() { candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate)); } self.match_simplified_candidates( @@ -1298,6 +1306,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { otherwise_block, &mut *new_candidates, ); + + for candidate in candidates { + self.merge_trivial_subcandidates(candidate); + } } else { self.match_simplified_candidates( span, @@ -1531,16 +1543,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut or_candidate_refs, ); candidate.subcandidates = or_candidates; - self.merge_trivial_subcandidates(candidate, self.source_info(or_span)); + candidate.or_span = Some(or_span); + self.merge_trivial_subcandidates(candidate); } /// Try to merge all of the subcandidates of the given candidate into one. /// This avoids exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. - fn merge_trivial_subcandidates( - &mut self, - candidate: &mut Candidate<'_, 'tcx>, - source_info: SourceInfo, - ) { + fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { if candidate.subcandidates.is_empty() || candidate.has_guard { // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard. return; @@ -1550,7 +1559,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Not `Iterator::all` because we don't want to short-circuit. for subcandidate in &mut candidate.subcandidates { - self.merge_trivial_subcandidates(subcandidate, source_info); + self.merge_trivial_subcandidates(subcandidate); // FIXME(or_patterns; matthewjasper) Try to be more aggressive here. can_merge &= @@ -1559,6 +1568,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if can_merge { let any_matches = self.cfg.start_new_block(); + let or_span = candidate.or_span.take().unwrap(); + let source_info = self.source_info(or_span); for subcandidate in mem::take(&mut candidate.subcandidates) { let or_block = subcandidate.pre_binding_block.unwrap(); self.cfg.goto(or_block, source_info, any_matches); @@ -1587,11 +1598,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn pick_test( &mut self, candidates: &mut [&mut Candidate<'_, 'tcx>], - ) -> (PlaceBuilder<'tcx>, Test<'tcx>) { + ) -> (Place<'tcx>, Test<'tcx>) { // Extract the match-pair from the highest priority candidate let match_pair = &candidates.first().unwrap().match_pairs[0]; let test = self.test(match_pair); - let match_place = match_pair.place.clone(); + // Unwrap is ok after simplification. + let match_place = match_pair.place.unwrap(); debug!(?test, ?match_pair); (match_place, test) @@ -1632,7 +1644,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// - candidate 1 becomes `[y @ false]` since we know that `x` was `false`. fn sort_candidates<'b, 'c, 'pat>( &mut self, - match_place: &PlaceBuilder<'tcx>, + match_place: Place<'tcx>, test: &Test<'tcx>, mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], ) -> ( @@ -1650,7 +1662,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // sorting. while let Some(candidate) = candidates.first_mut() { let Some(branch) = - self.sort_candidate(&match_place, test, candidate, &target_candidates) + self.sort_candidate(match_place, test, candidate, &target_candidates) else { break; }; @@ -1778,7 +1790,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // For each of the N possible test outcomes, build the vector of candidates that applies if // the test has that particular outcome. let (remaining_candidates, target_candidates) = - self.sort_candidates(&match_place, &test, candidates); + self.sort_candidates(match_place, &test, candidates); // The block that we should branch to if none of the // `target_candidates` match. @@ -1818,7 +1830,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span, start_block, remainder_start, - &match_place, + match_place, &test, target_blocks, ); diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 97b94a0b362..bf1906f370b 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -82,7 +82,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &*candidate.match_pairs { candidate.subcandidates = self.create_or_subcandidates(pats, has_guard); - candidate.match_pairs.pop(); + let first_match_pair = candidate.match_pairs.pop().unwrap(); + candidate.or_span = Some(first_match_pair.pattern.span); } candidate }) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 9d77bd063e1..b66dd83b7ec 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -5,7 +5,6 @@ // identify what tests are needed, perform the tests, and then filter // the candidates based on the result. -use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Candidate, MatchPair, Test, TestBranch, TestCase, TestKind}; use crate::build::Builder; use rustc_data_structures::fx::FxIndexMap; @@ -55,18 +54,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Test { span: match_pair.pattern.span, kind } } - #[instrument(skip(self, target_blocks, place_builder), level = "debug")] + #[instrument(skip(self, target_blocks, place), level = "debug")] pub(super) fn perform_test( &mut self, match_start_span: Span, scrutinee_span: Span, block: BasicBlock, otherwise_block: BasicBlock, - place_builder: &PlaceBuilder<'tcx>, + place: Place<'tcx>, test: &Test<'tcx>, target_blocks: FxIndexMap<TestBranch<'tcx>, BasicBlock>, ) { - let place = place_builder.to_place(self); let place_ty = place.ty(&self.local_decls, self.tcx); debug!(?place, ?place_ty); let target_block = |branch| target_blocks.get(&branch).copied().unwrap_or(otherwise_block); @@ -475,7 +473,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// tighter match code if we do something a bit different. pub(super) fn sort_candidate( &mut self, - test_place: &PlaceBuilder<'tcx>, + test_place: Place<'tcx>, test: &Test<'tcx>, candidate: &mut Candidate<'_, 'tcx>, sorted_candidates: &FxIndexMap<TestBranch<'tcx>, Vec<&mut Candidate<'_, 'tcx>>>, @@ -486,8 +484,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // than one, but it'd be very unusual to have two sides that // both require tests; you'd expect one side to be simplified // away.) - let (match_pair_index, match_pair) = - candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?; + let (match_pair_index, match_pair) = candidate + .match_pairs + .iter() + .enumerate() + .find(|&(_, mp)| mp.place == Some(test_place))?; let fully_matched; let ret = match (&test.kind, &match_pair.test_case) { @@ -521,7 +522,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate .match_pairs .iter() - .any(|mp| mp.place == *test_place && is_covering_range(&mp.test_case)) + .any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case)) }; if sorted_candidates .get(&TestBranch::Failure) diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 1148cd19a01..bc6f0a26582 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -95,35 +95,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { pub(in crate::build) fn new( - mut place: PlaceBuilder<'tcx>, + mut place_builder: PlaceBuilder<'tcx>, pattern: &'pat Pat<'tcx>, cx: &mut Builder<'_, 'tcx>, ) -> MatchPair<'pat, 'tcx> { // Force the place type to the pattern's type. // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? - if let Some(resolved) = place.resolve_upvar(cx) { - place = resolved; + if let Some(resolved) = place_builder.resolve_upvar(cx) { + place_builder = resolved; } // Only add the OpaqueCast projection if the given place is an opaque type and the // expected type from the pattern is not. - let may_need_cast = match place.base() { + let may_need_cast = match place_builder.base() { PlaceBase::Local(local) => { - let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty; + let ty = + Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty; ty != pattern.ty && ty.has_opaque_types() } _ => true, }; if may_need_cast { - place = place.project(ProjectionElem::OpaqueCast(pattern.ty)); + place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); } + let place = place_builder.try_to_place(cx); let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; let mut subpairs = Vec::new(); let test_case = match pattern.kind { PatKind::Never | PatKind::Wild | PatKind::Error(_) => default_irrefutable(), PatKind::Or { ref pats } => TestCase::Or { - pats: pats.iter().map(|pat| FlatPat::new(place.clone(), pat, cx)).collect(), + pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), }, PatKind::Range(ref range) => { @@ -142,13 +144,13 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { .. } => { // Apply the type ascription to the value at `match_pair.place` - let ascription = place.try_to_place(cx).map(|source| super::Ascription { + let ascription = place.map(|source| super::Ascription { annotation: annotation.clone(), source, variance, }); - subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); + subpairs.push(MatchPair::new(place_builder, subpattern, cx)); TestCase::Irrefutable { ascription, binding: None } } @@ -161,7 +163,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { ref subpattern, is_primary: _, } => { - let binding = place.try_to_place(cx).map(|source| super::Binding { + let binding = place.map(|source| super::Binding { span: pattern.span, source, var_id: var, @@ -170,14 +172,14 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { if let Some(subpattern) = subpattern.as_ref() { // this is the `x @ P` case; have to keep matching against `P` now - subpairs.push(MatchPair::new(place.clone(), subpattern, cx)); + subpairs.push(MatchPair::new(place_builder, subpattern, cx)); } TestCase::Irrefutable { ascription: None, binding } } PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { // Apply a type ascription for the inline constant to the value at `match_pair.place` - let ascription = place.try_to_place(cx).map(|source| { + let ascription = place.map(|source| { let span = pattern.span; let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); let args = ty::InlineConstArgs::new( @@ -203,16 +205,16 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { super::Ascription { annotation, source, variance: ty::Contravariant } }); - subpairs.push(MatchPair::new(place.clone(), pattern, cx)); + subpairs.push(MatchPair::new(place_builder, pattern, cx)); TestCase::Irrefutable { ascription, binding: None } } PatKind::Array { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix); + cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); default_irrefutable() } PatKind::Slice { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix); + cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); if prefix.is_empty() && slice.is_some() && suffix.is_empty() { default_irrefutable() @@ -225,7 +227,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { } PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { - let downcast_place = place.clone().downcast(adt_def, variant_index); // `(x as Variant)` + let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` subpairs = cx.field_match_pairs(downcast_place, subpatterns); let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { @@ -247,13 +249,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { } PatKind::Leaf { ref subpatterns } => { - subpairs = cx.field_match_pairs(place.clone(), subpatterns); + subpairs = cx.field_match_pairs(place_builder, subpatterns); default_irrefutable() } PatKind::Deref { ref subpattern } => { - let place_builder = place.clone().deref(); - subpairs.push(MatchPair::new(place_builder, subpattern, cx)); + subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx)); default_irrefutable() } @@ -310,8 +311,8 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } } else { // Insert a Shallow borrow of any place that is switched on. - if let Some(resolved_place) = match_pair.place.try_to_place(self.cx) { - self.fake_borrows.insert(resolved_place); + if let Some(place) = match_pair.place { + self.fake_borrows.insert(place); } for subpair in &match_pair.subpairs { 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_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 94a95428ab0..b60ee7649b2 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -1015,8 +1015,8 @@ fn build_construct_coroutine_by_move_shim<'tcx>( bug!(); }; - // We use `*mut Self` here because we only need to emit an ABI-compatible shim body, - // rather than match the signature exactly. + // We use `&mut Self` here because we only need to emit an ABI-compatible shim body, + // rather than match the signature exactly (which might take `&self` instead). // // The self type here is a coroutine-closure, not a coroutine, and we never read from // it because it never has any captures, because this is only true in the Fn/FnMut @@ -1025,7 +1025,7 @@ fn build_construct_coroutine_by_move_shim<'tcx>( if receiver_by_ref { // Triple-check that there's no captures here. assert_eq!(args.as_coroutine_closure().tupled_upvars_ty(), tcx.types.unit); - self_ty = Ty::new_mut_ptr(tcx, self_ty); + self_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, self_ty); } let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 35a052166bd..c746041ebd8 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -19,6 +19,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition { let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); 'blocks: for block in body.basic_blocks_mut() { for stmt in block.statements.iter_mut() { + // Simplify `assume` of a known value: either a NOP or unreachable. if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind && let NonDivergingIntrinsic::Assume(discr) = intrinsic && let Operand::Constant(ref c) = discr diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index bff59aa6023..8ad7bc394c5 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -14,11 +14,7 @@ pub struct UnreachablePropagation; impl MirPass<'_> for UnreachablePropagation { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { // Enable only under -Zmir-opt-level=2 as this can make programs less debuggable. - - // FIXME(#116171) Coverage gets confused by MIR passes that can remove all - // coverage statements from an instrumented function. This pass can be - // re-enabled when coverage codegen is robust against that happening. - sess.mir_opt_level() >= 2 && !sess.instrument_coverage() + sess.mir_opt_level() >= 2 } fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { 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_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index aa735f3de1f..8957d7d1bd3 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -14,10 +14,6 @@ parse_array_index_offset_of = array indexing not supported in offset_of parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed -parse_assoc_lifetime = associated lifetimes are not supported - .label = the lifetime is given here - .help = if you meant to specify a trait object, write `dyn Trait + 'lifetime` - parse_associated_static_item_not_allowed = associated `static` items are not allowed parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later @@ -445,6 +441,12 @@ parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated wit .suggestion = remove the lifetime annotation .label = annotated with lifetime here +parse_lifetime_in_eq_constraint = lifetimes are not permitted in this context + .label = lifetime is not allowed here + .context_label = this introduces an associated item binding + .help = if you meant to specify a trait object, write `dyn /* Trait */ + {$lifetime}` + .colon_sugg = you might have meant to write a bound here + parse_lone_slash = invalid trailing slash in literal .label = {parse_lone_slash} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 20ebfc6691b..a6eedabf689 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2631,13 +2631,22 @@ pub(crate) struct GenericsInPath { } #[derive(Diagnostic)] -#[diag(parse_assoc_lifetime)] +#[diag(parse_lifetime_in_eq_constraint)] #[help] -pub(crate) struct AssocLifetime { +pub(crate) struct LifetimeInEqConstraint { #[primary_span] - pub span: Span, #[label] - pub lifetime: Span, + pub span: Span, + pub lifetime: Ident, + #[label(parse_context_label)] + pub binding_label: Span, + #[suggestion( + parse_colon_sugg, + style = "verbose", + applicability = "maybe-incorrect", + code = ": " + )] + pub colon_sugg: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 7e317c3df14..18fb858c84c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2768,7 +2768,7 @@ impl<'a> Parser<'a> { }; return if self.token.kind == token::CloseDelim(Delimiter::Parenthesis) { // We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the - // parser state and emit a targetted suggestion. + // parser state and emit a targeted suggestion. let span = vec![start_span, self.token.span]; let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span)); self.bump(); // ) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9153f2b9d06..608cdd945ff 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -718,7 +718,11 @@ impl<'a> Parser<'a> { let bounds = self.parse_generic_bounds()?; AssocConstraintKind::Bound { bounds } } else if self.eat(&token::Eq) { - self.parse_assoc_equality_term(ident, self.prev_token.span)? + self.parse_assoc_equality_term( + ident, + gen_args.as_ref(), + self.prev_token.span, + )? } else { unreachable!(); }; @@ -753,11 +757,13 @@ impl<'a> Parser<'a> { } /// Parse the term to the right of an associated item equality constraint. - /// That is, parse `<term>` in `Item = <term>`. - /// Right now, this only admits types in `<term>`. + /// + /// That is, parse `$term` in `Item = $term` where `$term` is a type or + /// a const expression (wrapped in curly braces if complex). fn parse_assoc_equality_term( &mut self, ident: Ident, + gen_args: Option<&GenericArgs>, eq: Span, ) -> PResult<'a, AssocConstraintKind> { let arg = self.parse_generic_arg(None)?; @@ -769,9 +775,15 @@ impl<'a> Parser<'a> { c.into() } Some(GenericArg::Lifetime(lt)) => { - let guar = - self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span }); - self.mk_ty(span, ast::TyKind::Err(guar)).into() + let guar = self.dcx().emit_err(errors::LifetimeInEqConstraint { + span: lt.ident.span, + lifetime: lt.ident, + binding_label: span, + colon_sugg: gen_args + .map_or(ident.span, |args| args.span()) + .between(lt.ident.span), + }); + self.mk_ty(lt.ident.span, ast::TyKind::Err(guar)).into() } None => { let after_eq = eq.shrink_to_hi(); diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index c2e604b02b3..869cbebbc0d 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; @@ -19,9 +24,10 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt}; 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 +60,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 +110,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 +139,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, }, @@ -141,16 +163,6 @@ impl<'tcx> ReachableContext<'tcx> { if !self.any_library { // If we are building an executable, only explicitly extern // types need to be exported. - let reachable = - if let Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. }) - | Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(sig, ..), .. - }) = *node - { - sig.header.abi != Abi::Rust - } else { - false - }; let codegen_attrs = if self.tcx.def_kind(search_item).has_codegen_attrs() { self.tcx.codegen_fn_attrs(search_item) } else { @@ -159,7 +171,7 @@ impl<'tcx> ReachableContext<'tcx> { let is_extern = codegen_attrs.contains_extern_indicator(); let std_internal = codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); - if reachable || is_extern || std_internal { + if is_extern || std_internal { self.reachable_symbols.insert(search_item); } } else { @@ -174,7 +186,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 +240,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 +328,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 +406,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 +440,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_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index 674a0984ae9..c3fc036aed3 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -9,13 +9,6 @@ use rustc_span::def_id::DefId; use rustc_span::def_id::DefIndex; use std::fmt::Debug; use std::hash::Hash; -use std::marker::PhantomData; - -pub trait CacheSelector<'tcx, V> { - type Cache - where - V: Copy; -} pub trait QueryCache: Sized { type Key: Hash + Eq + Copy + Debug; @@ -29,14 +22,6 @@ pub trait QueryCache: Sized { fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)); } -pub struct DefaultCacheSelector<K>(PhantomData<K>); - -impl<'tcx, K: Eq + Hash, V: 'tcx> CacheSelector<'tcx, V> for DefaultCacheSelector<K> { - type Cache = DefaultCache<K, V> - where - V: Copy; -} - pub struct DefaultCache<K, V> { cache: Sharded<FxHashMap<K, (V, DepNodeIndex)>>, } @@ -81,14 +66,6 @@ where } } -pub struct SingleCacheSelector; - -impl<'tcx, V: 'tcx> CacheSelector<'tcx, V> for SingleCacheSelector { - type Cache = SingleCache<V> - where - V: Copy; -} - pub struct SingleCache<V> { cache: OnceLock<(V, DepNodeIndex)>, } @@ -123,14 +100,6 @@ where } } -pub struct VecCacheSelector<K>(PhantomData<K>); - -impl<'tcx, K: Idx, V: 'tcx> CacheSelector<'tcx, V> for VecCacheSelector<K> { - type Cache = VecCache<K, V> - where - V: Copy; -} - pub struct VecCache<K: Idx, V> { cache: Sharded<IndexVec<K, Option<(V, DepNodeIndex)>>>, } @@ -174,14 +143,6 @@ where } } -pub struct DefIdCacheSelector; - -impl<'tcx, V: 'tcx> CacheSelector<'tcx, V> for DefIdCacheSelector { - type Cache = DefIdCache<V> - where - V: Copy; -} - pub struct DefIdCache<V> { /// Stores the local DefIds in a dense map. Local queries are much more often dense, so this is /// a win over hashing query keys at marginal memory cost (~5% at most) compared to FxHashMap. diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 01b9d458f1e..91a0026f281 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -9,10 +9,7 @@ pub use self::job::{ }; mod caches; -pub use self::caches::{ - CacheSelector, DefIdCacheSelector, DefaultCacheSelector, QueryCache, SingleCacheSelector, - VecCacheSelector, -}; +pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; mod config; pub use self::config::{HashResult, QueryConfig}; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 476b31f44ae..4057bc9ffbd 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2730,7 +2730,7 @@ pub(crate) fn import_candidates( ); } -type PathString<'a> = (String, &'a str, Option<DefId>, &'a Option<String>, bool); +type PathString<'a> = (String, &'a str, Option<Span>, &'a Option<String>, bool); /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the @@ -2762,7 +2762,7 @@ fn show_candidates( accessible_path_strings.push(( pprust::path_to_string(&c.path), c.descr, - c.did, + c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))), &c.note, c.via_import, )) @@ -2771,7 +2771,7 @@ fn show_candidates( inaccessible_path_strings.push(( pprust::path_to_string(&c.path), c.descr, - c.did, + c.did.and_then(|did| Some(tcx.source_span(did.as_local()?))), &c.note, c.via_import, )) @@ -2889,15 +2889,14 @@ fn show_candidates( } else if !(inaccessible_path_strings.is_empty() || matches!(mode, DiagMode::Import { .. })) { let prefix = if let DiagMode::Pattern = mode { "you might have meant to match on " } else { "" }; - if let [(name, descr, def_id, note, _)] = &inaccessible_path_strings[..] { + if let [(name, descr, source_span, note, _)] = &inaccessible_path_strings[..] { let msg = format!( "{prefix}{descr} `{name}`{} exists but is inaccessible", if let DiagMode::Pattern = mode { ", which" } else { "" } ); - if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) { - let span = tcx.source_span(local_def_id); - let span = tcx.sess.source_map().guess_head_span(span); + if let Some(source_span) = source_span { + let span = tcx.sess.source_map().guess_head_span(*source_span); let mut multi_span = MultiSpan::from_span(span); multi_span.push_span_label(span, "not accessible"); err.span_note(multi_span, msg); @@ -2925,10 +2924,9 @@ fn show_candidates( let mut has_colon = false; let mut spans = Vec::new(); - for (name, _, def_id, _, _) in &inaccessible_path_strings { - if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) { - let span = tcx.source_span(local_def_id); - let span = tcx.sess.source_map().guess_head_span(span); + for (name, _, source_span, _, _) in &inaccessible_path_strings { + if let Some(source_span) = source_span { + let span = tcx.sess.source_map().guess_head_span(*source_span); spans.push((name, span)); } else { if !has_colon { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 9bf3e9ccabd..48711f43518 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -19,6 +19,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, MultiSpan}; use rustc_hir::def::{self, DefKind, PartialRes}; +use rustc_hir::def_id::DefId; use rustc_middle::metadata::ModChild; use rustc_middle::metadata::Reexport; use rustc_middle::span_bug; @@ -250,6 +251,9 @@ struct UnresolvedImportError { note: Option<String>, suggestion: Option<Suggestion>, candidates: Option<Vec<ImportSuggestion>>, + segment: Option<Symbol>, + /// comes from `PathRes::Failed { module }` + module: Option<DefId>, } // Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;` @@ -579,16 +583,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { &import.kind, import.span, ); - let err = UnresolvedImportError { - span: import.span, - label: None, - note: None, - suggestion: None, - candidates: None, - }; // FIXME: there should be a better way of doing this than // formatting this as a string then checking for `::` if path.contains("::") { + let err = UnresolvedImportError { + span: import.span, + label: None, + note: None, + suggestion: None, + candidates: None, + segment: None, + module: None, + }; errors.push((*import, err)) } } @@ -738,15 +744,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - match &import.kind { - ImportKind::Single { source, .. } => { - if let Some(ModuleOrUniformRoot::Module(module)) = import.imported_module.get() - && let Some(module) = module.opt_def_id() - { - self.find_cfg_stripped(&mut diag, &source.name, module) - } - } - _ => {} + if matches!(import.kind, ImportKind::Single { .. }) + && let Some(segment) = err.segment + && let Some(module) = err.module + { + self.find_cfg_stripped(&mut diag, &segment, module) } } @@ -916,10 +918,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { span, label, suggestion, + module, + segment_name, .. } => { if no_ambiguity { assert!(import.imported_module.get().is_none()); + let module = if let Some(ModuleOrUniformRoot::Module(m)) = module { + m.opt_def_id() + } else { + None + }; let err = match self.make_path_suggestion( span, import.module_path.clone(), @@ -935,6 +944,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Applicability::MaybeIncorrect, )), candidates: None, + segment: Some(segment_name), + module, }, None => UnresolvedImportError { span, @@ -942,6 +953,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { note: None, suggestion, candidates: None, + segment: Some(segment_name), + module, }, }; return Some(err); @@ -990,6 +1003,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { note: None, suggestion: None, candidates: None, + segment: None, + module: None, }); } } @@ -1199,6 +1214,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } else { None }, + module: import.imported_module.get().and_then(|module| { + if let ModuleOrUniformRoot::Module(m) = module { + m.opt_def_id() + } else { + None + } + }), + segment: Some(ident.name), }) } else { // `resolve_ident_in_module` reported a privacy error. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b2b339d2521..49b4a6efd3c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2531,7 +2531,17 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } ItemKind::Delegation(ref delegation) => { - self.resolve_delegation(delegation); + let span = delegation.path.segments.last().unwrap().ident.span; + self.with_generic_param_rib( + &[], + RibKind::Item(HasGenericParams::Yes(span), def_kind), + LifetimeRibKind::Generics { + binder: item.id, + kind: LifetimeBinderKind::Function, + span, + }, + |this| this.resolve_delegation(delegation), + ); } ItemKind::ExternCrate(..) => {} @@ -2819,7 +2829,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); } AssocItemKind::Delegation(delegation) => { - self.resolve_delegation(delegation); + self.with_generic_param_rib( + &[], + RibKind::AssocItem, + LifetimeRibKind::Generics { + binder: item.id, + kind: LifetimeBinderKind::Function, + span: delegation.path.segments.last().unwrap().ident.span, + }, + |this| this.resolve_delegation(delegation), + ); } AssocItemKind::Type(box TyAlias { generics, .. }) => self .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { @@ -3069,16 +3088,28 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { } AssocItemKind::Delegation(box delegation) => { debug!("resolve_implementation AssocItemKind::Delegation"); - self.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - seen_trait_items, - |i, s, c| MethodNotMemberOfTrait(i, s, c), + self.with_generic_param_rib( + &[], + RibKind::AssocItem, + LifetimeRibKind::Generics { + binder: item.id, + kind: LifetimeBinderKind::Function, + span: delegation.path.segments.last().unwrap().ident.span, + }, + |this| { + this.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + seen_trait_items, + |i, s, c| MethodNotMemberOfTrait(i, s, c), + ); + + this.resolve_delegation(delegation) + }, ); - self.resolve_delegation(delegation); } AssocItemKind::MacCall(_) => { panic!("unexpanded macro in resolve!") diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index dfc2d029d4c..39ccf6d3714 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -415,6 +415,19 @@ enum PathResult<'a> { label: String, suggestion: Option<Suggestion>, is_error_from_last_segment: bool, + /// The final module being resolved, for instance: + /// + /// ```compile_fail + /// mod a { + /// mod b { + /// mod c {} + /// } + /// } + /// + /// use a::not_exist::c; + /// ``` + /// + /// In this case, `module` will point to `a`. module: Option<ModuleOrUniformRoot<'a>>, /// The segment name of target segment_name: Symbol, @@ -1605,7 +1618,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .into_items() .map(|(k, f)| (k, f.key())) .collect(), - def_id_to_node_id: self.def_id_to_node_id, trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c06fe29c567..f612e8b5b1a 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2795,11 +2795,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let debuginfo = select_debuginfo(matches, &cg); let debuginfo_compression = unstable_opts.debuginfo_compression; - let mut search_paths = vec![]; - for s in &matches.opt_strs("L") { - search_paths.push(SearchPath::from_cli_opt(early_dcx, s)); - } - let libs = parse_libs(early_dcx, matches); let test = matches.opt_present("test"); @@ -2848,6 +2843,11 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M candidate.join("library/std/src/lib.rs").is_file().then_some(candidate) }; + let mut search_paths = vec![]; + for s in &matches.opt_strs("L") { + search_paths.push(SearchPath::from_cli_opt(&sysroot, &target_triple, early_dcx, s)); + } + let working_dir = std::env::current_dir().unwrap_or_else(|e| { early_dcx.early_fatal(format!("Current directory is invalid: {e}")); }); diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index 32d5e430717..16dd40acef0 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -1,5 +1,6 @@ use crate::filesearch::make_target_lib_path; use crate::EarlyDiagCtxt; +use rustc_target::spec::TargetTriple; use std::path::{Path, PathBuf}; #[derive(Clone, Debug)] @@ -46,7 +47,12 @@ impl PathKind { } impl SearchPath { - pub fn from_cli_opt(early_dcx: &EarlyDiagCtxt, path: &str) -> Self { + pub fn from_cli_opt( + sysroot: &Path, + triple: &TargetTriple, + early_dcx: &EarlyDiagCtxt, + path: &str, + ) -> Self { let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") { (PathKind::Native, stripped) } else if let Some(stripped) = path.strip_prefix("crate=") { @@ -60,12 +66,17 @@ impl SearchPath { } else { (PathKind::All, path) }; - if path.is_empty() { + let dir = match path.strip_prefix("@RUSTC_BUILTIN") { + Some(stripped) => { + make_target_lib_path(sysroot, triple.triple()).join("builtin").join(stripped) + } + None => PathBuf::from(path), + }; + if dir.as_os_str().is_empty() { #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable early_dcx.early_fatal("empty search path given via `-L`"); } - let dir = PathBuf::from(path); Self::new(kind, dir) } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 0c811d7dff1..8f721bac951 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -218,8 +218,6 @@ rustc_index::newtype_index! { /// /// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`. #[derive(Clone, PartialEq, Eq, Copy)] -// Don't derive order on 64-bit big-endian, so we can be consistent regardless of field order. -#[cfg_attr(not(all(target_pointer_width = "64", target_endian = "big")), derive(PartialOrd, Ord))] // On below-64 bit systems we can simply use the derived `Hash` impl #[cfg_attr(not(target_pointer_width = "64"), derive(Hash))] #[repr(C)] @@ -236,6 +234,12 @@ pub struct DefId { pub index: DefIndex, } +// To ensure correctness of incremental compilation, +// `DefId` must not implement `Ord` or `PartialOrd`. +// See https://github.com/rust-lang/rust/issues/90317. +impl !Ord for DefId {} +impl !PartialOrd for DefId {} + // On 64-bit systems, we can hash the whole `DefId` as one `u64` instead of two `u32`s. This // improves performance without impairing `FxHash` quality. So the below code gets compiled to a // noop on little endian systems because the memory layout of `DefId` is as follows: @@ -261,22 +265,6 @@ impl Hash for DefId { } } -// Implement the same comparison as derived with the other field order. -#[cfg(all(target_pointer_width = "64", target_endian = "big"))] -impl Ord for DefId { - #[inline] - fn cmp(&self, other: &DefId) -> std::cmp::Ordering { - Ord::cmp(&(self.index, self.krate), &(other.index, other.krate)) - } -} -#[cfg(all(target_pointer_width = "64", target_endian = "big"))] -impl PartialOrd for DefId { - #[inline] - fn partial_cmp(&self, other: &DefId) -> Option<std::cmp::Ordering> { - Some(self.cmp(other)) - } -} - impl DefId { /// Makes a local `DefId` from the given `DefIndex`. #[inline] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 616a7ccc7c6..0c974ef4ca3 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -427,6 +427,17 @@ impl FileName { src.hash(&mut hasher); FileName::InlineAsm(hasher.finish()) } + + /// Returns the path suitable for reading from the file system on the local host, + /// if this information exists. + /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. + pub fn into_local_path(self) -> Option<PathBuf> { + match self { + FileName::Real(path) => path.into_local_path(), + FileName::DocTest(path, _) => Some(path), + _ => None, + } + } } /// Represents a span. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 73fcd2a76df..891ddb7af5b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -674,6 +674,7 @@ symbols! { deref_mut, deref_mut_method, deref_patterns, + deref_pure, deref_target, derive, derive_const, 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 } diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 3101015281b..04b92fbd33b 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -1112,8 +1112,36 @@ pub fn typeid_for_instance<'tcx>( mut instance: Instance<'tcx>, options: TypeIdOptions, ) -> String { - if matches!(instance.def, ty::InstanceDef::Virtual(..)) { - instance.args = strip_receiver_auto(tcx, instance.args) + if (matches!(instance.def, ty::InstanceDef::Virtual(..)) + && Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn()) + || matches!(instance.def, ty::InstanceDef::DropGlue(..)) + { + // Adjust the type ids of DropGlues + // + // DropGlues may have indirect calls to one or more given types drop function. Rust allows + // for types to be erased to any trait object and retains the drop function for the original + // type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is + // called a second time, it only has information after type erasure and it could be a call + // on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on + // declaration/definition, and during code generation at call sites so they have the same + // type id and match. + // + // FIXME(rcvalle): This allows a drop call on any trait object to call the drop function of + // any other type. + // + let def_id = tcx + .lang_items() + .drop_trait() + .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item")); + let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { + def_id: def_id, + args: List::empty(), + }); + let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]); + let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn); + instance.args = tcx.mk_args_trait(self_ty, List::empty()); + } else if matches!(instance.def, ty::InstanceDef::Virtual(..)) { + instance.args = strip_receiver_auto(tcx, instance.args); } if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) @@ -1124,7 +1152,10 @@ pub fn typeid_for_instance<'tcx>( .trait_item_def_id .expect("Part of a trait implementation, but not linked to the def_id?"); let trait_method = tcx.associated_item(method_id); - if traits::is_vtable_safe_method(tcx, trait_ref.skip_binder().def_id, trait_method) { + let trait_id = trait_ref.skip_binder().def_id; + if traits::is_vtable_safe_method(tcx, trait_id, trait_method) + && tcx.object_safety_violations(trait_id).is_empty() + { // Trait methods will have a Self polymorphic parameter, where the concreteized // implementatation will not. We need to walk back to the more general trait method let trait_ref = tcx.instantiate_and_normalize_erasing_regions( @@ -1152,8 +1183,8 @@ pub fn typeid_for_instance<'tcx>( let fn_abi = tcx .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty()))) - .unwrap_or_else(|instance| { - bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance) + .unwrap_or_else(|error| { + bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}") }); typeid_for_fnabi(tcx, fn_abi, options) @@ -1182,6 +1213,7 @@ fn strip_receiver_auto<'tcx>( tcx.mk_args_trait(new_rcvr, args.into_iter().skip(1)) } +#[instrument(skip(tcx), ret)] fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> { assert!(!poly_trait_ref.has_non_region_param()); let principal_pred = poly_trait_ref.map_bound(|trait_ref| { @@ -1199,6 +1231,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc ty::ParamEnv::reveal_all(), alias_ty.to_ty(tcx), ); + debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx)); ty::ExistentialPredicate::Projection(ty::ExistentialProjection { def_id: assoc_ty.def_id, args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args, diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs index 2169e2971d8..703a3206af2 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs @@ -19,6 +19,7 @@ pub fn target() -> Target { stack_probes: StackProbeType::Inline, supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI + | SanitizerSet::KCFI | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::MEMTAG diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs index 98374023dc5..11fb28a9aed 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs @@ -10,6 +10,7 @@ pub fn target() -> Target { base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI + | SanitizerSet::KCFI | SanitizerSet::DATAFLOW | SanitizerSet::LEAK | SanitizerSet::MEMORY diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 3cc46b5c638..7a62030353d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -21,6 +21,7 @@ use crate::traits::{ }; use core::ops::ControlFlow; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart}; use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey}; @@ -2117,7 +2118,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }) .collect(); - impl_candidates.sort(); + impl_candidates.sort_by_key(|tr| tr.to_string()); impl_candidates.dedup(); return report(impl_candidates, err); } @@ -2143,7 +2144,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cand }) .collect(); - impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref)); + impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref.to_string())); let mut impl_candidates: Vec<_> = impl_candidates.into_iter().map(|cand| cand.trait_ref).collect(); impl_candidates.dedup(); @@ -2243,14 +2244,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); - let traits_with_same_path: std::collections::BTreeSet<_> = self + let traits_with_same_path: UnordSet<_> = self .tcx .all_traits() .filter(|trait_def_id| *trait_def_id != trait_ref.def_id()) - .filter(|trait_def_id| self.tcx.def_path_str(*trait_def_id) == required_trait_path) + .map(|trait_def_id| (self.tcx.def_path_str(trait_def_id), trait_def_id)) + .filter(|(p, _)| *p == required_trait_path) .collect(); + + let traits_with_same_path = + traits_with_same_path.into_items().into_sorted_stable_ord_by_key(|(p, _)| p); let mut suggested = false; - for trait_with_same_path in traits_with_same_path { + for (_, trait_with_same_path) in traits_with_same_path { let trait_impls = get_trait_impls(trait_with_same_path); if trait_impls.is_empty() { continue; diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 3f433a9e919..29d063321a7 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use super::NormalizeExt; use super::{ObligationCause, PredicateObligation, SelectionContext}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::Diag; use rustc_hir::def_id::DefId; use rustc_infer::infer::{InferCtxt, InferOk}; @@ -431,8 +431,8 @@ pub struct BoundVarReplacer<'me, 'tcx> { // These three maps track the bound variable that were replaced by placeholders. It might be // nice to remove these since we already have the `kind` in the placeholder; we really just need // the `var` (but we *could* bring that into scope if we were to track them as we pass them). - mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>, - mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>, + mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, + mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>, mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, // The current depth relative to *this* folding, *not* the entire normalization. In other words, // the depth of binders we've passed here. @@ -451,12 +451,13 @@ impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { value: T, ) -> ( T, - BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>, - BTreeMap<ty::PlaceholderType, ty::BoundTy>, + FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, + FxIndexMap<ty::PlaceholderType, ty::BoundTy>, BTreeMap<ty::PlaceholderConst, ty::BoundVar>, ) { - let mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion> = BTreeMap::new(); - let mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy> = BTreeMap::new(); + let mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion> = + FxIndexMap::default(); + let mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy> = FxIndexMap::default(); let mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar> = BTreeMap::new(); let mut replacer = BoundVarReplacer { @@ -574,8 +575,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { /// The inverse of [`BoundVarReplacer`]: replaces placeholders with the bound vars from which they came. pub struct PlaceholderReplacer<'me, 'tcx> { infcx: &'me InferCtxt<'tcx>, - mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>, - mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>, + mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, + mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>, mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, universe_indices: &'me [Option<ty::UniverseIndex>], current_index: ty::DebruijnIndex, @@ -584,8 +585,8 @@ pub struct PlaceholderReplacer<'me, 'tcx> { impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> { pub fn replace_placeholders<T: TypeFoldable<TyCtxt<'tcx>>>( infcx: &'me InferCtxt<'tcx>, - mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>, - mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>, + mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>, + mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>, mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>, universe_indices: &'me [Option<ty::UniverseIndex>], value: T, diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index a7c60c3b490..0377ed5d4c5 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -65,7 +65,7 @@ pub mod rustc { use std::fmt::{self, Write}; /// A reference in the layout. - #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)] + #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] pub struct Ref<'tcx> { pub lifetime: ty::Region<'tcx>, pub ty: Ty<'tcx>, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index af1dfb6f7e9..65c3cf1a607 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -125,8 +125,12 @@ fn fn_sig_for_fn_abi<'tcx>( coroutine_kind = ty::ClosureKind::FnOnce; // Implementations of `FnMut` and `Fn` for coroutine-closures - // still take their receiver by ref. - if receiver_by_ref { Ty::new_mut_ptr(tcx, coroutine_ty) } else { coroutine_ty } + // still take their receiver by (mut) ref. + if receiver_by_ref { + Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty) + } else { + coroutine_ty + } } else { tcx.closure_env_ty(coroutine_ty, coroutine_kind, env_region) }; diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 9c3d39307b2..331970ac362 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -745,7 +745,7 @@ fn coroutine_layout<'tcx>( let tcx = cx.tcx; let instantiate_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).instantiate(tcx, args); - let Some(info) = tcx.coroutine_layout(def_id) else { + let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else { return Err(error(cx, LayoutError::Unknown(ty))); }; let (ineligible_locals, assignments) = coroutine_saved_local_eligibility(info); @@ -1072,7 +1072,7 @@ fn variant_info_for_coroutine<'tcx>( return (vec![], None); }; - let coroutine = cx.tcx.optimized_mir(def_id).coroutine_layout().unwrap(); + let coroutine = cx.tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()).unwrap(); let upvar_names = cx.tcx.closure_saved_names_of_captured_variables(def_id); let mut upvars_size = Size::ZERO; diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 0aaaad5af05..5b08140db3a 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -8,15 +8,7 @@ use self::ConstKind::*; /// Represents a constant in Rust. #[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - PartialOrd(bound = ""), - PartialOrd = "feature_allow_slow_enum", - Ord(bound = ""), - Ord = "feature_allow_slow_enum", - Hash(bound = "") -)] +#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum ConstKind<I: Interner> { /// A const generic parameter. diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 373540de05e..ae1e1902f14 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -9,16 +9,16 @@ use crate::{ }; pub trait Interner: Sized { - type DefId: Copy + Debug + Hash + Ord; - type AdtDef: Copy + Debug + Hash + Ord; + type DefId: Copy + Debug + Hash + Eq; + type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: Copy + DebugWithInfcx<Self> + Hash - + Ord + + Eq + IntoIterator<Item = Self::GenericArg>; - type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Ord; - type Term: Copy + Debug + Hash + Ord; + type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq; + type Term: Copy + Debug + Hash + Eq; type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>; type BoundVars: IntoIterator<Item = Self::BoundVar>; @@ -30,56 +30,56 @@ pub trait Interner: Sized { type Ty: Copy + DebugWithInfcx<Self> + Hash - + Ord + + Eq + Into<Self::GenericArg> + IntoKind<Kind = TyKind<Self>> + TypeSuperVisitable<Self> + Flags + new::Ty<Self>; - type Tys: Copy + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>; - type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Ord; - type ParamTy: Copy + Debug + Hash + Ord; - type BoundTy: Copy + Debug + Hash + Ord; - type PlaceholderTy: Copy + Debug + Hash + Ord + PlaceholderLike; + type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>; + type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Eq; + type ParamTy: Copy + Debug + Hash + Eq; + type BoundTy: Copy + Debug + Hash + Eq; + type PlaceholderTy: Copy + Debug + Hash + Eq + PlaceholderLike; // Things stored inside of tys - type ErrorGuaranteed: Copy + Debug + Hash + Ord; - type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Ord; - type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Ord; - type AllocId: Copy + Debug + Hash + Ord; + type ErrorGuaranteed: Copy + Debug + Hash + Eq; + type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq; + type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Eq; + type AllocId: Copy + Debug + Hash + Eq; // Kinds of consts type Const: Copy + DebugWithInfcx<Self> + Hash - + Ord + + Eq + Into<Self::GenericArg> + IntoKind<Kind = ConstKind<Self>> + ConstTy<Self> + TypeSuperVisitable<Self> + Flags + new::Const<Self>; - type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Ord; - type PlaceholderConst: Copy + Debug + Hash + Ord + PlaceholderLike; - type ParamConst: Copy + Debug + Hash + Ord; - type BoundConst: Copy + Debug + Hash + Ord; - type ValueConst: Copy + Debug + Hash + Ord; - type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Ord; + type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq; + type PlaceholderConst: Copy + Debug + Hash + Eq + PlaceholderLike; + type ParamConst: Copy + Debug + Hash + Eq; + type BoundConst: Copy + Debug + Hash + Eq; + type ValueConst: Copy + Debug + Hash + Eq; + type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq; // Kinds of regions type Region: Copy + DebugWithInfcx<Self> + Hash - + Ord + + Eq + Into<Self::GenericArg> + IntoKind<Kind = RegionKind<Self>> + Flags + new::Region<Self>; - type EarlyParamRegion: Copy + Debug + Hash + Ord; - type LateParamRegion: Copy + Debug + Hash + Ord; - type BoundRegion: Copy + Debug + Hash + Ord; - type InferRegion: Copy + DebugWithInfcx<Self> + Hash + Ord; - type PlaceholderRegion: Copy + Debug + Hash + Ord + PlaceholderLike; + type EarlyParamRegion: Copy + Debug + Hash + Eq; + type LateParamRegion: Copy + Debug + Hash + Eq; + type BoundRegion: Copy + Debug + Hash + Eq; + type InferRegion: Copy + DebugWithInfcx<Self> + Hash + Eq; + type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike; // Predicates type Predicate: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 2e8481df56d..e1247e2661a 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -113,15 +113,7 @@ use self::RegionKind::*; /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html #[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - PartialOrd(bound = ""), - PartialOrd = "feature_allow_slow_enum", - Ord(bound = ""), - Ord = "feature_allow_slow_enum", - Hash(bound = "") -)] +#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] pub enum RegionKind<I: Interner> { /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`. diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 5ed73cd94f4..fad67fe3cbb 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -63,15 +63,7 @@ impl AliasKind { /// converted to this representation using `<dyn HirTyLowerer>::lower_ty`. #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")] #[derive(derivative::Derivative)] -#[derivative( - Clone(bound = ""), - Copy(bound = ""), - PartialOrd(bound = ""), - PartialOrd = "feature_allow_slow_enum", - Ord(bound = ""), - Ord = "feature_allow_slow_enum", - Hash(bound = "") -)] +#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum TyKind<I: Interner> { /// The primitive boolean type. Written as `bool`. @@ -803,8 +795,6 @@ impl<I: Interner> DebugWithInfcx<I> for InferTy { #[derivative( Clone(bound = ""), Copy(bound = ""), - PartialOrd(bound = ""), - Ord(bound = ""), PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index cfaf533088a..7c3fa2312e5 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -161,7 +161,7 @@ use core::marker::Unsize; use core::mem::{self, SizedTypeProperties}; use core::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; use core::ops::{ - CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DispatchFromDyn, Receiver, + CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver, }; use core::pin::Pin; use core::ptr::{self, addr_of_mut, NonNull, Unique}; @@ -1939,6 +1939,9 @@ impl<T: ?Sized, A: Allocator> DerefMut for Box<T, A> { } } +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl<T: ?Sized, A: Allocator> DerefPure for Box<T, A> {} + #[unstable(feature = "receiver_trait", issue = "none")] impl<T: ?Sized, A: Allocator> Receiver for Box<T, A> {} diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index 0a894258f46..66eb991c6d4 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -354,7 +354,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { // SAFETY: There is no tree yet so no reference to it exists. let map = unsafe { self.dormant_map.awaken() }; let mut root = NodeRef::new_leaf(self.alloc.clone()); - let val_ptr = root.borrow_mut().push(self.key, value) as *mut V; + let val_ptr = root.borrow_mut().push(self.key, value); map.root = Some(root.forget_type()); map.length = 1; val_ptr diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 0c7f94ccceb..6a64eaf576b 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -408,7 +408,7 @@ impl CString { fn strlen(s: *const c_char) -> usize; } let len = strlen(ptr) + 1; // Including the NUL byte - let slice = slice::from_raw_parts_mut(ptr, len as usize); + let slice = slice::from_raw_parts_mut(ptr, len); CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) } } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 02d155aaf12..20b7d0afa87 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -122,6 +122,7 @@ #![feature(const_waker)] #![feature(core_intrinsics)] #![feature(deprecated_suggestion)] +#![feature(deref_pure_trait)] #![feature(dispatch_from_dyn)] #![feature(error_generic_member_access)] #![feature(error_in_core)] @@ -169,6 +170,7 @@ #![feature(unicode_internals)] #![feature(unsize)] #![feature(utf8_chunks)] +#![feature(vec_pop_if)] // tidy-alphabetical-end // // Language features: diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 0ee293db73a..175e23b543c 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -114,7 +114,10 @@ impl<T> RawVec<T, Global> { #[must_use] #[inline] pub fn with_capacity(capacity: usize) -> Self { - handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global)) + match Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global) { + Ok(res) => res, + Err(err) => handle_error(err), + } } /// Like `with_capacity`, but guarantees the buffer is zeroed. @@ -152,7 +155,10 @@ impl<T, A: Allocator> RawVec<T, A> { #[cfg(not(no_global_oom_handling))] #[inline] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { - handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)) + match Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc) { + Ok(res) => res, + Err(err) => handle_error(err), + } } /// Like `try_with_capacity`, but parameterized over the choice of @@ -167,7 +173,10 @@ impl<T, A: Allocator> RawVec<T, A> { #[cfg(not(no_global_oom_handling))] #[inline] pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { - handle_reserve(Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc)) + match Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc) { + Ok(res) => res, + Err(err) => handle_error(err), + } } /// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`. @@ -326,7 +335,9 @@ impl<T, A: Allocator> RawVec<T, A> { len: usize, additional: usize, ) { - handle_reserve(slf.grow_amortized(len, additional)); + if let Err(err) = slf.grow_amortized(len, additional) { + handle_error(err); + } } if self.needs_to_grow(len, additional) { @@ -339,7 +350,9 @@ impl<T, A: Allocator> RawVec<T, A> { #[cfg(not(no_global_oom_handling))] #[inline(never)] pub fn reserve_for_push(&mut self, len: usize) { - handle_reserve(self.grow_amortized(len, 1)); + if let Err(err) = self.grow_amortized(len, 1) { + handle_error(err); + } } /// The same as `reserve`, but returns on errors instead of panicking or aborting. @@ -373,7 +386,9 @@ impl<T, A: Allocator> RawVec<T, A> { /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] pub fn reserve_exact(&mut self, len: usize, additional: usize) { - handle_reserve(self.try_reserve_exact(len, additional)); + if let Err(err) = self.try_reserve_exact(len, additional) { + handle_error(err); + } } /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. @@ -404,7 +419,9 @@ impl<T, A: Allocator> RawVec<T, A> { /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] pub fn shrink_to_fit(&mut self, cap: usize) { - handle_reserve(self.shrink(cap)); + if let Err(err) = self.shrink(cap) { + handle_error(err); + } } } @@ -559,12 +576,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec<T, A> { // Central function for reserve error handling. #[cfg(not(no_global_oom_handling))] -#[inline] -fn handle_reserve<T>(result: Result<T, TryReserveError>) -> T { - match result.map_err(|e| e.kind()) { - Ok(res) => res, - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), +#[cold] +fn handle_error(e: TryReserveError) -> ! { + match e.kind() { + CapacityOverflow => capacity_overflow(), + AllocError { layout, .. } => handle_alloc_error(layout), } } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index facfc9d208e..569db54b137 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -260,7 +260,7 @@ use core::marker::{PhantomData, Unsize}; #[cfg(not(no_global_oom_handling))] use core::mem::size_of_val; use core::mem::{self, align_of_val_raw, forget, ManuallyDrop}; -use core::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; +use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] use core::pin::Pin; @@ -2126,6 +2126,9 @@ impl<T: ?Sized, A: Allocator> Deref for Rc<T, A> { } } +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl<T: ?Sized, A: Allocator> DerefPure for Rc<T, A> {} + #[unstable(feature = "receiver_trait", issue = "none")] impl<T: ?Sized> Receiver for Rc<T> {} diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 21d5dce04a0..ebe6f7e7caa 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -511,9 +511,9 @@ impl<T> [T] { while m > 0 { // `buf.extend(buf)`: unsafe { - ptr::copy_nonoverlapping( + ptr::copy_nonoverlapping::<T>( buf.as_ptr(), - (buf.as_mut_ptr() as *mut T).add(buf.len()), + (buf.as_mut_ptr()).add(buf.len()), buf.len(), ); // `buf` has capacity of `self.len() * n`. @@ -532,9 +532,9 @@ impl<T> [T] { // `buf.extend(buf[0 .. rem_len])`: unsafe { // This is non-overlapping since `2^expn > rem`. - ptr::copy_nonoverlapping( + ptr::copy_nonoverlapping::<T>( buf.as_ptr(), - (buf.as_mut_ptr() as *mut T).add(buf.len()), + (buf.as_mut_ptr()).add(buf.len()), rem_len, ); // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`). diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index c4dcff1b1c4..7464df268cc 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -260,7 +260,7 @@ use crate::vec::Vec; /// # Representation /// /// A `String` is made up of three components: a pointer to some bytes, a -/// length, and a capacity. The pointer points to an internal buffer `String` +/// length, and a capacity. The pointer points to the internal buffer which `String` /// uses to store its data. The length is the number of bytes currently stored /// in the buffer, and the capacity is the size of the buffer in bytes. As such, /// the length will always be less than or equal to the capacity. @@ -2479,6 +2479,9 @@ impl ops::Deref for String { } } +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl ops::DerefPure for String {} + #[stable(feature = "derefmut_for_string", since = "1.3.0")] impl ops::DerefMut for String { #[inline] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 7e3e2fb38b1..4dea27221b7 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -21,7 +21,7 @@ use core::marker::{PhantomData, Unsize}; #[cfg(not(no_global_oom_handling))] use core::mem::size_of_val; use core::mem::{self, align_of_val_raw}; -use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver}; +use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::Pin; use core::ptr::{self, NonNull}; @@ -2107,6 +2107,9 @@ impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> { } } +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl<T: ?Sized, A: Allocator> DerefPure for Arc<T, A> {} + #[unstable(feature = "receiver_trait", issue = "none")] impl<T: ?Sized> Receiver for Arc<T> {} diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index b40768a52b6..a3fa6585a37 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -148,7 +148,7 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker { unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker { unsafe { Arc::increment_strong_count(waker as *const W) }; RawWaker::new( - waker as *const (), + waker, &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>), ) } @@ -320,7 +320,7 @@ fn local_raw_waker<W: LocalWake + 'static>(waker: Rc<W>) -> RawWaker { unsafe fn clone_waker<W: LocalWake + 'static>(waker: *const ()) -> RawWaker { unsafe { Rc::increment_strong_count(waker as *const W) }; RawWaker::new( - waker as *const (), + waker, &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>), ) } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 94bed825bb2..8ca8046dac5 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2058,6 +2058,31 @@ impl<T, A: Allocator> Vec<T, A> { } } + /// Removes and returns the last element in a vector if the predicate + /// returns `true`, or [`None`] if the predicate returns false or the vector + /// is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_pop_if)] + /// + /// let mut vec = vec![1, 2, 3, 4]; + /// let pred = |x: &mut i32| *x % 2 == 0; + /// + /// assert_eq!(vec.pop_if(pred), Some(4)); + /// assert_eq!(vec, [1, 2, 3]); + /// assert_eq!(vec.pop_if(pred), None); + /// ``` + #[unstable(feature = "vec_pop_if", issue = "122741")] + pub fn pop_if<F>(&mut self, f: F) -> Option<T> + where + F: FnOnce(&mut T) -> bool, + { + let last = self.last_mut()?; + if f(last) { self.pop() } else { None } + } + /// Moves all the elements of `other` into `self`, leaving `other` empty. /// /// # Panics @@ -2772,6 +2797,9 @@ impl<T, A: Allocator> ops::DerefMut for Vec<T, A> { } } +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl<T, A: Allocator> ops::DerefPure for Vec<T, A> {} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index f58998fbd79..04709af5c0a 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -43,6 +43,7 @@ #![feature(strict_provenance)] #![feature(drain_keep_rest)] #![feature(local_waker)] +#![feature(vec_pop_if)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index f1f841fe190..71d79893e01 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -2644,6 +2644,36 @@ fn test_vec_from_array_mut_ref() { assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]); } +#[test] +fn test_pop_if() { + let mut v = vec![1, 2, 3, 4]; + let pred = |x: &mut i32| *x % 2 == 0; + + assert_eq!(v.pop_if(pred), Some(4)); + assert_eq!(v, [1, 2, 3]); + + assert_eq!(v.pop_if(pred), None); + assert_eq!(v, [1, 2, 3]); +} + +#[test] +fn test_pop_if_empty() { + let mut v = Vec::<i32>::new(); + assert_eq!(v.pop_if(|_| true), None); + assert!(v.is_empty()); +} + +#[test] +fn test_pop_if_mutates() { + let mut v = vec![1]; + let pred = |x: &mut i32| { + *x += 1; + false + }; + assert_eq!(v.pop_if(pred), None); + assert_eq!(v, [2]); +} + /// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments /// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but /// `vec.insert(usize::MAX, val)` once slipped by! diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index 3dc8c84e0bf..a02fcf50416 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -7,7 +7,8 @@ description = "The Rust Core Library" autotests = false autobenches = false # If you update this, be sure to update it in a bunch of other places too! -# As of 2022, it was the ci/pgo.sh script and the core-no-fp-fmt-parse test. +# As of 2024, it was src/tools/opt-dist, the core-no-fp-fmt-parse test and +# the version of the prelude imported in core/lib.rs. edition = "2021" [lib] diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index bdb6599abf5..bb668d2a673 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -1,5 +1,4 @@ use crate::cmp::BytewiseEq; -use crate::convert::TryInto; #[stable(feature = "rust1", since = "1.0.0")] impl<T, U, const N: usize> PartialEq<[U; N]> for [T; N] diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 8b5b48c59c2..2a447aafe72 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -6,7 +6,7 @@ use crate::borrow::{Borrow, BorrowMut}; use crate::cmp::Ordering; -use crate::convert::{Infallible, TryFrom}; +use crate::convert::Infallible; use crate::error::Error; use crate::fmt; use crate::hash::{self, Hash}; diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index 8f612929110..f0c2636307f 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -1,7 +1,6 @@ //! Character conversions. use crate::char::TryFromCharError; -use crate::convert::TryFrom; use crate::error::Error; use crate::fmt; use crate::mem::transmute; diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 46a9006c146..0167d04c413 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -1,4 +1,3 @@ -use super::TryFrom; use crate::num::TryFromIntError; mod private { @@ -323,7 +322,6 @@ impl_try_from_lower_bounded!(isize => usize); #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; - use crate::convert::TryFrom; impl_try_from_upper_bounded!(usize => u8); impl_try_from_unbounded!(usize => u16, u32, u64, u128); @@ -346,7 +344,6 @@ mod ptr_try_from_impls { #[cfg(target_pointer_width = "32")] mod ptr_try_from_impls { use super::TryFromIntError; - use crate::convert::TryFrom; impl_try_from_upper_bounded!(usize => u8, u16); impl_try_from_unbounded!(usize => u32, u64, u128); @@ -372,7 +369,6 @@ mod ptr_try_from_impls { #[cfg(target_pointer_width = "64")] mod ptr_try_from_impls { use super::TryFromIntError; - use crate::convert::TryFrom; impl_try_from_upper_bounded!(usize => u8, u16, u32); impl_try_from_unbounded!(usize => u64, u128); diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index 54ed4c952fb..b8b96417d13 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -1,4 +1,3 @@ -use crate::convert::TryFrom; use crate::{ intrinsics, iter::{from_fn, TrustedLen, TrustedRandomAccess}, diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 055ead117ea..5eea764b28a 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -1,5 +1,4 @@ use crate::ascii::Char as AsciiChar; -use crate::convert::TryFrom; use crate::mem; use crate::net::{Ipv4Addr, Ipv6Addr}; use crate::num::NonZero; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index e1904ed220c..d2c9e1554b4 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -8,11 +8,11 @@ use super::super::ByRefSized; use super::super::TrustedRandomAccessNoCoerce; use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; -use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip}; use super::super::{ Inspect, Map, MapWhile, MapWindows, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, }; +use super::super::{Intersperse, IntersperseWith, Product, Sum, Zip}; fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index f0448a98981..3bc1a87f848 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -270,6 +270,7 @@ #![feature(arm_target_feature)] #![feature(avx512_target_feature)] #![feature(hexagon_target_feature)] +#![feature(loongarch_target_feature)] #![feature(mips_target_feature)] #![feature(powerpc_target_feature)] #![feature(riscv_target_feature)] @@ -285,7 +286,7 @@ extern crate self as core; #[prelude_import] #[allow(unused)] -use prelude::v1::*; +use prelude::rust_2021::*; #[cfg(not(test))] // See #65860 #[macro_use] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index a78842c8f8d..574a357b44a 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1726,20 +1726,28 @@ pub(crate) mod builtin { builtin # deref($pat) } - /// Unstable implementation detail of the `rustc` compiler, do not use. + /// Derive macro for `rustc-serialize`. Should not be used in new code. #[rustc_builtin_macro] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics, libstd_sys_internals, rt)] + #[unstable( + feature = "rustc_encodable_decodable", + issue = "none", + soft, + reason = "derive macro for `rustc-serialize`; should not be used in new code" + )] #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. pub macro RustcDecodable($item:item) { /* compiler built-in */ } - /// Unstable implementation detail of the `rustc` compiler, do not use. + /// Derive macro for `rustc-serialize`. Should not be used in new code. #[rustc_builtin_macro] - #[stable(feature = "rust1", since = "1.0.0")] - #[allow_internal_unstable(core_intrinsics, rt)] + #[unstable( + feature = "rustc_encodable_decodable", + issue = "none", + soft, + reason = "derive macro for `rustc-serialize`; should not be used in new code" + )] #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. pub macro RustcEncodable($item:item) { diff --git a/library/core/src/net/parser.rs b/library/core/src/net/parser.rs index 835ab9d73af..deea8212448 100644 --- a/library/core/src/net/parser.rs +++ b/library/core/src/net/parser.rs @@ -3,7 +3,6 @@ //! This module is "publicly exported" through the `FromStr` implementations //! below. -use crate::convert::{TryFrom, TryInto}; use crate::error::Error; use crate::fmt; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index c65ffbb98f2..1171407c07a 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -20,7 +20,15 @@ use super::{IntErrorKind, ParseIntError}; /// /// # Safety /// -/// Types implementing this trait must be primitves that are valid when zeroed. +/// Types implementing this trait must be primitives that are valid when zeroed. +/// +/// The associated `Self::NonZeroInner` type must have the same size+align as `Self`, +/// but with a niche and bit validity making it so the following `transmutes` are sound: +/// +/// - `Self::NonZeroInner` to `Option<Self::NonZeroInner>` +/// - `Option<Self::NonZeroInner>` to `Self` +/// +/// (And, consequently, `Self::NonZeroInner` to `Self`.) #[unstable( feature = "nonzero_internals", reason = "implementation detail which may disappear or be replaced at any time", @@ -434,17 +442,11 @@ where // of some not-inlined function, LLVM don't have range metadata // to understand that the value cannot be zero. // - // SAFETY: `Self` is guaranteed to have the same layout as `Option<Self>`. - match unsafe { intrinsics::transmute_unchecked(self) } { - None => { - // SAFETY: `NonZero` is guaranteed to only contain non-zero values, so this is unreachable. - unsafe { intrinsics::unreachable() } - } - Some(Self(inner)) => { - // SAFETY: `T::NonZeroInner` is guaranteed to have the same layout as `T`. - unsafe { intrinsics::transmute_unchecked(inner) } - } - } + // For now, using the transmute `assume`s the range at runtime. + // + // SAFETY: `ZeroablePrimitive` guarantees that the size and bit validity + // of `.0` is such that this transmute is sound. + unsafe { intrinsics::transmute_unchecked(self) } } } diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 2c7845d4304..3795a81c2c1 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -275,6 +275,25 @@ impl<T: ?Sized> DerefMut for &mut T { } } +/// Perma-unstable marker trait. Indicates that the type has a well-behaved [`Deref`] +/// (and, if applicable, [`DerefMut`]) implementation. This is relied on for soundness +/// of deref patterns. +/// +/// FIXME(deref_patterns): The precise semantics are undecided; the rough idea is that +/// successive calls to `deref`/`deref_mut` without intermediate mutation should be +/// idempotent, in the sense that they return the same value as far as pattern-matching +/// is concerned. Calls to `deref`/`deref_mut`` must leave the pointer itself likewise +/// unchanged. +#[unstable(feature = "deref_pure_trait", issue = "87121")] +#[cfg_attr(not(bootstrap), lang = "deref_pure")] +pub unsafe trait DerefPure {} + +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl<T: ?Sized> DerefPure for &T {} + +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl<T: ?Sized> DerefPure for &mut T {} + /// Indicates that a struct can be used as a method receiver, without the /// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`, /// `Rc<T>`, `&T`, and `Pin<P>`. diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 4289a86f89b..ac808bec50e 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -165,6 +165,9 @@ pub use self::bit::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssig #[stable(feature = "rust1", since = "1.0.0")] pub use self::deref::{Deref, DerefMut}; +#[unstable(feature = "deref_pure_trait", issue = "87121")] +pub use self::deref::DerefPure; + #[unstable(feature = "receiver_trait", issue = "none")] pub use self::deref::Receiver; diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0083d15efae..631e1654ce0 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -553,7 +553,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::iter::{self, FromIterator, FusedIterator, TrustedLen}; +use crate::iter::{self, FusedIterator, TrustedLen}; use crate::panicking::{panic, panic_str}; use crate::pin::Pin; use crate::{ diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index d14cac9afb5..e843a5d5790 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -806,7 +806,7 @@ //! //! As a consequence, the struct *must not* be [`#[repr(packed)]`][packed]. //! -//! 3. *Structural Notice of Destruction.* You must uphold the the +//! 3. *Structural Notice of Destruction.* You must uphold the //! [`Drop` guarantee][drop-guarantee]: once your struct is pinned, the struct's storage cannot //! be re-used without calling the structurally-pinned fields' destructors, as well. //! diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/common.rs index 29f73bb4942..b98f3a4659b 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/common.rs @@ -1,9 +1,7 @@ -//! The first version of the core prelude. +//! Items common to the prelude of all editions. //! //! See the [module-level documentation](super) for more. -#![stable(feature = "core_prelude", since = "1.4.0")] - // Re-exported core operators #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] @@ -68,11 +66,6 @@ pub use crate::{ #[doc(no_inline)] pub use crate::concat_bytes; -// Do not `doc(inline)` these `doc(hidden)` items. -#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow(deprecated)] -pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; - // Do not `doc(no_inline)` so that they become doc items on their own // (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index b4791c2c022..ca33ef160e8 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -6,7 +6,26 @@ #![stable(feature = "core_prelude", since = "1.4.0")] -pub mod v1; +mod common; + +/// The first version of the prelude of The Rust Standard Library. +/// +/// See the [module-level documentation](self) for more. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod v1 { + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::common::*; + + // Do not `doc(inline)` these `doc(hidden)` items. + #[unstable( + feature = "rustc_encodable_decodable", + issue = "none", + soft, + reason = "derive macro for `rustc-serialize`; should not be used in new code" + )] + #[allow(deprecated)] + pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; +} /// The 2015 version of the core prelude. /// @@ -46,14 +65,21 @@ pub mod rust_2021 { pub use crate::convert::{TryFrom, TryInto}; } -/// The 2024 edition of the core prelude. +/// The 2024 version of the core prelude. /// /// See the [module-level documentation](self) for more. #[unstable(feature = "prelude_2024", issue = "121042")] pub mod rust_2024 { - #[unstable(feature = "prelude_2024", issue = "121042")] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::common::*; + + #[stable(feature = "prelude_2021", since = "1.55.0")] + #[doc(no_inline)] + pub use crate::iter::FromIterator; + + #[stable(feature = "prelude_2021", since = "1.55.0")] #[doc(no_inline)] - pub use super::rust_2021::*; + pub use crate::convert::{TryFrom, TryInto}; #[unstable(feature = "prelude_2024", issue = "121042")] #[doc(no_inline)] diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index bc84fb5ccb0..68fce3960c7 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -1,4 +1,3 @@ -use crate::convert::{TryFrom, TryInto}; use crate::num::NonZero; #[cfg(debug_assertions)] use crate::ub_checks::assert_unsafe_precondition; diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 6879ac03f70..b2b627fe6a9 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -488,7 +488,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::iter::{self, FromIterator, FusedIterator, TrustedLen}; +use crate::iter::{self, FusedIterator, TrustedLen}; use crate::ops::{self, ControlFlow, Deref, DerefMut}; use crate::{convert, fmt, hint}; diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 00e75ec9a25..77002ef87aa 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -243,7 +243,7 @@ const EMULATE_ATOMIC_BOOL: bool = /// A boolean type which can be safely shared between threads. /// -/// This type has the same in-memory representation as a [`bool`]. +/// This type has the same size, alignment, and bit validity as a [`bool`]. /// /// **Note**: This type is only available on platforms that support atomic /// loads and stores of `u8`. @@ -272,7 +272,7 @@ unsafe impl Sync for AtomicBool {} /// A raw pointer type which can be safely shared between threads. /// -/// This type has the same in-memory representation as a `*mut T`. +/// This type has the same size and bit validity as a `*mut T`. /// /// **Note**: This type is only available on platforms that support atomic /// loads and stores of pointers. Its size depends on the target pointer's size. @@ -2121,7 +2121,7 @@ macro_rules! atomic_int { $int_type:ident $atomic_type:ident) => { /// An integer type which can be safely shared between threads. /// - /// This type has the same in-memory representation as the underlying + /// This type has the same size and bit validity as the underlying /// integer type, [` #[doc = $s_int_type] /// `]. diff --git a/library/core/src/unit.rs b/library/core/src/unit.rs index 6656dd5c40b..d656005f3d4 100644 --- a/library/core/src/unit.rs +++ b/library/core/src/unit.rs @@ -1,5 +1,3 @@ -use crate::iter::FromIterator; - /// Collapses all unit items from an iterator into one. /// /// This is more useful when combined with higher-level abstractions, like diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs index 7a161b7e01d..48514e52587 100644 --- a/library/portable-simd/crates/core_simd/src/lib.rs +++ b/library/portable-simd/crates/core_simd/src/lib.rs @@ -45,10 +45,6 @@ #![unstable(feature = "portable_simd", issue = "86656")] //! Portable SIMD module. -#[prelude_import] -#[allow(unused_imports)] -use core::prelude::v1::*; - #[path = "mod.rs"] mod core_simd; pub use self::core_simd::simd; diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs index 6c8205b112c..8dbdfc0e1fe 100644 --- a/library/portable-simd/crates/core_simd/src/vector.rs +++ b/library/portable-simd/crates/core_simd/src/vector.rs @@ -4,7 +4,6 @@ use crate::simd::{ ptr::{SimdConstPtr, SimdMutPtr}, LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle, }; -use core::convert::{TryFrom, TryInto}; /// A SIMD vector with the shape of `[T; N]` but the operations of `T`. /// diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 8a1ba436f72..f3cfc41bac7 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -2,6 +2,7 @@ use super::*; +use std::cell::RefCell; use std::marker::PhantomData; use std::sync::atomic::AtomicU32; @@ -189,61 +190,61 @@ struct Bridge<'a> { impl<'a> !Send for Bridge<'a> {} impl<'a> !Sync for Bridge<'a> {} -enum BridgeState<'a> { - /// No server is currently connected to this client. - NotConnected, +#[allow(unsafe_code)] +mod state { + use super::Bridge; + use std::cell::{Cell, RefCell}; + use std::ptr; - /// A server is connected and available for requests. - Connected(Bridge<'a>), - - /// Access to the bridge is being exclusively acquired - /// (e.g., during `BridgeState::with`). - InUse, -} + thread_local! { + static BRIDGE_STATE: Cell<*const ()> = const { Cell::new(ptr::null()) }; + } -enum BridgeStateL {} + pub(super) fn set<'bridge, R>(state: &RefCell<Bridge<'bridge>>, f: impl FnOnce() -> R) -> R { + struct RestoreOnDrop(*const ()); + impl Drop for RestoreOnDrop { + fn drop(&mut self) { + BRIDGE_STATE.set(self.0); + } + } -impl<'a> scoped_cell::ApplyL<'a> for BridgeStateL { - type Out = BridgeState<'a>; -} + let inner = ptr::from_ref(state).cast(); + let outer = BRIDGE_STATE.replace(inner); + let _restore = RestoreOnDrop(outer); -thread_local! { - static BRIDGE_STATE: scoped_cell::ScopedCell<BridgeStateL> = - const { scoped_cell::ScopedCell::new(BridgeState::NotConnected) }; -} + f() + } -impl BridgeState<'_> { - /// Take exclusive control of the thread-local - /// `BridgeState`, and pass it to `f`, mutably. - /// The state will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - /// - /// N.B., while `f` is running, the thread-local state - /// is `BridgeState::InUse`. - fn with<R>(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R { - BRIDGE_STATE.with(|state| state.replace(BridgeState::InUse, f)) + pub(super) fn with<R>( + f: impl for<'bridge> FnOnce(Option<&RefCell<Bridge<'bridge>>>) -> R, + ) -> R { + let state = BRIDGE_STATE.get(); + // SAFETY: the only place where the pointer is set is in `set`. It puts + // back the previous value after the inner call has returned, so we know + // that as long as the pointer is not null, it came from a reference to + // a `RefCell<Bridge>` that outlasts the call to this function. Since `f` + // works the same for any lifetime of the bridge, including the actual + // one, we can lie here and say that the lifetime is `'static` without + // anyone noticing. + let bridge = unsafe { state.cast::<RefCell<Bridge<'static>>>().as_ref() }; + f(bridge) } } impl Bridge<'_> { fn with<R>(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R { - BridgeState::with(|state| match state { - BridgeState::NotConnected => { - panic!("procedural macro API is used outside of a procedural macro"); - } - BridgeState::InUse => { - panic!("procedural macro API is used while it's already in use"); - } - BridgeState::Connected(bridge) => f(bridge), + state::with(|state| { + let bridge = state.expect("procedural macro API is used outside of a procedural macro"); + let mut bridge = bridge + .try_borrow_mut() + .expect("procedural macro API is used while it's already in use"); + f(&mut bridge) }) } } pub(crate) fn is_available() -> bool { - BridgeState::with(|state| match state { - BridgeState::Connected(_) | BridgeState::InUse => true, - BridgeState::NotConnected => false, - }) + state::with(|s| s.is_some()) } /// A client-side RPC entry-point, which may be using a different `proc_macro` @@ -282,11 +283,7 @@ fn maybe_install_panic_hook(force_show_panics: bool) { HIDE_PANICS_DURING_EXPANSION.call_once(|| { let prev = panic::take_hook(); panic::set_hook(Box::new(move |info| { - let show = BridgeState::with(|state| match state { - BridgeState::NotConnected => true, - BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, - }); - if show { + if force_show_panics || !is_available() { prev(info) } })); @@ -312,29 +309,24 @@ fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>( let (globals, input) = <(ExpnGlobals<Span>, A)>::decode(reader, &mut ()); // Put the buffer we used for input back in the `Bridge` for requests. - let new_state = - BridgeState::Connected(Bridge { cached_buffer: buf.take(), dispatch, globals }); - - BRIDGE_STATE.with(|state| { - state.set(new_state, || { - let output = f(input); - - // Take the `cached_buffer` back out, for the output value. - buf = Bridge::with(|bridge| bridge.cached_buffer.take()); - - // HACK(eddyb) Separate encoding a success value (`Ok(output)`) - // from encoding a panic (`Err(e: PanicMessage)`) to avoid - // having handles outside the `bridge.enter(|| ...)` scope, and - // to catch panics that could happen while encoding the success. - // - // Note that panics should be impossible beyond this point, but - // this is defensively trying to avoid any accidental panicking - // reaching the `extern "C"` (which should `abort` but might not - // at the moment, so this is also potentially preventing UB). - buf.clear(); - Ok::<_, ()>(output).encode(&mut buf, &mut ()); - }) - }) + let state = RefCell::new(Bridge { cached_buffer: buf.take(), dispatch, globals }); + + let output = state::set(&state, || f(input)); + + // Take the `cached_buffer` back out, for the output value. + buf = RefCell::into_inner(state).cached_buffer; + + // HACK(eddyb) Separate encoding a success value (`Ok(output)`) + // from encoding a panic (`Err(e: PanicMessage)`) to avoid + // having handles outside the `bridge.enter(|| ...)` scope, and + // to catch panics that could happen while encoding the success. + // + // Note that panics should be impossible beyond this point, but + // this is defensively trying to avoid any accidental panicking + // reaching the `extern "C"` (which should `abort` but might not + // at the moment, so this is also potentially preventing UB). + buf.clear(); + Ok::<_, ()>(output).encode(&mut buf, &mut ()); })) .map_err(PanicMessage::from) .unwrap_or_else(|e| { diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 67c72cf98d4..8553e8d5e4f 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -154,7 +154,7 @@ macro_rules! reverse_decode { mod arena; #[allow(unsafe_code)] mod buffer; -#[forbid(unsafe_code)] +#[deny(unsafe_code)] pub mod client; #[allow(unsafe_code)] mod closure; @@ -166,8 +166,6 @@ mod handle; #[forbid(unsafe_code)] mod rpc; #[allow(unsafe_code)] -mod scoped_cell; -#[allow(unsafe_code)] mod selfless_reify; #[forbid(unsafe_code)] pub mod server; diff --git a/library/proc_macro/src/bridge/scoped_cell.rs b/library/proc_macro/src/bridge/scoped_cell.rs deleted file mode 100644 index a8b34143908..00000000000 --- a/library/proc_macro/src/bridge/scoped_cell.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! `Cell` variant for (scoped) existential lifetimes. - -use std::cell::Cell; -use std::mem; - -/// Type lambda application, with a lifetime. -#[allow(unused_lifetimes)] -pub trait ApplyL<'a> { - type Out; -} - -/// Type lambda taking a lifetime, i.e., `Lifetime -> Type`. -pub trait LambdaL: for<'a> ApplyL<'a> {} - -impl<T: for<'a> ApplyL<'a>> LambdaL for T {} - -pub struct ScopedCell<T: LambdaL>(Cell<<T as ApplyL<'static>>::Out>); - -impl<T: LambdaL> ScopedCell<T> { - pub const fn new(value: <T as ApplyL<'static>>::Out) -> Self { - ScopedCell(Cell::new(value)) - } - - /// Sets the value in `self` to `replacement` while - /// running `f`, which gets the old value, mutably. - /// The old value will be restored after `f` exits, even - /// by panic, including modifications made to it by `f`. - #[rustc_confusables("swap")] - pub fn replace<'a, R>( - &self, - replacement: <T as ApplyL<'a>>::Out, - f: impl for<'b, 'c> FnOnce(&'b mut <T as ApplyL<'c>>::Out) -> R, - ) -> R { - /// Wrapper that ensures that the cell always gets filled - /// (with the original state, optionally changed by `f`), - /// even if `f` had panicked. - struct PutBackOnDrop<'a, T: LambdaL> { - cell: &'a ScopedCell<T>, - value: Option<<T as ApplyL<'static>>::Out>, - } - - impl<'a, T: LambdaL> Drop for PutBackOnDrop<'a, T> { - fn drop(&mut self) { - self.cell.0.set(self.value.take().unwrap()); - } - } - - let mut put_back_on_drop = PutBackOnDrop { - cell: self, - value: Some(self.0.replace(unsafe { - let erased = mem::transmute_copy(&replacement); - mem::forget(replacement); - erased - })), - }; - - f(put_back_on_drop.value.as_mut().unwrap()) - } - - /// Sets the value in `self` to `value` while running `f`. - pub fn set<R>(&self, value: <T as ApplyL<'_>>::Out, f: impl FnOnce() -> R) -> R { - self.replace(value, |_| f()) - } -} diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 5d0de2d06a0..9017ba79714 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -97,7 +97,7 @@ use crate::time::SystemTime; /// have been opened for asynchronous I/O (e.g. by using `FILE_FLAG_OVERLAPPED`). /// /// [`BufReader`]: io::BufReader -/// [`BufWriter`]: io::BufReader +/// [`BufWriter`]: io::BufWriter /// [`sync_all`]: File::sync_all /// [`write`]: File::write /// [`read`]: File::read @@ -385,7 +385,7 @@ impl File { /// See the [`OpenOptions::open`] function for more details. /// /// See also [`std::fs::write()`][self::write] for a simple function to - /// create a file with a given data. + /// create a file with some given data. /// /// # Examples /// @@ -1036,7 +1036,7 @@ impl OpenOptions { /// [`OpenOptions::append`] access must be used. /// /// See also [`std::fs::write()`][self::write] for a simple function to - /// create a file with a given data. + /// create a file with some given data. /// /// # Examples /// diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index d67493aaf4d..9b01d232611 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -580,6 +580,10 @@ impl io::Read for UnixStream { io::Read::read(&mut &*self, buf) } + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + io::Read::read_buf(&mut &*self, buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { io::Read::read_vectored(&mut &*self, bufs) } @@ -596,6 +600,10 @@ impl<'a> io::Read for &'a UnixStream { self.0.read(buf) } + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf) + } + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.0.read_vectored(bufs) } diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/common.rs index 36fa4e88b5b..f61e04e02b6 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/common.rs @@ -1,9 +1,7 @@ -//! The first version of the prelude of The Rust Standard Library. +//! Items common to the prelude of all editions. //! //! See the [module-level documentation](super) for more. -#![stable(feature = "rust1", since = "1.0.0")] - // Re-exported core operators #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] @@ -52,11 +50,6 @@ pub use core::prelude::v1::{ #[doc(no_inline)] pub use core::prelude::v1::concat_bytes; -// Do not `doc(inline)` these `doc(hidden)` items. -#[stable(feature = "builtin_macro_prelude", since = "1.38.0")] -#[allow(deprecated)] -pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; - // Do not `doc(no_inline)` so that they become doc items on their own // (no public module for them to be re-exported from). #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 7d44d2e4b5d..0bdbab716ad 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -93,7 +93,26 @@ #![stable(feature = "rust1", since = "1.0.0")] -pub mod v1; +mod common; + +/// The first version of the prelude of The Rust Standard Library. +/// +/// See the [module-level documentation](self) for more. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod v1 { + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::common::*; + + // Do not `doc(inline)` these `doc(hidden)` items. + #[unstable( + feature = "rustc_encodable_decodable", + issue = "none", + soft, + reason = "derive macro for `rustc-serialize`; should not be used in new code" + )] + #[allow(deprecated)] + pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; +} /// The 2015 version of the prelude of The Rust Standard Library. /// @@ -134,9 +153,8 @@ pub mod rust_2021 { /// See the [module-level documentation](self) for more. #[unstable(feature = "prelude_2024", issue = "121042")] pub mod rust_2024 { - #[unstable(feature = "prelude_2024", issue = "121042")] - #[doc(no_inline)] - pub use super::v1::*; + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::common::*; #[unstable(feature = "prelude_2024", issue = "121042")] #[doc(no_inline)] diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index d648cd08994..e0a8a7603d7 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -31,13 +31,14 @@ use crate::sys::sync as sys; /// <details><summary>Potential deadlock example</summary> /// /// ```text -/// // Thread 1 | // Thread 2 -/// let _rg = lock.read(); | -/// | // will block -/// | let _wg = lock.write(); -/// // may deadlock | -/// let _rg = lock.read(); | +/// // Thread 1 | // Thread 2 +/// let _rg1 = lock.read(); | +/// | // will block +/// | let _wg = lock.write(); +/// // may deadlock | +/// let _rg2 = lock.read(); | /// ``` +/// /// </details> /// /// The type parameter `T` represents the data that this lock protects. It is diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index a1c0321876f..9d8cc18b838 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -167,6 +167,8 @@ impl FileDesc { } #[cfg(any( + target_os = "aix", + target_os = "dragonfly", // DragonFly 1.5 target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", @@ -174,6 +176,7 @@ impl FileDesc { target_os = "illumos", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", // OpenBSD 2.7 ))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { let ret = cvt(unsafe { @@ -188,7 +191,9 @@ impl FileDesc { } #[cfg(not(any( + target_os = "aix", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", @@ -199,6 +204,8 @@ impl FileDesc { target_os = "linux", target_os = "macos", target_os = "netbsd", + target_os = "openbsd", + target_os = "watchos", )))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { io::default_read_vectored(|b| self.read_at(b, offset), bufs) @@ -236,9 +243,10 @@ impl FileDesc { // no `syscall` possible in these platform. #[cfg(any( all(target_os = "android", target_pointer_width = "32"), - target_os = "ios", - target_os = "tvos", - target_os = "macos", + target_os = "ios", // ios 14.0 + target_os = "tvos", // tvos 14.0 + target_os = "macos", // macos 11.0 + target_os = "watchos", // watchos 7.0 ))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); @@ -318,6 +326,8 @@ impl FileDesc { } #[cfg(any( + target_os = "aix", + target_os = "dragonfly", // DragonFly 1.5 target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", @@ -325,6 +335,7 @@ impl FileDesc { target_os = "illumos", target_os = "linux", target_os = "netbsd", + target_os = "openbsd", // OpenBSD 2.7 ))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { let ret = cvt(unsafe { @@ -339,7 +350,9 @@ impl FileDesc { } #[cfg(not(any( + target_os = "aix", target_os = "android", + target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", target_os = "fuchsia", @@ -350,6 +363,8 @@ impl FileDesc { target_os = "linux", target_os = "macos", target_os = "netbsd", + target_os = "openbsd", + target_os = "watchos", )))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { io::default_write_vectored(|b| self.write_at(b, offset), bufs) @@ -387,9 +402,10 @@ impl FileDesc { // no `syscall` possible in these platform. #[cfg(any( all(target_os = "android", target_pointer_width = "32"), - target_os = "ios", - target_os = "tvos", - target_os = "macos", + target_os = "ios", // ios 14.0 + target_os = "tvos", // tvos 14.0 + target_os = "macos", // macos 11.0 + target_os = "watchos", // watchos 7.0 ))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index b968f8df34c..99b6da60c14 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -517,7 +517,7 @@ impl FileAttr { #[cfg(any(target_os = "horizon", target_os = "hurd"))] pub fn modified(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(self.stat.st_mtim)) + SystemTime::new(self.stat.st_mtim.tv_sec as i64, self.stat.st_mtim.tv_nsec as i64) } #[cfg(not(any( @@ -545,7 +545,7 @@ impl FileAttr { #[cfg(any(target_os = "horizon", target_os = "hurd"))] pub fn accessed(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(self.stat.st_atim)) + SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64) } #[cfg(any( diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index a3e1b6782e8..4cd7c0e3059 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -424,7 +424,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { if !set.is_null() { let mut count: usize = 0; if libc::pthread_getaffinity_np(libc::pthread_self(), libc::_cpuset_size(set), set) == 0 { - for i in 0..u64::MAX { + for i in 0..libc::cpuid_t::MAX { match libc::_cpuset_isset(i, set) { -1 => break, 0 => continue, diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 581c46af0ea..2d785064245 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -107,13 +107,13 @@ where pub fn sockaddr_to_addr(storage: &c::sockaddr_storage, len: usize) -> io::Result<SocketAddr> { match storage.ss_family as c_int { c::AF_INET => { - assert!(len as usize >= mem::size_of::<c::sockaddr_in>()); + assert!(len >= mem::size_of::<c::sockaddr_in>()); Ok(SocketAddr::V4(FromInner::from_inner(unsafe { *(storage as *const _ as *const c::sockaddr_in) }))) } c::AF_INET6 => { - assert!(len as usize >= mem::size_of::<c::sockaddr_in6>()); + assert!(len >= mem::size_of::<c::sockaddr_in6>()); Ok(SocketAddr::V6(FromInner::from_inner(unsafe { *(storage as *const _ as *const c::sockaddr_in6) }))) diff --git a/library/stdarch b/library/stdarch -Subproject 56087ea170d878a7a57b3a5725e0c00f5f5cad7 +Subproject 967e7afd87cbea3232581a4a55031134ab88f59 diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 012d64e5344..d9c7032d0db 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1003,6 +1003,7 @@ impl Step for PlainSourceTarball { // Vendor all Cargo dependencies let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("vendor") + .arg("--versioned-dirs") .arg("--sync") .arg(builder.src.join("./src/tools/cargo/Cargo.toml")) .arg("--sync") diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index f22a9ca604e..48596af7ca0 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -680,9 +680,13 @@ impl Step for Miri { .arg("--manifest-path") .arg(builder.src.join("src/tools/miri/test-cargo-miri/Cargo.toml")); cargo.arg("--target").arg(target.rustc_target_arg()); - cargo.arg("--tests"); // don't run doctests, they are too confused by the staging cargo.arg("--").args(builder.config.test_args()); + // `prepare_tool_cargo` sets RUSTDOC to the bootstrap wrapper and RUSTDOC_REAL to a dummy path as this is a "run", not a "test". + // Also, we want the rustdoc from the "next" stage for the same reason that we build a std from the next stage. + // So let's just set that here, and bypass bootstrap's RUSTDOC (just like cargo-miri already ignores bootstrap's RUSTC_WRAPPER). + cargo.env("RUSTDOC", builder.rustdoc(compiler_std)); + // Tell `cargo miri` where to find things. cargo.env("MIRI_SYSROOT", &miri_sysroot); cargo.env("MIRI_HOST_SYSROOT", sysroot); @@ -2601,8 +2605,12 @@ impl Step for Crate { let mode = self.mode; // See [field@compile::Std::force_recompile]. - builder.ensure(compile::Std::force_recompile(compiler, target)); - builder.ensure(RemoteCopyLibs { compiler, target }); + builder.ensure(compile::Std::force_recompile(compiler, compiler.host)); + + if builder.config.build != target { + builder.ensure(compile::Std::force_recompile(compiler, target)); + builder.ensure(RemoteCopyLibs { compiler, target }); + } // If we're not doing a full bootstrap but we're testing a stage2 // version of libstd, then what we're actually testing is the libstd diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject e1eead1181a691e56299294d5f1d62fe7a26d31 +Subproject 98b33e9a441457b0a491fe1be90e7de64eafc3e diff --git a/src/doc/reference b/src/doc/reference -Subproject 5afb503a4c1ea3c84370f8f4c08a1cddd1cdf6a +Subproject 984b36eca4b9293df04d5ba4eb5c4f77db0f51d diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject e093099709456e6fd74fecd2505fdf49a2471c1 +Subproject 7601e0c5ad29d5bd3b518700ea63fddfff5915a diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 8a5d647f19b08998612146b1cb2ca47083db63e +Subproject ffa246b7fd95a96e1cd54883e613aed42c32547 diff --git a/src/doc/unstable-book/src/language-features/adt-const-params.md b/src/doc/unstable-book/src/language-features/adt-const-params.md new file mode 100644 index 00000000000..208bf5e4c15 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/adt-const-params.md @@ -0,0 +1,35 @@ +# `adt_const_params` + +The tracking issue for this feature is: [#95174] + +[#95174]: https://github.com/rust-lang/rust/issues/95174 + +------------------------ + +Allows for using more complex types for const parameters, such as structs or enums. + +```rust +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(ConstParamTy, PartialEq, Eq)] +enum Foo { + A, + B, + C, +} + +#[derive(ConstParamTy, PartialEq, Eq)] +struct Bar { + flag: bool, +} + +fn is_foo_a_and_bar_true<const F: Foo, const B: Bar>() -> bool { + match (F, B.flag) { + (Foo::A, true) => true, + _ => false, + } +} +``` diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ef707d179ea..0cdf52bfb00 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -41,7 +41,7 @@ use std::hash::Hash; use std::mem; use thin_vec::ThinVec; -use crate::core::{self, DocContext, ImplTraitParam}; +use crate::core::{self, DocContext}; use crate::formats::item_type::ItemType; use crate::visit_ast::Module as DocModule; @@ -761,7 +761,7 @@ fn clean_ty_generics<'tcx>( ) -> Generics { // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses, // since `Clean for ty::Predicate` would consume them. - let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default(); + let mut impl_trait = BTreeMap::<u32, Vec<GenericBound>>::default(); // Bounds in the type_params and lifetimes fields are repeated in the // predicates field (see rustc_hir_analysis::collect::ty_generics), so remove @@ -778,7 +778,7 @@ fn clean_ty_generics<'tcx>( return None; } if synthetic { - impl_trait.insert(param.index.into(), vec![]); + impl_trait.insert(param.index, vec![]); return None; } Some(clean_generic_param_def(param, cx)) @@ -823,7 +823,7 @@ fn clean_ty_generics<'tcx>( })(); if let Some(param_idx) = param_idx - && let Some(bounds) = impl_trait.get_mut(¶m_idx.into()) + && let Some(bounds) = impl_trait.get_mut(¶m_idx) { let pred = clean_predicate(*pred, cx)?; @@ -847,7 +847,7 @@ fn clean_ty_generics<'tcx>( }) .collect::<Vec<_>>(); - for (param, mut bounds) in impl_trait { + for (idx, mut bounds) in impl_trait { let mut has_sized = false; bounds.retain(|b| { if b.is_sized_bound(cx) { @@ -870,7 +870,6 @@ fn clean_ty_generics<'tcx>( bounds.insert(0, GenericBound::sized(cx)); } - let crate::core::ImplTraitParam::ParamIndex(idx) = param else { unreachable!() }; if let Some(proj) = impl_trait_proj.remove(&idx) { for (trait_did, name, rhs) in proj { let rhs = clean_middle_term(rhs, cx); @@ -878,7 +877,7 @@ fn clean_ty_generics<'tcx>( } } - cx.impl_trait_bounds.insert(param, bounds); + cx.impl_trait_bounds.insert(idx.into(), bounds); } // Now that `cx.impl_trait_bounds` is populated, we can process diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index be7e319bc79..f078ad2fb53 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -460,8 +460,6 @@ impl Options { &matches.free[0] }); - let libs = - matches.opt_strs("L").iter().map(|s| SearchPath::from_cli_opt(early_dcx, s)).collect(); let externs = parse_externs(early_dcx, matches, &unstable_opts); let extern_html_root_urls = match parse_extern_html_roots(matches) { Ok(ex) => ex, @@ -625,6 +623,20 @@ impl Options { } let target = parse_target_triple(early_dcx, matches); + let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); + + let sysroot = match &maybe_sysroot { + Some(s) => s.clone(), + None => { + rustc_session::filesearch::get_or_default_sysroot().expect("Failed finding sysroot") + } + }; + + let libs = matches + .opt_strs("L") + .iter() + .map(|s| SearchPath::from_cli_opt(&sysroot, &target, early_dcx, s)) + .collect(); let show_coverage = matches.opt_present("show-coverage"); @@ -653,7 +665,6 @@ impl Options { let bin_crate = crate_types.contains(&CrateType::Executable); let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); let playground_url = matches.opt_str("playground-url"); - let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); let module_sorting = if matches.opt_present("sort-modules-by-appearance") { ModuleSorting::DeclarationOrder } else { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 80a30ac2727..25b78d9598d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -509,7 +509,7 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> { /// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter /// for `impl Trait` in argument position. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub(crate) enum ImplTraitParam { DefId(DefId), ParamIndex(u32), diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 5d4f1acc4b1..fbb521a6188 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1728,6 +1728,8 @@ fn item_variants( } w.write_str("</h3></section>"); + write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); + let heading_and_fields = match &variant_data.kind { clean::VariantKind::Struct(s) => { // If there is no field to display, no need to add the heading. @@ -1789,8 +1791,6 @@ fn item_variants( } w.write_str("</div>"); } - - write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); } write!(w, "</div>"); } diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index f153a908329..be2786c99ec 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -65,8 +65,9 @@ pub(crate) fn build_index<'tcx>( // Sort search index items. This improves the compressibility of the search index. cache.search_index.sort_unstable_by(|k1, k2| { // `sort_unstable_by_key` produces lifetime errors - let k1 = (&k1.path, k1.name.as_str(), &k1.ty, &k1.parent); - let k2 = (&k2.path, k2.name.as_str(), &k2.ty, &k2.parent); + // HACK(rustdoc): should not be sorting `CrateNum` or `DefIndex`, this will soon go away, too + let k1 = (&k1.path, k1.name.as_str(), &k1.ty, k1.parent.map(|id| (id.index, id.krate))); + let k2 = (&k2.path, k2.name.as_str(), &k2.ty, k2.parent.map(|id| (id.index, id.krate))); Ord::cmp(&k1, &k2) }); diff --git a/src/tools/cargo b/src/tools/cargo -Subproject d438c80c45c24be676ef5867edc79d0a14910ef +Subproject 499a61ce7a0fc6a72040084862a68b2603e770e diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index 07fbb1cb5c9..981a76d683d 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -83,7 +83,10 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { LitFloatType::Unsuffixed => None, }; let (is_whole, is_inf, mut float_str) = match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => { + // FIXME(f16_f128): do a check like the others when parsing is available + return; + }, FloatTy::F32 => { let value = sym_str.parse::<f32>().unwrap(); @@ -94,7 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) }, - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => { + // FIXME(f16_f128): do a check like the others when parsing is available + return; + }, }; if is_inf { @@ -139,10 +145,11 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { #[must_use] fn max_digits(fty: FloatTy) -> u32 { match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + // FIXME(f16_f128): replace the magic numbers once `{f16,f128}::DIGITS` are available + FloatTy::F16 => 3, FloatTy::F32 => f32::DIGITS, FloatTy::F64 => f64::DIGITS, - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => 33, } } diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index bc5dd10cad0..e58d4776427 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node}; -use rustc_hir_typeck::{FnCtxt, Inherited}; +use rustc_hir_typeck::{FnCtxt, TypeckRootCtxt}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; @@ -438,8 +438,8 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind && let output_ty = return_ty(cx, item.owner_id) - && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id) - && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id) + && let root_ctxt = TypeckRootCtxt::new(cx.tcx, item.owner_id.def_id) + && let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, item.owner_id.def_id) && fn_ctxt.can_coerce(ty, output_ty) { if has_lifetime(output_ty) && has_lifetime(ty) { diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 7a7bb9f9c94..15f1890aa39 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -1,6 +1,6 @@ use rustc_hir as hir; use rustc_hir::Expr; -use rustc_hir_typeck::{cast, FnCtxt, Inherited}; +use rustc_hir_typeck::{cast, FnCtxt, TypeckRootCtxt}; use rustc_lint::LateContext; use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::Ty; @@ -34,8 +34,8 @@ pub(super) fn check_cast<'tcx>( let hir_id = e.hir_id; let local_def_id = hir_id.owner.def_id; - let inherited = Inherited::new(cx.tcx, local_def_id); - let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, local_def_id); + let root_ctxt = TypeckRootCtxt::new(cx.tcx, local_def_id); + let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, local_def_id); if let Ok(check) = cast::CastCheck::new( &fn_ctxt, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 6ff47dbffbc..e414bc384f1 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -691,9 +691,9 @@ pub fn line_directive<'line>( } } -/// This is generated by collecting directives from ui tests and then extracting their directive -/// names. This is **not** an exhaustive list of all possible directives. Instead, this is a -/// best-effort approximation for diagnostics. +/// This was originally generated by collecting directives from ui tests and then extracting their +/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is +/// a best-effort approximation for diagnostics. Add new headers to this list when needed. const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ // tidy-alphabetical-start "assembly-output", @@ -708,6 +708,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "check-run-results", "check-stdout", "check-test-line-numbers-match", + "compare-output-lines-by-subset", "compile-flags", "dont-check-compiler-stderr", "dont-check-compiler-stdout", @@ -826,6 +827,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-sanitizer-cfi", "needs-sanitizer-dataflow", "needs-sanitizer-hwaddress", + "needs-sanitizer-kcfi", "needs-sanitizer-leak", "needs-sanitizer-memory", "needs-sanitizer-memtag", @@ -835,6 +837,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-sanitizer-thread", "needs-threads", "needs-unwind", + "needs-wasmtime", "needs-xray", "no-prefer-dynamic", "normalize-stderr-32bit", @@ -870,6 +873,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-unix", "only-wasm32", "only-wasm32-bare", + "only-wasm32-wasip1", "only-windows", "only-x86", "only-x86_64", diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index d7c74038aea..db154932d5b 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -149,6 +149,11 @@ pub(super) fn handle_needs( condition: config.target_cfg().relocation_model == "pic", ignore_reason: "ignored on targets without PIC relocation model", }, + Need { + name: "needs-wasmtime", + condition: config.runner.as_ref().is_some_and(|r| r.contains("wasmtime")), + ignore_reason: "ignored when wasmtime runner is not available", + }, ]; let (name, comment) = match ln.split_once([':', ' ']) { diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index b043805291e..26e55b89708 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -505,6 +505,8 @@ binaries, and as such worth documenting: * `MIRI_LOCAL_CRATES` is set by `cargo-miri` to tell the Miri driver which crates should be given special treatment in diagnostics, in addition to the crate currently being compiled. +* `MIRI_ORIG_RUSTDOC` is set and read by different phases of `cargo-miri` to remember the + value of `RUSTDOC` from before it was overwritten. * `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to perform verbose logging. * `MIRI_HOST_SYSROOT` is set by bootstrap to tell `cargo-miri` which sysroot to use for *host* diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs index e547599d954..8c0f605fd6e 100644 --- a/src/tools/miri/cargo-miri/src/phases.rs +++ b/src/tools/miri/cargo-miri/src/phases.rs @@ -202,6 +202,9 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) { cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases! // Set rustdoc to us as well, so we can run doctests. + if let Some(orig_rustdoc) = env::var_os("RUSTDOC") { + cmd.env("MIRI_ORIG_RUSTDOC", orig_rustdoc); + } cmd.env("RUSTDOC", &cargo_miri_path); cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); @@ -581,9 +584,10 @@ pub fn phase_rustdoc(mut args: impl Iterator<Item = String>) { let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); - // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; - // just default to a straight-forward invocation for now: - let mut cmd = Command::new("rustdoc"); + // phase_cargo_miri sets the RUSTDOC env var to ourselves, and puts a backup + // of the old value into MIRI_ORIG_RUSTDOC. So that's what we have to invoke now. + let rustdoc = env::var("MIRI_ORIG_RUSTDOC").unwrap_or("rustdoc".to_string()); + let mut cmd = Command::new(rustdoc); let extern_flag = "--extern"; let runtool_flag = "--runtool"; diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 4904a489eae..8fffb91542f 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -364,6 +364,10 @@ fn main() { let args = rustc_driver::args::raw_args(&early_dcx) .unwrap_or_else(|_| std::process::exit(rustc_driver::EXIT_FAILURE)); + // Install the ctrlc handler that sets `rustc_const_eval::CTRL_C_RECEIVED`, even if + // MIRI_BE_RUSTC is set. + rustc_driver::install_ctrlc_handler(); + // If the environment asks us to actually be rustc, then do that. if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") { // Earliest rustc setup. diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 805c0580b2f..e2e18d3a734 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -3,12 +3,13 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::num::TryFromIntError; -use std::sync::atomic::{AtomicBool, Ordering::Relaxed}; +use std::sync::atomic::Ordering::Relaxed; use std::task::Poll; use std::time::{Duration, SystemTime}; use either::Either; +use rustc_const_eval::CTRL_C_RECEIVED; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::{Idx, IndexVec}; @@ -1045,21 +1046,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Run the core interpreter loop. Returns only when an interrupt occurs (an error or program /// termination). fn run_threads(&mut self) -> InterpResult<'tcx, !> { - static SIGNALED: AtomicBool = AtomicBool::new(false); - ctrlc::set_handler(move || { - // Indicate that we have ben 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 SIGNALED.swap(true, Relaxed) { - std::process::exit(1); - } - }) - .unwrap(); - let this = self.eval_context_mut(); + let this = self.eval_context_mut(); loop { - if SIGNALED.load(Relaxed) { + if CTRL_C_RECEIVED.load(Relaxed) { this.machine.handle_abnormal_termination(); std::process::exit(1); } diff --git a/src/tools/miri/tests/pass/async-closure-drop.rs b/src/tools/miri/tests/pass/async-closure-drop.rs new file mode 100644 index 00000000000..9b2fc2948bf --- /dev/null +++ b/src/tools/miri/tests/pass/async-closure-drop.rs @@ -0,0 +1,40 @@ +#![feature(async_closure, noop_waker, async_fn_traits)] + +use std::future::Future; +use std::pin::pin; +use std::task::*; + +pub fn block_on<T>(fut: impl Future<Output = T>) -> T { + let mut fut = pin!(fut); + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match fut.as_mut().poll(ctx) { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} + +async fn call_once(f: impl async FnOnce(DropMe)) { + f(DropMe("world")).await; +} + +#[derive(Debug)] +struct DropMe(&'static str); + +impl Drop for DropMe { + fn drop(&mut self) { + println!("{}", self.0); + } +} + +pub fn main() { + block_on(async { + let b = DropMe("hello"); + let async_closure = async move |a: DropMe| { + println!("{a:?} {b:?}"); + }; + call_once(async_closure).await; + }); +} diff --git a/src/tools/miri/tests/pass/async-closure-drop.stdout b/src/tools/miri/tests/pass/async-closure-drop.stdout new file mode 100644 index 00000000000..34cfdedc44a --- /dev/null +++ b/src/tools/miri/tests/pass/async-closure-drop.stdout @@ -0,0 +1,3 @@ +DropMe("world") DropMe("hello") +world +hello diff --git a/src/tools/miri/tests/pass/async-closure.rs b/src/tools/miri/tests/pass/async-closure.rs index 9b2fc2948bf..2f7ec2b9e6f 100644 --- a/src/tools/miri/tests/pass/async-closure.rs +++ b/src/tools/miri/tests/pass/async-closure.rs @@ -1,6 +1,7 @@ #![feature(async_closure, noop_waker, async_fn_traits)] use std::future::Future; +use std::ops::{AsyncFnMut, AsyncFnOnce}; use std::pin::pin; use std::task::*; @@ -16,25 +17,36 @@ pub fn block_on<T>(fut: impl Future<Output = T>) -> T { } } -async fn call_once(f: impl async FnOnce(DropMe)) { - f(DropMe("world")).await; +async fn call_mut(f: &mut impl AsyncFnMut(i32)) { + f(0).await; } -#[derive(Debug)] -struct DropMe(&'static str); +async fn call_once(f: impl AsyncFnOnce(i32)) { + f(1).await; +} -impl Drop for DropMe { - fn drop(&mut self) { - println!("{}", self.0); - } +async fn call_normal<F: Future<Output = ()>>(f: &impl Fn(i32) -> F) { + f(0).await; +} + +async fn call_normal_once<F: Future<Output = ()>>(f: impl FnOnce(i32) -> F) { + f(1).await; } pub fn main() { block_on(async { - let b = DropMe("hello"); - let async_closure = async move |a: DropMe| { - println!("{a:?} {b:?}"); + let b = 2i32; + let mut async_closure = async move |a: i32| { + println!("{a} {b}"); }; + call_mut(&mut async_closure).await; call_once(async_closure).await; + + // No-capture closures implement `Fn`. + let async_closure = async move |a: i32| { + println!("{a}"); + }; + call_normal(&async_closure).await; + call_normal_once(async_closure).await; }); } diff --git a/src/tools/miri/tests/pass/async-closure.stdout b/src/tools/miri/tests/pass/async-closure.stdout index 34cfdedc44a..7baae1aa94f 100644 --- a/src/tools/miri/tests/pass/async-closure.stdout +++ b/src/tools/miri/tests/pass/async-closure.stdout @@ -1,3 +1,4 @@ -DropMe("world") DropMe("hello") -world -hello +0 2 +1 2 +0 +1 diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 419b04231b5..7975677286d 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -1,19 +1,21 @@ +pub mod run; +pub mod rustc; +pub mod rustdoc; + use std::env; -use std::path::{Path, PathBuf}; -use std::process::{Command, Output}; +use std::path::PathBuf; +use std::process::Output; pub use object; pub use wasmparser; -pub fn out_dir() -> PathBuf { - env::var_os("TMPDIR").unwrap().into() -} +pub use run::{run, run_fail}; +pub use rustc::{aux_build, rustc, Rustc}; +pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; -fn setup_common_build_cmd(command: &str) -> Command { - let rustc = env::var(command).unwrap(); - let mut cmd = Command::new(rustc); - cmd.arg("--out-dir").arg(out_dir()).arg("-L").arg(out_dir()); - cmd +/// Path of `TMPDIR` (a temporary build directory, not under `/tmp`). +pub fn tmp_dir() -> PathBuf { + env::var_os("TMPDIR").unwrap().into() } fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! { @@ -24,170 +26,3 @@ fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap()); std::process::exit(1) } - -pub fn rustc() -> RustcInvocationBuilder { - RustcInvocationBuilder::new() -} - -pub fn aux_build() -> AuxBuildInvocationBuilder { - AuxBuildInvocationBuilder::new() -} - -pub fn rustdoc() -> Rustdoc { - Rustdoc::new() -} - -#[derive(Debug)] -pub struct RustcInvocationBuilder { - cmd: Command, -} - -impl RustcInvocationBuilder { - fn new() -> Self { - let cmd = setup_common_build_cmd("RUSTC"); - Self { cmd } - } - - pub fn arg(&mut self, arg: &str) -> &mut RustcInvocationBuilder { - self.cmd.arg(arg); - self - } - - pub fn args(&mut self, args: &[&str]) -> &mut RustcInvocationBuilder { - self.cmd.args(args); - self - } - - #[track_caller] - pub fn run(&mut self) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let output = self.cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); - } - output - } -} - -#[derive(Debug)] -pub struct AuxBuildInvocationBuilder { - cmd: Command, -} - -impl AuxBuildInvocationBuilder { - fn new() -> Self { - let mut cmd = setup_common_build_cmd("RUSTC"); - cmd.arg("--crate-type=lib"); - Self { cmd } - } - - pub fn arg(&mut self, arg: &str) -> &mut AuxBuildInvocationBuilder { - self.cmd.arg(arg); - self - } - - #[track_caller] - pub fn run(&mut self) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let output = self.cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); - } - output - } -} - -#[derive(Debug)] -pub struct Rustdoc { - cmd: Command, -} - -impl Rustdoc { - fn new() -> Self { - let cmd = setup_common_build_cmd("RUSTDOC"); - Self { cmd } - } - - pub fn arg(&mut self, arg: &str) -> &mut Self { - self.cmd.arg(arg); - self - } - - #[track_caller] - pub fn run(&mut self) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let output = self.cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); - } - output - } -} - -fn run_common(bin_name: &str) -> (Command, Output) { - let target = env::var("TARGET").unwrap(); - - let bin_name = - if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() }; - - let mut bin_path = PathBuf::new(); - bin_path.push(env::var("TMPDIR").unwrap()); - bin_path.push(&bin_name); - let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); - let mut cmd = Command::new(bin_path); - cmd.env(&ld_lib_path_envvar, { - let mut paths = vec![]; - paths.push(PathBuf::from(env::var("TMPDIR").unwrap())); - for p in env::split_paths(&env::var("TARGET_RPATH_ENV").unwrap()) { - paths.push(p.to_path_buf()); - } - for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) { - paths.push(p.to_path_buf()); - } - env::join_paths(paths.iter()).unwrap() - }); - - if target.contains("windows") { - let mut paths = vec![]; - for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) { - paths.push(p.to_path_buf()); - } - paths.push(Path::new(&std::env::var("TARGET_RPATH_DIR").unwrap()).to_path_buf()); - cmd.env("PATH", env::join_paths(paths.iter()).unwrap()); - } - - let output = cmd.output().unwrap(); - (cmd, output) -} - -/// Run a built binary and make sure it succeeds. -#[track_caller] -pub fn run(bin_name: &str) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let (cmd, output) = run_common(bin_name); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); - } - output -} - -/// Run a built binary and make sure it fails. -#[track_caller] -pub fn run_fail(bin_name: &str) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let (cmd, output) = run_common(bin_name); - if output.status.success() { - handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); - } - output -} diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs new file mode 100644 index 00000000000..42dcf54da22 --- /dev/null +++ b/src/tools/run-make-support/src/run.rs @@ -0,0 +1,67 @@ +use std::env; +use std::path::{Path, PathBuf}; +use std::process::{Command, Output}; + +use super::handle_failed_output; + +fn run_common(bin_name: &str) -> (Command, Output) { + let target = env::var("TARGET").unwrap(); + + let bin_name = + if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() }; + + let mut bin_path = PathBuf::new(); + bin_path.push(env::var("TMPDIR").unwrap()); + bin_path.push(&bin_name); + let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); + let mut cmd = Command::new(bin_path); + cmd.env(&ld_lib_path_envvar, { + let mut paths = vec![]; + paths.push(PathBuf::from(env::var("TMPDIR").unwrap())); + for p in env::split_paths(&env::var("TARGET_RPATH_ENV").unwrap()) { + paths.push(p.to_path_buf()); + } + for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) { + paths.push(p.to_path_buf()); + } + env::join_paths(paths.iter()).unwrap() + }); + + if target.contains("windows") { + let mut paths = vec![]; + for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) { + paths.push(p.to_path_buf()); + } + paths.push(Path::new(&std::env::var("TARGET_RPATH_DIR").unwrap()).to_path_buf()); + cmd.env("PATH", env::join_paths(paths.iter()).unwrap()); + } + + let output = cmd.output().unwrap(); + (cmd, output) +} + +/// Run a built binary and make sure it succeeds. +#[track_caller] +pub fn run(bin_name: &str) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let (cmd, output) = run_common(bin_name); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); + } + output +} + +/// Run a built binary and make sure it fails. +#[track_caller] +pub fn run_fail(bin_name: &str) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let (cmd, output) = run_common(bin_name); + if output.status.success() { + handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); + } + output +} diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs new file mode 100644 index 00000000000..d0ab8df42d2 --- /dev/null +++ b/src/tools/run-make-support/src/rustc.rs @@ -0,0 +1,147 @@ +use std::env; +use std::path::Path; +use std::process::{Command, Output}; + +use crate::{handle_failed_output, tmp_dir}; + +/// Construct a new `rustc` invocation. +pub fn rustc() -> Rustc { + Rustc::new() +} + +/// Construct a new `rustc` aux-build invocation. +pub fn aux_build() -> Rustc { + Rustc::new_aux_build() +} + +/// A `rustc` invocation builder. +#[derive(Debug)] +pub struct Rustc { + cmd: Command, +} + +fn setup_common() -> Command { + let rustc = env::var("RUSTC").unwrap(); + let mut cmd = Command::new(rustc); + cmd.arg("--out-dir").arg(tmp_dir()).arg("-L").arg(tmp_dir()); + cmd +} + +impl Rustc { + // `rustc` invocation constructor methods + + /// Construct a new `rustc` invocation. + pub fn new() -> Self { + let cmd = setup_common(); + Self { cmd } + } + + /// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`). + pub fn new_aux_build() -> Self { + let mut cmd = setup_common(); + cmd.arg("--crate-type=lib"); + Self { cmd } + } + + // Argument provider methods + + /// Configure the compilation environment. + pub fn cfg(&mut self, s: &str) -> &mut Self { + self.cmd.arg("--cfg"); + self.cmd.arg(s); + self + } + + /// Specify default optimization level `-O` (alias for `-C opt-level=2`). + pub fn opt(&mut self) -> &mut Self { + self.cmd.arg("-O"); + self + } + + /// Specify type(s) of output files to generate. + pub fn emit(&mut self, kinds: &str) -> &mut Self { + self.cmd.arg(format!("--emit={kinds}")); + self + } + + /// Specify where an external library is located. + pub fn extern_<P: AsRef<Path>>(&mut self, crate_name: &str, path: P) -> &mut Self { + assert!( + !crate_name.contains(|c: char| c.is_whitespace() || c == '\\' || c == '/'), + "crate name cannot contain whitespace or path separators" + ); + + let path = path.as_ref().to_string_lossy(); + + self.cmd.arg("--extern"); + self.cmd.arg(format!("{crate_name}={path}")); + + self + } + + /// Specify path to the input file. + pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } + + /// Specify target triple. + pub fn target(&mut self, target: &str) -> &mut Self { + assert!(!target.contains(char::is_whitespace), "target triple cannot contain spaces"); + self.cmd.arg(format!("--target={target}")); + self + } + + /// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. + /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>` + /// is passed (note the space). + pub fn arg(&mut self, arg: &str) -> &mut Self { + assert!( + !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")), + "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`" + ); + self.cmd.arg(arg); + self + } + + /// Generic command arguments provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. + /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>` + /// is passed (note the space). + pub fn args(&mut self, args: &[&str]) -> &mut Self { + for arg in args { + assert!( + !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")), + "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`" + ); + } + + self.cmd.args(args); + self + } + + // Command inspection, output and running helper methods + + /// Get the [`Output`][std::process::Output] of the finished `rustc` process. + pub fn output(&mut self) -> Output { + self.cmd.output().unwrap() + } + + /// Run the constructed `rustc` command and assert that it is successfully run. + #[track_caller] + pub fn run(&mut self) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); + } + output + } + + /// Inspect what the underlying [`Command`] is up to the current construction. + pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self { + f(&self.cmd); + self + } +} diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs new file mode 100644 index 00000000000..9607ff02f96 --- /dev/null +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -0,0 +1,80 @@ +use std::env; +use std::path::Path; +use std::process::{Command, Output}; + +use crate::handle_failed_output; + +/// Construct a plain `rustdoc` invocation with no flags set. +pub fn bare_rustdoc() -> Rustdoc { + Rustdoc::bare() +} + +/// Construct a new `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set. +pub fn rustdoc() -> Rustdoc { + Rustdoc::new() +} + +#[derive(Debug)] +pub struct Rustdoc { + cmd: Command, +} + +fn setup_common() -> Command { + let rustdoc = env::var("RUSTDOC").unwrap(); + Command::new(rustdoc) +} + +impl Rustdoc { + /// Construct a bare `rustdoc` invocation. + pub fn bare() -> Self { + let cmd = setup_common(); + Self { cmd } + } + + /// Construct a `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set. + pub fn new() -> Self { + let mut cmd = setup_common(); + let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap(); + cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy())); + Self { cmd } + } + + /// Specify path to the input file. + pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } + + /// Specify output directory. + pub fn out_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + self.cmd.arg("--out-dir").arg(path.as_ref()); + self + } + + /// Given a `path`, pass `@{path}` to `rustdoc` as an + /// [arg file](https://doc.rust-lang.org/rustdoc/command-line-arguments.html#path-load-command-line-flags-from-a-path). + pub fn arg_file<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + self.cmd.arg(format!("@{}", path.as_ref().display())); + self + } + + /// Fallback argument provider. Consider adding meaningfully named methods instead of using + /// this method. + pub fn arg(&mut self, arg: &str) -> &mut Self { + self.cmd.arg(arg); + self + } + + /// Run the build `rustdoc` command and assert that the run is successful. + #[track_caller] + pub fn run(&mut self) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); + } + output + } +} diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt new file mode 100644 index 00000000000..bdee3afa6b7 --- /dev/null +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -0,0 +1,337 @@ +run-make/alloc-no-oom-handling/Makefile +run-make/alloc-no-rc/Makefile +run-make/alloc-no-sync/Makefile +run-make/allocator-shim-circular-deps/Makefile +run-make/allow-non-lint-warnings-cmdline/Makefile +run-make/allow-warnings-cmdline-stability/Makefile +run-make/archive-duplicate-names/Makefile +run-make/arguments-non-c-like-enum/Makefile +run-make/atomic-lock-free/Makefile +run-make/bare-outfile/Makefile +run-make/branch-protection-check-IBT/Makefile +run-make/c-dynamic-dylib/Makefile +run-make/c-dynamic-rlib/Makefile +run-make/c-link-to-rust-dylib/Makefile +run-make/c-link-to-rust-staticlib/Makefile +run-make/c-link-to-rust-va-list-fn/Makefile +run-make/c-static-dylib/Makefile +run-make/c-static-rlib/Makefile +run-make/c-unwind-abi-catch-lib-panic/Makefile +run-make/c-unwind-abi-catch-panic/Makefile +run-make/cat-and-grep-sanity-check/Makefile +run-make/cdylib-dylib-linkage/Makefile +run-make/cdylib-fewer-symbols/Makefile +run-make/cdylib/Makefile +run-make/codegen-options-parsing/Makefile +run-make/comment-section/Makefile +run-make/compile-stdin/Makefile +run-make/compiler-lookup-paths-2/Makefile +run-make/compiler-lookup-paths/Makefile +run-make/compiler-rt-works-on-mingw/Makefile +run-make/compressed-debuginfo/Makefile +run-make/const-prop-lint/Makefile +run-make/const_fn_mir/Makefile +run-make/core-no-fp-fmt-parse/Makefile +run-make/core-no-oom-handling/Makefile +run-make/crate-data-smoke/Makefile +run-make/crate-hash-rustc-version/Makefile +run-make/crate-name-priority/Makefile +run-make/cross-lang-lto-clang/Makefile +run-make/cross-lang-lto-pgo-smoketest/Makefile +run-make/cross-lang-lto-upstream-rlibs/Makefile +run-make/cross-lang-lto/Makefile +run-make/debug-assertions/Makefile +run-make/debugger-visualizer-dep-info/Makefile +run-make/dep-graph/Makefile +run-make/dep-info-doesnt-run-much/Makefile +run-make/dep-info-spaces/Makefile +run-make/dep-info/Makefile +run-make/doctests-keep-binaries/Makefile +run-make/doctests-runtool/Makefile +run-make/dump-ice-to-disk/Makefile +run-make/dump-mono-stats/Makefile +run-make/duplicate-output-flavors/Makefile +run-make/dylib-chain/Makefile +run-make/emit-named-files/Makefile +run-make/emit-path-unhashed/Makefile +run-make/emit-shared-files/Makefile +run-make/emit-stack-sizes/Makefile +run-make/emit-to-stdout/Makefile +run-make/emit/Makefile +run-make/env-dep-info/Makefile +run-make/error-found-staticlib-instead-crate/Makefile +run-make/error-writing-dependencies/Makefile +run-make/exit-code/Makefile +run-make/export-executable-symbols/Makefile +run-make/extern-diff-internal-name/Makefile +run-make/extern-flag-disambiguates/Makefile +run-make/extern-flag-fun/Makefile +run-make/extern-flag-pathless/Makefile +run-make/extern-flag-rename-transitive/Makefile +run-make/extern-fn-explicit-align/Makefile +run-make/extern-fn-generic/Makefile +run-make/extern-fn-mangle/Makefile +run-make/extern-fn-reachable/Makefile +run-make/extern-fn-struct-passing-abi/Makefile +run-make/extern-fn-with-extern-types/Makefile +run-make/extern-fn-with-packed-struct/Makefile +run-make/extern-fn-with-union/Makefile +run-make/extern-multiple-copies/Makefile +run-make/extern-multiple-copies2/Makefile +run-make/extern-overrides-distribution/Makefile +run-make/extra-filename-with-temp-outputs/Makefile +run-make/fmt-write-bloat/Makefile +run-make/forced-unwind-terminate-pof/Makefile +run-make/foreign-double-unwind/Makefile +run-make/foreign-exceptions/Makefile +run-make/foreign-rust-exceptions/Makefile +run-make/fpic/Makefile +run-make/glibc-staticlib-args/Makefile +run-make/hir-tree/Makefile +run-make/inaccessible-temp-dir/Makefile +run-make/include_bytes_deps/Makefile +run-make/incr-add-rust-src-component/Makefile +run-make/incr-foreign-head-span/Makefile +run-make/incr-prev-body-beyond-eof/Makefile +run-make/incremental-debugger-visualizer/Makefile +run-make/incremental-session-fail/Makefile +run-make/inline-always-many-cgu/Makefile +run-make/interdependent-c-libraries/Makefile +run-make/intrinsic-unreachable/Makefile +run-make/invalid-library/Makefile +run-make/invalid-so/Makefile +run-make/invalid-staticlib/Makefile +run-make/issue-107094/Makefile +run-make/issue-10971-temps-dir/Makefile +run-make/issue-109934-lto-debuginfo/Makefile +run-make/issue-11908/Makefile +run-make/issue-14500/Makefile +run-make/issue-14698/Makefile +run-make/issue-15460/Makefile +run-make/issue-18943/Makefile +run-make/issue-20626/Makefile +run-make/issue-22131/Makefile +run-make/issue-24445/Makefile +run-make/issue-25581/Makefile +run-make/issue-26006/Makefile +run-make/issue-26092/Makefile +run-make/issue-28595/Makefile +run-make/issue-28766/Makefile +run-make/issue-30063/Makefile +run-make/issue-33329/Makefile +run-make/issue-35164/Makefile +run-make/issue-36710/Makefile +run-make/issue-37839/Makefile +run-make/issue-37893/Makefile +run-make/issue-38237/Makefile +run-make/issue-40535/Makefile +run-make/issue-46239/Makefile +run-make/issue-47384/Makefile +run-make/issue-47551/Makefile +run-make/issue-51671/Makefile +run-make/issue-53964/Makefile +run-make/issue-64153/Makefile +run-make/issue-68794-textrel-on-minimal-lib/Makefile +run-make/issue-69368/Makefile +run-make/issue-7349/Makefile +run-make/issue-83045/Makefile +run-make/issue-83112-incr-test-moved-file/Makefile +run-make/issue-84395-lto-embed-bitcode/Makefile +run-make/issue-85019-moved-src-dir/Makefile +run-make/issue-85401-static-mir/Makefile +run-make/issue-85441/Makefile +run-make/issue-88756-default-output/Makefile +run-make/issue-97463-abi-param-passing/Makefile +run-make/issue64319/Makefile +run-make/jobserver-error/Makefile +run-make/libs-through-symlinks/Makefile +run-make/libtest-json/Makefile +run-make/libtest-junit/Makefile +run-make/libtest-padding/Makefile +run-make/libtest-thread-limit/Makefile +run-make/link-arg/Makefile +run-make/link-args-order/Makefile +run-make/link-cfg/Makefile +run-make/link-dedup/Makefile +run-make/link-framework/Makefile +run-make/link-path-order/Makefile +run-make/linkage-attr-on-static/Makefile +run-make/llvm-ident/Makefile +run-make/llvm-outputs/Makefile +run-make/long-linker-command-lines-cmd-exe/Makefile +run-make/long-linker-command-lines/Makefile +run-make/longjmp-across-rust/Makefile +run-make/ls-metadata/Makefile +run-make/lto-dylib-dep/Makefile +run-make/lto-empty/Makefile +run-make/lto-linkage-used-attr/Makefile +run-make/lto-no-link-whole-rlib/Makefile +run-make/lto-readonly-lib/Makefile +run-make/lto-smoke-c/Makefile +run-make/lto-smoke/Makefile +run-make/macos-deployment-target/Makefile +run-make/macos-fat-archive/Makefile +run-make/manual-crate-name/Makefile +run-make/manual-link/Makefile +run-make/many-crates-but-no-match/Makefile +run-make/metadata-dep-info/Makefile +run-make/metadata-flag-frobs-symbols/Makefile +run-make/min-global-align/Makefile +run-make/mingw-export-call-convention/Makefile +run-make/mismatching-target-triples/Makefile +run-make/missing-crate-dependency/Makefile +run-make/mixing-deps/Makefile +run-make/mixing-formats/Makefile +run-make/mixing-libs/Makefile +run-make/msvc-opt-minsize/Makefile +run-make/multiple-emits/Makefile +run-make/native-link-modifier-bundle/Makefile +run-make/native-link-modifier-verbatim-linker/Makefile +run-make/native-link-modifier-verbatim-rustc/Makefile +run-make/native-link-modifier-whole-archive/Makefile +run-make/no-alloc-shim/Makefile +run-make/no-builtins-attribute/Makefile +run-make/no-builtins-lto/Makefile +run-make/no-cdylib-as-rdylib/Makefile +run-make/no-duplicate-libs/Makefile +run-make/no-input-file/Makefile +run-make/no-intermediate-extras/Makefile +run-make/obey-crate-type-flag/Makefile +run-make/optimization-remarks-dir-pgo/Makefile +run-make/optimization-remarks-dir/Makefile +run-make/output-filename-conflicts-with-directory/Makefile +run-make/output-filename-overwrites-input/Makefile +run-make/output-type-permutations/Makefile +run-make/output-with-hyphens/Makefile +run-make/override-aliased-flags/Makefile +run-make/overwrite-input/Makefile +run-make/panic-abort-eh_frame/Makefile +run-make/panic-impl-transitive/Makefile +run-make/pass-linker-flags-flavor/Makefile +run-make/pass-linker-flags-from-dep/Makefile +run-make/pass-linker-flags/Makefile +run-make/pass-non-c-like-enum-to-c/Makefile +run-make/pdb-alt-path/Makefile +run-make/pdb-buildinfo-cl-cmd/Makefile +run-make/pgo-branch-weights/Makefile +run-make/pgo-gen-lto/Makefile +run-make/pgo-gen-no-imp-symbols/Makefile +run-make/pgo-gen/Makefile +run-make/pgo-indirect-call-promotion/Makefile +run-make/pgo-use/Makefile +run-make/pointer-auth-link-with-c/Makefile +run-make/prefer-dylib/Makefile +run-make/prefer-rlib/Makefile +run-make/pretty-print-to-file/Makefile +run-make/pretty-print-with-dep-file/Makefile +run-make/print-calling-conventions/Makefile +run-make/print-cfg/Makefile +run-make/print-native-static-libs/Makefile +run-make/print-target-list/Makefile +run-make/profile/Makefile +run-make/prune-link-args/Makefile +run-make/raw-dylib-alt-calling-convention/Makefile +run-make/raw-dylib-c/Makefile +run-make/raw-dylib-cross-compilation/Makefile +run-make/raw-dylib-custom-dlltool/Makefile +run-make/raw-dylib-import-name-type/Makefile +run-make/raw-dylib-inline-cross-dylib/Makefile +run-make/raw-dylib-link-ordinal/Makefile +run-make/raw-dylib-stdcall-ordinal/Makefile +run-make/redundant-libs/Makefile +run-make/relocation-model/Makefile +run-make/relro-levels/Makefile +run-make/remap-path-prefix-dwarf/Makefile +run-make/remap-path-prefix/Makefile +run-make/repr128-dwarf/Makefile +run-make/reproducible-build-2/Makefile +run-make/reproducible-build/Makefile +run-make/resolve-rename/Makefile +run-make/return-non-c-like-enum-from-c/Makefile +run-make/return-non-c-like-enum/Makefile +run-make/rlib-chain/Makefile +run-make/rlib-format-packed-bundled-libs-2/Makefile +run-make/rlib-format-packed-bundled-libs-3/Makefile +run-make/rlib-format-packed-bundled-libs/Makefile +run-make/rmeta-preferred/Makefile +run-make/rust-lld-custom-target/Makefile +run-make/rust-lld/Makefile +run-make/rustc-macro-dep-files/Makefile +run-make/rustdoc-determinism/Makefile +run-make/rustdoc-error-lines/Makefile +run-make/rustdoc-io-error/Makefile +run-make/rustdoc-map-file/Makefile +run-make/rustdoc-output-path/Makefile +run-make/rustdoc-scrape-examples-invalid-expr/Makefile +run-make/rustdoc-scrape-examples-macros/Makefile +run-make/rustdoc-scrape-examples-multiple/Makefile +run-make/rustdoc-scrape-examples-ordering/Makefile +run-make/rustdoc-scrape-examples-remap/Makefile +run-make/rustdoc-scrape-examples-test/Makefile +run-make/rustdoc-scrape-examples-whitespace/Makefile +run-make/rustdoc-shared-flags/Makefile +run-make/rustdoc-target-spec-json-path/Makefile +run-make/rustdoc-themes/Makefile +run-make/rustdoc-verify-output-files/Makefile +run-make/rustdoc-with-out-dir-option/Makefile +run-make/rustdoc-with-output-option/Makefile +run-make/rustdoc-with-short-out-dir-option/Makefile +run-make/sanitizer-cdylib-link/Makefile +run-make/sanitizer-dylib-link/Makefile +run-make/sanitizer-staticlib-link/Makefile +run-make/separate-link-fail/Makefile +run-make/separate-link/Makefile +run-make/sepcomp-cci-copies/Makefile +run-make/sepcomp-inlining/Makefile +run-make/sepcomp-separate/Makefile +run-make/share-generics-dylib/Makefile +run-make/short-ice/Makefile +run-make/silly-file-names/Makefile +run-make/simd-ffi/Makefile +run-make/simple-dylib/Makefile +run-make/simple-rlib/Makefile +run-make/split-debuginfo/Makefile +run-make/stable-symbol-names/Makefile +run-make/static-dylib-by-default/Makefile +run-make/static-extern-type/Makefile +run-make/static-pie/Makefile +run-make/static-unwinding/Makefile +run-make/staticlib-blank-lib/Makefile +run-make/staticlib-dylib-linkage/Makefile +run-make/std-core-cycle/Makefile +run-make/stdin-non-utf8/Makefile +run-make/suspicious-library/Makefile +run-make/symbol-mangling-hashed/Makefile +run-make/symbol-visibility/Makefile +run-make/symbols-include-type-name/Makefile +run-make/symlinked-extern/Makefile +run-make/symlinked-libraries/Makefile +run-make/symlinked-rlib/Makefile +run-make/sysroot-crates-are-unstable/Makefile +run-make/target-cpu-native/Makefile +run-make/target-specs/Makefile +run-make/target-without-atomic-cas/Makefile +run-make/test-benches/Makefile +run-make/test-harness/Makefile +run-make/thumb-none-cortex-m/Makefile +run-make/thumb-none-qemu/Makefile +run-make/track-path-dep-info/Makefile +run-make/track-pgo-dep-info/Makefile +run-make/translation/Makefile +run-make/type-mismatch-same-crate-name/Makefile +run-make/unknown-mod-stdin/Makefile +run-make/unstable-flag-required/Makefile +run-make/use-suggestions-rust-2018/Makefile +run-make/used-cdylib-macos/Makefile +run-make/used/Makefile +run-make/valid-print-requests/Makefile +run-make/version/Makefile +run-make/volatile-intrinsics/Makefile +run-make/wasm-exceptions-nostd/Makefile +run-make/wasm-override-linker/Makefile +run-make/weird-output-filenames/Makefile +run-make/windows-binary-no-external-deps/Makefile +run-make/windows-safeseh/Makefile +run-make/windows-spawn/Makefile +run-make/windows-subsystem/Makefile +run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 10fdfc0a65f..b74afa0d3e8 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -208,6 +208,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "byteorder", // via ruzstd in object in thorin-dwp "cc", "cfg-if", + "cfg_aliases", "compiler_builtins", "cpufeatures", "crc32fast", @@ -216,6 +217,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "crossbeam-epoch", "crossbeam-utils", "crypto-common", + "ctrlc", "darling", "darling_core", "darling_macro", @@ -281,6 +283,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "memmap2", "memoffset", "miniz_oxide", + "nix", "nu-ansi-term", "num-conv", "num_cpus", diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 670b7eb2be9..57436e8d7fe 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -69,6 +69,7 @@ mod fluent_used; pub(crate) mod iter_header; pub mod mir_opt_tests; pub mod pal; +pub mod run_make_tests; pub mod rustdoc_css_themes; pub mod rustdoc_gui_tests; pub mod style; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 2bce246c308..93be4d61a9a 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -103,6 +103,8 @@ fn main() { check!(tests_revision_unpaired_stdout_stderr, &tests_path); check!(debug_artifacts, &tests_path); check!(ui_tests, &root_path, bless); + // FIXME(jieyouxu): remove this check once all run-make tests are ported over to rmake.rs. + check!(run_make_tests, &tests_path, &src_path, bless); check!(mir_opt_tests, &tests_path, bless); check!(rustdoc_gui_tests, &tests_path); check!(rustdoc_css_themes, &librustdoc_path); diff --git a/src/tools/tidy/src/run_make_tests.rs b/src/tools/tidy/src/run_make_tests.rs new file mode 100644 index 00000000000..98021cec130 --- /dev/null +++ b/src/tools/tidy/src/run_make_tests.rs @@ -0,0 +1,89 @@ +//! Tidy check to ensure that no new Makefiles are added under `tests/run-make/`. + +use std::collections::BTreeSet; +use std::fs::File; +use std::io::Write; +use std::path::{Path, PathBuf}; + +pub fn check(tests_path: &Path, src_path: &Path, bless: bool, bad: &mut bool) { + let allowed_makefiles = { + let allowed_makefiles = include_str!("allowed_run_make_makefiles.txt"); + let allowed_makefiles = allowed_makefiles.lines().collect::<Vec<_>>(); + let is_sorted = allowed_makefiles.windows(2).all(|w| w[0] < w[1]); + if !is_sorted && !bless { + tidy_error!( + bad, + "`src/tools/tidy/src/allowed_run_make_makefiles.txt` is not in order, likely \ + because you modified it manually, please only update it with command \ + `x test tidy --bless`" + ); + } + let allowed_makefiles_unique = + allowed_makefiles.iter().map(ToString::to_string).collect::<BTreeSet<String>>(); + if allowed_makefiles_unique.len() != allowed_makefiles.len() { + tidy_error!( + bad, + "`src/tools/tidy/src/allowed_run_make_makefiles.txt` contains duplicate entries, \ + likely because you modified it manually, please only update it with command \ + `x test tidy --bless`" + ); + } + allowed_makefiles_unique + }; + + let mut remaining_makefiles = allowed_makefiles.clone(); + + crate::walk::walk_no_read( + &[tests_path.join("run-make").as_ref()], + |_, _| false, + &mut |entry| { + if entry.file_type().map_or(true, |t| t.is_dir()) { + return; + } + + if entry.file_name().to_str().map_or(true, |f| f != "Makefile") { + return; + } + + let makefile_path = entry.path().strip_prefix(&tests_path).unwrap(); + let makefile_path = makefile_path.to_str().unwrap().replace('\\', "/"); + + if !remaining_makefiles.remove(&makefile_path) { + tidy_error!( + bad, + "found run-make Makefile not permitted in \ + `src/tools/tidy/src/allowed_run_make_makefiles.txt`, please write new run-make \ + tests with `rmake.rs` instead: {}", + entry.path().display() + ); + } + }, + ); + + // If there are any expected Makefiles remaining, they were moved or deleted. + // Our data must remain up to date, so they must be removed from + // `src/tools/tidy/src/allowed_run_make_makefiles.txt`. + // This can be done automatically on --bless, or else a tidy error will be issued. + if bless && !remaining_makefiles.is_empty() { + let tidy_src = src_path.join("tools").join("tidy").join("src"); + let org_file_path = tidy_src.join("allowed_run_make_makefiles.txt"); + let temp_file_path = tidy_src.join("blessed_allowed_run_make_makefiles.txt"); + let mut temp_file = t!(File::create_new(&temp_file_path)); + for file in allowed_makefiles.difference(&remaining_makefiles) { + t!(writeln!(temp_file, "{file}")); + } + t!(std::fs::rename(&temp_file_path, &org_file_path)); + } else { + for file in remaining_makefiles { + let mut p = PathBuf::from(tests_path); + p.push(file); + tidy_error!( + bad, + "Makefile `{}` no longer exists and should be removed from the exclusions in \ + `src/tools/tidy/src/allowed_run_make_makefiles.txt`, you can run --bless to update \ + the allow list", + p.display() + ); + } + } +} diff --git a/tests/codegen/intrinsics/typed_swap.rs b/tests/codegen/intrinsics/typed_swap.rs index b55fb8ee36f..e73931d1d54 100644 --- a/tests/codegen/intrinsics/typed_swap.rs +++ b/tests/codegen/intrinsics/typed_swap.rs @@ -24,9 +24,8 @@ pub unsafe fn swap_i32(x: &mut i32, y: &mut i32) { // CHECK-NOT: alloca // CHECK: %[[TEMP:.+]] = load i32, ptr %x, align 4 - // CHECK-SAME: !noundef + // OPT3-SAME: !noundef // OPT0: %[[TEMP2:.+]] = load i32, ptr %y, align 4 - // OPT0-SAME: !noundef // OPT0: store i32 %[[TEMP2]], ptr %x, align 4 // OPT0-NOT: memcpy // OPT3-NOT: load @@ -42,9 +41,9 @@ pub unsafe fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) { // CHECK-NOT: alloca // CHECK: load i32 - // CHECK-SAME: !noundef + // OPT3-SAME: !noundef // CHECK: load i32 - // CHECK-SAME: !noundef + // OPT3-SAME: !noundef // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 8, i1 false) // CHECK: store i32 // CHECK: store i32 @@ -57,10 +56,10 @@ pub unsafe fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) { // CHECK-NOT: alloca // CHECK: load ptr - // CHECK-SAME: !nonnull - // CHECK-SAME: !noundef + // OPT3-SAME: !nonnull + // OPT3-SAME: !noundef // CHECK: load i64 - // CHECK-SAME: !noundef + // OPT3-SAME: !noundef // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 16, i1 false) // CHECK: store ptr // CHECK: store i64 diff --git a/tests/codegen/loads.rs b/tests/codegen/loads.rs index b86b3dd3a19..ba4de77ce6f 100644 --- a/tests/codegen/loads.rs +++ b/tests/codegen/loads.rs @@ -1,4 +1,5 @@ -//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 +//@ compile-flags: -C no-prepopulate-passes -Zmir-opt-level=0 -O + #![crate_type = "lib"] #![feature(generic_nonzero)] diff --git a/tests/codegen/overaligned-constant.rs b/tests/codegen/overaligned-constant.rs index 351c8ea8f4b..9e5b69ff267 100644 --- a/tests/codegen/overaligned-constant.rs +++ b/tests/codegen/overaligned-constant.rs @@ -16,7 +16,7 @@ fn main() { // CHECK-LABEL: @_ZN20overaligned_constant4main // CHECK: [[full:%_.*]] = alloca %SmallStruct, align 8 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[full]], ptr align 8 @0, i64 32, i1 false) - // CHECK: %b.0 = load i32, ptr @0, align 4, + // CHECK: %b.0 = load i32, ptr @0, align 4 // CHECK: %b.1 = load i32, ptr getelementptr inbounds ({{.*}}), align 4 let mut s = S(1); diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs new file mode 100644 index 00000000000..3ec1988edd6 --- /dev/null +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-drop-in-place.rs @@ -0,0 +1,27 @@ +// Verifies that type metadata identifiers for drop functions are emitted correctly. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Zsanitizer=cfi -Ctarget-feature=-crt-static + +#![crate_type="lib"] + +// CHECK-LABEL: define{{.*}}4core3ptr47drop_in_place$LT$dyn$u20$core..marker..Send$GT$ +// CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: call i1 @llvm.type.test(ptr {{%.+}}, metadata !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE") + +struct EmptyDrop; +// CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}EmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} + +struct NonEmptyDrop; + +impl Drop for NonEmptyDrop { + fn drop(&mut self) {} + // CHECK: define{{.*}}4core3ptr{{[0-9]+}}drop_in_place$LT${{.*}}NonEmptyDrop$GT${{.*}}!type ![[TYPE1]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +} + +pub fn foo() { + let _ = Box::new(EmptyDrop) as Box<dyn Send>; + let _ = Box::new(NonEmptyDrop) as Box<dyn Send>; +} + +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops4drop4Dropu6regionEE"} diff --git a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs index f08c9e6702e..f9c7cca3989 100644 --- a/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs +++ b/tests/codegen/sanitizer/kcfi/emit-type-metadata-trait-objects.rs @@ -29,6 +29,8 @@ impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b trait Freeze { } #[lang="drop_in_place"] fn drop_in_place_fn<T>() { } +#[lang="drop"] +trait Drop { fn drop(&mut self); } pub trait Trait1 { fn foo(&self); diff --git a/tests/coverage/unreachable.cov-map b/tests/coverage/unreachable.cov-map index 55d124a16f5..9d4698527d0 100644 --- a/tests/coverage/unreachable.cov-map +++ b/tests/coverage/unreachable.cov-map @@ -14,11 +14,11 @@ Number of expressions: 0 Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 37) -Function name: unreachable::unreachable_intrinsic -Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 01, 01, 2c] +Function name: unreachable::unreachable_intrinsic (unused) +Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 01, 2c] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 22, 1) to (start + 1, 44) +- Code(Zero) at (prev + 22, 1) to (start + 1, 44) diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir index f51540bcfff..cab7bdb7e3c 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-abort.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref -fn main::{closure#0}::{closure#1}(_1: *mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} { +fn main::{closure#0}::{closure#1}(_1: &mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} { let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10}; bb0: { diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir index f51540bcfff..cab7bdb7e3c 100644 --- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir +++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.panic-unwind.mir @@ -1,6 +1,6 @@ // MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref -fn main::{closure#0}::{closure#1}(_1: *mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} { +fn main::{closure#0}::{closure#1}(_1: &mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} { let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10}; bb0: { diff --git a/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir index 8b22743d2b0..7480324b177 100644 --- a/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir @@ -9,7 +9,7 @@ storage_conflicts: BitMatrix(0x0) {}, } */ -fn a::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}>, _2: &mut Context<'_>) -> Poll<()> { +fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) -> Poll<()> { debug _task_context => _4; let mut _0: std::task::Poll<()>; let mut _3: (); @@ -17,7 +17,7 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}> let mut _5: u32; bb0: { - _5 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}))); + _5 = discriminant((*(_1.0: &mut {async fn body of a()}))); switchInt(move _5) -> [0: bb1, 1: bb4, otherwise: bb5]; } @@ -29,7 +29,7 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}> bb2: { _0 = Poll::<()>::Ready(move _3); - discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}))) = 1; + discriminant((*(_1.0: &mut {async fn body of a()}))) = 1; return; } diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index 2f7c4f7d402..d697ea49231 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -51,19 +51,19 @@ }, } */ -fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, _2: &mut Context<'_>) -> Poll<()> { +fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> Poll<()> { debug _task_context => _38; let mut _0: std::task::Poll<()>; let _3: (); - let mut _4: {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _5: {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _6: {async fn body@$DIR/async_await.rs:12:14: 12:16}; + let mut _4: {async fn body of a()}; + let mut _5: {async fn body of a()}; + let mut _6: {async fn body of a()}; let mut _7: (); let _8: (); let mut _9: std::task::Poll<()>; - let mut _10: std::pin::Pin<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}>; - let mut _11: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _12: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}; + let mut _10: std::pin::Pin<&mut {async fn body of a()}>; + let mut _11: &mut {async fn body of a()}; + let mut _12: &mut {async fn body of a()}; let mut _13: &mut std::task::Context<'_>; let mut _14: &mut std::task::Context<'_>; let mut _15: &mut std::task::Context<'_>; @@ -71,14 +71,14 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, let mut _18: !; let mut _19: &mut std::task::Context<'_>; let mut _20: (); - let mut _21: {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _22: {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _23: {async fn body@$DIR/async_await.rs:12:14: 12:16}; + let mut _21: {async fn body of a()}; + let mut _22: {async fn body of a()}; + let mut _23: {async fn body of a()}; let _24: (); let mut _25: std::task::Poll<()>; - let mut _26: std::pin::Pin<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}>; - let mut _27: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}; - let mut _28: &mut {async fn body@$DIR/async_await.rs:12:14: 12:16}; + let mut _26: std::pin::Pin<&mut {async fn body of a()}>; + let mut _27: &mut {async fn body of a()}; + let mut _28: &mut {async fn body of a()}; let mut _29: &mut std::task::Context<'_>; let mut _30: &mut std::task::Context<'_>; let mut _31: &mut std::task::Context<'_>; @@ -90,7 +90,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, let mut _38: &mut std::task::Context<'_>; let mut _39: u32; scope 1 { - debug __awaitee => (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#3).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}); + debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()}); let _17: (); scope 2 { } @@ -99,7 +99,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, } } scope 4 { - debug __awaitee => (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#4).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}); + debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()}); let _33: (); scope 5 { } @@ -109,7 +109,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, } bb0: { - _39 = discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))); + _39 = discriminant((*(_1.0: &mut {async fn body of b()}))); switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb8]; } @@ -122,14 +122,14 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, } bb2: { - _4 = <{async fn body@$DIR/async_await.rs:12:14: 12:16} as IntoFuture>::into_future(move _5) -> [return: bb3, unwind unreachable]; + _4 = <{async fn body of a()} as IntoFuture>::into_future(move _5) -> [return: bb3, unwind unreachable]; } bb3: { StorageDead(_5); PlaceMention(_4); nop; - (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#3).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}) = move _4; + (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()}) = move _4; goto -> bb4; } @@ -139,9 +139,9 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageLive(_10); StorageLive(_11); StorageLive(_12); - _12 = &mut (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#3).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}); + _12 = &mut (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()}); _11 = &mut (*_12); - _10 = Pin::<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}>::new_unchecked(move _11) -> [return: bb5, unwind unreachable]; + _10 = Pin::<&mut {async fn body of a()}>::new_unchecked(move _11) -> [return: bb5, unwind unreachable]; } bb5: { @@ -157,7 +157,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb6: { _13 = &mut (*_14); StorageDead(_15); - _9 = <{async fn body@$DIR/async_await.rs:12:14: 12:16} as Future>::poll(move _10, move _13) -> [return: bb7, unwind unreachable]; + _9 = <{async fn body of a()} as Future>::poll(move _10, move _13) -> [return: bb7, unwind unreachable]; } bb7: { @@ -186,7 +186,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageDead(_4); StorageDead(_19); StorageDead(_20); - discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))) = 3; + discriminant((*(_1.0: &mut {async fn body of b()}))) = 3; return; } @@ -199,7 +199,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageDead(_12); StorageDead(_9); StorageDead(_8); - drop((((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#3).0: {async fn body@$DIR/async_await.rs:12:14: 12:16})) -> [return: bb12, unwind unreachable]; + drop((((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()})) -> [return: bb12, unwind unreachable]; } bb11: { @@ -224,14 +224,14 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, } bb14: { - _21 = <{async fn body@$DIR/async_await.rs:12:14: 12:16} as IntoFuture>::into_future(move _22) -> [return: bb15, unwind unreachable]; + _21 = <{async fn body of a()} as IntoFuture>::into_future(move _22) -> [return: bb15, unwind unreachable]; } bb15: { StorageDead(_22); PlaceMention(_21); nop; - (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#4).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}) = move _21; + (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()}) = move _21; goto -> bb16; } @@ -241,9 +241,9 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageLive(_26); StorageLive(_27); StorageLive(_28); - _28 = &mut (((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#4).0: {async fn body@$DIR/async_await.rs:12:14: 12:16}); + _28 = &mut (((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()}); _27 = &mut (*_28); - _26 = Pin::<&mut {async fn body@$DIR/async_await.rs:12:14: 12:16}>::new_unchecked(move _27) -> [return: bb17, unwind unreachable]; + _26 = Pin::<&mut {async fn body of a()}>::new_unchecked(move _27) -> [return: bb17, unwind unreachable]; } bb17: { @@ -259,7 +259,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb18: { _29 = &mut (*_30); StorageDead(_31); - _25 = <{async fn body@$DIR/async_await.rs:12:14: 12:16} as Future>::poll(move _26, move _29) -> [return: bb19, unwind unreachable]; + _25 = <{async fn body of a()} as Future>::poll(move _26, move _29) -> [return: bb19, unwind unreachable]; } bb19: { @@ -283,7 +283,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageDead(_21); StorageDead(_35); StorageDead(_36); - discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))) = 4; + discriminant((*(_1.0: &mut {async fn body of b()}))) = 4; return; } @@ -296,7 +296,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, StorageDead(_28); StorageDead(_25); StorageDead(_24); - drop((((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2})) as variant#4).0: {async fn body@$DIR/async_await.rs:12:14: 12:16})) -> [return: bb23, unwind unreachable]; + drop((((*(_1.0: &mut {async fn body of b()})) as variant#4).0: {async fn body of a()})) -> [return: bb23, unwind unreachable]; } bb22: { @@ -319,7 +319,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body@$DIR/async_await.rs:15:18: 18:2}>, bb25: { _0 = Poll::<()>::Ready(move _37); - discriminant((*(_1.0: &mut {async fn body@$DIR/async_await.rs:15:18: 18:2}))) = 1; + discriminant((*(_1.0: &mut {async fn body of b()}))) = 1; return; } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index b189b4e73f4..0243e31cb1a 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -5,24 +5,24 @@ debug permit => (_1.0: ActionPermit<'_, T>); debug ctx => (*(_1.1: &mut std::task::Context<'_>)); let mut _0: (); - let mut _2: {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; + let mut _2: {async fn body of ActionPermit<'_, T>::perform()}; let mut _3: ActionPermit<'_, T>; - let mut _5: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; + let mut _5: &mut {async fn body of ActionPermit<'_, T>::perform()}; let _6: (); let mut _7: std::task::Poll<()>; - let mut _8: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>; + let mut _8: std::pin::Pin<&mut {async fn body of ActionPermit<'_, T>::perform()}>; let mut _9: &mut std::task::Context<'_>; let mut _10: &mut std::task::Context<'_>; scope 1 { debug fut => _2; - let _4: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>; + let _4: std::pin::Pin<&mut {async fn body of ActionPermit<'_, T>::perform()}>; scope 2 { debug fut => _4; scope 4 { } + scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) { + debug _task_context => _31; -+ debug self => ((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})).0: ActionPermit<'_, T>); ++ debug self => ((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})).0: ActionPermit<'_, T>); + let _11: ActionPermit<'_, T>; + let mut _12: std::future::Ready<()>; + let mut _13: std::future::Ready<()>; @@ -43,19 +43,19 @@ + let mut _30: (); + let mut _31: &mut std::task::Context<'_>; + let mut _32: u32; -+ let mut _33: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _34: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _35: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _36: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _37: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _38: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _39: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _40: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _33: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _34: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _35: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _36: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _37: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _38: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _39: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()}; + scope 8 { -+ debug self => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).0: ActionPermit<'_, T>); ++ debug self => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).0: ActionPermit<'_, T>); + let mut _15: std::future::Ready<()>; + scope 9 { -+ debug __awaitee => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).1: std::future::Ready<()>); ++ debug __awaitee => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).1: std::future::Ready<()>); + let _26: (); + scope 10 { + } @@ -71,7 +71,7 @@ + } } scope 3 { -+ scope 6 (inlined Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked) { ++ scope 6 (inlined Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked) { + debug pointer => _5; + } } @@ -93,11 +93,11 @@ StorageLive(_4); StorageLive(_5); _5 = &mut _2; -- _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked(move _5) -> [return: bb2, unwind unreachable]; +- _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked(move _5) -> [return: bb2, unwind unreachable]; - } - - bb2: { -+ _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}> { __pointer: _5 }; ++ _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}> { __pointer: _5 }; StorageDead(_5); StorageLive(_6); StorageLive(_7); @@ -106,7 +106,7 @@ StorageLive(_9); _10 = deref_copy (_1.1: &mut std::task::Context<'_>); _9 = &mut (*_10); -- _7 = <{async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6} as Future>::poll(move _8, move _9) -> [return: bb3, unwind unreachable]; +- _7 = <{async fn body of ActionPermit<'_, T>::perform()} as Future>::poll(move _8, move _9) -> [return: bb3, unwind unreachable]; + StorageLive(_11); + StorageLive(_15); + StorageLive(_16); @@ -123,7 +123,7 @@ + StorageLive(_38); + StorageLive(_39); + StorageLive(_40); -+ _33 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _33 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + _32 = discriminant((*_33)); + switchInt(move _32) -> [0: bb3, 1: bb13, 3: bb12, otherwise: bb8]; } @@ -164,8 +164,8 @@ + bb3: { + _31 = move _9; -+ _34 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); -+ _35 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _34 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ _35 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>); + StorageLive(_12); + StorageLive(_13); @@ -183,7 +183,7 @@ - StorageDead(_2); - return; + StorageDead(_13); -+ _36 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _36 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + (((*_36) as variant#3).1: std::future::Ready<()>) = move _12; + goto -> bb5; + } @@ -194,7 +194,7 @@ + StorageLive(_19); + StorageLive(_20); + StorageLive(_21); -+ _37 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>); + _20 = &mut (*_21); + _19 = Pin::<&mut std::future::Ready<()>>::new_unchecked(move _20) -> [return: bb6, unwind unreachable]; @@ -236,7 +236,7 @@ + StorageDead(_12); + StorageDead(_28); + StorageDead(_29); -+ _38 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _38 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + discriminant((*_38)) = 3; + goto -> bb2; + } @@ -251,13 +251,13 @@ + StorageDead(_18); + StorageDead(_17); + StorageDead(_12); -+ _39 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _39 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb11, unwind unreachable]; + } + + bb11: { + _7 = Poll::<()>::Ready(move _30); -+ _40 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _40 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + discriminant((*_40)) = 1; + goto -> bb2; + } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index ed18c0a3adb..96a93cdda3d 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -5,24 +5,24 @@ debug permit => (_1.0: ActionPermit<'_, T>); debug ctx => (*(_1.1: &mut std::task::Context<'_>)); let mut _0: (); - let mut _2: {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; + let mut _2: {async fn body of ActionPermit<'_, T>::perform()}; let mut _3: ActionPermit<'_, T>; - let mut _5: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; + let mut _5: &mut {async fn body of ActionPermit<'_, T>::perform()}; let _6: (); let mut _7: std::task::Poll<()>; - let mut _8: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>; + let mut _8: std::pin::Pin<&mut {async fn body of ActionPermit<'_, T>::perform()}>; let mut _9: &mut std::task::Context<'_>; let mut _10: &mut std::task::Context<'_>; scope 1 { debug fut => _2; - let _4: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>; + let _4: std::pin::Pin<&mut {async fn body of ActionPermit<'_, T>::perform()}>; scope 2 { debug fut => _4; scope 4 { } + scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) { + debug _task_context => _31; -+ debug self => ((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})).0: ActionPermit<'_, T>); ++ debug self => ((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})).0: ActionPermit<'_, T>); + let _11: ActionPermit<'_, T>; + let mut _12: std::future::Ready<()>; + let mut _13: std::future::Ready<()>; @@ -43,21 +43,21 @@ + let mut _30: (); + let mut _31: &mut std::task::Context<'_>; + let mut _32: u32; -+ let mut _33: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _34: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _35: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _36: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _37: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _38: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _39: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _40: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _41: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; -+ let mut _42: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}; ++ let mut _33: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _34: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _35: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _36: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _37: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _38: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _39: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _41: &mut {async fn body of ActionPermit<'_, T>::perform()}; ++ let mut _42: &mut {async fn body of ActionPermit<'_, T>::perform()}; + scope 8 { -+ debug self => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).0: ActionPermit<'_, T>); ++ debug self => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).0: ActionPermit<'_, T>); + let mut _15: std::future::Ready<()>; + scope 9 { -+ debug __awaitee => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).1: std::future::Ready<()>); ++ debug __awaitee => (((*(_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()})) as variant#3).1: std::future::Ready<()>); + let _26: (); + scope 10 { + } @@ -73,7 +73,7 @@ + } } scope 3 { -+ scope 6 (inlined Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked) { ++ scope 6 (inlined Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked) { + debug pointer => _5; + } } @@ -95,11 +95,11 @@ StorageLive(_4); StorageLive(_5); _5 = &mut _2; -- _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked(move _5) -> [return: bb2, unwind: bb5]; +- _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}>::new_unchecked(move _5) -> [return: bb2, unwind: bb5]; - } - - bb2: { -+ _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}> { __pointer: _5 }; ++ _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}> { __pointer: _5 }; StorageDead(_5); StorageLive(_6); StorageLive(_7); @@ -108,7 +108,7 @@ StorageLive(_9); _10 = deref_copy (_1.1: &mut std::task::Context<'_>); _9 = &mut (*_10); -- _7 = <{async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6} as Future>::poll(move _8, move _9) -> [return: bb3, unwind: bb5]; +- _7 = <{async fn body of ActionPermit<'_, T>::perform()} as Future>::poll(move _8, move _9) -> [return: bb3, unwind: bb5]; + StorageLive(_11); + StorageLive(_15); + StorageLive(_16); @@ -127,7 +127,7 @@ + StorageLive(_40); + StorageLive(_41); + StorageLive(_42); -+ _33 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _33 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + _32 = discriminant((*_33)); + switchInt(move _32) -> [0: bb5, 1: bb22, 2: bb21, 3: bb20, otherwise: bb10]; } @@ -181,8 +181,8 @@ - return; + bb5: { + _31 = move _9; -+ _34 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); -+ _35 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _34 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ _35 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>); + StorageLive(_12); + StorageLive(_13); @@ -200,7 +200,7 @@ - drop(_2) -> [return: bb6, unwind terminate(cleanup)]; + bb6: { + StorageDead(_13); -+ _36 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _36 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + (((*_36) as variant#3).1: std::future::Ready<()>) = move _12; + goto -> bb7; } @@ -213,7 +213,7 @@ + StorageLive(_19); + StorageLive(_20); + StorageLive(_21); -+ _37 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>); + _20 = &mut (*_21); + _19 = Pin::<&mut std::future::Ready<()>>::new_unchecked(move _20) -> [return: bb8, unwind: bb15]; @@ -255,7 +255,7 @@ + StorageDead(_12); + StorageDead(_28); + StorageDead(_29); -+ _38 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _38 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + discriminant((*_38)) = 3; + goto -> bb4; + } @@ -270,13 +270,13 @@ + StorageDead(_18); + StorageDead(_17); + StorageDead(_12); -+ _39 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _39 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb13, unwind: bb19]; + } + + bb13: { + _7 = Poll::<()>::Ready(move _30); -+ _40 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _40 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + discriminant((*_40)) = 1; + goto -> bb4; + } @@ -308,12 +308,12 @@ + + bb18 (cleanup): { + StorageDead(_12); -+ _41 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _41 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + drop((((*_41) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb19, unwind terminate(cleanup)]; + } + + bb19 (cleanup): { -+ _42 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}); ++ _42 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + discriminant((*_42)) = 2; + goto -> bb2; + } diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff index f1d18b0f7ff..f11c993340f 100644 --- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff +++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -26,18 +26,20 @@ _3 = _1; _2 = move _3 as [u32; 4] (Transmute); StorageDead(_3); - switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb6]; + switchInt(_2[0 of 4]) -> [0: bb1, otherwise: bb4]; } bb1: { - switchInt(_2[1 of 4]) -> [0: bb2, otherwise: bb6]; + switchInt(_2[1 of 4]) -> [0: bb2, otherwise: bb4]; } bb2: { - switchInt(_2[2 of 4]) -> [0: bb4, 4294901760: bb5, otherwise: bb6]; + switchInt(_2[2 of 4]) -> [0: bb3, 4294901760: bb3, otherwise: bb4]; } bb3: { + StorageLive(_4); + _4 = _2[3 of 4]; StorageLive(_5); StorageLive(_6); _6 = _4; @@ -46,27 +48,15 @@ _0 = Option::<[u8; 4]>::Some(move _5); StorageDead(_5); StorageDead(_4); - goto -> bb7; + goto -> bb5; } bb4: { - StorageLive(_4); - _4 = _2[3 of 4]; - goto -> bb3; - } - - bb5: { - StorageLive(_4); - _4 = _2[3 of 4]; - goto -> bb3; - } - - bb6: { _0 = Option::<[u8; 4]>::None; - goto -> bb7; + goto -> bb5; } - bb7: { + bb5: { StorageDead(_2); return; } diff --git a/tests/run-make-fulldeps/pretty-expanded/input.rs b/tests/run-make-fulldeps/pretty-expanded/input.rs index af3d75b3bf2..02b235068a1 100644 --- a/tests/run-make-fulldeps/pretty-expanded/input.rs +++ b/tests/run-make-fulldeps/pretty-expanded/input.rs @@ -1,12 +1,8 @@ -#[crate_type="lib"] - // #13544 -extern crate rustc_serialize; - -#[derive(RustcEncodable)] pub struct A; -#[derive(RustcEncodable)] pub struct B(isize); -#[derive(RustcEncodable)] pub struct C { x: isize } -#[derive(RustcEncodable)] pub enum D {} -#[derive(RustcEncodable)] pub enum E { y } -#[derive(RustcEncodable)] pub enum F { z(isize) } +#[derive(Debug)] pub struct A; +#[derive(Debug)] pub struct B(isize); +#[derive(Debug)] pub struct C { x: isize } +#[derive(Debug)] pub enum D {} +#[derive(Debug)] pub enum E { y } +#[derive(Debug)] pub enum F { z(isize) } diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs index 586f4e4095f..1204260a2f4 100644 --- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -1,24 +1,25 @@ // ignore-tidy-linelength +// Check that the `CURRENT_RUSTC_VERSION` placeholder is correctly replaced by the current +// `rustc` version and the `since` property in feature stability gating is properly respected. + extern crate run_make_support; use std::path::PathBuf; -use run_make_support::{aux_build, rustc}; +use run_make_support::{rustc, aux_build}; fn main() { - aux_build() - .arg("--emit=metadata") - .arg("stable.rs") - .run(); + aux_build().input("stable.rs").emit("metadata").run(); + let mut stable_path = PathBuf::from(env!("TMPDIR")); stable_path.push("libstable.rmeta"); + let output = rustc() - .arg("--emit=metadata") - .arg("--extern") - .arg(&format!("stable={}", &stable_path.to_string_lossy())) - .arg("main.rs") - .run(); + .input("main.rs") + .emit("metadata") + .extern_("stable", &stable_path) + .output(); let stderr = String::from_utf8_lossy(&output.stderr); let version = include_str!(concat!(env!("S"), "/src/version")); diff --git a/tests/run-make/a-b-a-linker-guard/rmake.rs b/tests/run-make/a-b-a-linker-guard/rmake.rs index ef4813e1214..ffc1b2000b9 100644 --- a/tests/run-make/a-b-a-linker-guard/rmake.rs +++ b/tests/run-make/a-b-a-linker-guard/rmake.rs @@ -1,44 +1,36 @@ // ignore-tidy-linelength +// Test that if we build `b` against a version of `a` that has one set of types, it will not run +// with a dylib that has a different set of types. + extern crate run_make_support; use run_make_support::{run, run_fail, rustc}; fn main() { rustc() - .arg("a.rs") - .arg("--cfg") - .arg("x") - .arg("-C") - .arg("prefer-dynamic") - .arg("-Z") - .arg("unstable-options") - .arg("-C") - .arg("symbol-mangling-version=legacy") + .input("a.rs") + .cfg("x") + .arg("-Zunstable-options") + .arg("-Cprefer-dynamic") + .arg("-Csymbol-mangling-version=legacy") .run(); rustc() - .arg("b.rs") - .arg("-C") - .arg("prefer-dynamic") - .arg("-Z") - .arg("unstable-options") - .arg("-C") - .arg("symbol-mangling-version=legacy") - .run(); + .input("b.rs") + .arg("-Zunstable-options") + .arg("-Cprefer-dynamic") + .arg("-Csymbol-mangling-version=legacy") + .run(); run("b"); rustc() - .arg("a.rs") - .arg("--cfg") - .arg("y") - .arg("-C") - .arg("prefer-dynamic") - .arg("-Z") - .arg("unstable-options") - .arg("-C") - .arg("symbol-mangling-version=legacy") + .input("a.rs") + .cfg("y") + .arg("-Zunstable-options") + .arg("-Cprefer-dynamic") + .arg("-Csymbol-mangling-version=legacy") .run(); run_fail("b"); diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make/compiler-builtins/rmake.rs index e7a5e8addbe..e5939470b46 100644 --- a/tests/run-make/compiler-builtins/rmake.rs +++ b/tests/run-make/compiler-builtins/rmake.rs @@ -8,6 +8,10 @@ //! settings. Turning off optimizations and enabling debug assertions tends to produce the most //! dependence on core that is possible, so that is the configuration we test here. +// wasm and nvptx targets don't produce rlib files that object can parse. +//@ ignore-wasm +//@ ignore-nvptx64 + #![deny(warnings)] extern crate run_make_support; @@ -18,7 +22,7 @@ use run_make_support::object::read::Object; use run_make_support::object::ObjectSection; use run_make_support::object::ObjectSymbol; use run_make_support::object::RelocationTarget; -use run_make_support::out_dir; +use run_make_support::tmp_dir; use std::collections::HashSet; const MANIFEST: &str = r#" @@ -31,19 +35,15 @@ edition = "2021" path = "lib.rs""#; fn main() { - let target_dir = out_dir().join("target"); + let target_dir = tmp_dir().join("target"); let target = std::env::var("TARGET").unwrap(); - if target.starts_with("wasm") || target.starts_with("nvptx") { - // wasm and nvptx targets don't produce rlib files that object can parse. - return; - } println!("Testing compiler_builtins for {}", target); // Set up the tiniest Cargo project: An empty no_std library. Just enough to run -Zbuild-std. - let manifest_path = out_dir().join("Cargo.toml"); + let manifest_path = tmp_dir().join("Cargo.toml"); std::fs::write(&manifest_path, MANIFEST.as_bytes()).unwrap(); - std::fs::write(out_dir().join("lib.rs"), b"#![no_std]").unwrap(); + std::fs::write(tmp_dir().join("lib.rs"), b"#![no_std]").unwrap(); let path = std::env::var("PATH").unwrap(); let rustc = std::env::var("RUSTC").unwrap(); diff --git a/tests/run-make/jobserver-error/Makefile b/tests/run-make/jobserver-error/Makefile index a7601b86715..9f34970f96f 100644 --- a/tests/run-make/jobserver-error/Makefile +++ b/tests/run-make/jobserver-error/Makefile @@ -4,9 +4,11 @@ include ../tools.mk # ignore-cross-compile # Test compiler behavior in case environment specifies wrong jobserver. +# Note that by default, the compiler uses file descriptors 0 (stdin), 1 (stdout), 2 (stderr), +# but also 3 and 4 for either end of the ctrl-c signal handler self-pipe. all: - bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=3,3" $(RUSTC)' 2>&1 | diff cannot_open_fd.stderr - + bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=5,5" $(RUSTC)' 2>&1 | diff cannot_open_fd.stderr - bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=3,3" $(RUSTC) - 3</dev/null' 2>&1 | diff not_a_pipe.stderr - # This test randomly fails, see https://github.com/rust-lang/rust/issues/110321 diff --git a/tests/run-make/jobserver-error/cannot_open_fd.stderr b/tests/run-make/jobserver-error/cannot_open_fd.stderr index 343de5cd52c..7c421846535 100644 --- a/tests/run-make/jobserver-error/cannot_open_fd.stderr +++ b/tests/run-make/jobserver-error/cannot_open_fd.stderr @@ -1,4 +1,4 @@ -warning: failed to connect to jobserver from environment variable `MAKEFLAGS="--jobserver-auth=3,3"`: cannot open file descriptor 3 from the jobserver environment variable value: Bad file descriptor (os error 9) +warning: failed to connect to jobserver from environment variable `MAKEFLAGS="--jobserver-auth=5,5"`: cannot open file descriptor 5 from the jobserver environment variable value: Bad file descriptor (os error 9) | = note: the build environment is likely misconfigured diff --git a/tests/run-make/link-framework/Makefile b/tests/run-make/link-framework/Makefile new file mode 100644 index 00000000000..f33347ac7f8 --- /dev/null +++ b/tests/run-make/link-framework/Makefile @@ -0,0 +1,23 @@ +# only-macos +# +# Check that linking to a framework actually makes it to the linker. + +include ../tools.mk + +all: + $(RUSTC) dep-link-framework.rs + $(RUSTC) dep-link-weak-framework.rs + + $(RUSTC) empty.rs + otool -L $(TMPDIR)/no-link | $(CGREP) -v CoreFoundation + + $(RUSTC) link-framework.rs + otool -L $(TMPDIR)/link-framework | $(CGREP) CoreFoundation | $(CGREP) -v weak + + $(RUSTC) link-weak-framework.rs + otool -L $(TMPDIR)/link-weak-framework | $(CGREP) CoreFoundation | $(CGREP) weak + +# When linking the framework both normally, and weakly, the weak linking takes preference + + $(RUSTC) link-both.rs + otool -L $(TMPDIR)/link-both | $(CGREP) CoreFoundation | $(CGREP) weak diff --git a/tests/run-make/link-framework/dep-link-framework.rs b/tests/run-make/link-framework/dep-link-framework.rs new file mode 100644 index 00000000000..9bdeb2052d2 --- /dev/null +++ b/tests/run-make/link-framework/dep-link-framework.rs @@ -0,0 +1,4 @@ +#![crate_type = "rlib"] + +#[link(name = "CoreFoundation", kind = "framework")] +extern "C" {} diff --git a/tests/run-make/link-framework/dep-link-weak-framework.rs b/tests/run-make/link-framework/dep-link-weak-framework.rs new file mode 100644 index 00000000000..d3e1cf9c98f --- /dev/null +++ b/tests/run-make/link-framework/dep-link-weak-framework.rs @@ -0,0 +1,6 @@ +#![crate_type = "rlib"] +#![feature(link_arg_attribute)] + +#[link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim")] +#[link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim")] +extern "C" {} diff --git a/tests/run-make/link-framework/empty.rs b/tests/run-make/link-framework/empty.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make/link-framework/empty.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/link-framework/link-both.rs b/tests/run-make/link-framework/link-both.rs new file mode 100644 index 00000000000..31fc79e1929 --- /dev/null +++ b/tests/run-make/link-framework/link-both.rs @@ -0,0 +1,4 @@ +extern crate dep_link_framework; +extern crate dep_link_weak_framework; + +fn main() {} diff --git a/tests/run-make/link-framework/link-framework.rs b/tests/run-make/link-framework/link-framework.rs new file mode 100644 index 00000000000..e33e830248e --- /dev/null +++ b/tests/run-make/link-framework/link-framework.rs @@ -0,0 +1,3 @@ +extern crate dep_link_framework; + +fn main() {} diff --git a/tests/run-make/link-framework/link-weak-framework.rs b/tests/run-make/link-framework/link-weak-framework.rs new file mode 100644 index 00000000000..f0557f8013a --- /dev/null +++ b/tests/run-make/link-framework/link-weak-framework.rs @@ -0,0 +1,3 @@ +extern crate dep_link_weak_framework; + +fn main() {} diff --git a/tests/run-make/rustdoc-test-args/rmake.rs b/tests/run-make/rustdoc-test-args/rmake.rs index 808d13928eb..c8edfb6370e 100644 --- a/tests/run-make/rustdoc-test-args/rmake.rs +++ b/tests/run-make/rustdoc-test-args/rmake.rs @@ -1,8 +1,8 @@ extern crate run_make_support; -use run_make_support::{out_dir, rustdoc}; -use std::{fs, iter}; +use run_make_support::{rustdoc, tmp_dir}; use std::path::Path; +use std::{fs, iter}; fn generate_a_lot_of_cfgs(path: &Path) { let content = iter::repeat("--cfg=a\n").take(100_000).collect::<String>(); @@ -10,9 +10,8 @@ fn generate_a_lot_of_cfgs(path: &Path) { } fn main() { - let arg_file = out_dir().join("args"); + let arg_file = tmp_dir().join("args"); generate_a_lot_of_cfgs(&arg_file); - let arg_file = format!("@{}", arg_file.display()); - rustdoc().arg("--test").arg(&arg_file).arg("foo.rs").run(); + rustdoc().out_dir(tmp_dir()).input("foo.rs").arg_file(&arg_file).arg("--test").run(); } diff --git a/tests/run-make/wasm-abi/rmake.rs b/tests/run-make/wasm-abi/rmake.rs index 07b826ae6fe..d83332f6e03 100644 --- a/tests/run-make/wasm-abi/rmake.rs +++ b/tests/run-make/wasm-abi/rmake.rs @@ -1,25 +1,16 @@ +//@ only-wasm32-wasip1 +//@ needs-wasmtime + extern crate run_make_support; -use run_make_support::{out_dir, rustc}; +use run_make_support::{rustc, tmp_dir}; use std::path::Path; use std::process::Command; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } - - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").run(); - let file = out_dir().join("foo.wasm"); + rustc().input("foo.rs").target("wasm32-wasip1").run(); - let has_wasmtime = match Command::new("wasmtime").arg("--version").output() { - Ok(s) => s.status.success(), - _ => false, - }; - if !has_wasmtime { - println!("skipping test, wasmtime isn't available"); - return; - } + let file = tmp_dir().join("foo.wasm"); run(&file, "return_two_i32", "1\n2\n"); run(&file, "return_two_i64", "3\n4\n"); diff --git a/tests/run-make/wasm-custom-section/rmake.rs b/tests/run-make/wasm-custom-section/rmake.rs index 9ad152695ec..825fcf71514 100644 --- a/tests/run-make/wasm-custom-section/rmake.rs +++ b/tests/run-make/wasm-custom-section/rmake.rs @@ -1,17 +1,14 @@ +//@ only-wasm32-wasip1 extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{rustc, tmp_dir, wasmparser}; use std::collections::HashMap; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } - - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").run(); - rustc().arg("bar.rs").arg("--target=wasm32-wasip1").arg("-Clto").arg("-O").run(); + rustc().input("foo.rs").target("wasm32-wasip1").run(); + rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - let file = std::fs::read(&out_dir().join("bar.wasm")).unwrap(); + let file = std::fs::read(&tmp_dir().join("bar.wasm")).unwrap(); let mut custom = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-custom-sections-opt/rmake.rs b/tests/run-make/wasm-custom-sections-opt/rmake.rs index db31d6b7163..634683adc22 100644 --- a/tests/run-make/wasm-custom-sections-opt/rmake.rs +++ b/tests/run-make/wasm-custom-sections-opt/rmake.rs @@ -1,16 +1,14 @@ +//@ only-wasm32-wasip1 extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{tmp_dir, wasmparser, rustc}; use std::collections::HashMap; use std::path::Path; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } + rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-O").run(); - verify(&out_dir().join("foo.wasm")); + verify(&tmp_dir().join("foo.wasm")); } fn verify(path: &Path) { diff --git a/tests/run-make/wasm-export-all-symbols/rmake.rs b/tests/run-make/wasm-export-all-symbols/rmake.rs index e3b118279b7..400d6db5651 100644 --- a/tests/run-make/wasm-export-all-symbols/rmake.rs +++ b/tests/run-make/wasm-export-all-symbols/rmake.rs @@ -1,15 +1,13 @@ +//@ only-wasm32-wasip1 + extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{tmp_dir, wasmparser, rustc}; use std::collections::HashMap; use std::path::Path; use wasmparser::ExternalKind::*; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } - test(&[]); test(&["-O"]); test(&["-Clto"]); @@ -17,16 +15,17 @@ fn main() { fn test(args: &[&str]) { eprintln!("running with {args:?}"); - rustc().arg("bar.rs").arg("--target=wasm32-wasip1").args(args).run(); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").args(args).run(); - rustc().arg("main.rs").arg("--target=wasm32-wasip1").args(args).run(); + + rustc().input("bar.rs").target("wasm32-wasip1").args(args).run(); + rustc().input("foo.rs").target("wasm32-wasip1").args(args).run(); + rustc().input("main.rs").target("wasm32-wasip1").args(args).run(); verify_exports( - &out_dir().join("foo.wasm"), + &tmp_dir().join("foo.wasm"), &[("foo", Func), ("FOO", Global), ("memory", Memory)], ); verify_exports( - &out_dir().join("main.wasm"), + &tmp_dir().join("main.wasm"), &[ ("foo", Func), ("FOO", Global), diff --git a/tests/run-make/wasm-import-module/rmake.rs b/tests/run-make/wasm-import-module/rmake.rs index e521b5b0983..1b814e9ccce 100644 --- a/tests/run-make/wasm-import-module/rmake.rs +++ b/tests/run-make/wasm-import-module/rmake.rs @@ -1,18 +1,21 @@ +//@ only-wasm32-wasip1 + extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{tmp_dir, wasmparser, rustc}; use std::collections::HashMap; use wasmparser::TypeRef::Func; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } - - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").run(); - rustc().arg("bar.rs").arg("--target=wasm32-wasip1").arg("-Clto").arg("-O").run(); + rustc().input("foo.rs").target("wasm32-wasip1").run(); + rustc() + .input("bar.rs") + .target("wasm32-wasip1") + .arg("-Clto") + .opt() + .run(); - let file = std::fs::read(&out_dir().join("bar.wasm")).unwrap(); + let file = std::fs::read(&tmp_dir().join("bar.wasm")).unwrap(); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs index 0260485f744..bffa311d93a 100644 --- a/tests/run-make/wasm-panic-small/rmake.rs +++ b/tests/run-make/wasm-panic-small/rmake.rs @@ -1,14 +1,11 @@ +//@ only-wasm32-wasip1 #![deny(warnings)] extern crate run_make_support; -use run_make_support::{out_dir, rustc}; +use run_make_support::{rustc, tmp_dir}; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } - test("a"); test("b"); test("c"); @@ -17,16 +14,10 @@ fn main() { fn test(cfg: &str) { eprintln!("running cfg {cfg:?}"); - rustc() - .arg("foo.rs") - .arg("--target=wasm32-wasip1") - .arg("-Clto") - .arg("-O") - .arg("--cfg") - .arg(cfg) - .run(); - let bytes = std::fs::read(&out_dir().join("foo.wasm")).unwrap(); + rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().cfg(cfg).run(); + + let bytes = std::fs::read(&tmp_dir().join("foo.wasm")).unwrap(); println!("{}", bytes.len()); assert!(bytes.len() < 40_000); } diff --git a/tests/run-make/wasm-spurious-import/rmake.rs b/tests/run-make/wasm-spurious-import/rmake.rs index 0ac9104bfb4..8f716061d28 100644 --- a/tests/run-make/wasm-spurious-import/rmake.rs +++ b/tests/run-make/wasm-spurious-import/rmake.rs @@ -1,24 +1,21 @@ +//@ only-wasm32-wasip1 + extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{rustc, tmp_dir, wasmparser}; use std::collections::HashMap; -use wasmparser::TypeRef::Func; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } - rustc() - .arg("main.rs") - .arg("--target=wasm32-wasip1") - .arg("-Coverflow-checks=yes") + .input("main.rs") + .target("wasm32-wasip1") + .arg("-Coverflow-checks") .arg("-Cpanic=abort") .arg("-Clto") .arg("-Copt-level=z") .run(); - let file = std::fs::read(&out_dir().join("main.wasm")).unwrap(); + let file = std::fs::read(&tmp_dir().join("main.wasm")).unwrap(); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-stringify-ints-small/rmake.rs b/tests/run-make/wasm-stringify-ints-small/rmake.rs index 80cff7acdf4..5efbfee8d38 100644 --- a/tests/run-make/wasm-stringify-ints-small/rmake.rs +++ b/tests/run-make/wasm-stringify-ints-small/rmake.rs @@ -1,17 +1,14 @@ +//@ only-wasm32-wasip1 #![deny(warnings)] extern crate run_make_support; -use run_make_support::{out_dir, rustc}; +use run_make_support::{rustc, tmp_dir}; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } + rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-Clto").arg("-O").run(); - - let bytes = std::fs::read(&out_dir().join("foo.wasm")).unwrap(); + let bytes = std::fs::read(&tmp_dir().join("foo.wasm")).unwrap(); println!("{}", bytes.len()); assert!(bytes.len() < 50_000); } diff --git a/tests/run-make/wasm-symbols-different-module/rmake.rs b/tests/run-make/wasm-symbols-different-module/rmake.rs index c3cc1e0c32b..88bd16a404c 100644 --- a/tests/run-make/wasm-symbols-different-module/rmake.rs +++ b/tests/run-make/wasm-symbols-different-module/rmake.rs @@ -1,13 +1,10 @@ +//@ only-wasm32-wasip1 extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{rustc, tmp_dir, wasmparser}; use std::collections::{HashMap, HashSet}; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } - test_file("foo.rs", &[("a", &["foo"]), ("b", &["foo"])]); test_file("bar.rs", &[("m1", &["f", "g"]), ("m2", &["f"])]); test_file("baz.rs", &[("sqlite", &["allocate", "deallocate"])]); @@ -24,9 +21,9 @@ fn test_file(file: &str, expected_imports: &[(&str, &[&str])]) { fn test(file: &str, args: &[&str], expected_imports: &[(&str, &[&str])]) { println!("test {file:?} {args:?} for {expected_imports:?}"); - rustc().arg(file).arg("--target=wasm32-wasip1").args(args).run(); + rustc().input(file).target("wasm32-wasip1").args(args).run(); - let file = std::fs::read(&out_dir().join(file).with_extension("wasm")).unwrap(); + let file = std::fs::read(&tmp_dir().join(file).with_extension("wasm")).unwrap(); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-symbols-not-exported/rmake.rs b/tests/run-make/wasm-symbols-not-exported/rmake.rs index 5ff0dc578b3..c9207f70ae5 100644 --- a/tests/run-make/wasm-symbols-not-exported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-exported/rmake.rs @@ -1,22 +1,19 @@ +//@ only-wasm32-wasip1 extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{rustc, tmp_dir, wasmparser}; use std::path::Path; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } - - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").run(); - verify_symbols(&out_dir().join("foo.wasm")); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-O").run(); - verify_symbols(&out_dir().join("foo.wasm")); + rustc().input("foo.rs").target("wasm32-wasip1").run(); + verify_symbols(&tmp_dir().join("foo.wasm")); + rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); + verify_symbols(&tmp_dir().join("foo.wasm")); - rustc().arg("bar.rs").arg("--target=wasm32-wasip1").run(); - verify_symbols(&out_dir().join("bar.wasm")); - rustc().arg("bar.rs").arg("--target=wasm32-wasip1").arg("-O").run(); - verify_symbols(&out_dir().join("bar.wasm")); + rustc().input("bar.rs").target("wasm32-wasip1").run(); + verify_symbols(&tmp_dir().join("bar.wasm")); + rustc().input("bar.rs").target("wasm32-wasip1").opt().run(); + verify_symbols(&tmp_dir().join("bar.wasm")); } fn verify_symbols(path: &Path) { diff --git a/tests/run-make/wasm-symbols-not-imported/rmake.rs b/tests/run-make/wasm-symbols-not-imported/rmake.rs index 974f415166b..4d41dc7c0aa 100644 --- a/tests/run-make/wasm-symbols-not-imported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-imported/rmake.rs @@ -1,21 +1,18 @@ +//@ only-wasm32-wasip1 extern crate run_make_support; -use run_make_support::{out_dir, rustc, wasmparser}; +use run_make_support::{rustc, tmp_dir, wasmparser}; use std::path::Path; fn main() { - if std::env::var("TARGET").unwrap() != "wasm32-wasip1" { - return; - } - - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").run(); - verify_symbols(&out_dir().join("foo.wasm")); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-Clto").run(); - verify_symbols(&out_dir().join("foo.wasm")); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-O").run(); - verify_symbols(&out_dir().join("foo.wasm")); - rustc().arg("foo.rs").arg("--target=wasm32-wasip1").arg("-Clto").arg("-O").run(); - verify_symbols(&out_dir().join("foo.wasm")); + rustc().input("foo.rs").target("wasm32-wasip1").run(); + verify_symbols(&tmp_dir().join("foo.wasm")); + rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").run(); + verify_symbols(&tmp_dir().join("foo.wasm")); + rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); + verify_symbols(&tmp_dir().join("foo.wasm")); + rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); + verify_symbols(&tmp_dir().join("foo.wasm")); } fn verify_symbols(path: &Path) { diff --git a/tests/run-pass-valgrind/osx-frameworks.rs b/tests/run-pass-valgrind/osx-frameworks.rs deleted file mode 100644 index 71465c0d199..00000000000 --- a/tests/run-pass-valgrind/osx-frameworks.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ pretty-expanded FIXME #23616 - -#![feature(rustc_private)] - -extern crate libc; - -#[cfg(target_os = "macos")] -#[link(name = "CoreFoundation", kind = "framework")] -extern "C" { - fn CFRunLoopGetTypeID() -> libc::c_ulong; -} - -#[cfg(target_os = "macos")] -pub fn main() { - unsafe { - CFRunLoopGetTypeID(); - } -} - -#[cfg(not(target_os = "macos"))] -pub fn main() {} diff --git a/tests/rustdoc-gui/target.goml b/tests/rustdoc-gui/target.goml index c5e7f813dd1..26071df8d04 100644 --- a/tests/rustdoc-gui/target.goml +++ b/tests/rustdoc-gui/target.goml @@ -1,4 +1,4 @@ -// Check that the targetted element has the expected styles. +// Check that the targeted element has the expected styles. go-to: "file://" + |DOC_PATH| + "/lib2/struct.Foo.html#method.a_method" show-text: true diff --git a/tests/ui/anonymous-higher-ranked-lifetime.stderr b/tests/ui/anonymous-higher-ranked-lifetime.stderr index cc27a0fcf95..c28d856ad55 100644 --- a/tests/ui/anonymous-higher-ranked-lifetime.stderr +++ b/tests/ui/anonymous-higher-ranked-lifetime.stderr @@ -70,7 +70,7 @@ LL | f4(|_: (), _: ()| {}); | | found signature defined here | expected due to this | - = note: expected closure signature `for<'r, 'a> fn(&'a (), &'r ()) -> _` + = note: expected closure signature `for<'a, 'r> fn(&'a (), &'r ()) -> _` found closure signature `fn((), ()) -> _` note: required by a bound in `f4` --> $DIR/anonymous-higher-ranked-lifetime.rs:19:25 @@ -217,7 +217,7 @@ LL | h2(|_: (), _: (), _: (), _: ()| {}); | | found signature defined here | expected due to this | - = note: expected closure signature `for<'t0, 'a> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>, &'t0 (), for<'a, 'b> fn(&'a (), &'b ())) -> _` + = note: expected closure signature `for<'a, 't0> fn(&'a (), Box<(dyn for<'a> Fn(&'a ()) + 'static)>, &'t0 (), for<'a, 'b> fn(&'a (), &'b ())) -> _` found closure signature `fn((), (), (), ()) -> _` note: required by a bound in `h2` --> $DIR/anonymous-higher-ranked-lifetime.rs:30:25 diff --git a/tests/ui/associated-consts/associated-const-ambiguity-report.stderr b/tests/ui/associated-consts/associated-const-ambiguity-report.stderr index 42d722291c3..35ee95d1215 100644 --- a/tests/ui/associated-consts/associated-const-ambiguity-report.stderr +++ b/tests/ui/associated-consts/associated-const-ambiguity-report.stderr @@ -4,16 +4,16 @@ error[E0034]: multiple applicable items in scope LL | const X: i32 = <i32>::ID; | ^^ multiple `ID` found | -note: candidate #1 is defined in an impl of the trait `Foo` for the type `i32` - --> $DIR/associated-const-ambiguity-report.rs:10:5 - | -LL | const ID: i32 = 1; - | ^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `Bar` for the type `i32` +note: candidate #1 is defined in an impl of the trait `Bar` for the type `i32` --> $DIR/associated-const-ambiguity-report.rs:14:5 | LL | const ID: i32 = 3; | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `Foo` for the type `i32` + --> $DIR/associated-const-ambiguity-report.rs:10:5 + | +LL | const ID: i32 = 1; + | ^^^^^^^^^^^^^ help: use fully-qualified syntax to disambiguate | LL | const X: i32 = <i32 as Bar>::ID; diff --git a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs new file mode 100644 index 00000000000..7df042d5f88 --- /dev/null +++ b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.rs @@ -0,0 +1,30 @@ +// Regression test for issue #105056. +//@ edition: 2021 + +fn f(_: impl Trait<T = Copy>) {} +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait +//~| HELP you might have meant to write a bound here +//~| ERROR the trait `Copy` cannot be made into an object + +fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {} +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait +//~| HELP you might have meant to write a bound here +//~| ERROR only auto traits can be used as additional traits in a trait object +//~| HELP consider creating a new trait +//~| ERROR the trait `Eq` cannot be made into an object + +fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {} +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait +//~| HELP you might have meant to write a bound here + +// Don't suggest assoc ty bound in trait object types, that's not valid: +type Obj = dyn Trait<T = Clone>; +//~^ ERROR trait objects must include the `dyn` keyword +//~| HELP add `dyn` keyword before this trait + +trait Trait { type T; } + +fn main() {} diff --git a/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr new file mode 100644 index 00000000000..13be2162c52 --- /dev/null +++ b/tests/ui/associated-type-bounds/suggest-assoc-ty-bound-on-eq-bound.stderr @@ -0,0 +1,91 @@ +error[E0038]: the trait `Copy` cannot be made into an object + --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:20 + | +LL | fn f(_: impl Trait<T = Copy>) {} + | ^^^^^^^^ `Copy` cannot be made into an object + | + = note: the trait cannot be made into an object because it requires `Self: Sized` + = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:42 + | +LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {} + | --------------- ^^ additional non-auto trait + | | + | first non-auto trait + | + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Debug + Eq {}` + = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> + +error[E0038]: the trait `Eq` cannot be made into an object + --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24 + | +LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {} + | ^^^^^^^^^^^^^^^^^^^^ `Eq` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: the trait cannot be made into an object because it uses `Self` as a type parameter + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:4:24 + | +LL | fn f(_: impl Trait<T = Copy>) {} + | ^^^^ + | +help: add `dyn` keyword before this trait + | +LL | fn f(_: impl Trait<T = dyn Copy>) {} + | +++ +help: you might have meant to write a bound here + | +LL | fn f(_: impl Trait<T: Copy>) {} + | ~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:10:24 + | +LL | fn g(_: impl Trait<T = std::fmt::Debug + Eq>) {} + | ^^^^^^^^^^^^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL | fn g(_: impl Trait<T = dyn std::fmt::Debug + Eq>) {} + | +++ +help: you might have meant to write a bound here + | +LL | fn g(_: impl Trait<T: std::fmt::Debug + Eq>) {} + | ~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:18:26 + | +LL | fn h(_: impl Trait<T<> = 'static + for<'a> Fn(&'a ())>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL | fn h(_: impl Trait<T<> = dyn 'static + for<'a> Fn(&'a ())>) {} + | +++ +help: you might have meant to write a bound here + | +LL | fn h(_: impl Trait<T<>: 'static + for<'a> Fn(&'a ())>) {} + | ~ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/suggest-assoc-ty-bound-on-eq-bound.rs:24:26 + | +LL | type Obj = dyn Trait<T = Clone>; + | ^^^^^ + | +help: add `dyn` keyword before this trait + | +LL | type Obj = dyn Trait<T = dyn Clone>; + | +++ + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0038, E0225, E0782. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout index d6fb643702c..def967ba195 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout @@ -1,17 +1,17 @@ -print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2}`: 3078 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of test()}`: 3078 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Suspend0`: 3077 bytes -print-type-size local `.__awaitee`: 3077 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2} +print-type-size local `.__awaitee`: 3077 bytes, type: {async fn body of calls_fut<{async fn body of big_fut()}>()} print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}>`: 3077 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes print-type-size field `.value`: 3077 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}>`: 3077 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of calls_fut<{async fn body of big_fut()}>()}>`: 3077 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 3077 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 3077 bytes -print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}`: 3077 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of calls_fut<{async fn body of big_fut()}>()}`: 3077 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1025 bytes print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes @@ -20,29 +20,29 @@ print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 print-type-size padding: 1 bytes print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes print-type-size local `..coroutine_field4`: 1 bytes, type: bool -print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19} +print-type-size local `.__awaitee`: 1 bytes, type: {async fn body of wait()} print-type-size variant `Suspend1`: 3076 bytes print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes print-type-size padding: 1026 bytes print-type-size local `..coroutine_field4`: 1 bytes, alignment: 1 bytes, type: bool -print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37} +print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body of big_fut()} print-type-size variant `Suspend2`: 2052 bytes print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes print-type-size padding: 1 bytes print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes print-type-size local `..coroutine_field4`: 1 bytes, type: bool -print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19} +print-type-size local `.__awaitee`: 1 bytes, type: {async fn body of wait()} print-type-size variant `Returned`: 1025 bytes print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes print-type-size variant `Panicked`: 1025 bytes print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37}>`: 1025 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes print-type-size field `.value`: 1025 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37}>`: 1025 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of big_fut()}>`: 1025 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1025 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1025 bytes -print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37}`: 1025 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of big_fut()}`: 1025 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1024 bytes print-type-size upvar `.arg`: 1024 bytes @@ -52,13 +52,13 @@ print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.arg`: 1024 bytes print-type-size type: `std::mem::ManuallyDrop<bool>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes print-type-size type: `std::mem::MaybeUninit<bool>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1 bytes @@ -67,7 +67,7 @@ print-type-size discriminant: 1 bytes print-type-size variant `Ready`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Pending`: 0 bytes -print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}`: 1 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of wait()}`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Returned`: 0 bytes diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout index 589df102af4..67168a3d6ef 100644 --- a/tests/ui/async-await/future-sizes/large-arg.stdout +++ b/tests/ui/async-await/future-sizes/large-arg.stdout @@ -1,47 +1,47 @@ -print-type-size type: `{async fn body@$DIR/large-arg.rs:6:21: 8:2}`: 3076 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of test()}`: 3076 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Suspend0`: 3075 bytes -print-type-size local `.__awaitee`: 3075 bytes, type: {async fn body@$DIR/large-arg.rs:10:30: 12:2} +print-type-size local `.__awaitee`: 3075 bytes, type: {async fn body of a<[u8; 1024]>()} print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/large-arg.rs:10:30: 12:2}>`: 3075 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes print-type-size field `.value`: 3075 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/large-arg.rs:10:30: 12:2}>`: 3075 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of a<[u8; 1024]>()}>`: 3075 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 3075 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 3075 bytes -print-type-size type: `{async fn body@$DIR/large-arg.rs:10:30: 12:2}`: 3075 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of a<[u8; 1024]>()}`: 3075 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Suspend0`: 3074 bytes print-type-size upvar `.t`: 1024 bytes -print-type-size local `.__awaitee`: 2050 bytes, type: {async fn body@$DIR/large-arg.rs:13:26: 15:2} +print-type-size local `.__awaitee`: 2050 bytes, type: {async fn body of b<[u8; 1024]>()} print-type-size variant `Returned`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/large-arg.rs:13:26: 15:2}>`: 2050 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes print-type-size field `.value`: 2050 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/large-arg.rs:13:26: 15:2}>`: 2050 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of b<[u8; 1024]>()}>`: 2050 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 2050 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 2050 bytes -print-type-size type: `{async fn body@$DIR/large-arg.rs:13:26: 15:2}`: 2050 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of b<[u8; 1024]>()}`: 2050 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Suspend0`: 2049 bytes print-type-size upvar `.t`: 1024 bytes -print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/large-arg.rs:16:26: 18:2} +print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body of c<[u8; 1024]>()} print-type-size variant `Returned`: 1024 bytes print-type-size upvar `.t`: 1024 bytes print-type-size variant `Panicked`: 1024 bytes print-type-size upvar `.t`: 1024 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/large-arg.rs:16:26: 18:2}>`: 1025 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes print-type-size field `.value`: 1025 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/large-arg.rs:16:26: 18:2}>`: 1025 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of c<[u8; 1024]>()}>`: 1025 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1025 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1025 bytes @@ -50,7 +50,7 @@ print-type-size discriminant: 1 bytes print-type-size variant `Ready`: 1024 bytes print-type-size field `.0`: 1024 bytes print-type-size variant `Pending`: 0 bytes -print-type-size type: `{async fn body@$DIR/large-arg.rs:16:26: 18:2}`: 1025 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of c<[u8; 1024]>()}`: 1025 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 1024 bytes print-type-size upvar `.t`: 1024 bytes diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr index 8a226d712ff..32bd2554abb 100644 --- a/tests/ui/binop/binary-op-suggest-deref.stderr +++ b/tests/ui/binop/binary-op-suggest-deref.stderr @@ -247,14 +247,14 @@ LL | _ = &&0 == Foo; | = help: the trait `PartialEq<Foo>` is not implemented for `&&{integer}` = help: the following other types implement trait `PartialEq<Rhs>`: - isize - i8 + f32 + f64 + i128 i16 i32 i64 - i128 - usize - u8 + i8 + isize and 6 others error[E0369]: binary operation `==` cannot be applied to type `Foo` @@ -303,10 +303,10 @@ LL | let _ = FOO & (*"Sized".to_string().into_boxed_str()); | = help: the trait `BitAnd<str>` is not implemented for `i32` = help: the following other types implement trait `BitAnd<Rhs>`: - <i32 as BitAnd> - <i32 as BitAnd<&i32>> <&'a i32 as BitAnd<i32>> <&i32 as BitAnd<&i32>> + <i32 as BitAnd<&i32>> + <i32 as BitAnd> error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/binary-op-suggest-deref.rs:78:17 diff --git a/tests/ui/binop/binop-mul-i32-f32.stderr b/tests/ui/binop/binop-mul-i32-f32.stderr index 6ed3e7b4447..29e1ff91834 100644 --- a/tests/ui/binop/binop-mul-i32-f32.stderr +++ b/tests/ui/binop/binop-mul-i32-f32.stderr @@ -6,10 +6,10 @@ LL | x * y | = help: the trait `Mul<f32>` is not implemented for `i32` = help: the following other types implement trait `Mul<Rhs>`: - <i32 as Mul> - <i32 as Mul<&i32>> <&'a i32 as Mul<i32>> <&i32 as Mul<&i32>> + <i32 as Mul<&i32>> + <i32 as Mul> error: aborting due to 1 previous error diff --git a/tests/ui/binop/shift-various-bad-types.stderr b/tests/ui/binop/shift-various-bad-types.stderr index b43672ef3b5..38db66f86b4 100644 --- a/tests/ui/binop/shift-various-bad-types.stderr +++ b/tests/ui/binop/shift-various-bad-types.stderr @@ -6,14 +6,14 @@ LL | 22 >> p.char; | = help: the trait `Shr<char>` is not implemented for `{integer}` = help: the following other types implement trait `Shr<Rhs>`: - <isize as Shr> - <isize as Shr<i8>> - <isize as Shr<i16>> - <isize as Shr<i32>> - <isize as Shr<i64>> - <isize as Shr<i128>> - <isize as Shr<usize>> - <isize as Shr<u8>> + <&'a i128 as Shr<i128>> + <&'a i128 as Shr<i16>> + <&'a i128 as Shr<i32>> + <&'a i128 as Shr<i64>> + <&'a i128 as Shr<i8>> + <&'a i128 as Shr<isize>> + <&'a i128 as Shr<u128>> + <&'a i128 as Shr<u16>> and 568 others error[E0277]: no implementation for `{integer} >> &str` @@ -24,14 +24,14 @@ LL | 22 >> p.str; | = help: the trait `Shr<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Shr<Rhs>`: - <isize as Shr> - <isize as Shr<i8>> - <isize as Shr<i16>> - <isize as Shr<i32>> - <isize as Shr<i64>> - <isize as Shr<i128>> - <isize as Shr<usize>> - <isize as Shr<u8>> + <&'a i128 as Shr<i128>> + <&'a i128 as Shr<i16>> + <&'a i128 as Shr<i32>> + <&'a i128 as Shr<i64>> + <&'a i128 as Shr<i8>> + <&'a i128 as Shr<isize>> + <&'a i128 as Shr<u128>> + <&'a i128 as Shr<u16>> and 568 others error[E0277]: no implementation for `{integer} >> &Panolpy` @@ -42,14 +42,14 @@ LL | 22 >> p; | = help: the trait `Shr<&Panolpy>` is not implemented for `{integer}` = help: the following other types implement trait `Shr<Rhs>`: - <isize as Shr> - <isize as Shr<i8>> - <isize as Shr<i16>> - <isize as Shr<i32>> - <isize as Shr<i64>> - <isize as Shr<i128>> - <isize as Shr<usize>> - <isize as Shr<u8>> + <&'a i128 as Shr<i128>> + <&'a i128 as Shr<i16>> + <&'a i128 as Shr<i32>> + <&'a i128 as Shr<i64>> + <&'a i128 as Shr<i8>> + <&'a i128 as Shr<isize>> + <&'a i128 as Shr<u128>> + <&'a i128 as Shr<u16>> and 568 others error[E0308]: mismatched types diff --git a/tests/ui/borrowck/cloning-in-async-block-121547.rs b/tests/ui/borrowck/cloning-in-async-block-121547.rs new file mode 100644 index 00000000000..b2d8dbae977 --- /dev/null +++ b/tests/ui/borrowck/cloning-in-async-block-121547.rs @@ -0,0 +1,11 @@ +//@ edition:2021 + +async fn clone_async_block(value: String) { + for _ in 0..10 { + async { //~ ERROR: use of moved value: `value` [E0382] + drop(value); + //~^ HELP: consider cloning the value if the performance cost is acceptable + }.await + } +} +fn main() {} diff --git a/tests/ui/borrowck/cloning-in-async-block-121547.stderr b/tests/ui/borrowck/cloning-in-async-block-121547.stderr new file mode 100644 index 00000000000..ae57e0018f8 --- /dev/null +++ b/tests/ui/borrowck/cloning-in-async-block-121547.stderr @@ -0,0 +1,22 @@ +error[E0382]: use of moved value: `value` + --> $DIR/cloning-in-async-block-121547.rs:5:9 + | +LL | async fn clone_async_block(value: String) { + | ----- move occurs because `value` has type `String`, which does not implement the `Copy` trait +LL | for _ in 0..10 { + | -------------- inside of this loop +LL | / async { +LL | | drop(value); + | | ----- use occurs due to use in coroutine +LL | | +LL | | }.await + | |_________^ value moved here, in previous iteration of loop + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(value.clone()); + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/cfg/diagnostics-same-crate.rs b/tests/ui/cfg/diagnostics-same-crate.rs index 2d0907c6dfb..d9ff8d61e92 100644 --- a/tests/ui/cfg/diagnostics-same-crate.rs +++ b/tests/ui/cfg/diagnostics-same-crate.rs @@ -4,8 +4,12 @@ pub mod inner { //~^ NOTE found an item that was configured out #[cfg(FALSE)] - pub mod doesnt_exist { //~ NOTE found an item that was configured out + pub mod doesnt_exist { + //~^ NOTE found an item that was configured out + //~| NOTE found an item that was configured out + //~| NOTE found an item that was configured out pub fn hello() {} + pub mod hi {} } pub mod wrong { @@ -20,6 +24,15 @@ pub mod inner { } } +mod placeholder { + use super::inner::doesnt_exist; + //~^ ERROR unresolved import `super::inner::doesnt_exist` + //~| NOTE no `doesnt_exist` in `inner` + use super::inner::doesnt_exist::hi; + //~^ ERROR unresolved import `super::inner::doesnt_exist` + //~| NOTE could not find `doesnt_exist` in `inner` +} + #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)] pub fn vanished() {} diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr index 62a9d132de0..83a44587238 100644 --- a/tests/ui/cfg/diagnostics-same-crate.stderr +++ b/tests/ui/cfg/diagnostics-same-crate.stderr @@ -1,5 +1,29 @@ +error[E0432]: unresolved import `super::inner::doesnt_exist` + --> $DIR/diagnostics-same-crate.rs:28:9 + | +LL | use super::inner::doesnt_exist; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no `doesnt_exist` in `inner` + | +note: found an item that was configured out + --> $DIR/diagnostics-same-crate.rs:7:13 + | +LL | pub mod doesnt_exist { + | ^^^^^^^^^^^^ + +error[E0432]: unresolved import `super::inner::doesnt_exist` + --> $DIR/diagnostics-same-crate.rs:31:23 + | +LL | use super::inner::doesnt_exist::hi; + | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` + | +note: found an item that was configured out + --> $DIR/diagnostics-same-crate.rs:7:13 + | +LL | pub mod doesnt_exist { + | ^^^^^^^^^^^^ + error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner` - --> $DIR/diagnostics-same-crate.rs:37:12 + --> $DIR/diagnostics-same-crate.rs:50:12 | LL | inner::doesnt_exist::hello(); | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` @@ -11,7 +35,7 @@ LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in module `inner` - --> $DIR/diagnostics-same-crate.rs:32:12 + --> $DIR/diagnostics-same-crate.rs:45:12 | LL | inner::uwu(); | ^^^ not found in `inner` @@ -23,31 +47,31 @@ LL | pub fn uwu() {} | ^^^ error[E0425]: cannot find function `meow` in module `inner::right` - --> $DIR/diagnostics-same-crate.rs:41:19 + --> $DIR/diagnostics-same-crate.rs:54:19 | LL | inner::right::meow(); | ^^^^ not found in `inner::right` | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:18:16 + --> $DIR/diagnostics-same-crate.rs:22:16 | LL | pub fn meow() {} | ^^^^ = note: the item is gated behind the `what-a-cool-feature` feature error[E0425]: cannot find function `uwu` in this scope - --> $DIR/diagnostics-same-crate.rs:28:5 + --> $DIR/diagnostics-same-crate.rs:41:5 | LL | uwu(); | ^^^ not found in this scope error[E0425]: cannot find function `vanished` in this scope - --> $DIR/diagnostics-same-crate.rs:48:5 + --> $DIR/diagnostics-same-crate.rs:61:5 | LL | vanished(); | ^^^^^^^^ not found in this scope -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0425, E0433. +Some errors have detailed explanations: E0425, E0432, E0433. For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/const-generics/exhaustive-value.stderr b/tests/ui/const-generics/exhaustive-value.stderr index 42814c1fb70..acaa0cf1a50 100644 --- a/tests/ui/const-generics/exhaustive-value.stderr +++ b/tests/ui/const-generics/exhaustive-value.stderr @@ -6,13 +6,13 @@ LL | <() as Foo<N>>::test() | = help: the following other types implement trait `Foo<N>`: <() as Foo<0>> - <() as Foo<1>> - <() as Foo<2>> - <() as Foo<3>> - <() as Foo<4>> - <() as Foo<5>> - <() as Foo<6>> - <() as Foo<7>> + <() as Foo<100>> + <() as Foo<101>> + <() as Foo<102>> + <() as Foo<103>> + <() as Foo<104>> + <() as Foo<105>> + <() as Foo<106>> and 248 others error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index 6d3b0b8508c..5b296a14869 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -6,11 +6,11 @@ LL | let y = Mask::<_, _>::splat(false); | = note: cannot satisfy `_: MaskElement` = help: the following types implement trait `MaskElement`: - isize - i8 i16 i32 i64 + i8 + isize note: required by a bound in `Mask::<T, N>::splat` --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the type for type parameter `T` is specified diff --git a/tests/ui/const-generics/issues/issue-67185-2.stderr b/tests/ui/const-generics/issues/issue-67185-2.stderr index e39d43205c1..5cc3bb673bc 100644 --- a/tests/ui/const-generics/issues/issue-67185-2.stderr +++ b/tests/ui/const-generics/issues/issue-67185-2.stderr @@ -5,8 +5,8 @@ LL | <u8 as Baz>::Quaks: Bar, | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `[u16; 3]` | = help: the following other types implement trait `Bar`: - [u16; 4] [[u16; 3]; 3] + [u16; 4] = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | @@ -20,8 +20,8 @@ LL | [<u8 as Baz>::Quaks; 2]: Bar, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` | = help: the following other types implement trait `Bar`: - [u16; 4] [[u16; 3]; 3] + [u16; 4] = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | @@ -35,8 +35,8 @@ LL | impl Foo for FooImpl {} | ^^^ the trait `Bar` is not implemented for `[u16; 3]`, which is required by `<u8 as Baz>::Quaks: Bar` | = help: the following other types implement trait `Bar`: - [u16; 4] [[u16; 3]; 3] + [u16; 4] note: required by a bound in `Foo` --> $DIR/issue-67185-2.rs:15:25 | @@ -53,8 +53,8 @@ LL | impl Foo for FooImpl {} | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`, which is required by `[<u8 as Baz>::Quaks; 2]: Bar` | = help: the following other types implement trait `Bar`: - [u16; 4] [[u16; 3]; 3] + [u16; 4] note: required by a bound in `Foo` --> $DIR/issue-67185-2.rs:14:30 | @@ -71,8 +71,8 @@ LL | fn f(_: impl Foo) {} | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` | = help: the following other types implement trait `Bar`: - [u16; 4] [[u16; 3]; 3] + [u16; 4] note: required by a bound in `Foo` --> $DIR/issue-67185-2.rs:14:30 | @@ -89,8 +89,8 @@ LL | fn f(_: impl Foo) {} | ^^^ the trait `Bar` is not implemented for `[u16; 3]` | = help: the following other types implement trait `Bar`: - [u16; 4] [[u16; 3]; 3] + [u16; 4] note: required by a bound in `Foo` --> $DIR/issue-67185-2.rs:15:25 | diff --git a/tests/ui/consts/auxiliary/issue-63226.rs b/tests/ui/consts/auxiliary/issue-63226.rs index 2dc9539ba52..5bb0e694af7 100644 --- a/tests/ui/consts/auxiliary/issue-63226.rs +++ b/tests/ui/consts/auxiliary/issue-63226.rs @@ -2,13 +2,24 @@ pub struct VTable{ state:extern "C" fn(), } -impl VTable{ +impl VTable { pub const fn vtable()->&'static VTable{ Self::VTABLE } const VTABLE: &'static VTable = &VTable{state}; + + pub const VTABLE2: &'static VTable = + &VTable{state: state2}; } +pub const VTABLE3: &'static VTable = + &VTable{state: state3}; + +// Only referenced via a `pub const fn`, and yet reachable. extern "C" fn state() {} +// Only referenced via a associated `pub const`, and yet reachable. +extern "C" fn state2() {} +// Only referenced via a free `pub const`, and yet reachable. +extern "C" fn state3() {} diff --git a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr index 06e398edca9..05f33c33946 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -12,10 +12,10 @@ LL | = [0; (i8::MAX + 1u8) as usize]; | = help: the trait `Add<u8>` is not implemented for `i8` = help: the following other types implement trait `Add<Rhs>`: - <i8 as Add> - <i8 as Add<&i8>> <&'a i8 as Add<i8>> <&i8 as Add<&i8>> + <i8 as Add<&i8>> + <i8 as Add> error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr index 07ef2ac090f..d019f5920b5 100644 --- a/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/tests/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -12,10 +12,10 @@ LL | : [u32; (i8::MAX as i8 + 1u8) as usize] | = help: the trait `Add<u8>` is not implemented for `i8` = help: the following other types implement trait `Add<Rhs>`: - <i8 as Add> - <i8 as Add<&i8>> <&'a i8 as Add<i8>> <&i8 as Add<&i8>> + <i8 as Add<&i8>> + <i8 as Add> error[E0604]: only `u8` can be cast as `char`, not `i8` --> $DIR/const-eval-overflow-4b.rs:22:13 diff --git a/tests/ui/consts/issue-63226.rs b/tests/ui/consts/issue-63226.rs index f8ceab33925..41e63c294ac 100644 --- a/tests/ui/consts/issue-63226.rs +++ b/tests/ui/consts/issue-63226.rs @@ -8,5 +8,7 @@ use issue_63226::VTable; static ICE_ICE:&'static VTable=VTable::vtable(); +static MORE_ICE:&'static VTable=VTable::VTABLE2; +static MORE_ICE3:&'static VTable=issue_63226::VTABLE3; fn main() {} diff --git a/tests/ui/consts/missing-larger-array-impl.stderr b/tests/ui/consts/missing-larger-array-impl.stderr index acf38d00ec6..ff4fa36d684 100644 --- a/tests/ui/consts/missing-larger-array-impl.stderr +++ b/tests/ui/consts/missing-larger-array-impl.stderr @@ -5,14 +5,14 @@ LL | <[X; 35] as Default>::default(); | ^^^^^^^ the trait `Default` is not implemented for `[X; 35]` | = help: the following other types implement trait `Default`: + &[T] + &mut [T] [T; 0] - [T; 1] - [T; 2] - [T; 3] - [T; 4] - [T; 5] - [T; 6] - [T; 7] + [T; 10] + [T; 11] + [T; 12] + [T; 13] + [T; 14] and 27 others error: aborting due to 1 previous error diff --git a/tests/ui/consts/missing_assoc_const_type.rs b/tests/ui/consts/missing_assoc_const_type.rs new file mode 100644 index 00000000000..8d95e3dca63 --- /dev/null +++ b/tests/ui/consts/missing_assoc_const_type.rs @@ -0,0 +1,28 @@ +//! Test that we compute the right type for associated constants +//! of impls, even if the type is missing. We know it from the trait +//! declaration after all. + +trait Range { + const FIRST: u8; + const LAST: u8; +} + +struct TwoDigits; +impl Range for TwoDigits { + const FIRST: = 10; + //~^ ERROR: missing type for `const` item + const LAST: u8 = 99; +} + +const fn digits(x: u8) -> usize { + match x { + TwoDigits::FIRST..=TwoDigits::LAST => 0, + 0..=9 | 100..=255 => panic!(), + } +} + +const FOOMP: [(); { + digits(42) +}] = []; + +fn main() {} diff --git a/tests/ui/consts/missing_assoc_const_type.stderr b/tests/ui/consts/missing_assoc_const_type.stderr new file mode 100644 index 00000000000..28af1f0f321 --- /dev/null +++ b/tests/ui/consts/missing_assoc_const_type.stderr @@ -0,0 +1,8 @@ +error: missing type for `const` item + --> $DIR/missing_assoc_const_type.rs:12:17 + | +LL | const FIRST: = 10; + | ^ help: provide a type for the associated constant: `u8` + +error: aborting due to 1 previous error + diff --git a/tests/ui/consts/missing_assoc_const_type2.rs b/tests/ui/consts/missing_assoc_const_type2.rs new file mode 100644 index 00000000000..baf236700a3 --- /dev/null +++ b/tests/ui/consts/missing_assoc_const_type2.rs @@ -0,0 +1,21 @@ +//! Test that we compute the right type for associated constants +//! of impls, even if the type is missing. We know it from the trait +//! declaration after all. + +trait Range { + const FIRST: u8; + const LAST: u8; +} + +struct TwoDigits; +impl Range for TwoDigits { + const FIRST: = 10; + //~^ ERROR: missing type + const LAST: u8 = 99; +} + +const FOOMP: [(); { + TwoDigits::FIRST as usize +}] = [(); 10]; + +fn main() {} diff --git a/tests/ui/consts/missing_assoc_const_type2.stderr b/tests/ui/consts/missing_assoc_const_type2.stderr new file mode 100644 index 00000000000..1255ca2d102 --- /dev/null +++ b/tests/ui/consts/missing_assoc_const_type2.stderr @@ -0,0 +1,8 @@ +error: missing type for `const` item + --> $DIR/missing_assoc_const_type2.rs:12:17 + | +LL | const FIRST: = 10; + | ^ help: provide a type for the associated constant: `u8` + +error: aborting due to 1 previous error + diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr index 4089c850c80..54dffa3befc 100644 --- a/tests/ui/consts/too_generic_eval_ice.stderr +++ b/tests/ui/consts/too_generic_eval_ice.stderr @@ -22,14 +22,14 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]` = help: the following other types implement trait `PartialEq<Rhs>`: - <[T; N] as PartialEq<[U; N]>> - <[T; N] as PartialEq<[U]>> + <&[T] as PartialEq<Vec<U, A>>> + <&[T] as PartialEq<[U; N]>> + <&mut [T] as PartialEq<Vec<U, A>>> + <&mut [T] as PartialEq<[U; N]>> <[T; N] as PartialEq<&[U]>> <[T; N] as PartialEq<&mut [U]>> - <[T] as PartialEq<Vec<U, A>>> - <[T] as PartialEq<[U; N]>> - <[T] as PartialEq<[U]>> - <&[T] as PartialEq<Vec<U, A>>> + <[T; N] as PartialEq<[U; N]>> + <[T; N] as PartialEq<[U]>> and 3 others error: aborting due to 3 previous errors diff --git a/tests/ui/debuginfo/auxiliary/dylib-dep-helper-aux.rs b/tests/ui/debuginfo/auxiliary/dylib-dep-helper-aux.rs new file mode 100644 index 00000000000..d45e0bcd3b4 --- /dev/null +++ b/tests/ui/debuginfo/auxiliary/dylib-dep-helper-aux.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -g -Cstrip=none -Cforce-frame-pointers=yes + +#[inline(never)] +pub fn callback<F>(f: F) +where + F: FnOnce((&'static str, u32)), +{ + f((file!(), line!())) +} + +#[inline(always)] +pub fn callback_inlined<F>(f: F) +where + F: FnOnce((&'static str, u32)), +{ + f((file!(), line!())) +} diff --git a/tests/ui/debuginfo/auxiliary/dylib-dep-helper.rs b/tests/ui/debuginfo/auxiliary/dylib-dep-helper.rs new file mode 100644 index 00000000000..565d8b65de0 --- /dev/null +++ b/tests/ui/debuginfo/auxiliary/dylib-dep-helper.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -g -Cstrip=none -Cforce-frame-pointers=yes + +#![crate_type = "cdylib"] +#![crate_type = "rlib"] + +#![allow(improper_ctypes_definitions)] + +type Pos = (&'static str, u32); + +macro_rules! pos { + () => { + (file!(), line!()) + }; +} + +#[no_mangle] +pub extern "C" fn foo(outer: Pos, inner: fn(Pos, Pos)) { + inner(outer, pos!()); +} diff --git a/tests/ui/debuginfo/backtrace-dylib-dep.rs b/tests/ui/debuginfo/backtrace-dylib-dep.rs new file mode 100644 index 00000000000..e2414073ede --- /dev/null +++ b/tests/ui/debuginfo/backtrace-dylib-dep.rs @@ -0,0 +1,114 @@ +// Check that backtrace info is correctly generated for dynamic libraries and is usable by a +// rust binary. +// Part of porting some backtrace tests to rustc: <https://github.com/rust-lang/rust/issues/122899>. +// Original test: +// <https://github.com/rust-lang/backtrace-rs/tree/6fa4b85b9962c3e1be8c2e5cc605cd078134152b/crates/dylib-dep> +// ignore-tidy-linelength +//@ ignore-android FIXME #17520 +//@ ignore-fuchsia Backtraces not symbolized +//@ ignore-musl musl doesn't support dynamic libraries (at least when the original test was written). +//@ needs-unwind +//@ compile-flags: -g -Copt-level=0 -Cstrip=none -Cforce-frame-pointers=yes +//@ aux-crate: dylib_dep_helper=dylib-dep-helper.rs +//@ aux-crate: auxiliary=dylib-dep-helper-aux.rs +//@ run-pass + +#![allow(improper_ctypes)] +#![allow(improper_ctypes_definitions)] + +extern crate dylib_dep_helper; +extern crate auxiliary; + +use std::backtrace::Backtrace; + +macro_rules! pos { + () => { + (file!(), line!()) + }; +} + +macro_rules! check { + ($($pos:expr),*) => ({ + verify(&[$($pos,)* pos!()]); + }) +} + +fn verify(filelines: &[Pos]) { + let trace = Backtrace::capture(); + eprintln!("-----------------------------------"); + eprintln!("looking for:"); + for (file, line) in filelines.iter().rev() { + eprintln!("\t{file}:{line}"); + } + eprintln!("found:\n{trace:#?}"); + let mut iter = filelines.iter().rev(); + // FIXME(jieyouxu): use proper `BacktraceFrame` accessors when it becomes available. Right now, + // this depends on the debug format of `Backtrace` which is of course fragile. + let backtrace = format!("{:#?}", trace); + while let Some((file, line)) = iter.next() { + // FIXME(jieyouxu): make this test use proper accessors on `BacktraceFrames` once it has + // them. + assert!(backtrace.contains(file), "expected backtrace to contain {}", file); + assert!(backtrace.contains(&line.to_string()), "expected backtrace to contain {}", line); + } +} + +type Pos = (&'static str, u32); + +extern "C" { + #[link_name = "foo"] + fn foo(p: Pos, cb: fn(Pos, Pos)); +} + +fn main() { + std::env::set_var("RUST_BACKTRACE", "1"); + + unsafe { + foo(pos!(), |a, b| { + check!(a, b) + }) + } + + outer(pos!()); +} + +#[inline(never)] +fn outer(main_pos: Pos) { + inner(main_pos, pos!()); + inner_inlined(main_pos, pos!()); +} + +#[inline(never)] +fn inner(main_pos: Pos, outer_pos: Pos) { + check!(main_pos, outer_pos); + check!(main_pos, outer_pos); + let inner_pos = pos!(); auxiliary::callback(|aux_pos| { + check!(main_pos, outer_pos, inner_pos, aux_pos); + }); + let inner_pos = pos!(); auxiliary::callback_inlined(|aux_pos| { + check!(main_pos, outer_pos, inner_pos, aux_pos); + }); +} + +#[inline(always)] +fn inner_inlined(main_pos: Pos, outer_pos: Pos) { + check!(main_pos, outer_pos); + check!(main_pos, outer_pos); + + #[inline(always)] + fn inner_further_inlined(main_pos: Pos, outer_pos: Pos, inner_pos: Pos) { + check!(main_pos, outer_pos, inner_pos); + } + inner_further_inlined(main_pos, outer_pos, pos!()); + + let inner_pos = pos!(); auxiliary::callback(|aux_pos| { + check!(main_pos, outer_pos, inner_pos, aux_pos); + }); + let inner_pos = pos!(); auxiliary::callback_inlined(|aux_pos| { + check!(main_pos, outer_pos, inner_pos, aux_pos); + }); + + // this tests a distinction between two independent calls to the inlined function. + // (un)fortunately, LLVM somehow merges two consecutive such calls into one node. + inner_further_inlined(main_pos, outer_pos, pos!()); +} diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs index df456f94507..d2723dc32e0 100644 --- a/tests/ui/delegation/bad-resolve.rs +++ b/tests/ui/delegation/bad-resolve.rs @@ -1,5 +1,5 @@ #![feature(fn_delegation)] -//~^ WARN the feature `fn_delegation` is incomplete +#![allow(incomplete_features)] trait Trait { const C: u32 = 0; @@ -34,14 +34,6 @@ impl Trait for S { reuse foo { &self.0 } //~^ ERROR cannot find function `foo` in this scope - reuse F::foo { &self.0 } - //~^ ERROR cannot find function `foo` in `F` - //~| ERROR duplicate definitions with name `foo` -} - -impl S { - reuse F::foo { &self.0 } - //~^ ERROR cannot find function `foo` in `F` } fn main() {} diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index d5206637310..f669ac3730e 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -25,18 +25,6 @@ LL | reuse <F as Trait>::baz; | | help: there is an associated function with a similar name: `bar` | not a member of trait `Trait` -error[E0201]: duplicate definitions with name `foo`: - --> $DIR/bad-resolve.rs:37:5 - | -LL | fn foo(&self, x: i32) -> i32 { x } - | ---------------------------------- item in trait -... -LL | reuse foo { &self.0 } - | --------------------- previous definition here -LL | -LL | reuse F::foo { &self.0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition - error[E0423]: expected function, found associated constant `Trait::C` --> $DIR/bad-resolve.rs:24:11 | @@ -66,27 +54,6 @@ error[E0425]: cannot find function `foo` in this scope LL | reuse foo { &self.0 } | ^^^ not found in this scope -error[E0425]: cannot find function `foo` in `F` - --> $DIR/bad-resolve.rs:37:14 - | -LL | reuse F::foo { &self.0 } - | ^^^ not found in `F` - -error[E0425]: cannot find function `foo` in `F` - --> $DIR/bad-resolve.rs:43:14 - | -LL | reuse F::foo { &self.0 } - | ^^^ not found in `F` - -warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad-resolve.rs:1:12 - | -LL | #![feature(fn_delegation)] - | ^^^^^^^^^^^^^ - | - = note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0046]: not all trait items implemented, missing: `Type` --> $DIR/bad-resolve.rs:22:1 | @@ -96,7 +63,7 @@ LL | type Type; LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ missing `Type` in implementation -error: aborting due to 11 previous errors; 1 warning emitted +error: aborting due to 8 previous errors -Some errors have detailed explanations: E0046, E0201, E0324, E0407, E0423, E0425, E0575, E0576. +Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0575, E0576. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/duplicate-definition-inside-trait-impl.rs b/tests/ui/delegation/duplicate-definition-inside-trait-impl.rs index bd685b40b2f..9c7afcef3ec 100644 --- a/tests/ui/delegation/duplicate-definition-inside-trait-impl.rs +++ b/tests/ui/delegation/duplicate-definition-inside-trait-impl.rs @@ -1,5 +1,5 @@ #![feature(fn_delegation)] -//~^ WARN the feature `fn_delegation` is incomplete +#![allow(incomplete_features)] trait Trait { fn foo(&self) -> u32 { 0 } diff --git a/tests/ui/delegation/duplicate-definition-inside-trait-impl.stderr b/tests/ui/delegation/duplicate-definition-inside-trait-impl.stderr index a5f9e6ad0bf..a0f157800cb 100644 --- a/tests/ui/delegation/duplicate-definition-inside-trait-impl.stderr +++ b/tests/ui/delegation/duplicate-definition-inside-trait-impl.stderr @@ -9,15 +9,6 @@ LL | reuse to_reuse::foo { self } LL | reuse Trait::foo; | ^^^^^^^^^^^^^^^^^ duplicate definition -warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/duplicate-definition-inside-trait-impl.rs:1:12 - | -LL | #![feature(fn_delegation)] - | ^^^^^^^^^^^^^ - | - = note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0201`. diff --git a/tests/ui/delegation/explicit-paths-in-traits-pass.rs b/tests/ui/delegation/explicit-paths-in-traits-pass.rs index 4abcc18b9b2..7d281ad150a 100644 --- a/tests/ui/delegation/explicit-paths-in-traits-pass.rs +++ b/tests/ui/delegation/explicit-paths-in-traits-pass.rs @@ -1,7 +1,7 @@ //@ run-pass #![feature(fn_delegation)] -//~^ WARN the feature `fn_delegation` is incomplete +#![allow(incomplete_features)] trait ToReuse { fn foo(&self, x: i32) -> i32 { x } diff --git a/tests/ui/delegation/explicit-paths-in-traits-pass.stderr b/tests/ui/delegation/explicit-paths-in-traits-pass.stderr deleted file mode 100644 index 8a320b44e63..00000000000 --- a/tests/ui/delegation/explicit-paths-in-traits-pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/explicit-paths-in-traits-pass.rs:3:12 - | -LL | #![feature(fn_delegation)] - | ^^^^^^^^^^^^^ - | - = note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/delegation/explicit-paths-pass.rs b/tests/ui/delegation/explicit-paths-pass.rs index 140605a2bc5..fada793bd11 100644 --- a/tests/ui/delegation/explicit-paths-pass.rs +++ b/tests/ui/delegation/explicit-paths-pass.rs @@ -1,7 +1,7 @@ //@ run-pass #![feature(fn_delegation)] -//~^ WARN the feature `fn_delegation` is incomplete +#![allow(incomplete_features)] trait Trait { fn bar(&self, x: i32) -> i32 { x } @@ -10,7 +10,6 @@ trait Trait { } fn static_method(x: i32) -> i32 { x } fn static_method2(x: i32, y: i32) -> i32 { x + y } - fn baz<'a>(&self, x: &'a i32) -> &'a i32 { x } } struct F; @@ -29,11 +28,9 @@ impl Trait for S { reuse Trait::description { &self.0 } reuse <F as Trait>::static_method; reuse <F as Trait>::static_method2 { S::static_method(self) } - reuse Trait::baz { &self.0 } } impl S { - reuse Trait::baz { &self.0 } reuse <F as Trait>::static_method { to_reuse::foo(self) } } @@ -49,16 +46,8 @@ fn main() { assert_eq!(42, <S as Trait>::static_method(42)); assert_eq!(21, S::static_method2(10, 10)); - reuse <S as Trait>::static_method; - reuse <S as Trait>::static_method2 { static_method(self) } #[inline] reuse to_reuse::foo; - assert_eq!(42, static_method(42)); - assert_eq!(21, static_method2(10, 10)); assert_eq!(43, foo(42)); assert_eq!(15, zero_args()); - - let x: i32 = 15; - assert_eq!(&x, <S as Trait>::baz(&s, &x)); - assert_eq!(&x, S::baz(&s, &x)); } diff --git a/tests/ui/delegation/explicit-paths-pass.stderr b/tests/ui/delegation/explicit-paths-pass.stderr deleted file mode 100644 index 6d25fb4a5a5..00000000000 --- a/tests/ui/delegation/explicit-paths-pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/explicit-paths-pass.rs:3:12 - | -LL | #![feature(fn_delegation)] - | ^^^^^^^^^^^^^ - | - = note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/delegation/explicit-paths-signature-pass.rs b/tests/ui/delegation/explicit-paths-signature-pass.rs index b53e5779924..8c16ad92393 100644 --- a/tests/ui/delegation/explicit-paths-signature-pass.rs +++ b/tests/ui/delegation/explicit-paths-signature-pass.rs @@ -1,7 +1,7 @@ //@ run-pass #![feature(fn_delegation)] -//~^ WARN the feature `fn_delegation` is incomplete +#![allow(incomplete_features)] mod to_reuse { use crate::S; diff --git a/tests/ui/delegation/explicit-paths-signature-pass.stderr b/tests/ui/delegation/explicit-paths-signature-pass.stderr deleted file mode 100644 index 6c81a2ea0af..00000000000 --- a/tests/ui/delegation/explicit-paths-signature-pass.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/explicit-paths-signature-pass.rs:3:12 - | -LL | #![feature(fn_delegation)] - | ^^^^^^^^^^^^^ - | - = note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/delegation/explicit-paths.rs b/tests/ui/delegation/explicit-paths.rs index 1feaaa73f79..a91ca4cb931 100644 --- a/tests/ui/delegation/explicit-paths.rs +++ b/tests/ui/delegation/explicit-paths.rs @@ -1,25 +1,84 @@ #![feature(fn_delegation)] -//~^ WARN the feature `fn_delegation` is incomplete +#![allow(incomplete_features)] trait Trait { - fn bar(&self) -> i32 { 42 } + fn foo1(&self, x: i32) -> i32 { x } + fn foo2(x: i32) -> i32 { x } } struct F; impl Trait for F {} - struct S(F); -impl Trait for S { - reuse <F as Trait>::bar; - //~^ ERROR mismatched types +pub mod to_reuse { + pub fn foo3() {} +} + +impl F { + fn foo4(&self) {} +} + +mod fn_to_other { + use super::*; + + reuse Trait::foo1; + //~^ ERROR delegation to a trait method from a free function is not supported yet + reuse <S as Trait>::foo2; + //~^ ERROR delegation to a trait method from a free function is not supported yet + reuse to_reuse::foo3; + reuse S::foo4; + //~^ ERROR cannot find function `foo4` in `S` +} + +mod inherent_impl_assoc_fn_to_other { + use crate::*; + + impl S { + reuse Trait::foo1 { &self.0 } + reuse <S as Trait>::foo2; + reuse to_reuse::foo3; + reuse F::foo4 { &self.0 } + //~^ ERROR cannot find function `foo4` in `F` + } +} + +mod trait_impl_assoc_fn_to_other { + use crate::*; + + impl Trait for S { + reuse Trait::foo1 { &self.0 } + reuse <F as Trait>::foo2; + reuse to_reuse::foo3; + //~^ ERROR method `foo3` is not a member of trait `Trait` + reuse F::foo4 { &self.0 } + //~^ ERROR method `foo4` is not a member of trait `Trait` + //~| ERROR cannot find function `foo4` in `F` + } +} + +mod trait_assoc_fn_to_other { + use crate::*; + + trait Trait2 : Trait { + reuse <F as Trait>::foo1 { self } + //~^ ERROR mismatched types + reuse <F as Trait>::foo2; + reuse to_reuse::foo3; + reuse F::foo4 { &F } + //~^ ERROR cannot find function `foo4` in `F` + } } -struct S2(F); +mod type_mismatch { + use crate::*; -impl Trait for S2 { - reuse <S2 as Trait>::bar { &self.0 } - //~^ ERROR mismatched types + struct S2; + impl Trait for S { + //~^ ERROR conflicting implementations of trait `Trait` for type `S` + reuse <S2 as Trait>::foo1; + //~^ ERROR mismatched types + //~| ERROR the trait bound `S2: Trait` is not satisfied + } } fn main() {} diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr index 2994b2390de..30891c94c0e 100644 --- a/tests/ui/delegation/explicit-paths.stderr +++ b/tests/ui/delegation/explicit-paths.stderr @@ -1,38 +1,129 @@ -warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/explicit-paths.rs:1:12 +error[E0407]: method `foo3` is not a member of trait `Trait` + --> $DIR/explicit-paths.rs:51:9 | -LL | #![feature(fn_delegation)] - | ^^^^^^^^^^^^^ +LL | reuse to_reuse::foo3; + | ^^^^^^^^^^^^^^^^----^ + | | | + | | help: there is an associated function with a similar name: `foo1` + | not a member of trait `Trait` + +error[E0407]: method `foo4` is not a member of trait `Trait` + --> $DIR/explicit-paths.rs:53:9 + | +LL | reuse F::foo4 { &self.0 } + | ^^^^^^^^^----^^^^^^^^^^^^ + | | | + | | help: there is an associated function with a similar name: `foo1` + | not a member of trait `Trait` + +error[E0425]: cannot find function `foo4` in `S` + --> $DIR/explicit-paths.rs:29:14 + | +LL | reuse S::foo4; + | ^^^^ not found in `S` + +error[E0425]: cannot find function `foo4` in `F` + --> $DIR/explicit-paths.rs:40:18 + | +LL | reuse F::foo4 { &self.0 } + | ^^^^ not found in `F` + | +note: function `fn_to_other::foo4` exists but is inaccessible + --> $DIR/explicit-paths.rs:29:5 + | +LL | reuse S::foo4; + | ^^^^^^^^^^^^^^ not accessible + +error[E0425]: cannot find function `foo4` in `F` + --> $DIR/explicit-paths.rs:53:18 + | +LL | reuse F::foo4 { &self.0 } + | ^^^^ not found in `F` + | +note: function `fn_to_other::foo4` exists but is inaccessible + --> $DIR/explicit-paths.rs:29:5 + | +LL | reuse S::foo4; + | ^^^^^^^^^^^^^^ not accessible + +error[E0425]: cannot find function `foo4` in `F` + --> $DIR/explicit-paths.rs:67:18 + | +LL | reuse F::foo4 { &F } + | ^^^^ not found in `F` + | +note: function `fn_to_other::foo4` exists but is inaccessible + --> $DIR/explicit-paths.rs:29:5 | - = note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information - = note: `#[warn(incomplete_features)]` on by default +LL | reuse S::foo4; + | ^^^^^^^^^^^^^^ not accessible + +error[E0119]: conflicting implementations of trait `Trait` for type `S` + --> $DIR/explicit-paths.rs:76:5 + | +LL | impl Trait for S { + | ---------------- first implementation here +... +LL | impl Trait for S { + | ^^^^^^^^^^^^^^^^ conflicting implementation for `S` + +error: delegation to a trait method from a free function is not supported yet + --> $DIR/explicit-paths.rs:24:18 + | +LL | fn foo1(&self, x: i32) -> i32 { x } + | ----------------------------- callee defined here +... +LL | reuse Trait::foo1; + | ^^^^ + +error: delegation to a trait method from a free function is not supported yet + --> $DIR/explicit-paths.rs:26:25 + | +LL | fn foo2(x: i32) -> i32 { x } + | ---------------------- callee defined here +... +LL | reuse <S as Trait>::foo2; + | ^^^^ error[E0308]: mismatched types - --> $DIR/explicit-paths.rs:14:25 + --> $DIR/explicit-paths.rs:63:36 | -LL | reuse <F as Trait>::bar; - | --------------^^^ - | | | - | | expected `&F`, found `&S` - | arguments to this function are incorrect +LL | trait Trait2 : Trait { + | -------------------- found this type parameter +LL | reuse <F as Trait>::foo1 { self } + | ^^^^ expected `&F`, found `&Self` | = note: expected reference `&F` - found reference `&S` -note: method defined here - --> $DIR/explicit-paths.rs:5:8 + found reference `&Self` + +error[E0277]: the trait bound `S2: Trait` is not satisfied + --> $DIR/explicit-paths.rs:78:16 | -LL | fn bar(&self) -> i32 { 42 } - | ^^^ ----- +LL | reuse <S2 as Trait>::foo1; + | ^^ the trait `Trait` is not implemented for `S2` + | + = help: the following other types implement trait `Trait`: + F + S error[E0308]: mismatched types - --> $DIR/explicit-paths.rs:21:32 + --> $DIR/explicit-paths.rs:78:30 | -LL | reuse <S2 as Trait>::bar { &self.0 } - | ^^^^^^^ expected `&S2`, found `&F` +LL | reuse <S2 as Trait>::foo1; + | ---------------^^^^ + | | | + | | expected `&S2`, found `&S` + | arguments to this function are incorrect | = note: expected reference `&S2` - found reference `&F` + found reference `&S` +note: method defined here + --> $DIR/explicit-paths.rs:5:8 + | +LL | fn foo1(&self, x: i32) -> i32 { x } + | ^^^^ ----- -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0119, E0277, E0308, E0407, E0425. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/delegation/not-supported.rs b/tests/ui/delegation/not-supported.rs index 23081b1e1fc..9dccb12b57a 100644 --- a/tests/ui/delegation/not-supported.rs +++ b/tests/ui/delegation/not-supported.rs @@ -1,6 +1,6 @@ #![feature(c_variadic)] #![feature(fn_delegation)] -//~^ WARN the feature `fn_delegation` is incomplete +#![allow(incomplete_features)] mod generics { trait GenericTrait<T> { diff --git a/tests/ui/delegation/not-supported.stderr b/tests/ui/delegation/not-supported.stderr index 324b79f3c53..f6c49366899 100644 --- a/tests/ui/delegation/not-supported.stderr +++ b/tests/ui/delegation/not-supported.stderr @@ -1,12 +1,3 @@ -warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/not-supported.rs:2:12 - | -LL | #![feature(fn_delegation)] - | ^^^^^^^^^^^^^ - | - = note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information - = note: `#[warn(incomplete_features)]` on by default - error: delegation with early bound generics is not supported yet --> $DIR/not-supported.rs:16:29 | @@ -178,7 +169,7 @@ LL | pub reuse to_reuse2::foo; LL | reuse to_reuse1::foo; | ^^^ -error: aborting due to 19 previous errors; 1 warning emitted +error: aborting due to 19 previous errors Some errors have detailed explanations: E0049, E0195. For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/delegation/parse.rs b/tests/ui/delegation/parse.rs index 5e8026c5532..72b00bf6e0d 100644 --- a/tests/ui/delegation/parse.rs +++ b/tests/ui/delegation/parse.rs @@ -2,7 +2,7 @@ #![feature(decl_macro)] #![feature(fn_delegation)] -//~^ WARN the feature `fn_delegation` is incomplete +#![allow(incomplete_features)] macro_rules! reuse { {} => {} } diff --git a/tests/ui/delegation/parse.stderr b/tests/ui/delegation/parse.stderr deleted file mode 100644 index 1e420ceeec7..00000000000 --- a/tests/ui/delegation/parse.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/parse.rs:4:12 - | -LL | #![feature(fn_delegation)] - | ^^^^^^^^^^^^^ - | - = note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/delegation/target-expr-pass.rs b/tests/ui/delegation/target-expr-pass.rs index 1f2edf0dc13..9e326a19b8f 100644 --- a/tests/ui/delegation/target-expr-pass.rs +++ b/tests/ui/delegation/target-expr-pass.rs @@ -1,7 +1,7 @@ //@ run-pass #![feature(fn_delegation)] -//~^ WARN the feature `fn_delegation` is incomplete +#![allow(incomplete_features)] mod to_reuse { pub fn foo(x: i32) -> i32 { x } diff --git a/tests/ui/delegation/target-expr-pass.stderr b/tests/ui/delegation/target-expr-pass.stderr index dd1f3a14e0b..c8d73ec6e5a 100644 --- a/tests/ui/delegation/target-expr-pass.stderr +++ b/tests/ui/delegation/target-expr-pass.stderr @@ -1,12 +1,3 @@ -warning: the feature `fn_delegation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/target-expr-pass.rs:3:12 - | -LL | #![feature(fn_delegation)] - | ^^^^^^^^^^^^^ - | - = note: see issue #118212 <https://github.com/rust-lang/rust/issues/118212> for more information - = note: `#[warn(incomplete_features)]` on by default - warning: trait `Trait` is never used --> $DIR/target-expr-pass.rs:17:7 | @@ -27,5 +18,5 @@ warning: struct `S` is never constructed LL | struct S(F); | ^ -warning: 4 warnings emitted +warning: 3 warnings emitted diff --git a/tests/ui/delegation/target-expr.rs b/tests/ui/delegation/target-expr.rs new file mode 100644 index 00000000000..fd7ea943b9d --- /dev/null +++ b/tests/ui/delegation/target-expr.rs @@ -0,0 +1,40 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn static_method(x: i32) -> i32 { x } +} + +struct F; + +struct S(F); +impl Trait for S {} + +fn foo(x: i32) -> i32 { x } + +fn bar<T: Default>(_: T) { + reuse Trait::static_method { + //~^ ERROR delegation to a trait method from a free function is not supported yet + //~| ERROR delegation with early bound generics is not supported yet + //~| ERROR mismatched types + let _ = T::Default(); + //~^ ERROR can't use generic parameters from outer item + } +} + +fn main() { + let y = 0; + reuse <S as Trait>::static_method { + //~^ ERROR delegation to a trait method from a free function is not supported yet + let x = y; + //~^ ERROR can't capture dynamic environment in a fn item + foo(self); + + let reuse_ptr: fn(i32) -> i32 = static_method; + reuse_ptr(0) + } + self.0; + //~^ ERROR expected value, found module `self` + let z = x; + //~^ ERROR cannot find value `x` in this scope +} diff --git a/tests/ui/delegation/target-expr.stderr b/tests/ui/delegation/target-expr.stderr new file mode 100644 index 00000000000..b30f0c474c6 --- /dev/null +++ b/tests/ui/delegation/target-expr.stderr @@ -0,0 +1,84 @@ +error[E0401]: can't use generic parameters from outer item + --> $DIR/target-expr.rs:20:17 + | +LL | fn bar<T: Default>(_: T) { + | - type parameter from outer item +LL | reuse Trait::static_method { + | - help: try introducing a local generic parameter here: `T,` +... +LL | let _ = T::Default(); + | ^^^^^^^^^^ use of generic parameter from outer item + +error[E0434]: can't capture dynamic environment in a fn item + --> $DIR/target-expr.rs:29:17 + | +LL | let x = y; + | ^ + | + = help: use the `|| { ... }` closure form instead + +error[E0424]: expected value, found module `self` + --> $DIR/target-expr.rs:36:5 + | +LL | fn main() { + | ---- this function can't have a `self` parameter +... +LL | self.0; + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter + +error[E0425]: cannot find value `x` in this scope + --> $DIR/target-expr.rs:38:13 + | +LL | let z = x; + | ^ + | +help: the binding `x` is available in a different scope in the same function + --> $DIR/target-expr.rs:29:13 + | +LL | let x = y; + | ^ + +error: delegation with early bound generics is not supported yet + --> $DIR/target-expr.rs:16:18 + | +LL | fn static_method(x: i32) -> i32 { x } + | ------------------------------- callee defined here +... +LL | reuse Trait::static_method { + | ^^^^^^^^^^^^^ + +error: delegation to a trait method from a free function is not supported yet + --> $DIR/target-expr.rs:16:18 + | +LL | fn static_method(x: i32) -> i32 { x } + | ------------------------------- callee defined here +... +LL | reuse Trait::static_method { + | ^^^^^^^^^^^^^ + +error: delegation to a trait method from a free function is not supported yet + --> $DIR/target-expr.rs:27:25 + | +LL | fn static_method(x: i32) -> i32 { x } + | ------------------------------- callee defined here +... +LL | reuse <S as Trait>::static_method { + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/target-expr.rs:16:32 + | +LL | reuse Trait::static_method { + | ________________________________^ +LL | | +LL | | +LL | | +LL | | let _ = T::Default(); +LL | | +LL | | } + | |_____^ expected `i32`, found `()` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0308, E0401, E0424, E0425, E0434. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/deriving/issue-103157.stderr b/tests/ui/deriving/issue-103157.stderr index f76701860ef..612a7aff225 100644 --- a/tests/ui/deriving/issue-103157.stderr +++ b/tests/ui/deriving/issue-103157.stderr @@ -8,14 +8,14 @@ LL | Float(Option<f64>), | ^^^^^^^^^^^ the trait `Eq` is not implemented for `f64`, which is required by `Option<f64>: Eq` | = help: the following other types implement trait `Eq`: - isize - i8 + i128 i16 i32 i64 - i128 - usize - u8 + i8 + isize + u128 + u16 and 4 others = note: required for `Option<f64>` to implement `Eq` note: required by a bound in `AssertParamIsEq` diff --git a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr index 6ac0bf21e4a..a2b7d804cb8 100644 --- a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr +++ b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr @@ -7,12 +7,12 @@ LL | f1.foo(1usize); | required by a bound introduced by this call | = help: the following other types implement trait `Foo<A>`: - <Bar as Foo<i8>> <Bar as Foo<i16>> <Bar as Foo<i32>> - <Bar as Foo<u8>> + <Bar as Foo<i8>> <Bar as Foo<u16>> <Bar as Foo<u32>> + <Bar as Foo<u8>> error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index ae15e054f62..7229b9ac986 100644 --- a/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/tests/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -8,10 +8,10 @@ LL | Foo::<i32>::bar(&1i8); | = help: the following other types implement trait `Foo<B>`: <i8 as Foo<bool>> - <i8 as Foo<u8>> <i8 as Foo<u16>> <i8 as Foo<u32>> <i8 as Foo<u64>> + <i8 as Foo<u8>> error[E0277]: the trait bound `u8: Foo<i32>` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:25:21 @@ -38,10 +38,10 @@ LL | Foo::<i32>::bar(&true); = help: the following other types implement trait `Foo<B>`: <bool as Foo<bool>> <bool as Foo<i8>> - <bool as Foo<u8>> <bool as Foo<u16>> <bool as Foo<u32>> <bool as Foo<u64>> + <bool as Foo<u8>> error: aborting due to 3 previous errors diff --git a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs new file mode 100644 index 00000000000..13f8fd5fe22 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs @@ -0,0 +1,16 @@ +#![crate_type = "lib"] + +// This isn't intended to compile, so it's easiest to just ignore this error. +extern crate rustc_serialize; //~ERROR can't find crate for `rustc_serialize` + +#[derive( + RustcEncodable, + //~^ ERROR use of unstable library feature 'rustc_encodable_decodable' + //~^^ WARNING this was previously accepted by the compiler + //~^^^ WARNING use of deprecated macro `RustcEncodable` + RustcDecodable, + //~^ ERROR use of unstable library feature 'rustc_encodable_decodable' + //~^^ WARNING this was previously accepted by the compiler + //~^^^ WARNING use of deprecated macro `RustcDecodable` +)] +struct S; diff --git a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr new file mode 100644 index 00000000000..02b74dacf4d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr @@ -0,0 +1,66 @@ +error[E0463]: can't find crate for `rustc_serialize` + --> $DIR/feature-gate-rustc_encodable_decodable.rs:4:1 + | +LL | extern crate rustc_serialize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate + | + = help: maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview` + +error: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code + --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5 + | +LL | RustcEncodable, + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266> + = note: `#[deny(soft_unstable)]` on by default + +warning: use of deprecated macro `RustcEncodable`: rustc-serialize is deprecated and no longer supported + --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5 + | +LL | RustcEncodable, + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +error: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code + --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5 + | +LL | RustcDecodable, + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266> + +warning: use of deprecated macro `RustcDecodable`: rustc-serialize is deprecated and no longer supported + --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5 + | +LL | RustcDecodable, + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0463`. +Future incompatibility report: Future breakage diagnostic: +error: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code + --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5 + | +LL | RustcEncodable, + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266> + = note: `#[deny(soft_unstable)]` on by default + +Future breakage diagnostic: +error: use of unstable library feature 'rustc_encodable_decodable': derive macro for `rustc-serialize`; should not be used in new code + --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5 + | +LL | RustcDecodable, + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266> + = note: `#[deny(soft_unstable)]` on by default + diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr index 3c5428e59fb..a22bba07c02 100644 --- a/tests/ui/fmt/ifmt-unimpl.stderr +++ b/tests/ui/fmt/ifmt-unimpl.stderr @@ -7,14 +7,14 @@ LL | format!("{:X}", "3"); | required by a bound introduced by this call | = help: the following other types implement trait `UpperHex`: - isize - i8 + &T + &mut T + NonZero<T> + Saturating<T> + Wrapping<T> + i128 i16 i32 - i64 - i128 - usize - u8 and 9 others = note: required for `&str` to implement `UpperHex` note: required by a bound in `core::fmt::rt::Argument::<'a>::new_upper_hex` diff --git a/tests/ui/generic-const-items/hkl_where_bounds.rs b/tests/ui/generic-const-items/hkl_where_bounds.rs new file mode 100644 index 00000000000..cded518312a --- /dev/null +++ b/tests/ui/generic-const-items/hkl_where_bounds.rs @@ -0,0 +1,14 @@ +//! Test that nonsense bounds prevent consts from being evaluated at all. +//@ check-pass + +#![feature(generic_const_items)] +#![allow(incomplete_features)] +trait Trait { + const ASSOC: u32; +} + +// rustfmt eats the where bound +#[rustfmt::skip] +const ASSOC: u32 = <&'static ()>::ASSOC where for<'a> &'a (): Trait; + +fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/future.current.stderr b/tests/ui/higher-ranked/trait-bounds/future.current.stderr index 5a6381ad28e..673bc48a424 100644 --- a/tests/ui/higher-ranked/trait-bounds/future.current.stderr +++ b/tests/ui/higher-ranked/trait-bounds/future.current.stderr @@ -1,6 +1,6 @@ error: the compiler unexpectedly panicked. this is a bug. query stack during panic: -#0 [evaluate_obligation] evaluating trait selection obligation `for<'a> {async fn body@$DIR/future.rs:33:35: 35:2}: core::future::future::Future` +#0 [evaluate_obligation] evaluating trait selection obligation `for<'a> {async fn body of strlen()}: core::future::future::Future` #1 [codegen_select_candidate] computing candidate for `<strlen as Trait>` end of query stack diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr b/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr new file mode 100644 index 00000000000..ded9a92d8e8 --- /dev/null +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.infer.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/defining-use-captured-non-universal-region.rs:13:18 + | +LL | fn foo<'a>() -> impl Sized + 'a { + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | let i: i32 = foo::<'_>(); + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs b/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs new file mode 100644 index 00000000000..e18302dc061 --- /dev/null +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.rs @@ -0,0 +1,22 @@ +// This was an ICE. See #110726. + +//@ revisions: statik infer fixed +//@ [fixed] check-pass +#![allow(unconditional_recursion)] + +fn foo<'a>() -> impl Sized + 'a { + #[cfg(statik)] + let i: i32 = foo::<'static>(); + //[statik]~^ ERROR expected generic lifetime parameter, found `'static` + + #[cfg(infer)] + let i: i32 = foo::<'_>(); + //[infer]~^ ERROR expected generic lifetime parameter, found `'_` + + #[cfg(fixed)] + let i: i32 = foo::<'a>(); + + i +} + +fn main() {} diff --git a/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr b/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr new file mode 100644 index 00000000000..43beb29f9ec --- /dev/null +++ b/tests/ui/impl-trait/defining-use-captured-non-universal-region.statik.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'static` + --> $DIR/defining-use-captured-non-universal-region.rs:9:18 + | +LL | fn foo<'a>() -> impl Sized + 'a { + | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type +LL | #[cfg(statik)] +LL | let i: i32 = foo::<'static>(); + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-2.rs b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-2.rs new file mode 100644 index 00000000000..56e099c28d2 --- /dev/null +++ b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-2.rs @@ -0,0 +1,74 @@ +// issue: #110623 +//@ check-pass + +use std::{collections::BTreeMap, num::ParseIntError, str::FromStr}; + +enum FileSystem { + File(usize), + Directory(BTreeMap<String, FileSystem>), +} + +impl FromStr for FileSystem { + type Err = ParseIntError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + if s.starts_with("dir") { + Ok(Self::new_dir()) + } else { + Ok(Self::File(s.split_whitespace().next().unwrap().parse()?)) + } + } +} + +impl FileSystem { + fn new_dir() -> FileSystem { + FileSystem::Directory(BTreeMap::new()) + } + + fn insert(&mut self, name: String, other: FileSystem) -> Option<FileSystem> { + match self { + FileSystem::File(_) => panic!("can only insert into directory!"), + FileSystem::Directory(tree) => tree.insert(name, other), + } + } + + // Recursively build a tree from commands. This uses (abuses?) + // the fact that `cd /` only appears at the start and that + // subsequent `cd`s can only move ONE level to use the recursion + // stack as the filesystem stack + fn build<'a>( + &mut self, + mut commands: impl Iterator<Item = &'a str> + 'a, + ) -> Option<impl Iterator<Item = &'a str> + 'a> { + let cmd = commands.next()?; + let mut elements = cmd.lines(); + match elements.next().map(str::trim) { + Some("cd /") | None => self.build(commands), + Some("cd ..") => { + // return to higher scope + Some(commands) + } + Some("ls") => { + for item in elements { + let name = item.split_whitespace().last().unwrap(); + let prior = self.insert(name.to_string(), item.parse().unwrap()); + debug_assert!(prior.is_none()); + } + // continue on + self.build(commands) + } + Some(other_cd) => { + let name = other_cd + .trim() + .strip_prefix("cd ") + .expect("expected a cd command"); + let mut directory = FileSystem::new_dir(); + let further_commands = directory.build(commands); + self.insert(name.to_string(), directory); + self.build(further_commands?) // THIS LINE FAILS TO COMPILE + } + } + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs new file mode 100644 index 00000000000..a6dcad3face --- /dev/null +++ b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +trait Bar<const FOO: &'static str> {} +impl Bar<"asdf"> for () {} + +fn foo<const FOO: &'static str>() -> impl Bar<"asdf"> { + () +} + +fn main() {} diff --git a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region.rs b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region.rs new file mode 100644 index 00000000000..f90ff51c651 --- /dev/null +++ b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region.rs @@ -0,0 +1,16 @@ +// issue: #111906 +//@ check-pass + +#![allow(unconditional_recursion)] + +fn foo<'a: 'a>() -> impl Sized { + let _: () = foo::<'a>(); + loop {} +} + +fn bar<'a: 'a>() -> impl Sized + 'a { + let _: *mut &'a () = bar::<'a>(); + loop {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/equality.stderr b/tests/ui/impl-trait/equality.stderr index 9b8bff215e0..69f4cbbbf42 100644 --- a/tests/ui/impl-trait/equality.stderr +++ b/tests/ui/impl-trait/equality.stderr @@ -30,10 +30,10 @@ LL | n + sum_to(n - 1) | = help: the trait `Add<impl Foo>` is not implemented for `u32` = help: the following other types implement trait `Add<Rhs>`: - <u32 as Add> - <u32 as Add<&u32>> <&'a u32 as Add<u32>> <&u32 as Add<&u32>> + <u32 as Add<&u32>> + <u32 as Add> error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr index 1d648162113..78ef8ec404c 100644 --- a/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.current.stderr @@ -1,4 +1,4 @@ -error: {foo<DefId(..)_'a/#0>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} +error: {foo<'{erased}>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} --> $DIR/erased-regions-in-hidden-ty.rs:12:36 | LL | fn foo<'a: 'a>(x: &'a Vec<i32>) -> impl Fn() + 'static { diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr index 1d648162113..78ef8ec404c 100644 --- a/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.next.stderr @@ -1,4 +1,4 @@ -error: {foo<DefId(..)_'a/#0>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} +error: {foo<'{erased}>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} --> $DIR/erased-regions-in-hidden-ty.rs:12:36 | LL | fn foo<'a: 'a>(x: &'a Vec<i32>) -> impl Fn() + 'static { diff --git a/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs index 9d71685f179..e60f1badcae 100644 --- a/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs +++ b/tests/ui/impl-trait/erased-regions-in-hidden-ty.rs @@ -10,7 +10,7 @@ // Make sure that the compiler can handle `ReErased` in the hidden type of an opaque. fn foo<'a: 'a>(x: &'a Vec<i32>) -> impl Fn() + 'static { - //~^ ERROR 'a/#0>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} + //~^ ERROR '{erased}>::{closure#0} closure_kind_ty=i8 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=()} // Can't write whole type because of lack of path sanitization || () } diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs index 15778662375..199cbbf4fcc 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.rs @@ -2,10 +2,8 @@ use std::fmt::Debug; fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - //~^ ERROR cannot resolve opaque type - |x| x - //~^ ERROR concrete type differs from previous defining opaque type use + //~^ ERROR expected generic lifetime parameter, found `'_` } fn _b<'a>() -> impl Fn(&'a u8) -> (impl Debug + 'a) { diff --git a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr index c19420bbb0c..6064b09ef09 100644 --- a/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr +++ b/tests/ui/impl-trait/impl-fn-predefined-lifetimes.stderr @@ -1,21 +1,11 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/impl-fn-predefined-lifetimes.rs:7:9 - | -LL | |x| x - | ^ expected `impl Debug + '_`, got `&u8` - | -note: previous use here - --> $DIR/impl-fn-predefined-lifetimes.rs:7:5 - | -LL | |x| x - | ^^^^^ - -error[E0720]: cannot resolve opaque type - --> $DIR/impl-fn-predefined-lifetimes.rs:4:35 +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/impl-fn-predefined-lifetimes.rs:5:9 | LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) { - | ^^^^^^^^^^^^^^^ cannot resolve opaque type + | -- this generic parameter must be used with a generic lifetime parameter +LL | |x| x + | ^ -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0720`. +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr index 421afc96eed..d62e3ac4183 100644 --- a/tests/ui/impl-trait/impl_trait_projections.stderr +++ b/tests/ui/impl-trait/impl_trait_projections.stderr @@ -35,14 +35,14 @@ LL | -> <::std::ops::Range<impl Debug> as Iterator>::Item | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator` | = help: the following other types implement trait `Step`: + Char + Ipv4Addr + Ipv6Addr char - isize - i8 + i128 i16 i32 i64 - i128 - usize and 8 others = note: required for `std::ops::Range<impl Debug>` to implement `Iterator` @@ -56,14 +56,14 @@ LL | | } | |_^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator` | = help: the following other types implement trait `Step`: + Char + Ipv4Addr + Ipv6Addr char - isize - i8 + i128 i16 i32 i64 - i128 - usize and 8 others = note: required for `std::ops::Range<impl Debug>` to implement `Iterator` diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs index 41d5f0f6449..5b3a4eb53ff 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs @@ -5,6 +5,7 @@ trait Foo { fn bar<'other: 'a>() -> impl Sized + 'a {} //~^ ERROR use of undeclared lifetime name `'a` //~| ERROR use of undeclared lifetime name `'a` + //~| ERROR expected generic lifetime parameter, found `'static` } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr index b0832eb33ca..8975578dabd 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr @@ -28,6 +28,15 @@ help: consider introducing lifetime `'a` here LL | trait Foo<'a> { | ++++ -error: aborting due to 2 previous errors +error[E0792]: expected generic lifetime parameter, found `'static` + --> $DIR/bad-item-bound-within-rpitit-2.rs:5:45 + | +LL | fn bar<'other: 'a>() -> impl Sized + 'a {} + | ------ ^^ + | | + | cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0261`. +Some errors have detailed explanations: E0261, E0792. +For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/impl-trait/no-method-suggested-traits.stderr b/tests/ui/impl-trait/no-method-suggested-traits.stderr index 7a4dc366618..676247d1a42 100644 --- a/tests/ui/impl-trait/no-method-suggested-traits.stderr +++ b/tests/ui/impl-trait/no-method-suggested-traits.stderr @@ -127,8 +127,8 @@ LL | Foo.method(); = note: the following traits define an item `method`, perhaps you need to implement one of them: candidate #1: `foo::Bar` candidate #2: `PubPub` - candidate #3: `no_method_suggested_traits::qux::PrivPub` - candidate #4: `Reexported` + candidate #3: `Reexported` + candidate #4: `no_method_suggested_traits::qux::PrivPub` error[E0599]: no method named `method` found for struct `Rc<&mut Box<&Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:42:43 @@ -140,8 +140,8 @@ LL | std::rc::Rc::new(&mut Box::new(&Foo)).method(); = note: the following traits define an item `method`, perhaps you need to implement one of them: candidate #1: `foo::Bar` candidate #2: `PubPub` - candidate #3: `no_method_suggested_traits::qux::PrivPub` - candidate #4: `Reexported` + candidate #3: `Reexported` + candidate #4: `no_method_suggested_traits::qux::PrivPub` error[E0599]: no method named `method2` found for type `u64` in the current scope --> $DIR/no-method-suggested-traits.rs:45:10 diff --git a/tests/ui/impl-trait/rpit/early_bound.rs b/tests/ui/impl-trait/rpit/early_bound.rs index 6dda687929c..005bcea59f2 100644 --- a/tests/ui/impl-trait/rpit/early_bound.rs +++ b/tests/ui/impl-trait/rpit/early_bound.rs @@ -5,6 +5,7 @@ fn test<'a: 'a>(n: bool) -> impl Sized + 'a { let true = n else { loop {} }; let _ = || { let _ = identity::<&'a ()>(test(false)); + //~^ ERROR expected generic lifetime parameter, found `'_` }; loop {} } diff --git a/tests/ui/impl-trait/rpit/early_bound.stderr b/tests/ui/impl-trait/rpit/early_bound.stderr index 780dea4e284..b0c7bd4199c 100644 --- a/tests/ui/impl-trait/rpit/early_bound.stderr +++ b/tests/ui/impl-trait/rpit/early_bound.stderr @@ -1,3 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/early_bound.rs:7:17 + | +LL | fn test<'a: 'a>(n: bool) -> impl Sized + 'a { + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | let _ = identity::<&'a ()>(test(false)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: concrete type differs from previous defining opaque type use --> $DIR/early_bound.rs:3:29 | @@ -10,5 +19,6 @@ note: previous use here LL | let _ = identity::<&'a ()>(test(false)); | ^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs new file mode 100644 index 00000000000..5e04e6b091a --- /dev/null +++ b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.rs @@ -0,0 +1,37 @@ +// issue: #111935 + +#![allow(unconditional_recursion)] + +// Lt indirection is necessary to make the lifetime of the function late-bound, +// in order to bypass some other bugs. +type Lt<'lt> = Option<*mut &'lt ()>; + +mod statik { + use super::*; + // invalid defining use: Opaque<'static> := () + fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a { + let _: () = foo(Lt::<'static>::None); + //~^ ERROR expected generic lifetime parameter, found `'static` + } +} + +mod infer { + use super::*; + // invalid defining use: Opaque<'_> := () + fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a { + let _: () = foo(Lt::<'_>::None); + //~^ ERROR expected generic lifetime parameter, found `'_` + } +} + +mod equal { + use super::*; + // invalid defining use: Opaque<'a, 'a> := () + // because of the use of equal lifetimes in args + fn foo<'a, 'b>(_: Lt<'a>, _: Lt<'b>) -> impl Sized + 'a + 'b { + let _: () = foo(Lt::<'a>::None, Lt::<'a>::None); + //~^ ERROR non-defining opaque type use in defining scope + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr new file mode 100644 index 00000000000..d2a224601fb --- /dev/null +++ b/tests/ui/impl-trait/rpit/non-defining-use-lifetimes.stderr @@ -0,0 +1,31 @@ +error[E0792]: expected generic lifetime parameter, found `'static` + --> $DIR/non-defining-use-lifetimes.rs:13:16 + | +LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a { + | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type +LL | let _: () = foo(Lt::<'static>::None); + | ^^ + +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/non-defining-use-lifetimes.rs:22:16 + | +LL | fn foo<'a>(_: Lt<'a>) -> impl Sized + 'a { + | -- this generic parameter must be used with a generic lifetime parameter +LL | let _: () = foo(Lt::<'_>::None); + | ^^ + +error: non-defining opaque type use in defining scope + --> $DIR/non-defining-use-lifetimes.rs:32:16 + | +LL | let _: () = foo(Lt::<'a>::None, Lt::<'a>::None); + | ^^ + | +note: lifetime used multiple times + --> $DIR/non-defining-use-lifetimes.rs:31:58 + | +LL | fn foo<'a, 'b>(_: Lt<'a>, _: Lt<'b>) -> impl Sized + 'a + 'b { + | ^^ ^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/include-macros/parent_dir.rs b/tests/ui/include-macros/parent_dir.rs new file mode 100644 index 00000000000..5fadff77a37 --- /dev/null +++ b/tests/ui/include-macros/parent_dir.rs @@ -0,0 +1,12 @@ +//@ normalize-stderr-test: "`: .*" -> "`: $$FILE_NOT_FOUND_MSG" + +fn main() { + let _ = include_str!("include-macros/file.txt"); //~ ERROR couldn't read + //~^HELP different directory + let _ = include_str!("hello.rs"); //~ ERROR couldn't read + //~^HELP different directory + let _ = include_bytes!("../../data.bin"); //~ ERROR couldn't read + //~^HELP different directory + let _ = include_str!("tests/ui/include-macros/file.txt"); //~ ERROR couldn't read + //~^HELP different directory +} diff --git a/tests/ui/include-macros/parent_dir.stderr b/tests/ui/include-macros/parent_dir.stderr new file mode 100644 index 00000000000..0470d5b1f1e --- /dev/null +++ b/tests/ui/include-macros/parent_dir.stderr @@ -0,0 +1,50 @@ +error: couldn't read `$DIR/include-macros/file.txt`: $FILE_NOT_FOUND_MSG + --> $DIR/parent_dir.rs:4:13 + | +LL | let _ = include_str!("include-macros/file.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a file with the same name in a different directory + | +LL | let _ = include_str!("file.txt"); + | ~~~~~~~~~~ + +error: couldn't read `$DIR/hello.rs`: $FILE_NOT_FOUND_MSG + --> $DIR/parent_dir.rs:6:13 + | +LL | let _ = include_str!("hello.rs"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a file with the same name in a different directory + | +LL | let _ = include_str!("../hello.rs"); + | ~~~~~~~~~~~~~ + +error: couldn't read `$DIR/../../data.bin`: $FILE_NOT_FOUND_MSG + --> $DIR/parent_dir.rs:8:13 + | +LL | let _ = include_bytes!("../../data.bin"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a file with the same name in a different directory + | +LL | let _ = include_bytes!("data.bin"); + | ~~~~~~~~~~ + +error: couldn't read `$DIR/tests/ui/include-macros/file.txt`: $FILE_NOT_FOUND_MSG + --> $DIR/parent_dir.rs:10:13 + | +LL | let _ = include_str!("tests/ui/include-macros/file.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a file with the same name in a different directory + | +LL | let _ = include_str!("file.txt"); + | ~~~~~~~~~~ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/issues/issue-11771.stderr b/tests/ui/issues/issue-11771.stderr index b37140f60f9..161fce4b031 100644 --- a/tests/ui/issues/issue-11771.stderr +++ b/tests/ui/issues/issue-11771.stderr @@ -6,14 +6,14 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add<Rhs>`: - <isize as Add> - <isize as Add<&isize>> - <i8 as Add> - <i8 as Add<&i8>> - <i16 as Add> - <i16 as Add<&i16>> - <i32 as Add> - <i32 as Add<&i32>> + <&'a f32 as Add<f32>> + <&'a f64 as Add<f64>> + <&'a i128 as Add<i128>> + <&'a i16 as Add<i16>> + <&'a i32 as Add<i32>> + <&'a i64 as Add<i64>> + <&'a i8 as Add<i8>> + <&'a isize as Add<isize>> and 48 others error[E0277]: cannot add `()` to `{integer}` @@ -24,14 +24,14 @@ LL | 1 + | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add<Rhs>`: - <isize as Add> - <isize as Add<&isize>> - <i8 as Add> - <i8 as Add<&i8>> - <i16 as Add> - <i16 as Add<&i16>> - <i32 as Add> - <i32 as Add<&i32>> + <&'a f32 as Add<f32>> + <&'a f64 as Add<f64>> + <&'a i128 as Add<i128>> + <&'a i16 as Add<i16>> + <&'a i32 as Add<i32>> + <&'a i64 as Add<i64>> + <&'a i8 as Add<i8>> + <&'a isize as Add<isize>> and 48 others error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-18446.stderr b/tests/ui/issues/issue-18446.stderr index d84c490df4d..08a9cfc644f 100644 --- a/tests/ui/issues/issue-18446.stderr +++ b/tests/ui/issues/issue-18446.stderr @@ -4,17 +4,17 @@ error[E0034]: multiple applicable items in scope LL | x.foo(); | ^^^ multiple `foo` found | -note: candidate #1 is defined in an impl for the type `(dyn T + 'a)` - --> $DIR/issue-18446.rs:9:5 - | -LL | fn foo(&self) {} - | ^^^^^^^^^^^^^ -note: candidate #2 is defined in the trait `T` +note: candidate #1 is defined in the trait `T` --> $DIR/issue-18446.rs:5:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ -help: disambiguate the method for candidate #2 +note: candidate #2 is defined in an impl for the type `(dyn T + 'a)` + --> $DIR/issue-18446.rs:9:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +help: disambiguate the method for candidate #1 | LL | T::foo(&x); | ~~~~~~~~~~ diff --git a/tests/ui/issues/issue-24352.stderr b/tests/ui/issues/issue-24352.stderr index 015569cce06..a9f886158e1 100644 --- a/tests/ui/issues/issue-24352.stderr +++ b/tests/ui/issues/issue-24352.stderr @@ -6,10 +6,10 @@ LL | 1.0f64 - 1 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub<Rhs>`: - <f64 as Sub> - <f64 as Sub<&f64>> <&'a f64 as Sub<f64>> <&f64 as Sub<&f64>> + <f64 as Sub<&f64>> + <f64 as Sub> help: consider using a floating-point literal by writing it with `.0` | LL | 1.0f64 - 1.0 diff --git a/tests/ui/issues/issue-3702-2.stderr b/tests/ui/issues/issue-3702-2.stderr index 4edca796f43..7ab6520a0ca 100644 --- a/tests/ui/issues/issue-3702-2.stderr +++ b/tests/ui/issues/issue-3702-2.stderr @@ -4,24 +4,24 @@ error[E0034]: multiple applicable items in scope LL | self.to_int() + other.to_int() | ^^^^^^ multiple `to_int` found | -note: candidate #1 is defined in an impl of the trait `ToPrimitive` for the type `isize` - --> $DIR/issue-3702-2.rs:2:5 - | -LL | fn to_int(&self) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `Add` for the type `isize` +note: candidate #1 is defined in an impl of the trait `Add` for the type `isize` --> $DIR/issue-3702-2.rs:14:5 | LL | fn to_int(&self) -> isize { *self } | ^^^^^^^^^^^^^^^^^^^^^^^^^ -help: disambiguate the method for candidate #1 +note: candidate #2 is defined in an impl of the trait `ToPrimitive` for the type `isize` + --> $DIR/issue-3702-2.rs:2:5 | -LL | ToPrimitive::to_int(&self) + other.to_int() - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ -help: disambiguate the method for candidate #2 +LL | fn to_int(&self) -> isize { 0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method for candidate #1 | LL | Add::to_int(&self) + other.to_int() | ~~~~~~~~~~~~~~~~~~ +help: disambiguate the method for candidate #2 + | +LL | ToPrimitive::to_int(&self) + other.to_int() + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-50582.stderr b/tests/ui/issues/issue-50582.stderr index 7b65fa25ae3..1967b51128f 100644 --- a/tests/ui/issues/issue-50582.stderr +++ b/tests/ui/issues/issue-50582.stderr @@ -16,14 +16,14 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); | = help: the trait `Add<()>` is not implemented for `{integer}` = help: the following other types implement trait `Add<Rhs>`: - <isize as Add> - <isize as Add<&isize>> - <i8 as Add> - <i8 as Add<&i8>> - <i16 as Add> - <i16 as Add<&i16>> - <i32 as Add> - <i32 as Add<&i32>> + <&'a f32 as Add<f32>> + <&'a f64 as Add<f64>> + <&'a i128 as Add<i128>> + <&'a i16 as Add<i16>> + <&'a i32 as Add<i32>> + <&'a i64 as Add<i64>> + <&'a i8 as Add<i8>> + <&'a isize as Add<isize>> and 48 others error: aborting due to 2 previous errors diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr index 1bfe765e78a..4d1e4207fdc 100644 --- a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr @@ -33,8 +33,8 @@ LL | println!("{}", scores.sum::<i32>()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum<A>`: - <i32 as Sum> <i32 as Sum<&'a i32>> + <i32 as Sum> note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:14:10 | @@ -66,8 +66,8 @@ LL | .sum::<i32>(), | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum<A>`: - <i32 as Sum> <i32 as Sum<&'a i32>> + <i32 as Sum> note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:23:14 | @@ -99,8 +99,8 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum<A>`: - <i32 as Sum> <i32 as Sum<&'a i32>> + <i32 as Sum> note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-fixable.rs:27:38 | diff --git a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr index f68c596367e..9381a98e077 100644 --- a/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr +++ b/tests/ui/iterators/invalid-iterator-chain-with-int-infer.stderr @@ -8,8 +8,8 @@ LL | let x = Some(()).iter().map(|()| 1).sum::<f32>(); | = help: the trait `Sum<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sum<A>`: - <f32 as Sum> <f32 as Sum<&'a f32>> + <f32 as Sum> note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain-with-int-infer.rs:2:29 | diff --git a/tests/ui/iterators/invalid-iterator-chain.stderr b/tests/ui/iterators/invalid-iterator-chain.stderr index 4dc13086912..6129a724f44 100644 --- a/tests/ui/iterators/invalid-iterator-chain.stderr +++ b/tests/ui/iterators/invalid-iterator-chain.stderr @@ -33,8 +33,8 @@ LL | println!("{}", scores.sum::<i32>()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum<A>`: - <i32 as Sum> <i32 as Sum<&'a i32>> + <i32 as Sum> note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:12:10 | @@ -65,8 +65,8 @@ LL | .sum::<i32>(), | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum<A>`: - <i32 as Sum> <i32 as Sum<&'a i32>> + <i32 as Sum> note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:25:14 | @@ -104,8 +104,8 @@ LL | .sum::<i32>(), | = help: the trait `Sum<f64>` is not implemented for `i32` = help: the following other types implement trait `Sum<A>`: - <i32 as Sum> <i32 as Sum<&'a i32>> + <i32 as Sum> note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:33:14 | @@ -134,8 +134,8 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); | = help: the trait `Sum<()>` is not implemented for `i32` = help: the following other types implement trait `Sum<A>`: - <i32 as Sum> <i32 as Sum<&'a i32>> + <i32 as Sum> note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:38:38 | @@ -162,8 +162,8 @@ LL | println!("{}", vec![(), ()].iter().sum::<i32>()); | = help: the trait `Sum<&()>` is not implemented for `i32` = help: the following other types implement trait `Sum<A>`: - <i32 as Sum> <i32 as Sum<&'a i32>> + <i32 as Sum> note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:39:33 | diff --git a/tests/ui/layout/failed-to-get-layout-for-type-error-ice-92979.rs b/tests/ui/layout/failed-to-get-layout-for-type-error-ice-92979.rs new file mode 100644 index 00000000000..7445d8dc51e --- /dev/null +++ b/tests/ui/layout/failed-to-get-layout-for-type-error-ice-92979.rs @@ -0,0 +1,78 @@ +// ICE: failed to get layout for [type error] +// issue: rust-lang/rust#92979 + +use std::fs; +use std::fs::File; +use std::io::Read; +use std::convert::TryInto; + +fn get_file_as_byte_vec(filename: &String) -> Vec<u8> { + let mut f = File::open(&filename).expect("no file found"); + let metadata = fs::metadata(&filename).expect("unable to read metadata"); + let mut buffer = vec![0; metadata.len() as usize]; + f.read(&mut buffer).expect("buffer overflow"); + + buffer +} + + + +fn demo<T, const N: usize>(v: Vec<T>) -> [T; N] { + v.try_into() + .unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len())) +} + + +fn main() { + + // Specify filepath + let file: &String = &String::from("SomeBinaryDataFileWith4ByteHeaders_f32s_and_u32s"); + + // Read file into a vector of bytes + let file_data = get_file_as_byte_vec(file); + + // Print length of vector and first few values + let length = file_data.len(); + println!("The read function read {} bytes", length); + println!("The first few bytes:"); + for i in 0..20{ + println!("{}", file_data[i]); + } + + // Manually count just to make sure + let mut n: u64 = 0; + for data in file_data{ + n += 1; + } + println!("We counted {} bytes", n); + assert!(n as usize == length, "Manual counting does not equal len method"); + + // Simulation parameters + const N: usize = 49627502; // Number of Particles + const bs: f64 = 125.0; // Box Size + const HEADER_INCREMENT: u64 = 4*1; + + // Initialize index and counter variables + let (mut j, mut pos, mut vel, mut id, mut mass): (u64, u64, u64, u64, u64) = (0, 0, 0, 0, 0); + + // Unpack Position Data + j += HEADER_INCREMENT; + let mut position: Vec<f32> = Vec::new(); + while position.len() < N*3 { + + let p: Vec<u8> = Vec::new(); + for item in 0i8..4 { + let item = item; + p.push(file_data[j as usize]); + j += 1; + } + &mut position[position.len()] = f32::from_be_bytes(demo(p)); + //~^ ERROR invalid left-hand side of assignment + } + + // Ensure position data is indeed position by checking values + for p in position { + assert!((p > 0.) & (p < 125.), "Not in box") + } + +} diff --git a/tests/ui/layout/failed-to-get-layout-for-type-error-ice-92979.stderr b/tests/ui/layout/failed-to-get-layout-for-type-error-ice-92979.stderr new file mode 100644 index 00000000000..a6b9e376896 --- /dev/null +++ b/tests/ui/layout/failed-to-get-layout-for-type-error-ice-92979.stderr @@ -0,0 +1,16 @@ +error[E0070]: invalid left-hand side of assignment + --> $DIR/failed-to-get-layout-for-type-error-ice-92979.rs:69:39 + | +LL | &mut position[position.len()] = f32::from_be_bytes(demo(p)); + | ----------------------------- ^ + | | + | cannot assign to this expression + | +help: consider dereferencing here to assign to the mutably borrowed value + | +LL | *&mut position[position.len()] = f32::from_be_bytes(demo(p)); + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0070`. diff --git a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.rs b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.rs new file mode 100644 index 00000000000..6380449124f --- /dev/null +++ b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.rs @@ -0,0 +1,59 @@ +// ICE argument to function with "rust-call" ABI is not a tuple +// issue: rust-lang/rust#81974 + +#![feature(unboxed_closures)] +#![feature(fn_traits)] + +use std::collections::HashMap; +use std::hash::Hash; + +struct CachedFun<A, B> { + cache: HashMap<A, B>, + fun: fn(&mut CachedFun<A, B>, A) -> B, +} + +impl<A: Eq + Hash, B> CachedFun<A, B> { + fn new(fun: fn(&mut Self, A) -> B) -> Self { + CachedFun { + cache: HashMap::new(), + fun, + } + } +} + +impl<A, B> FnOnce<A> for CachedFun<A, B> +//~^ ERROR type parameter to bare `FnOnce` trait must be a tuple +where + A: Eq + Hash + Clone, + B: Clone, +{ + type Output = B; + extern "rust-call" fn call_once(mut self, a: A) -> Self::Output { + //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument + self.call_mut(a) + //~^ ERROR `A` is not a tuple + } +} + +impl<A, B> FnMut<A> for CachedFun<A, B> +//~^ ERROR type parameter to bare `FnMut` trait must be a tuple +where + A: Eq + Hash + Clone, + B: Clone, +{ + extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output { + //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument + self.cache.get(&a).map(|a| a.clone()).unwrap_or_else(|| { + let b = (self.fun)(self, a.clone()); + self.cache.insert(a, b.clone()); + b + }) + } +} + +fn main() -> () { + let pesce = |y: &mut CachedFun<i32, i32>, x| x + 1; + let cachedcoso = CachedFun::new(pesce); + cachedcoso.call_once(1); + //~^ ERROR `i32` is not a tuple +} diff --git a/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr new file mode 100644 index 00000000000..cceaddf7803 --- /dev/null +++ b/tests/ui/layout/rust-call-abi-not-a-tuple-ice-81974.stderr @@ -0,0 +1,78 @@ +error[E0059]: type parameter to bare `FnOnce` trait must be a tuple + --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:24:12 + | +LL | impl<A, B> FnOnce<A> for CachedFun<A, B> + | ^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | +note: required by a bound in `FnOnce` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL +help: consider further restricting this bound + | +LL | A: Eq + Hash + Clone + std::marker::Tuple, + | ++++++++++++++++++++ + +error[E0059]: type parameter to bare `FnMut` trait must be a tuple + --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:38:12 + | +LL | impl<A, B> FnMut<A> for CachedFun<A, B> + | ^^^^^^^^ the trait `Tuple` is not implemented for `A` + | +note: required by a bound in `FnMut` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL +help: consider further restricting this bound + | +LL | A: Eq + Hash + Clone + std::marker::Tuple, + | ++++++++++++++++++++ + +error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument + --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:31:5 + | +LL | extern "rust-call" fn call_once(mut self, a: A) -> Self::Output { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | +help: consider further restricting this bound + | +LL | A: Eq + Hash + Clone + std::marker::Tuple, + | ++++++++++++++++++++ + +error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument + --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:44:5 + | +LL | extern "rust-call" fn call_mut(&mut self, a: A) -> Self::Output { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `A` + | +help: consider further restricting this bound + | +LL | A: Eq + Hash + Clone + std::marker::Tuple, + | ++++++++++++++++++++ + +error[E0277]: `A` is not a tuple + --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:33:23 + | +LL | self.call_mut(a) + | -------- ^ the trait `Tuple` is not implemented for `A` + | | + | required by a bound introduced by this call + | +note: required by a bound in `call_mut` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL +help: consider further restricting this bound + | +LL | A: Eq + Hash + Clone + std::marker::Tuple, + | ++++++++++++++++++++ + +error[E0277]: `i32` is not a tuple + --> $DIR/rust-call-abi-not-a-tuple-ice-81974.rs:57:26 + | +LL | cachedcoso.call_once(1); + | --------- ^ the trait `Tuple` is not implemented for `i32` + | | + | required by a bound introduced by this call + | +note: required by a bound in `call_once` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0059, E0277. +For more information about an error, try `rustc --explain E0059`. diff --git a/tests/ui/lazy-type-alias/trailing-where-clause.stderr b/tests/ui/lazy-type-alias/trailing-where-clause.stderr index baf4215bbf7..534df382eb6 100644 --- a/tests/ui/lazy-type-alias/trailing-where-clause.stderr +++ b/tests/ui/lazy-type-alias/trailing-where-clause.stderr @@ -5,12 +5,12 @@ LL | let _: Alias<()>; | ^^ the trait `From<()>` is not implemented for `String` | = help: the following other types implement trait `From<T>`: - <String as From<char>> + <String as From<&String>> + <String as From<&mut str>> + <String as From<&str>> <String as From<Box<str>>> <String as From<Cow<'a, str>>> - <String as From<&str>> - <String as From<&mut str>> - <String as From<&String>> + <String as From<char>> note: required by a bound in `Alias` --> $DIR/trailing-where-clause.rs:8:13 | diff --git a/tests/ui/linkage-attr/framework.omit.stderr b/tests/ui/linkage-attr/framework.omit.stderr new file mode 100644 index 00000000000..5cb4d391437 --- /dev/null +++ b/tests/ui/linkage-attr/framework.omit.stderr @@ -0,0 +1,8 @@ +error: linking with `cc` failed: exit status: 1 + | + ld: Undefined symbols: + _CFRunLoopGetTypeID, referenced from: + clang: error: linker command failed with exit code 1 (use -v to see invocation) + + +error: aborting due to 1 previous error diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs new file mode 100644 index 00000000000..662ef4c429d --- /dev/null +++ b/tests/ui/linkage-attr/framework.rs @@ -0,0 +1,30 @@ +// Check that linking frameworks on Apple platforms works. +//@ only-macos +//@ revisions: omit link weak both +//@ [omit]build-fail +//@ [link]run-pass +//@ [weak]run-pass +//@ [both]run-pass + +// The linker's exact error output changes between Xcode versions. +//@ compare-output-lines-by-subset +//@ normalize-stderr-test: "Undefined symbols for architecture .*" -> "ld: Undefined symbols:" +//@ normalize-stderr-test: "._CFRunLoopGetTypeID.," -> "_CFRunLoopGetTypeID," + +#![cfg_attr(any(weak, both), feature(link_arg_attribute))] + +#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))] +#[cfg_attr( + any(weak, both), + link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"), + link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim") +)] +extern "C" { + fn CFRunLoopGetTypeID() -> core::ffi::c_ulong; +} + +pub fn main() { + unsafe { + CFRunLoopGetTypeID(); + } +} diff --git a/tests/ui/macros/macros-nonfatal-errors.rs b/tests/ui/macros/macros-nonfatal-errors.rs index 20e6d705003..46e865031ec 100644 --- a/tests/ui/macros/macros-nonfatal-errors.rs +++ b/tests/ui/macros/macros-nonfatal-errors.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr-test: "existed:.*\(" -> "existed: $$FILE_NOT_FOUND_MSG (" +//@ normalize-stderr-test: "`: .*" -> "`: $$FILE_NOT_FOUND_MSG" // test that errors in a (selection) of macros don't kill compilation // immediately, so that we get more errors listed at a time. diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr index ca373ea6cd9..abf43e2a009 100644 --- a/tests/ui/macros/macros-nonfatal-errors.stderr +++ b/tests/ui/macros/macros-nonfatal-errors.stderr @@ -200,7 +200,7 @@ error: argument must be a string literal LL | include_str!(invalid); | ^^^^^^^ -error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) +error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG --> $DIR/macros-nonfatal-errors.rs:113:5 | LL | include_str!("i'd be quite surprised if a file with this name existed"); @@ -214,7 +214,7 @@ error: argument must be a string literal LL | include_bytes!(invalid); | ^^^^^^^ -error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) +error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG --> $DIR/macros-nonfatal-errors.rs:115:5 | LL | include_bytes!("i'd be quite surprised if a file with this name existed"); diff --git a/tests/ui/match/postfix-match/no-unused-parens.rs b/tests/ui/match/postfix-match/no-unused-parens.rs new file mode 100644 index 00000000000..46cac7a6107 --- /dev/null +++ b/tests/ui/match/postfix-match/no-unused-parens.rs @@ -0,0 +1,8 @@ +//@ check-pass + +#![feature(postfix_match)] + +fn main() { + (&1).match { a => a }; + (1 + 2).match { b => b }; +} diff --git a/tests/ui/methods/method-ambig-two-traits-cross-crate.stderr b/tests/ui/methods/method-ambig-two-traits-cross-crate.stderr index 0c775612bfb..0fc0c909ea8 100644 --- a/tests/ui/methods/method-ambig-two-traits-cross-crate.stderr +++ b/tests/ui/methods/method-ambig-two-traits-cross-crate.stderr @@ -4,20 +4,20 @@ error[E0034]: multiple applicable items in scope LL | fn main() { 1_usize.me(); } | ^^ multiple `me` found | - = note: candidate #1 is defined in an impl of the trait `Me` for the type `usize` -note: candidate #2 is defined in an impl of the trait `Me2` for the type `usize` +note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize` --> $DIR/method-ambig-two-traits-cross-crate.rs:10:22 | LL | impl Me2 for usize { fn me(&self) -> usize { *self } } | ^^^^^^^^^^^^^^^^^^^^^ + = note: candidate #2 is defined in an impl of the trait `Me` for the type `usize` help: disambiguate the method for candidate #1 | -LL | fn main() { Me::me(&1_usize); } - | ~~~~~~~~~~~~~~~~ -help: disambiguate the method for candidate #2 - | LL | fn main() { Me2::me(&1_usize); } | ~~~~~~~~~~~~~~~~~ +help: disambiguate the method for candidate #2 + | +LL | fn main() { Me::me(&1_usize); } + | ~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/methods/method-ambig-two-traits-with-default-method.stderr b/tests/ui/methods/method-ambig-two-traits-with-default-method.stderr index 9da307436e9..b36ef77fb7e 100644 --- a/tests/ui/methods/method-ambig-two-traits-with-default-method.stderr +++ b/tests/ui/methods/method-ambig-two-traits-with-default-method.stderr @@ -4,23 +4,23 @@ error[E0034]: multiple applicable items in scope LL | 1_usize.method(); | ^^^^^^ multiple `method` found | -note: candidate #1 is defined in an impl of the trait `Foo` for the type `usize` - --> $DIR/method-ambig-two-traits-with-default-method.rs:5:13 - | -LL | trait Foo { fn method(&self) {} } - | ^^^^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `Bar` for the type `usize` +note: candidate #1 is defined in an impl of the trait `Bar` for the type `usize` --> $DIR/method-ambig-two-traits-with-default-method.rs:6:13 | LL | trait Bar { fn method(&self) {} } | ^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `Foo` for the type `usize` + --> $DIR/method-ambig-two-traits-with-default-method.rs:5:13 + | +LL | trait Foo { fn method(&self) {} } + | ^^^^^^^^^^^^^^^^ help: disambiguate the method for candidate #1 | -LL | Foo::method(&1_usize); +LL | Bar::method(&1_usize); | ~~~~~~~~~~~~~~~~~~~~~ help: disambiguate the method for candidate #2 | -LL | Bar::method(&1_usize); +LL | Foo::method(&1_usize); | ~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr index 6df49e432a1..7d9b38fb29b 100644 --- a/tests/ui/methods/method-call-err-msg.stderr +++ b/tests/ui/methods/method-call-err-msg.stderr @@ -64,8 +64,8 @@ note: the trait `Iterator` must be implemented --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `take`, perhaps you need to implement one of them: - candidate #1: `std::io::Read` - candidate #2: `Iterator` + candidate #1: `Iterator` + candidate #2: `std::io::Read` error[E0061]: this method takes 3 arguments but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:21:7 diff --git a/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index 755179650bb..6159d87c73e 100644 --- a/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/tests/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -29,33 +29,33 @@ error[E0034]: multiple applicable items in scope LL | let z = x.foo(); | ^^^ multiple `foo` found | -note: candidate #1 is defined in an impl of the trait `X` for the type `T` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:45:9 +note: candidate #1 is defined in the trait `FinalFoo` + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:59:5 | -LL | fn foo(self: Smaht<Self, u64>) -> u64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo(&self) -> u8; + | ^^^^^^^^^^^^^^^^^^^^ note: candidate #2 is defined in an impl of the trait `NuisanceFoo` for the type `T` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:72:9 | LL | fn foo(self) {} | ^^^^^^^^^^^^ -note: candidate #3 is defined in the trait `FinalFoo` - --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:59:5 +note: candidate #3 is defined in an impl of the trait `X` for the type `T` + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:45:9 | -LL | fn foo(&self) -> u8; - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn foo(self: Smaht<Self, u64>) -> u64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the method for candidate #1 | -LL | let z = X::foo(x); - | ~~~~~~~~~ +LL | let z = FinalFoo::foo(&x); + | ~~~~~~~~~~~~~~~~~ help: disambiguate the method for candidate #2 | LL | let z = NuisanceFoo::foo(x); | ~~~~~~~~~~~~~~~~~~~ help: disambiguate the method for candidate #3 | -LL | let z = FinalFoo::foo(&x); - | ~~~~~~~~~~~~~~~~~ +LL | let z = X::foo(x); + | ~~~~~~~~~ error[E0308]: mismatched types --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:139:24 diff --git a/tests/ui/methods/method-not-found-generic-arg-elision.stderr b/tests/ui/methods/method-not-found-generic-arg-elision.stderr index b97688d3868..a665500fd9e 100644 --- a/tests/ui/methods/method-not-found-generic-arg-elision.stderr +++ b/tests/ui/methods/method-not-found-generic-arg-elision.stderr @@ -35,10 +35,10 @@ LL | wrapper.method(); | ^^^^^^ method not found in `Wrapper<bool>` | = note: the method was found for - - `Wrapper<i8>` - `Wrapper<i16>` - `Wrapper<i32>` - `Wrapper<i64>` + - `Wrapper<i8>` and 2 more types error[E0599]: no method named `other` found for struct `Wrapper` in the current scope @@ -60,9 +60,9 @@ LL | wrapper.method(); | ^^^^^^ method not found in `Wrapper2<'_, bool, 3>` | = note: the method was found for - - `Wrapper2<'a, i8, C>` - `Wrapper2<'a, i16, C>` - `Wrapper2<'a, i32, C>` + - `Wrapper2<'a, i8, C>` error[E0599]: no method named `other` found for struct `Wrapper2` in the current scope --> $DIR/method-not-found-generic-arg-elision.rs:98:13 diff --git a/tests/ui/mismatched_types/binops.stderr b/tests/ui/mismatched_types/binops.stderr index b18ab7f7608..3585587ed4c 100644 --- a/tests/ui/mismatched_types/binops.stderr +++ b/tests/ui/mismatched_types/binops.stderr @@ -6,14 +6,14 @@ LL | 1 + Some(1); | = help: the trait `Add<Option<{integer}>>` is not implemented for `{integer}` = help: the following other types implement trait `Add<Rhs>`: - <isize as Add> - <isize as Add<&isize>> - <i8 as Add> - <i8 as Add<&i8>> - <i16 as Add> - <i16 as Add<&i16>> - <i32 as Add> - <i32 as Add<&i32>> + <&'a f32 as Add<f32>> + <&'a f64 as Add<f64>> + <&'a i128 as Add<i128>> + <&'a i16 as Add<i16>> + <&'a i32 as Add<i32>> + <&'a i64 as Add<i64>> + <&'a i8 as Add<i8>> + <&'a isize as Add<isize>> and 48 others error[E0277]: cannot subtract `Option<{integer}>` from `usize` @@ -24,10 +24,10 @@ LL | 2 as usize - Some(1); | = help: the trait `Sub<Option<{integer}>>` is not implemented for `usize` = help: the following other types implement trait `Sub<Rhs>`: - <usize as Sub> - <usize as Sub<&usize>> <&'a usize as Sub<usize>> <&usize as Sub<&usize>> + <usize as Sub<&usize>> + <usize as Sub> error[E0277]: cannot multiply `{integer}` by `()` --> $DIR/binops.rs:4:7 @@ -37,14 +37,14 @@ LL | 3 * (); | = help: the trait `Mul<()>` is not implemented for `{integer}` = help: the following other types implement trait `Mul<Rhs>`: - <isize as Mul> - <isize as Mul<&isize>> - <i8 as Mul> - <i8 as Mul<&i8>> - <i16 as Mul> - <i16 as Mul<&i16>> - <i32 as Mul> - <i32 as Mul<&i32>> + <&'a f32 as Mul<f32>> + <&'a f64 as Mul<f64>> + <&'a i128 as Mul<i128>> + <&'a i16 as Mul<i16>> + <&'a i32 as Mul<i32>> + <&'a i64 as Mul<i64>> + <&'a i8 as Mul<i8>> + <&'a isize as Mul<isize>> and 49 others error[E0277]: cannot divide `{integer}` by `&str` @@ -55,14 +55,14 @@ LL | 4 / ""; | = help: the trait `Div<&str>` is not implemented for `{integer}` = help: the following other types implement trait `Div<Rhs>`: - <isize as Div> - <isize as Div<&isize>> - <i8 as Div> - <i8 as Div<&i8>> - <i16 as Div> - <i16 as Div<&i16>> - <i32 as Div> - <i32 as Div<&i32>> + <&'a f32 as Div<f32>> + <&'a f64 as Div<f64>> + <&'a i128 as Div<i128>> + <&'a i16 as Div<i16>> + <&'a i32 as Div<i32>> + <&'a i64 as Div<i64>> + <&'a i8 as Div<i8>> + <&'a isize as Div<isize>> and 54 others error[E0277]: can't compare `{integer}` with `String` @@ -73,14 +73,14 @@ LL | 5 < String::new(); | = help: the trait `PartialOrd<String>` is not implemented for `{integer}` = help: the following other types implement trait `PartialOrd<Rhs>`: - isize - i8 + f32 + f64 + i128 i16 i32 i64 - i128 - usize - u8 + i8 + isize and 6 others error[E0277]: can't compare `{integer}` with `Result<{integer}, _>` @@ -91,14 +91,14 @@ LL | 6 == Ok(1); | = help: the trait `PartialEq<Result<{integer}, _>>` is not implemented for `{integer}` = help: the following other types implement trait `PartialEq<Rhs>`: - isize - i8 + f32 + f64 + i128 i16 i32 i64 - i128 - usize - u8 + i8 + isize and 6 others error: aborting due to 6 previous errors diff --git a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr index ff28480bd99..01abf2e17f1 100644 --- a/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr +++ b/tests/ui/never_type/diverging-fallback-no-leak.fallback.stderr @@ -7,8 +7,8 @@ LL | unconstrained_arg(return); | required by a bound introduced by this call | = help: the following other types implement trait `Test`: - i32 () + i32 = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 <https://github.com/rust-lang/rust/issues/48950> for more information) = help: did you intend to use the type `()` here instead? note: required by a bound in `unconstrained_arg` diff --git a/tests/ui/never_type/issue-13352.stderr b/tests/ui/never_type/issue-13352.stderr index 91885380b1f..1b979d93446 100644 --- a/tests/ui/never_type/issue-13352.stderr +++ b/tests/ui/never_type/issue-13352.stderr @@ -6,10 +6,10 @@ LL | 2_usize + (loop {}); | = help: the trait `Add<()>` is not implemented for `usize` = help: the following other types implement trait `Add<Rhs>`: - <usize as Add> - <usize as Add<&usize>> <&'a usize as Add<usize>> <&usize as Add<&usize>> + <usize as Add<&usize>> + <usize as Add> error: aborting due to 1 previous error diff --git a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr index be0fc0f98e2..14685a3f937 100644 --- a/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/not-suggest-float-literal.stderr @@ -6,10 +6,10 @@ LL | x + 100.0 | = help: the trait `Add<{float}>` is not implemented for `u8` = help: the following other types implement trait `Add<Rhs>`: - <u8 as Add> - <u8 as Add<&u8>> <&'a u8 as Add<u8>> <&u8 as Add<&u8>> + <u8 as Add<&u8>> + <u8 as Add> error[E0277]: cannot add `&str` to `f64` --> $DIR/not-suggest-float-literal.rs:6:7 @@ -19,10 +19,10 @@ LL | x + "foo" | = help: the trait `Add<&str>` is not implemented for `f64` = help: the following other types implement trait `Add<Rhs>`: - <f64 as Add> - <f64 as Add<&f64>> <&'a f64 as Add<f64>> <&f64 as Add<&f64>> + <f64 as Add<&f64>> + <f64 as Add> error[E0277]: cannot add `{integer}` to `f64` --> $DIR/not-suggest-float-literal.rs:11:7 @@ -32,10 +32,10 @@ LL | x + y | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add<Rhs>`: - <f64 as Add> - <f64 as Add<&f64>> <&'a f64 as Add<f64>> <&f64 as Add<&f64>> + <f64 as Add<&f64>> + <f64 as Add> error[E0277]: cannot subtract `{float}` from `u8` --> $DIR/not-suggest-float-literal.rs:15:7 @@ -45,10 +45,10 @@ LL | x - 100.0 | = help: the trait `Sub<{float}>` is not implemented for `u8` = help: the following other types implement trait `Sub<Rhs>`: - <u8 as Sub> - <u8 as Sub<&u8>> <&'a u8 as Sub<u8>> <&u8 as Sub<&u8>> + <u8 as Sub<&u8>> + <u8 as Sub> error[E0277]: cannot subtract `&str` from `f64` --> $DIR/not-suggest-float-literal.rs:19:7 @@ -58,10 +58,10 @@ LL | x - "foo" | = help: the trait `Sub<&str>` is not implemented for `f64` = help: the following other types implement trait `Sub<Rhs>`: - <f64 as Sub> - <f64 as Sub<&f64>> <&'a f64 as Sub<f64>> <&f64 as Sub<&f64>> + <f64 as Sub<&f64>> + <f64 as Sub> error[E0277]: cannot subtract `{integer}` from `f64` --> $DIR/not-suggest-float-literal.rs:24:7 @@ -71,10 +71,10 @@ LL | x - y | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub<Rhs>`: - <f64 as Sub> - <f64 as Sub<&f64>> <&'a f64 as Sub<f64>> <&f64 as Sub<&f64>> + <f64 as Sub<&f64>> + <f64 as Sub> error[E0277]: cannot multiply `u8` by `{float}` --> $DIR/not-suggest-float-literal.rs:28:7 @@ -84,10 +84,10 @@ LL | x * 100.0 | = help: the trait `Mul<{float}>` is not implemented for `u8` = help: the following other types implement trait `Mul<Rhs>`: - <u8 as Mul> - <u8 as Mul<&u8>> <&'a u8 as Mul<u8>> <&u8 as Mul<&u8>> + <u8 as Mul<&u8>> + <u8 as Mul> error[E0277]: cannot multiply `f64` by `&str` --> $DIR/not-suggest-float-literal.rs:32:7 @@ -97,10 +97,10 @@ LL | x * "foo" | = help: the trait `Mul<&str>` is not implemented for `f64` = help: the following other types implement trait `Mul<Rhs>`: - <f64 as Mul> - <f64 as Mul<&f64>> <&'a f64 as Mul<f64>> <&f64 as Mul<&f64>> + <f64 as Mul<&f64>> + <f64 as Mul> error[E0277]: cannot multiply `f64` by `{integer}` --> $DIR/not-suggest-float-literal.rs:37:7 @@ -110,10 +110,10 @@ LL | x * y | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul<Rhs>`: - <f64 as Mul> - <f64 as Mul<&f64>> <&'a f64 as Mul<f64>> <&f64 as Mul<&f64>> + <f64 as Mul<&f64>> + <f64 as Mul> error[E0277]: cannot divide `u8` by `{float}` --> $DIR/not-suggest-float-literal.rs:41:7 @@ -123,11 +123,11 @@ LL | x / 100.0 | = help: the trait `Div<{float}>` is not implemented for `u8` = help: the following other types implement trait `Div<Rhs>`: - <u8 as Div> - <u8 as Div<NonZero<u8>>> - <u8 as Div<&u8>> <&'a u8 as Div<u8>> <&u8 as Div<&u8>> + <u8 as Div<&u8>> + <u8 as Div<NonZero<u8>>> + <u8 as Div> error[E0277]: cannot divide `f64` by `&str` --> $DIR/not-suggest-float-literal.rs:45:7 @@ -137,10 +137,10 @@ LL | x / "foo" | = help: the trait `Div<&str>` is not implemented for `f64` = help: the following other types implement trait `Div<Rhs>`: - <f64 as Div> - <f64 as Div<&f64>> <&'a f64 as Div<f64>> <&f64 as Div<&f64>> + <f64 as Div<&f64>> + <f64 as Div> error[E0277]: cannot divide `f64` by `{integer}` --> $DIR/not-suggest-float-literal.rs:50:7 @@ -150,10 +150,10 @@ LL | x / y | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div<Rhs>`: - <f64 as Div> - <f64 as Div<&f64>> <&'a f64 as Div<f64>> <&f64 as Div<&f64>> + <f64 as Div<&f64>> + <f64 as Div> error: aborting due to 12 previous errors diff --git a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr index 929a9e3b595..03779d35637 100644 --- a/tests/ui/numbers-arithmetic/suggest-float-literal.stderr +++ b/tests/ui/numbers-arithmetic/suggest-float-literal.stderr @@ -6,10 +6,10 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Add<Rhs>`: - <f32 as Add> - <f32 as Add<&f32>> <&'a f32 as Add<f32>> <&f32 as Add<&f32>> + <f32 as Add<&f32>> + <f32 as Add> help: consider using a floating-point literal by writing it with `.0` | LL | x + 100.0 @@ -23,10 +23,10 @@ LL | x + 100 | = help: the trait `Add<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Add<Rhs>`: - <f64 as Add> - <f64 as Add<&f64>> <&'a f64 as Add<f64>> <&f64 as Add<&f64>> + <f64 as Add<&f64>> + <f64 as Add> help: consider using a floating-point literal by writing it with `.0` | LL | x + 100.0 @@ -40,10 +40,10 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Sub<Rhs>`: - <f32 as Sub> - <f32 as Sub<&f32>> <&'a f32 as Sub<f32>> <&f32 as Sub<&f32>> + <f32 as Sub<&f32>> + <f32 as Sub> help: consider using a floating-point literal by writing it with `.0` | LL | x - 100.0 @@ -57,10 +57,10 @@ LL | x - 100 | = help: the trait `Sub<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Sub<Rhs>`: - <f64 as Sub> - <f64 as Sub<&f64>> <&'a f64 as Sub<f64>> <&f64 as Sub<&f64>> + <f64 as Sub<&f64>> + <f64 as Sub> help: consider using a floating-point literal by writing it with `.0` | LL | x - 100.0 @@ -74,10 +74,10 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Mul<Rhs>`: - <f32 as Mul> - <f32 as Mul<&f32>> <&'a f32 as Mul<f32>> <&f32 as Mul<&f32>> + <f32 as Mul<&f32>> + <f32 as Mul> help: consider using a floating-point literal by writing it with `.0` | LL | x * 100.0 @@ -91,10 +91,10 @@ LL | x * 100 | = help: the trait `Mul<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Mul<Rhs>`: - <f64 as Mul> - <f64 as Mul<&f64>> <&'a f64 as Mul<f64>> <&f64 as Mul<&f64>> + <f64 as Mul<&f64>> + <f64 as Mul> help: consider using a floating-point literal by writing it with `.0` | LL | x * 100.0 @@ -108,10 +108,10 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f32` = help: the following other types implement trait `Div<Rhs>`: - <f32 as Div> - <f32 as Div<&f32>> <&'a f32 as Div<f32>> <&f32 as Div<&f32>> + <f32 as Div<&f32>> + <f32 as Div> help: consider using a floating-point literal by writing it with `.0` | LL | x / 100.0 @@ -125,10 +125,10 @@ LL | x / 100 | = help: the trait `Div<{integer}>` is not implemented for `f64` = help: the following other types implement trait `Div<Rhs>`: - <f64 as Div> - <f64 as Div<&f64>> <&'a f64 as Div<f64>> <&f64 as Div<&f64>> + <f64 as Div<&f64>> + <f64 as Div> help: consider using a floating-point literal by writing it with `.0` | LL | x / 100.0 diff --git a/tests/ui/on-unimplemented/multiple-impls.stderr b/tests/ui/on-unimplemented/multiple-impls.stderr index f59c93a7c37..b50dc251baa 100644 --- a/tests/ui/on-unimplemented/multiple-impls.stderr +++ b/tests/ui/on-unimplemented/multiple-impls.stderr @@ -8,8 +8,8 @@ LL | Index::index(&[] as &[i32], 2u32); | = help: the trait `Index<u32>` is not implemented for `[i32]` = help: the following other types implement trait `Index<Idx>`: - <[i32] as Index<Foo<usize>>> <[i32] as Index<Bar<usize>>> + <[i32] as Index<Foo<usize>>> error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied --> $DIR/multiple-impls.rs:36:33 @@ -21,8 +21,8 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); | = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]` = help: the following other types implement trait `Index<Idx>`: - <[i32] as Index<Foo<usize>>> <[i32] as Index<Bar<usize>>> + <[i32] as Index<Foo<usize>>> error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied --> $DIR/multiple-impls.rs:39:33 @@ -34,8 +34,8 @@ LL | Index::index(&[] as &[i32], Bar(2u32)); | = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]` = help: the following other types implement trait `Index<Idx>`: - <[i32] as Index<Foo<usize>>> <[i32] as Index<Bar<usize>>> + <[i32] as Index<Foo<usize>>> error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied --> $DIR/multiple-impls.rs:33:5 @@ -45,8 +45,8 @@ LL | Index::index(&[] as &[i32], 2u32); | = help: the trait `Index<u32>` is not implemented for `[i32]` = help: the following other types implement trait `Index<Idx>`: - <[i32] as Index<Foo<usize>>> <[i32] as Index<Bar<usize>>> + <[i32] as Index<Foo<usize>>> error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied --> $DIR/multiple-impls.rs:36:5 @@ -56,8 +56,8 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); | = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]` = help: the following other types implement trait `Index<Idx>`: - <[i32] as Index<Foo<usize>>> <[i32] as Index<Bar<usize>>> + <[i32] as Index<Foo<usize>>> error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied --> $DIR/multiple-impls.rs:39:5 @@ -67,8 +67,8 @@ LL | Index::index(&[] as &[i32], Bar(2u32)); | = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]` = help: the following other types implement trait `Index<Idx>`: - <[i32] as Index<Foo<usize>>> <[i32] as Index<Bar<usize>>> + <[i32] as Index<Foo<usize>>> error: aborting due to 6 previous errors diff --git a/tests/ui/on-unimplemented/slice-index.stderr b/tests/ui/on-unimplemented/slice-index.stderr index c0314fa42d7..f17f3cfce8d 100644 --- a/tests/ui/on-unimplemented/slice-index.stderr +++ b/tests/ui/on-unimplemented/slice-index.stderr @@ -17,8 +17,8 @@ LL | x[..1i32]; | = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo<i32>`, which is required by `[i32]: Index<_>` = help: the following other types implement trait `SliceIndex<T>`: - <RangeTo<usize> as SliceIndex<str>> <RangeTo<usize> as SliceIndex<[T]>> + <RangeTo<usize> as SliceIndex<str>> = note: required for `[i32]` to implement `Index<RangeTo<i32>>` error: aborting due to 2 previous errors diff --git a/tests/ui/on-unimplemented/sum.stderr b/tests/ui/on-unimplemented/sum.stderr index 257dec20074..65bab458cf1 100644 --- a/tests/ui/on-unimplemented/sum.stderr +++ b/tests/ui/on-unimplemented/sum.stderr @@ -8,8 +8,8 @@ LL | vec![(), ()].iter().sum::<i32>(); | = help: the trait `Sum<&()>` is not implemented for `i32` = help: the following other types implement trait `Sum<A>`: - <i32 as Sum> <i32 as Sum<&'a i32>> + <i32 as Sum> note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:4:18 | @@ -30,8 +30,8 @@ LL | vec![(), ()].iter().product::<i32>(); | = help: the trait `Product<&()>` is not implemented for `i32` = help: the following other types implement trait `Product<A>`: - <i32 as Product> <i32 as Product<&'a i32>> + <i32 as Product> note: the method call chain might not have had the expected associated types --> $DIR/sum.rs:7:18 | diff --git a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs index 558fcdfe177..cb65f80b089 100644 --- a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs +++ b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs @@ -1,6 +1,6 @@ #[cfg(FALSE)] fn syntax() { - bar::<Item = 'a>(); //~ ERROR associated lifetimes are not supported + bar::<Item = 'a>(); //~ ERROR lifetimes are not permitted in this context } fn main() {} diff --git a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr index 39a6682fcae..606b737e723 100644 --- a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr +++ b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.stderr @@ -1,12 +1,17 @@ -error: associated lifetimes are not supported - --> $DIR/recover-assoc-lifetime-constraint.rs:3:11 +error: lifetimes are not permitted in this context + --> $DIR/recover-assoc-lifetime-constraint.rs:3:18 | LL | bar::<Item = 'a>(); - | ^^^^^^^-- - | | - | the lifetime is given here + | -------^^ + | | | + | | lifetime is not allowed here + | this introduces an associated item binding | - = help: if you meant to specify a trait object, write `dyn Trait + 'lifetime` + = help: if you meant to specify a trait object, write `dyn /* Trait */ + 'a` +help: you might have meant to write a bound here + | +LL | bar::<Item: 'a>(); + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/pattern/deref-patterns/ref-mut.rs b/tests/ui/pattern/deref-patterns/ref-mut.rs new file mode 100644 index 00000000000..1918008a761 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/ref-mut.rs @@ -0,0 +1,17 @@ +#![feature(deref_patterns)] +//~^ WARN the feature `deref_patterns` is incomplete + +use std::rc::Rc; + +fn main() { + match &mut vec![1] { + deref!(x) => {} + _ => {} + } + + match &mut Rc::new(1) { + deref!(x) => {} + //~^ ERROR the trait bound `Rc<{integer}>: DerefMut` is not satisfied + _ => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/ref-mut.stderr b/tests/ui/pattern/deref-patterns/ref-mut.stderr new file mode 100644 index 00000000000..41f1c3061ce --- /dev/null +++ b/tests/ui/pattern/deref-patterns/ref-mut.stderr @@ -0,0 +1,20 @@ +warning: the feature `deref_patterns` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/ref-mut.rs:1:12 + | +LL | #![feature(deref_patterns)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #87121 <https://github.com/rust-lang/rust/issues/87121> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied + --> $DIR/ref-mut.rs:13:9 + | +LL | deref!(x) => {} + | ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>` + | + = note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout index 1df4d85d09e..83a6962e4cd 100644 --- a/tests/ui/print_type_sizes/async.stdout +++ b/tests/ui/print_type_sizes/async.stdout @@ -1,11 +1,11 @@ -print-type-size type: `{async fn body@$DIR/async.rs:10:36: 13:2}`: 16386 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of test()}`: 16386 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 8192 bytes print-type-size upvar `.arg`: 8192 bytes print-type-size variant `Suspend0`: 16385 bytes print-type-size upvar `.arg`: 8192 bytes print-type-size local `.arg`: 8192 bytes -print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async.rs:8:17: 8:19} +print-type-size local `.__awaitee`: 1 bytes, type: {async fn body of wait()} print-type-size variant `Returned`: 8192 bytes print-type-size upvar `.arg`: 8192 bytes print-type-size variant `Panicked`: 8192 bytes @@ -16,9 +16,9 @@ print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment print-type-size variant `MaybeUninit`: 8192 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 8192 bytes -print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async.rs:8:17: 8:19}>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeUninit<{async fn body@$DIR/async.rs:8:17: 8:19}>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<{async fn body of wait()}>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1 bytes @@ -27,7 +27,7 @@ print-type-size discriminant: 1 bytes print-type-size variant `Ready`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Pending`: 0 bytes -print-type-size type: `{async fn body@$DIR/async.rs:8:17: 8:19}`: 1 bytes, alignment: 1 bytes +print-type-size type: `{async fn body of wait()}`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Returned`: 0 bytes diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr index 3d9b7a940b7..f98420557c6 100644 --- a/tests/ui/range/range-1.stderr +++ b/tests/ui/range/range-1.stderr @@ -11,14 +11,14 @@ LL | for i in false..true {} | ^^^^^^^^^^^ the trait `Step` is not implemented for `bool`, which is required by `std::ops::Range<bool>: IntoIterator` | = help: the following other types implement trait `Step`: + Char + Ipv4Addr + Ipv6Addr char - isize - i8 + i128 i16 i32 i64 - i128 - usize and 8 others = note: required for `std::ops::Range<bool>` to implement `Iterator` = note: required for `std::ops::Range<bool>` to implement `IntoIterator` diff --git a/tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs b/tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs new file mode 100644 index 00000000000..dd604b6bf7d --- /dev/null +++ b/tests/ui/sanitizer/cfi-assoc-ty-lifetime-issue-123053.rs @@ -0,0 +1,38 @@ +// Regression test for issue 123053, where associated types with lifetimes caused generation of the +// trait object type to fail, causing an ICE. +// +//@ needs-sanitizer-cfi +//@ compile-flags: -Ccodegen-units=1 -Clto -Ctarget-feature=-crt-static -Zsanitizer=cfi --edition=2021 +//@ no-prefer-dynamic +//@ only-x86_64-unknown-linux-gnu +//@ build-pass + +trait Iterable { + type Item<'a> + where + Self: 'a; + type Iter<'a>: Iterator<Item = Self::Item<'a>> + where + Self: 'a; + + fn iter<'a>(&'a self) -> Self::Iter<'a>; +} + +impl<T> Iterable for [T] { + type Item<'a> = <std::slice::Iter<'a, T> as Iterator>::Item where T: 'a; + type Iter<'a> = std::slice::Iter<'a, T> where T: 'a; + + fn iter<'a>(&'a self) -> Self::Iter<'a> { + self.iter() + } +} + +fn get_first<'a, I: Iterable + ?Sized>(it: &'a I) -> Option<I::Item<'a>> { + it.iter().next() +} + +fn main() { + let v = vec![1, 2, 3]; + + assert_eq!(Some(&1), get_first(&*v)); +} diff --git a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs index a46a3afd734..1ae494d87d4 100644 --- a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs +++ b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs @@ -5,11 +5,15 @@ // // This checks that the reified function pointer will have the expected alias set at its call-site. -//@ needs-sanitizer-cfi +//@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux -//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi -//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 +//@ [cfi] needs-sanitizer-cfi +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [kcfi] compile-flags: -Z sanitizer=kcfi //@ run-pass pub fn main() { diff --git a/tests/ui/sanitizer/cfi-complex-receiver.rs b/tests/ui/sanitizer/cfi-complex-receiver.rs index c3e59258db2..52095a384b2 100644 --- a/tests/ui/sanitizer/cfi-complex-receiver.rs +++ b/tests/ui/sanitizer/cfi-complex-receiver.rs @@ -2,11 +2,15 @@ // * Arc<dyn Foo> as for custom receivers // * &dyn Bar<T=Baz> for type constraints -//@ needs-sanitizer-cfi +//@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux -//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi -//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 +//@ [cfi] needs-sanitizer-cfi +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [kcfi] compile-flags: -Z sanitizer=kcfi //@ run-pass use std::sync::Arc; diff --git a/tests/ui/sanitizer/cfi-drop-in-place.rs b/tests/ui/sanitizer/cfi-drop-in-place.rs new file mode 100644 index 00000000000..8ce2c432602 --- /dev/null +++ b/tests/ui/sanitizer/cfi-drop-in-place.rs @@ -0,0 +1,20 @@ +// Verifies that drops can be called on arbitrary trait objects. +// +// FIXME(#122848): Remove only-linux when fixed. +//@ only-linux +//@ needs-sanitizer-cfi +//@ compile-flags: -Clto -Copt-level=0 -Cprefer-dynamic=off -Ctarget-feature=-crt-static -Zsanitizer=cfi +//@ run-pass + +struct EmptyDrop; + +struct NonEmptyDrop; + +impl Drop for NonEmptyDrop { + fn drop(&mut self) {} +} + +fn main() { + let _ = Box::new(EmptyDrop) as Box<dyn Send>; + let _ = Box::new(NonEmptyDrop) as Box<dyn Send>; +} diff --git a/tests/ui/sanitizer/cfi-self-ref.rs b/tests/ui/sanitizer/cfi-self-ref.rs index 32d0b100702..f8793aec6e2 100644 --- a/tests/ui/sanitizer/cfi-self-ref.rs +++ b/tests/ui/sanitizer/cfi-self-ref.rs @@ -1,10 +1,14 @@ // Check that encoding self-referential types works with #[repr(transparent)] -//@ needs-sanitizer-cfi +//@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux -//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi -//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 +//@ [cfi] needs-sanitizer-cfi +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [kcfi] compile-flags: -Z sanitizer=kcfi //@ run-pass use std::marker::PhantomData; diff --git a/tests/ui/sanitizer/cfi-virtual-auto.rs b/tests/ui/sanitizer/cfi-virtual-auto.rs index 7a0c246a412..517c3d49f76 100644 --- a/tests/ui/sanitizer/cfi-virtual-auto.rs +++ b/tests/ui/sanitizer/cfi-virtual-auto.rs @@ -1,10 +1,14 @@ // Tests that calling a trait object method on a trait object with additional auto traits works. -//@ needs-sanitizer-cfi +//@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work //@ only-linux -//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi -//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 +//@ [cfi] needs-sanitizer-cfi +//@ [kcfi] needs-sanitizer-kcfi +//@ compile-flags: -C target-feature=-crt-static +//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0 +//@ [cfi] compile-flags: -Z sanitizer=cfi +//@ [kcfi] compile-flags: -Z sanitizer=kcfi //@ run-pass trait Foo { diff --git a/tests/ui/span/multiline-span-simple.stderr b/tests/ui/span/multiline-span-simple.stderr index f0eec632aa1..2de792b03d7 100644 --- a/tests/ui/span/multiline-span-simple.stderr +++ b/tests/ui/span/multiline-span-simple.stderr @@ -6,10 +6,10 @@ LL | foo(1 as u32 + | = help: the trait `Add<()>` is not implemented for `u32` = help: the following other types implement trait `Add<Rhs>`: - <u32 as Add> - <u32 as Add<&u32>> <&'a u32 as Add<u32>> <&u32 as Add<&u32>> + <u32 as Add<&u32>> + <u32 as Add> error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/impl-trait-return-trailing-semicolon.stderr b/tests/ui/suggestions/impl-trait-return-trailing-semicolon.stderr index 6465eeb8bc6..e74c2c4214f 100644 --- a/tests/ui/suggestions/impl-trait-return-trailing-semicolon.stderr +++ b/tests/ui/suggestions/impl-trait-return-trailing-semicolon.stderr @@ -16,8 +16,8 @@ LL | fn bar() -> impl Bar { | ^^^^^^^^ the trait `Bar` is not implemented for `()` | = help: the following other types implement trait `Bar`: - i32 Qux + i32 error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/into-str.stderr b/tests/ui/suggestions/into-str.stderr index d10a294c7d2..2fdfab8bdc5 100644 --- a/tests/ui/suggestions/into-str.stderr +++ b/tests/ui/suggestions/into-str.stderr @@ -8,12 +8,12 @@ LL | foo(String::new()); | = note: to coerce a `String` into a `&str`, use `&*` as a prefix = help: the following other types implement trait `From<T>`: - <String as From<char>> + <String as From<&String>> + <String as From<&mut str>> + <String as From<&str>> <String as From<Box<str>>> <String as From<Cow<'a, str>>> - <String as From<&str>> - <String as From<&mut str>> - <String as From<&String>> + <String as From<char>> = note: required for `String` to implement `Into<&str>` note: required by a bound in `foo` --> $DIR/into-str.rs:1:31 diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr index 0f6bfbeec45..e626b5b0eb7 100644 --- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr @@ -5,14 +5,14 @@ LL | let _: &[i8] = data.into(); | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`, which is required by `&[u8]: Into<_>` | = help: the following other types implement trait `From<T>`: - <[bool; N] as From<Mask<T, N>>> - <[T; N] as From<Simd<T, N>>> + <[T; 10] as From<(T, T, T, T, T, T, T, T, T, T)>> + <[T; 11] as From<(T, T, T, T, T, T, T, T, T, T, T)>> + <[T; 12] as From<(T, T, T, T, T, T, T, T, T, T, T, T)>> <[T; 1] as From<(T,)>> <[T; 2] as From<(T, T)>> <[T; 3] as From<(T, T, T)>> <[T; 4] as From<(T, T, T, T)>> <[T; 5] as From<(T, T, T, T, T)>> - <[T; 6] as From<(T, T, T, T, T, T)>> and 6 others = note: required for `&[u8]` to implement `Into<&[i8]>` diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr index bd9838bc623..27006f59b90 100644 --- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr +++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr @@ -6,13 +6,13 @@ LL | s.strip_suffix(b'\n').unwrap_or(s) | = help: the trait `FnMut<(char,)>` is not implemented for `u8`, which is required by `u8: Pattern<'_>` = help: the following other types implement trait `Pattern<'a>`: - char - [char; N] &'b String &'b [char; N] &'b [char] - &'c &'b str &'b str + &'c &'b str + [char; N] + char = note: required for `u8` to implement `Pattern<'_>` error: aborting due to 1 previous error diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr index 0d8bd8ee964..4d968e7bee1 100644 --- a/tests/ui/traits/method-on-unbounded-type-param.stderr +++ b/tests/ui/traits/method-on-unbounded-type-param.stderr @@ -9,10 +9,10 @@ LL | a.cmp(&b) = help: items from traits can only be used if the type parameter is bounded by the trait help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: | -LL | fn f<T: Ord>(a: T, b: T) -> std::cmp::Ordering { - | +++++ LL | fn f<T: Iterator>(a: T, b: T) -> std::cmp::Ordering { | ++++++++++ +LL | fn f<T: Ord>(a: T, b: T) -> std::cmp::Ordering { + | +++++ error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied --> $DIR/method-on-unbounded-type-param.rs:5:10 @@ -30,10 +30,10 @@ LL | (&a).cmp(&b) = help: items from traits can only be used if the type parameter is bounded by the trait help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: | -LL | fn g<T: Ord>(a: T, b: T) -> std::cmp::Ordering { - | +++++ LL | fn g<T: Iterator>(a: T, b: T) -> std::cmp::Ordering { | ++++++++++ +LL | fn g<T: Ord>(a: T, b: T) -> std::cmp::Ordering { + | +++++ error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied --> $DIR/method-on-unbounded-type-param.rs:8:7 @@ -51,10 +51,10 @@ LL | a.cmp(&b) = help: items from traits can only be used if the type parameter is bounded by the trait help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them: | -LL | fn h<T: Ord>(a: &T, b: T) -> std::cmp::Ordering { - | +++++ LL | fn h<T: Iterator>(a: &T, b: T) -> std::cmp::Ordering { | ++++++++++ +LL | fn h<T: Ord>(a: &T, b: T) -> std::cmp::Ordering { + | +++++ error[E0599]: the method `cmp` exists for struct `Box<dyn T>`, but its trait bounds were not satisfied --> $DIR/method-on-unbounded-type-param.rs:14:7 @@ -76,8 +76,8 @@ LL | x.cmp(&x); which is required by `&mut dyn T: Iterator` = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `cmp`, perhaps you need to implement one of them: - candidate #1: `Ord` - candidate #2: `Iterator` + candidate #1: `Iterator` + candidate #2: `Ord` error: aborting due to 4 previous errors diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index 79f270fd1bb..8a6c5fc10c5 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -31,12 +31,12 @@ LL | .map_err(|_| ())?; | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From<T>`: - <String as From<char>> + <String as From<&String>> + <String as From<&mut str>> + <String as From<&str>> <String as From<Box<str>>> <String as From<Cow<'a, str>>> - <String as From<&str>> - <String as From<&mut str>> - <String as From<&String>> + <String as From<char>> = note: required for `Result<(), String>` to implement `FromResidual<Result<Infallible, ()>>` error[E0277]: `?` couldn't convert the error to `String` diff --git a/tests/ui/traits/trait-selection-ice-84727.rs b/tests/ui/traits/trait-selection-ice-84727.rs new file mode 100644 index 00000000000..08a282892a5 --- /dev/null +++ b/tests/ui/traits/trait-selection-ice-84727.rs @@ -0,0 +1,38 @@ +// ICE Where clause `Binder(..)` was applicable to `Obligation(..)` but now is not +// issue: rust-lang/rust#84727 + +struct Cell<Fg, Bg = Fg> { + foreground: Color<Fg>, + //~^ ERROR cannot find type `Color` in this scope + background: Color<Bg>, + //~^ ERROR cannot find type `Color` in this scope +} + +trait Over<Bottom, Output> { + fn over(self) -> Output; +} + +impl<TopFg, TopBg, BottomFg, BottomBg, NewFg, NewBg> + Over<Cell<BottomFg, BottomBg>, Cell<NewFg, NewBg>> for Cell<TopFg, TopBg> +where + Self: Over<Color<BottomBg>, Cell<NewFg>>, + //~^ ERROR cannot find type `Color` in this scope +{ + fn over(self) -> Cell<NewFg> { + //~^ ERROR mismatched types + self.over(); + } +} + +impl<'b, TopFg, TopBg, BottomFg, BottomBg> Over<&Cell<BottomFg, BottomBg>, ()> + for Cell<TopFg, TopBg> +where + Cell<TopFg, TopBg>: Over<Cell<BottomFg>, Cell<BottomFg>>, +{ + fn over(self) -> Cell<NewBg> { + //~^ ERROR cannot find type `NewBg` in this scope + self.over(); + } +} + +pub fn main() {} diff --git a/tests/ui/traits/trait-selection-ice-84727.stderr b/tests/ui/traits/trait-selection-ice-84727.stderr new file mode 100644 index 00000000000..d4bc4163897 --- /dev/null +++ b/tests/ui/traits/trait-selection-ice-84727.stderr @@ -0,0 +1,47 @@ +error[E0412]: cannot find type `Color` in this scope + --> $DIR/trait-selection-ice-84727.rs:5:17 + | +LL | foreground: Color<Fg>, + | ^^^^^ not found in this scope + +error[E0412]: cannot find type `Color` in this scope + --> $DIR/trait-selection-ice-84727.rs:7:17 + | +LL | background: Color<Bg>, + | ^^^^^ not found in this scope + +error[E0412]: cannot find type `Color` in this scope + --> $DIR/trait-selection-ice-84727.rs:18:16 + | +LL | Self: Over<Color<BottomBg>, Cell<NewFg>>, + | ^^^^^ not found in this scope + +error[E0412]: cannot find type `NewBg` in this scope + --> $DIR/trait-selection-ice-84727.rs:32:27 + | +LL | fn over(self) -> Cell<NewBg> { + | ^^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | impl<'b, TopFg, TopBg, BottomFg, BottomBg, NewBg> Over<&Cell<BottomFg, BottomBg>, ()> + | +++++++ + +error[E0308]: mismatched types + --> $DIR/trait-selection-ice-84727.rs:21:22 + | +LL | fn over(self) -> Cell<NewFg> { + | ---- ^^^^^^^^^^^ expected `Cell<NewFg>`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression +LL | +LL | self.over(); + | - help: remove this semicolon to return this value + | + = note: expected struct `Cell<NewFg>` + found unit type `()` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0308, E0412. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index 817acc8fc99..e3edec6a4c7 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -10,8 +10,8 @@ LL | Ok(Err(123_i32)?) | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From<T>`: - <u8 as From<bool>> <u8 as From<Char>> + <u8 as From<bool>> = note: required for `Result<u64, u8>` to implement `FromResidual<Result<Infallible, i32>>` error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` @@ -24,8 +24,8 @@ LL | Some(3)?; | = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>` = help: the following other types implement trait `FromResidual<R>`: - <Result<T, F> as FromResidual<Yeet<E>>> <Result<T, F> as FromResidual<Result<Infallible, E>>> + <Result<T, F> as FromResidual<Yeet<E>>> error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` --> $DIR/bad-interconversion.rs:17:31 @@ -37,8 +37,8 @@ LL | Ok(ControlFlow::Break(123)?) | = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>` = help: the following other types implement trait `FromResidual<R>`: - <Result<T, F> as FromResidual<Yeet<E>>> <Result<T, F> as FromResidual<Result<Infallible, E>>> + <Result<T, F> as FromResidual<Yeet<E>>> error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/bad-interconversion.rs:22:22 diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr index 34618de78cd..a0dd18fa039 100644 --- a/tests/ui/try-trait/issue-32709.stderr +++ b/tests/ui/try-trait/issue-32709.stderr @@ -10,7 +10,6 @@ LL | Err(5)?; | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From<T>`: - <(T,) as From<[T; 1]>> <(T, T) as From<[T; 2]>> <(T, T, T) as From<[T; 3]>> <(T, T, T, T) as From<[T; 4]>> @@ -18,6 +17,7 @@ LL | Err(5)?; <(T, T, T, T, T, T) as From<[T; 6]>> <(T, T, T, T, T, T, T) as From<[T; 7]>> <(T, T, T, T, T, T, T, T) as From<[T; 8]>> + <(T, T, T, T, T, T, T, T, T) as From<[T; 9]>> and 4 others = note: required for `Result<i32, ()>` to implement `FromResidual<Result<Infallible, {integer}>>` diff --git a/tests/ui/try-trait/option-to-result.stderr b/tests/ui/try-trait/option-to-result.stderr index 1c4d718f1ee..fabc1ff2c76 100644 --- a/tests/ui/try-trait/option-to-result.stderr +++ b/tests/ui/try-trait/option-to-result.stderr @@ -9,8 +9,8 @@ LL | a?; | = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>` = help: the following other types implement trait `FromResidual<R>`: - <Result<T, F> as FromResidual<Yeet<E>>> <Result<T, F> as FromResidual<Result<Infallible, E>>> + <Result<T, F> as FromResidual<Yeet<E>>> error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/option-to-result.rs:11:6 diff --git a/tests/ui/try-trait/try-on-option.stderr b/tests/ui/try-trait/try-on-option.stderr index eeb0439df29..fad6a1fe823 100644 --- a/tests/ui/try-trait/try-on-option.stderr +++ b/tests/ui/try-trait/try-on-option.stderr @@ -9,8 +9,8 @@ LL | x?; | = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>` = help: the following other types implement trait `FromResidual<R>`: - <Result<T, F> as FromResidual<Yeet<E>>> <Result<T, F> as FromResidual<Result<Infallible, E>>> + <Result<T, F> as FromResidual<Yeet<E>>> error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option.rs:11:6 diff --git a/tests/ui/type-alias-impl-trait/bivariant-duplicate-lifetime-unconstrained.rs b/tests/ui/type-alias-impl-trait/bivariant-duplicate-lifetime-unconstrained.rs new file mode 100644 index 00000000000..3b83b2e544b --- /dev/null +++ b/tests/ui/type-alias-impl-trait/bivariant-duplicate-lifetime-unconstrained.rs @@ -0,0 +1,18 @@ +// The defining use below has an unconstrained lifetime argument. +// Opaque<'{empty}, 'a> := (); +// Make sure we accept it because the lifetime parameter in such position is +// irrelevant - it is an artifact of how we internally represent opaque +// generics. +// See issue #122307 for details. + +//@ check-pass +#![feature(type_alias_impl_trait)] +#![allow(unconditional_recursion)] + +type Opaque<'a> = impl Sized + 'a; + +fn test<'a>() -> Opaque<'a> { + let _: () = test::<'a>(); +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs b/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs index d97a3010a17..0e1d44e7bb3 100644 --- a/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs +++ b/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs @@ -8,12 +8,24 @@ impl<T> Equate for T { type Proj = T; } trait Indirect { type Ty; } impl<A, B: Equate<Proj = A>> Indirect for (A, B) { type Ty = (); } -type Opq = impl Sized; -fn define_1(_: Opq) { - let _ = None::<<(Opq, u8) as Indirect>::Ty>; +mod basic { + use super::*; + type Opq = impl Sized; + fn define_1(_: Opq) { + let _ = None::<<(Opq, u8) as Indirect>::Ty>; + } + fn define_2() -> Opq { + 0u8 + } } -fn define_2() -> Opq { - 0u8 + +// `Opq<'a> == &'b u8` shouldn't be an error because `'a == 'b`. +mod lifetime { + use super::*; + type Opq<'a> = impl Sized + 'a; + fn define<'a: 'b, 'b: 'a>(_: Opq<'a>) { + let _ = None::<<(Opq<'a>, &'b u8) as Indirect>::Ty>; + } } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.rs b/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.rs new file mode 100644 index 00000000000..9101e4385b3 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.rs @@ -0,0 +1,19 @@ +#![feature(type_alias_impl_trait)] + +mod case1 { + type Opaque<'x> = impl Sized + 'x; + fn foo<'s>() -> Opaque<'s> { + let _ = || { let _: Opaque<'s> = (); }; + //~^ ERROR expected generic lifetime parameter, found `'_` + } +} + +mod case2 { + type Opaque<'x> = impl Sized + 'x; + fn foo<'s>() -> Opaque<'s> { + let _ = || -> Opaque<'s> {}; + //~^ ERROR expected generic lifetime parameter, found `'_` + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.stderr b/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.stderr new file mode 100644 index 00000000000..a8fd1f691dd --- /dev/null +++ b/tests/ui/type-alias-impl-trait/defined-in-closure-external-lifetime.stderr @@ -0,0 +1,21 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/defined-in-closure-external-lifetime.rs:6:29 + | +LL | type Opaque<'x> = impl Sized + 'x; + | -- this generic parameter must be used with a generic lifetime parameter +LL | fn foo<'s>() -> Opaque<'s> { +LL | let _ = || { let _: Opaque<'s> = (); }; + | ^^^^^^^^^^ + +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/defined-in-closure-external-lifetime.rs:14:34 + | +LL | type Opaque<'x> = impl Sized + 'x; + | -- this generic parameter must be used with a generic lifetime parameter +LL | fn foo<'s>() -> Opaque<'s> { +LL | let _ = || -> Opaque<'s> {}; + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs new file mode 100644 index 00000000000..59ba2694a76 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs @@ -0,0 +1,37 @@ +// issue: #112841 + +#![feature(type_alias_impl_trait)] + +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} + +mod mod1 { + type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + fn test<'a>() -> Opaque<'a, 'a> {} + //~^ ERROR non-defining opaque type use in defining scope + //~| ERROR non-defining opaque type use in defining scope +} + +mod mod2 { + type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + fn test<'a: 'b, 'b: 'a>() -> Opaque<'a, 'b> {} + //~^ ERROR non-defining opaque type use in defining scope +} + +mod mod3 { + type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + fn test<'a: 'b, 'b: 'a>(a: &'a str) -> Opaque<'a, 'b> { a } + //~^ ERROR non-defining opaque type use in defining scope +} + +// This is similar to the previous cases in that 'a is equal to 'static, +// which is is some sense an implicit parameter to `Opaque`. +// For example, given a defining use `Opaque<'a> := &'a ()`, +// it is ambiguous whether `Opaque<'a> := &'a ()` or `Opaque<'a> := &'static ()` +mod mod4 { + type Opaque<'a> = impl super::Trait<'a, 'a>; + fn test<'a: 'static>() -> Opaque<'a> {} + //~^ ERROR expected generic lifetime parameter, found `'static` +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.stderr b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.stderr new file mode 100644 index 00000000000..b08bc8b8268 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.stderr @@ -0,0 +1,59 @@ +error: non-defining opaque type use in defining scope + --> $DIR/equal-lifetime-params-not-ok.rs:10:22 + | +LL | fn test<'a>() -> Opaque<'a, 'a> {} + | ^^^^^^^^^^^^^^ generic argument `'a` used twice + | +note: for this opaque type + --> $DIR/equal-lifetime-params-not-ok.rs:9:27 + | +LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: non-defining opaque type use in defining scope + --> $DIR/equal-lifetime-params-not-ok.rs:10:37 + | +LL | fn test<'a>() -> Opaque<'a, 'a> {} + | ^^ + | +note: lifetime used multiple times + --> $DIR/equal-lifetime-params-not-ok.rs:9:17 + | +LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + | ^^ ^^ + +error: non-defining opaque type use in defining scope + --> $DIR/equal-lifetime-params-not-ok.rs:17:49 + | +LL | fn test<'a: 'b, 'b: 'a>() -> Opaque<'a, 'b> {} + | ^^ + | +note: lifetime used multiple times + --> $DIR/equal-lifetime-params-not-ok.rs:16:17 + | +LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + | ^^ ^^ + +error: non-defining opaque type use in defining scope + --> $DIR/equal-lifetime-params-not-ok.rs:23:61 + | +LL | fn test<'a: 'b, 'b: 'a>(a: &'a str) -> Opaque<'a, 'b> { a } + | ^ + | +note: lifetime used multiple times + --> $DIR/equal-lifetime-params-not-ok.rs:22:17 + | +LL | type Opaque<'a, 'b> = impl super::Trait<'a, 'b>; + | ^^ ^^ + +error[E0792]: expected generic lifetime parameter, found `'static` + --> $DIR/equal-lifetime-params-not-ok.rs:33:42 + | +LL | type Opaque<'a> = impl super::Trait<'a, 'a>; + | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type +LL | fn test<'a: 'static>() -> Opaque<'a> {} + | ^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs b/tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs new file mode 100644 index 00000000000..0ce85a4d6cb --- /dev/null +++ b/tests/ui/type-alias-impl-trait/equal-lifetime-params-ok.rs @@ -0,0 +1,52 @@ +// Normally we do not allow equal lifetimes in opaque type generic args at +// their defining sites. An exception to this rule, however, is when the bounds +// of the opaque type *require* the lifetimes to be equal. +// issue: #113916 +//@ check-pass + +#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_assoc_type)] + +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} + +mod equal_params { + type Opaque<'a: 'b, 'b: 'a> = impl super::Trait<'a, 'b>; + fn test<'a: 'b, 'b: 'a>() -> Opaque<'a, 'b> { + let _ = None::<&'a &'b &'a ()>; + 0u8 + } +} + +mod equal_static { + type Opaque<'a: 'static> = impl Sized + 'a; + fn test<'a: 'static>() -> Opaque<'a> { + let _ = None::<&'static &'a ()>; + 0u8 + } +} + +mod implied_bounds { + trait Traitor { + type Assoc; + fn define(self) -> Self::Assoc; + } + + impl<'a> Traitor for &'static &'a () { + type Assoc = impl Sized + 'a; + fn define(self) -> Self::Assoc { + let _ = None::<&'static &'a ()>; + 0u8 + } + } + + impl<'a, 'b> Traitor for (&'a &'b (), &'b &'a ()) { + type Assoc = impl Sized + 'a + 'b; + fn define(self) -> Self::Assoc { + let _ = None::<(&'a &'b (), &'b &'a ())>; + 0u8 + } + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.basic.stderr b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.basic.stderr new file mode 100644 index 00000000000..e5f86c8c193 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.basic.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/generic-not-strictly-equal.rs:33:5 + | +LL | type Opaque<'a> = impl Copy + Captures<'a>; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | relate(opaque, hidden); // defining use: Opaque<'?1> := u8 + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.member_constraints.stderr b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.member_constraints.stderr new file mode 100644 index 00000000000..693af69d6fa --- /dev/null +++ b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.member_constraints.stderr @@ -0,0 +1,15 @@ +error[E0700]: hidden type for `Opaque<'x>` captures lifetime that does not appear in bounds + --> $DIR/generic-not-strictly-equal.rs:33:5 + | +LL | type Opaque<'a> = impl Copy + Captures<'a>; + | ------------------------ opaque type defined here +LL | +LL | fn test<'x>(_: Opaque<'x>) { + | -- hidden type `&'x u8` captures the lifetime `'x` as defined here +... +LL | relate(opaque, hidden); // defining use: Opaque<'?1> := u8 + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.rs b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.rs new file mode 100644 index 00000000000..a059fd3b822 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/generic-not-strictly-equal.rs @@ -0,0 +1,38 @@ +// `Opaque<'?1> := u8` is not a valid defining use here. +// +// Due to fundamental limitations of the member constraints algorithm, +// we require '?1 to be *equal* to some universal region. +// +// While '?1 is eventually inferred to be equal to 'x because of the constraint '?1: 'x, +// we don't consider them equal in the strict sense because they lack the bidirectional outlives +// constraints ['?1: 'x, 'x: '?1]. In NLL terms, they are not part of the same SCC. +// +// See #113971 for details. + +//@ revisions: basic member_constraints +#![feature(type_alias_impl_trait)] + +trait Captures<'a> {} +impl<T> Captures<'_> for T {} + +fn ensure_outlives<'a, X: 'a>(_: X) {} +fn relate<X>(_: X, _: X) {} + +type Opaque<'a> = impl Copy + Captures<'a>; + +fn test<'x>(_: Opaque<'x>) { + let opaque = None::<Opaque<'_>>; // let's call this lifetime '?1 + + #[cfg(basic)] + let hidden = None::<u8>; + + #[cfg(member_constraints)] + let hidden = None::<&'x u8>; + + ensure_outlives::<'x>(opaque); // outlives constraint: '?1: 'x + relate(opaque, hidden); // defining use: Opaque<'?1> := u8 + //[basic]~^ ERROR expected generic lifetime parameter, found `'_` + //[member_constraints]~^^ ERROR captures lifetime that does not appear in bounds +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs index ef9fe604ea7..3b54fb7ea99 100644 --- a/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs @@ -13,6 +13,7 @@ type FutNothing<'a> = impl 'a + Future<Output = ()>; async fn operation(_: &mut ()) -> () { //~^ ERROR: concrete type differs from previous call(operation).await + //~^ ERROR: expected generic lifetime parameter, found `'any` } async fn call<F>(_f: F) diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr index d7a0452727e..c41ed0642a4 100644 --- a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr +++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr @@ -6,20 +6,17 @@ LL | type FutNothing<'a> = impl 'a + Future<Output = ()>; | = note: `FutNothing` must be used in combination with a concrete type within the same module -error: concrete type differs from previous defining opaque type use - --> $DIR/hkl_forbidden4.rs:13:1 - | -LL | async fn operation(_: &mut ()) -> () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body@$DIR/hkl_forbidden4.rs:13:38: 16:2}` - | -note: previous use here +error[E0792]: expected generic lifetime parameter, found `'any` --> $DIR/hkl_forbidden4.rs:15:5 | +LL | async fn operation(_: &mut ()) -> () { + | - this generic parameter must be used with a generic lifetime parameter +LL | LL | call(operation).await | ^^^^^^^^^^^^^^^ error[E0792]: expected generic lifetime parameter, found `'any` - --> $DIR/hkl_forbidden4.rs:21:1 + --> $DIR/hkl_forbidden4.rs:22:1 | LL | type FutNothing<'a> = impl 'a + Future<Output = ()>; | -- this generic parameter must be used with a generic lifetime parameter @@ -29,6 +26,18 @@ LL | | LL | | } | |_^ -error: aborting due to 3 previous errors +error: concrete type differs from previous defining opaque type use + --> $DIR/hkl_forbidden4.rs:13:1 + | +LL | async fn operation(_: &mut ()) -> () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body of operation()}` + | +note: previous use here + --> $DIR/hkl_forbidden4.rs:15:5 + | +LL | call(operation).await + | ^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/lifetime_mismatch.rs b/tests/ui/type-alias-impl-trait/lifetime_mismatch.rs index 9ec585d93f5..45a55050c44 100644 --- a/tests/ui/type-alias-impl-trait/lifetime_mismatch.rs +++ b/tests/ui/type-alias-impl-trait/lifetime_mismatch.rs @@ -5,7 +5,6 @@ type Foo<'a> = impl Sized; fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> (Foo<'a>, Foo<'b>) { (x, y) //~^ ERROR opaque type used twice with different lifetimes - //~| ERROR opaque type used twice with different lifetimes } type Bar<'a, 'b> = impl std::fmt::Debug; @@ -13,9 +12,6 @@ type Bar<'a, 'b> = impl std::fmt::Debug; fn bar<'x, 'y>(i: &'x i32, j: &'y i32) -> (Bar<'x, 'y>, Bar<'y, 'x>) { (i, j) //~^ ERROR opaque type used twice with different lifetimes - //~| ERROR opaque type used twice with different lifetimes - //~| ERROR opaque type used twice with different lifetimes - //~| ERROR opaque type used twice with different lifetimes } fn main() { diff --git a/tests/ui/type-alias-impl-trait/lifetime_mismatch.stderr b/tests/ui/type-alias-impl-trait/lifetime_mismatch.stderr index 7f54f47d27d..4f7b0f17407 100644 --- a/tests/ui/type-alias-impl-trait/lifetime_mismatch.stderr +++ b/tests/ui/type-alias-impl-trait/lifetime_mismatch.stderr @@ -14,53 +14,7 @@ LL | (x, y) | ^^^^^^ error: opaque type used twice with different lifetimes - --> $DIR/lifetime_mismatch.rs:6:5 - | -LL | (x, y) - | ^^^^^^ - | | - | lifetime `'a` used here - | lifetime `'b` previously used here - | -note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types - --> $DIR/lifetime_mismatch.rs:6:5 - | -LL | (x, y) - | ^^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: opaque type used twice with different lifetimes - --> $DIR/lifetime_mismatch.rs:14:5 - | -LL | (i, j) - | ^^^^^^ - | | - | lifetime `'x` used here - | lifetime `'y` previously used here - | -note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types - --> $DIR/lifetime_mismatch.rs:14:5 - | -LL | (i, j) - | ^^^^^^ - -error: opaque type used twice with different lifetimes - --> $DIR/lifetime_mismatch.rs:14:5 - | -LL | (i, j) - | ^^^^^^ - | | - | lifetime `'y` used here - | lifetime `'x` previously used here - | -note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types - --> $DIR/lifetime_mismatch.rs:14:5 - | -LL | (i, j) - | ^^^^^^ - -error: opaque type used twice with different lifetimes - --> $DIR/lifetime_mismatch.rs:14:5 + --> $DIR/lifetime_mismatch.rs:13:5 | LL | (i, j) | ^^^^^^ @@ -69,27 +23,10 @@ LL | (i, j) | lifetime `'y` previously used here | note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types - --> $DIR/lifetime_mismatch.rs:14:5 - | -LL | (i, j) - | ^^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: opaque type used twice with different lifetimes - --> $DIR/lifetime_mismatch.rs:14:5 - | -LL | (i, j) - | ^^^^^^ - | | - | lifetime `'y` used here - | lifetime `'x` previously used here - | -note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types - --> $DIR/lifetime_mismatch.rs:14:5 + --> $DIR/lifetime_mismatch.rs:13:5 | LL | (i, j) | ^^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs index 5bec38c5e5b..580fb58ef83 100644 --- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs +++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.rs @@ -3,11 +3,8 @@ type Foo<'a, 'b> = impl std::fmt::Debug; fn foo<'x, 'y>(i: &'x i32, j: &'y i32) -> (Foo<'x, 'y>, Foo<'y, 'x>) { - (i, i) + (i, j) //~^ ERROR opaque type used twice with different lifetimes - //~| ERROR opaque type used twice with different lifetimes - //~| ERROR opaque type used twice with different lifetimes - //~| ERROR opaque type used twice with different lifetimes } fn main() {} diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr index 0ccb3e2221d..b2b9e604a6b 100644 --- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr +++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn-lifetimes.stderr @@ -1,7 +1,7 @@ error: opaque type used twice with different lifetimes --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5 | -LL | (i, i) +LL | (i, j) | ^^^^^^ | | | lifetime `'x` used here @@ -10,55 +10,8 @@ LL | (i, i) note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5 | -LL | (i, i) +LL | (i, j) | ^^^^^^ -error: opaque type used twice with different lifetimes - --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5 - | -LL | (i, i) - | ^^^^^^ - | | - | lifetime `'y` used here - | lifetime `'x` previously used here - | -note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types - --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5 - | -LL | (i, i) - | ^^^^^^ - -error: opaque type used twice with different lifetimes - --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5 - | -LL | (i, i) - | ^^^^^^ - | | - | lifetime `'x` used here - | lifetime `'y` previously used here - | -note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types - --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5 - | -LL | (i, i) - | ^^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: opaque type used twice with different lifetimes - --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5 - | -LL | (i, i) - | ^^^^^^ - | | - | lifetime `'y` used here - | lifetime `'x` previously used here - | -note: if all non-lifetime generic parameters are the same, but the lifetime parameters differ, it is not possible to differentiate the opaque types - --> $DIR/multiple-def-uses-in-one-fn-lifetimes.rs:6:5 - | -LL | (i, i) - | ^^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.stderr b/tests/ui/type-alias-impl-trait/nested-tait-inference2.stderr index c549ca5b2ce..241342b0509 100644 --- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.stderr +++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.stderr @@ -8,8 +8,8 @@ LL | () | -- return type was inferred to be `()` here | = help: the following other types implement trait `Foo<A>`: - <() as Foo<u32>> <() as Foo<()>> + <() as Foo<u32>> error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/param_mismatch4.rs b/tests/ui/type-alias-impl-trait/param_mismatch4.rs new file mode 100644 index 00000000000..e072f3ab8e0 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/param_mismatch4.rs @@ -0,0 +1,16 @@ +//! This test checks that when checking for opaque types that +//! only differ in lifetimes, we handle the case of non-generic +//! regions correctly. +#![feature(type_alias_impl_trait)] + +type Opq<'a> = impl Sized; + +// Two defining uses: Opq<'{empty}> and Opq<'a>. +// This used to ICE. +// issue: #122782 +fn build<'a>() -> Opq<'a> { + let _: Opq<'_> = (); + //~^ ERROR expected generic lifetime parameter, found `'_` +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/param_mismatch4.stderr b/tests/ui/type-alias-impl-trait/param_mismatch4.stderr new file mode 100644 index 00000000000..d3fdea25a3d --- /dev/null +++ b/tests/ui/type-alias-impl-trait/param_mismatch4.stderr @@ -0,0 +1,12 @@ +error[E0792]: expected generic lifetime parameter, found `'_` + --> $DIR/param_mismatch4.rs:12:12 + | +LL | type Opq<'a> = impl Sized; + | -- this generic parameter must be used with a generic lifetime parameter +... +LL | let _: Opq<'_> = (); + | ^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0792`. diff --git a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903-fixed.rs b/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903-fixed.rs new file mode 100644 index 00000000000..109a70c766d --- /dev/null +++ b/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903-fixed.rs @@ -0,0 +1,26 @@ +//@ check-pass + +#![feature(type_alias_impl_trait)] +#![allow(dead_code)] + +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +impl<R: Duh, F: FnMut() -> R> Trait for F { + type Assoc = R; +} + +type Sendable = impl Send + Duh; + +type Foo = impl Trait<Assoc = Sendable>; + +fn foo() -> Foo { + || 42 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs b/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs new file mode 100644 index 00000000000..4f9d54737dc --- /dev/null +++ b/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.rs @@ -0,0 +1,29 @@ +//@ check-pass + +// See https://doc.rust-lang.org/1.77.0/nightly-rustc/rustc_lint/opaque_hidden_inferred_bound/static.OPAQUE_HIDDEN_INFERRED_BOUND.html#example + +#![feature(type_alias_impl_trait)] +#![allow(dead_code)] + +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +impl<R: Duh, F: FnMut() -> R> Trait for F { + type Assoc = R; +} + +type Sendable = impl Send; + +type Foo = impl Trait<Assoc = Sendable>; + //~^ WARNING opaque type `Foo` does not satisfy its associated type bounds + +fn foo() -> Foo { + || 42 +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr b/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr new file mode 100644 index 00000000000..68def454c7f --- /dev/null +++ b/tests/ui/type-alias-impl-trait/tait-in-function-return-type-issue-101903.stderr @@ -0,0 +1,13 @@ +warning: opaque type `Foo` does not satisfy its associated type bounds + --> $DIR/tait-in-function-return-type-issue-101903.rs:22:23 + | +LL | type Assoc: Duh; + | --- this associated type bound is unsatisfied for `Sendable` +... +LL | type Foo = impl Trait<Assoc = Sendable>; + | ^^^^^^^^^^^^^^^^ + | + = note: `#[warn(opaque_hidden_inferred_bound)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/type/type-check-defaults.stderr b/tests/ui/type/type-check-defaults.stderr index 10d600cbfcc..9ba63ffe9c9 100644 --- a/tests/ui/type/type-check-defaults.stderr +++ b/tests/ui/type/type-check-defaults.stderr @@ -66,10 +66,10 @@ LL | trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {} | = help: the trait `Add<u8>` is not implemented for `i32` = help: the following other types implement trait `Add<Rhs>`: - <i32 as Add> - <i32 as Add<&i32>> <&'a i32 as Add<i32>> <&i32 as Add<&i32>> + <i32 as Add<&i32>> + <i32 as Add> error: aborting due to 7 previous errors diff --git a/tests/ui/typeck/issue-81293.stderr b/tests/ui/typeck/issue-81293.stderr index 292c63070ae..6976be71135 100644 --- a/tests/ui/typeck/issue-81293.stderr +++ b/tests/ui/typeck/issue-81293.stderr @@ -21,10 +21,10 @@ LL | a = c + b * 5; | = help: the trait `Add<u16>` is not implemented for `usize` = help: the following other types implement trait `Add<Rhs>`: - <usize as Add> - <usize as Add<&usize>> <&'a usize as Add<usize>> <&usize as Add<&usize>> + <usize as Add<&usize>> + <usize as Add> error: aborting due to 3 previous errors diff --git a/tests/ui/typeck/issue-90101.stderr b/tests/ui/typeck/issue-90101.stderr index d5ba157974d..800d7e9594a 100644 --- a/tests/ui/typeck/issue-90101.stderr +++ b/tests/ui/typeck/issue-90101.stderr @@ -7,11 +7,11 @@ LL | func(Path::new("hello").to_path_buf().to_string_lossy(), "world") | required by a bound introduced by this call | = help: the following other types implement trait `From<T>`: + <PathBuf as From<&T>> <PathBuf as From<Box<Path>>> <PathBuf as From<Cow<'a, Path>>> <PathBuf as From<OsString>> <PathBuf as From<String>> - <PathBuf as From<&T>> = note: required for `Cow<'_, str>` to implement `Into<PathBuf>` note: required by a bound in `func` --> $DIR/issue-90101.rs:3:20 diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr index 8bcad56916a..7977504dae1 100644 --- a/tests/ui/typeck/typeck_type_placeholder_item.stderr +++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr @@ -546,6 +546,15 @@ help: use type parameters instead LL | fn fn_test10<T>(&self, _x : T) { } | +++ ~ +error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants + --> $DIR/typeck_type_placeholder_item.rs:194:14 + | +LL | const D: _ = 42; + | ^ + | | + | not allowed in type signatures + | help: replace with the correct type: `i32` + error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types --> $DIR/typeck_type_placeholder_item.rs:217:31 | @@ -574,19 +583,7 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:209:14 | LL | const D: _ = 42; - | ^ - | | - | not allowed in type signatures - | help: replace with the correct type: `i32` - -error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants - --> $DIR/typeck_type_placeholder_item.rs:194:14 - | -LL | const D: _ = 42; - | ^ - | | - | not allowed in type signatures - | help: replace with the correct type: `i32` + | ^ not allowed in type signatures error[E0046]: not all trait items implemented, missing: `F` --> $DIR/typeck_type_placeholder_item.rs:200:1 diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr index c1281ce6a42..964fd4af009 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -6,10 +6,10 @@ LL | <i32 as Add<u32>>::add(1, 2); | = help: the trait `Add<u32>` is not implemented for `i32` = help: the following other types implement trait `Add<Rhs>`: - <i32 as Add> - <i32 as Add<&i32>> <&'a i32 as Add<i32>> <&i32 as Add<&i32>> + <i32 as Add<&i32>> + <i32 as Add> error[E0277]: cannot add `u32` to `i32` --> $DIR/ufcs-qpath-self-mismatch.rs:4:5 @@ -19,10 +19,10 @@ LL | <i32 as Add<u32>>::add(1, 2); | = help: the trait `Add<u32>` is not implemented for `i32` = help: the following other types implement trait `Add<Rhs>`: - <i32 as Add> - <i32 as Add<&i32>> <&'a i32 as Add<i32>> <&i32 as Add<&i32>> + <i32 as Add<&i32>> + <i32 as Add> error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:7:28 diff --git a/triagebot.toml b/triagebot.toml index a42bafe148c..0df71c60d54 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -424,7 +424,15 @@ message_on_reopen = "Issue #{number} has been reopened. Pinging @*T-types*." [notify-zulip."A-edition-2021"] required_labels = ["C-bug"] -zulip_stream = 268952 # #edition 2021 +zulip_stream = 268952 # #edition +topic = "Edition Bugs" +message_on_add = """\ +Issue #{number} "{title}" has been added (previous edition 2021). +""" + +[notify-zulip."A-edition-2024"] +required_labels = ["C-bug"] +zulip_stream = 268952 # #edition topic = "Edition Bugs" message_on_add = """\ Issue #{number} "{title}" has been added. @@ -709,6 +717,9 @@ cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] [mentions."src/doc/unstable-book/src/compiler-flags/check-cfg.md"] cc = ["@Urgau"] +[mentions."src/doc/rustc/src/platform-support"] +cc = ["@Nilstrieb"] + [mentions."tests/codegen/sanitizer"] cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] |
