diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index bb09f701531cf..8a3f76415968e 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1213,8 +1213,41 @@ impl<'a> Visitor<'a> for AstValidator<'a> { deny_equality_constraints(self, predicate, generics); } } - - visit::walk_generics(self, 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); + + // 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); diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 5440e63543d40..f44267a404bf3 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -235,18 +235,6 @@ pub struct ScopeTree { /// escape into 'static and should have no local cleanup scope. rvalue_scopes: FxHashMap>, - /// 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, - /// 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> 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> 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); } } diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs index b532021bed2e9..14a373c59423f 100644 --- a/compiler/rustc_passes/src/region.rs +++ b/compiler/rustc_passes/src/region.rs @@ -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, - /// 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![], diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index fc1ea4ec84629..174df09cbdbb2 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -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, - /// 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 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, 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, 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, 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 (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 = 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, 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()); + let (mut binders, scope_type) = self.poly_trait_ref_binder_info(); - (outer_binders, lifetimes) - }; + let initial_bound_vars = binders.len() as u32; + let mut lifetimes: FxHashMap = 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 Future + 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(¶m_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 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, } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index b5a458db6075f..ac5ec24eeeeb5 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -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. diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index fd7c50e978800..427f967a9b6bd 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -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); diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 8f8d4e3a89832..5fa092af1da02 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -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() } } diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs index 7727293927282..4794f89a5aee3 100644 --- a/library/std/src/sys/hermit/args.rs +++ b/library/std/src/sys/hermit/args.rs @@ -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) } } diff --git a/library/std/src/sys/sgx/args.rs b/library/std/src/sys/sgx/args.rs index 2d2e692ec7d35..463188ad7c0c3 100644 --- a/library/std/src/sys/sgx/args.rs +++ b/library/std/src/sys/sgx/args.rs @@ -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) } } diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index 6967647249390..cba0627e93a85 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -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) } } diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index bf649f6d76f81..503ba410097c8 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -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}; diff --git a/library/std/src/sys/unix/rwlock.rs b/library/std/src/sys/unix/rwlock.rs index 2b5067a34f648..d97d9d712fc93 100644 --- a/library/std/src/sys/unix/rwlock.rs +++ b/library/std/src/sys/unix/rwlock.rs @@ -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() } + } +} diff --git a/library/std/src/sys/unsupported/args.rs b/library/std/src/sys/unsupported/args.rs index 71d0c5fa13e18..360bb65af6953 100644 --- a/library/std/src/sys/unsupported/args.rs +++ b/library/std/src/sys/unsupported/args.rs @@ -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() } } diff --git a/library/std/src/sys/wasi/args.rs b/library/std/src/sys/wasi/args.rs index 9a27218e1fb70..86405dede4277 100644 --- a/library/std/src/sys/wasi/args.rs +++ b/library/std/src/sys/wasi/args.rs @@ -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> { } } -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) } } diff --git a/library/std/src/sys/wasm/args.rs b/library/std/src/sys/wasm/args.rs index 3b6557ae3257f..99d300b53b3b9 100644 --- a/library/std/src/sys/wasm/args.rs +++ b/library/std/src/sys/wasm/args.rs @@ -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) } } diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index bcc2ea9ae00f0..31197e4accc6d 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -164,19 +164,9 @@ pub struct Args { parsed_args_list: vec::IntoIter, } -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) } } diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs index 70b31b19f824c..3705d641a1be6 100644 --- a/library/std/src/sys_common/rwlock.rs +++ b/library/std/src/sys_common/rwlock.rs @@ -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() } - } -} diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 8f11dda2fb205..213ca9ec9e3ea 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -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; } diff --git a/src/llvm-project b/src/llvm-project index ea6bb2615f04d..0ed6038a318e3 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit ea6bb2615f04d53db11b6a43a14be5c9d1eaebe1 +Subproject commit 0ed6038a318e34e3d76a9e55bdebc4cfd17f902a diff --git a/src/test/ui/reify-intrinsic.rs b/src/test/ui/reify-intrinsic.rs index 09baa059e5567..05535b92cca73 100644 --- a/src/test/ui/reify-intrinsic.rs +++ b/src/test/ui/reify-intrinsic.rs @@ -12,4 +12,12 @@ fn b() { //~^ ERROR casting } +fn c() { + let _ = [ + std::intrinsics::copy_nonoverlapping::, + std::intrinsics::copy::, + //~^ ERROR cannot coerce + ]; +} + fn main() {} diff --git a/src/test/ui/reify-intrinsic.stderr b/src/test/ui/reify-intrinsic.stderr index 675447f972179..5d82fdbd31190 100644 --- a/src/test/ui/reify-intrinsic.stderr +++ b/src/test/ui/reify-intrinsic.stderr @@ -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::, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers + | + = note: expected type `unsafe extern "rust-intrinsic" fn(_, _, _) {copy_nonoverlapping::}` + found fn item `unsafe extern "rust-intrinsic" fn(_, _, _) {std::intrinsics::copy::}` + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0606. For more information about an error, try `rustc --explain E0308`.