diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index d2f8ef8eaae7d..46dbbd83d1905 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -16,6 +16,7 @@ #![feature(maybe_uninit_slice)] #![feature(min_specialization)] #![feature(decl_macro)] +#![feature(pointer_byte_offsets)] #![feature(rustc_attrs)] #![cfg_attr(test, feature(test))] #![feature(strict_provenance)] @@ -211,7 +212,7 @@ impl TypedArena { unsafe { if mem::size_of::() == 0 { - self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T); + self.ptr.set(self.ptr.get().wrapping_byte_add(1)); let ptr = ptr::NonNull::::dangling().as_ptr(); // Don't drop the object. This `write` is equivalent to `forget`. ptr::write(ptr, object); diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 2816f81fef121..2100487107517 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -541,7 +541,7 @@ impl<'a, 'b> Context<'a, 'b> { ) { match c { parse::CountImplied | parse::CountIs(..) => {} - parse::CountIsParam(i) => { + parse::CountIsParam(i) | parse::CountIsStar(i) => { self.unused_names_lint.maybe_add_positional_named_arg( self.args.get(i), named_arg_type, @@ -589,7 +589,7 @@ impl<'a, 'b> Context<'a, 'b> { + self .arg_with_formatting .iter() - .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_))) + .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_))) .count(); if self.names.is_empty() && !numbered_position_args && count != self.num_args() { e = self.ecx.struct_span_err( @@ -639,7 +639,7 @@ impl<'a, 'b> Context<'a, 'b> { if let Some(span) = fmt.precision_span { let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end)); match fmt.precision { - parse::CountIsParam(pos) if pos > self.num_args() => { + parse::CountIsParam(pos) if pos >= self.num_args() => { e.span_label( span, &format!( @@ -651,12 +651,12 @@ impl<'a, 'b> Context<'a, 'b> { ); zero_based_note = true; } - parse::CountIsParam(pos) => { + parse::CountIsStar(pos) => { let count = self.pieces.len() + self .arg_with_formatting .iter() - .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_))) + .filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_))) .count(); e.span_label( span, @@ -837,7 +837,7 @@ impl<'a, 'b> Context<'a, 'b> { }; match c { parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))), - parse::CountIsParam(i) => { + parse::CountIsParam(i) | parse::CountIsStar(i) => { // This needs mapping too, as `i` is referring to a macro // argument. If `i` is not found in `count_positions` then // the error had already been emitted elsewhere. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 2da9123b84610..d37eaeed095a1 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -187,9 +187,6 @@ pub enum LocalValue { impl<'tcx, Prov: Provenance + 'static> LocalState<'tcx, Prov> { /// Read the local's value or error if the local is not yet live or not live anymore. - /// - /// Note: This may only be invoked from the `Machine::access_local` hook and not from - /// anywhere else. You may be invalidating machine invariants if you do! #[inline] pub fn access(&self) -> InterpResult<'tcx, &Operand> { match &self.value { diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 6bed8a7a00773..b151d03681f43 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -215,23 +215,12 @@ pub trait Machine<'mir, 'tcx>: Sized { right: &ImmTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; - /// Called to read the specified `local` from the `frame`. - /// Since reading a ZST is not actually accessing memory or locals, this is never invoked - /// for ZST reads. - #[inline] - fn access_local<'a>( - frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, - local: mir::Local, - ) -> InterpResult<'tcx, &'a Operand> - where - 'tcx: 'mir, - { - frame.locals[local].access() - } - /// Called to write the specified `local` from the `frame`. /// Since writing a ZST is not actually accessing memory or locals, this is never invoked /// for ZST reads. + /// + /// Due to borrow checker trouble, we indicate the `frame` as an index rather than an `&mut + /// Frame`. #[inline] fn access_local_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index e80a82acd585b..91a97fe4d4dd8 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -444,7 +444,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - /// Read from a local. Will not actually access the local if reading from a ZST. + /// Read from a local. /// Will not access memory, instead an indirect `Operand` is returned. /// /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an @@ -456,12 +456,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { let layout = self.layout_of_local(frame, local, layout)?; - let op = if layout.is_zst() { - // Bypass `access_local` (helps in ConstProp) - Operand::Immediate(Immediate::Uninit) - } else { - *M::access_local(frame, local)? - }; + let op = *frame.locals[local].access()?; Ok(OpTy { op, layout, align: Some(layout.align.abi) }) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 7aa76fe1dae0a..d56323448cea1 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -642,7 +642,7 @@ where // avoid force_allocation. let src = match self.read_immediate_raw(src)? { Ok(src_val) => { - assert!(!src.layout.is_unsized(), "cannot have unsized immediates"); + assert!(!src.layout.is_unsized(), "cannot copy unsized immediates"); assert!( !dest.layout.is_unsized(), "the src is sized, so the dest must also be sized" diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 742339f2b0aff..16ce5bc71750a 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -100,6 +100,8 @@ where // This makes several assumptions about what layouts we will encounter; we match what // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`). let field_val: Immediate<_> = match (*base, base.layout.abi) { + // if the entire value is uninit, then so is the field (can happen in ConstProp) + (Immediate::Uninit, _) => Immediate::Uninit, // the field contains no information, can be left uninit _ if field_layout.is_zst() => Immediate::Uninit, // the field covers the entire type @@ -124,6 +126,7 @@ where b_val }) } + // everything else is a bug _ => span_bug!( self.cur_span(), "invalid field access on immediate {}, layout {:#?}", diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index c1b201da69121..ddad72fdab93d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -103,7 +103,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // Find the index of the named region that was part of the // error. We will then search the function parameters for a bound // region at the right depth with the same index - (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => { + (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { self.found_type = Some(arg); @@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { Some( rl::Region::Static | rl::Region::Free(_, _) - | rl::Region::EarlyBound(_, _) + | rl::Region::EarlyBound(_) | rl::Region::LateBound(_, _, _), ) | None, @@ -188,7 +188,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) { match (self.tcx.named_region(lifetime.hir_id), self.bound_region) { // the lifetime of the TyPath! - (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => { + (Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); if id == def_id { self.found_it = true; @@ -209,7 +209,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { ( Some( rl::Region::Static - | rl::Region::EarlyBound(_, _) + | rl::Region::EarlyBound(_) | rl::Region::LateBound(_, _, _) | rl::Region::Free(_, _), ) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index af7ef96e485b5..3d002380f09dd 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2026,13 +2026,13 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN impl ExplicitOutlivesRequirements { fn lifetimes_outliving_lifetime<'tcx>( inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)], - index: u32, + def_id: DefId, ) -> Vec> { inferred_outlives .iter() .filter_map(|(pred, _)| match pred.kind().skip_binder() { ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { - ty::ReEarlyBound(ebr) if ebr.index == index => Some(b), + ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b), _ => None, }, _ => None, @@ -2069,8 +2069,12 @@ impl ExplicitOutlivesRequirements { .filter_map(|(i, bound)| { if let hir::GenericBound::Outlives(lifetime) = bound { let is_inferred = match tcx.named_region(lifetime.hir_id) { - Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| { - if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false } + Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| { + if let ty::ReEarlyBound(ebr) = **r { + ebr.def_id == def_id + } else { + false + } }), _ => false, }; @@ -2164,11 +2168,14 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { for (i, where_predicate) in hir_generics.predicates.iter().enumerate() { let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate { hir::WherePredicate::RegionPredicate(predicate) => { - if let Some(Region::EarlyBound(index, ..)) = + if let Some(Region::EarlyBound(region_def_id)) = cx.tcx.named_region(predicate.lifetime.hir_id) { ( - Self::lifetimes_outliving_lifetime(inferred_outlives, index), + Self::lifetimes_outliving_lifetime( + inferred_outlives, + region_def_id, + ), &predicate.bounds, predicate.span, predicate.in_where_clause, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 643294cace43b..9d201a0c79992 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -199,6 +199,7 @@ provide! { tcx, def_id, other, cdata, codegen_fn_attrs => { table } impl_trait_ref => { table } const_param_default => { table } + object_lifetime_default => { table } thir_abstract_const => { table } optimized_mir => { table } mir_for_ctfe => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index cd5da40150d4e..3482d9f04514e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1076,6 +1076,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); } } + if let DefKind::TyParam | DefKind::ConstParam = def_kind { + if let Some(default) = self.tcx.object_lifetime_default(def_id) { + record!(self.tables.object_lifetime_default[def_id] <- default); + } + } if let DefKind::Trait | DefKind::TraitAlias = def_kind { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index e6cceaf29d51f..aeffc85b50755 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -16,6 +16,7 @@ use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; +use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc_middle::mir; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::query::Providers; @@ -358,6 +359,7 @@ define_tables! { codegen_fn_attrs: Table>, impl_trait_ref: Table>>, const_param_default: Table>>, + object_lifetime_default: Table>, optimized_mir: Table>>, mir_for_ctfe: Table>>, promoted_mir: Table>>>, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 25c18cf50c11f..8f7877392483f 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -486,7 +486,9 @@ impl<'hir> Map<'hir> { let def_kind = self.tcx.def_kind(def_id); match def_kind { DefKind::Trait | DefKind::TraitAlias => def_id, - DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id), + DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => { + self.tcx.local_parent(def_id) + } _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind), } } @@ -495,7 +497,9 @@ impl<'hir> Map<'hir> { let def_kind = self.tcx.def_kind(def_id); match def_kind { DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper, - DefKind::TyParam | DefKind::ConstParam => self.tcx.item_name(def_id.to_def_id()), + DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => { + self.tcx.item_name(def_id.to_def_id()) + } _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind), } } diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 9b2f445670532..a171f5711dcff 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -10,7 +10,7 @@ use rustc_macros::HashStable; #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum Region { Static, - EarlyBound(/* index */ u32, /* lifetime decl */ DefId), + EarlyBound(/* lifetime decl */ DefId), LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId), Free(DefId, /* lifetime decl */ DefId), } @@ -35,7 +35,13 @@ impl Set1 { } } -pub type ObjectLifetimeDefault = Set1; +#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)] +pub enum ObjectLifetimeDefault { + Empty, + Static, + Ambiguous, + Param(DefId), +} /// Maps the id of each lifetime reference to the lifetime decl /// that it corresponds to. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ecedbe8fc8eaa..ddca9820da1ae 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1597,8 +1597,9 @@ rustc_queries! { /// for each parameter if a trait object were to be passed for that parameter. /// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`. /// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`. - query object_lifetime_defaults(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> { - desc { "looking up lifetime defaults for a region on an item" } + query object_lifetime_default(key: DefId) -> Option { + desc { "looking up lifetime defaults for generic parameter `{:?}`", key } + separate_provide_extern } query late_bound_vars_map(_: LocalDefId) -> Option<&'tcx FxHashMap>> { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 823e7f22af24d..42b5d5a6efd7e 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -1,4 +1,3 @@ -use crate::middle::resolve_lifetime::ObjectLifetimeDefault; use crate::ty; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::EarlyBinder; @@ -13,7 +12,7 @@ use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predi #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub enum GenericParamDefKind { Lifetime, - Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool }, + Type { has_default: bool, synthetic: bool }, Const { has_default: bool }, } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index ae6e2eecbffb5..19b8f27bc95ca 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -53,6 +53,7 @@ trivially_parameterized_over_tcx! { crate::metadata::ModChild, crate::middle::codegen_fn_attrs::CodegenFnAttrs, crate::middle::exported_symbols::SymbolExportInfo, + crate::middle::resolve_lifetime::ObjectLifetimeDefault, crate::mir::ConstQualifs, ty::Generics, ty::ImplPolarity, diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 5c9f4f57243b7..53f33a7a0bad2 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -243,24 +243,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } - fn access_local<'a>( - frame: &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>, - local: Local, - ) -> InterpResult<'tcx, &'a interpret::Operand> { - let l = &frame.locals[local]; - - if matches!( - l.value, - LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)) - ) { - // For us "uninit" means "we don't know its value, might be initiailized or not". - // So stop here. - throw_machine_stop_str!("tried to access alocal with unknown value ") - } - - l.access() - } - fn access_local_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, frame: usize, @@ -431,7 +413,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn get_const(&self, place: Place<'tcx>) -> Option> { let op = match self.ecx.eval_place_to_op(place, None) { - Ok(op) => op, + Ok(op) => { + if matches!(*op, interpret::Operand::Immediate(Immediate::Uninit)) { + // Make sure nobody accidentally uses this value. + return None; + } + op + } Err(e) => { trace!("get_const failed: {}", e); return None; @@ -643,6 +631,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if rvalue.needs_subst() { return None; } + if !rvalue + .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx) + .is_sized(self.ecx.tcx, self.param_env) + { + // the interpreter doesn't support unsized locals (only unsized arguments), + // but rustc does (in a kinda broken way), so we have to skip them here + return None; + } if self.tcx.sess.mir_opt_level() >= 4 { self.eval_rvalue_with_identities(rvalue, place) @@ -660,18 +656,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { self.use_ecx(|this| match rvalue { Rvalue::BinaryOp(op, box (left, right)) | Rvalue::CheckedBinaryOp(op, box (left, right)) => { - let l = this.ecx.eval_operand(left, None); - let r = this.ecx.eval_operand(right, None); + let l = this.ecx.eval_operand(left, None).and_then(|x| this.ecx.read_immediate(&x)); + let r = + this.ecx.eval_operand(right, None).and_then(|x| this.ecx.read_immediate(&x)); let const_arg = match (l, r) { - (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?, - (Err(e), Err(_)) => return Err(e), - (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place), + (Ok(x), Err(_)) | (Err(_), Ok(x)) => x, // exactly one side is known + (Err(e), Err(_)) => return Err(e), // neither side is known + (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place), // both sides are known }; if !matches!(const_arg.layout.abi, abi::Abi::Scalar(..)) { // We cannot handle Scalar Pair stuff. - return this.ecx.eval_rvalue_into_place(rvalue, place); + // No point in calling `eval_rvalue_into_place`, since only one side is known + throw_machine_stop_str!("cannot optimize this") } let arg_value = const_arg.to_scalar().to_bits(const_arg.layout.size)?; @@ -696,7 +694,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { this.ecx.write_immediate(*const_arg, &dest) } } - _ => this.ecx.eval_rvalue_into_place(rvalue, place), + _ => throw_machine_stop_str!("cannot optimize this"), } } _ => this.ecx.eval_rvalue_into_place(rvalue, place), @@ -1073,7 +1071,11 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { if let Some(ref value) = self.eval_operand(&cond) { trace!("assertion on {:?} should be {:?}", value, expected); let expected = Scalar::from_bool(*expected); - let value_const = self.ecx.read_scalar(&value).unwrap(); + let Ok(value_const) = self.ecx.read_scalar(&value) else { + // FIXME should be used use_ecx rather than a local match... but we have + // quite a few of these read_scalar/read_immediate that need fixing. + return + }; if expected != value_const { // Poison all places this operand references so that further code // doesn't use the invalid value diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 74b146833d03f..082d6c9f07e53 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -6,6 +6,7 @@ use crate::const_prop::ConstPropMachine; use crate::const_prop::ConstPropMode; use crate::MirLint; use rustc_const_eval::const_eval::ConstEvalErr; +use rustc_const_eval::interpret::Immediate; use rustc_const_eval::interpret::{ self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar, StackPopCleanup, }; @@ -229,7 +230,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn get_const(&self, place: Place<'tcx>) -> Option> { let op = match self.ecx.eval_place_to_op(place, None) { - Ok(op) => op, + Ok(op) => { + if matches!(*op, interpret::Operand::Immediate(Immediate::Uninit)) { + // Make sure nobody accidentally uses this value. + return None; + } + op + } Err(e) => { trace!("get_const failed: {}", e); return None; @@ -515,6 +522,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if rvalue.needs_subst() { return None; } + if !rvalue + .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx) + .is_sized(self.ecx.tcx, self.param_env) + { + // the interpreter doesn't support unsized locals (only unsized arguments), + // but rustc does (in a kinda broken way), so we have to skip them here + return None; + } self.use_ecx(source_info, |this| this.ecx.eval_rvalue_into_place(rvalue, place)) } @@ -624,7 +639,11 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { if let Some(ref value) = self.eval_operand(&cond, source_info) { trace!("assertion on {:?} should be {:?}", value, expected); let expected = Scalar::from_bool(*expected); - let value_const = self.ecx.read_scalar(&value).unwrap(); + let Ok(value_const) = self.ecx.read_scalar(&value) else { + // FIXME should be used use_ecx rather than a local match... but we have + // quite a few of these read_scalar/read_immediate that need fixing. + return + }; if expected != value_const { enum DbgVal { Val(T), @@ -641,9 +660,9 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { let mut eval_to_int = |op| { // This can be `None` if the lhs wasn't const propagated and we just // triggered the assert on the value of the rhs. - self.eval_operand(op, source_info).map_or(DbgVal::Underscore, |op| { - DbgVal::Val(self.ecx.read_immediate(&op).unwrap().to_const_int()) - }) + self.eval_operand(op, source_info) + .and_then(|op| self.ecx.read_immediate(&op).ok()) + .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int())) }; let msg = match msg { AssertKind::DivisionByZero(op) => { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index b63a173cc29e6..a9e502016aa8d 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -167,6 +167,8 @@ pub enum Count<'a> { CountIsName(&'a str, InnerSpan), /// The count is specified by the argument at the given index. CountIsParam(usize), + /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index. + CountIsStar(usize), /// The count is implied and cannot be explicitly specified. CountImplied, } @@ -618,7 +620,7 @@ impl<'a> Parser<'a> { // We can do this immediately as `position` is resolved later. let i = self.curarg; self.curarg += 1; - spec.precision = CountIsParam(i); + spec.precision = CountIsStar(i); } else { spec.precision = self.count(start + 1); } diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index 44ef0cd0eb5d2..2f8c229c68ffe 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -244,7 +244,7 @@ fn format_counts() { fill: None, align: AlignUnknown, flags: 0, - precision: CountIsParam(0), + precision: CountIsStar(0), precision_span: Some(InnerSpan { start: 3, end: 5 }), width: CountImplied, width_span: None, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5789531d2ff5a..f376da29bd919 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -16,6 +16,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID}; use rustc_hir::{MethodKind, Target}; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{ @@ -172,6 +173,9 @@ impl CheckAttrVisitor<'_> { sym::no_implicit_prelude => { self.check_generic_attr(hir_id, attr, target, &[Target::Mod]) } + sym::rustc_object_lifetime_default => { + self.check_object_lifetime_default(hir_id, span) + } _ => {} } @@ -410,6 +414,30 @@ impl CheckAttrVisitor<'_> { } } + /// Debugging aid for `object_lifetime_default` query. + fn check_object_lifetime_default(&self, hir_id: HirId, span: Span) { + let tcx = self.tcx; + if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) { + let object_lifetime_default_reprs: String = generics + .params + .iter() + .filter_map(|p| { + let param_id = tcx.hir().local_def_id(p.hir_id); + let default = tcx.object_lifetime_default(param_id)?; + Some(match default { + ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(), + ObjectLifetimeDefault::Static => "'static".to_owned(), + ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(), + ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(), + }) + }) + .collect::>() + .join(","); + + tcx.sess.span_err(span, &object_lifetime_default_reprs); + } + } + /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid. fn check_track_caller( &self, diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 94460e33d8b01..6ea976a590064 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -11,23 +11,21 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefIdMap, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node}; use rustc_middle::bug; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_lifetime::*; -use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; -use std::borrow::Cow; use std::fmt; -use std::mem::take; trait RegionExt { - fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region); + fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region); fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region); @@ -36,19 +34,13 @@ trait RegionExt { fn shifted(self, amount: u32) -> Region; fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region; - - fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option - where - L: Iterator; } impl RegionExt for Region { - fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) { - let i = *index; - *index += 1; + fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) { let def_id = hir_map.local_def_id(param.hir_id); - debug!("Region::early: index={} def_id={:?}", i, def_id); - (def_id, Region::EarlyBound(i, def_id.to_def_id())) + debug!("Region::early: def_id={:?}", def_id); + (def_id, Region::EarlyBound(def_id.to_def_id())) } fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) { @@ -65,9 +57,7 @@ impl RegionExt for Region { match *self { Region::Static => None, - Region::EarlyBound(_, id) | Region::LateBound(_, _, id) | Region::Free(_, id) => { - Some(id) - } + Region::EarlyBound(id) | Region::LateBound(_, _, id) | Region::Free(_, id) => Some(id), } } @@ -88,17 +78,6 @@ impl RegionExt for Region { _ => self, } } - - fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option - where - L: Iterator, - { - if let Region::EarlyBound(index, _) = self { - params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned()) - } else { - Some(self) - } - } } /// Maps the id of each lifetime reference to the lifetime decl @@ -131,9 +110,6 @@ pub(crate) struct LifetimeContext<'a, 'tcx> { /// be false if the `Item` we are resolving lifetimes for is not a trait or /// we eventually need lifetimes resolve for trait items. trait_definition_only: bool, - - /// Cache for cross-crate per-definition object lifetime defaults. - xcrate_object_lifetime_defaults: DefIdMap>, } #[derive(Debug)] @@ -147,25 +123,6 @@ enum Scope<'a> { /// for diagnostics. lifetimes: FxIndexMap, - /// if we extend this scope with another scope, what is the next index - /// we should use for an early-bound region? - next_early_index: u32, - - /// Whether or not this binder would serve as the parent - /// binder for opaque types introduced within. For example: - /// - /// ```text - /// fn foo<'a>() -> impl for<'b> Trait> - /// ``` - /// - /// Here, the opaque types we create for the `impl Trait` - /// and `impl Trait2` references will both have the `foo` item - /// as their parent. When we get to `impl Trait2`, we find - /// that it is nested within the `for<>` binder -- this flag - /// allows us to skip that when looking for the parent binder - /// of the resulting opaque type. - opaque_type_parent: bool, - scope_type: BinderScopeType, /// The late bound vars for a given item are stored by `HirId` to be @@ -245,19 +202,9 @@ struct TruncatedScopeDebug<'a>(&'a Scope<'a>); impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { - Scope::Binder { - lifetimes, - next_early_index, - opaque_type_parent, - scope_type, - hir_id, - where_bound_origin, - s: _, - } => f + Scope::Binder { lifetimes, scope_type, hir_id, where_bound_origin, s: _ } => f .debug_struct("Binder") .field("lifetimes", lifetimes) - .field("next_early_index", next_early_index) - .field("opaque_type_parent", opaque_type_parent) .field("scope_type", scope_type) .field("hir_id", hir_id) .field("where_bound_origin", where_bound_origin) @@ -294,10 +241,7 @@ pub fn provide(providers: &mut ty::query::Providers) { named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id), is_late_bound_map, - object_lifetime_defaults: |tcx, id| match tcx.hir().find_by_def_id(id) { - Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item), - _ => None, - }, + object_lifetime_default, late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id), ..*providers @@ -363,7 +307,6 @@ fn do_resolve( map: &mut named_region_map, scope: ROOT_SCOPE, trait_definition_only, - xcrate_object_lifetime_defaults: Default::default(), }; visitor.visit_item(item); @@ -432,13 +375,6 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId { item } -/// In traits, there is an implicit `Self` type parameter which comes before the generics. -/// We have to account for this when computing the index of the other generic parameters. -/// This function returns whether there is such an implicit parameter defined on the given item. -fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { - matches!(*node, hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..)) -} - fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind { match region { Region::LateBound(_, _, def_id) => { @@ -558,7 +494,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } - let next_early_index = self.next_early_index(); let (lifetimes, binders): (FxIndexMap, Vec<_>) = bound_generic_params .iter() @@ -576,8 +511,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: e.hir_id, lifetimes, s: self.scope, - next_early_index, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; @@ -603,7 +536,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } match item.kind { hir::ItemKind::Fn(_, ref generics, _) => { - self.visit_early_late(None, item.hir_id(), generics, |this| { + self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_item(this, item); }); } @@ -670,31 +603,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | hir::ItemKind::TraitAlias(ref generics, ..) | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { // These kinds of items have only early-bound lifetime parameters. - let mut index = if sub_items_have_self_param(&item.kind) { - 1 // Self comes before lifetimes - } else { - 0 - }; - let mut non_lifetime_count = 0; let lifetimes = generics .params .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { - Some(Region::early(self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None + Some(Region::early(self.tcx.hir(), param)) } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, }) .collect(); self.map.late_bound_vars.insert(item.hir_id(), vec![]); let scope = Scope::Binder { hir_id: item.hir_id(), lifetimes, - next_early_index: index + non_lifetime_count, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, s: ROOT_SCOPE, where_bound_origin: None, @@ -712,7 +634,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { hir::ForeignItemKind::Fn(_, _, ref generics) => { - self.visit_early_late(None, item.hir_id(), generics, |this| { + self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_foreign_item(this, item); }) } @@ -729,7 +651,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { match ty.kind { hir::TyKind::BareFn(ref c) => { - let next_early_index = self.next_early_index(); let (lifetimes, binders): (FxIndexMap, Vec<_>) = c .generic_params .iter() @@ -746,8 +667,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: ty.hir_id, lifetimes, s: self.scope, - next_early_index, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; @@ -886,32 +805,23 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // We want to start our early-bound indices at the end of the parent scope, // not including any parent `impl Trait`s. - let mut index = self.next_early_index_for_opaque_type(); - debug!(?index); - let mut lifetimes = FxIndexMap::default(); - let mut non_lifetime_count = 0; debug!(?generics.params); for param in generics.params { match param.kind { GenericParamKind::Lifetime { .. } => { - let (def_id, reg) = Region::early(self.tcx.hir(), &mut index, ¶m); + let (def_id, reg) = Region::early(self.tcx.hir(), ¶m); lifetimes.insert(def_id, reg); } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {} } } - let next_early_index = index + non_lifetime_count; self.map.late_bound_vars.insert(ty.hir_id, vec![]); let scope = Scope::Binder { hir_id: ty.hir_id, lifetimes, - next_early_index, s: self.scope, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; @@ -933,39 +843,27 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { use self::hir::TraitItemKind::*; match trait_item.kind { Fn(_, _) => { - let tcx = self.tcx; - self.visit_early_late( - Some(tcx.hir().get_parent_item(trait_item.hir_id())), - trait_item.hir_id(), - &trait_item.generics, - |this| intravisit::walk_trait_item(this, trait_item), - ); + self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| { + intravisit::walk_trait_item(this, trait_item) + }); } Type(bounds, ref ty) => { let generics = &trait_item.generics; - let mut index = self.next_early_index(); - debug!("visit_ty: index = {}", index); - let mut non_lifetime_count = 0; let lifetimes = generics .params .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { - Some(Region::early(self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None + Some(Region::early(self.tcx.hir(), param)) } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, }) .collect(); self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]); let scope = Scope::Binder { hir_id: trait_item.hir_id(), lifetimes, - next_early_index: index + non_lifetime_count, s: self.scope, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; @@ -993,40 +891,26 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { use self::hir::ImplItemKind::*; match impl_item.kind { - Fn(..) => { - let tcx = self.tcx; - self.visit_early_late( - Some(tcx.hir().get_parent_item(impl_item.hir_id())), - impl_item.hir_id(), - &impl_item.generics, - |this| intravisit::walk_impl_item(this, impl_item), - ); - } + Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| { + intravisit::walk_impl_item(this, impl_item) + }), TyAlias(ref ty) => { let generics = &impl_item.generics; - let mut index = self.next_early_index(); - let mut non_lifetime_count = 0; - debug!("visit_ty: index = {}", index); let lifetimes: FxIndexMap = generics .params .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { - Some(Region::early(self.tcx.hir(), &mut index, param)) - } - GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => { - non_lifetime_count += 1; - None + Some(Region::early(self.tcx.hir(), param)) } + GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None, }) .collect(); self.map.late_bound_vars.insert(ty.hir_id, vec![]); let scope = Scope::Binder { hir_id: ty.hir_id, lifetimes, - next_early_index: index + non_lifetime_count, s: self.scope, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; @@ -1129,7 +1013,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }) .unzip(); this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone()); - let next_early_index = this.next_early_index(); // Even if there are no lifetimes defined here, we still wrap it in a binder // scope. If there happens to be a nested poly trait ref (an error), that // will be `Concatenating` anyways, so we don't have to worry about the depth @@ -1138,8 +1021,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: bounded_ty.hir_id, lifetimes, s: this.scope, - next_early_index, - opaque_type_parent: false, scope_type: BinderScopeType::Normal, where_bound_origin: Some(origin), }; @@ -1210,8 +1091,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: *hir_id, lifetimes: FxIndexMap::default(), s: self.scope, - next_early_index: self.next_early_index(), - opaque_type_parent: false, scope_type, where_bound_origin: None, }; @@ -1230,7 +1109,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ) { debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); - let next_early_index = self.next_early_index(); let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); let initial_bound_vars = binders.len() as u32; @@ -1260,8 +1138,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir_id: trait_ref.trait_ref.hir_ref_id, lifetimes, s: self.scope, - next_early_index, - opaque_type_parent: false, scope_type, where_bound_origin: None, }; @@ -1272,127 +1148,46 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } -fn compute_object_lifetime_defaults<'tcx>( +fn object_lifetime_default<'tcx>( tcx: TyCtxt<'tcx>, - item: &hir::Item<'_>, -) -> Option<&'tcx [ObjectLifetimeDefault]> { - match item.kind { - hir::ItemKind::Struct(_, ref generics) - | hir::ItemKind::Union(_, ref generics) - | hir::ItemKind::Enum(_, ref generics) - | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - ref generics, - origin: hir::OpaqueTyOrigin::TyAlias, - .. - }) - | hir::ItemKind::TyAlias(_, ref generics) - | hir::ItemKind::Trait(_, _, ref generics, ..) => { - let result = object_lifetime_defaults_for_item(tcx, generics); - - // Debugging aid. - let attrs = tcx.hir().attrs(item.hir_id()); - if tcx.sess.contains_name(attrs, sym::rustc_object_lifetime_default) { - let object_lifetime_default_reprs: String = result - .iter() - .map(|set| match *set { - Set1::Empty => "BaseDefault".into(), - Set1::One(Region::Static) => "'static".into(), - Set1::One(Region::EarlyBound(mut i, _)) => generics - .params - .iter() - .find_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - if i == 0 { - return Some(param.name.ident().to_string().into()); - } - i -= 1; - None - } - _ => None, - }) - .unwrap(), - Set1::One(_) => bug!(), - Set1::Many => "Ambiguous".into(), - }) - .collect::>>() - .join(","); - tcx.sess.span_err(item.span, &object_lifetime_default_reprs); - } - - Some(result) - } - _ => None, - } -} - -/// 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. -fn object_lifetime_defaults_for_item<'tcx>( - tcx: TyCtxt<'tcx>, - generics: &hir::Generics<'_>, -) -> &'tcx [ObjectLifetimeDefault] { - fn add_bounds(set: &mut Set1, bounds: &[hir::GenericBound<'_>]) { - for bound in bounds { - if let hir::GenericBound::Outlives(ref lifetime) = *bound { - set.insert(lifetime.name.normalize_to_macros_2_0()); - } - } - } - - let process_param = |param: &hir::GenericParam<'_>| match param.kind { + param_def_id: DefId, +) -> Option { + 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)?; + 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)?; + + // 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::Lifetime { .. } => None, GenericParamKind::Type { .. } => { let mut set = Set1::Empty; - let param_def_id = tcx.hir().local_def_id(param.hir_id); - for predicate in generics.predicates { - // Look for `type: ...` where clauses. - let hir::WherePredicate::BoundPredicate(ref data) = *predicate else { continue }; - + // 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 !data.bound_generic_params.is_empty() { + if !bound.bound_generic_params.is_empty() { continue; } - let res = match data.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res, - _ => continue, - }; - - if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) { - add_bounds(&mut set, &data.bounds); + for bound in bound.bounds { + if let hir::GenericBound::Outlives(ref lifetime) = *bound { + set.insert(lifetime.name.normalize_to_macros_2_0()); + } } } Some(match set { - Set1::Empty => Set1::Empty, - Set1::One(name) => { - if name == hir::LifetimeName::Static { - Set1::One(Region::Static) - } else { - generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - let param_def_id = tcx.hir().local_def_id(param.hir_id); - Some(( - param_def_id, - hir::LifetimeName::Param(param_def_id, param.name), - )) - } - _ => None, - }) - .enumerate() - .find(|&(_, (_, lt_name))| lt_name == name) - .map_or(Set1::Many, |(i, (def_id, _))| { - Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id())) - }) - } + 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()) } - Set1::Many => Set1::Many, + _ => ObjectLifetimeDefault::Ambiguous, }) } GenericParamKind::Const { .. } => { @@ -1400,11 +1195,9 @@ fn object_lifetime_defaults_for_item<'tcx>( // // We still store a dummy value here to allow generic parameters // in an arbitrary order. - Some(Set1::Empty) + Some(ObjectLifetimeDefault::Empty) } - }; - - tcx.arena.alloc_from_iter(generics.params.iter().filter_map(process_param)) + } } impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { @@ -1413,20 +1206,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>), { let LifetimeContext { tcx, map, .. } = self; - let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope, trait_definition_only: self.trait_definition_only, - xcrate_object_lifetime_defaults, }; let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); { let _enter = span.enter(); f(&mut this); } - self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; } /// Visits self by adding a scope and handling recursive walk over the contents with `walk`. @@ -1449,30 +1239,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { /// ordering is not important there. fn visit_early_late( &mut self, - parent_id: Option, hir_id: hir::HirId, generics: &'tcx hir::Generics<'tcx>, walk: F, ) where F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>), { - // Find the start of nested early scopes, e.g., in methods. - let mut next_early_index = 0; - if let Some(parent_id) = parent_id { - let parent = self.tcx.hir().expect_item(parent_id); - if sub_items_have_self_param(&parent.kind) { - next_early_index += 1; // Self comes before lifetimes - } - match parent.kind { - hir::ItemKind::Trait(_, _, ref generics, ..) - | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { - next_early_index += generics.params.len() as u32; - } - _ => {} - } - } - - let mut non_lifetime_count = 0; let mut named_late_bound_vars = 0; let lifetimes: FxIndexMap = generics .params @@ -1484,16 +1256,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { named_late_bound_vars += 1; Some(Region::late(late_bound_idx, self.tcx.hir(), param)) } else { - Some(Region::early(self.tcx.hir(), &mut next_early_index, param)) + Some(Region::early(self.tcx.hir(), param)) } } - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - non_lifetime_count += 1; - None - } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None, }) .collect(); - let next_early_index = next_early_index + non_lifetime_count; let binders: Vec<_> = generics .params @@ -1512,51 +1280,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let scope = Scope::Binder { hir_id, lifetimes, - next_early_index, s: self.scope, - opaque_type_parent: true, scope_type: BinderScopeType::Normal, where_bound_origin: None, }; self.with(scope, walk); } - fn next_early_index_helper(&self, only_opaque_type_parent: bool) -> u32 { - let mut scope = self.scope; - loop { - match *scope { - Scope::Root => return 0, - - Scope::Binder { next_early_index, opaque_type_parent, .. } - if (!only_opaque_type_parent || opaque_type_parent) => - { - return next_early_index; - } - - Scope::Binder { s, .. } - | Scope::Body { s, .. } - | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } - | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => scope = s, - } - } - } - - /// Returns the next index one would use for an early-bound-region - /// if extending the current scope. - fn next_early_index(&self) -> u32 { - self.next_early_index_helper(true) - } - - /// Returns the next index one would use for an `impl Trait` that - /// is being converted into an opaque type alias `impl Trait`. This will be the - /// next early index from the enclosing item, for the most - /// part. See the `opaque_type_parent` field for more info. - fn next_early_index_for_opaque_type(&self) -> u32 { - self.next_early_index_helper(false) - } - #[tracing::instrument(level = "debug", skip(self))] fn resolve_lifetime_ref( &mut self, @@ -1679,17 +1409,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { ); } + #[tracing::instrument(level = "debug", skip(self))] fn visit_segment_args( &mut self, res: Res, depth: usize, generic_args: &'tcx hir::GenericArgs<'tcx>, ) { - debug!( - "visit_segment_args(res={:?}, depth={:?}, generic_args={:?})", - res, depth, generic_args, - ); - if generic_args.parenthesized { self.visit_fn_like_elision( generic_args.inputs(), @@ -1707,13 +1433,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // Figure out if this is a type/trait segment, // which requires object lifetime defaults. - let parent_def_id = |this: &mut Self, def_id: DefId| { - let def_key = this.tcx.def_key(def_id); - DefId { krate: def_id.krate, index: def_key.parent.expect("missing parent") } - }; let type_def_id = match res { - Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(parent_def_id(self, def_id)), - Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)), + Res::Def(DefKind::AssocTy, def_id) if depth == 1 => Some(self.tcx.parent(def_id)), + Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(self.tcx.parent(def_id)), Res::Def( DefKind::Struct | DefKind::Union @@ -1725,7 +1447,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { _ => None, }; - debug!("visit_segment_args: type_def_id={:?}", type_def_id); + debug!(?type_def_id); // Compute a vector of defaults, one for each type parameter, // per the rules given in RFCs 599 and 1156. Example: @@ -1763,55 +1485,39 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }; let map = &self.map; - let set_to_region = |set: &ObjectLifetimeDefault| match *set { - Set1::Empty => { + let generics = self.tcx.generics_of(def_id); + + // `type_def_id` points to an item, so there is nothing to inherit generics from. + debug_assert_eq!(generics.parent_count, 0); + + let set_to_region = |set: ObjectLifetimeDefault| match set { + ObjectLifetimeDefault::Empty => { if in_body { None } else { Some(Region::Static) } } - Set1::One(r) => { - let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(lt) => Some(lt), + ObjectLifetimeDefault::Static => Some(Region::Static), + ObjectLifetimeDefault::Param(param_def_id) => { + // This index can be used with `generic_args` since `parent_count == 0`. + let index = generics.param_def_id_to_index[¶m_def_id] as usize; + generic_args.args.get(index).and_then(|arg| match arg { + GenericArg::Lifetime(lt) => map.defs.get(<.hir_id).copied(), _ => None, - }); - r.subst(lifetimes, map) + }) } - Set1::Many => None, + ObjectLifetimeDefault::Ambiguous => None, }; - if let Some(def_id) = def_id.as_local() { - let id = self.tcx.hir().local_def_id_to_hir_id(def_id); - self.tcx - .object_lifetime_defaults(id.owner) - .unwrap() - .iter() - .map(set_to_region) - .collect() - } else { - let tcx = self.tcx; - self.xcrate_object_lifetime_defaults - .entry(def_id) - .or_insert_with(|| { - tcx.generics_of(def_id) - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamDefKind::Type { object_lifetime_default, .. } => { - Some(object_lifetime_default) - } - GenericParamDefKind::Const { .. } => Some(Set1::Empty), - GenericParamDefKind::Lifetime => None, - }) - .collect() - }) - .iter() - .map(set_to_region) - .collect() - } + generics + .params + .iter() + .filter_map(|param| self.tcx.object_lifetime_default(param.def_id)) + .map(set_to_region) + .collect() }); - debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults); + debug!(?object_lifetime_defaults); let mut i = 0; for arg in generic_args.args { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 5bb02bc246caf..5c96f1c4623a6 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -222,9 +222,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.mk_region(ty::ReLateBound(debruijn, br)) } - Some(rl::Region::EarlyBound(index, id)) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name })) + Some(rl::Region::EarlyBound(def_id)) => { + let name = tcx.hir().ty_param_name(def_id.expect_local()); + let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name })) } Some(rl::Region::Free(scope, id)) => { @@ -253,9 +256,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) } }; - debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r); - r } @@ -2853,10 +2854,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); if !infer_replacements.is_empty() { - diag.multipart_suggestion(&format!( + diag.multipart_suggestion( + &format!( "try replacing `_` with the type{} in the corresponding trait method signature", rustc_errors::pluralize!(infer_replacements.len()), - ), infer_replacements, Applicability::MachineApplicable); + ), + infer_replacements, + Applicability::MachineApplicable, + ); } diag.emit(); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 970b39dc845af..6236ad370df60 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1617,7 +1617,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { has_default: false, - object_lifetime_default: rl::Set1::Empty, synthetic: false, }, }); @@ -1661,8 +1660,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { kind: ty::GenericParamDefKind::Lifetime, })); - let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id.owner); - // Now create the real type and const parameters. let type_start = own_start - has_self as u32 + params.len() as u32; let mut i = 0; @@ -1687,13 +1684,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { } } - let kind = ty::GenericParamDefKind::Type { - has_default: default.is_some(), - object_lifetime_default: object_lifetime_defaults - .as_ref() - .map_or(rl::Set1::Empty, |o| o[i]), - synthetic, - }; + let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic }; let param_def = ty::GenericParamDef { index: type_start + i as u32, @@ -1745,11 +1736,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { name: Symbol::intern(arg), def_id, pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { - has_default: false, - object_lifetime_default: rl::Set1::Empty, - synthetic: false, - }, + kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, })); } @@ -1762,11 +1749,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { name: Symbol::intern(""), def_id, pure_wrt_drop: false, - kind: ty::GenericParamDefKind::Type { - has_default: false, - object_lifetime_default: rl::Set1::Empty, - synthetic: false, - }, + kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, }); } } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 4351548811d2e..ed049194dd068 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -4,7 +4,6 @@ use crate::alloc::{Allocator, Global}; use crate::raw_vec::RawVec; use core::array; use core::fmt; -use core::intrinsics::arith_offset; use core::iter::{ FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, }; @@ -154,7 +153,7 @@ impl Iterator for IntoIter { // purposefully don't use 'ptr.offset' because for // vectors with 0-size elements this would return the // same pointer. - self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T }; + self.ptr = self.ptr.wrapping_byte_add(1); // Make up a value of this ZST. Some(unsafe { mem::zeroed() }) @@ -184,7 +183,7 @@ impl Iterator for IntoIter { // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound // effectively results in unsigned pointers representing positions 0..usize::MAX, // which is valid for ZSTs. - self.ptr = unsafe { arith_offset(self.ptr as *const i8, step_size as isize) as *mut T } + self.ptr = self.ptr.wrapping_byte_add(step_size); } else { // SAFETY: the min() above ensures that step_size is in bounds self.ptr = unsafe { self.ptr.add(step_size) }; @@ -217,7 +216,7 @@ impl Iterator for IntoIter { return Err(unsafe { array::IntoIter::new_unchecked(raw_ary, 0..len) }); } - self.ptr = unsafe { arith_offset(self.ptr as *const i8, N as isize) as *mut T }; + self.ptr = self.ptr.wrapping_byte_add(N); // Safety: ditto return Ok(unsafe { MaybeUninit::array_assume_init(raw_ary) }); } @@ -267,7 +266,7 @@ impl DoubleEndedIterator for IntoIter { None } else if mem::size_of::() == 0 { // See above for why 'ptr.offset' isn't used - self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T }; + self.end = self.ptr.wrapping_byte_sub(1); // Make up a value of this ZST. Some(unsafe { mem::zeroed() }) @@ -283,9 +282,7 @@ impl DoubleEndedIterator for IntoIter { let step_size = self.len().min(n); if mem::size_of::() == 0 { // SAFETY: same as for advance_by() - self.end = unsafe { - arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T - } + self.end = self.end.wrapping_byte_sub(step_size); } else { // SAFETY: same as for advance_by() self.end = unsafe { self.end.sub(step_size) }; diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 2c786fd511ead..1f19b9e594549 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -59,7 +59,7 @@ use core::cmp::Ordering; use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; -use core::intrinsics::{arith_offset, assume}; +use core::intrinsics::assume; use core::iter; #[cfg(not(no_global_oom_handling))] use core::iter::FromIterator; @@ -2678,7 +2678,7 @@ impl IntoIterator for Vec { let alloc = ManuallyDrop::new(ptr::read(me.allocator())); let begin = me.as_mut_ptr(); let end = if mem::size_of::() == 0 { - arith_offset(begin as *const i8, me.len() as isize) as *const T + begin.wrapping_byte_add(me.len()) } else { begin.add(me.len()) as *const T }; diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index 32d1a4e550834..7da49b04aaae9 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -28,24 +28,14 @@ impl<'buf, 'state> PadAdapter<'buf, 'state> { } impl fmt::Write for PadAdapter<'_, '_> { - fn write_str(&mut self, mut s: &str) -> fmt::Result { - while !s.is_empty() { + fn write_str(&mut self, s: &str) -> fmt::Result { + for s in s.split_inclusive('\n') { if self.state.on_newline { self.buf.write_str(" ")?; } - let split = match s.find('\n') { - Some(pos) => { - self.state.on_newline = true; - pos + 1 - } - None => { - self.state.on_newline = false; - s.len() - } - }; - self.buf.write_str(&s[..split])?; - s = &s[split..]; + self.state.on_newline = s.ends_with('\n'); + self.buf.write_str(s)?; } Ok(()) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 3f3eb3b3c5c52..ef7b3b1d1470a 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -249,7 +249,7 @@ impl *const T { let offset = dest_addr.wrapping_sub(self_addr); // This is the canonical desugarring of this operation - self.cast::().wrapping_offset(offset).cast::() + self.wrapping_byte_offset(offset) } /// Creates a new pointer by mapping `self`'s address to a new one. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 03ee879f7da28..6a3b9ee9a7daa 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -255,7 +255,7 @@ impl *mut T { let offset = dest_addr.wrapping_sub(self_addr); // This is the canonical desugarring of this operation - self.cast::().wrapping_offset(offset).cast::() + self.wrapping_byte_offset(offset) } /// Creates a new pointer by mapping `self`'s address to a new one. diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index c05242222dde7..47455760a4bd7 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -64,7 +64,7 @@ macro_rules! iterator { // backwards by `n`. `n` must not exceed `self.len()`. macro_rules! zst_shrink { ($self: ident, $n: ident) => { - $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T; + $self.end = $self.end.wrapping_byte_offset(-$n); } } diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index 13b12db209a76..94b0310603bf4 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -155,7 +155,7 @@ fn ptr_add_data() { assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1)); assert_eq!(atom.load(SeqCst), n); - let bytes_from_n = |b| n.cast::().wrapping_add(b).cast::(); + let bytes_from_n = |b| n.wrapping_byte_add(b); assert_eq!(atom.fetch_byte_add(1, SeqCst), n); assert_eq!(atom.load(SeqCst), bytes_from_n(1)); diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 12861794c2d2c..97a369810056d 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -650,7 +650,7 @@ fn thin_box() { .unwrap_or_else(|| handle_alloc_error(layout)) .cast::>(); ptr.as_ptr().write(meta); - ptr.cast::().as_ptr().add(offset).cast::().write(value); + ptr.as_ptr().byte_add(offset).cast::().write(value); Self { ptr, phantom: PhantomData } } } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index e1ab06b0d0f69..28a2c99f7e5e3 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -377,6 +377,35 @@ impl File { OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref()) } + /// Creates a new file in read-write mode; error if the file exists. + /// + /// This function will create a file if it does not exist, or return an error if it does. This + /// way, if the call succeeds, the file returned is guaranteed to be new. + /// + /// This option is useful because it is atomic. Otherwise between checking whether a file + /// exists and creating a new one, the file may have been created by another process (a TOCTOU + /// race condition / attack). + /// + /// This can also be written using + /// `File::options().read(true).write(true).create_new(true).open(...)`. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(file_create_new)] + /// + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let mut f = File::create_new("foo.txt")?; + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "file_create_new", issue = "none")] + pub fn create_new>(path: P) -> io::Result { + OpenOptions::new().read(true).write(true).create_new(true).open(path.as_ref()) + } + /// Returns a new OpenOptions object. /// /// This function returns a new OpenOptions object that you can use to diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 292bf4826fd23..781ae03ad45dc 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -269,10 +269,10 @@ where } TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::().as_ptr()), TAG_CUSTOM => { - // It would be correct for us to use `ptr::sub` here (see the + // It would be correct for us to use `ptr::byte_sub` here (see the // comment above the `wrapping_add` call in `new_custom` for why), // but it isn't clear that it makes a difference, so we don't. - let custom = ptr.as_ptr().cast::().wrapping_sub(TAG_CUSTOM).cast::(); + let custom = ptr.as_ptr().wrapping_byte_sub(TAG_CUSTOM).cast::(); ErrorData::Custom(make_custom(custom)) } _ => { diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index a9fa7b0a6aca0..01a3873c75cec 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1037,8 +1037,6 @@ pub trait Read { /// # Examples /// /// ```no_run -/// #![feature(io_read_to_string)] -/// /// # use std::io; /// fn main() -> io::Result<()> { /// let stdin = io::read_to_string(io::stdin())?; @@ -1047,7 +1045,7 @@ pub trait Read { /// Ok(()) /// } /// ``` -#[unstable(feature = "io_read_to_string", issue = "80218")] +#[stable(feature = "io_read_to_string", since = "CURRENT_RUSTC_VERSION")] pub fn read_to_string(mut reader: R) -> Result { let mut buf = String::new(); reader.read_to_string(&mut buf)?; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f5dcdab4cd570..8936e11b8e02e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -300,6 +300,7 @@ #![feature(panic_can_unwind)] #![feature(panic_info_message)] #![feature(panic_internals)] +#![feature(pointer_byte_offsets)] #![feature(pointer_is_aligned)] #![feature(portable_simd)] #![feature(prelude_2024)] diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 420159b5a6751..c425de081a6a6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -192,7 +192,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>( fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime { let def = cx.tcx.named_region(lifetime.hir_id); if let Some( - rl::Region::EarlyBound(_, node_id) + rl::Region::EarlyBound(node_id) | rl::Region::LateBound(_, _, node_id) | rl::Region::Free(_, node_id), ) = def diff --git a/src/test/codegen/issue-96274.rs b/src/test/codegen/issue-96274.rs new file mode 100644 index 0000000000000..e3abf73096125 --- /dev/null +++ b/src/test/codegen/issue-96274.rs @@ -0,0 +1,11 @@ +// min-llvm-version: 15.0 +// compile-flags: -O + +#![crate_type = "lib"] + +use std::mem::MaybeUninit; + +pub fn maybe_uninit() -> [MaybeUninit; 3000] { + // CHECK-NOT: memset + [MaybeUninit::uninit(); 3000] +} diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index b466cfdd59594..0f8898c389b7f 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -504,9 +504,9 @@ enum EnumAddLifetimeBoundToParameter<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeBoundToParameter<'a, T: 'a> { Variant1(T), @@ -559,9 +559,9 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] +#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail6")] enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a { Variant1(T), diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 1988f3f35417c..c453eeceb77f5 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -1066,9 +1066,9 @@ trait TraitAddTraitBoundToTypeParameterOfTrait { } trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } @@ -1144,9 +1144,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } @@ -1201,9 +1201,9 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } @@ -1254,9 +1254,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { } diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff index 4f205667be0e2..186a953735675 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff @@ -41,7 +41,8 @@ StorageLive(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:9: +4:10 _4 = (_2.1: i32); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+4:13: +4:16 StorageLive(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:9: +5:10 - _5 = (_2.0: i32); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16 +- _5 = (_2.0: i32); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16 ++ _5 = const 1_i32; // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+5:13: +5:16 nop; // scope 0 at $DIR/mutable_variable_unprop_assign.rs:+0:11: +6:2 StorageDead(_5); // scope 3 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 StorageDead(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2 diff --git a/src/test/ui/fmt/ifmt-bad-arg.rs b/src/test/ui/fmt/ifmt-bad-arg.rs index 84f4cc7f4ccd8..f00cb05c9ebc3 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.rs +++ b/src/test/ui/fmt/ifmt-bad-arg.rs @@ -94,4 +94,6 @@ tenth number: {}", // doesn't exist. println!("{:.*}"); //~^ ERROR 2 positional arguments in format string, but no arguments were given + println!("{:.0$}"); + //~^ ERROR 1 positional argument in format string, but no arguments were given } diff --git a/src/test/ui/fmt/ifmt-bad-arg.stderr b/src/test/ui/fmt/ifmt-bad-arg.stderr index 5439ee173985b..dbb4bc6d9370e 100644 --- a/src/test/ui/fmt/ifmt-bad-arg.stderr +++ b/src/test/ui/fmt/ifmt-bad-arg.stderr @@ -273,6 +273,17 @@ LL | println!("{:.*}"); = note: positional arguments are zero-based = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html +error: 1 positional argument in format string, but no arguments were given + --> $DIR/ifmt-bad-arg.rs:97:15 + | +LL | println!("{:.0$}"); + | ^^---^ + | | + | this precision flag expects an `usize` argument at position 0, but no arguments were given + | + = note: positional arguments are zero-based + = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html + error[E0425]: cannot find value `foo` in this scope --> $DIR/ifmt-bad-arg.rs:27:18 | @@ -339,7 +350,7 @@ LL | pub fn from_usize(x: &usize) -> ArgumentV1<'_> { | ^^^^^^^^^^ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 37 previous errors +error: aborting due to 38 previous errors Some errors have detailed explanations: E0308, E0425. For more information about an error, try `rustc --explain E0308`.