diff options
| -rw-r--r-- | crates/hir-ty/src/layout/adt.rs | 50 | ||||
| -rw-r--r-- | crates/hir-ty/src/layout/tests.rs | 13 | ||||
| -rw-r--r-- | crates/test-utils/src/minicore.rs | 10 |
3 files changed, 73 insertions, 0 deletions
diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index e353034eb99..9244353f3ae 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -4,6 +4,7 @@ use std::{ cmp::{self, Ordering}, iter, num::NonZeroUsize, + ops::Bound, }; use chalk_ir::TyKind; @@ -18,6 +19,8 @@ use hir_def::{ }; use la_arena::{ArenaMap, RawIdx}; +struct X(Option<NonZeroUsize>); + use crate::{ db::HirDatabase, lang_items::is_unsafe_cell, @@ -137,7 +140,38 @@ pub fn layout_of_adt_query( Abi::Aggregate { sized: _ } => {} } st.largest_niche = None; + return Ok(st); + } + + let (start, end) = layout_scalar_valid_range(db, def); + match st.abi { + Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { + if let Bound::Included(start) = start { + let valid_range = scalar.valid_range_mut(); + valid_range.start = start; + } + if let Bound::Included(end) = end { + let valid_range = scalar.valid_range_mut(); + valid_range.end = end; + } + // Update `largest_niche` if we have introduced a larger niche. + let niche = Niche::from_scalar(dl, Size::ZERO, *scalar); + if let Some(niche) = niche { + match st.largest_niche { + Some(largest_niche) => { + // Replace the existing niche even if they're equal, + // because this one is at a lower offset. + if largest_niche.available(dl) <= niche.available(dl) { + st.largest_niche = Some(niche); + } + } + None => st.largest_niche = Some(niche), + } + } + } + _ => user_error!("nonscalar layout for layout_scalar_valid_range"), } + return Ok(st); } @@ -591,6 +625,22 @@ pub fn layout_of_adt_query( Ok(best_layout.layout) } +fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound<u128>, Bound<u128>) { + let attrs = db.attrs(def.into()); + let get = |name| { + let attr = attrs.by_key(name).tt_values(); + for tree in attr { + if let Some(x) = tree.token_trees.first() { + if let Ok(x) = x.to_string().parse() { + return Bound::Included(x); + } + } + } + Bound::Unbounded + }; + (get("rustc_layout_scalar_valid_range_start"), get("rustc_layout_scalar_valid_range_end")) +} + pub fn layout_of_adt_recover( _: &dyn HirDatabase, _: &[String], diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index 9543b4dcbc6..1cd6d4eae24 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -147,6 +147,19 @@ fn tuple() { } #[test] +fn non_zero() { + check_size_and_align( + r#" + //- minicore: non_zero, option + use core::num::NonZeroU8; + struct Goal(Option<NonZeroU8>); + "#, + 1, + 1, + ); +} + +#[test] fn niche_optimization() { check_size_and_align( r#" diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 69d2e62b256..af9efd2600e 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -29,6 +29,7 @@ //! index: sized //! iterator: option //! iterators: iterator, fn +//! non_zero: //! option: //! ord: eq, option //! pin: @@ -680,6 +681,15 @@ mod macros { } // endregion:derive +// region:non_zero +pub mod num { + #[repr(transparent)] + #[rustc_layout_scalar_valid_range_start(1)] + #[rustc_nonnull_optimization_guaranteed] + pub struct NonZeroU8(u8); +} +// endregion:non_zero + // region:bool_impl #[lang = "bool"] impl bool { |
