Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Closes #471] Add const_assert_generics module #489

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions kernel-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ test = []
[profile.dev]
panic = "abort"
opt-level = 1
incremental = false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아직 const_evaluatable_check feature가 unstable해서, 이걸 끄지 않고 debug mode로 컴파일하면 ICE가 발생합니다. (rust-lang/rust#77708)


[profile.release]
panic = "abort"
Expand Down
2 changes: 2 additions & 0 deletions kernel-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
#![feature(const_fn)]
#![feature(const_fn_fn_ptr_basics)]
#![feature(const_fn_union)]
#![feature(const_generics)]
#![feature(const_evaluatable_checked)]
#![feature(const_precise_live_drops)]
#![feature(const_trait_impl)]
#![feature(generic_associated_types)]
Expand Down
15 changes: 5 additions & 10 deletions kernel-rs/src/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use core::{
use static_assertions::const_assert;

use crate::arch::addr::{PAddr, PGSIZE};
use crate::util::const_assert_generics::{Assert2, True};

// `RawPage` must be aligned with PGSIZE.
const_assert!(PGSIZE == 4096);
Expand Down Expand Up @@ -75,16 +76,10 @@ impl Page {
}
}

pub fn as_uninit_mut<T>(&mut self) -> &mut MaybeUninit<T> {
// TODO(https://github.com/kaist-cp/rv6/issues/471):
// Use const_assert! (or equivalent) instead. Currently, use of T inside const_assert!
// incurs a compile error: "can't use generic parameters from outer function".
// Also, there's a workaround using feature(const_generics) and
// feature(const_evaluatable_checked). However, using them makes the compiler panic.
// When the compiler becomes updated, we will fix the following lines to use static checks.
assert!(mem::size_of::<T>() <= PGSIZE);
assert_eq!(PGSIZE % mem::align_of::<T>(), 0);

pub fn as_uninit_mut<T>(&mut self) -> &mut MaybeUninit<T>
where
Assert2<{ mem::size_of::<T>() <= PGSIZE }, { PGSIZE % mem::align_of::<T>() == 0 }>: True,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

참고: 이 줄을 Assert({mem::size_of::<T>() <= PGSIZE && PGSIZE % mem::align_of::<T>() == 0}>: True로 변경하면, const expression이 너무 복잡하니 const fn으로 대체하라는 에러가 발생하게 됩니다.
그래서, 부득이하게 Assert2를 추가했습니다.

{
// SAFETY: self.inner is an array of length PGSIZE aligned with PGSIZE bytes.
// The above assertions show that it can contain a value of T. As it contains arbitrary
// data, we cannot treat it as &mut T. Instead, we use &mut MaybeUninit<T>. It's ok because
Expand Down
28 changes: 28 additions & 0 deletions kernel-rs/src/util/const_assert_generics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//! Types that let you compile-time assert in `where` clauses,
//! especially about the input generic parameters.
//!
//! # Example
//! ```rust,no_run
//! # use core::mem;
//! #![feature(const_generics)]
//! #![feature(const_evaluatable_checked)]
//!
//! unsafe fn transmute<T, U>(t: T) -> U
//! where
//! Assert2<
//! { mem::size_of::<T>() == mem::size_of::<U>() },
//! { mem::align_of::<T>() == mem::align_of::<U>() },
//! >: True
//! {
//! /* Omitted */
//! }
//! ```

pub struct Assert<const EXPR: bool>;
pub struct Assert2<const EXPR: bool, const EXPR2: bool>;
pub struct Assert3<const EXPR: bool, const EXPR2: bool, const EXPR3: bool>;

pub trait True {}
impl True for Assert<true> {}
impl True for Assert2<true, true> {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 저는 Assert 하나만 남기는게 어떨까 합니다. 두번 쓰면 되니까...
  • 혹시 error message도 넣을 수 있을까요?
  • 이 기능을 제공하는 혹시 별도 crate이 있나요? 있으면 그걸 쓰는게 좋을 것 같아서요.

Copy link
Collaborator Author

@travis1829 travis1829 Apr 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 아쉽지만, 다음과 같은 방법을 쓰려고 하면 compile error가 발생합니다.
    pub fn as_uninit_mut<T>(&mut self) -> &mut MaybeUninit<T>
        where
            Assert<{ mem::size_of::<T>() <= PGSIZE }>: True, Assert<{ PGSIZE % mem::align_of::<T>() == 0 }>: True
  • error message를 넣는건 안 될것 같습니다. macro를 쓰면 가능할지도 모르겠는데, where clause에서는 macro자체를 쓸 수 없는 것 같습니다.
    • 참고로, 지금은 이런 에러 메세지를 띄웁니다.
    mismatched types
    expected type `false`
       found type `true`
    
  • 따로 이런 crate가 존재하지는 않는 것 같습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

impl True for Assert3<true, true, true> {}
1 change: 1 addition & 0 deletions kernel-rs/src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// TODO(https://github.com/kaist-cp/rv6/issues/120)
#![allow(dead_code)]

pub mod const_assert_generics;
pub mod etrace;
pub mod list;
pub mod pinned_array;
Expand Down