diff --git a/src/addr.rs b/src/addr.rs index 5cac6c2db..1c93f0219 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -531,21 +531,25 @@ impl Sub for PhysAddr { /// Align address downwards. /// -/// Returns the greatest x with alignment `align` so that x <= addr. The alignment must be -/// a power of 2. +/// Returns the greatest `x` with alignment `align` so that `x <= addr`. +/// +/// Panics if the alignment is not a power of two. Without the `const_fn` +/// feature, the panic message will be "index out of bounds". #[inline] -pub fn align_down(addr: u64, align: u64) -> u64 { - assert!(align.is_power_of_two(), "`align` must be a power of two"); +pub const fn align_down(addr: u64, align: u64) -> u64 { + const_assert!(align.is_power_of_two(), "`align` must be a power of two"); addr & !(align - 1) } /// Align address upwards. /// -/// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be -/// a power of 2. +/// Returns the smallest `x` with alignment `align` so that `x >= addr`. +/// +/// Panics if the alignment is not a power of two. Without the `const_fn` +/// feature, the panic message will be "index out of bounds". #[inline] -pub fn align_up(addr: u64, align: u64) -> u64 { - assert!(align.is_power_of_two(), "`align` must be a power of two"); +pub const fn align_up(addr: u64, align: u64) -> u64 { + const_assert!(align.is_power_of_two(), "`align` must be a power of two"); let align_mask = align - 1; if addr & align_mask == 0 { addr // already aligned diff --git a/src/lib.rs b/src/lib.rs index 42be18368..cf146e31a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,19 @@ macro_rules! const_fn { }; } +// Helper method for assert! in const fn. Uses out of bounds indexing if an +// assertion fails and the "const_fn" feature is not enabled. +#[cfg(feature = "const_fn")] +macro_rules! const_assert { + ($cond:expr, $($arg:tt)+) => { assert!($cond, $($arg)*) }; +} +#[cfg(not(feature = "const_fn"))] +macro_rules! const_assert { + ($cond:expr, $($arg:tt)+) => { + [(); 1][!($cond as bool) as usize] + }; +} + #[cfg(all(feature = "instructions", feature = "external_asm"))] pub(crate) mod asm; diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index f71a8c11c..c96d81161 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -117,13 +117,10 @@ impl GlobalDescriptorTable { let mut table = [0; 8]; let mut idx = 0; - #[cfg(feature = "const_fn")] - assert!( + const_assert!( next_free <= 8, "initializing a GDT from a slice requires it to be **at most** 8 elements." ); - #[cfg(not(feature = "const_fn"))] - [(); 1][!(next_free <= 8) as usize]; while idx != next_free { table[idx] = slice[idx]; @@ -144,7 +141,8 @@ impl GlobalDescriptorTable { const_fn! { /// Adds the given segment descriptor to the GDT, returning the segment selector. /// - /// Panics if the GDT has no free entries left. + /// Panics if the GDT has no free entries left. Without the `const_fn` + /// feature, the panic message will be "index out of bounds". #[inline] pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector { let index = match entry {