Skip to content

Commit f2c9502

Browse files
committed
support nonzero* niche optimizations
1 parent 86b5b60 commit f2c9502

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

crates/hir-ty/src/layout/adt.rs

+50
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{
44
cmp::{self, Ordering},
55
iter,
66
num::NonZeroUsize,
7+
ops::Bound,
78
};
89

910
use chalk_ir::TyKind;
@@ -18,6 +19,8 @@ use hir_def::{
1819
};
1920
use la_arena::{ArenaMap, RawIdx};
2021

22+
struct X(Option<NonZeroUsize>);
23+
2124
use crate::{
2225
db::HirDatabase,
2326
lang_items::is_unsafe_cell,
@@ -137,7 +140,38 @@ pub fn layout_of_adt_query(
137140
Abi::Aggregate { sized: _ } => {}
138141
}
139142
st.largest_niche = None;
143+
return Ok(st);
144+
}
145+
146+
let (start, end) = layout_scalar_valid_range(db, def);
147+
match st.abi {
148+
Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => {
149+
if let Bound::Included(start) = start {
150+
let valid_range = scalar.valid_range_mut();
151+
valid_range.start = start;
152+
}
153+
if let Bound::Included(end) = end {
154+
let valid_range = scalar.valid_range_mut();
155+
valid_range.end = end;
156+
}
157+
// Update `largest_niche` if we have introduced a larger niche.
158+
let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
159+
if let Some(niche) = niche {
160+
match st.largest_niche {
161+
Some(largest_niche) => {
162+
// Replace the existing niche even if they're equal,
163+
// because this one is at a lower offset.
164+
if largest_niche.available(dl) <= niche.available(dl) {
165+
st.largest_niche = Some(niche);
166+
}
167+
}
168+
None => st.largest_niche = Some(niche),
169+
}
170+
}
171+
}
172+
_ => user_error!("nonscalar layout for layout_scalar_valid_range"),
140173
}
174+
141175
return Ok(st);
142176
}
143177

@@ -591,6 +625,22 @@ pub fn layout_of_adt_query(
591625
Ok(best_layout.layout)
592626
}
593627

628+
fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound<u128>, Bound<u128>) {
629+
let attrs = db.attrs(def.into());
630+
let get = |name| {
631+
let attr = attrs.by_key(name).tt_values();
632+
for tree in attr {
633+
if let Some(x) = tree.token_trees.first() {
634+
if let Ok(x) = x.to_string().parse() {
635+
return Bound::Included(x);
636+
}
637+
}
638+
}
639+
Bound::Unbounded
640+
};
641+
(get("rustc_layout_scalar_valid_range_start"), get("rustc_layout_scalar_valid_range_end"))
642+
}
643+
594644
pub fn layout_of_adt_recover(
595645
_: &dyn HirDatabase,
596646
_: &[String],

crates/hir-ty/src/layout/tests.rs

+13
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,19 @@ fn tuple() {
146146
}
147147
}
148148

149+
#[test]
150+
fn non_zero() {
151+
check_size_and_align(
152+
r#"
153+
//- minicore: non_zero, option
154+
use core::num::NonZeroU8;
155+
struct Goal(Option<NonZeroU8>);
156+
"#,
157+
1,
158+
1,
159+
);
160+
}
161+
149162
#[test]
150163
fn niche_optimization() {
151164
check_size_and_align(

crates/test-utils/src/minicore.rs

+10
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
//! index: sized
3030
//! iterator: option
3131
//! iterators: iterator, fn
32+
//! non_zero:
3233
//! option:
3334
//! ord: eq, option
3435
//! pin:
@@ -680,6 +681,15 @@ mod macros {
680681
}
681682
// endregion:derive
682683

684+
// region:non_zero
685+
pub mod num {
686+
#[repr(transparent)]
687+
#[rustc_layout_scalar_valid_range_start(1)]
688+
#[rustc_nonnull_optimization_guaranteed]
689+
pub struct NonZeroU8(u8);
690+
}
691+
// endregion:non_zero
692+
683693
// region:bool_impl
684694
#[lang = "bool"]
685695
impl bool {

0 commit comments

Comments
 (0)