Auto merge of #94357 - matthiaskrgr:rollup-xrjaof3, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #93845 (Remove in band lifetimes) - #94155 (Extend toggle GUI test a bit) - #94252 (don't special case `DefKind::Ctor` in encoding) - #94305 (Remove an unnecessary restriction in `dest_prop`) - #94343 (Miri fn ptr check: don't use conservative null check) - #94344 (diagnostic: suggest parens when users want logical ops, but get closures) - #94352 (Fix SGX docs build) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
9f8f0a6e94
96 changed files with 386 additions and 1660 deletions
|
@ -142,13 +142,9 @@ struct LoweringContext<'a, 'hir: 'a> {
|
|||
/// indicate whether or not we're in a place where new lifetimes will result
|
||||
/// in in-band lifetime definitions, such a function or an impl header,
|
||||
/// including implicit lifetimes from `impl_header_lifetime_elision`.
|
||||
is_collecting_in_band_lifetimes: bool,
|
||||
is_collecting_anonymous_lifetimes: bool,
|
||||
|
||||
/// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
|
||||
/// When `is_collecting_in_band_lifetimes` is true, each lifetime is checked
|
||||
/// against this list to see if it is already in-scope, or if a definition
|
||||
/// needs to be created for it.
|
||||
///
|
||||
/// We always store a `normalize_to_macros_2_0()` version of the param-name in this
|
||||
/// vector.
|
||||
in_scope_lifetimes: Vec<ParamName>,
|
||||
|
@ -379,7 +375,7 @@ pub fn lower_crate<'a, 'hir>(
|
|||
task_context: None,
|
||||
current_item: None,
|
||||
lifetimes_to_define: Vec::new(),
|
||||
is_collecting_in_band_lifetimes: false,
|
||||
is_collecting_anonymous_lifetimes: false,
|
||||
in_scope_lifetimes: Vec::new(),
|
||||
allow_try_trait: Some([sym::try_trait_v2][..].into()),
|
||||
allow_gen_future: Some([sym::gen_future][..].into()),
|
||||
|
@ -726,13 +722,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> (Vec<(Span, ParamName)>, T) {
|
||||
let was_collecting = std::mem::replace(&mut self.is_collecting_in_band_lifetimes, true);
|
||||
let was_collecting = std::mem::replace(&mut self.is_collecting_anonymous_lifetimes, true);
|
||||
let len = self.lifetimes_to_define.len();
|
||||
|
||||
let res = f(self);
|
||||
|
||||
let lifetimes_to_define = self.lifetimes_to_define.split_off(len);
|
||||
self.is_collecting_in_band_lifetimes = was_collecting;
|
||||
self.is_collecting_anonymous_lifetimes = was_collecting;
|
||||
(lifetimes_to_define, res)
|
||||
}
|
||||
|
||||
|
@ -749,7 +745,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// that collisions are ok here and this shouldn't
|
||||
// really show up for end-user.
|
||||
let (str_name, kind) = match hir_name {
|
||||
ParamName::Plain(ident) => (ident.name, hir::LifetimeParamKind::InBand),
|
||||
ParamName::Plain(ident) => (ident.name, hir::LifetimeParamKind::Explicit),
|
||||
ParamName::Fresh(_) => (kw::UnderscoreLifetime, hir::LifetimeParamKind::Elided),
|
||||
ParamName::Error => (kw::UnderscoreLifetime, hir::LifetimeParamKind::Error),
|
||||
};
|
||||
|
@ -773,38 +769,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// When there is a reference to some lifetime `'a`, and in-band
|
||||
/// lifetimes are enabled, then we want to push that lifetime into
|
||||
/// the vector of names to define later. In that case, it will get
|
||||
/// added to the appropriate generics.
|
||||
fn maybe_collect_in_band_lifetime(&mut self, ident: Ident) {
|
||||
if !self.is_collecting_in_band_lifetimes {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.sess.features_untracked().in_band_lifetimes {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.in_scope_lifetimes.contains(&ParamName::Plain(ident.normalize_to_macros_2_0())) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hir_name = ParamName::Plain(ident);
|
||||
|
||||
if self.lifetimes_to_define.iter().any(|(_, lt_name)| {
|
||||
lt_name.normalize_to_macros_2_0() == hir_name.normalize_to_macros_2_0()
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.lifetimes_to_define.push((ident.span, hir_name));
|
||||
}
|
||||
|
||||
/// When we have either an elided or `'_` lifetime in an impl
|
||||
/// header, we convert it to an in-band lifetime.
|
||||
fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName {
|
||||
assert!(self.is_collecting_in_band_lifetimes);
|
||||
fn collect_fresh_anonymous_lifetime(&mut self, span: Span) -> ParamName {
|
||||
assert!(self.is_collecting_anonymous_lifetimes);
|
||||
let index = self.lifetimes_to_define.len() + self.in_scope_lifetimes.len();
|
||||
let hir_name = ParamName::Fresh(index);
|
||||
self.lifetimes_to_define.push((span, hir_name));
|
||||
|
@ -1946,7 +1914,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
ident if ident.name == kw::UnderscoreLifetime => match self.anonymous_lifetime_mode {
|
||||
AnonymousLifetimeMode::CreateParameter => {
|
||||
let fresh_name = self.collect_fresh_in_band_lifetime(span);
|
||||
let fresh_name = self.collect_fresh_anonymous_lifetime(span);
|
||||
self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(fresh_name))
|
||||
}
|
||||
|
||||
|
@ -1957,7 +1925,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span),
|
||||
},
|
||||
ident => {
|
||||
self.maybe_collect_in_band_lifetime(ident);
|
||||
let param_name = ParamName::Plain(self.lower_ident(ident));
|
||||
self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(param_name))
|
||||
}
|
||||
|
@ -2001,8 +1968,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
let (name, kind) = match param.kind {
|
||||
GenericParamKind::Lifetime => {
|
||||
let was_collecting_in_band = self.is_collecting_in_band_lifetimes;
|
||||
self.is_collecting_in_band_lifetimes = false;
|
||||
let was_collecting_in_band = self.is_collecting_anonymous_lifetimes;
|
||||
self.is_collecting_anonymous_lifetimes = false;
|
||||
|
||||
let lt = self
|
||||
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
|
||||
|
@ -2025,7 +1992,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let kind =
|
||||
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit };
|
||||
|
||||
self.is_collecting_in_band_lifetimes = was_collecting_in_band;
|
||||
self.is_collecting_anonymous_lifetimes = was_collecting_in_band;
|
||||
|
||||
(param_name, kind)
|
||||
}
|
||||
|
@ -2384,7 +2351,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh
|
||||
// `'f`.
|
||||
AnonymousLifetimeMode::CreateParameter => {
|
||||
let fresh_name = self.collect_fresh_in_band_lifetime(span);
|
||||
let fresh_name = self.collect_fresh_anonymous_lifetime(span);
|
||||
hir::Lifetime {
|
||||
hir_id: self.next_id(),
|
||||
span: self.lower_span(span),
|
||||
|
|
|
@ -217,8 +217,9 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
|||
// Comparisons of abstract pointers with null pointers are known if the pointer
|
||||
// is in bounds, because if they are in bounds, the pointer can't be null.
|
||||
// Inequality with integers other than null can never be known for sure.
|
||||
(Scalar::Int(int), Scalar::Ptr(ptr, _)) | (Scalar::Ptr(ptr, _), Scalar::Int(int)) => {
|
||||
int.is_null() && !self.memory.ptr_may_be_null(ptr.into())
|
||||
(Scalar::Int(int), ptr @ Scalar::Ptr(..))
|
||||
| (ptr @ Scalar::Ptr(..), Scalar::Int(int)) => {
|
||||
int.is_null() && !self.scalar_may_be_null(ptr)
|
||||
}
|
||||
// FIXME: return `true` for at least some comparisons where we can reliably
|
||||
// determine the result of runtime inequality tests at compile-time.
|
||||
|
|
|
@ -22,9 +22,9 @@ use rustc_span::{Pos, Span};
|
|||
use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};
|
||||
|
||||
use super::{
|
||||
AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
|
||||
MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance, Scalar,
|
||||
ScalarMaybeUninit, StackPopJump,
|
||||
AllocCheck, AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine,
|
||||
MemPlace, MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, Provenance,
|
||||
Scalar, ScalarMaybeUninit, StackPopJump,
|
||||
};
|
||||
use crate::transform::validate::equal_up_to_regions;
|
||||
|
||||
|
@ -440,6 +440,29 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
self.memory.scalar_to_ptr(scalar)
|
||||
}
|
||||
|
||||
/// Test if this value might be null.
|
||||
/// If the machine does not support ptr-to-int casts, this is conservative.
|
||||
pub fn scalar_may_be_null(&self, scalar: Scalar<M::PointerTag>) -> bool {
|
||||
match scalar.try_to_int() {
|
||||
Ok(int) => int.is_null(),
|
||||
Err(_) => {
|
||||
let ptr = self.scalar_to_ptr(scalar);
|
||||
match self.memory.ptr_try_get_alloc(ptr) {
|
||||
Ok((alloc_id, offset, _)) => {
|
||||
let (size, _align) = self
|
||||
.memory
|
||||
.get_size_and_align(alloc_id, AllocCheck::MaybeDead)
|
||||
.expect("alloc info with MaybeDead cannot fail");
|
||||
// If the pointer is out-of-bounds, it may be null.
|
||||
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
|
||||
offset > size
|
||||
}
|
||||
Err(offset) => offset == 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Call this to turn untagged "global" pointers (obtained via `tcx`) into
|
||||
/// the machine pointer to the allocation. Must never be used
|
||||
/// for any other pointers, nor for TLS statics.
|
||||
|
|
|
@ -483,21 +483,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Test if the pointer might be null.
|
||||
pub fn ptr_may_be_null(&self, ptr: Pointer<Option<M::PointerTag>>) -> bool {
|
||||
match self.ptr_try_get_alloc(ptr) {
|
||||
Ok((alloc_id, offset, _)) => {
|
||||
let (size, _align) = self
|
||||
.get_size_and_align(alloc_id, AllocCheck::MaybeDead)
|
||||
.expect("alloc info with MaybeDead cannot fail");
|
||||
// If the pointer is out-of-bounds, it may be null.
|
||||
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
|
||||
offset > size
|
||||
}
|
||||
Err(offset) => offset == 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocation accessors
|
||||
|
|
|
@ -720,12 +720,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Err(dbg_val) => {
|
||||
// So this is a pointer then, and casting to an int failed.
|
||||
// Can only happen during CTFE.
|
||||
let ptr = self.scalar_to_ptr(tag_val);
|
||||
// The niche must be just 0, and the ptr not null, then we know this is
|
||||
// okay. Everything else, we conservatively reject.
|
||||
let ptr_valid = niche_start == 0
|
||||
&& variants_start == variants_end
|
||||
&& !self.memory.ptr_may_be_null(ptr);
|
||||
&& !self.scalar_may_be_null(tag_val);
|
||||
if !ptr_valid {
|
||||
throw_ub!(InvalidTag(dbg_val))
|
||||
}
|
||||
|
|
|
@ -572,21 +572,25 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
|
||||
err_ub!(InvalidUninitBytes(None)) => { "uninitialized bytes" } expected { "a proper pointer or integer value" },
|
||||
);
|
||||
let ptr = self.ecx.scalar_to_ptr(value);
|
||||
// Ensure the pointer is non-null.
|
||||
if self.ecx.memory.ptr_may_be_null(ptr) {
|
||||
throw_validation_failure!(self.path, { "a potentially null function pointer" });
|
||||
}
|
||||
|
||||
// If we check references recursively, also check that this points to a function.
|
||||
if let Some(_) = self.ref_tracking {
|
||||
let ptr = self.ecx.scalar_to_ptr(value);
|
||||
let _fn = try_validation!(
|
||||
self.ecx.memory.get_fn(ptr),
|
||||
self.path,
|
||||
err_ub!(DanglingIntPointer(0, _)) =>
|
||||
{ "a null function pointer" },
|
||||
err_ub!(DanglingIntPointer(..)) |
|
||||
err_ub!(InvalidFunctionPointer(..)) =>
|
||||
{ "{:x}", value } expected { "a function pointer" },
|
||||
);
|
||||
// FIXME: Check if the signature matches
|
||||
} else {
|
||||
// Otherwise (for standalone Miri), we have to still check it to be non-null.
|
||||
if self.ecx.scalar_may_be_null(value) {
|
||||
throw_validation_failure!(self.path, { "a null function pointer" });
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
@ -644,10 +648,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
Err(_) => {
|
||||
// So this is a pointer then, and casting to an int failed.
|
||||
// Can only happen during CTFE.
|
||||
let ptr = self.ecx.scalar_to_ptr(value);
|
||||
if start == 1 && end == max_value {
|
||||
// Only null is the niche. So make sure the ptr is NOT null.
|
||||
if self.ecx.memory.ptr_may_be_null(ptr) {
|
||||
if self.ecx.scalar_may_be_null(value) {
|
||||
throw_validation_failure!(self.path,
|
||||
{ "a potentially null pointer" }
|
||||
expected {
|
||||
|
@ -758,7 +761,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
|||
fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
|
||||
trace!("visit_value: {:?}, {:?}", *op, op.layout);
|
||||
|
||||
// Check primitive types -- the leafs of our recursive descend.
|
||||
// Check primitive types -- the leaves of our recursive descent.
|
||||
if self.try_visit_primitive(op)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
In-band lifetimes cannot be used in `fn`/`Fn` syntax.
|
||||
|
||||
Erroneous code examples:
|
||||
|
||||
```compile_fail,E0687
|
||||
```ignore (feature got removed)
|
||||
#![feature(in_band_lifetimes)]
|
||||
|
||||
fn foo(x: fn(&'a u32)) {} // error!
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
In-band lifetimes were mixed with explicit lifetime binders.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0688
|
||||
```ignore (feature got removed)
|
||||
#![feature(in_band_lifetimes)]
|
||||
|
||||
fn foo<'a>(x: &'a u32, y: &'b u32) {} // error!
|
||||
|
|
|
@ -400,8 +400,6 @@ declare_features! (
|
|||
(active, if_let_guard, "1.47.0", Some(51114), None),
|
||||
/// Allows using imported `main` function
|
||||
(active, imported_main, "1.53.0", Some(28937), None),
|
||||
/// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`).
|
||||
(active, in_band_lifetimes, "1.23.0", Some(44524), None),
|
||||
/// Allows inferring `'static` outlives requirements (RFC 2093).
|
||||
(active, infer_static_outlives_requirements, "1.26.0", Some(54185), None),
|
||||
/// Allows associated types in inherent impls.
|
||||
|
|
|
@ -104,6 +104,9 @@ declare_features! (
|
|||
(removed, impl_trait_in_bindings, "1.55.0", Some(63065), None,
|
||||
Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")),
|
||||
(removed, import_shadowing, "1.0.0", None, None, None),
|
||||
/// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`).
|
||||
(removed, in_band_lifetimes, "1.23.0", Some(44524), None,
|
||||
Some("removed due to unsolved ergonomic questions and added lifetime resolution complexity")),
|
||||
/// Lazily evaluate constants. This allows constants to depend on type parameters.
|
||||
(removed, lazy_normalization_consts, "1.46.0", Some(72219), None, Some("superseded by `generic_const_exprs`")),
|
||||
/// Allows using the `#[link_args]` attribute.
|
||||
|
|
|
@ -471,11 +471,6 @@ pub enum LifetimeParamKind {
|
|||
// `fn foo<'a>(x: &'a u8) -> &'a u8 { x }`).
|
||||
Explicit,
|
||||
|
||||
// Indicates that the lifetime definition was synthetically added
|
||||
// as a result of an in-band lifetime usage (e.g., in
|
||||
// `fn foo(x: &'a u8) -> &'a u8 { x }`).
|
||||
InBand,
|
||||
|
||||
// Indication that the lifetime was elided (e.g., in both cases in
|
||||
// `fn foo(x: &u8) -> &'_ u8 { x }`).
|
||||
Elided,
|
||||
|
|
|
@ -125,7 +125,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
|||
// Find the index of the named region that was part of the
|
||||
// error. We will then search the function parameters for a bound
|
||||
// region at the right depth with the same index
|
||||
(Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
|
||||
(Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
|
||||
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
|
||||
if id == def_id {
|
||||
self.found_type = Some(arg);
|
||||
|
@ -137,7 +137,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
|||
// error. We will then search the function parameters for a bound
|
||||
// region at the right depth with the same index
|
||||
(
|
||||
Some(rl::Region::LateBound(debruijn_index, _, id, _)),
|
||||
Some(rl::Region::LateBound(debruijn_index, _, id)),
|
||||
ty::BrNamed(def_id, _),
|
||||
) => {
|
||||
debug!(
|
||||
|
@ -155,8 +155,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
|
|||
Some(
|
||||
rl::Region::Static
|
||||
| rl::Region::Free(_, _)
|
||||
| rl::Region::EarlyBound(_, _, _)
|
||||
| rl::Region::LateBound(_, _, _, _)
|
||||
| rl::Region::EarlyBound(_, _)
|
||||
| rl::Region::LateBound(_, _, _)
|
||||
| rl::Region::LateBoundAnon(_, _, _),
|
||||
)
|
||||
| None,
|
||||
|
@ -221,7 +221,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
(Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
|
||||
(Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
|
||||
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
|
||||
if id == def_id {
|
||||
self.found_it = true;
|
||||
|
@ -229,7 +229,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
(Some(rl::Region::LateBound(debruijn_index, _, id, _)), ty::BrNamed(def_id, _)) => {
|
||||
(Some(rl::Region::LateBound(debruijn_index, _, id)), ty::BrNamed(def_id, _)) => {
|
||||
debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,);
|
||||
debug!("id={:?}", id);
|
||||
debug!("def_id={:?}", def_id);
|
||||
|
@ -242,8 +242,8 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
|
|||
(
|
||||
Some(
|
||||
rl::Region::Static
|
||||
| rl::Region::EarlyBound(_, _, _)
|
||||
| rl::Region::LateBound(_, _, _, _)
|
||||
| rl::Region::EarlyBound(_, _)
|
||||
| rl::Region::LateBound(_, _, _)
|
||||
| rl::Region::LateBoundAnon(_, _, _)
|
||||
| rl::Region::Free(_, _),
|
||||
)
|
||||
|
|
|
@ -6,7 +6,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
|||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{
|
||||
CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE,
|
||||
};
|
||||
|
@ -983,12 +983,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
let def_id = local_id.to_def_id();
|
||||
let def_kind = tcx.opt_def_kind(local_id);
|
||||
let Some(def_kind) = def_kind else { continue };
|
||||
record!(self.tables.opt_def_kind[def_id] <- match def_kind {
|
||||
// Replace Ctor by the enclosing object to avoid leaking details in children crates.
|
||||
DefKind::Ctor(CtorOf::Struct, _) => DefKind::Struct,
|
||||
DefKind::Ctor(CtorOf::Variant, _) => DefKind::Variant,
|
||||
def_kind => def_kind,
|
||||
});
|
||||
record!(self.tables.opt_def_kind[def_id] <- def_kind);
|
||||
record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
|
||||
record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
|
||||
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
|
||||
|
|
|
@ -4,47 +4,14 @@ use crate::ty;
|
|||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{GenericParam, ItemLocalId};
|
||||
use rustc_hir::{GenericParamKind, LifetimeParamKind};
|
||||
use rustc_hir::ItemLocalId;
|
||||
use rustc_macros::HashStable;
|
||||
|
||||
/// The origin of a named lifetime definition.
|
||||
///
|
||||
/// This is used to prevent the usage of in-band lifetimes in `Fn`/`fn` syntax.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
|
||||
pub enum LifetimeDefOrigin {
|
||||
// Explicit binders like `fn foo<'a>(x: &'a u8)` or elided like `impl Foo<&u32>`
|
||||
ExplicitOrElided,
|
||||
// In-band declarations like `fn foo(x: &'a u8)`
|
||||
InBand,
|
||||
// Some kind of erroneous origin
|
||||
Error,
|
||||
}
|
||||
|
||||
impl LifetimeDefOrigin {
|
||||
pub fn from_param(param: &GenericParam<'_>) -> Self {
|
||||
match param.kind {
|
||||
GenericParamKind::Lifetime { kind } => match kind {
|
||||
LifetimeParamKind::InBand => LifetimeDefOrigin::InBand,
|
||||
LifetimeParamKind::Explicit => LifetimeDefOrigin::ExplicitOrElided,
|
||||
LifetimeParamKind::Elided => LifetimeDefOrigin::ExplicitOrElided,
|
||||
LifetimeParamKind::Error => LifetimeDefOrigin::Error,
|
||||
},
|
||||
_ => bug!("expected a lifetime param"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
|
||||
pub enum Region {
|
||||
Static,
|
||||
EarlyBound(/* index */ u32, /* lifetime decl */ DefId, LifetimeDefOrigin),
|
||||
LateBound(
|
||||
ty::DebruijnIndex,
|
||||
/* late-bound index */ u32,
|
||||
/* lifetime decl */ DefId,
|
||||
LifetimeDefOrigin,
|
||||
),
|
||||
EarlyBound(/* index */ u32, /* lifetime decl */ DefId),
|
||||
LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId),
|
||||
LateBoundAnon(ty::DebruijnIndex, /* late-bound index */ u32, /* anon index */ u32),
|
||||
Free(DefId, /* lifetime decl */ DefId),
|
||||
}
|
||||
|
|
|
@ -38,12 +38,6 @@
|
|||
//! It must also not contain any indexing projections, since those take an arbitrary `Local` as
|
||||
//! the index, and that local might only be initialized shortly before `dest` is used.
|
||||
//!
|
||||
//! Subtle case: If `dest` is a, or projects through a union, then we have to make sure that there
|
||||
//! remains an assignment to it, since that sets the "active field" of the union. But if `src` is
|
||||
//! a ZST, it might not be initialized, so there might not be any use of it before the assignment,
|
||||
//! and performing the optimization would simply delete the assignment, leaving `dest`
|
||||
//! uninitialized.
|
||||
//!
|
||||
//! * `src` must be a bare `Local` without any indirections or field projections (FIXME: Is this a
|
||||
//! fundamental restriction or just current impl state?). It can be copied or moved by the
|
||||
//! assignment.
|
||||
|
@ -103,7 +97,6 @@ use rustc_index::{
|
|||
bit_set::{BitMatrix, BitSet},
|
||||
vec::IndexVec,
|
||||
};
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{dump_mir, PassWhere};
|
||||
use rustc_middle::mir::{
|
||||
|
@ -135,7 +128,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
|
|||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let def_id = body.source.def_id();
|
||||
|
||||
let candidates = find_candidates(tcx, body);
|
||||
let candidates = find_candidates(body);
|
||||
if candidates.is_empty() {
|
||||
debug!("{:?}: no dest prop candidates, done", def_id);
|
||||
return;
|
||||
|
@ -803,9 +796,8 @@ struct CandidateAssignment<'tcx> {
|
|||
/// comment) and also throw out assignments that involve a local that has its address taken or is
|
||||
/// otherwise ineligible (eg. locals used as array indices are ignored because we cannot propagate
|
||||
/// arbitrary places into array indices).
|
||||
fn find_candidates<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> Vec<CandidateAssignment<'tcx>> {
|
||||
fn find_candidates<'tcx>(body: &Body<'tcx>) -> Vec<CandidateAssignment<'tcx>> {
|
||||
let mut visitor = FindAssignments {
|
||||
tcx,
|
||||
body,
|
||||
candidates: Vec::new(),
|
||||
ever_borrowed_locals: ever_borrowed_locals(body),
|
||||
|
@ -816,7 +808,6 @@ fn find_candidates<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> Vec<CandidateA
|
|||
}
|
||||
|
||||
struct FindAssignments<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
candidates: Vec<CandidateAssignment<'tcx>>,
|
||||
ever_borrowed_locals: BitSet<Local>,
|
||||
|
@ -845,10 +836,11 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
// Can't optimize if both locals ever have their address taken (can introduce
|
||||
// aliasing).
|
||||
// FIXME: This can be smarter and take `StorageDead` into account (which
|
||||
// invalidates borrows).
|
||||
// Can't optimize if either local ever has their address taken. This optimization does
|
||||
// liveness analysis only based on assignments, and a local can be live even if its
|
||||
// never assigned to again, because a reference to it might be live.
|
||||
// FIXME: This can be smarter and take `StorageDead` into account (which invalidates
|
||||
// borrows).
|
||||
if self.ever_borrowed_locals.contains(dest.local)
|
||||
|| self.ever_borrowed_locals.contains(src.local)
|
||||
{
|
||||
|
@ -862,22 +854,11 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
// Handle the "subtle case" described above by rejecting any `dest` that is or
|
||||
// projects through a union.
|
||||
let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty);
|
||||
if place_ty.ty.is_union() {
|
||||
return;
|
||||
}
|
||||
for elem in dest.projection {
|
||||
if let PlaceElem::Index(_) = elem {
|
||||
// `dest` contains an indexing projection.
|
||||
return;
|
||||
}
|
||||
|
||||
place_ty = place_ty.projection_ty(self.tcx, elem);
|
||||
if place_ty.ty.is_union() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.candidates.push(CandidateAssignment {
|
||||
|
|
|
@ -372,10 +372,17 @@ impl<'a> Parser<'a> {
|
|||
self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
|
||||
false
|
||||
}
|
||||
(true, Some(AssocOp::LAnd)) => {
|
||||
(true, Some(AssocOp::LAnd)) |
|
||||
(true, Some(AssocOp::LOr)) |
|
||||
(true, Some(AssocOp::BitOr)) => {
|
||||
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`. Separated from the
|
||||
// above due to #74233.
|
||||
// These cases are ambiguous and can't be identified in the parser alone.
|
||||
//
|
||||
// Bitwise AND is left out because guessing intent is hard. We can make
|
||||
// suggestions based on the assumption that double-refs are rarely intentional,
|
||||
// and closures are distinct enough that they don't get mixed up with their
|
||||
// return value.
|
||||
let sp = self.sess.source_map().start_point(self.token.span);
|
||||
self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span);
|
||||
false
|
||||
|
@ -1247,7 +1254,14 @@ impl<'a> Parser<'a> {
|
|||
} else if self.check(&token::OpenDelim(token::Brace)) {
|
||||
self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs)
|
||||
} else if self.check(&token::BinOp(token::Or)) || self.check(&token::OrOr) {
|
||||
self.parse_closure_expr(attrs)
|
||||
self.parse_closure_expr(attrs).map_err(|mut err| {
|
||||
// If the input is something like `if a { 1 } else { 2 } | if a { 3 } else { 4 }`
|
||||
// then suggest parens around the lhs.
|
||||
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&lo) {
|
||||
self.sess.expr_parentheses_needed(&mut err, *sp);
|
||||
}
|
||||
err
|
||||
})
|
||||
} else if self.check(&token::OpenDelim(token::Bracket)) {
|
||||
self.parse_array_or_repeat_expr(attrs, token::Bracket)
|
||||
} else if self.check_path() {
|
||||
|
|
|
@ -1838,7 +1838,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
|||
lifetime_ref
|
||||
);
|
||||
err.span_label(lifetime_ref.span, "undeclared lifetime");
|
||||
let mut suggests_in_band = false;
|
||||
let mut suggested_spans = vec![];
|
||||
for missing in &self.missing_named_lifetime_spots {
|
||||
match missing {
|
||||
|
@ -1854,7 +1853,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
|||
}) {
|
||||
(param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
|
||||
} else {
|
||||
suggests_in_band = true;
|
||||
(generics.span, format!("<{}>", lifetime_ref))
|
||||
};
|
||||
if suggested_spans.contains(&span) {
|
||||
|
@ -1889,15 +1887,6 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
if self.tcx.sess.is_nightly_build()
|
||||
&& !self.tcx.features().in_band_lifetimes
|
||||
&& suggests_in_band
|
||||
{
|
||||
err.help(
|
||||
"if you want to experiment with in-band lifetime bindings, \
|
||||
add `#![feature(in_band_lifetimes)]` to the crate attributes",
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// ignore-tidy-filelength
|
||||
//! Name resolution for lifetimes.
|
||||
//!
|
||||
//! Name resolution for lifetimes follows *much* simpler rules than the
|
||||
|
@ -16,7 +15,7 @@ use rustc_hir::def_id::{DefIdMap, LocalDefId};
|
|||
use rustc_hir::hir_id::ItemLocalId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath};
|
||||
use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind};
|
||||
use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::resolve_lifetime::*;
|
||||
|
@ -63,23 +62,18 @@ impl RegionExt for Region {
|
|||
let i = *index;
|
||||
*index += 1;
|
||||
let def_id = hir_map.local_def_id(param.hir_id);
|
||||
let origin = LifetimeDefOrigin::from_param(param);
|
||||
debug!("Region::early: index={} def_id={:?}", i, def_id);
|
||||
(param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id(), origin))
|
||||
(param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id()))
|
||||
}
|
||||
|
||||
fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) {
|
||||
let depth = ty::INNERMOST;
|
||||
let def_id = hir_map.local_def_id(param.hir_id);
|
||||
let origin = LifetimeDefOrigin::from_param(param);
|
||||
debug!(
|
||||
"Region::late: idx={:?}, param={:?} depth={:?} def_id={:?} origin={:?}",
|
||||
idx, param, depth, def_id, origin,
|
||||
"Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
|
||||
idx, param, depth, def_id,
|
||||
);
|
||||
(
|
||||
param.name.normalize_to_macros_2_0(),
|
||||
Region::LateBound(depth, idx, def_id.to_def_id(), origin),
|
||||
)
|
||||
(param.name.normalize_to_macros_2_0(), Region::LateBound(depth, idx, def_id.to_def_id()))
|
||||
}
|
||||
|
||||
fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region {
|
||||
|
@ -93,7 +87,7 @@ impl RegionExt for Region {
|
|||
match *self {
|
||||
Region::Static | Region::LateBoundAnon(..) => None,
|
||||
|
||||
Region::EarlyBound(_, id, _) | Region::LateBound(_, _, id, _) | Region::Free(_, id) => {
|
||||
Region::EarlyBound(_, id) | Region::LateBound(_, _, id) | Region::Free(_, id) => {
|
||||
Some(id)
|
||||
}
|
||||
}
|
||||
|
@ -101,8 +95,8 @@ impl RegionExt for Region {
|
|||
|
||||
fn shifted(self, amount: u32) -> Region {
|
||||
match self {
|
||||
Region::LateBound(debruijn, idx, id, origin) => {
|
||||
Region::LateBound(debruijn.shifted_in(amount), idx, id, origin)
|
||||
Region::LateBound(debruijn, idx, id) => {
|
||||
Region::LateBound(debruijn.shifted_in(amount), idx, id)
|
||||
}
|
||||
Region::LateBoundAnon(debruijn, index, anon_index) => {
|
||||
Region::LateBoundAnon(debruijn.shifted_in(amount), index, anon_index)
|
||||
|
@ -113,8 +107,8 @@ impl RegionExt for Region {
|
|||
|
||||
fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region {
|
||||
match self {
|
||||
Region::LateBound(debruijn, index, id, origin) => {
|
||||
Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id, origin)
|
||||
Region::LateBound(debruijn, index, id) => {
|
||||
Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id)
|
||||
}
|
||||
Region::LateBoundAnon(debruijn, index, anon_index) => {
|
||||
Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index, anon_index)
|
||||
|
@ -127,7 +121,7 @@ impl RegionExt for Region {
|
|||
where
|
||||
L: Iterator<Item = &'a hir::Lifetime>,
|
||||
{
|
||||
if let Region::EarlyBound(index, _, _) = self {
|
||||
if let Region::EarlyBound(index, _) = self {
|
||||
params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.hir_id).cloned())
|
||||
} else {
|
||||
Some(self)
|
||||
|
@ -568,7 +562,7 @@ fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool {
|
|||
|
||||
fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind {
|
||||
match region {
|
||||
Region::LateBound(_, _, def_id, _) => {
|
||||
Region::LateBound(_, _, def_id) => {
|
||||
let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local()));
|
||||
ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name))
|
||||
}
|
||||
|
@ -1010,7 +1004,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
// well-supported at the moment, so this doesn't work.
|
||||
// In the future, this should be fixed and this error should be removed.
|
||||
let def = self.map.defs.get(&lifetime.hir_id).cloned();
|
||||
let Some(Region::LateBound(_, _, def_id, _)) = def else {
|
||||
let Some(Region::LateBound(_, _, def_id)) = def else {
|
||||
continue
|
||||
};
|
||||
let Some(def_id) = def_id.as_local() else {
|
||||
|
@ -1046,7 +1040,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => {
|
||||
let (name, reg) = Region::early(self.tcx.hir(), &mut index, ¶m);
|
||||
let Region::EarlyBound(_, def_id, _) = reg else {
|
||||
let Region::EarlyBound(_, def_id) = reg else {
|
||||
bug!();
|
||||
};
|
||||
// We cannot predict what lifetimes are unused in opaque type.
|
||||
|
@ -1325,9 +1319,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
|
||||
if !self.trait_definition_only {
|
||||
check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params);
|
||||
}
|
||||
let scope = Scope::TraitRefBoundary { s: self.scope };
|
||||
self.with(scope, |_, this| {
|
||||
for param in generics.params {
|
||||
|
@ -1535,30 +1526,6 @@ impl ShadowKind {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_mixed_explicit_and_in_band_defs(tcx: TyCtxt<'_>, params: &[hir::GenericParam<'_>]) {
|
||||
let lifetime_params: Vec<_> = params
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { kind, .. } => Some((kind, param.span)),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let explicit = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::Explicit);
|
||||
let in_band = lifetime_params.iter().find(|(kind, _)| *kind == LifetimeParamKind::InBand);
|
||||
|
||||
if let (Some((_, explicit_span)), Some((_, in_band_span))) = (explicit, in_band) {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
*in_band_span,
|
||||
E0688,
|
||||
"cannot mix in-band and explicit lifetime definitions"
|
||||
)
|
||||
.span_label(*in_band_span, "in-band lifetime definition here")
|
||||
.span_label(*explicit_span, "explicit lifetime definition here")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn signal_shadowing_problem(tcx: TyCtxt<'_>, name: Symbol, orig: Original, shadower: Shadower) {
|
||||
let mut err = if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
|
||||
// lifetime/lifetime shadowing is an error
|
||||
|
@ -1696,7 +1663,7 @@ fn compute_object_lifetime_defaults<'tcx>(
|
|||
.map(|set| match *set {
|
||||
Set1::Empty => "BaseDefault".into(),
|
||||
Set1::One(Region::Static) => "'static".into(),
|
||||
Set1::One(Region::EarlyBound(mut i, _, _)) => generics
|
||||
Set1::One(Region::EarlyBound(mut i, _)) => generics
|
||||
.params
|
||||
.iter()
|
||||
.find_map(|param| match param.kind {
|
||||
|
@ -1777,18 +1744,16 @@ fn object_lifetime_defaults_for_item<'tcx>(
|
|||
.params
|
||||
.iter()
|
||||
.filter_map(|param| match param.kind {
|
||||
GenericParamKind::Lifetime { .. } => Some((
|
||||
param.hir_id,
|
||||
hir::LifetimeName::Param(param.name),
|
||||
LifetimeDefOrigin::from_param(param),
|
||||
)),
|
||||
GenericParamKind::Lifetime { .. } => {
|
||||
Some((param.hir_id, hir::LifetimeName::Param(param.name)))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.enumerate()
|
||||
.find(|&(_, (_, lt_name, _))| lt_name == name)
|
||||
.map_or(Set1::Many, |(i, (id, _, origin))| {
|
||||
.find(|&(_, (_, lt_name))| lt_name == name)
|
||||
.map_or(Set1::Many, |(i, (id, _))| {
|
||||
let def_id = tcx.hir().local_def_id(id);
|
||||
Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id(), origin))
|
||||
Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1846,13 +1811,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
fn lifetime_deletion_span(&self, name: Ident, generics: &hir::Generics<'_>) -> Option<Span> {
|
||||
generics.params.iter().enumerate().find_map(|(i, param)| {
|
||||
if param.name.ident() == name {
|
||||
let in_band = matches!(
|
||||
param.kind,
|
||||
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::InBand }
|
||||
);
|
||||
if in_band {
|
||||
Some(param.span)
|
||||
} else if generics.params.len() == 1 {
|
||||
if generics.params.len() == 1 {
|
||||
// if sole lifetime, remove the entire `<>` brackets
|
||||
Some(generics.span)
|
||||
} else {
|
||||
|
@ -1982,8 +1941,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
let def_ids: Vec<_> = defined_by
|
||||
.values()
|
||||
.flat_map(|region| match region {
|
||||
Region::EarlyBound(_, def_id, _)
|
||||
| Region::LateBound(_, _, def_id, _)
|
||||
Region::EarlyBound(_, def_id)
|
||||
| Region::LateBound(_, _, def_id)
|
||||
| Region::Free(_, def_id) => Some(*def_id),
|
||||
|
||||
Region::LateBoundAnon(..) | Region::Static => None,
|
||||
|
@ -2338,39 +2297,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Check for fn-syntax conflicts with in-band lifetime definitions
|
||||
if !self.trait_definition_only && self.is_in_fn_syntax {
|
||||
match def {
|
||||
Region::EarlyBound(_, _, LifetimeDefOrigin::InBand)
|
||||
| Region::LateBound(_, _, _, LifetimeDefOrigin::InBand) => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
lifetime_ref.span,
|
||||
E0687,
|
||||
"lifetimes used in `fn` or `Fn` syntax must be \
|
||||
explicitly declared using `<...>` binders"
|
||||
)
|
||||
.span_label(lifetime_ref.span, "in-band lifetime definition")
|
||||
.emit();
|
||||
}
|
||||
|
||||
Region::Static
|
||||
| Region::EarlyBound(
|
||||
_,
|
||||
_,
|
||||
LifetimeDefOrigin::ExplicitOrElided | LifetimeDefOrigin::Error,
|
||||
)
|
||||
| Region::LateBound(
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
LifetimeDefOrigin::ExplicitOrElided | LifetimeDefOrigin::Error,
|
||||
)
|
||||
| Region::LateBoundAnon(..)
|
||||
| Region::Free(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
self.insert_lifetime(lifetime_ref, def);
|
||||
} else {
|
||||
self.emit_undeclared_lifetime_error(lifetime_ref);
|
||||
|
@ -2950,7 +2876,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
|
||||
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
|
||||
match lifetime {
|
||||
Region::LateBound(debruijn, _, _, _)
|
||||
Region::LateBound(debruijn, _, _)
|
||||
| Region::LateBoundAnon(debruijn, _, _)
|
||||
if debruijn < self.outer_index =>
|
||||
{
|
||||
|
@ -3356,8 +3282,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
Region::Free(_, def_id)
|
||||
| Region::LateBound(_, _, def_id, _)
|
||||
| Region::EarlyBound(_, def_id, _) => {
|
||||
| Region::LateBound(_, _, def_id)
|
||||
| Region::EarlyBound(_, def_id) => {
|
||||
// A lifetime declared by the user.
|
||||
let track_lifetime_uses = self.track_lifetime_uses();
|
||||
debug!(?track_lifetime_uses);
|
||||
|
|
|
@ -205,7 +205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let r = match tcx.named_region(lifetime.hir_id) {
|
||||
Some(rl::Region::Static) => tcx.lifetimes.re_static,
|
||||
|
||||
Some(rl::Region::LateBound(debruijn, index, def_id, _)) => {
|
||||
Some(rl::Region::LateBound(debruijn, index, def_id)) => {
|
||||
let name = lifetime_name(def_id.expect_local());
|
||||
let br = ty::BoundRegion {
|
||||
var: ty::BoundVar::from_u32(index),
|
||||
|
@ -222,7 +222,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
tcx.mk_region(ty::ReLateBound(debruijn, br))
|
||||
}
|
||||
|
||||
Some(rl::Region::EarlyBound(index, id, _)) => {
|
||||
Some(rl::Region::EarlyBound(index, id)) => {
|
||||
let name = lifetime_name(id.expect_local());
|
||||
tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: id, index, name }))
|
||||
}
|
||||
|
|
|
@ -1377,7 +1377,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||
match self.tcx.named_region(lt.hir_id) {
|
||||
Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
|
||||
Some(
|
||||
rl::Region::LateBound(debruijn, _, _, _)
|
||||
rl::Region::LateBound(debruijn, _, _)
|
||||
| rl::Region::LateBoundAnon(debruijn, _, _),
|
||||
) if debruijn < self.outer_index => {}
|
||||
Some(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue