mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-07 20:58:39 +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(maybe_uninit_slice)]
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
|
#![feature(pointer_byte_offsets)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![cfg_attr(test, feature(test))]
|
#![cfg_attr(test, feature(test))]
|
||||||
#![feature(strict_provenance)]
|
#![feature(strict_provenance)]
|
||||||
@ -211,7 +212,7 @@ impl<T> TypedArena<T> {
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if mem::size_of::<T>() == 0 {
|
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();
|
let ptr = ptr::NonNull::<T>::dangling().as_ptr();
|
||||||
// Don't drop the object. This `write` is equivalent to `forget`.
|
// Don't drop the object. This `write` is equivalent to `forget`.
|
||||||
ptr::write(ptr, object);
|
ptr::write(ptr, object);
|
||||||
|
@ -541,7 +541,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
) {
|
) {
|
||||||
match c {
|
match c {
|
||||||
parse::CountImplied | parse::CountIs(..) => {}
|
parse::CountImplied | parse::CountIs(..) => {}
|
||||||
parse::CountIsParam(i) => {
|
parse::CountIsParam(i) | parse::CountIsStar(i) => {
|
||||||
self.unused_names_lint.maybe_add_positional_named_arg(
|
self.unused_names_lint.maybe_add_positional_named_arg(
|
||||||
self.args.get(i),
|
self.args.get(i),
|
||||||
named_arg_type,
|
named_arg_type,
|
||||||
@ -589,7 +589,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
+ self
|
+ self
|
||||||
.arg_with_formatting
|
.arg_with_formatting
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
|
.filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
|
||||||
.count();
|
.count();
|
||||||
if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
|
if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
|
||||||
e = self.ecx.struct_span_err(
|
e = self.ecx.struct_span_err(
|
||||||
@ -639,7 +639,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
if let Some(span) = fmt.precision_span {
|
if let Some(span) = fmt.precision_span {
|
||||||
let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
|
let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
|
||||||
match fmt.precision {
|
match fmt.precision {
|
||||||
parse::CountIsParam(pos) if pos > self.num_args() => {
|
parse::CountIsParam(pos) if pos >= self.num_args() => {
|
||||||
e.span_label(
|
e.span_label(
|
||||||
span,
|
span,
|
||||||
&format!(
|
&format!(
|
||||||
@ -651,12 +651,12 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
);
|
);
|
||||||
zero_based_note = true;
|
zero_based_note = true;
|
||||||
}
|
}
|
||||||
parse::CountIsParam(pos) => {
|
parse::CountIsStar(pos) => {
|
||||||
let count = self.pieces.len()
|
let count = self.pieces.len()
|
||||||
+ self
|
+ self
|
||||||
.arg_with_formatting
|
.arg_with_formatting
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
|
.filter(|fmt| matches!(fmt.precision, parse::CountIsStar(_)))
|
||||||
.count();
|
.count();
|
||||||
e.span_label(
|
e.span_label(
|
||||||
span,
|
span,
|
||||||
@ -837,7 +837,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
};
|
};
|
||||||
match c {
|
match c {
|
||||||
parse::CountIs(i) => count(sym::Is, Some(self.ecx.expr_usize(sp, i))),
|
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
|
// This needs mapping too, as `i` is referring to a macro
|
||||||
// argument. If `i` is not found in `count_positions` then
|
// argument. If `i` is not found in `count_positions` then
|
||||||
// the error had already been emitted elsewhere.
|
// 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> {
|
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.
|
/// 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]
|
#[inline]
|
||||||
pub fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
|
pub fn access(&self) -> InterpResult<'tcx, &Operand<Prov>> {
|
||||||
match &self.value {
|
match &self.value {
|
||||||
|
@ -215,23 +215,12 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||||||
right: &ImmTy<'tcx, Self::Provenance>,
|
right: &ImmTy<'tcx, Self::Provenance>,
|
||||||
) -> InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)>;
|
) -> 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`.
|
/// Called to write the specified `local` from the `frame`.
|
||||||
/// Since writing a ZST is not actually accessing memory or locals, this is never invoked
|
/// Since writing a ZST is not actually accessing memory or locals, this is never invoked
|
||||||
/// for ZST reads.
|
/// for ZST reads.
|
||||||
|
///
|
||||||
|
/// Due to borrow checker trouble, we indicate the `frame` as an index rather than an `&mut
|
||||||
|
/// Frame`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn access_local_mut<'a>(
|
fn access_local_mut<'a>(
|
||||||
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
|
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.
|
/// 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
|
/// 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>>,
|
layout: Option<TyAndLayout<'tcx>>,
|
||||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||||
let layout = self.layout_of_local(frame, local, layout)?;
|
let layout = self.layout_of_local(frame, local, layout)?;
|
||||||
let op = if layout.is_zst() {
|
let op = *frame.locals[local].access()?;
|
||||||
// Bypass `access_local` (helps in ConstProp)
|
|
||||||
Operand::Immediate(Immediate::Uninit)
|
|
||||||
} else {
|
|
||||||
*M::access_local(frame, local)?
|
|
||||||
};
|
|
||||||
Ok(OpTy { op, layout, align: Some(layout.align.abi) })
|
Ok(OpTy { op, layout, align: Some(layout.align.abi) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,7 +642,7 @@ where
|
|||||||
// avoid force_allocation.
|
// avoid force_allocation.
|
||||||
let src = match self.read_immediate_raw(src)? {
|
let src = match self.read_immediate_raw(src)? {
|
||||||
Ok(src_val) => {
|
Ok(src_val) => {
|
||||||
assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
|
assert!(!src.layout.is_unsized(), "cannot copy unsized immediates");
|
||||||
assert!(
|
assert!(
|
||||||
!dest.layout.is_unsized(),
|
!dest.layout.is_unsized(),
|
||||||
"the src is sized, so the dest must also be sized"
|
"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
|
// 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`).
|
// 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) {
|
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
|
// the field contains no information, can be left uninit
|
||||||
_ if field_layout.is_zst() => Immediate::Uninit,
|
_ if field_layout.is_zst() => Immediate::Uninit,
|
||||||
// the field covers the entire type
|
// the field covers the entire type
|
||||||
@ -124,6 +126,7 @@ where
|
|||||||
b_val
|
b_val
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// everything else is a bug
|
||||||
_ => span_bug!(
|
_ => span_bug!(
|
||||||
self.cur_span(),
|
self.cur_span(),
|
||||||
"invalid field access on immediate {}, layout {:#?}",
|
"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
|
// Find the index of the named region that was part of the
|
||||||
// error. We will then search the function parameters for a bound
|
// error. We will then search the function parameters for a bound
|
||||||
// region at the right depth with the same index
|
// 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);
|
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
|
||||||
if id == def_id {
|
if id == def_id {
|
||||||
self.found_type = Some(arg);
|
self.found_type = Some(arg);
|
||||||
@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
|||||||
Some(
|
Some(
|
||||||
rl::Region::Static
|
rl::Region::Static
|
||||||
| rl::Region::Free(_, _)
|
| rl::Region::Free(_, _)
|
||||||
| rl::Region::EarlyBound(_, _)
|
| rl::Region::EarlyBound(_)
|
||||||
| rl::Region::LateBound(_, _, _),
|
| rl::Region::LateBound(_, _, _),
|
||||||
)
|
)
|
||||||
| None,
|
| None,
|
||||||
@ -188,7 +188,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
|
|||||||
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
|
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
|
||||||
match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
|
match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
|
||||||
// the lifetime of the TyPath!
|
// 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);
|
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
|
||||||
if id == def_id {
|
if id == def_id {
|
||||||
self.found_it = true;
|
self.found_it = true;
|
||||||
@ -209,7 +209,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
|
|||||||
(
|
(
|
||||||
Some(
|
Some(
|
||||||
rl::Region::Static
|
rl::Region::Static
|
||||||
| rl::Region::EarlyBound(_, _)
|
| rl::Region::EarlyBound(_)
|
||||||
| rl::Region::LateBound(_, _, _)
|
| rl::Region::LateBound(_, _, _)
|
||||||
| rl::Region::Free(_, _),
|
| rl::Region::Free(_, _),
|
||||||
)
|
)
|
||||||
|
@ -2026,13 +2026,13 @@ declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMEN
|
|||||||
impl ExplicitOutlivesRequirements {
|
impl ExplicitOutlivesRequirements {
|
||||||
fn lifetimes_outliving_lifetime<'tcx>(
|
fn lifetimes_outliving_lifetime<'tcx>(
|
||||||
inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
|
inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)],
|
||||||
index: u32,
|
def_id: DefId,
|
||||||
) -> Vec<ty::Region<'tcx>> {
|
) -> Vec<ty::Region<'tcx>> {
|
||||||
inferred_outlives
|
inferred_outlives
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(pred, _)| match pred.kind().skip_binder() {
|
.filter_map(|(pred, _)| match pred.kind().skip_binder() {
|
||||||
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
|
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,
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -2069,8 +2069,12 @@ impl ExplicitOutlivesRequirements {
|
|||||||
.filter_map(|(i, bound)| {
|
.filter_map(|(i, bound)| {
|
||||||
if let hir::GenericBound::Outlives(lifetime) = bound {
|
if let hir::GenericBound::Outlives(lifetime) = bound {
|
||||||
let is_inferred = match tcx.named_region(lifetime.hir_id) {
|
let is_inferred = match tcx.named_region(lifetime.hir_id) {
|
||||||
Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| {
|
Some(Region::EarlyBound(def_id)) => inferred_outlives.iter().any(|r| {
|
||||||
if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false }
|
if let ty::ReEarlyBound(ebr) = **r {
|
||||||
|
ebr.def_id == def_id
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
@ -2164,11 +2168,14 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
|||||||
for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
|
for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
|
||||||
let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
|
let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
|
||||||
hir::WherePredicate::RegionPredicate(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)
|
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.bounds,
|
||||||
predicate.span,
|
predicate.span,
|
||||||
predicate.in_where_clause,
|
predicate.in_where_clause,
|
||||||
|
@ -199,6 +199,7 @@ provide! { tcx, def_id, other, cdata,
|
|||||||
codegen_fn_attrs => { table }
|
codegen_fn_attrs => { table }
|
||||||
impl_trait_ref => { table }
|
impl_trait_ref => { table }
|
||||||
const_param_default => { table }
|
const_param_default => { table }
|
||||||
|
object_lifetime_default => { table }
|
||||||
thir_abstract_const => { table }
|
thir_abstract_const => { table }
|
||||||
optimized_mir => { table }
|
optimized_mir => { table }
|
||||||
mir_for_ctfe => { 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);
|
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 {
|
if let DefKind::Trait | DefKind::TraitAlias = def_kind {
|
||||||
record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
|
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::metadata::ModChild;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||||
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
||||||
|
use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::ty::fast_reject::SimplifiedType;
|
use rustc_middle::ty::fast_reject::SimplifiedType;
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
@ -358,6 +359,7 @@ define_tables! {
|
|||||||
codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
|
codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
|
||||||
impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
|
impl_trait_ref: Table<DefIndex, LazyValue<ty::TraitRef<'static>>>,
|
||||||
const_param_default: Table<DefIndex, LazyValue<rustc_middle::ty::Const<'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>>>,
|
optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
||||||
mir_for_ctfe: 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>>>>,
|
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);
|
let def_kind = self.tcx.def_kind(def_id);
|
||||||
match def_kind {
|
match def_kind {
|
||||||
DefKind::Trait | DefKind::TraitAlias => def_id,
|
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),
|
_ => 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);
|
let def_kind = self.tcx.def_kind(def_id);
|
||||||
match def_kind {
|
match def_kind {
|
||||||
DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper,
|
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),
|
_ => 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)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
|
||||||
pub enum Region {
|
pub enum Region {
|
||||||
Static,
|
Static,
|
||||||
EarlyBound(/* index */ u32, /* lifetime decl */ DefId),
|
EarlyBound(/* lifetime decl */ DefId),
|
||||||
LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId),
|
LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId),
|
||||||
Free(DefId, /* 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
|
/// Maps the id of each lifetime reference to the lifetime decl
|
||||||
/// that it corresponds to.
|
/// 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 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 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]`.
|
/// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`.
|
||||||
query object_lifetime_defaults(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> {
|
query object_lifetime_default(key: DefId) -> Option<ObjectLifetimeDefault> {
|
||||||
desc { "looking up lifetime defaults for a region on an item" }
|
desc { "looking up lifetime defaults for generic parameter `{:?}`", key }
|
||||||
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
query late_bound_vars_map(_: LocalDefId)
|
query late_bound_vars_map(_: LocalDefId)
|
||||||
-> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
|
-> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
|
|
||||||
use crate::ty;
|
use crate::ty;
|
||||||
use crate::ty::subst::{Subst, SubstsRef};
|
use crate::ty::subst::{Subst, SubstsRef};
|
||||||
use crate::ty::EarlyBinder;
|
use crate::ty::EarlyBinder;
|
||||||
@ -13,7 +12,7 @@ use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predi
|
|||||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||||
pub enum GenericParamDefKind {
|
pub enum GenericParamDefKind {
|
||||||
Lifetime,
|
Lifetime,
|
||||||
Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool },
|
Type { has_default: bool, synthetic: bool },
|
||||||
Const { has_default: bool },
|
Const { has_default: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ trivially_parameterized_over_tcx! {
|
|||||||
crate::metadata::ModChild,
|
crate::metadata::ModChild,
|
||||||
crate::middle::codegen_fn_attrs::CodegenFnAttrs,
|
crate::middle::codegen_fn_attrs::CodegenFnAttrs,
|
||||||
crate::middle::exported_symbols::SymbolExportInfo,
|
crate::middle::exported_symbols::SymbolExportInfo,
|
||||||
|
crate::middle::resolve_lifetime::ObjectLifetimeDefault,
|
||||||
crate::mir::ConstQualifs,
|
crate::mir::ConstQualifs,
|
||||||
ty::Generics,
|
ty::Generics,
|
||||||
ty::ImplPolarity,
|
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")
|
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>(
|
fn access_local_mut<'a>(
|
||||||
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
|
||||||
frame: usize,
|
frame: usize,
|
||||||
@ -431,7 +413,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
|
|
||||||
fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
|
fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
|
||||||
let op = match self.ecx.eval_place_to_op(place, None) {
|
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) => {
|
Err(e) => {
|
||||||
trace!("get_const failed: {}", e);
|
trace!("get_const failed: {}", e);
|
||||||
return None;
|
return None;
|
||||||
@ -643,6 +631,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
if rvalue.needs_subst() {
|
if rvalue.needs_subst() {
|
||||||
return None;
|
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 {
|
if self.tcx.sess.mir_opt_level() >= 4 {
|
||||||
self.eval_rvalue_with_identities(rvalue, place)
|
self.eval_rvalue_with_identities(rvalue, place)
|
||||||
@ -660,18 +656,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
self.use_ecx(|this| match rvalue {
|
self.use_ecx(|this| match rvalue {
|
||||||
Rvalue::BinaryOp(op, box (left, right))
|
Rvalue::BinaryOp(op, box (left, right))
|
||||||
| Rvalue::CheckedBinaryOp(op, box (left, right)) => {
|
| Rvalue::CheckedBinaryOp(op, box (left, right)) => {
|
||||||
let l = this.ecx.eval_operand(left, 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);
|
let r =
|
||||||
|
this.ecx.eval_operand(right, None).and_then(|x| this.ecx.read_immediate(&x));
|
||||||
|
|
||||||
let const_arg = match (l, r) {
|
let const_arg = match (l, r) {
|
||||||
(Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
|
(Ok(x), Err(_)) | (Err(_), Ok(x)) => x, // exactly one side is known
|
||||||
(Err(e), Err(_)) => return Err(e),
|
(Err(e), Err(_)) => return Err(e), // neither side is known
|
||||||
(Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place),
|
(Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place), // both sides are known
|
||||||
};
|
};
|
||||||
|
|
||||||
if !matches!(const_arg.layout.abi, abi::Abi::Scalar(..)) {
|
if !matches!(const_arg.layout.abi, abi::Abi::Scalar(..)) {
|
||||||
// We cannot handle Scalar Pair stuff.
|
// 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)?;
|
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.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),
|
_ => 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) {
|
if let Some(ref value) = self.eval_operand(&cond) {
|
||||||
trace!("assertion on {:?} should be {:?}", value, expected);
|
trace!("assertion on {:?} should be {:?}", value, expected);
|
||||||
let expected = Scalar::from_bool(*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 {
|
if expected != value_const {
|
||||||
// Poison all places this operand references so that further code
|
// Poison all places this operand references so that further code
|
||||||
// doesn't use the invalid value
|
// doesn't use the invalid value
|
||||||
|
@ -6,6 +6,7 @@ use crate::const_prop::ConstPropMachine;
|
|||||||
use crate::const_prop::ConstPropMode;
|
use crate::const_prop::ConstPropMode;
|
||||||
use crate::MirLint;
|
use crate::MirLint;
|
||||||
use rustc_const_eval::const_eval::ConstEvalErr;
|
use rustc_const_eval::const_eval::ConstEvalErr;
|
||||||
|
use rustc_const_eval::interpret::Immediate;
|
||||||
use rustc_const_eval::interpret::{
|
use rustc_const_eval::interpret::{
|
||||||
self, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, Scalar, StackPopCleanup,
|
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>> {
|
fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
|
||||||
let op = match self.ecx.eval_place_to_op(place, None) {
|
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) => {
|
Err(e) => {
|
||||||
trace!("get_const failed: {}", e);
|
trace!("get_const failed: {}", e);
|
||||||
return None;
|
return None;
|
||||||
@ -515,6 +522,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
if rvalue.needs_subst() {
|
if rvalue.needs_subst() {
|
||||||
return None;
|
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))
|
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) {
|
if let Some(ref value) = self.eval_operand(&cond, source_info) {
|
||||||
trace!("assertion on {:?} should be {:?}", value, expected);
|
trace!("assertion on {:?} should be {:?}", value, expected);
|
||||||
let expected = Scalar::from_bool(*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 {
|
if expected != value_const {
|
||||||
enum DbgVal<T> {
|
enum DbgVal<T> {
|
||||||
Val(T),
|
Val(T),
|
||||||
@ -641,9 +660,9 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
|||||||
let mut eval_to_int = |op| {
|
let mut eval_to_int = |op| {
|
||||||
// This can be `None` if the lhs wasn't const propagated and we just
|
// This can be `None` if the lhs wasn't const propagated and we just
|
||||||
// triggered the assert on the value of the rhs.
|
// triggered the assert on the value of the rhs.
|
||||||
self.eval_operand(op, source_info).map_or(DbgVal::Underscore, |op| {
|
self.eval_operand(op, source_info)
|
||||||
DbgVal::Val(self.ecx.read_immediate(&op).unwrap().to_const_int())
|
.and_then(|op| self.ecx.read_immediate(&op).ok())
|
||||||
})
|
.map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int()))
|
||||||
};
|
};
|
||||||
let msg = match msg {
|
let msg = match msg {
|
||||||
AssertKind::DivisionByZero(op) => {
|
AssertKind::DivisionByZero(op) => {
|
||||||
|
@ -167,6 +167,8 @@ pub enum Count<'a> {
|
|||||||
CountIsName(&'a str, InnerSpan),
|
CountIsName(&'a str, InnerSpan),
|
||||||
/// The count is specified by the argument at the given index.
|
/// The count is specified by the argument at the given index.
|
||||||
CountIsParam(usize),
|
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.
|
/// The count is implied and cannot be explicitly specified.
|
||||||
CountImplied,
|
CountImplied,
|
||||||
}
|
}
|
||||||
@ -618,7 +620,7 @@ impl<'a> Parser<'a> {
|
|||||||
// We can do this immediately as `position` is resolved later.
|
// We can do this immediately as `position` is resolved later.
|
||||||
let i = self.curarg;
|
let i = self.curarg;
|
||||||
self.curarg += 1;
|
self.curarg += 1;
|
||||||
spec.precision = CountIsParam(i);
|
spec.precision = CountIsStar(i);
|
||||||
} else {
|
} else {
|
||||||
spec.precision = self.count(start + 1);
|
spec.precision = self.count(start + 1);
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ fn format_counts() {
|
|||||||
fill: None,
|
fill: None,
|
||||||
align: AlignUnknown,
|
align: AlignUnknown,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
precision: CountIsParam(0),
|
precision: CountIsStar(0),
|
||||||
precision_span: Some(InnerSpan { start: 3, end: 5 }),
|
precision_span: Some(InnerSpan { start: 3, end: 5 }),
|
||||||
width: CountImplied,
|
width: CountImplied,
|
||||||
width_span: None,
|
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::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID};
|
||||||
use rustc_hir::{MethodKind, Target};
|
use rustc_hir::{MethodKind, Target};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
|
use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::lint::builtin::{
|
use rustc_session::lint::builtin::{
|
||||||
@ -172,6 +173,9 @@ impl CheckAttrVisitor<'_> {
|
|||||||
sym::no_implicit_prelude => {
|
sym::no_implicit_prelude => {
|
||||||
self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
|
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.
|
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
|
||||||
fn check_track_caller(
|
fn check_track_caller(
|
||||||
&self,
|
&self,
|
||||||
|
@ -11,23 +11,21 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
|||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::struct_span_err;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
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::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
|
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::hir::map::Map;
|
use rustc_middle::hir::map::Map;
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::middle::resolve_lifetime::*;
|
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::def_id::DefId;
|
||||||
use rustc_span::symbol::{sym, Ident};
|
use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem::take;
|
|
||||||
|
|
||||||
trait RegionExt {
|
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);
|
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(self, amount: u32) -> Region;
|
||||||
|
|
||||||
fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> 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 {
|
impl RegionExt for Region {
|
||||||
fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
|
fn early(hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
|
||||||
let i = *index;
|
|
||||||
*index += 1;
|
|
||||||
let def_id = hir_map.local_def_id(param.hir_id);
|
let def_id = hir_map.local_def_id(param.hir_id);
|
||||||
debug!("Region::early: index={} def_id={:?}", i, def_id);
|
debug!("Region::early: def_id={:?}", def_id);
|
||||||
(def_id, Region::EarlyBound(i, def_id.to_def_id()))
|
(def_id, Region::EarlyBound(def_id.to_def_id()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
|
fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (LocalDefId, Region) {
|
||||||
@ -65,9 +57,7 @@ impl RegionExt for Region {
|
|||||||
match *self {
|
match *self {
|
||||||
Region::Static => None,
|
Region::Static => None,
|
||||||
|
|
||||||
Region::EarlyBound(_, id) | Region::LateBound(_, _, id) | Region::Free(_, id) => {
|
Region::EarlyBound(id) | Region::LateBound(_, _, id) | Region::Free(_, id) => Some(id),
|
||||||
Some(id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,17 +78,6 @@ impl RegionExt for Region {
|
|||||||
_ => self,
|
_ => 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
|
/// 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
|
/// be false if the `Item` we are resolving lifetimes for is not a trait or
|
||||||
/// we eventually need lifetimes resolve for trait items.
|
/// we eventually need lifetimes resolve for trait items.
|
||||||
trait_definition_only: bool,
|
trait_definition_only: bool,
|
||||||
|
|
||||||
/// Cache for cross-crate per-definition object lifetime defaults.
|
|
||||||
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -147,25 +123,6 @@ enum Scope<'a> {
|
|||||||
/// for diagnostics.
|
/// for diagnostics.
|
||||||
lifetimes: FxIndexMap<LocalDefId, Region>,
|
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,
|
scope_type: BinderScopeType,
|
||||||
|
|
||||||
/// The late bound vars for a given item are stored by `HirId` to be
|
/// 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> {
|
impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Scope::Binder {
|
Scope::Binder { lifetimes, scope_type, hir_id, where_bound_origin, s: _ } => f
|
||||||
lifetimes,
|
|
||||||
next_early_index,
|
|
||||||
opaque_type_parent,
|
|
||||||
scope_type,
|
|
||||||
hir_id,
|
|
||||||
where_bound_origin,
|
|
||||||
s: _,
|
|
||||||
} => f
|
|
||||||
.debug_struct("Binder")
|
.debug_struct("Binder")
|
||||||
.field("lifetimes", lifetimes)
|
.field("lifetimes", lifetimes)
|
||||||
.field("next_early_index", next_early_index)
|
|
||||||
.field("opaque_type_parent", opaque_type_parent)
|
|
||||||
.field("scope_type", scope_type)
|
.field("scope_type", scope_type)
|
||||||
.field("hir_id", hir_id)
|
.field("hir_id", hir_id)
|
||||||
.field("where_bound_origin", where_bound_origin)
|
.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),
|
named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id),
|
||||||
is_late_bound_map,
|
is_late_bound_map,
|
||||||
object_lifetime_defaults: |tcx, id| match tcx.hir().find_by_def_id(id) {
|
object_lifetime_default,
|
||||||
Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
|
late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
|
||||||
|
|
||||||
..*providers
|
..*providers
|
||||||
@ -363,7 +307,6 @@ fn do_resolve(
|
|||||||
map: &mut named_region_map,
|
map: &mut named_region_map,
|
||||||
scope: ROOT_SCOPE,
|
scope: ROOT_SCOPE,
|
||||||
trait_definition_only,
|
trait_definition_only,
|
||||||
xcrate_object_lifetime_defaults: Default::default(),
|
|
||||||
};
|
};
|
||||||
visitor.visit_item(item);
|
visitor.visit_item(item);
|
||||||
|
|
||||||
@ -432,13 +375,6 @@ fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
|
|||||||
item
|
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 {
|
fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind {
|
||||||
match region {
|
match region {
|
||||||
Region::LateBound(_, _, def_id) => {
|
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<_>) =
|
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
|
||||||
bound_generic_params
|
bound_generic_params
|
||||||
.iter()
|
.iter()
|
||||||
@ -576,8 +511,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||||||
hir_id: e.hir_id,
|
hir_id: e.hir_id,
|
||||||
lifetimes,
|
lifetimes,
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
next_early_index,
|
|
||||||
opaque_type_parent: false,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
where_bound_origin: None,
|
where_bound_origin: None,
|
||||||
};
|
};
|
||||||
@ -603,7 +536,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
match item.kind {
|
match item.kind {
|
||||||
hir::ItemKind::Fn(_, ref generics, _) => {
|
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);
|
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::TraitAlias(ref generics, ..)
|
||||||
| hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
|
| hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
|
||||||
// These kinds of items have only early-bound lifetime parameters.
|
// 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
|
let lifetimes = generics
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|param| match param.kind {
|
.filter_map(|param| match param.kind {
|
||||||
GenericParamKind::Lifetime { .. } => {
|
GenericParamKind::Lifetime { .. } => {
|
||||||
Some(Region::early(self.tcx.hir(), &mut index, param))
|
Some(Region::early(self.tcx.hir(), param))
|
||||||
}
|
|
||||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
|
||||||
non_lifetime_count += 1;
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.map.late_bound_vars.insert(item.hir_id(), vec![]);
|
self.map.late_bound_vars.insert(item.hir_id(), vec![]);
|
||||||
let scope = Scope::Binder {
|
let scope = Scope::Binder {
|
||||||
hir_id: item.hir_id(),
|
hir_id: item.hir_id(),
|
||||||
lifetimes,
|
lifetimes,
|
||||||
next_early_index: index + non_lifetime_count,
|
|
||||||
opaque_type_parent: true,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
s: ROOT_SCOPE,
|
s: ROOT_SCOPE,
|
||||||
where_bound_origin: None,
|
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>) {
|
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
|
||||||
match item.kind {
|
match item.kind {
|
||||||
hir::ForeignItemKind::Fn(_, _, ref generics) => {
|
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);
|
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>) {
|
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
||||||
match ty.kind {
|
match ty.kind {
|
||||||
hir::TyKind::BareFn(ref c) => {
|
hir::TyKind::BareFn(ref c) => {
|
||||||
let next_early_index = self.next_early_index();
|
|
||||||
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
|
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
|
||||||
.generic_params
|
.generic_params
|
||||||
.iter()
|
.iter()
|
||||||
@ -746,8 +667,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||||||
hir_id: ty.hir_id,
|
hir_id: ty.hir_id,
|
||||||
lifetimes,
|
lifetimes,
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
next_early_index,
|
|
||||||
opaque_type_parent: false,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
where_bound_origin: None,
|
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,
|
// We want to start our early-bound indices at the end of the parent scope,
|
||||||
// not including any parent `impl Trait`s.
|
// 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 lifetimes = FxIndexMap::default();
|
||||||
let mut non_lifetime_count = 0;
|
|
||||||
debug!(?generics.params);
|
debug!(?generics.params);
|
||||||
for param in generics.params {
|
for param in generics.params {
|
||||||
match param.kind {
|
match param.kind {
|
||||||
GenericParamKind::Lifetime { .. } => {
|
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);
|
lifetimes.insert(def_id, reg);
|
||||||
}
|
}
|
||||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
|
||||||
non_lifetime_count += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
let next_early_index = index + non_lifetime_count;
|
|
||||||
self.map.late_bound_vars.insert(ty.hir_id, vec![]);
|
self.map.late_bound_vars.insert(ty.hir_id, vec![]);
|
||||||
|
|
||||||
let scope = Scope::Binder {
|
let scope = Scope::Binder {
|
||||||
hir_id: ty.hir_id,
|
hir_id: ty.hir_id,
|
||||||
lifetimes,
|
lifetimes,
|
||||||
next_early_index,
|
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
opaque_type_parent: false,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
where_bound_origin: None,
|
where_bound_origin: None,
|
||||||
};
|
};
|
||||||
@ -933,39 +843,27 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||||||
use self::hir::TraitItemKind::*;
|
use self::hir::TraitItemKind::*;
|
||||||
match trait_item.kind {
|
match trait_item.kind {
|
||||||
Fn(_, _) => {
|
Fn(_, _) => {
|
||||||
let tcx = self.tcx;
|
self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| {
|
||||||
self.visit_early_late(
|
intravisit::walk_trait_item(this, trait_item)
|
||||||
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),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Type(bounds, ref ty) => {
|
Type(bounds, ref ty) => {
|
||||||
let generics = &trait_item.generics;
|
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
|
let lifetimes = generics
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|param| match param.kind {
|
.filter_map(|param| match param.kind {
|
||||||
GenericParamKind::Lifetime { .. } => {
|
GenericParamKind::Lifetime { .. } => {
|
||||||
Some(Region::early(self.tcx.hir(), &mut index, param))
|
Some(Region::early(self.tcx.hir(), param))
|
||||||
}
|
|
||||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
|
||||||
non_lifetime_count += 1;
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]);
|
self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]);
|
||||||
let scope = Scope::Binder {
|
let scope = Scope::Binder {
|
||||||
hir_id: trait_item.hir_id(),
|
hir_id: trait_item.hir_id(),
|
||||||
lifetimes,
|
lifetimes,
|
||||||
next_early_index: index + non_lifetime_count,
|
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
opaque_type_parent: true,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
where_bound_origin: None,
|
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>) {
|
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
|
||||||
use self::hir::ImplItemKind::*;
|
use self::hir::ImplItemKind::*;
|
||||||
match impl_item.kind {
|
match impl_item.kind {
|
||||||
Fn(..) => {
|
Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| {
|
||||||
let tcx = self.tcx;
|
intravisit::walk_impl_item(this, impl_item)
|
||||||
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),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
TyAlias(ref ty) => {
|
TyAlias(ref ty) => {
|
||||||
let generics = &impl_item.generics;
|
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
|
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|param| match param.kind {
|
.filter_map(|param| match param.kind {
|
||||||
GenericParamKind::Lifetime { .. } => {
|
GenericParamKind::Lifetime { .. } => {
|
||||||
Some(Region::early(self.tcx.hir(), &mut index, param))
|
Some(Region::early(self.tcx.hir(), param))
|
||||||
}
|
|
||||||
GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => {
|
|
||||||
non_lifetime_count += 1;
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.map.late_bound_vars.insert(ty.hir_id, vec![]);
|
self.map.late_bound_vars.insert(ty.hir_id, vec![]);
|
||||||
let scope = Scope::Binder {
|
let scope = Scope::Binder {
|
||||||
hir_id: ty.hir_id,
|
hir_id: ty.hir_id,
|
||||||
lifetimes,
|
lifetimes,
|
||||||
next_early_index: index + non_lifetime_count,
|
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
opaque_type_parent: true,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
where_bound_origin: None,
|
where_bound_origin: None,
|
||||||
};
|
};
|
||||||
@ -1129,7 +1013,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||||||
})
|
})
|
||||||
.unzip();
|
.unzip();
|
||||||
this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone());
|
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
|
// 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
|
// 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
|
// 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,
|
hir_id: bounded_ty.hir_id,
|
||||||
lifetimes,
|
lifetimes,
|
||||||
s: this.scope,
|
s: this.scope,
|
||||||
next_early_index,
|
|
||||||
opaque_type_parent: false,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
where_bound_origin: Some(origin),
|
where_bound_origin: Some(origin),
|
||||||
};
|
};
|
||||||
@ -1210,8 +1091,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||||||
hir_id: *hir_id,
|
hir_id: *hir_id,
|
||||||
lifetimes: FxIndexMap::default(),
|
lifetimes: FxIndexMap::default(),
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
next_early_index: self.next_early_index(),
|
|
||||||
opaque_type_parent: false,
|
|
||||||
scope_type,
|
scope_type,
|
||||||
where_bound_origin: None,
|
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);
|
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 (mut binders, scope_type) = self.poly_trait_ref_binder_info();
|
||||||
|
|
||||||
let initial_bound_vars = binders.len() as u32;
|
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,
|
hir_id: trait_ref.trait_ref.hir_ref_id,
|
||||||
lifetimes,
|
lifetimes,
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
next_early_index,
|
|
||||||
opaque_type_parent: false,
|
|
||||||
scope_type,
|
scope_type,
|
||||||
where_bound_origin: None,
|
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>,
|
tcx: TyCtxt<'tcx>,
|
||||||
item: &hir::Item<'_>,
|
param_def_id: DefId,
|
||||||
) -> Option<&'tcx [ObjectLifetimeDefault]> {
|
) -> Option<ObjectLifetimeDefault> {
|
||||||
match item.kind {
|
let param_def_id = param_def_id.expect_local();
|
||||||
hir::ItemKind::Struct(_, ref generics)
|
let parent_def_id = tcx.local_parent(param_def_id);
|
||||||
| hir::ItemKind::Union(_, ref generics)
|
let generics = tcx.hir().get_generics(parent_def_id)?;
|
||||||
| hir::ItemKind::Enum(_, ref generics)
|
let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id);
|
||||||
| hir::ItemKind::OpaqueTy(hir::OpaqueTy {
|
let param = generics.params.iter().find(|p| p.hir_id == param_hir_id)?;
|
||||||
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.
|
// Scan the bounds and where-clauses on parameters to extract bounds
|
||||||
let attrs = tcx.hir().attrs(item.hir_id());
|
// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
|
||||||
if tcx.sess.contains_name(attrs, sym::rustc_object_lifetime_default) {
|
// for each type parameter.
|
||||||
let object_lifetime_default_reprs: String = result
|
match param.kind {
|
||||||
.iter()
|
GenericParamKind::Lifetime { .. } => None,
|
||||||
.map(|set| match *set {
|
GenericParamKind::Type { .. } => {
|
||||||
Set1::Empty => "BaseDefault".into(),
|
let mut set = Set1::Empty;
|
||||||
Set1::One(Region::Static) => "'static".into(),
|
|
||||||
Set1::One(Region::EarlyBound(mut i, _)) => generics
|
// Look for `type: ...` where clauses.
|
||||||
.params
|
for bound in generics.bounds_for_param(param_def_id) {
|
||||||
.iter()
|
// Ignore `for<'a> type: ...` as they can change what
|
||||||
.find_map(|param| match param.kind {
|
// lifetimes mean (although we could "just" handle it).
|
||||||
GenericParamKind::Lifetime { .. } => {
|
if !bound.bound_generic_params.is_empty() {
|
||||||
if i == 0 {
|
continue;
|
||||||
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)
|
for bound in bound.bounds {
|
||||||
}
|
|
||||||
_ => 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 {
|
if let hir::GenericBound::Outlives(ref lifetime) = *bound {
|
||||||
set.insert(lifetime.name.normalize_to_macros_2_0());
|
set.insert(lifetime.name.normalize_to_macros_2_0());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let process_param = |param: &hir::GenericParam<'_>| 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 };
|
|
||||||
|
|
||||||
// Ignore `for<'a> type: ...` as they can change what
|
|
||||||
// lifetimes mean (although we could "just" handle it).
|
|
||||||
if !data.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(match set {
|
Some(match set {
|
||||||
Set1::Empty => Set1::Empty,
|
Set1::Empty => ObjectLifetimeDefault::Empty,
|
||||||
Set1::One(name) => {
|
Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
|
||||||
if name == hir::LifetimeName::Static {
|
Set1::One(hir::LifetimeName::Param(param_def_id, _)) => {
|
||||||
Set1::One(Region::Static)
|
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
|
||||||
} 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,
|
_ => ObjectLifetimeDefault::Ambiguous,
|
||||||
})
|
|
||||||
.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::Many => Set1::Many,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
GenericParamKind::Const { .. } => {
|
GenericParamKind::Const { .. } => {
|
||||||
@ -1400,11 +1195,9 @@ fn object_lifetime_defaults_for_item<'tcx>(
|
|||||||
//
|
//
|
||||||
// We still store a dummy value here to allow generic parameters
|
// We still store a dummy value here to allow generic parameters
|
||||||
// in an arbitrary order.
|
// 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> {
|
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
@ -1413,20 +1206,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||||||
F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
|
F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
|
||||||
{
|
{
|
||||||
let LifetimeContext { tcx, map, .. } = self;
|
let LifetimeContext { tcx, map, .. } = self;
|
||||||
let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
|
|
||||||
let mut this = LifetimeContext {
|
let mut this = LifetimeContext {
|
||||||
tcx: *tcx,
|
tcx: *tcx,
|
||||||
map,
|
map,
|
||||||
scope: &wrap_scope,
|
scope: &wrap_scope,
|
||||||
trait_definition_only: self.trait_definition_only,
|
trait_definition_only: self.trait_definition_only,
|
||||||
xcrate_object_lifetime_defaults,
|
|
||||||
};
|
};
|
||||||
let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
|
let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
|
||||||
{
|
{
|
||||||
let _enter = span.enter();
|
let _enter = span.enter();
|
||||||
f(&mut this);
|
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`.
|
/// 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.
|
/// ordering is not important there.
|
||||||
fn visit_early_late<F>(
|
fn visit_early_late<F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
parent_id: Option<LocalDefId>,
|
|
||||||
hir_id: hir::HirId,
|
hir_id: hir::HirId,
|
||||||
generics: &'tcx hir::Generics<'tcx>,
|
generics: &'tcx hir::Generics<'tcx>,
|
||||||
walk: F,
|
walk: F,
|
||||||
) where
|
) where
|
||||||
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
|
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 mut named_late_bound_vars = 0;
|
||||||
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
|
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
|
||||||
.params
|
.params
|
||||||
@ -1484,16 +1256,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||||||
named_late_bound_vars += 1;
|
named_late_bound_vars += 1;
|
||||||
Some(Region::late(late_bound_idx, self.tcx.hir(), param))
|
Some(Region::late(late_bound_idx, self.tcx.hir(), param))
|
||||||
} else {
|
} else {
|
||||||
Some(Region::early(self.tcx.hir(), &mut next_early_index, param))
|
Some(Region::early(self.tcx.hir(), param))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
|
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
|
||||||
non_lifetime_count += 1;
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let next_early_index = next_early_index + non_lifetime_count;
|
|
||||||
|
|
||||||
let binders: Vec<_> = generics
|
let binders: Vec<_> = generics
|
||||||
.params
|
.params
|
||||||
@ -1512,51 +1280,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||||||
let scope = Scope::Binder {
|
let scope = Scope::Binder {
|
||||||
hir_id,
|
hir_id,
|
||||||
lifetimes,
|
lifetimes,
|
||||||
next_early_index,
|
|
||||||
s: self.scope,
|
s: self.scope,
|
||||||
opaque_type_parent: true,
|
|
||||||
scope_type: BinderScopeType::Normal,
|
scope_type: BinderScopeType::Normal,
|
||||||
where_bound_origin: None,
|
where_bound_origin: None,
|
||||||
};
|
};
|
||||||
self.with(scope, walk);
|
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))]
|
#[tracing::instrument(level = "debug", skip(self))]
|
||||||
fn resolve_lifetime_ref(
|
fn resolve_lifetime_ref(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -1679,17 +1409,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip(self))]
|
||||||
fn visit_segment_args(
|
fn visit_segment_args(
|
||||||
&mut self,
|
&mut self,
|
||||||
res: Res,
|
res: Res,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
generic_args: &'tcx hir::GenericArgs<'tcx>,
|
generic_args: &'tcx hir::GenericArgs<'tcx>,
|
||||||
) {
|
) {
|
||||||
debug!(
|
|
||||||
"visit_segment_args(res={:?}, depth={:?}, generic_args={:?})",
|
|
||||||
res, depth, generic_args,
|
|
||||||
);
|
|
||||||
|
|
||||||
if generic_args.parenthesized {
|
if generic_args.parenthesized {
|
||||||
self.visit_fn_like_elision(
|
self.visit_fn_like_elision(
|
||||||
generic_args.inputs(),
|
generic_args.inputs(),
|
||||||
@ -1707,13 +1433,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||||||
|
|
||||||
// Figure out if this is a type/trait segment,
|
// Figure out if this is a type/trait segment,
|
||||||
// which requires object lifetime defaults.
|
// 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 {
|
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::AssocTy, def_id) if depth == 1 => Some(self.tcx.parent(def_id)),
|
||||||
Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(parent_def_id(self, def_id)),
|
Res::Def(DefKind::Variant, def_id) if depth == 0 => Some(self.tcx.parent(def_id)),
|
||||||
Res::Def(
|
Res::Def(
|
||||||
DefKind::Struct
|
DefKind::Struct
|
||||||
| DefKind::Union
|
| DefKind::Union
|
||||||
@ -1725,7 +1447,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||||||
_ => None,
|
_ => 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,
|
// Compute a vector of defaults, one for each type parameter,
|
||||||
// per the rules given in RFCs 599 and 1156. Example:
|
// 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 map = &self.map;
|
||||||
let set_to_region = |set: &ObjectLifetimeDefault| match *set {
|
let generics = self.tcx.generics_of(def_id);
|
||||||
Set1::Empty => {
|
|
||||||
|
// `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 {
|
if in_body {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(Region::Static)
|
Some(Region::Static)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Set1::One(r) => {
|
ObjectLifetimeDefault::Static => Some(Region::Static),
|
||||||
let lifetimes = generic_args.args.iter().filter_map(|arg| match arg {
|
ObjectLifetimeDefault::Param(param_def_id) => {
|
||||||
GenericArg::Lifetime(lt) => Some(lt),
|
// 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,
|
_ => None,
|
||||||
});
|
})
|
||||||
r.subst(lifetimes, map)
|
|
||||||
}
|
}
|
||||||
Set1::Many => None,
|
ObjectLifetimeDefault::Ambiguous => None,
|
||||||
};
|
};
|
||||||
if let Some(def_id) = def_id.as_local() {
|
generics
|
||||||
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
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|param| match param.kind {
|
.filter_map(|param| self.tcx.object_lifetime_default(param.def_id))
|
||||||
GenericParamDefKind::Type { object_lifetime_default, .. } => {
|
|
||||||
Some(object_lifetime_default)
|
|
||||||
}
|
|
||||||
GenericParamDefKind::Const { .. } => Some(Set1::Empty),
|
|
||||||
GenericParamDefKind::Lifetime => None,
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.iter()
|
|
||||||
.map(set_to_region)
|
.map(set_to_region)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!("visit_segment_args: object_lifetime_defaults={:?}", object_lifetime_defaults);
|
debug!(?object_lifetime_defaults);
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
for arg in generic_args.args {
|
for arg in generic_args.args {
|
||||||
|
@ -222,9 +222,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
tcx.mk_region(ty::ReLateBound(debruijn, br))
|
tcx.mk_region(ty::ReLateBound(debruijn, br))
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(rl::Region::EarlyBound(index, id)) => {
|
Some(rl::Region::EarlyBound(def_id)) => {
|
||||||
let name = lifetime_name(id.expect_local());
|
let name = tcx.hir().ty_param_name(def_id.expect_local());
|
||||||
tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name }))
|
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)) => {
|
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);
|
debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r);
|
||||||
|
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2853,10 +2854,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if !infer_replacements.is_empty() {
|
if !infer_replacements.is_empty() {
|
||||||
diag.multipart_suggestion(&format!(
|
diag.multipart_suggestion(
|
||||||
|
&format!(
|
||||||
"try replacing `_` with the type{} in the corresponding trait method signature",
|
"try replacing `_` with the type{} in the corresponding trait method signature",
|
||||||
rustc_errors::pluralize!(infer_replacements.len()),
|
rustc_errors::pluralize!(infer_replacements.len()),
|
||||||
), infer_replacements, Applicability::MachineApplicable);
|
),
|
||||||
|
infer_replacements,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
diag.emit();
|
diag.emit();
|
||||||
|
@ -1617,7 +1617,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
|||||||
pure_wrt_drop: false,
|
pure_wrt_drop: false,
|
||||||
kind: ty::GenericParamDefKind::Type {
|
kind: ty::GenericParamDefKind::Type {
|
||||||
has_default: false,
|
has_default: false,
|
||||||
object_lifetime_default: rl::Set1::Empty,
|
|
||||||
synthetic: false,
|
synthetic: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -1661,8 +1660,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
|||||||
kind: ty::GenericParamDefKind::Lifetime,
|
kind: ty::GenericParamDefKind::Lifetime,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id.owner);
|
|
||||||
|
|
||||||
// Now create the real type and const parameters.
|
// Now create the real type and const parameters.
|
||||||
let type_start = own_start - has_self as u32 + params.len() as u32;
|
let type_start = own_start - has_self as u32 + params.len() as u32;
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
@ -1687,13 +1684,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let kind = ty::GenericParamDefKind::Type {
|
let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
|
||||||
has_default: default.is_some(),
|
|
||||||
object_lifetime_default: object_lifetime_defaults
|
|
||||||
.as_ref()
|
|
||||||
.map_or(rl::Set1::Empty, |o| o[i]),
|
|
||||||
synthetic,
|
|
||||||
};
|
|
||||||
|
|
||||||
let param_def = ty::GenericParamDef {
|
let param_def = ty::GenericParamDef {
|
||||||
index: type_start + i as u32,
|
index: type_start + i as u32,
|
||||||
@ -1745,11 +1736,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
|||||||
name: Symbol::intern(arg),
|
name: Symbol::intern(arg),
|
||||||
def_id,
|
def_id,
|
||||||
pure_wrt_drop: false,
|
pure_wrt_drop: false,
|
||||||
kind: ty::GenericParamDefKind::Type {
|
kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
|
||||||
has_default: false,
|
|
||||||
object_lifetime_default: rl::Set1::Empty,
|
|
||||||
synthetic: false,
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1762,11 +1749,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
|||||||
name: Symbol::intern("<const_ty>"),
|
name: Symbol::intern("<const_ty>"),
|
||||||
def_id,
|
def_id,
|
||||||
pure_wrt_drop: false,
|
pure_wrt_drop: false,
|
||||||
kind: ty::GenericParamDefKind::Type {
|
kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
|
||||||
has_default: false,
|
|
||||||
object_lifetime_default: rl::Set1::Empty,
|
|
||||||
synthetic: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ use crate::alloc::{Allocator, Global};
|
|||||||
use crate::raw_vec::RawVec;
|
use crate::raw_vec::RawVec;
|
||||||
use core::array;
|
use core::array;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::intrinsics::arith_offset;
|
|
||||||
use core::iter::{
|
use core::iter::{
|
||||||
FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
|
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
|
// purposefully don't use 'ptr.offset' because for
|
||||||
// vectors with 0-size elements this would return the
|
// vectors with 0-size elements this would return the
|
||||||
// same pointer.
|
// 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.
|
// Make up a value of this ZST.
|
||||||
Some(unsafe { mem::zeroed() })
|
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
|
// SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound
|
||||||
// effectively results in unsigned pointers representing positions 0..usize::MAX,
|
// effectively results in unsigned pointers representing positions 0..usize::MAX,
|
||||||
// which is valid for ZSTs.
|
// 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 {
|
} else {
|
||||||
// SAFETY: the min() above ensures that step_size is in bounds
|
// SAFETY: the min() above ensures that step_size is in bounds
|
||||||
self.ptr = unsafe { self.ptr.add(step_size) };
|
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) });
|
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
|
// Safety: ditto
|
||||||
return Ok(unsafe { MaybeUninit::array_assume_init(raw_ary) });
|
return Ok(unsafe { MaybeUninit::array_assume_init(raw_ary) });
|
||||||
}
|
}
|
||||||
@ -267,7 +266,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
|||||||
None
|
None
|
||||||
} else if mem::size_of::<T>() == 0 {
|
} else if mem::size_of::<T>() == 0 {
|
||||||
// See above for why 'ptr.offset' isn't used
|
// 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.
|
// Make up a value of this ZST.
|
||||||
Some(unsafe { mem::zeroed() })
|
Some(unsafe { mem::zeroed() })
|
||||||
@ -283,9 +282,7 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
|||||||
let step_size = self.len().min(n);
|
let step_size = self.len().min(n);
|
||||||
if mem::size_of::<T>() == 0 {
|
if mem::size_of::<T>() == 0 {
|
||||||
// SAFETY: same as for advance_by()
|
// SAFETY: same as for advance_by()
|
||||||
self.end = unsafe {
|
self.end = self.end.wrapping_byte_sub(step_size);
|
||||||
arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// SAFETY: same as for advance_by()
|
// SAFETY: same as for advance_by()
|
||||||
self.end = unsafe { self.end.sub(step_size) };
|
self.end = unsafe { self.end.sub(step_size) };
|
||||||
|
@ -59,7 +59,7 @@ use core::cmp::Ordering;
|
|||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
use core::intrinsics::{arith_offset, assume};
|
use core::intrinsics::assume;
|
||||||
use core::iter;
|
use core::iter;
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use core::iter::FromIterator;
|
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 alloc = ManuallyDrop::new(ptr::read(me.allocator()));
|
||||||
let begin = me.as_mut_ptr();
|
let begin = me.as_mut_ptr();
|
||||||
let end = if mem::size_of::<T>() == 0 {
|
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 {
|
} else {
|
||||||
begin.add(me.len()) as *const T
|
begin.add(me.len()) as *const T
|
||||||
};
|
};
|
||||||
|
@ -28,24 +28,14 @@ impl<'buf, 'state> PadAdapter<'buf, 'state> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Write for PadAdapter<'_, '_> {
|
impl fmt::Write for PadAdapter<'_, '_> {
|
||||||
fn write_str(&mut self, mut s: &str) -> fmt::Result {
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
while !s.is_empty() {
|
for s in s.split_inclusive('\n') {
|
||||||
if self.state.on_newline {
|
if self.state.on_newline {
|
||||||
self.buf.write_str(" ")?;
|
self.buf.write_str(" ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let split = match s.find('\n') {
|
self.state.on_newline = s.ends_with('\n');
|
||||||
Some(pos) => {
|
self.buf.write_str(s)?;
|
||||||
self.state.on_newline = true;
|
|
||||||
pos + 1
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
self.state.on_newline = false;
|
|
||||||
s.len()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.buf.write_str(&s[..split])?;
|
|
||||||
s = &s[split..];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -249,7 +249,7 @@ impl<T: ?Sized> *const T {
|
|||||||
let offset = dest_addr.wrapping_sub(self_addr);
|
let offset = dest_addr.wrapping_sub(self_addr);
|
||||||
|
|
||||||
// This is the canonical desugarring of this operation
|
// 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.
|
/// 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);
|
let offset = dest_addr.wrapping_sub(self_addr);
|
||||||
|
|
||||||
// This is the canonical desugarring of this operation
|
// 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.
|
/// 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()`.
|
// backwards by `n`. `n` must not exceed `self.len()`.
|
||||||
macro_rules! zst_shrink {
|
macro_rules! zst_shrink {
|
||||||
($self: ident, $n: ident) => {
|
($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.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1));
|
||||||
assert_eq!(atom.load(SeqCst), n);
|
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.fetch_byte_add(1, SeqCst), n);
|
||||||
assert_eq!(atom.load(SeqCst), bytes_from_n(1));
|
assert_eq!(atom.load(SeqCst), bytes_from_n(1));
|
||||||
|
@ -650,7 +650,7 @@ fn thin_box() {
|
|||||||
.unwrap_or_else(|| handle_alloc_error(layout))
|
.unwrap_or_else(|| handle_alloc_error(layout))
|
||||||
.cast::<DynMetadata<T>>();
|
.cast::<DynMetadata<T>>();
|
||||||
ptr.as_ptr().write(meta);
|
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 }
|
Self { ptr, phantom: PhantomData }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,6 +377,35 @@ impl File {
|
|||||||
OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
|
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.
|
/// Returns a new OpenOptions object.
|
||||||
///
|
///
|
||||||
/// This function returns a new OpenOptions object that you can use to
|
/// 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_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
|
||||||
TAG_CUSTOM => {
|
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),
|
// 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.
|
// 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))
|
ErrorData::Custom(make_custom(custom))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -1037,8 +1037,6 @@ pub trait Read {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// #![feature(io_read_to_string)]
|
|
||||||
///
|
|
||||||
/// # use std::io;
|
/// # use std::io;
|
||||||
/// fn main() -> io::Result<()> {
|
/// fn main() -> io::Result<()> {
|
||||||
/// let stdin = io::read_to_string(io::stdin())?;
|
/// let stdin = io::read_to_string(io::stdin())?;
|
||||||
@ -1047,7 +1045,7 @@ pub trait Read {
|
|||||||
/// Ok(())
|
/// 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> {
|
pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
reader.read_to_string(&mut buf)?;
|
reader.read_to_string(&mut buf)?;
|
||||||
|
@ -300,6 +300,7 @@
|
|||||||
#![feature(panic_can_unwind)]
|
#![feature(panic_can_unwind)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(panic_internals)]
|
#![feature(panic_internals)]
|
||||||
|
#![feature(pointer_byte_offsets)]
|
||||||
#![feature(pointer_is_aligned)]
|
#![feature(pointer_is_aligned)]
|
||||||
#![feature(portable_simd)]
|
#![feature(portable_simd)]
|
||||||
#![feature(prelude_2024)]
|
#![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 {
|
fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
|
||||||
let def = cx.tcx.named_region(lifetime.hir_id);
|
let def = cx.tcx.named_region(lifetime.hir_id);
|
||||||
if let Some(
|
if let Some(
|
||||||
rl::Region::EarlyBound(_, node_id)
|
rl::Region::EarlyBound(node_id)
|
||||||
| rl::Region::LateBound(_, _, node_id)
|
| rl::Region::LateBound(_, _, node_id)
|
||||||
| rl::Region::Free(_, node_id),
|
| rl::Region::Free(_, node_id),
|
||||||
) = def
|
) = 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)))]
|
#[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="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")]
|
#[rustc_clean(cfg="cfail6")]
|
||||||
enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
|
enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
|
||||||
Variant1(T),
|
Variant1(T),
|
||||||
@ -559,9 +559,9 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(cfail1,cfail4)))]
|
#[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="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")]
|
#[rustc_clean(cfg="cfail6")]
|
||||||
enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
|
enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
|
||||||
Variant1(T),
|
Variant1(T),
|
||||||
|
@ -1066,9 +1066,9 @@ trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
|
|||||||
trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { }
|
trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { }
|
||||||
|
|
||||||
#[cfg(not(any(cfail1,cfail4)))]
|
#[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(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")]
|
#[rustc_clean(cfg="cfail6")]
|
||||||
trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { }
|
trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { }
|
||||||
|
|
||||||
@ -1144,9 +1144,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + Refer
|
|||||||
trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { }
|
trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { }
|
||||||
|
|
||||||
#[cfg(not(any(cfail1,cfail4)))]
|
#[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(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")]
|
#[rustc_clean(cfg="cfail6")]
|
||||||
trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
|
trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
|
||||||
|
|
||||||
@ -1201,9 +1201,9 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0
|
|||||||
trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { }
|
trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { }
|
||||||
|
|
||||||
#[cfg(not(any(cfail1,cfail4)))]
|
#[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(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")]
|
#[rustc_clean(cfg="cfail6")]
|
||||||
trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { }
|
trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { }
|
||||||
|
|
||||||
@ -1254,9 +1254,9 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T>
|
|||||||
trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { }
|
trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { }
|
||||||
|
|
||||||
#[cfg(not(any(cfail1,cfail4)))]
|
#[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(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")]
|
#[rustc_clean(cfg="cfail6")]
|
||||||
trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { }
|
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
|
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
|
_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
|
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
|
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(_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
|
StorageDead(_4); // scope 2 at $DIR/mutable_variable_unprop_assign.rs:+6:1: +6:2
|
||||||
|
@ -94,4 +94,6 @@ tenth number: {}",
|
|||||||
// doesn't exist.
|
// doesn't exist.
|
||||||
println!("{:.*}");
|
println!("{:.*}");
|
||||||
//~^ ERROR 2 positional arguments in format string, but no arguments were given
|
//~^ 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: positional arguments are zero-based
|
||||||
= note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
|
= 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
|
error[E0425]: cannot find value `foo` in this scope
|
||||||
--> $DIR/ifmt-bad-arg.rs:27:18
|
--> $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)
|
= 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.
|
Some errors have detailed explanations: E0308, E0425.
|
||||||
For more information about an error, try `rustc --explain E0308`.
|
For more information about an error, try `rustc --explain E0308`.
|
||||||
|
Loading…
Reference in New Issue
Block a user