Skip to content

Commit 4b9f4b2

Browse files
committed
Auto merge of #88308 - eddyb:cooked-layouts, r=nagisa
Morph `layout_raw` query into `layout_of`. Before this PR, `LayoutCx::layout_of` wrapped the `layout_raw` query, to: * normalize the type, before attempting to compute the layout * pass the layout to `record_layout_for_printing`, for `-Zprint-type-sizes` Moving those two responsibilities into the query may reduce overhead (due to cached calls skipping those steps), but I want to do a perf run to know. One of the changes I had to make was changing the return type of the query, to be able to both get out the type produced by normalizing inside the query *and* to match the signature of the old `TyCtxt::layout_of`. This change may be worse, perf-wise, so that's another reason I want to check. r? `@nagisa` cc `@oli-obk`
2 parents 20997f6 + edb4b2d commit 4b9f4b2

File tree

9 files changed

+54
-94
lines changed

9 files changed

+54
-94
lines changed

Diff for: compiler/rustc_middle/src/query/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1100,10 +1100,12 @@ rustc_queries! {
11001100
cache_on_disk_if { false }
11011101
}
11021102

1103-
query layout_raw(
1104-
env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
1105-
) -> Result<&'tcx rustc_target::abi::Layout, ty::layout::LayoutError<'tcx>> {
1106-
desc { "computing layout of `{}`", env.value }
1103+
/// Computes the layout of a type. Note that this implicitly
1104+
/// executes in "reveal all" mode, and will normalize the input type.
1105+
query layout_of(
1106+
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
1107+
) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> {
1108+
desc { "computing layout of `{}`", key.value }
11071109
}
11081110

11091111
query dylib_dependency_formats(_: CrateNum)

Diff for: compiler/rustc_middle/src/ty/layout.rs

+33-75
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,10 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
205205
}
206206
}
207207

208-
fn layout_raw<'tcx>(
208+
fn layout_of<'tcx>(
209209
tcx: TyCtxt<'tcx>,
210210
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
211-
) -> Result<&'tcx Layout, LayoutError<'tcx>> {
211+
) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
212212
ty::tls::with_related_context(tcx, move |icx| {
213213
let (param_env, ty) = query.into_parts();
214214

@@ -220,21 +220,33 @@ fn layout_raw<'tcx>(
220220
let icx = ty::tls::ImplicitCtxt { layout_depth: icx.layout_depth + 1, ..icx.clone() };
221221

222222
ty::tls::enter_context(&icx, |_| {
223+
let param_env = param_env.with_reveal_all_normalized(tcx);
224+
let unnormalized_ty = ty;
225+
let ty = tcx.normalize_erasing_regions(param_env, ty);
226+
if ty != unnormalized_ty {
227+
// Ensure this layout is also cached for the normalized type.
228+
return tcx.layout_of(param_env.and(ty));
229+
}
230+
223231
let cx = LayoutCx { tcx, param_env };
224-
let layout = cx.layout_raw_uncached(ty);
232+
233+
let layout = cx.layout_of_uncached(ty)?;
234+
let layout = TyAndLayout { ty, layout };
235+
236+
cx.record_layout_for_printing(layout);
237+
225238
// Type-level uninhabitedness should always imply ABI uninhabitedness.
226-
if let Ok(layout) = layout {
227-
if tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
228-
assert!(layout.abi.is_uninhabited());
229-
}
239+
if tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
240+
assert!(layout.abi.is_uninhabited());
230241
}
231-
layout
242+
243+
Ok(layout)
232244
})
233245
})
234246
}
235247

236248
pub fn provide(providers: &mut ty::query::Providers) {
237-
*providers = ty::query::Providers { layout_raw, ..*providers };
249+
*providers = ty::query::Providers { layout_of, ..*providers };
238250
}
239251

240252
pub struct LayoutCx<'tcx, C> {
@@ -492,7 +504,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
492504
})
493505
}
494506

495-
fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> {
507+
fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> {
496508
let tcx = self.tcx;
497509
let param_env = self.param_env;
498510
let dl = self.data_layout();
@@ -889,7 +901,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
889901
let present_first = match present_first {
890902
Some(present_first) => present_first,
891903
// Uninhabited because it has no variants, or only absent ones.
892-
None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)),
904+
None if def.is_enum() => {
905+
return Ok(tcx.layout_of(param_env.and(tcx.types.never))?.layout);
906+
}
893907
// If it's a struct, still compute a layout so that we can still compute the
894908
// field offsets.
895909
None => VariantIdx::new(0),
@@ -1368,11 +1382,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13681382

13691383
// Types with no meaningful known layout.
13701384
ty::Projection(_) | ty::Opaque(..) => {
1371-
let normalized = tcx.normalize_erasing_regions(param_env, ty);
1372-
if ty == normalized {
1373-
return Err(LayoutError::Unknown(ty));
1374-
}
1375-
tcx.layout_raw(param_env.and(normalized))?
1385+
// NOTE(eddyb) `layout_of` query should've normalized these away,
1386+
// if that was possible, so there's no reason to try again here.
1387+
return Err(LayoutError::Unknown(ty));
13761388
}
13771389

13781390
ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
@@ -1712,7 +1724,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
17121724
Ok(layout)
17131725
}
17141726

1715-
/// This is invoked by the `layout_raw` query to record the final
1727+
/// This is invoked by the `layout_of` query to record the final
17161728
/// layout of each type.
17171729
#[inline(always)]
17181730
fn record_layout_for_printing(&self, layout: TyAndLayout<'tcx>) {
@@ -2040,22 +2052,9 @@ impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> {
20402052
type TyAndLayout = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
20412053

20422054
/// Computes the layout of a type. Note that this implicitly
2043-
/// executes in "reveal all" mode.
2055+
/// executes in "reveal all" mode, and will normalize the input type.
20442056
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
2045-
let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
2046-
let ty = self.tcx.normalize_erasing_regions(param_env, ty);
2047-
let layout = self.tcx.layout_raw(param_env.and(ty))?;
2048-
let layout = TyAndLayout { ty, layout };
2049-
2050-
// N.B., this recording is normally disabled; when enabled, it
2051-
// can however trigger recursive invocations of `layout_of`.
2052-
// Therefore, we execute it *after* the main query has
2053-
// completed, to avoid problems around recursive structures
2054-
// and the like. (Admittedly, I wasn't able to reproduce a problem
2055-
// here, but it seems like the right thing to do. -nmatsakis)
2056-
self.record_layout_for_printing(layout);
2057-
2058-
Ok(layout)
2057+
self.tcx.layout_of(self.param_env.and(ty))
20592058
}
20602059
}
20612060

@@ -2064,50 +2063,9 @@ impl LayoutOf for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
20642063
type TyAndLayout = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
20652064

20662065
/// Computes the layout of a type. Note that this implicitly
2067-
/// executes in "reveal all" mode.
2066+
/// executes in "reveal all" mode, and will normalize the input type.
20682067
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
2069-
let param_env = self.param_env.with_reveal_all_normalized(*self.tcx);
2070-
let ty = self.tcx.normalize_erasing_regions(param_env, ty);
2071-
let layout = self.tcx.layout_raw(param_env.and(ty))?;
2072-
let layout = TyAndLayout { ty, layout };
2073-
2074-
// N.B., this recording is normally disabled; when enabled, it
2075-
// can however trigger recursive invocations of `layout_of`.
2076-
// Therefore, we execute it *after* the main query has
2077-
// completed, to avoid problems around recursive structures
2078-
// and the like. (Admittedly, I wasn't able to reproduce a problem
2079-
// here, but it seems like the right thing to do. -nmatsakis)
2080-
let cx = LayoutCx { tcx: *self.tcx, param_env: self.param_env };
2081-
cx.record_layout_for_printing(layout);
2082-
2083-
Ok(layout)
2084-
}
2085-
}
2086-
2087-
// Helper (inherent) `layout_of` methods to avoid pushing `LayoutCx` to users.
2088-
impl TyCtxt<'tcx> {
2089-
/// Computes the layout of a type. Note that this implicitly
2090-
/// executes in "reveal all" mode.
2091-
#[inline]
2092-
pub fn layout_of(
2093-
self,
2094-
param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
2095-
) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
2096-
let cx = LayoutCx { tcx: self, param_env: param_env_and_ty.param_env };
2097-
cx.layout_of(param_env_and_ty.value)
2098-
}
2099-
}
2100-
2101-
impl ty::query::TyCtxtAt<'tcx> {
2102-
/// Computes the layout of a type. Note that this implicitly
2103-
/// executes in "reveal all" mode.
2104-
#[inline]
2105-
pub fn layout_of(
2106-
self,
2107-
param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
2108-
) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
2109-
let cx = LayoutCx { tcx: self.at(self.span), param_env: param_env_and_ty.param_env };
2110-
cx.layout_of(param_env_and_ty.value)
2068+
self.tcx.layout_of(self.param_env.and(ty))
21112069
}
21122070
}
21132071

Diff for: compiler/rustc_mir/src/util/alignment.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ where
2424
};
2525

2626
let ty = place.ty(local_decls, tcx).ty;
27-
match tcx.layout_raw(param_env.and(ty)) {
27+
match tcx.layout_of(param_env.and(ty)) {
2828
Ok(layout) if layout.align.abi <= pack => {
2929
// If the packed alignment is greater or equal to the field alignment, the type won't be
3030
// further disaligned.

Diff for: compiler/rustc_target/src/abi/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1139,7 +1139,7 @@ impl Layout {
11391139
/// to that obtained from `layout_of(ty)`, as we need to produce
11401140
/// layouts for which Rust types do not exist, such as enum variants
11411141
/// or synthetic fields of enums (i.e., discriminants) and fat pointers.
1142-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1142+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
11431143
pub struct TyAndLayout<'a, Ty> {
11441144
pub ty: Ty,
11451145
pub layout: &'a Layout,

Diff for: compiler/rustc_typeck/src/check/upvar.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,7 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
14811481
match p.kind {
14821482
ProjectionKind::Field(..) => match ty.kind() {
14831483
ty::Adt(def, _) if def.repr.packed() => {
1484-
match tcx.layout_raw(param_env.and(p.ty)) {
1484+
match tcx.layout_of(param_env.and(p.ty)) {
14851485
Ok(layout) if layout.align.abi.bytes() == 1 => {
14861486
// if the alignment is 1, the type can't be further
14871487
// disaligned.

Diff for: src/test/ui/consts/const-size_of-cycle.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`..
1515
LL | bytes: [u8; std::mem::size_of::<Foo>()]
1616
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
1717
= note: ...which requires computing layout of `Foo`...
18+
= note: ...which requires computing layout of `[u8; _]`...
1819
= note: ...which requires normalizing `[u8; _]`...
1920
= note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle
2021
note: cycle used when checking that `Foo` is well-formed

Diff for: src/test/ui/consts/issue-44415.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`..
1515
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
1616
| ^^^^^^
1717
= note: ...which requires computing layout of `Foo`...
18+
= note: ...which requires computing layout of `[u8; _]`...
1819
= note: ...which requires normalizing `[u8; _]`...
1920
= note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle
2021
note: cycle used when checking that `Foo` is well-formed

Diff for: src/test/ui/recursion/issue-26548-recursion-via-normalize.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
//~ ERROR cycle detected when computing layout of
2-
//~| NOTE ...which requires computing layout of
3-
//~| NOTE ...which again requires computing layout of
1+
//~ ERROR cycle detected when computing layout of `S`
2+
//~| NOTE ...which requires computing layout of `std::option::Option<<S as Mirror>::It>`...
3+
//~| NOTE ...which requires computing layout of `std::option::Option<S>`...
4+
//~| NOTE ...which again requires computing layout of `S`, completing the cycle
5+
//~| NOTE cycle used when computing layout of `std::option::Option<S>`
46

57
// build-fail
68

@@ -13,6 +15,5 @@ impl<T: ?Sized> Mirror for T {
1315
struct S(Option<<S as Mirror>::It>);
1416

1517
fn main() {
16-
//~^ NOTE cycle used when optimizing MIR for `main`
1718
let _s = S(None);
1819
}

Diff for: src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
error[E0391]: cycle detected when computing layout of `std::option::Option<S>`
1+
error[E0391]: cycle detected when computing layout of `S`
22
|
3-
= note: ...which requires computing layout of `S`...
4-
= note: ...which again requires computing layout of `std::option::Option<S>`, completing the cycle
5-
note: cycle used when optimizing MIR for `main`
6-
--> $DIR/issue-26548-recursion-via-normalize.rs:15:1
7-
|
8-
LL | fn main() {
9-
| ^^^^^^^^^
3+
= note: ...which requires computing layout of `std::option::Option<<S as Mirror>::It>`...
4+
= note: ...which requires computing layout of `std::option::Option<S>`...
5+
= note: ...which again requires computing layout of `S`, completing the cycle
6+
= note: cycle used when computing layout of `std::option::Option<S>`
107

118
error: aborting due to previous error
129

0 commit comments

Comments
 (0)