Skip to content

Commit 8981dbb

Browse files
committed
Auto merge of #73978 - Mark-Simulacrum:shrink-paramenv, r=nnethercote
Shrink ParamEnv to 16 bytes r? @nnethercote x.py check passes but I haven't tried running perf or tests
2 parents 0c03aee + 8512d2e commit 8981dbb

File tree

24 files changed

+188
-83
lines changed

24 files changed

+188
-83
lines changed

src/librustc_infer/infer/outlives/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub fn explicit_outlives_bounds<'tcx>(
1111
param_env: ty::ParamEnv<'tcx>,
1212
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
1313
debug!("explicit_outlives_bounds()");
14-
param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate.kind() {
14+
param_env.caller_bounds().into_iter().filter_map(move |predicate| match predicate.kind() {
1515
ty::PredicateKind::Projection(..)
1616
| ty::PredicateKind::Trait(..)
1717
| ty::PredicateKind::Subtype(..)

src/librustc_infer/infer/outlives/verify.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
221221
// dubious for projections, but it will work for simple cases
222222
// like `T` and `T::Item`. It may not work as well for things
223223
// like `<T as Foo<'a>>::Item`.
224-
let c_b = self.param_env.caller_bounds;
224+
let c_b = self.param_env.caller_bounds();
225225
let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b.into_iter());
226226

227227
// Next, collect regions we scraped from the well-formedness

src/librustc_infer/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
5757

5858
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
5959
#[cfg(target_arch = "x86_64")]
60-
static_assert_size!(PredicateObligation<'_>, 48);
60+
static_assert_size!(PredicateObligation<'_>, 40);
6161

6262
pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
6363
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;

src/librustc_middle/ty/layout.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1588,7 +1588,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
15881588
// Ignore layouts that are done with non-empty environments or
15891589
// non-monomorphic layouts, as the user only wants to see the stuff
15901590
// resulting from the final codegen session.
1591-
if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds.is_empty() {
1591+
if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() {
15921592
return;
15931593
}
15941594

src/librustc_middle/ty/mod.rs

+112-10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// ignore-tidy-filelength
2+
13
pub use self::fold::{TypeFoldable, TypeVisitor};
24
pub use self::AssocItemContainer::*;
35
pub use self::BorrowKind::*;
@@ -45,6 +47,7 @@ use std::cell::RefCell;
4547
use std::cmp::Ordering;
4648
use std::fmt;
4749
use std::hash::{Hash, Hasher};
50+
use std::marker::PhantomData;
4851
use std::ops::Range;
4952
use std::ptr;
5053

@@ -1571,24 +1574,93 @@ pub type PlaceholderConst = Placeholder<BoundVar>;
15711574
/// When type checking, we use the `ParamEnv` to track
15721575
/// details about the set of where-clauses that are in scope at this
15731576
/// particular point.
1574-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TypeFoldable)]
1577+
#[derive(Copy, Clone)]
15751578
pub struct ParamEnv<'tcx> {
1579+
// We pack the caller_bounds List pointer and a Reveal enum into this usize.
1580+
// Specifically, the low bit represents Reveal, with 0 meaning `UserFacing`
1581+
// and 1 meaning `All`. The rest is the pointer.
1582+
//
1583+
// This relies on the List<ty::Predicate<'tcx>> type having at least 2-byte
1584+
// alignment. Lists start with a usize and are repr(C) so this should be
1585+
// fine; there is a debug_assert in the constructor as well.
1586+
//
1587+
// Note that the choice of 0 for UserFacing is intentional -- since it is the
1588+
// first variant in Reveal this means that joining the pointer is a simple `or`.
1589+
packed_data: usize,
1590+
15761591
/// `Obligation`s that the caller must satisfy. This is basically
15771592
/// the set of bounds on the in-scope type parameters, translated
15781593
/// into `Obligation`s, and elaborated and normalized.
1579-
pub caller_bounds: &'tcx List<ty::Predicate<'tcx>>,
1594+
///
1595+
/// Note: This is packed into the `packed_data` usize above, use the
1596+
/// `caller_bounds()` method to access it.
1597+
caller_bounds: PhantomData<&'tcx List<ty::Predicate<'tcx>>>,
15801598

15811599
/// Typically, this is `Reveal::UserFacing`, but during codegen we
1582-
/// want `Reveal::All` -- note that this is always paired with an
1583-
/// empty environment. To get that, use `ParamEnv::reveal()`.
1584-
pub reveal: traits::Reveal,
1600+
/// want `Reveal::All`.
1601+
///
1602+
/// Note: This is packed into the caller_bounds usize above, use the reveal()
1603+
/// method to access it.
1604+
reveal: PhantomData<traits::Reveal>,
15851605

15861606
/// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`,
15871607
/// register that `def_id` (useful for transitioning to the chalk trait
15881608
/// solver).
15891609
pub def_id: Option<DefId>,
15901610
}
15911611

1612+
impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
1613+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1614+
f.debug_struct("ParamEnv")
1615+
.field("caller_bounds", &self.caller_bounds())
1616+
.field("reveal", &self.reveal())
1617+
.field("def_id", &self.def_id)
1618+
.finish()
1619+
}
1620+
}
1621+
1622+
impl<'tcx> Hash for ParamEnv<'tcx> {
1623+
fn hash<H: Hasher>(&self, state: &mut H) {
1624+
// List hashes as the raw pointer, so we can skip splitting into the
1625+
// pointer and the enum.
1626+
self.packed_data.hash(state);
1627+
self.def_id.hash(state);
1628+
}
1629+
}
1630+
1631+
impl<'tcx> PartialEq for ParamEnv<'tcx> {
1632+
fn eq(&self, other: &Self) -> bool {
1633+
self.caller_bounds() == other.caller_bounds()
1634+
&& self.reveal() == other.reveal()
1635+
&& self.def_id == other.def_id
1636+
}
1637+
}
1638+
impl<'tcx> Eq for ParamEnv<'tcx> {}
1639+
1640+
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ParamEnv<'tcx> {
1641+
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
1642+
self.caller_bounds().hash_stable(hcx, hasher);
1643+
self.reveal().hash_stable(hcx, hasher);
1644+
self.def_id.hash_stable(hcx, hasher);
1645+
}
1646+
}
1647+
1648+
impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
1649+
fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
1650+
ParamEnv::new(
1651+
self.caller_bounds().fold_with(folder),
1652+
self.reveal().fold_with(folder),
1653+
self.def_id.fold_with(folder),
1654+
)
1655+
}
1656+
1657+
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1658+
self.caller_bounds().visit_with(visitor)
1659+
|| self.reveal().visit_with(visitor)
1660+
|| self.def_id.visit_with(visitor)
1661+
}
1662+
}
1663+
15921664
impl<'tcx> ParamEnv<'tcx> {
15931665
/// Construct a trait environment suitable for contexts where
15941666
/// there are no where-clauses in scope. Hidden types (like `impl
@@ -1599,6 +1671,17 @@ impl<'tcx> ParamEnv<'tcx> {
15991671
Self::new(List::empty(), Reveal::UserFacing, None)
16001672
}
16011673

1674+
#[inline]
1675+
pub fn caller_bounds(self) -> &'tcx List<ty::Predicate<'tcx>> {
1676+
// mask out bottom bit
1677+
unsafe { &*((self.packed_data & (!1)) as *const _) }
1678+
}
1679+
1680+
#[inline]
1681+
pub fn reveal(self) -> traits::Reveal {
1682+
if self.packed_data & 1 == 0 { traits::Reveal::UserFacing } else { traits::Reveal::All }
1683+
}
1684+
16021685
/// Construct a trait environment with no where-clauses in scope
16031686
/// where the values of all `impl Trait` and other hidden types
16041687
/// are revealed. This is suitable for monomorphized, post-typeck
@@ -1618,7 +1701,25 @@ impl<'tcx> ParamEnv<'tcx> {
16181701
reveal: Reveal,
16191702
def_id: Option<DefId>,
16201703
) -> Self {
1621-
ty::ParamEnv { caller_bounds, reveal, def_id }
1704+
let packed_data = caller_bounds as *const _ as usize;
1705+
// Check that we can pack the reveal data into the pointer.
1706+
debug_assert!(packed_data & 1 == 0);
1707+
ty::ParamEnv {
1708+
packed_data: packed_data
1709+
| match reveal {
1710+
Reveal::UserFacing => 0,
1711+
Reveal::All => 1,
1712+
},
1713+
caller_bounds: PhantomData,
1714+
reveal: PhantomData,
1715+
def_id,
1716+
}
1717+
}
1718+
1719+
pub fn with_user_facing(mut self) -> Self {
1720+
// clear bottom bit
1721+
self.packed_data &= !1;
1722+
self
16221723
}
16231724

16241725
/// Returns a new parameter environment with the same clauses, but
@@ -1627,13 +1728,14 @@ impl<'tcx> ParamEnv<'tcx> {
16271728
/// the desired behavior during codegen and certain other special
16281729
/// contexts; normally though we want to use `Reveal::UserFacing`,
16291730
/// which is the default.
1630-
pub fn with_reveal_all(self) -> Self {
1631-
ty::ParamEnv { reveal: Reveal::All, ..self }
1731+
pub fn with_reveal_all(mut self) -> Self {
1732+
self.packed_data |= 1;
1733+
self
16321734
}
16331735

16341736
/// Returns this same environment but with no caller bounds.
16351737
pub fn without_caller_bounds(self) -> Self {
1636-
ty::ParamEnv { caller_bounds: List::empty(), ..self }
1738+
Self::new(List::empty(), self.reveal(), self.def_id)
16371739
}
16381740

16391741
/// Creates a suitable environment in which to perform trait
@@ -1649,7 +1751,7 @@ impl<'tcx> ParamEnv<'tcx> {
16491751
/// satisfiable. We generally want to behave as if they were true,
16501752
/// although the surrounding function is never reachable.
16511753
pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
1652-
match self.reveal {
1754+
match self.reveal() {
16531755
Reveal::UserFacing => ParamEnvAnd { param_env: self, value },
16541756

16551757
Reveal::All => {

src/librustc_middle/ty/structural_impls.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -521,11 +521,8 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
521521
impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
522522
type Lifted = ty::ParamEnv<'tcx>;
523523
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
524-
tcx.lift(&self.caller_bounds).map(|caller_bounds| ty::ParamEnv {
525-
reveal: self.reveal,
526-
caller_bounds,
527-
def_id: self.def_id,
528-
})
524+
tcx.lift(&self.caller_bounds())
525+
.map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.def_id))
529526
}
530527
}
531528

src/librustc_mir/const_eval/eval_queries.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,9 @@ pub fn const_eval_validated_provider<'tcx>(
226226
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
227227
) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> {
228228
// see comment in const_eval_raw_provider for what we're doing here
229-
if key.param_env.reveal == Reveal::All {
229+
if key.param_env.reveal() == Reveal::All {
230230
let mut key = key;
231-
key.param_env.reveal = Reveal::UserFacing;
231+
key.param_env = key.param_env.with_user_facing();
232232
match tcx.const_eval_validated(key) {
233233
// try again with reveal all as requested
234234
Err(ErrorHandled::TooGeneric) => {}
@@ -267,9 +267,9 @@ pub fn const_eval_raw_provider<'tcx>(
267267
// information being available.
268268

269269
// In case we fail in the `UserFacing` variant, we just do the real computation.
270-
if key.param_env.reveal == Reveal::All {
270+
if key.param_env.reveal() == Reveal::All {
271271
let mut key = key;
272-
key.param_env.reveal = Reveal::UserFacing;
272+
key.param_env = key.param_env.with_user_facing();
273273
match tcx.const_eval_raw(key) {
274274
// try again with reveal all as requested
275275
Err(ErrorHandled::TooGeneric) => {}
@@ -326,7 +326,7 @@ pub fn const_eval_raw_provider<'tcx>(
326326
// this is `Reveal::UserFacing`, then it's expected that we could get a
327327
// `TooGeneric` error. When we fall back to `Reveal::All`, then it will either
328328
// succeed or we'll report this error then.
329-
if key.param_env.reveal == Reveal::All {
329+
if key.param_env.reveal() == Reveal::All {
330330
tcx.sess.delay_span_bug(
331331
err.span,
332332
&format!("static eval failure did not emit an error: {:#?}", v),

src/librustc_mir/util/elaborate_drops.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ where
279279
let subpath = self.elaborator.field_subpath(variant_path, field);
280280
let tcx = self.tcx();
281281

282-
assert_eq!(self.elaborator.param_env().reveal, Reveal::All);
282+
assert_eq!(self.elaborator.param_env().reveal(), Reveal::All);
283283
let field_ty =
284284
tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs));
285285
(tcx.mk_place_field(base_place, field, field_ty), subpath)

src/librustc_trait_selection/traits/auto_trait.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,8 @@ impl AutoTraitFinder<'tcx> {
281281
},
282282
}));
283283

284-
let computed_preds = param_env.caller_bounds.iter();
285-
let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds.iter().collect();
284+
let computed_preds = param_env.caller_bounds().iter();
285+
let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds().iter().collect();
286286

287287
let mut new_env = param_env;
288288
let dummy_cause = ObligationCause::dummy();
@@ -368,12 +368,12 @@ impl AutoTraitFinder<'tcx> {
368368
)
369369
.map(|o| o.predicate);
370370
new_env =
371-
ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal, None);
371+
ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal(), None);
372372
}
373373

374374
let final_user_env = ty::ParamEnv::new(
375375
tcx.mk_predicates(user_computed_preds.into_iter()),
376-
user_env.reveal,
376+
user_env.reveal(),
377377
None,
378378
);
379379
debug!(

src/librustc_trait_selection/traits/chalk_fulfill.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ fn in_environment(
137137

138138
let environment = match obligation.param_env.def_id {
139139
Some(def_id) => environment(infcx.tcx, def_id),
140-
None if obligation.param_env.caller_bounds.is_empty() => ty::List::empty(),
140+
None if obligation.param_env.caller_bounds().is_empty() => ty::List::empty(),
141141
// FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl
142142
// and ui/generics/generic-static-methods
143143
//_ => bug!("non-empty `ParamEnv` with no def-id"),

src/librustc_trait_selection/traits/fulfill.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub struct PendingPredicateObligation<'tcx> {
8484

8585
// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
8686
#[cfg(target_arch = "x86_64")]
87-
static_assert_size!(PendingPredicateObligation<'_>, 72);
87+
static_assert_size!(PendingPredicateObligation<'_>, 64);
8888

8989
impl<'a, 'tcx> FulfillmentContext<'tcx> {
9090
/// Creates a new fulfillment context.

src/librustc_trait_selection/traits/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -297,15 +297,15 @@ pub fn normalize_param_env_or_error<'tcx>(
297297
);
298298

299299
let mut predicates: Vec<_> =
300-
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.into_iter())
300+
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter())
301301
.map(|obligation| obligation.predicate)
302302
.collect();
303303

304304
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
305305

306306
let elaborated_env = ty::ParamEnv::new(
307307
tcx.intern_predicates(&predicates),
308-
unnormalized_env.reveal,
308+
unnormalized_env.reveal(),
309309
unnormalized_env.def_id,
310310
);
311311

@@ -361,7 +361,7 @@ pub fn normalize_param_env_or_error<'tcx>(
361361
let outlives_env: Vec<_> =
362362
non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
363363
let outlives_env =
364-
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal, None);
364+
ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal(), None);
365365
let outlives_predicates = match do_normalize_predicates(
366366
tcx,
367367
region_context,
@@ -383,7 +383,7 @@ pub fn normalize_param_env_or_error<'tcx>(
383383
debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
384384
ty::ParamEnv::new(
385385
tcx.intern_predicates(&predicates),
386-
unnormalized_env.reveal,
386+
unnormalized_env.reveal(),
387387
unnormalized_env.def_id,
388388
)
389389
}

src/librustc_trait_selection/traits/object_safety.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ fn receiver_is_dispatchable<'tcx>(
631631
// create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
632632
// `U: ?Sized` is already implied here
633633
let param_env = {
634-
let mut param_env = tcx.param_env(method.def_id);
634+
let param_env = tcx.param_env(method.def_id);
635635

636636
// Self: Unsize<U>
637637
let unsize_predicate = ty::TraitRef {
@@ -656,15 +656,17 @@ fn receiver_is_dispatchable<'tcx>(
656656
};
657657

658658
let caller_bounds: Vec<Predicate<'tcx>> = param_env
659-
.caller_bounds
659+
.caller_bounds()
660660
.iter()
661661
.chain(iter::once(unsize_predicate))
662662
.chain(iter::once(trait_predicate))
663663
.collect();
664664

665-
param_env.caller_bounds = tcx.intern_predicates(&caller_bounds);
666-
667-
param_env
665+
ty::ParamEnv::new(
666+
tcx.intern_predicates(&caller_bounds),
667+
param_env.reveal(),
668+
param_env.def_id,
669+
)
668670
};
669671

670672
// Receiver: DispatchFromDyn<Receiver[Self => U]>

0 commit comments

Comments
 (0)