Auto merge of #84440 - Dylan-DPC:rollup-0xjb8oi, r=Dylan-DPC

Rollup of 7 pull requests

Successful merges:

 - #84343 (Remove `ScopeTree::closure_tree`)
 - #84376 (Uses flex to fix formatting of h1 at any width)
 - #84377 (Followup to #83944)
 - #84396 (Update LLVM submodule)
 - #84402 (Move `sys_common::rwlock::StaticRWLock` etc. to `sys::unix::rwlock`)
 - #84404 (Check for intrinsics before coercing to a function pointer)
 - #84413 (Remove `sys::args::Args::inner_debug` and use `Debug` instead)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2021-04-22 18:17:23 +00:00
commit 5f1aeb52c2
21 changed files with 370 additions and 565 deletions

View File

@ -1213,8 +1213,41 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
deny_equality_constraints(self, predicate, generics);
}
}
walk_list!(self, visit_generic_param, &generics.params);
for predicate in &generics.where_clause.predicates {
match predicate {
WherePredicate::BoundPredicate(bound_pred) => {
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
visit::walk_generics(self, generics)
// This is slightly complicated. Our representation for poly-trait-refs contains a single
// binder and thus we only allow a single level of quantification. However,
// the syntax of Rust permits quantification in two places in where clauses,
// e.g., `T: for <'a> Foo<'a>` and `for <'a, 'b> &'b T: Foo<'a>`. If both are
// defined, then error.
if !bound_pred.bound_generic_params.is_empty() {
for bound in &bound_pred.bounds {
match bound {
GenericBound::Trait(t, _) => {
if !t.bound_generic_params.is_empty() {
struct_span_err!(
self.err_handler(),
t.span,
E0316,
"nested quantification of lifetimes"
)
.emit();
}
}
GenericBound::Outlives(_) => {}
}
}
}
}
_ => {}
}
self.visit_where_predicate(predicate);
}
}
fn visit_generic_param(&mut self, param: &'a GenericParam) {
@ -1263,14 +1296,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
visit::walk_pat(self, pat)
}
fn visit_where_predicate(&mut self, p: &'a WherePredicate) {
if let &WherePredicate::BoundPredicate(ref bound_predicate) = p {
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
self.check_late_bound_lifetime_defs(&bound_predicate.bound_generic_params);
}
visit::walk_where_predicate(self, p);
}
fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
visit::walk_poly_trait_ref(self, t, m);

View File

@ -235,18 +235,6 @@ pub struct ScopeTree {
/// escape into 'static and should have no local cleanup scope.
rvalue_scopes: FxHashMap<hir::ItemLocalId, Option<Scope>>,
/// Encodes the hierarchy of fn bodies. Every fn body (including
/// closures) forms its own distinct region hierarchy, rooted in
/// the block that is the fn body. This map points from the ID of
/// that root block to the ID of the root block for the enclosing
/// fn, if any. Thus the map structures the fn bodies into a
/// hierarchy based on their lexical mapping. This is used to
/// handle the relationships between regions in a fn and in a
/// closure defined by that fn. See the "Modeling closures"
/// section of the README in infer::region_constraints for
/// more details.
closure_tree: FxHashMap<hir::ItemLocalId, hir::ItemLocalId>,
/// If there are any `yield` nested within a scope, this map
/// stores the `Span` of the last one and its index in the
/// postorder of the Visitor traversal on the HIR.
@ -356,23 +344,6 @@ impl ScopeTree {
self.destruction_scopes.get(&n).cloned()
}
/// Records that `sub_closure` is defined within `sup_closure`. These IDs
/// should be the ID of the block that is the fn body, which is
/// also the root of the region hierarchy for that fn.
pub fn record_closure_parent(
&mut self,
sub_closure: hir::ItemLocalId,
sup_closure: hir::ItemLocalId,
) {
debug!(
"record_closure_parent(sub_closure={:?}, sup_closure={:?})",
sub_closure, sup_closure
);
assert!(sub_closure != sup_closure);
let previous = self.closure_tree.insert(sub_closure, sup_closure);
assert!(previous.is_none());
}
pub fn record_var_scope(&mut self, var: hir::ItemLocalId, lifetime: Scope) {
debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
assert!(var != lifetime.item_local_id());
@ -474,7 +445,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
ref var_map,
ref destruction_scopes,
ref rvalue_scopes,
ref closure_tree,
ref yield_in_scope,
} = *self;
@ -488,7 +458,6 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
var_map.hash_stable(hcx, hasher);
destruction_scopes.hash_stable(hcx, hasher);
rvalue_scopes.hash_stable(hcx, hasher);
closure_tree.hash_stable(hcx, hasher);
yield_in_scope.hash_stable(hcx, hasher);
}
}

View File

@ -23,14 +23,6 @@ use std::mem;
#[derive(Debug, Copy, Clone)]
pub struct Context {
/// The root of the current region tree. This is typically the id
/// of the innermost fn body. Each fn forms its own disjoint tree
/// in the region hierarchy. These fn bodies are themselves
/// arranged into a tree. See the "Modeling closures" section of
/// the README in `rustc_trait_selection::infer::region_constraints`
/// for more details.
root_id: Option<hir::ItemLocalId>,
/// The scope that contains any new variables declared, plus its depth in
/// the scope tree.
var_parent: Option<(Scope, ScopeDepth)>,
@ -743,11 +735,6 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
let outer_pessimistic_yield = mem::replace(&mut self.pessimistic_yield, false);
self.terminating_scopes.insert(body.value.hir_id.local_id);
if let Some(root_id) = self.cx.root_id {
self.scope_tree.record_closure_parent(body.value.hir_id.local_id, root_id);
}
self.cx.root_id = Some(body.value.hir_id.local_id);
self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::CallSite });
self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::Arguments });
@ -824,7 +811,7 @@ fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
tcx,
scope_tree: ScopeTree::default(),
expr_and_pat_count: 0,
cx: Context { root_id: None, parent: None, var_parent: None },
cx: Context { parent: None, var_parent: None },
terminating_scopes: Default::default(),
pessimistic_yield: false,
fixup_scopes: vec![],

View File

@ -165,29 +165,6 @@ crate struct LifetimeContext<'a, 'tcx> {
map: &'a mut NamedRegionMap,
scope: ScopeRef<'a>,
/// This is slightly complicated. Our representation for poly-trait-refs contains a single
/// binder and thus we only allow a single level of quantification. However,
/// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
/// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the De Bruijn indices
/// correct when representing these constraints, we should only introduce one
/// scope. However, we want to support both locations for the quantifier and
/// during lifetime resolution we want precise information (so we can't
/// desugar in an earlier phase). Moreso, an error here doesn't cause a bail
/// from type checking, so we need to be extra careful that we don't lose
/// any bound var information.
///
/// So, if we encounter a quantifier at the outer scope, we set
/// `trait_ref_hack` to the hir id of the bounded type (and introduce a scope).
/// Then, if we encounter a quantifier at the inner scope, then we know to
/// emit an error. Importantly though, we do have to track the lifetimes
/// defined on the outer scope (i.e. the bounded ty), since we continue
/// to type check after emitting an error; we therefore assume that the bound
/// vars on the inner trait refs come from both quantifiers.
///
/// If we encounter a quantifier in the inner scope `trait_ref_hack` being
/// `None`, then we just introduce the scope at the inner quantifier as normal.
trait_ref_hack: Option<hir::HirId>,
/// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
is_in_fn_syntax: bool,
@ -244,10 +221,7 @@ enum Scope<'a> {
/// of the resulting opaque type.
opaque_type_parent: bool,
/// True only if this `Binder` scope is from the quantifiers on a
/// `PolyTraitRef`. This is necessary for `associated_type_bounds`, which
/// requires binders of nested trait refs to be merged.
from_poly_trait_ref: bool,
scope_type: BinderScopeType,
/// The late bound vars for a given item are stored by `HirId` to be
/// queried later. However, if we enter an elision scope, we have to
@ -282,41 +256,6 @@ enum Scope<'a> {
s: ScopeRef<'a>,
},
/// This is a particularly interesting consequence of how we handle poly
/// trait refs. See `trait_ref_hack` for additional info. This bit is
/// important w.r.t. querying late-bound vars.
///
/// To completely understand why this is necessary, first it's important to
/// realize that `T: for<'a> U + for<'a, 'b> V` is actually two separate
/// trait refs: `T: for<'a> U` and `T: for<'b> V` and as such, the late
/// bound vars on each needs to be tracked separately. Also, in this case,
/// are *three* relevant `HirId`s: one for the entire bound and one
/// for each separate one.
///
/// Next, imagine three different poly trait refs:
/// 1) `for<'a, 'b> T: U<'a, 'b>`
/// 2) `T: for<'a, 'b> U<'a, 'b>`
/// 3) `for<'a> T: for<'b> U<'a, 'b>`
///
/// First, note that the third example is semantically invalid and an error,
/// but we *must* handle it as valid, since type checking isn't bailed out
/// of. Other than that, if ask for bound vars for each, we expect
/// `['a, 'b]`. If we *didn't* allow binders before `T`, then we would
/// always introduce a binder scope at the inner trait ref. This is great,
/// because later on during type-checking, we will ask "what are the late
/// bound vars on this trait ref". However, because we allow bound vars on
/// the bound itself, we have to have some way of keeping track of the fact
/// that we actually want to store the late bound vars as being associated
/// with the trait ref; this is that.
///
/// One alternative way to handle this would be to just introduce a new
/// `Binder` scope, but that's semantically a bit different, since bound
/// vars from both `for<...>`s *do* share the same binder level.
TraitRefHackInner {
hir_id: hir::HirId,
s: ScopeRef<'a>,
},
/// When we have nested trait refs, we concanetate late bound vars for inner
/// trait refs from outer ones. But we also need to include any HRTB
/// lifetimes encountered when identifying the trait that an associated type
@ -333,6 +272,22 @@ enum Scope<'a> {
Root,
}
#[derive(Copy, Clone, Debug)]
enum BinderScopeType {
/// Any non-concatenating binder scopes.
Normal,
/// Within a syntactic trait ref, there may be multiple poly trait refs that
/// are nested (under the `associcated_type_bounds` feature). The binders of
/// the innner poly trait refs are extended from the outer poly trait refs
/// and don't increase the late bound depth. If you had
/// `T: for<'a> Foo<Bar: for<'b> Baz<'a, 'b>>`, then the `for<'b>` scope
/// would be `Concatenating`. This also used in trait refs in where clauses
/// where we have two binders `for<> T: for<> Foo` (I've intentionally left
/// out any lifetimes because they aren't needed to show the two scopes).
/// The inner `for<>` has a scope of `Concatenating`.
Concatenating,
}
// A helper struct for debugging scopes without printing parent scopes
struct TruncatedScopeDebug<'a>(&'a Scope<'a>);
@ -344,7 +299,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
next_early_index,
track_lifetime_uses,
opaque_type_parent,
from_poly_trait_ref,
scope_type,
hir_id,
s: _,
} => f
@ -353,7 +308,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
.field("next_early_index", next_early_index)
.field("track_lifetime_uses", track_lifetime_uses)
.field("opaque_type_parent", opaque_type_parent)
.field("from_poly_trait_ref", from_poly_trait_ref)
.field("scope_type", scope_type)
.field("hir_id", hir_id)
.field("s", &"..")
.finish(),
@ -368,11 +323,6 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
.field("lifetime", lifetime)
.field("s", &"..")
.finish(),
Scope::TraitRefHackInner { hir_id, s: _ } => f
.debug_struct("TraitRefHackInner")
.field("hir_id", hir_id)
.field("s", &"..")
.finish(),
Scope::Supertrait { lifetimes, s: _ } => f
.debug_struct("Supertrait")
.field("lifetimes", lifetimes)
@ -495,7 +445,6 @@ fn do_resolve(
tcx,
map: &mut named_region_map,
scope: ROOT_SCOPE,
trait_ref_hack: None,
is_in_fn_syntax: false,
is_in_const_generic: false,
trait_definition_only,
@ -618,6 +567,43 @@ fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::
}
}
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
/// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref.
fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderScopeType) {
let mut scope = self.scope;
let mut supertrait_lifetimes = vec![];
loop {
match scope {
Scope::Body { .. } | Scope::Root => {
break (vec![], BinderScopeType::Normal);
}
Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => {
scope = s;
}
Scope::Supertrait { s, lifetimes } => {
supertrait_lifetimes = lifetimes.clone();
scope = s;
}
Scope::TraitRefBoundary { .. } => {
// We should only see super trait lifetimes if there is a `Binder` above
assert!(supertrait_lifetimes.is_empty());
break (vec![], BinderScopeType::Normal);
}
Scope::Binder { hir_id, .. } => {
// Nested poly trait refs have the binders concatenated
let mut full_binders =
self.map.late_bound_vars.entry(*hir_id).or_default().clone();
full_binders.extend(supertrait_lifetimes.into_iter());
break (full_binders, BinderScopeType::Concatenating);
}
}
}
}
}
impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
type Map = Map<'tcx>;
@ -675,7 +661,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
s: self.scope,
track_lifetime_uses: true,
opaque_type_parent: false,
from_poly_trait_ref: false,
scope_type: BinderScopeType::Normal,
};
self.with(scope, move |_old_scope, this| {
intravisit::walk_fn(this, fk, fd, b, s, hir_id)
@ -800,12 +786,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
next_early_index: index + non_lifetime_count,
opaque_type_parent: true,
track_lifetime_uses,
from_poly_trait_ref: false,
scope_type: BinderScopeType::Normal,
s: ROOT_SCOPE,
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
intravisit::walk_item(this, item);
let scope = Scope::TraitRefBoundary { s: this.scope };
this.with(scope, |_, this| {
intravisit::walk_item(this, item);
});
});
self.missing_named_lifetime_spots.pop();
}
@ -869,7 +858,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
next_early_index,
track_lifetime_uses: true,
opaque_type_parent: false,
from_poly_trait_ref: false,
scope_type: BinderScopeType::Normal,
};
self.with(scope, |old_scope, this| {
// a bare fn has no bounds, so everything
@ -939,9 +928,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// Elided lifetimes are not allowed in non-return
// position impl Trait
let scope = Scope::Elision { elide: Elide::Forbid, s: self.scope };
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |_, this| {
intravisit::walk_item(this, opaque_ty);
let scope = Scope::Elision { elide: Elide::Forbid, s: this.scope };
this.with(scope, |_, this| {
intravisit::walk_item(this, opaque_ty);
})
});
return;
@ -1062,7 +1054,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
s: this.scope,
track_lifetime_uses: true,
opaque_type_parent: false,
from_poly_trait_ref: false,
scope_type: BinderScopeType::Normal,
};
this.with(scope, |_old_scope, this| {
this.visit_generics(generics);
@ -1082,7 +1074,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
s: self.scope,
track_lifetime_uses: true,
opaque_type_parent: false,
from_poly_trait_ref: false,
scope_type: BinderScopeType::Normal,
};
self.with(scope, |_old_scope, this| {
let scope = Scope::TraitRefBoundary { s: this.scope };
@ -1141,7 +1133,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
s: self.scope,
track_lifetime_uses: true,
opaque_type_parent: true,
from_poly_trait_ref: false,
scope_type: BinderScopeType::Normal,
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
@ -1210,7 +1202,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
s: self.scope,
track_lifetime_uses: true,
opaque_type_parent: true,
from_poly_trait_ref: false,
scope_type: BinderScopeType::Normal,
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
@ -1270,98 +1262,102 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
if !self.trait_definition_only {
check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params);
}
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { ref default, .. } => {
walk_list!(self, visit_param_bound, param.bounds);
if let Some(ref ty) = default {
self.visit_ty(&ty);
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |_, this| {
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { ref default, .. } => {
walk_list!(this, visit_param_bound, param.bounds);
if let Some(ref ty) = default {
this.visit_ty(&ty);
}
}
GenericParamKind::Const { ref ty, .. } => {
let was_in_const_generic = this.is_in_const_generic;
this.is_in_const_generic = true;
walk_list!(this, visit_param_bound, param.bounds);
this.visit_ty(&ty);
this.is_in_const_generic = was_in_const_generic;
}
}
GenericParamKind::Const { ref ty, .. } => {
let was_in_const_generic = self.is_in_const_generic;
self.is_in_const_generic = true;
walk_list!(self, visit_param_bound, param.bounds);
self.visit_ty(&ty);
self.is_in_const_generic = was_in_const_generic;
}
}
}
for predicate in generics.where_clause.predicates {
match predicate {
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
ref bounded_ty,
bounds,
ref bound_generic_params,
..
}) => {
let (lifetimes, binders): (FxHashMap<hir::ParamName, Region>, Vec<_>) =
bound_generic_params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(param),
_ => None,
})
.enumerate()
.map(|(late_bound_idx, param)| {
let pair =
Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
(pair, r)
})
.unzip();
self.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone());
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |_, this| {
if !lifetimes.is_empty() {
let next_early_index = this.next_early_index();
let scope = Scope::Binder {
hir_id: bounded_ty.hir_id,
lifetimes,
s: this.scope,
next_early_index,
track_lifetime_uses: true,
opaque_type_parent: false,
from_poly_trait_ref: true,
};
this.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &bound_generic_params);
this.visit_ty(&bounded_ty);
this.trait_ref_hack = Some(bounded_ty.hir_id);
walk_list!(this, visit_param_bound, bounds);
this.trait_ref_hack = None;
})
} else {
for predicate in generics.where_clause.predicates {
match predicate {
&hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
ref bounded_ty,
bounds,
ref bound_generic_params,
..
}) => {
let (lifetimes, binders): (FxHashMap<hir::ParamName, Region>, Vec<_>) =
bound_generic_params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(param),
_ => None,
})
.enumerate()
.map(|(late_bound_idx, param)| {
let pair =
Region::late(late_bound_idx as u32, &this.tcx.hir(), param);
let r = late_region_as_bound_region(this.tcx, &pair.1);
(pair, r)
})
.unzip();
this.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone());
let next_early_index = this.next_early_index();
// Even if there are no lifetimes defined here, we still wrap it in a binder
// scope. If there happens to be a nested poly trait ref (an error), that
// will be `Concatenating` anyways, so we don't have to worry about the depth
// being wrong.
let scope = Scope::Binder {
hir_id: bounded_ty.hir_id,
lifetimes,
s: this.scope,
next_early_index,
track_lifetime_uses: true,
opaque_type_parent: false,
scope_type: BinderScopeType::Normal,
};
this.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &bound_generic_params);
this.visit_ty(&bounded_ty);
walk_list!(this, visit_param_bound, bounds);
}
})
}
&hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
ref lifetime,
bounds,
..
}) => {
self.visit_lifetime(lifetime);
walk_list!(self, visit_param_bound, bounds);
}
&hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
ref lhs_ty,
ref rhs_ty,
..
}) => {
self.visit_ty(lhs_ty);
self.visit_ty(rhs_ty);
})
}
&hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
ref lifetime,
bounds,
..
}) => {
this.visit_lifetime(lifetime);
walk_list!(this, visit_param_bound, bounds);
}
&hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
ref lhs_ty,
ref rhs_ty,
..
}) => {
this.visit_ty(lhs_ty);
this.visit_ty(rhs_ty);
}
}
}
}
})
}
fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) {
match bound {
hir::GenericBound::LangItemTrait(_, _, hir_id, _) if self.trait_ref_hack.is_none() => {
self.map.late_bound_vars.insert(*hir_id, vec![]);
hir::GenericBound::LangItemTrait(_, _, hir_id, _) => {
// FIXME(jackh726): This is pretty weird. `LangItemTrait` doesn't go
// through the regular poly trait ref code, so we don't get another
// chance to introduce a binder. For now, I'm keeping the existing logic
// of "if there isn't a Binder scope above us, add one", but I
// imagine there's a better way to go about this.
let (binders, scope_type) = self.poly_trait_ref_binder_info();
self.map.late_bound_vars.insert(*hir_id, binders);
let scope = Scope::Binder {
hir_id: *hir_id,
lifetimes: FxHashMap::default(),
@ -1369,7 +1365,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
next_early_index: self.next_early_index(),
track_lifetime_uses: true,
opaque_type_parent: false,
from_poly_trait_ref: false,
scope_type,
};
self.with(scope, |_, this| {
intravisit::walk_param_bound(this, bound);
@ -1388,148 +1384,53 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref);
let trait_ref_hack = self.trait_ref_hack.take();
let next_early_index = self.next_early_index();
// See note on `trait_ref_hack`. If `for<..>` has been defined in both
// the outer and inner part of the trait ref, emit an error.
let has_lifetimes = trait_ref.bound_generic_params.iter().any(|param| match param.kind {
GenericParamKind::Lifetime { .. } => true,
_ => false,
});
if trait_ref_hack.is_some() && has_lifetimes {
struct_span_err!(
self.tcx.sess,
trait_ref.span,
E0316,
"nested quantification of lifetimes"
)
.emit();
}
let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
let (binders, lifetimes) = if let Some(hir_id) = trait_ref_hack {
let mut binders = self.map.late_bound_vars.entry(hir_id).or_default().clone();
let initial_bound_vars = binders.len() as u32;
let mut lifetimes: FxHashMap<hir::ParamName, Region> = FxHashMap::default();
let binders_iter = trait_ref
.bound_generic_params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(param),
_ => None,
})
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(
initial_bound_vars + late_bound_idx as u32,
&self.tcx.hir(),
param,
);
let r = late_region_as_bound_region(self.tcx, &pair.1);
lifetimes.insert(pair.0, pair.1);
r
});
binders.extend(binders_iter);
(binders, lifetimes)
} else {
let mut supertrait_lifetimes = vec![];
let mut scope = self.scope;
let mut outer_binders = loop {
match scope {
Scope::Body { .. } | Scope::Root => {
break vec![];
}
Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => {
scope = s;
}
Scope::TraitRefHackInner { hir_id, .. } => {
// Nested poly trait refs have the binders concatenated
// If we reach `TraitRefHackInner`, then there is only one more `Binder` above us,
// over all the bounds. We don't want this, since all the lifetimes we care about
// are here anyways.
let mut full_binders =
self.map.late_bound_vars.entry(*hir_id).or_default().clone();
full_binders.extend(supertrait_lifetimes.into_iter());
break full_binders;
}
Scope::Supertrait { s, lifetimes } => {
supertrait_lifetimes = lifetimes.clone();
scope = s;
}
Scope::TraitRefBoundary { .. } => {
// We should only see super trait lifetimes if there is a `Binder` above
assert!(supertrait_lifetimes.is_empty());
break vec![];
}
Scope::Binder { hir_id, from_poly_trait_ref, .. } => {
if !from_poly_trait_ref {
// We should only see super trait lifetimes if there is a `Binder` above
assert!(supertrait_lifetimes.is_empty());
break vec![];
}
// Nested poly trait refs have the binders concatenated
let mut full_binders =
self.map.late_bound_vars.entry(*hir_id).or_default().clone();
full_binders.extend(supertrait_lifetimes.into_iter());
break full_binders;
}
}
};
let (lifetimes, local_binders): (FxHashMap<hir::ParamName, Region>, Vec<_>) = trait_ref
.bound_generic_params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(param),
_ => None,
})
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(
outer_binders.len() as u32 + late_bound_idx as u32,
&self.tcx.hir(),
param,
);
let r = late_region_as_bound_region(self.tcx, &pair.1);
(pair, r)
})
.unzip();
outer_binders.extend(local_binders.into_iter());
(outer_binders, lifetimes)
};
let initial_bound_vars = binders.len() as u32;
let mut lifetimes: FxHashMap<hir::ParamName, Region> = FxHashMap::default();
let binders_iter = trait_ref
.bound_generic_params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(param),
_ => None,
})
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(
initial_bound_vars + late_bound_idx as u32,
&self.tcx.hir(),
param,
);
let r = late_region_as_bound_region(self.tcx, &pair.1);
lifetimes.insert(pair.0, pair.1);
r
});
binders.extend(binders_iter);
debug!(?binders);
self.map.late_bound_vars.insert(trait_ref.trait_ref.hir_ref_id, binders);
if trait_ref_hack.is_none() || has_lifetimes {
let scope = Scope::Binder {
hir_id: trait_ref.trait_ref.hir_ref_id,
lifetimes,
s: self.scope,
next_early_index,
track_lifetime_uses: true,
opaque_type_parent: false,
from_poly_trait_ref: true,
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
this.visit_trait_ref(&trait_ref.trait_ref);
});
} else {
let scope =
Scope::TraitRefHackInner { hir_id: trait_ref.trait_ref.hir_ref_id, s: self.scope };
self.with(scope, |_old_scope, this| {
this.visit_trait_ref(&trait_ref.trait_ref);
});
}
self.trait_ref_hack = trait_ref_hack;
// Always introduce a scope here, even if this is in a where clause and
// we introduced the binders around the bounded Ty. In that case, we
// just reuse the concatenation functionality also present in nested trait
// refs.
let scope = Scope::Binder {
hir_id: trait_ref.trait_ref.hir_ref_id,
lifetimes,
s: self.scope,
next_early_index,
track_lifetime_uses: true,
opaque_type_parent: false,
scope_type,
};
self.with(scope, |old_scope, this| {
this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params);
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
this.visit_trait_ref(&trait_ref.trait_ref);
});
if should_pop_missing_lt {
self.missing_named_lifetime_spots.pop();
}
@ -1680,7 +1581,6 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) {
Scope::Body { s, .. }
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
scope = s;
@ -1871,12 +1771,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let labels_in_fn = take(&mut self.labels_in_fn);
let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults);
let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots);
let trait_ref_hack = take(&mut self.trait_ref_hack);
let mut this = LifetimeContext {
tcx: *tcx,
map,
scope: &wrap_scope,
trait_ref_hack,
is_in_fn_syntax: self.is_in_fn_syntax,
is_in_const_generic: self.is_in_const_generic,
trait_definition_only: self.trait_definition_only,
@ -1896,7 +1794,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
self.labels_in_fn = this.labels_in_fn;
self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
self.missing_named_lifetime_spots = this.missing_named_lifetime_spots;
self.trait_ref_hack = this.trait_ref_hack;
}
/// helper method to determine the span to remove when suggesting the
@ -2265,7 +2162,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
s: self.scope,
opaque_type_parent: true,
track_lifetime_uses: false,
from_poly_trait_ref: false,
scope_type: BinderScopeType::Normal,
};
self.with(scope, move |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
@ -2289,7 +2186,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
| Scope::Body { s, .. }
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => scope = s,
}
@ -2323,7 +2219,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
// given name or we run out of scopes.
// search.
let mut late_depth = 0;
let mut in_poly_trait_ref = false;
let mut scope = self.scope;
let mut outermost_body = None;
let result = loop {
@ -2341,25 +2236,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
break None;
}
Scope::TraitRefBoundary { s, .. } => {
// We've exited nested poly trait refs; mark that we are no longer in nested trait refs.
// We don't increase the late depth because this isn't a `Binder` scope.
//
// This came up in #83737, which boiled down to a case like this:
//
// ```
// F: for<> Fn(&()) -> Box<dyn for<> Future<Output = ()> + Unpin>,
// // ^^^^^
// ```
//
// Here, as we traverse upwards from the `dyn for<>` binder, we want to reset `in_poly_trait_ref`
// to false, so that we avoid excess contaenation when we encounter the outer `for<>` binder.
in_poly_trait_ref = false;
scope = s;
}
Scope::Binder { ref lifetimes, from_poly_trait_ref, s, .. } => {
Scope::Binder { ref lifetimes, scope_type, s, .. } => {
match lifetime_ref.name {
LifetimeName::Param(param_name) => {
if let Some(&def) = lifetimes.get(&param_name.normalize_to_macros_2_0())
@ -2369,47 +2246,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
_ => bug!("expected LifetimeName::Param"),
}
match (from_poly_trait_ref, in_poly_trait_ref) {
// This is the first binder we see that is a poly trait ref; add one to the
// late depth and mark that we're potentially in nested trait refs.
(true, false) => {
in_poly_trait_ref = true;
late_depth += 1;
}
// We've already seen a binder that is a poly trait ref and this one is too,
// that means that they are nested and we are concatenating the bound vars;
// don't increase the late depth.
//
// This happens specifically with associated trait bounds like the following:
//
// ```
// for<'a> T: Iterator<Item: for<'b> Foo<'a, 'b>>
// ```
//
// In this case, as we traverse `for<'b>`, we would increment `late_depth` but
// set `in_poly_trait_ref` to true. Then when we traverse `for<'a>`, we would
// not increment `late_depth` again. (NB: Niko thinks this logic is actually
// wrong.)
(true, true) => {}
// We've exited nested poly trait refs; add one to the late depth and mark
// that we are no longer in nested trait refs
(false, true) => {
in_poly_trait_ref = false;
late_depth += 1;
}
// Any other kind of nested binders: just increase late depth.
(false, false) => {
late_depth += 1;
}
match scope_type {
BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {}
}
scope = s;
}
Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. } => {
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
scope = s;
}
}
@ -2562,7 +2409,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::Binder { s, .. }
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
scope = s;
@ -2761,7 +2607,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let mut scope = &*self.scope;
let hir_id = loop {
match scope {
Scope::Binder { hir_id, .. } | Scope::TraitRefHackInner { hir_id, .. } => {
Scope::Binder { hir_id, .. } => {
break *hir_id;
}
Scope::Body { id, .. } => break id.hir_id,
@ -3112,7 +2958,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let span = lifetime_refs[0].span;
let mut late_depth = 0;
let mut in_poly_trait_ref = false;
let mut scope = self.scope;
let mut lifetime_names = FxHashSet::default();
let mut lifetime_spans = vec![];
@ -3123,14 +2968,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::Root => break None,
Scope::TraitRefBoundary { s, .. } => {
// We've exited nested poly trait refs; mark that we are no longer in nested trait refs.
// We don't increase the late depth because this isn't a `Binder` scope
in_poly_trait_ref = false;
scope = s;
}
Scope::Binder { s, ref lifetimes, from_poly_trait_ref, .. } => {
Scope::Binder { s, ref lifetimes, scope_type, .. } => {
// collect named lifetimes for suggestions
for name in lifetimes.keys() {
if let hir::ParamName::Plain(name) = name {
@ -3138,20 +2976,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
lifetime_spans.push(name.span);
}
}
// See comments in `resolve_lifetime_ref`
match (from_poly_trait_ref, in_poly_trait_ref) {
(true, false) => {
in_poly_trait_ref = true;
late_depth += 1;
}
(true, true) => {}
(false, true) => {
in_poly_trait_ref = false;
late_depth += 1;
}
(false, false) => {
late_depth += 1;
}
match scope_type {
BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {}
}
scope = s;
}
@ -3201,8 +3028,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
}
Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. } => {
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
scope = s;
}
}
@ -3308,31 +3135,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref);
let mut late_depth = 0;
let mut in_poly_trait_ref = false;
let mut scope = self.scope;
let lifetime = loop {
match *scope {
Scope::TraitRefBoundary { s, .. } => {
// We've exited nested poly trait refs; mark that we are no longer in nested trait refs.
// We don't increase the late depth because this isn't a `Binder` scope
in_poly_trait_ref = false;
scope = s;
}
Scope::Binder { s, from_poly_trait_ref, .. } => {
match (from_poly_trait_ref, in_poly_trait_ref) {
(true, false) => {
in_poly_trait_ref = true;
late_depth += 1;
}
(true, true) => {}
(false, true) => {
in_poly_trait_ref = false;
late_depth += 1;
}
(false, false) => {
late_depth += 1;
}
Scope::Binder { s, scope_type, .. } => {
match scope_type {
BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {}
}
scope = s;
}
@ -3343,7 +3152,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l,
Scope::TraitRefHackInner { s, .. } | Scope::Supertrait { s, .. } => {
Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => {
scope = s;
}
}
@ -3470,7 +3279,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
Scope::Body { s, .. }
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
old_scope = s;
@ -3529,7 +3337,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
} => break false,
Scope::ObjectLifetimeDefault { s, .. }
| Scope::TraitRefHackInner { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => scope = s,
}

View File

@ -439,8 +439,7 @@ fn virtual_call_violation_for_method<'tcx>(
return Some(MethodViolationCode::WhereClauseReferencesSelf);
}
let receiver_ty =
tcx.liberate_late_bound_regions(method.def_id, sig.map_bound(|sig| sig.inputs()[0]));
let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
// Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
// However, this is already considered object-safe. We allow it as a special case here.

View File

@ -973,6 +973,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) {
// Intrinsics are not coercible to function pointers.
if a_sig.abi() == Abi::RustIntrinsic
|| a_sig.abi() == Abi::PlatformIntrinsic
|| b_sig.abi() == Abi::RustIntrinsic
|| b_sig.abi() == Abi::PlatformIntrinsic
{
return Err(TypeError::IntrinsicCast);
}
// The signature must match.
let a_sig = self.normalize_associated_types_in(new.span, a_sig);
let b_sig = self.normalize_associated_types_in(new.span, b_sig);

View File

@ -799,7 +799,7 @@ impl DoubleEndedIterator for Args {
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Args").field("inner", &self.inner.inner.inner_debug()).finish()
f.debug_struct("Args").field("inner", &self.inner.inner).finish()
}
}
@ -840,7 +840,7 @@ impl DoubleEndedIterator for ArgsOs {
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for ArgsOs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ArgsOs").field("inner", &self.inner.inner_debug()).finish()
f.debug_struct("ArgsOs").field("inner", &self.inner).finish()
}
}

View File

@ -1,4 +1,5 @@
use crate::ffi::OsString;
use crate::fmt;
use crate::marker::PhantomData;
use crate::vec;
@ -22,9 +23,9 @@ pub struct Args {
_dont_send_or_sync_me: PhantomData<*mut ()>,
}
impl Args {
pub fn inner_debug(&self) -> &[OsString] {
self.iter.as_slice()
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.as_slice().fmt(f)
}
}

View File

@ -1,5 +1,6 @@
use super::abi::usercalls::{alloc, raw::ByteBuffer};
use crate::ffi::OsString;
use crate::fmt;
use crate::slice;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sys::os_str::Buf;
@ -31,9 +32,9 @@ pub fn args() -> Args {
pub struct Args(slice::Iter<'static, OsString>);
impl Args {
pub fn inner_debug(&self) -> &[OsString] {
self.0.as_slice()
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.as_slice().fmt(f)
}
}

View File

@ -6,6 +6,7 @@
#![allow(dead_code)] // runtime init functions not used during testing
use crate::ffi::OsString;
use crate::fmt;
use crate::marker::PhantomData;
use crate::vec;
@ -29,9 +30,9 @@ pub struct Args {
_dont_send_or_sync_me: PhantomData<*mut ()>,
}
impl Args {
pub fn inner_debug(&self) -> &[OsString] {
self.iter.as_slice()
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.as_slice().fmt(f)
}
}

View File

@ -21,8 +21,8 @@ use crate::slice;
use crate::str;
use crate::sys::cvt;
use crate::sys::fd;
use crate::sys::rwlock::{RWLockReadGuard, StaticRWLock};
use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
use crate::sys_common::rwlock::{RWLockReadGuard, StaticRWLock};
use crate::vec;
use libc::{c_char, c_int, c_void};

View File

@ -139,3 +139,55 @@ impl RWLock {
}
}
}
pub struct StaticRWLock(RWLock);
impl StaticRWLock {
pub const fn new() -> StaticRWLock {
StaticRWLock(RWLock::new())
}
/// Acquires shared access to the underlying lock, blocking the current
/// thread to do so.
///
/// The lock is automatically unlocked when the returned guard is dropped.
#[inline]
pub fn read_with_guard(&'static self) -> RWLockReadGuard {
// SAFETY: All methods require static references, therefore self
// cannot be moved between invocations.
unsafe {
self.0.read();
}
RWLockReadGuard(&self.0)
}
/// Acquires write access to the underlying lock, blocking the current thread
/// to do so.
///
/// The lock is automatically unlocked when the returned guard is dropped.
#[inline]
pub fn write_with_guard(&'static self) -> RWLockWriteGuard {
// SAFETY: All methods require static references, therefore self
// cannot be moved between invocations.
unsafe {
self.0.write();
}
RWLockWriteGuard(&self.0)
}
}
pub struct RWLockReadGuard(&'static RWLock);
impl Drop for RWLockReadGuard {
fn drop(&mut self) {
unsafe { self.0.read_unlock() }
}
}
pub struct RWLockWriteGuard(&'static RWLock);
impl Drop for RWLockWriteGuard {
fn drop(&mut self) {
unsafe { self.0.write_unlock() }
}
}

View File

@ -9,9 +9,9 @@ pub fn args() -> Args {
Args {}
}
impl Args {
pub fn inner_debug(&self) -> &[OsString] {
&[]
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().finish()
}
}

View File

@ -1,6 +1,7 @@
#![deny(unsafe_op_in_unsafe_fn)]
use crate::ffi::{CStr, OsStr, OsString};
use crate::fmt;
use crate::marker::PhantomData;
use crate::os::wasi::ffi::OsStrExt;
use crate::vec;
@ -38,9 +39,9 @@ fn maybe_args() -> Option<Vec<OsString>> {
}
}
impl Args {
pub fn inner_debug(&self) -> &[OsString] {
self.iter.as_slice()
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.as_slice().fmt(f)
}
}

View File

@ -1,4 +1,5 @@
use crate::ffi::OsString;
use crate::fmt;
use crate::marker::PhantomData;
use crate::vec;
@ -17,9 +18,9 @@ pub struct Args {
_dont_send_or_sync_me: PhantomData<*mut ()>,
}
impl Args {
pub fn inner_debug(&self) -> &[OsString] {
self.iter.as_slice()
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.as_slice().fmt(f)
}
}

View File

@ -164,19 +164,9 @@ pub struct Args {
parsed_args_list: vec::IntoIter<OsString>,
}
pub struct ArgsInnerDebug<'a> {
args: &'a Args,
}
impl<'a> fmt::Debug for ArgsInnerDebug<'a> {
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.args.parsed_args_list.as_slice().fmt(f)
}
}
impl Args {
pub fn inner_debug(&self) -> ArgsInnerDebug<'_> {
ArgsInnerDebug { args: self }
self.parsed_args_list.as_slice().fmt(f)
}
}

View File

@ -86,62 +86,3 @@ impl RWLock {
self.0.destroy()
}
}
// the cfg annotations only exist due to dead code warnings. the code itself is portable
#[cfg(unix)]
pub struct StaticRWLock(RWLock);
#[cfg(unix)]
impl StaticRWLock {
pub const fn new() -> StaticRWLock {
StaticRWLock(RWLock::new())
}
/// Acquires shared access to the underlying lock, blocking the current
/// thread to do so.
///
/// The lock is automatically unlocked when the returned guard is dropped.
#[inline]
pub fn read_with_guard(&'static self) -> RWLockReadGuard {
// SAFETY: All methods require static references, therefore self
// cannot be moved between invocations.
unsafe {
self.0.read();
}
RWLockReadGuard(&self.0)
}
/// Acquires write access to the underlying lock, blocking the current thread
/// to do so.
///
/// The lock is automatically unlocked when the returned guard is dropped.
#[inline]
pub fn write_with_guard(&'static self) -> RWLockWriteGuard {
// SAFETY: All methods require static references, therefore self
// cannot be moved between invocations.
unsafe {
self.0.write();
}
RWLockWriteGuard(&self.0)
}
}
#[cfg(unix)]
pub struct RWLockReadGuard(&'static RWLock);
#[cfg(unix)]
impl Drop for RWLockReadGuard {
fn drop(&mut self) {
unsafe { self.0.read_unlock() }
}
}
#[cfg(unix)]
pub struct RWLockWriteGuard(&'static RWLock);
#[cfg(unix)]
impl Drop for RWLockWriteGuard {
fn drop(&mut self) {
unsafe { self.0.write_unlock() }
}
}

View File

@ -116,6 +116,8 @@ h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
padding-bottom: 6px;
}
h1.fqn {
display: flex;
width: 100%;
border-bottom: 1px dashed;
margin-top: 0;
}
@ -458,6 +460,13 @@ nav.sub {
font-weight: normal;
}
h1.fqn > .out-of-band {
float: unset;
flex: 1;
text-align: right;
margin-left: 8px;
}
h3.impl > .out-of-band {
font-size: 21px;
}
@ -1450,10 +1459,6 @@ h4 > .notable-traits {
padding: 0;
}
.content .in-band {
width: 100%;
}
.content h4 > .out-of-band {
position: inherit;
}

@ -1 +1 @@
Subproject commit ea6bb2615f04d53db11b6a43a14be5c9d1eaebe1
Subproject commit 0ed6038a318e34e3d76a9e55bdebc4cfd17f902a

View File

@ -12,4 +12,12 @@ fn b() {
//~^ ERROR casting
}
fn c() {
let _ = [
std::intrinsics::copy_nonoverlapping::<i32>,
std::intrinsics::copy::<i32>,
//~^ ERROR cannot coerce
];
}
fn main() {}

View File

@ -19,7 +19,16 @@ error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_,
LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
error[E0308]: cannot coerce intrinsics to function pointers
--> $DIR/reify-intrinsic.rs:18:9
|
LL | std::intrinsics::copy::<i32>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
|
= note: expected type `unsafe extern "rust-intrinsic" fn(_, _, _) {copy_nonoverlapping::<i32>}`
found fn item `unsafe extern "rust-intrinsic" fn(_, _, _) {std::intrinsics::copy::<i32>}`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0308, E0606.
For more information about an error, try `rustc --explain E0308`.