mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Auto merge of #101152 - Dylan-DPC:rollup-v4iw8ux, r=Dylan-DPC
Rollup of 8 pull requests Successful merges: - #98304 (Add MaybeUninit memset test) - #98801 (Add a `File::create_new` constructor) - #99821 (Remove separate indexing of early-bound regions) - #100239 (remove an ineffective check in const_prop) - #100337 (Stabilize `std::io::read_to_string`) - #100819 (Make use of `[wrapping_]byte_{add,sub}`) - #100934 (Remove a panicking branch from `fmt::builders::PadAdapter`) - #101000 (Separate CountIsStar from CountIsParam in rustc_parse_format.) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
bc4b39c271
@ -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<T> TypedArena<T> {
|
||||
|
||||
unsafe {
|
||||
if mem::size_of::<T>() == 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::<T>::dangling().as_ptr();
|
||||
// Don't drop the object. This `write` is equivalent to `forget`.
|
||||
ptr::write(ptr, object);
|
||||
|
@ -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.
|
||||
|
@ -187,9 +187,6 @@ pub enum LocalValue<Prov: Provenance = AllocId> {
|
||||
|
||||
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<Prov>> {
|
||||
match &self.value {
|
||||
|
@ -215,23 +215,12 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||
right: &ImmTy<'tcx, Self::Provenance>,
|
||||
) -> InterpResult<'tcx, (Scalar<Self::Provenance>, 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<Self::Provenance>>
|
||||
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>,
|
||||
|
@ -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<TyAndLayout<'tcx>>,
|
||||
) -> 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) })
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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 {:#?}",
|
||||
|
@ -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(_, _),
|
||||
)
|
||||
|
@ -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<ty::Region<'tcx>> {
|
||||
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,
|
||||
|
@ -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 }
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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<DefIndex, LazyValue<CodegenFnAttrs>>,
|
||||
impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
|
||||
const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'static>>>,
|
||||
object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
|
||||
optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
||||
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
||||
promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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<T: PartialEq> Set1<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub type ObjectLifetimeDefault = Set1<Region>;
|
||||
#[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.
|
||||
|
@ -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<ObjectLifetimeDefault> {
|
||||
desc { "looking up lifetime defaults for generic parameter `{:?}`", key }
|
||||
separate_provide_extern
|
||||
}
|
||||
query late_bound_vars_map(_: LocalDefId)
|
||||
-> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
|
||||
|
@ -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 },
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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<Self::Provenance>> {
|
||||
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<OpTy<'tcx>> {
|
||||
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
|
||||
|
@ -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<OpTy<'tcx>> {
|
||||
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<T> {
|
||||
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) => {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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::<Vec<String>>()
|
||||
.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,
|
||||
|
@ -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<Region>
|
||||
where
|
||||
L: Iterator<Item = &'a hir::Lifetime>;
|
||||
}
|
||||
|
||||
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<Region>
|
||||
where
|
||||
L: Iterator<Item = &'a hir::Lifetime>,
|
||||
{
|
||||
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<Vec<ObjectLifetimeDefault>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -147,25 +123,6 @@ enum Scope<'a> {
|
||||
/// for diagnostics.
|
||||
lifetimes: FxIndexMap<LocalDefId, Region>,
|
||||
|
||||
/// 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<Item = impl Trait2<'a>>
|
||||
/// ```
|
||||
///
|
||||
/// 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<LocalDefId, Region>, 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<LocalDefId, Region>, 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<LocalDefId, Region> = 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);
|
||||
param_def_id: DefId,
|
||||
) -> Option<ObjectLifetimeDefault> {
|
||||
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)?;
|
||||
|
||||
// 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::<Vec<Cow<'static, str>>>()
|
||||
.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<hir::LifetimeName>, 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 {
|
||||
// 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<F>(
|
||||
&mut self,
|
||||
parent_id: Option<LocalDefId>,
|
||||
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<LocalDefId, Region> = 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,
|
||||
};
|
||||
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()
|
||||
}
|
||||
}
|
||||
ObjectLifetimeDefault::Ambiguous => None,
|
||||
};
|
||||
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 {
|
||||
|
@ -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();
|
||||
|
@ -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("<const_ty>"),
|
||||
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 },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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<T, A: Allocator> Iterator for IntoIter<T, A> {
|
||||
// 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<T, A: Allocator> Iterator for IntoIter<T, A> {
|
||||
// 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<T, A: Allocator> Iterator for IntoIter<T, A> {
|
||||
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<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
||||
None
|
||||
} else if mem::size_of::<T>() == 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<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
||||
let step_size = self.len().min(n);
|
||||
if mem::size_of::<T>() == 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) };
|
||||
|
@ -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<T, A: Allocator> IntoIterator for Vec<T, A> {
|
||||
let alloc = ManuallyDrop::new(ptr::read(me.allocator()));
|
||||
let begin = me.as_mut_ptr();
|
||||
let end = if mem::size_of::<T>() == 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
|
||||
};
|
||||
|
@ -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(())
|
||||
|
@ -249,7 +249,7 @@ impl<T: ?Sized> *const T {
|
||||
let offset = dest_addr.wrapping_sub(self_addr);
|
||||
|
||||
// This is the canonical desugarring of this operation
|
||||
self.cast::<u8>().wrapping_offset(offset).cast::<T>()
|
||||
self.wrapping_byte_offset(offset)
|
||||
}
|
||||
|
||||
/// Creates a new pointer by mapping `self`'s address to a new one.
|
||||
|
@ -255,7 +255,7 @@ impl<T: ?Sized> *mut T {
|
||||
let offset = dest_addr.wrapping_sub(self_addr);
|
||||
|
||||
// This is the canonical desugarring of this operation
|
||||
self.cast::<u8>().wrapping_offset(offset).cast::<T>()
|
||||
self.wrapping_byte_offset(offset)
|
||||
}
|
||||
|
||||
/// Creates a new pointer by mapping `self`'s address to a new one.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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::<u8>().wrapping_add(b).cast::<i64>();
|
||||
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));
|
||||
|
@ -650,7 +650,7 @@ fn thin_box() {
|
||||
.unwrap_or_else(|| handle_alloc_error(layout))
|
||||
.cast::<DynMetadata<T>>();
|
||||
ptr.as_ptr().write(meta);
|
||||
ptr.cast::<u8>().as_ptr().add(offset).cast::<Value>().write(value);
|
||||
ptr.as_ptr().byte_add(offset).cast::<Value>().write(value);
|
||||
Self { ptr, phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
@ -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<P: AsRef<Path>>(path: P) -> io::Result<File> {
|
||||
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
|
||||
|
@ -269,10 +269,10 @@ where
|
||||
}
|
||||
TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().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::<u8>().wrapping_sub(TAG_CUSTOM).cast::<Custom>();
|
||||
let custom = ptr.as_ptr().wrapping_byte_sub(TAG_CUSTOM).cast::<Custom>();
|
||||
ErrorData::Custom(make_custom(custom))
|
||||
}
|
||||
_ => {
|
||||
|
@ -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<R: Read>(mut reader: R) -> Result<String> {
|
||||
let mut buf = String::new();
|
||||
reader.read_to_string(&mut buf)?;
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
11
src/test/codegen/issue-96274.rs
Normal file
11
src/test/codegen/issue-96274.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// min-llvm-version: 15.0
|
||||
// compile-flags: -O
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
pub fn maybe_uninit() -> [MaybeUninit<u8>; 3000] {
|
||||
// CHECK-NOT: memset
|
||||
[MaybeUninit::uninit(); 3000]
|
||||
}
|
@ -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),
|
||||
|
@ -1066,9 +1066,9 @@ trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
|
||||
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<T: ReferencedTrait0 + Refer
|
||||
trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, 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 TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
|
||||
|
||||
@ -1201,9 +1201,9 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> 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<T>
|
||||
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 { }
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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`.
|
||||
|
Loading…
Reference in New Issue
Block a user