diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 593eac2df489..3a5b6ad608aa 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -508,7 +508,7 @@ fn finalize_body_lowering( // FIXME(fn_delegation): proper support for parent generics propagation // in method call scenario. - let segment = self.process_segment(span, &segment, &mut generics.child, false); + let segment = self.process_segment(span, &segment, &mut generics.child); let segment = self.arena.alloc(segment); self.arena.alloc(hir::Expr { @@ -534,14 +534,10 @@ fn finalize_body_lowering( new_path.segments = self.arena.alloc_from_iter( new_path.segments.iter().enumerate().map(|(idx, segment)| { - let mut process_segment = |result, add_lifetimes| { - self.process_segment(span, segment, result, add_lifetimes) - }; - if idx + 2 == len { - process_segment(&mut generics.parent, true) + self.process_segment(span, segment, &mut generics.parent) } else if idx + 1 == len { - process_segment(&mut generics.child, false) + self.process_segment(span, segment, &mut generics.child) } else { segment.clone() } @@ -551,7 +547,7 @@ fn finalize_body_lowering( hir::QPath::Resolved(ty, self.arena.alloc(new_path)) } hir::QPath::TypeRelative(ty, segment) => { - let segment = self.process_segment(span, segment, &mut generics.child, false); + let segment = self.process_segment(span, segment, &mut generics.child); hir::QPath::TypeRelative(ty, self.arena.alloc(segment)) } @@ -584,13 +580,12 @@ fn process_segment( span: Span, segment: &hir::PathSegment<'hir>, result: &mut GenericsGenerationResult<'hir>, - add_lifetimes: bool, ) -> hir::PathSegment<'hir> { let details = result.generics.args_propagation_details(); let segment = if details.should_propagate { let generics = result.generics.into_hir_generics(self, span); - let args = generics.into_generic_args(self, add_lifetimes, span); + let args = generics.into_generic_args(self, span); // Needed for better error messages (`trait-impl-wrong-args-count.rs` test). let args = if args.is_empty() { None } else { Some(args) }; diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index 201f6bfb4bd6..503877cff978 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::GenericParamDefKind; use rustc_middle::{bug, ty}; use rustc_span::symbol::kw; -use rustc_span::{Ident, Span}; +use rustc_span::{Ident, Span, sym}; use crate::{LoweringContext, ResolverAstLoweringExt}; @@ -25,22 +25,37 @@ pub(super) enum DelegationGenericsKind { TraitImpl(bool /* Has user-specified args */), } +#[derive(Debug, Clone, Copy)] +pub(super) enum GenericsPosition { + Parent, + Child, +} + pub(super) struct DelegationGenerics { generics: T, kind: DelegationGenericsKind, + pos: GenericsPosition, } impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> { - fn default(generics: &'hir [ty::GenericParamDef]) -> Self { - DelegationGenerics { generics, kind: DelegationGenericsKind::Default } + fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self { + DelegationGenerics { generics, pos, kind: DelegationGenericsKind::Default } } - fn user_specified(generics: &'hir [ty::GenericParamDef]) -> Self { - DelegationGenerics { generics, kind: DelegationGenericsKind::UserSpecified } + fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self { + DelegationGenerics { generics, pos, kind: DelegationGenericsKind::UserSpecified } } - fn trait_impl(generics: &'hir [ty::GenericParamDef], user_specified: bool) -> Self { - DelegationGenerics { generics, kind: DelegationGenericsKind::TraitImpl(user_specified) } + fn trait_impl( + generics: &'hir [ty::GenericParamDef], + user_specified: bool, + pos: GenericsPosition, + ) -> Self { + DelegationGenerics { + generics, + pos, + kind: DelegationGenericsKind::TraitImpl(user_specified), + } } } @@ -103,8 +118,14 @@ pub(super) fn into_hir_generics( span: Span, ) -> &mut HirOrTyGenerics<'hir> { if let HirOrTyGenerics::Ty(ty) = self { - let params = ctx.uplift_delegation_generic_params(span, ty.generics); - *self = HirOrTyGenerics::Hir(DelegationGenerics { generics: params, kind: ty.kind }); + let rename_self = matches!(ty.pos, GenericsPosition::Child); + let params = ctx.uplift_delegation_generic_params(span, ty.generics, rename_self); + + *self = HirOrTyGenerics::Hir(DelegationGenerics { + generics: params, + kind: ty.kind, + pos: ty.pos, + }); } self @@ -120,7 +141,6 @@ fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> { pub(super) fn into_generic_args( &self, ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>, - add_lifetimes: bool, span: Span, ) -> &'hir hir::GenericArgs<'hir> { match self { @@ -128,6 +148,7 @@ pub(super) fn into_generic_args( bug!("Attempting to get generic args before uplifting to HIR") } HirOrTyGenerics::Hir(hir) => { + let add_lifetimes = matches!(hir.pos, GenericsPosition::Parent); ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span) } } @@ -227,10 +248,15 @@ pub(super) fn uplift_delegation_generics( if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) { // Considering parent generics, during signature inheritance // we will take those args that are in trait impl header trait ref. - let parent = DelegationGenerics::trait_impl(&[], true); + let parent = DelegationGenerics::trait_impl(&[], true, GenericsPosition::Parent); let parent = GenericsGenerationResult::new(parent); - let child = DelegationGenerics::trait_impl(sig_params, child_user_specified); + let child = DelegationGenerics::trait_impl( + sig_params, + child_user_specified, + GenericsPosition::Child, + ); + let child = GenericsGenerationResult::new(child); return GenericsGenerationResults { @@ -263,25 +289,32 @@ pub(super) fn uplift_delegation_generics( DelegationGenerics { kind: DelegationGenericsKind::SelfAndUserSpecified, generics: &sig_parent_params[..1], + pos: GenericsPosition::Parent, } } else { - DelegationGenerics::user_specified(&[]) + DelegationGenerics::user_specified(&[], GenericsPosition::Parent) } } else { let skip_self = usize::from(!generate_self); - DelegationGenerics::default(&sig_parent_params[skip_self..]) + DelegationGenerics::default( + &sig_parent_params[skip_self..], + GenericsPosition::Parent, + ) } } else { - DelegationGenerics::default(&[]) + DelegationGenerics::default(&[], GenericsPosition::Parent) }; let child_generics = if child_user_specified { let synth_params_index = sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len()); - DelegationGenerics::user_specified(&sig_params[synth_params_index..]) + DelegationGenerics::user_specified( + &sig_params[synth_params_index..], + GenericsPosition::Child, + ) } else { - DelegationGenerics::default(sig_params) + DelegationGenerics::default(sig_params, GenericsPosition::Child) }; GenericsGenerationResults { @@ -296,6 +329,7 @@ fn uplift_delegation_generic_params( &mut self, span: Span, params: &'hir [ty::GenericParamDef], + rename_self: bool, ) -> &'hir hir::Generics<'hir> { let params = self.arena.alloc_from_iter(params.iter().map(|p| { let def_kind = match p.kind { @@ -304,7 +338,20 @@ fn uplift_delegation_generic_params( GenericParamDefKind::Const { .. } => DefKind::ConstParam, }; - let param_ident = Ident::new(p.name, span); + // Rename Self generic param to This so it is properly propagated. + // If the user will create a function `fn foo() {}` with generic + // param "Self" then it will not be generated in HIR, the same thing + // applies to traits, `trait Trait {}` will be represented as + // `trait Trait {}` in HIR and "unexpected keyword `Self` in generic parameters" + // error will be emitted. + // Note that we do not rename `Self` to `This` after non-recursive reuse + // from Trait, in this case the `Self` should not be propagated + // (we rely that implicit `Self` generic param of a trait is named "Self") + // and it is OK to have Self generic param generated during lowering. + let param_name = + if rename_self && p.name == kw::SelfUpper { sym::This } else { p.name }; + + let param_ident = Ident::new(param_name, span); let def_name = Some(param_ident.name); let node_id = self.next_node_id(); diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index f6544c035145..cb66dabf507a 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -396,6 +396,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { _ => EF_PPC64_ABI_UNKNOWN, } } + Architecture::Sparc32Plus => elf::EF_SPARC_32PLUS, _ => 0, } } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 57139d077d49..2f27b7e5082f 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -16,10 +16,7 @@ use hir::def::DefKind; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_hir::def_id::LocalDefIdMap; -use rustc_hir::definitions::{ - DefPathData, PerParentDisambiguatorState, PerParentDisambiguatorsMap, -}; +use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState}; use rustc_hir::{self as hir}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::interpret::{ @@ -108,7 +105,7 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, mutability: Mutability, - disambiguators: Option<&mut LocalDefIdMap>, + disambiguator: Option<&mut PerParentDisambiguatorState>, ) -> Result + 'tcx, InternError> { trace!("intern_shallow {:?}", alloc_id); // remove allocation @@ -132,7 +129,7 @@ fn intern_shallow<'tcx, M: CompileTimeMachine<'tcx>>( static_id, alloc_id, alloc, - disambiguators.expect("disambiguators needed"), + disambiguator.expect("disambiguator needed"), ); } else { ecx.tcx.set_alloc_id_memory(alloc_id, alloc); @@ -147,19 +144,18 @@ fn intern_as_new_static<'tcx>( static_id: LocalDefId, alloc_id: AllocId, alloc: ConstAllocation<'tcx>, - disambiguators: &mut LocalDefIdMap, + disambiguator: &mut PerParentDisambiguatorState, ) { - // `intern_const_alloc_recursive` is called once per static and it contains the `DisambiguatorState`. + // `intern_const_alloc_recursive` is called once per static and it contains the `PerParentDisambiguatorState`. // The `::{{nested}}` path is thus unique to `intern_const_alloc_recursive` and the - // `DisambiguatorState` ensures the generated path is unique for this call as we generate + // `PerParentDisambiguatorState` ensures the generated path is unique for this call as we generate // `::{{nested#n}}` where `n` is the `n`th `intern_as_new_static` call. let feed = tcx.create_def( static_id, None, DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, Some(DefPathData::NestedStatic), - //FIXME(oli-obk): cleanup (https://github.com/rust-lang/rust/pull/155547#discussion_r3110792640) - disambiguators.get_or_create(static_id), + disambiguator, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); @@ -209,7 +205,9 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( intern_kind: InternKind, ret: &MPlaceTy<'tcx>, ) -> Result<(), InternError> { - let mut disambiguators = Default::default(); + let mut disambiguator = + ecx.machine.static_def_id().map(|id| PerParentDisambiguatorState::new(id)); + let mut disambiguator = disambiguator.as_mut(); // We are interning recursively, and for mutability we are distinguishing the "root" allocation // that we are starting in, and all other allocations that we are encountering recursively. @@ -248,13 +246,15 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( // This gives us the initial set of nested allocations, which will then all be processed // recursively in the loop below. let mut todo: Vec<_> = if is_static { + assert!(disambiguator.is_some()); // Do not steal the root allocation, we need it later to create the return value of `eval_static_initializer`. // But still change its mutability to match the requested one. let (kind, alloc) = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap(); prepare_alloc(*ecx.tcx, *kind, alloc, base_mutability)?; alloc.provenance().ptrs().iter().map(|&(_, prov)| prov).collect() } else { - intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguators))?.collect() + assert!(disambiguator.is_none()); + intern_shallow(ecx, base_alloc_id, base_mutability, None)?.collect() }; // We need to distinguish "has just been interned" from "was already in `tcx`", // so we track this in a separate set. @@ -336,7 +336,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx>>( // okay with losing some potential for immutability here. This can anyway only affect // `static mut`. just_interned.insert(alloc_id); - let next = intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguators))?; + let next = intern_shallow(ecx, alloc_id, inner_mutability, disambiguator.as_deref_mut())?; todo.extend(next); } if found_bad_mutable_ptr { diff --git a/compiler/rustc_session/src/config/print_request.rs b/compiler/rustc_session/src/config/print_request.rs index dc53fcc6955f..b87236cef764 100644 --- a/compiler/rustc_session/src/config/print_request.rs +++ b/compiler/rustc_session/src/config/print_request.rs @@ -50,11 +50,6 @@ pub enum PrintKind { } impl PrintKind { - /// FIXME: rust-analyzer doesn't support `#![feature(macro_derive)]` yet - /// (), which breaks autocomplete. - /// Work around that by aliasing the trait constant to a regular constant. - const ALL_VARIANTS: &[Self] = ::ALL_VARIANTS; - fn name(self) -> &'static str { use PrintKind::*; match self { diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs index 7dd36d6e82c4..1e4f70ebcd31 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs @@ -1,4 +1,6 @@ -use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CfgAbi, FloatAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { Target { @@ -24,6 +26,7 @@ pub(crate) fn target() -> Target { // linker error, so set it to `true` here. // FIXME(#146996): Remove this override once #146996 has been fixed. default_uwtable: false, + supported_sanitizers: SanitizerSet::ADDRESS, ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs index a1f90b307c3c..8bf3dfd24722 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs @@ -1,4 +1,6 @@ -use crate::spec::{Arch, CfgAbi, FloatAbi, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Arch, CfgAbi, FloatAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base, +}; // This target is for glibc Linux on ARMv7 without NEON or // thumb-mode. See the thumbv7neon variant for enabling both. @@ -23,6 +25,7 @@ pub(crate) fn target() -> Target { max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), + supported_sanitizers: SanitizerSet::ADDRESS, ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs index 011307a50c34..4e20f04173f0 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabi.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7a-none-eabi".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-A".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs index 4baa73c3cdb8..bf4241a47277 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_none_eabihf.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7a-none-eabihf".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-A, hardfloat".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs index da66a5343200..296a1d00bad3 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabi.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7r-none-eabi".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-R".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs index d591db8faf6a..8d5ac8a2d0a3 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv7r_none_eabihf.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv7r-none-eabihf".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv7-R, hardfloat".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs index 459dff9c1aa9..808287ffa3d6 100644 --- a/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/thumbv8r_none_eabihf.rs @@ -7,7 +7,7 @@ pub(crate) fn target() -> Target { llvm_target: "thumbv8r-none-eabihf".into(), metadata: TargetMetadata { description: Some("Thumb-mode Bare Armv8-R, hardfloat".into()), - tier: Some(2), + tier: Some(3), host_tools: Some(false), std: Some(false), }, diff --git a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs index 8c5a253b0e2f..629560af0156 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs @@ -10,7 +10,7 @@ //! those target flags doesn't automatically rebuild libcore / liballoc with //! them, and in order to get those libraries rebuilt you need to use the //! nightly Rust feature `-Zbuild-std`. This target is for people who want to -//! use stable Rust, and target a stable set pf WebAssembly features. +//! use stable Rust, and target a stable set of WebAssembly features. use crate::spec::{Arch, Cc, LinkerFlavor, Os, Target, TargetMetadata, base}; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index e6597a67d0ba..1a308ee334d3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -363,6 +363,7 @@ pub(super) fn maybe_report_ambiguity( if impl_candidates.len() < 40 { self.report_similar_impl_candidates( impl_candidates.as_slice(), + obligation, trait_pred, obligation.cause.body_id, &mut err, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 4a36cab36336..0d6cd53dacab 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1973,6 +1973,7 @@ pub(super) fn find_similar_impl_candidates( pub(super) fn report_similar_impl_candidates( &self, impl_candidates: &[ImplCandidate<'tcx>], + obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, body_def_id: LocalDefId, err: &mut Diag<'_>, @@ -2037,6 +2038,20 @@ pub(super) fn report_similar_impl_candidates( }; if let [single] = &impl_candidates { + let self_ty = trait_pred.skip_binder().self_ty(); + if !self_ty.has_escaping_bound_vars() { + let self_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty()); + if let ty::Ref(_, inner_ty, _) = self_ty.kind() + && self.can_eq(param_env, single.trait_ref.self_ty(), *inner_ty) + && !self.where_clause_expr_matches_failed_self_ty(obligation, self_ty) + { + // Avoid pointing at a nearby impl like `String: Borrow` when the + // failing obligation comes from something nested inside an enclosing call + // expression such as `foo(&[String::from("a")])`. + return true; + } + } + // If we have a single implementation, try to unify it with the trait ref // that failed. This should uncover a better hint for what *is* implemented. if self.probe(|_| { @@ -2456,6 +2471,7 @@ fn report_similar_impl_candidates_for_root_obligation( let impl_candidates = self.find_similar_impl_candidates(trait_pred); self.report_similar_impl_candidates( &impl_candidates, + obligation, trait_pred, body_def_id, err, @@ -3137,6 +3153,7 @@ fn try_to_add_help_message( let impl_candidates = self.find_similar_impl_candidates(trait_predicate); if !self.report_similar_impl_candidates( &impl_candidates, + obligation, trait_predicate, body_def_id, err, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 98504d2e0553..562c5956c9a8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1584,6 +1584,39 @@ pub fn extract_callable_info( if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) } } + pub(super) fn where_clause_expr_matches_failed_self_ty( + &self, + obligation: &PredicateObligation<'tcx>, + old_self_ty: Ty<'tcx>, + ) -> bool { + let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code() else { + return true; + }; + let (Some(typeck_results), Some(body)) = ( + self.typeck_results.as_ref(), + self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id), + ) else { + return true; + }; + + let mut expr_finder = FindExprBySpan::new(obligation.cause.span, self.tcx); + expr_finder.visit_expr(body.value); + let Some(expr) = expr_finder.result else { + return true; + }; + + let inner_old_self_ty = match old_self_ty.kind() { + ty::Ref(_, inner_ty, _) => Some(*inner_ty), + _ => None, + }; + + [typeck_results.expr_ty_adjusted_opt(expr)].into_iter().flatten().any(|expr_ty| { + self.can_eq(obligation.param_env, expr_ty, old_self_ty) + || inner_old_self_ty + .is_some_and(|inner_ty| self.can_eq(obligation.param_env, expr_ty, inner_ty)) + }) + } + pub(super) fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, @@ -1857,6 +1890,15 @@ pub(super) fn suggest_add_reference_to_arg( if let hir::ExprKind::AddrOf(_, _, _) = expr.kind { return false; } + let old_self_ty = old_pred.skip_binder().self_ty(); + if !old_self_ty.has_escaping_bound_vars() + && !self.where_clause_expr_matches_failed_self_ty( + obligation, + self.tcx.instantiate_bound_regions_with_erased(old_pred.self_ty()), + ) + { + return false; + } let needs_parens_post = expr_needs_parens(expr); let needs_parens_pre = match self.tcx.parent_hir_node(expr.hir_id) { Node::Expr(e) diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 1d24a207103c..443f33aaa0b0 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,8 +1,6 @@ use rustc_hir::def::DefKind; -use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdMap}; -use rustc_hir::definitions::{ - DefPathData, PerParentDisambiguatorState, PerParentDisambiguatorsMap, -}; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; +use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, ConstItemRhs, ImplItemImplKind, ItemKind}; use rustc_middle::query::Providers; @@ -131,7 +129,7 @@ struct RPITVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, synthetics: Vec, data: DefPathData, - disambiguators: &'a mut LocalDefIdMap, + disambiguator: &'a mut PerParentDisambiguatorState, } impl<'tcx> Visitor<'tcx> for RPITVisitor<'_, 'tcx> { @@ -140,7 +138,7 @@ fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result self.tcx, opaque.def_id, self.data, - &mut self.disambiguators, + &mut self.disambiguator, )); intravisit::walk_opaque_ty(self, opaque) } @@ -151,7 +149,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( def_id: LocalDefId, ) -> DefIdMap> { let item = tcx.hir_expect_item(def_id); - let disambiguators = &mut Default::default(); + let disambiguator = &mut PerParentDisambiguatorState::new(def_id); match item.kind { ItemKind::Trait(.., trait_item_refs) => trait_item_refs .iter() @@ -165,7 +163,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( }; let def_name = tcx.item_name(fn_def_id.to_def_id()); let data = DefPathData::AnonAssocTy(def_name); - let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, disambiguators }; + let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, disambiguator }; visitor.visit_fn_ret_ty(output); let defs = visitor .synthetics @@ -199,7 +197,7 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( return Some((did, vec![])); }; let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| { - associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguators) + associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguator) .to_def_id() }); Some((did, iter.collect())) @@ -223,7 +221,7 @@ fn associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, data: DefPathData, - disambiguators: &mut LocalDefIdMap, + disambiguator: &mut PerParentDisambiguatorState, ) -> LocalDefId { let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) = @@ -242,7 +240,7 @@ fn associated_type_for_impl_trait_in_trait( None, DefKind::AssocTy, Some(data), - disambiguators.get_or_create(trait_def_id), + disambiguator, ); let local_def_id = trait_assoc_ty.def_id(); @@ -285,7 +283,7 @@ fn associated_type_for_impl_trait_in_impl( tcx: TyCtxt<'_>, trait_assoc_def_id: DefId, impl_fn: &hir::ImplItem<'_>, - disambiguators: &mut LocalDefIdMap, + disambiguator: &mut PerParentDisambiguatorState, ) -> LocalDefId { let impl_local_def_id = tcx.local_parent(impl_fn.owner_id.def_id); @@ -308,7 +306,7 @@ fn associated_type_for_impl_trait_in_impl( None, DefKind::AssocTy, Some(data), - disambiguators.get_or_create(impl_local_def_id), + disambiguator, ); let local_def_id = impl_assoc_ty.def_id(); diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 4a4c7ee388f9..85d42b57dc06 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -11,7 +11,7 @@ //! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], //! but should be implemented when the conversion can fail. //! -//! The traits in this module are often used as trait bounds for generic functions such that to +//! The traits in this module are often used as trait bounds for generic functions such that //! arguments of multiple types are supported. See the documentation of each trait for examples. //! //! As a library author, you should always prefer implementing [`From`][`From`] or diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index fab695c1c5e1..c2ffd0793a81 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -131,6 +131,7 @@ /// [`read`]: File::read #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "File")] +#[diagnostic::on_move(note = "you can use `File::try_clone` to duplicate a `File` instance")] pub struct File { inner: fs_imp::File, } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 807befec1ad1..8f83fede1edd 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -278,6 +278,7 @@ #![feature(const_trait_impl)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] +#![feature(diagnostic_on_move)] #![feature(doc_cfg)] #![feature(doc_masked)] #![feature(doc_notable_trait)] diff --git a/src/doc/unstable-book/src/language-features/diagnostic-on-move.md b/src/doc/unstable-book/src/language-features/diagnostic-on-move.md new file mode 100644 index 000000000000..ba35b0736141 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/diagnostic-on-move.md @@ -0,0 +1,92 @@ +# `diagnostic_on_move` + +The tracking issue for this feature is: [#154181] + +------------------------ + +The `diagnostic_on_move` feature allows use of the `#[diagnostic::on_move]` attribute. It should be +placed on struct, enum and union declarations, though it is not an error to be located in other +positions. This attribute is a hint to the compiler to supplement the error message when the +annotated type is involved in a borrowcheck error. + +For example, [`File`] is annotated as such: +```rust +#![feature(diagnostic_on_move)] + +#[diagnostic::on_move(note = "you can use `File::try_clone` \ + to duplicate a `File` instance")] +pub struct File { + // ... +} +``` + +When you try to use a `File` after it's already been moved, it will helpfully tell you about `try_clone`. + +The message and label can also be customized: + +```rust +#![feature(diagnostic_on_move)] + +use std::marker::PhantomData; + +#[diagnostic::on_move( + message = "`{Self}` cannot be used multiple times", + label = "this token may only be used once", + note = "you can create a new `Token` with `Token::conjure()`" +)] +pub struct Token<'brand> { + spooky: PhantomData<&'brand ()>, +} + +impl Token<'_> { + pub fn conjure<'u>() -> Token<'u> { + Token { + spooky: PhantomData, + } + } +} +``` +The user may try to use it like this: +```rust,compile_fail,E0382 +# #![feature(diagnostic_on_move)] +# +# use std::marker::PhantomData; +# +# #[diagnostic::on_move( +# message = "`{Self}` cannot be used multiple times", +# label = "this token may only be used once", +# note = "you can create a new `Token` with `Token::conjure()`" +# )] +# pub struct Token<'brand> { +# spooky: PhantomData<&'brand ()>, +# } +# +# impl Token<'_> { +# pub fn conjure<'u>() -> Token<'u> { +# Token { +# spooky: PhantomData, +# } +# } +# } +# fn main() { +let token = Token::conjure(); +let _ = (token, token); +# } +``` +This will result in the following error: +```text +error[E0382]: `Token` cannot be used multiple times + --> src/main.rs:24:21 + | + 1 | let token = Token::conjure(); + | ----- this token may only be used once + 2 | let _ = (token, token); + | ----- ^^^^^ value used here after move + | | + | value moved here + | + = note: you can create a new `Token` with `Token::conjure()` +``` + +[`File`]: https://doc.rust-lang.org/nightly/std/fs/struct.File.html "File in std::fs" +[#154181]: https://github.com/rust-lang/rust/issues/154181 "Tracking Issue for #[diagnostic::on_move]" diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 631a3b47b557..ec3407d361eb 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -516,7 +516,7 @@ fn human_readable_target_os(os: Symbol) -> Option<&'static str> { Managarm => "Managarm", Motor => "Motor OS", NetBsd => "NetBSD", - None => "bare-metal", // FIXME(scrabsha): is this appropriate? + None => "bare-metal", Nto => "QNX Neutrino", NuttX => "NuttX", OpenBsd => "OpenBSD", @@ -593,7 +593,7 @@ fn human_readable_target_env(env: Symbol) -> Option<&'static str> { // tidy-alphabetical-start Gnu => "GNU", MacAbi => "Catalyst", - Mlibc => "mac ABI", + Mlibc => "Managarm C Library", Msvc => "MSVC", Musl => "musl", Newlib => "Newlib", diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 2a00da4dd45c..18b00224dfcb 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -15,9 +15,7 @@ use crate::fold::DocFolder; use crate::formats::Impl; use crate::formats::item_type::ItemType; -use crate::html::markdown::short_markdown_summary; -use crate::html::render::IndexItem; -use crate::html::render::search_index::get_function_type_for_search; +use crate::html::render::{IndexItem, IndexItemInfo}; use crate::visit_lib::RustdocEffectiveVisibilities; /// This cache is used to store information about the [`clean::Crate`] being @@ -580,7 +578,6 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It debug_assert!(!item.is_stripped()); - let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); // For searching purposes, a re-export is a duplicate if: // // - It's either an inline, or a true re-export @@ -591,32 +588,24 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It _ => item_def_id, }; let (impl_id, trait_parent) = cache.parent_stack_last_impl_and_trait_id(); - let search_type = get_function_type_for_search( - item, + let info = IndexItemInfo::new( tcx, - clean_impl_generics(cache.parent_stack.last()).as_ref(), - parent_did, cache, + item, + parent_did, + clean_impl_generics(cache.parent_stack.last()).as_ref(), ); - let aliases = item.attrs.get_doc_aliases(); - let is_deprecated = item.is_deprecated(tcx); - let is_unstable = item.is_unstable(); let index_item = IndexItem { - ty: item.type_(), defid: Some(defid), name, module_path: parent_path.to_vec(), - desc, parent: parent_did, parent_idx: None, trait_parent, trait_parent_idx: None, exact_module_path: None, impl_id, - search_type, - aliases, - is_deprecated, - is_unstable, + info, }; cache.search_index.push(index_item); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index a36a3132640c..8600fccdbe62 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -66,7 +66,7 @@ pub(crate) use self::context::*; pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources}; pub(crate) use self::write_shared::*; -use crate::clean::{self, Defaultness, ItemId, RenderedLink}; +use crate::clean::{self, Defaultness, Item, ItemId, RenderedLink}; use crate::display::{Joined as _, MaybeDisplay as _}; use crate::error::Error; use crate::formats::Impl; @@ -79,8 +79,9 @@ print_type, print_where_clause, visibility_print_with_space, }; use crate::html::markdown::{ - HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, + HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, short_markdown_summary, }; +use crate::html::render::search_index::get_function_type_for_search; use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD; use crate::html::{highlight, sources}; use crate::scrape_examples::{CallData, CallLocation}; @@ -124,25 +125,48 @@ enum RenderMode { // Helper structs for rendering items/sidebars and carrying along contextual // information +#[derive(Debug)] +pub(crate) struct IndexItemInfo { + pub(crate) ty: ItemType, + pub(crate) desc: String, + pub(crate) search_type: Option, + pub(crate) aliases: Box<[Symbol]>, + pub(crate) deprecation: Option, + pub(crate) is_unstable: bool, +} + +impl IndexItemInfo { + pub(crate) fn new( + tcx: TyCtxt<'_>, + cache: &Cache, + item: &Item, + parent_did: Option, + impl_generics: Option<&(clean::Type, clean::Generics)>, + ) -> Self { + let ty = item.type_(); + let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); + let search_type = get_function_type_for_search(item, tcx, impl_generics, parent_did, cache); + let aliases = item.attrs.get_doc_aliases(); + let deprecation = item.deprecation(tcx); + let is_unstable = item.is_unstable(); + Self { ty, desc, search_type, aliases, deprecation, is_unstable } + } +} + /// Struct representing one entry in the JS search index. These are all emitted /// by hand to a large JS file at the end of cache-creation. #[derive(Debug)] pub(crate) struct IndexItem { - pub(crate) ty: ItemType, pub(crate) defid: Option, pub(crate) name: Symbol, pub(crate) module_path: Vec, - pub(crate) desc: String, pub(crate) parent: Option, pub(crate) parent_idx: Option, pub(crate) trait_parent: Option, pub(crate) trait_parent_idx: Option, pub(crate) exact_module_path: Option>, pub(crate) impl_id: Option, - pub(crate) search_type: Option, - pub(crate) aliases: Box<[Symbol]>, - pub(crate) is_deprecated: bool, - pub(crate) is_unstable: bool, + pub(crate) info: IndexItemInfo, } /// A type used for the search index. diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 935fe258c807..797b103ab9b8 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -13,7 +13,7 @@ use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::thin_vec::ThinVec; -use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::def_id::{CrateNum, DefIndex, LOCAL_CRATE}; use rustc_hir::find_attr; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; @@ -29,7 +29,9 @@ use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; use crate::html::markdown::short_markdown_summary; -use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId}; +use crate::html::render::{ + self, IndexItem, IndexItemFunctionType, IndexItemInfo, RenderType, RenderTypeId, +}; #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub(crate) struct SerializedSearchIndex { @@ -1270,29 +1272,18 @@ pub(crate) fn build_index( &cache.orphan_impl_items { if let Some((fqp, _)) = cache.paths.get(&parent) { - let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); + let info = IndexItemInfo::new(tcx, cache, item, Some(parent), impl_generics.as_ref()); search_index.push(IndexItem { - ty: item.type_(), defid: item.item_id.as_def_id(), name: item.name.unwrap(), module_path: fqp[..fqp.len() - 1].to_vec(), - desc, parent: Some(parent), parent_idx: None, trait_parent, trait_parent_idx: None, exact_module_path: None, impl_id, - search_type: get_function_type_for_search( - item, - tcx, - impl_generics.as_ref(), - Some(parent), - cache, - ), - aliases: item.attrs.get_doc_aliases(), - is_deprecated: item.is_deprecated(tcx), - is_unstable: item.is_unstable(), + info, }); } } @@ -1301,11 +1292,10 @@ pub(crate) fn build_index( search_index.sort_unstable_by(|k1, k2| { // `sort_unstable_by_key` produces lifetime errors // HACK(rustdoc): should not be sorting `CrateNum` or `DefIndex`, this will soon go away, too - let k1 = - (&k1.module_path, k1.name.as_str(), &k1.ty, k1.parent.map(|id| (id.index, id.krate))); - let k2 = - (&k2.module_path, k2.name.as_str(), &k2.ty, k2.parent.map(|id| (id.index, id.krate))); - Ord::cmp(&k1, &k2) + fn key(i: &IndexItem) -> (&[Symbol], &str, ItemType, Option<(DefIndex, CrateNum)>) { + (&i.module_path, i.name.as_str(), i.info.ty, i.parent.map(|id| (id.index, id.krate))) + } + Ord::cmp(&key(k1), &key(k2)) }); // Now, convert to an on-disk search index format @@ -1466,7 +1456,7 @@ pub(crate) fn build_index( if fqp.last() != Some(&item.name) { return None; } - let path = if item.ty == ItemType::Macro + let path = if item.info.ty == ItemType::Macro && find_attr!(tcx, defid, MacroExport { .. }) { // `#[macro_export]` always exports to the crate root. @@ -1501,8 +1491,9 @@ pub(crate) fn build_index( if item.impl_id.is_some() && let Some(parent_idx) = item.parent_idx { - let count = - associated_item_duplicates.entry((parent_idx, item.ty, item.name)).or_insert(0); + let count = associated_item_duplicates + .entry((parent_idx, item.info.ty, item.name)) + .or_insert(0); *count += 1; } } @@ -1525,24 +1516,27 @@ pub(crate) fn build_index( let new_entry_id = serialized_index.add_entry( item.name, EntryData { - ty: item.ty, + ty: item.info.ty, parent: item.parent_idx, trait_parent: item.trait_parent_idx, module_path, exact_module_path, - deprecated: item.is_deprecated, - unstable: item.is_unstable, + deprecated: item + .info + .deprecation + .is_some_and(|deprecation| deprecation.is_in_effect()), + unstable: item.info.is_unstable, associated_item_disambiguator_or_extern_crate_url: if let Some(impl_id) = item.impl_id && let Some(parent_idx) = item.parent_idx && associated_item_duplicates - .get(&(parent_idx, item.ty, item.name)) + .get(&(parent_idx, item.info.ty, item.name)) .copied() .unwrap_or(0) > 1 { Some(render::get_id_for_impl(tcx, ItemId::DefId(impl_id))) - } else if item.ty == ItemType::ExternCrate + } else if item.info.ty == ItemType::ExternCrate && let Some(local_def_id) = item.defid.and_then(|def_id| def_id.as_local()) && let cnum = tcx.extern_mod_stmt_cnum(local_def_id).unwrap_or(LOCAL_CRATE) && let Some(ExternalLocation::Remote { url, is_absolute }) = @@ -1555,12 +1549,12 @@ pub(crate) fn build_index( }, krate: crate_idx, }, - item.desc.to_string(), + item.info.desc.to_string(), ); // Aliases // ------- - for alias in &item.aliases[..] { + for alias in &item.info.aliases { serialized_index.push_alias(alias.as_str().to_string(), new_entry_id); } @@ -1833,7 +1827,7 @@ fn convert_render_type( _ => {} } } - if let Some(search_type) = &mut item.search_type { + if let Some(search_type) = &mut item.info.search_type { let mut used_in_function_inputs = BTreeSet::new(); let mut used_in_function_output = BTreeSet::new(); for item in &mut search_type.inputs { @@ -1900,7 +1894,7 @@ fn convert_render_type( // The number 8 is arbitrary. We want it big, but not enormous, // because the postings list has to fill in an empty array for each // unoccupied size. - if item.ty.is_fn_like() { 0 } else { 16 }; + if item.info.ty.is_fn_like() { 0 } else { 16 }; serialized_index.function_data[new_entry_id] = Some(search_type.clone()); #[derive(Clone, Copy)] diff --git a/tests/pretty/delegation-self-rename.pp b/tests/pretty/delegation-self-rename.pp new file mode 100644 index 000000000000..59a07315185c --- /dev/null +++ b/tests/pretty/delegation-self-rename.pp @@ -0,0 +1,55 @@ +#![attr = Feature([fn_delegation#0])] +extern crate std; +#[attr = PreludeImport] +use ::std::prelude::rust_2015::*; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:delegation-self-rename.pp + + +trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U, + impl FnOnce() -> usize>(&self, f: impl FnOnce() -> usize) -> usize + where impl FnOnce() -> usize: FnOnce() -> usize { f() + 1 } +} + +struct X; +impl <'a, A, const B: bool> Trait<'a, A, B> for X { } + +#[attr = Inline(Hint)] +fn foo<'a, Self, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(self: _, arg1: _) -> _ where + 'a:'a { self.foo::(arg1) } +#[attr = Inline(Hint)] +fn bar usize>(self: _, arg1: _) + -> _ { Trait::<'static, (), true>::foo::(self, arg1) } + +#[attr = Inline(Hint)] +fn foo2<'a, This, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where + 'a:'a { foo::(arg0, arg1) } +#[attr = Inline(Hint)] +fn bar2 usize>(arg0: _, arg1: _) + -> _ { bar::(arg0, arg1) } + +trait Trait2 { + #[attr = Inline(Hint)] + fn foo3<'a, This, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where + 'a:'a { foo2::(arg0, arg1) } + #[attr = Inline(Hint)] + fn bar3 usize>(arg0: _, arg1: _) + -> _ { bar2::(arg0, arg1) } +} + +impl Trait2 for () { } + +#[attr = Inline(Hint)] +fn foo4<'a, This, A, const B: _, const B2: _, T, U, + impl FnOnce() -> usize>(arg0: _, arg1: _) -> _ where + 'a:'a { <() as Trait2>::foo3::(arg0, arg1) } +#[attr = Inline(Hint)] +fn bar4 usize>(arg0: _, arg1: _) + -> _ { <() as Trait2>::bar3::(arg0, arg1) } + +fn main() { } diff --git a/tests/pretty/delegation-self-rename.rs b/tests/pretty/delegation-self-rename.rs new file mode 100644 index 000000000000..9054bb2b8957 --- /dev/null +++ b/tests/pretty/delegation-self-rename.rs @@ -0,0 +1,32 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:delegation-self-rename.pp + +#![feature(fn_delegation)] + +trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { + f() + 1 + } +} + +struct X; +impl<'a, A, const B: bool> Trait<'a, A, B> for X {} + +reuse Trait::foo; +reuse Trait::<'static, (), true>::foo:: as bar; + +reuse foo as foo2; +reuse bar as bar2; + +trait Trait2 { + reuse foo2 as foo3; + reuse bar2 as bar3; +} + +impl Trait2 for () {} + +reuse <() as Trait2>::foo3 as foo4; +reuse <() as Trait2>::bar3 as bar4; + +fn main() {} diff --git a/tests/rustdoc-html/doc-cfg/all-targets.rs b/tests/rustdoc-html/doc-cfg/all-targets.rs index 048d0d4c73d2..5b61d6164ee5 100644 --- a/tests/rustdoc-html/doc-cfg/all-targets.rs +++ b/tests/rustdoc-html/doc-cfg/all-targets.rs @@ -2,7 +2,7 @@ //@ has all_targets/fn.foo.html \ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ -// 'Available on GNU or Catalyst or mac ABI or MSVC or musl or Newlib or \ +// 'Available on GNU or Catalyst or Managarm C Library or MSVC or musl or Newlib or \ // Neutrino 7.0 or Neutrino 7.1 or Neutrino 7.1 with io-sock or Neutrino 8.0 or \ // OpenHarmony or relibc or SGX or Simulator or WASIp1 or WASIp2 or WASIp3 or \ // uClibc or V5 or target_env=fake_env only.' diff --git a/tests/ui/allocator/regression-abort-on-free-issue-150898.rs b/tests/ui/allocator/regression-abort-on-free-issue-150898.rs new file mode 100644 index 000000000000..41a7695bee77 --- /dev/null +++ b/tests/ui/allocator/regression-abort-on-free-issue-150898.rs @@ -0,0 +1,59 @@ +// Regression test for https://github.com/rust-lang/rust/issues/150898 +// +// This test fails on Apple platforms with versions containing an allocator +// bug. If this fails with SIGABRT, you may need to upgrade your system to +// avoid other unexpected behavior. +// +// Note that the failure is non-deterministic so this test may pass even in +// conditions where the bug is present. That being said, on the author's +// machine this has a 100% rate of hitting the crash on at least a couple +// threads. +// +// The bug was resolved by macOS 26.4. + +//@ run-pass +//@ only-aarch64-apple-darwin +//@ compile-flags: -C opt-level=1 -C codegen-units=1 + +use std::thread; + +fn main() { + // Running with multiple threads substantially increases the change of + // hitting the bug. + thread::scope(|s| { + for _ in 0..10 { + s.spawn(run); + } + }); +} + +fn run() { + // This doesn't always fail, so rerun a few times + for _ in 0..100 { + unsafe { + core::arch::asm!( + " + // Alloc 18 bytes + mov x0, #18 + bl _malloc + // Save the pointer to x21 + mov x21, x0 + // Alloc 18 bytes again + mov x0, #18 + bl _malloc + // Store the contents of `x13` to the second allocation. `x13` is the + // magic register to cause the crash, other registers work well. + str x13, [x0] + // Free the pointers + bl _free + mov x0, x21 + bl _free + ", + out("x0") _, + out("x13") _, + out("x21") _, + clobber_abi("C"), + ) + } + } +} diff --git a/tests/ui/delegation/generics/self-rename.rs b/tests/ui/delegation/generics/self-rename.rs new file mode 100644 index 000000000000..a4c92cecb5c6 --- /dev/null +++ b/tests/ui/delegation/generics/self-rename.rs @@ -0,0 +1,45 @@ +//@ run-pass + +#![feature(fn_delegation)] + +trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { + f() + 1 + } +} + +struct X; +impl<'a, A, const B: bool> Trait<'a, A, B> for X {} + +reuse Trait::foo; +reuse Trait::<'static, (), true>::foo:: as bar; + +reuse foo as foo2; +reuse bar as bar2; + +trait Trait2 { + reuse foo2 as foo3; + reuse bar2 as bar3; +} + +impl Trait2 for () {} + +reuse <() as Trait2>::foo3 as foo4; +reuse <() as Trait2>::bar3 as bar4; + +fn main() { + assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + assert_eq!(foo2::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + assert_eq!(<()>::foo3::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + assert_eq!(foo4::<'static, X, (), true, false, (), ()>(&X, || 123), 124); + + assert_eq!(bar::(&X, || 123), 124); + assert_eq!(bar2::(&X, || 123), 124); + assert_eq!(<()>::bar3::(&X, || 123), 124); + assert_eq!(bar4::(&X, || 123), 124); + + assert_eq!(bar(&X, || 123), 124); + assert_eq!(bar2(&X, || 123), 124); + assert_eq!(<()>::bar3(&X, || 123), 124); + assert_eq!(bar4::(&X, || 123), 124); +} diff --git a/tests/ui/delegation/generics/synth-params-ice-154780.rs b/tests/ui/delegation/generics/synth-params-ice-154780.rs index 3ea52818a8f0..ef8684698612 100644 --- a/tests/ui/delegation/generics/synth-params-ice-154780.rs +++ b/tests/ui/delegation/generics/synth-params-ice-154780.rs @@ -62,40 +62,49 @@ pub fn check() { } } -// FIXME(fn_delegation): rename Self generic param in recursive delegations -// mod test_4 { -// trait Trait<'a, A, const B: bool> { -// fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { -// f() -// } -// } +// Test recursive delegation through trait +mod test_4 { + trait Trait<'a, A, const B: bool> { + fn foo<'b, const B2: bool, T, U>(&self, f: impl FnOnce() -> usize) -> usize { + f() + } + } -// struct X; -// impl<'a, A, const B: bool> Trait<'a, A, B> for X {} + struct X; + impl<'a, A, const B: bool> Trait<'a, A, B> for X {} -// reuse Trait::foo; -// reuse Trait::<'static, (), true>::foo:: as bar; + reuse Trait::foo; + reuse Trait::<'static, (), true>::foo:: as bar; -// trait Trait2 { -// reuse foo; -// reuse bar; -// } + trait Trait2 { + reuse foo; + reuse bar; + } -// reuse Trait2::foo as foo2; -// reuse Trait2::foo::<'static, X, (), true, false, (), ()> as foo3; -// reuse Trait2::bar as bar2; -// reuse Trait2::bar:: as bar3; + impl Trait2 for () {} -// pub fn check() { -// assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 123); -// assert_eq!(bar::(&X, || 123), 123); -// assert_eq!(bar(&X, || 123), 123); -// } -// } + reuse <() as Trait2>::foo as foo2; + reuse <() as Trait2>::foo::<'static, X, (), true, false, (), ()> as foo3; + reuse <() as Trait2>::bar as bar2; + reuse <() as Trait2>::bar:: as bar3; + + pub fn check() { + assert_eq!(foo::<'static, X, (), true, false, (), ()>(&X, || 123), 123); + assert_eq!(bar::(&X, || 123), 123); + assert_eq!(bar(&X, || 123), 123); + + assert_eq!(foo2::<'static, X, (), true, false, (), ()>(&X, || 123), 123); + assert_eq!(bar2::(&X, || 123), 123); + assert_eq!(bar2(&X, || 123), 123); + + assert_eq!(foo3(&X, || 123), 123); + assert_eq!(bar3(&X, || 123), 123); + } +} fn main() { test_1::check(); test_2::check(); test_3::check(); - // test_4::check(); + test_4::check(); } diff --git a/tests/ui/diagnostic_namespace/on_move/std_impls.rs b/tests/ui/diagnostic_namespace/on_move/std_impls.rs new file mode 100644 index 000000000000..ea63d731a343 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/std_impls.rs @@ -0,0 +1,25 @@ +//@ dont-require-annotations: NOTE + +use std::fs::File; +use std::sync::Arc; +use std::rc::Rc; + +fn main(){ + let file = File::open("foo.txt").unwrap(); + (file, file); + //~^ ERROR use of moved value: `file` + //~| NOTE you can use `File::try_clone` to duplicate a `File` instance + + let arc = Arc::new(42); + //~^ NOTE this move could be avoided by cloning the original `Arc`, which is inexpensive + (arc, arc); + //~^ ERROR the type `Arc` does not implement `Copy` + //~| NOTE consider using `Arc::clone` + + + let rc = Rc::new(12); + //~^ NOTE this move could be avoided by cloning the original `Rc`, which is inexpensive + (rc, rc); + //~^ ERROR the type `Rc` does not implement `Copy` + //~| NOTE consider using `Rc::clone` +} diff --git a/tests/ui/diagnostic_namespace/on_move/std_impls.stderr b/tests/ui/diagnostic_namespace/on_move/std_impls.stderr new file mode 100644 index 000000000000..ba8869d9c73f --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_move/std_impls.stderr @@ -0,0 +1,49 @@ +error[E0382]: use of moved value: `file` + --> $DIR/std_impls.rs:9:12 + | +LL | let file = File::open("foo.txt").unwrap(); + | ---- move occurs because `file` has type `File`, which does not implement the `Copy` trait +LL | (file, file); + | ---- ^^^^ value used here after move + | | + | value moved here + | + = note: you can use `File::try_clone` to duplicate a `File` instance + +error[E0382]: the type `Arc` does not implement `Copy` + --> $DIR/std_impls.rs:15:11 + | +LL | let arc = Arc::new(42); + | --- this move could be avoided by cloning the original `Arc`, which is inexpensive +LL | +LL | (arc, arc); + | --- ^^^ value used here after move + | | + | value moved here + | + = note: consider using `Arc::clone` +help: clone the value to increment its reference count + | +LL | (arc.clone(), arc); + | ++++++++ + +error[E0382]: the type `Rc` does not implement `Copy` + --> $DIR/std_impls.rs:22:10 + | +LL | let rc = Rc::new(12); + | -- this move could be avoided by cloning the original `Rc`, which is inexpensive +LL | +LL | (rc, rc); + | -- ^^ value used here after move + | | + | value moved here + | + = note: consider using `Rc::clone` +help: clone the value to increment its reference count + | +LL | (rc.clone(), rc); + | ++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs new file mode 100644 index 000000000000..d8e2e7091d6e --- /dev/null +++ b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.rs @@ -0,0 +1,8 @@ +use std::borrow::Borrow; + +fn foo(_v: impl IntoIterator>) {} + +fn main() { + foo(&[String::from("a")]); + //~^ ERROR the trait bound `&String: Borrow` is not satisfied +} diff --git a/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr new file mode 100644 index 000000000000..8910ed892ec0 --- /dev/null +++ b/tests/ui/suggestions/dont-suggest-borrow-whole-call-issue-155088.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `&String: Borrow` is not satisfied + --> $DIR/dont-suggest-borrow-whole-call-issue-155088.rs:6:5 + | +LL | foo(&[String::from("a")]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Borrow` is not implemented for `&String` + | +note: required by a bound in `foo` + --> $DIR/dont-suggest-borrow-whole-call-issue-155088.rs:3:42 + | +LL | fn foo(_v: impl IntoIterator>) {} + | ^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.