diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 7325bce605592..41295f2b7b661 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1339,13 +1339,19 @@ impl<'hir> LoweringContext<'_, 'hir> { .map(|predicate| self.lower_where_predicate(predicate)), ); - let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = - self.lower_generic_params_mut(&generics.params).collect(); + let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self + .lower_generic_params_mut(&generics.params, hir::GenericParamSource::Generics) + .collect(); // Introduce extra lifetimes if late resolution tells us to. let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id); params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { - self.lifetime_res_to_generic_param(ident, node_id, res) + self.lifetime_res_to_generic_param( + ident, + node_id, + res, + hir::GenericParamSource::Generics, + ) })); let has_where_clause_predicates = !generics.where_clause.predicates.is_empty(); @@ -1449,7 +1455,8 @@ impl<'hir> LoweringContext<'_, 'hir> { span, }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { hir_id: self.next_id(), - bound_generic_params: self.lower_generic_params(bound_generic_params), + bound_generic_params: self + .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder), bounded_ty: self .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5d78d914b6d7f..5352a56b16588 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -804,6 +804,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ident: Ident, node_id: NodeId, res: LifetimeRes, + source: hir::GenericParamSource, ) -> Option> { let (name, kind) = match res { LifetimeRes::Param { .. } => { @@ -837,6 +838,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: false, kind: hir::GenericParamKind::Lifetime { kind }, colon_span: None, + source, }) } @@ -852,11 +854,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { binder: NodeId, generic_params: &[GenericParam], ) -> &'hir [hir::GenericParam<'hir>] { - let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect(); + let mut generic_params: Vec<_> = self + .lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder) + .collect(); let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder); debug!(?extra_lifetimes); generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { - self.lifetime_res_to_generic_param(ident, node_id, res) + self.lifetime_res_to_generic_param(ident, node_id, res, hir::GenericParamSource::Binder) })); let generic_params = self.arena.alloc_from_iter(generic_params); debug!(?generic_params); @@ -1375,8 +1379,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span, ); let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); - let (param, bounds, path) = - self.lower_generic_and_bounds(*def_node_id, span, ident, bounds); + let (param, bounds, path) = self.lower_universal_param_and_bounds( + *def_node_id, + span, + ident, + bounds, + ); self.impl_trait_defs.push(param); if let Some(bounds) = bounds { self.impl_trait_bounds.push(bounds); @@ -1530,6 +1538,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: false, kind: hir::GenericParamKind::Lifetime { kind }, colon_span: None, + source: hir::GenericParamSource::Generics, } }, )); @@ -1987,6 +1996,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: false, kind: hir::GenericParamKind::Lifetime { kind }, colon_span: None, + source: hir::GenericParamSource::Generics, } }, )); @@ -2152,16 +2162,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_generic_params_mut<'s>( &'s mut self, params: &'s [GenericParam], + source: hir::GenericParamSource, ) -> impl Iterator> + Captures<'a> + Captures<'s> { - params.iter().map(move |param| self.lower_generic_param(param)) + params.iter().map(move |param| self.lower_generic_param(param, source)) } - fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::GenericParam<'hir>] { - self.arena.alloc_from_iter(self.lower_generic_params_mut(params)) + fn lower_generic_params( + &mut self, + params: &[GenericParam], + source: hir::GenericParamSource, + ) -> &'hir [hir::GenericParam<'hir>] { + self.arena.alloc_from_iter(self.lower_generic_params_mut(params, source)) } #[instrument(level = "trace", skip(self))] - fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> { + fn lower_generic_param( + &mut self, + param: &GenericParam, + source: hir::GenericParamSource, + ) -> hir::GenericParam<'hir> { let (name, kind) = self.lower_generic_param_kind(param); let hir_id = self.lower_node_id(param.id); @@ -2174,6 +2193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: self.tcx.sess.contains_name(¶m.attrs, sym::may_dangle), kind, colon_span: param.colon_span.map(|s| self.lower_span(s)), + source, } } @@ -2266,7 +2286,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self), ret)] - fn lower_generic_and_bounds( + fn lower_universal_param_and_bounds( &mut self, node_id: NodeId, span: Span, @@ -2286,6 +2306,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span, kind: hir::GenericParamKind::Type { default: None, synthetic: true }, colon_span: None, + source: hir::GenericParamSource::Generics, }; let preds = self.lower_generic_bound_predicate( diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 300348d78ed9c..adc06d9aa108a 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -316,8 +316,6 @@ declare_features! ( (active, c_unwind, "1.52.0", Some(74990), None), /// Allows using C-variadics. (active, c_variadic, "1.34.0", Some(44930), None), - /// Allows capturing disjoint fields in a closure/generator (RFC 2229). - (incomplete, capture_disjoint_fields, "1.49.0", Some(53488), None), /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (active, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows `cfg(target_abi = "...")`. diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 79a12801de29d..04d4f6cb14e4c 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -52,6 +52,8 @@ declare_features! ( (removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")), (removed, await_macro, "1.38.0", Some(50547), None, Some("subsumed by `.await` syntax")), + /// Allows capturing disjoint fields in a closure/generator (RFC 2229). + (removed, capture_disjoint_fields, "1.49.0", Some(53488), None, Some("stabilized in Rust 2021")), /// Allows comparing raw pointers during const eval. (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None, Some("cannot be allowed in const eval in any meaningful way")), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 72e9f7c13437e..19d3d41c9841c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -498,6 +498,7 @@ pub struct GenericParam<'hir> { pub pure_wrt_drop: bool, pub kind: GenericParamKind<'hir>, pub colon_span: Option, + pub source: GenericParamSource, } impl<'hir> GenericParam<'hir> { @@ -516,6 +517,20 @@ impl<'hir> GenericParam<'hir> { } } +/// Records where the generic parameter originated from. +/// +/// This can either be from an item's generics, in which case it's typically +/// early-bound (but can be a late-bound lifetime in functions, for example), +/// or from a `for<...>` binder, in which case it's late-bound (and notably, +/// does not show up in the parent item's generics). +#[derive(Debug, HashStable_Generic, PartialEq, Eq, Copy, Clone)] +pub enum GenericParamSource { + // Early or late-bound parameters defined on an item + Generics, + // Late-bound parameters defined via a `for<...>` + Binder, +} + #[derive(Default)] pub struct GenericParamCount { pub lifetimes: usize, diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index a15cf454df72f..25c467bfd2bd6 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -50,6 +50,7 @@ use rustc_trait_selection::traits::{self, astconv_object_safety_violations, Obli use smallvec::{smallvec, SmallVec}; use std::collections::BTreeSet; +use std::fmt::Display; use std::slice; #[derive(Debug)] @@ -1095,11 +1096,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // those that do. self.one_bound_for_assoc_type( || traits::supertraits(tcx, trait_ref), - || trait_ref.print_only_trait_path().to_string(), + trait_ref.print_only_trait_path(), binding.item_name, path_span, - || match binding.kind { - ConvertedBindingKind::Equality(ty) => Some(ty.to_string()), + match binding.kind { + ConvertedBindingKind::Equality(term) => Some(term), _ => None, }, )? @@ -1789,10 +1790,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_name, ) }, - || param_name.to_string(), + param_name, assoc_name, span, - || None, + None, ) } @@ -1802,10 +1803,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn one_bound_for_assoc_type( &self, all_candidates: impl Fn() -> I, - ty_param_name: impl Fn() -> String, + ty_param_name: impl Display, assoc_name: Ident, span: Span, - is_equality: impl Fn() -> Option, + is_equality: Option>, ) -> Result, ErrorGuaranteed> where I: Iterator>, @@ -1821,7 +1822,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (None, None) => { let reported = self.complain_about_assoc_type_not_found( all_candidates, - &ty_param_name(), + &ty_param_name.to_string(), assoc_name, span, ); @@ -1833,7 +1834,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let Some(bound2) = next_cand { debug!(?bound2); - let is_equality = is_equality(); let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates); let mut err = if is_equality.is_some() { // More specific Error Index entry. @@ -1843,7 +1843,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { E0222, "ambiguous associated type `{}` in bounds of `{}`", assoc_name, - ty_param_name() + ty_param_name ) } else { struct_span_err!( @@ -1852,7 +1852,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { E0221, "ambiguous associated type `{}` in bounds of `{}`", assoc_name, - ty_param_name() + ty_param_name ) }; err.span_label(span, format!("ambiguous associated type `{}`", assoc_name)); @@ -1886,18 +1886,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_suggestion_verbose( span.with_hi(assoc_name.span.lo()), "use fully qualified syntax to disambiguate", - format!( - "<{} as {}>::", - ty_param_name(), - bound.print_only_trait_path(), - ), + format!("<{} as {}>::", ty_param_name, bound.print_only_trait_path()), Applicability::MaybeIncorrect, ); } } else { err.note(&format!( "associated type `{}` could derive from `{}`", - ty_param_name(), + ty_param_name, bound.print_only_trait_path(), )); } @@ -1906,7 +1902,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.help(&format!( "consider introducing a new type parameter `T` and adding `where` constraints:\ \n where\n T: {},\n{}", - ty_param_name(), + ty_param_name, where_bounds.join(",\n"), )); } @@ -2070,10 +2066,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.one_bound_for_assoc_type( || traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())), - || "Self".to_string(), + kw::SelfUpper, assoc_ident, span, - || None, + None, )? } ( diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4ea471f8f0553..848828175e2d8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -792,8 +792,10 @@ fn check_impl_items_against_trait<'tcx>( trait_def.must_implement_one_of.as_deref(); for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) { - let is_implemented = ancestors - .leaf_def(tcx, trait_item_id) + let leaf_def = ancestors.leaf_def(tcx, trait_item_id); + + let is_implemented = leaf_def + .as_ref() .map_or(false, |node_item| node_item.item.defaultness(tcx).has_value()); if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { @@ -801,8 +803,8 @@ fn check_impl_items_against_trait<'tcx>( } // true if this item is specifically implemented in this impl - let is_implemented_here = ancestors - .leaf_def(tcx, trait_item_id) + let is_implemented_here = leaf_def + .as_ref() .map_or(false, |node_item| !node_item.defining_node.is_from_trait()); if !is_implemented_here { @@ -831,6 +833,36 @@ fn check_impl_items_against_trait<'tcx>( } } } + + if let Some(leaf_def) = &leaf_def + && !leaf_def.is_final() + && let def_id = leaf_def.item.def_id + && tcx.impl_method_has_trait_impl_trait_tys(def_id) + { + let def_kind = tcx.def_kind(def_id); + let descr = tcx.def_kind_descr(def_kind, def_id); + let (msg, feature) = if tcx.asyncness(def_id).is_async() { + ( + format!("async {descr} in trait cannot be specialized"), + sym::async_fn_in_trait, + ) + } else { + ( + format!( + "{descr} with return-position `impl Trait` in trait cannot be specialized" + ), + sym::return_position_impl_trait_in_trait, + ) + }; + tcx.sess + .struct_span_err(tcx.def_span(def_id), msg) + .note(format!( + "specialization behaves in inconsistent and \ + surprising ways with `#![feature({feature})]`, \ + and for now is disallowed" + )) + .emit(); + } } if !missing_items.is_empty() { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 6c00b8ff7bdee..b14e65183aa3d 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1034,45 +1034,53 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault { debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam); let param_def_id = param_def_id.expect_local(); - let parent_def_id = tcx.local_parent(param_def_id); - let generics = tcx.hir().get_generics(parent_def_id).unwrap(); - let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id); - let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap(); - - // Scan the bounds and where-clauses on parameters to extract bounds - // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` - // for each type parameter. - match param.kind { - GenericParamKind::Type { .. } => { - let mut set = Set1::Empty; - - // Look for `type: ...` where clauses. - for bound in generics.bounds_for_param(param_def_id) { - // Ignore `for<'a> type: ...` as they can change what - // lifetimes mean (although we could "just" handle it). - if !bound.bound_generic_params.is_empty() { - continue; - } + let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(param_def_id) else { + bug!("expected GenericParam for object_lifetime_default"); + }; + match param.source { + hir::GenericParamSource::Generics => { + let parent_def_id = tcx.local_parent(param_def_id); + let generics = tcx.hir().get_generics(parent_def_id).unwrap(); + let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id); + let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap(); + + // Scan the bounds and where-clauses on parameters to extract bounds + // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` + // for each type parameter. + match param.kind { + GenericParamKind::Type { .. } => { + let mut set = Set1::Empty; + + // Look for `type: ...` where clauses. + for bound in generics.bounds_for_param(param_def_id) { + // Ignore `for<'a> type: ...` as they can change what + // lifetimes mean (although we could "just" handle it). + if !bound.bound_generic_params.is_empty() { + continue; + } - for bound in bound.bounds { - if let hir::GenericBound::Outlives(lifetime) = bound { - set.insert(lifetime.res); + for bound in bound.bounds { + if let hir::GenericBound::Outlives(lifetime) = bound { + set.insert(lifetime.res); + } + } } - } - } - match set { - Set1::Empty => ObjectLifetimeDefault::Empty, - Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, - Set1::One(hir::LifetimeName::Param(param_def_id)) => { - ObjectLifetimeDefault::Param(param_def_id.to_def_id()) + match set { + Set1::Empty => ObjectLifetimeDefault::Empty, + Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, + Set1::One(hir::LifetimeName::Param(param_def_id)) => { + ObjectLifetimeDefault::Param(param_def_id.to_def_id()) + } + _ => ObjectLifetimeDefault::Ambiguous, + } + } + _ => { + bug!("object_lifetime_default_raw must only be called on a type parameter") } - _ => ObjectLifetimeDefault::Ambiguous, } } - _ => { - bug!("object_lifetime_default_raw must only be called on a type parameter") - } + hir::GenericParamSource::Binder => ObjectLifetimeDefault::Empty, } } @@ -1392,9 +1400,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { return; } - self.tcx - .sess - .delay_span_bug(self.tcx.hir().span(hir_id), "could not resolve {param_def_id:?}"); + self.tcx.sess.delay_span_bug( + self.tcx.hir().span(hir_id), + format!("could not resolve {param_def_id:?}"), + ); } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 3e27a78135e49..e8bc50440e234 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We now fake capture information for all variables that are mentioned within the closure // We do this after handling migrations so that min_captures computes before - if !enable_precise_capture(self.tcx, span) { + if !enable_precise_capture(span) { let mut capture_information: InferredCaptureInformation<'tcx> = Default::default(); if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { @@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If we have an origin, store it. if let Some(origin) = origin { - let origin = if enable_precise_capture(self.tcx, span) { + let origin = if enable_precise_capture(span) { (origin.0, origin.1) } else { (origin.0, Place { projections: vec![], ..origin.1 }) @@ -1243,8 +1243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// This will make more sense with an example: /// - /// ```rust - /// #![feature(capture_disjoint_fields)] + /// ```rust,edition2021 /// /// struct FancyInteger(i32); // This implements Drop /// @@ -2250,12 +2249,10 @@ fn truncate_capture_for_optimization( (place, curr_mode) } -/// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if -/// user is using Rust Edition 2021 or higher. -/// +/// Precise capture is enabled if user is using Rust Edition 2021 or higher. /// `span` is the span of the closure. -fn enable_precise_capture(tcx: TyCtxt<'_>, span: Span) -> bool { +fn enable_precise_capture(span: Span) -> bool { // We use span here to ensure that if the closure was generated by a macro with a different // edition. - tcx.features().capture_disjoint_fields || span.rust_2021() + span.rust_2021() } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f0dafe73c004e..27490a09a3646 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1101,34 +1101,6 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } -fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if tcx.def_kind(def_id) != DefKind::AssocFn { - return false; - } - - let Some(item) = tcx.opt_associated_item(def_id) else { return false; }; - if item.container != ty::AssocItemContainer::ImplContainer { - return false; - } - - let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; - - // FIXME(RPITIT): This does a somewhat manual walk through the signature - // of the trait fn to look for any RPITITs, but that's kinda doing a lot - // of work. We can probably remove this when we refactor RPITITs to be - // associated types. - tcx.fn_sig(trait_item_def_id).subst_identity().skip_binder().output().walk().any(|arg| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Projection, data) = ty.kind() - && tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder - { - true - } else { - false - } - }) -} - // Return `false` to avoid encoding impl trait in trait, while we don't use the query. fn should_encode_fn_impl_trait_in_trait<'tcx>(_tcx: TyCtxt<'tcx>, _def_id: DefId) -> bool { false @@ -1211,7 +1183,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(def_id); } - if should_encode_trait_impl_trait_tys(tcx, def_id) + if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { record!(self.tables.trait_impl_trait_tys[def_id] <- table); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0333198c20310..469d943672777 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -794,8 +794,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn consider_optimizing String>(self, msg: T) -> bool { - let cname = self.crate_name(LOCAL_CRATE); - self.sess.consider_optimizing(cname.as_str(), msg) + self.sess.consider_optimizing(|| self.crate_name(LOCAL_CRATE), msg) } /// Obtain all lang items of this crate and all dependencies (recursively) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index fc5757564a74b..5084bc9cec6c6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2541,6 +2541,34 @@ impl<'tcx> TyCtxt<'tcx> { } def_id } + + pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { + if self.def_kind(def_id) != DefKind::AssocFn { + return false; + } + + let Some(item) = self.opt_associated_item(def_id) else { return false; }; + if item.container != ty::AssocItemContainer::ImplContainer { + return false; + } + + let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; + + // FIXME(RPITIT): This does a somewhat manual walk through the signature + // of the trait fn to look for any RPITITs, but that's kinda doing a lot + // of work. We can probably remove this when we refactor RPITITs to be + // associated types. + self.fn_sig(trait_item_def_id).subst_identity().skip_binder().output().walk().any(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Alias(ty::Projection, data) = ty.kind() + && self.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder + { + true + } else { + false + } + }) + } } /// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition. diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index eb20b2308c0bd..33200b80a572d 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::AdtDef; -use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, Variance}; use rustc_span::Span; use rustc_target::abi::VariantIdx; @@ -183,7 +183,7 @@ fn to_upvars_resolved_place_builder<'tcx>( &projection, ) else { let closure_span = cx.tcx.def_span(closure_def_id); - if !enable_precise_capture(cx.tcx, closure_span) { + if !enable_precise_capture(closure_span) { bug!( "No associated capture found for {:?}[{:#?}] even though \ capture_disjoint_fields isn't enabled", @@ -745,8 +745,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } -/// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if -/// user is using Rust Edition 2021 or higher. -fn enable_precise_capture(tcx: TyCtxt<'_>, closure_span: Span) -> bool { - tcx.features().capture_disjoint_fields || closure_span.rust_2021() +/// Precise capture is enabled if user is using Rust Edition 2021 or higher. +fn enable_precise_capture(closure_span: Span) -> bool { + closure_span.rust_2021() } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 446ba63ed1c86..12634f67185fd 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -882,10 +882,14 @@ impl Session { /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. - pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { + pub fn consider_optimizing( + &self, + get_crate_name: impl Fn() -> Symbol, + msg: impl Fn() -> String, + ) -> bool { let mut ret = true; if let Some((ref c, _)) = self.opts.unstable_opts.fuel { - if c == crate_name { + if c == get_crate_name().as_str() { assert_eq!(self.threads(), 1); let mut fuel = self.optimization_fuel.lock(); ret = fuel.remaining != 0; @@ -903,7 +907,7 @@ impl Session { } } if let Some(ref c) = self.opts.unstable_opts.print_fuel { - if c == crate_name { + if c == get_crate_name().as_str() { assert_eq!(self.threads(), 1); self.print_fuel.fetch_add(1, SeqCst); } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index d542240be9b24..013db2edb398d 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1307,25 +1307,8 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( let _ = selcx.infcx.commit_if_ok(|_| { match selcx.select(&obligation.with(tcx, trait_predicate)) { Ok(Some(super::ImplSource::UserDefined(data))) => { - let Ok(leaf_def) = specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) else { - return Err(()); - }; - // Only reveal a specializable default if we're past type-checking - // and the obligation is monomorphic, otherwise passes such as - // transmute checking and polymorphic MIR optimizations could - // get a result which isn't correct for all monomorphizations. - if leaf_def.is_final() - || (obligation.param_env.reveal() == Reveal::All - && !selcx - .infcx - .resolve_vars_if_possible(obligation.predicate.trait_ref(tcx)) - .still_further_specializable()) - { - candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data)); - Ok(()) - } else { - Err(()) - } + candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data)); + Ok(()) } Ok(None) => { candidate_set.mark_ambiguous(); @@ -2216,7 +2199,8 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( Ok(assoc_ty) => assoc_ty, Err(guar) => return Progress::error(tcx, guar), }; - if !leaf_def.item.defaultness(tcx).has_value() { + // We don't support specialization for RPITITs anyways... yet. + if !leaf_def.is_final() { return Progress { term: tcx.ty_error_misc().into(), obligations }; } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 3947a64e5c6ff..ccb7be68eb1b2 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -67,6 +67,7 @@ #![feature(slice_internals)] #![feature(slice_partition_dedup)] #![feature(ip)] +#![feature(ip_in_core)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] #![feature(iter_collect_into)] diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 3fc6cc44ce4c8..edd77c824ad7c 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -54,6 +54,20 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result; + /// Like `read_at`, except that it reads into a slice of buffers. + /// + /// Data is copied to fill each buffer in order, with the final buffer + /// written to possibly being only partially filled. This method must behave + /// equivalently to a single call to read with concatenated buffers. + #[unstable(feature = "unix_file_vectored_at", issue = "89517")] + fn read_vectored_at( + &mut self, + bufs: &mut [io::IoSliceMut<'_>], + offset: u64, + ) -> io::Result { + io::default_read_vectored(|b| self.read_at(b, offset), bufs) + } + /// Reads the exact number of byte required to fill `buf` from the given offset. /// /// The offset is relative to the start of the file and thus independent @@ -155,6 +169,16 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn write_at(&self, buf: &[u8], offset: u64) -> io::Result; + /// Like `write_at`, except that it writes from a slice of buffers. + /// + /// Data is copied from each buffer in order, with the final buffer read + /// from possibly being only partially consumed. This method must behave as + /// a call to `write_at` with the buffers concatenated would. + #[unstable(feature = "unix_file_vectored_at", issue = "89517")] + fn write_vectored_at(&mut self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result { + io::default_write_vectored(|b| self.write_at(b, offset), bufs) + } + /// Attempts to write an entire buffer starting from a given offset. /// /// The offset is relative to the start of the file and thus independent @@ -218,9 +242,19 @@ impl FileExt for fs::File { fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { self.as_inner().read_at(buf, offset) } + fn read_vectored_at( + &mut self, + bufs: &mut [io::IoSliceMut<'_>], + offset: u64, + ) -> io::Result { + self.as_inner().read_vectored_at(bufs, offset) + } fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { self.as_inner().write_at(buf, offset) } + fn write_vectored_at(&mut self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result { + self.as_inner().write_vectored_at(bufs, offset) + } } /// Unix-specific extensions to [`fs::Permissions`]. diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 66c33d58d6ca3..3213f4bf2a0c6 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -92,7 +92,7 @@ impl FileDesc { let ret = cvt(unsafe { libc::readv( self.as_raw_fd(), - bufs.as_ptr() as *const libc::iovec, + bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, cmp::min(bufs.len(), max_iov()) as libc::c_int, ) })?; @@ -101,7 +101,7 @@ impl FileDesc { #[cfg(any(target_os = "espidf", target_os = "horizon"))] pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - return crate::io::default_read_vectored(|b| self.read(b), bufs); + io::default_read_vectored(|b| self.read(b), bufs) } #[inline] @@ -147,6 +147,44 @@ impl FileDesc { Ok(()) } + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { + let ret = cvt(unsafe { + libc::preadv( + self.as_raw_fd(), + bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, + cmp::min(bufs.len(), max_iov()) as libc::c_int, + offset as _, + ) + })?; + Ok(ret as usize) + } + + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + )))] + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { + io::default_read_vectored(|b| self.read_at(b, offset), bufs) + } + pub fn write(&self, buf: &[u8]) -> io::Result { let ret = cvt(unsafe { libc::write( @@ -172,7 +210,7 @@ impl FileDesc { #[cfg(any(target_os = "espidf", target_os = "horizon"))] pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - return crate::io::default_write_vectored(|b| self.write(b), bufs); + io::default_write_vectored(|b| self.write(b), bufs) } #[inline] @@ -197,6 +235,44 @@ impl FileDesc { } } + #[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + ))] + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { + let ret = cvt(unsafe { + libc::pwritev( + self.as_raw_fd(), + bufs.as_ptr() as *const libc::iovec, + cmp::min(bufs.len(), max_iov()) as libc::c_int, + offset as _, + ) + })?; + Ok(ret as usize) + } + + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + )))] + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { + io::default_write_vectored(|b| self.write_at(b, offset), bufs) + } + #[cfg(not(any( target_env = "newlib", target_os = "solaris", diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 8e1f35d6cc920..ec674801a8ff8 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1098,6 +1098,10 @@ impl File { self.0.read_buf(cursor) } + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { + self.0.read_vectored_at(bufs, offset) + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } @@ -1115,6 +1119,10 @@ impl File { self.0.write_at(buf, offset) } + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { + self.0.write_vectored_at(bufs, offset) + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } diff --git a/tests/debuginfo/captured-fields-1.rs b/tests/debuginfo/captured-fields-1.rs index afbf942d40471..b71734c2354df 100644 --- a/tests/debuginfo/captured-fields-1.rs +++ b/tests/debuginfo/captured-fields-1.rs @@ -1,5 +1,5 @@ // compile-flags:-g - +// edition:2021 // === GDB TESTS =================================================================================== // gdb-command:run @@ -44,7 +44,6 @@ // lldbg-check:(captured_fields_1::main::{closure_env#5}) $5 = { my_var = { my_field1 = 11 my_field2 = 22 } } // lldb-command:continue -#![feature(capture_disjoint_fields)] #![allow(unused)] struct MyStruct { diff --git a/tests/debuginfo/captured-fields-2.rs b/tests/debuginfo/captured-fields-2.rs index c872354a92489..8d463fb245162 100644 --- a/tests/debuginfo/captured-fields-2.rs +++ b/tests/debuginfo/captured-fields-2.rs @@ -1,5 +1,5 @@ // compile-flags:-g - +// edition:2021 // === GDB TESTS =================================================================================== // gdb-command:run @@ -20,7 +20,6 @@ // lldbg-check:(unsigned int) $1 = 22 // lldb-command:continue -#![feature(capture_disjoint_fields)] #![allow(unused)] struct MyStruct { @@ -29,10 +28,7 @@ struct MyStruct { } fn main() { - let mut my_var = MyStruct { - my_field1: 11, - my_field2: 22, - }; + let mut my_var = MyStruct { my_field1: 11, my_field2: 22 }; let my_ref = &mut my_var; let test = || { diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr index 371122ea71ec0..f71fd9980a261 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr @@ -7,20 +7,13 @@ LL | #![feature(async_fn_in_trait)] = note: see issue #91611 for more information = note: `#[warn(incomplete_features)]` on by default -error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/dont-project-to-specializable-projection.rs:14:35 +error: async associated function in trait cannot be specialized + --> $DIR/dont-project-to-specializable-projection.rs:14:5 | LL | default async fn foo(_: T) -> &'static str { - | ^^^^^^^^^^^^ expected associated type, found future + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: type in trait - --> $DIR/dont-project-to-specializable-projection.rs:10:27 - | -LL | async fn foo(_: T) -> &'static str; - | ^^^^^^^^^^^^ - = note: expected signature `fn(_) -> impl Future` - found signature `fn(_) -> impl Future` + = note: specialization behaves in inconsistent and surprising ways with `#![feature(async_fn_in_trait)]`, and for now is disallowed error: aborting due to previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/closures/2229_closure_analysis/issue_88118.rs b/tests/ui/closures/2229_closure_analysis/issue_88118.rs index 453b7e04a369b..bfb487649a3ce 100644 --- a/tests/ui/closures/2229_closure_analysis/issue_88118.rs +++ b/tests/ui/closures/2229_closure_analysis/issue_88118.rs @@ -1,10 +1,7 @@ // Regression test for #88118. Used to ICE. -// +// edition:2021 // check-pass -#![allow(incomplete_features)] -#![feature(capture_disjoint_fields)] - fn foo(handler: impl FnOnce() -> MsU + Clone + 'static) { Box::new(move |value| { (|_| handler.clone()())(value); diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.rs b/tests/ui/impl-trait/in-trait/specialization-broken.rs index 9d27d3710a601..2fcffdf3f9a29 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.rs +++ b/tests/ui/impl-trait/in-trait/specialization-broken.rs @@ -15,6 +15,7 @@ where { fn bar(&self) -> U { //~^ ERROR method `bar` has an incompatible type for trait + //~| ERROR method with return-position `impl Trait` in trait cannot be specialized *self } } diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.stderr index 37cfd74498d81..dc621d6b8a848 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.stderr +++ b/tests/ui/impl-trait/in-trait/specialization-broken.stderr @@ -18,6 +18,14 @@ LL | fn bar(&self) -> impl Sized; = note: expected signature `fn(&U) -> impl Sized` found signature `fn(&U) -> U` -error: aborting due to previous error +error: method with return-position `impl Trait` in trait cannot be specialized + --> $DIR/specialization-broken.rs:16:5 + | +LL | fn bar(&self) -> U { + | ^^^^^^^^^^^^^^^^^^ + | + = note: specialization behaves in inconsistent and surprising ways with `#![feature(return_position_impl_trait_in_trait)]`, and for now is disallowed + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.rs b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.rs new file mode 100644 index 0000000000000..9830241c3770c --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.rs @@ -0,0 +1,7 @@ +// check-pass +// compile-flags: --crate-type=lib + +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +pub fn f() where for (T, U): Copy {} diff --git a/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.stderr b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.stderr new file mode 100644 index 0000000000000..667575b72d4cb --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.stderr @@ -0,0 +1,11 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/object-lifetime-default-for-late.rs:4:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted +