Thanks again to Open Source Security, inc and Embecosm for their ongoing support for this project.
Milestone Progress
We continued to make progress on many fronts last week. The incremental refactor to coercion sites is key as the goal here not only ensures our implementation conforms to Rustc, it will eventually improve our location information for diagnostics on type errors and clean up a lot of code. We have also made a lot of progress in bugs, in general, this week by closing out existing issues that have already been fixed and reviewing and merging outstanding fixes.
Our GSoC project into constexpr is progressing nicely (code is not merged into main yet), with many control flow mechanisms such as conditionals and loops starting to work. We will need to start working on a cleanup effort to make the code mergeable back to main soon.
One missing piece of our GitHub CI is that we are not running our test suite for the 32-bit configuration, so we have regressed on 32-bit systems because of a fix that went into our transmute implementation. We will add the -m32 flags to our testing phase in CI to try and catch these issues as part of pull requests.
In other news, our integration tests of the Blake3 and libcore SIP hasher have made quite a lot of progress. The blake3 test case in particular, is only missing for loop support and some minor issues in parsing range syntax to close the topic out now.
As for our GCC patches, version two of the patches is still a work in progress as it takes time to build up the patches to ensure each one is buildable, but splitting each pass up here looks like a good solution for review purposes.
Completed Activities
- Fix bug in recurisve macro expansion PR1429
- Make builtin macro expansion more conformant to rustc PR1430
- Fix bad transmute of aggregate types PR1433
- Incremental refactor for conformant coercion sites pt1 PR1431
- Update type hasher to stop bad converions during codegen PR1435
- Array index access does not need to unsize to a slice PR1437
- Add test case for calling builtin macro when it does not exist PR1442
- Simplify testcase PR1438
Contributors this week
Overall Task Status
Category | Last Week | This Week | Delta |
TODO | 160 | 157 | -3 |
In Progress | 29 | 29 | – |
Completed | 420 | 430 | +10 |
Test Cases
Category | Last Week | This Week | Delta |
Passing | 6531 | 6607 | +76 |
Failed | – | – | – |
XFAIL | 51 | 51 | – |
XPASS | – | – | – |
Bugs
Category | Last Week | This Week | Delta |
TODO | 55 | 54 | -1 |
In Progress | 13 | 14 | +1 |
Completed | 178 | 185 | +7 |
Milestone Progress
Milestone | Last Week | This Week | Delta | Start Date | Completion Date | Target |
Data Structures 1 – Core | 100% | 100% | – | 30th Nov 2020 | 27th Jan 2021 | 29th Jan 2021 |
Control Flow 1 – Core | 100% | 100% | – | 28th Jan 2021 | 10th Feb 2021 | 26th Feb 2021 |
Data Structures 2 – Generics | 100% | 100% | – | 11th Feb 2021 | 14th May 2021 | 28th May 2021 |
Data Structures 3 – Traits | 100% | 100% | – | 20th May 2021 | 17th Sept 2021 | 27th Aug 2021 |
Control Flow 2 – Pattern Matching | 100% | 100% | – | 20th Sept 2021 | 9th Dec 2021 | 29th Nov 2021 |
Macros and cfg expansion | 100 | 100% | – | 1st Dec 2021 | 31st Mar 2022 | 28th Mar 2022 |
Imports and Visibility | 100% | 100% | – | 29th Mar 2022 | 13th Jul 2022 | 27th May 2022 |
Const Generics | 45% | 50% | +5% | 30th May 2022 | – | 17th Oct 2022 |
Intrinsics | 0% | 0% | – | 6th Sept 2022 | – | 14th Nov 2022 |
Risks
Risk | Impact (1-3) | Likelihood (0-10) | Risk (I * L) | Mitigation |
Rust Language Changes | 2 | 7 | 14 | Target specific Rustc version for first go |
Missing GCC 13 upstream window | 1 | 6 | 6 | Merge in GCC 14 and be proactive about reviews |
Planned Activities
- Prepare gcc patches v2
- Continue work on const evaluation
Detailed changelog
Deref coercions
We have started an incremental refactor to cleanup how our type system works. The refactor here is focused on coercion sites firstly so that we become more conformant to Rustc. So for example now we can support deref coercions which can look pretty strange from a language perspective, here we are “borrowing foo” which actually ends up producing a deref call to unbox the generic structure foo. This same autoderef cycle already occurs in method resolution but is also supported in coercion sites.
extern "C" {
fn printf(s: *const i8, ...);
}
struct Foo<T>(T);
impl<T> core::ops::Deref for Foo<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn main() {
let foo: Foo<i32> = Foo(123);
let bar: &i32 = &foo;
unsafe {
let a = "%i\n\0";
let b = a as *const str;
let c = b as *const i8;
printf(c, *bar);
}
}
see: https://godbolt.org/z/qPz6G84hd
Array index does not need to unsize
When working through some complex test cases where we define the libcore code for slice creation and access, then add in normal array index operations there was an issue that gccrs always produced an unsize coercion for arrays to a slice in order to do array index access. This is completly unnecessary but could be technically valid rust code since it is valid to unsize an array to a slice. It does however miss GCC -Warray-bounds checking at compile time and add in unnessecary overhead in non optimized builds.
mod intrinsics {
extern "rust-intrinsic" {
pub fn offset<T>(ptr: *const T, count: isize) -> *const T;
}
}
mod mem {
extern "rust-intrinsic" {
fn size_of<T>() -> usize;
}
}
extern "C" {
fn printf(s: *const i8, ...);
}
struct FatPtr<T> {
data: *const T,
len: usize,
}
pub union Repr<T> {
rust: *const [T],
rust_mut: *mut [T],
raw: FatPtr<T>,
}
pub enum Option<T> {
None,
Some(T),
}
#[lang = "Range"]
pub struct Range<Idx> {
pub start: Idx,
pub end: Idx,
}
#[lang = "const_slice_ptr"]
impl<T> *const [T] {
pub const fn len(self) -> usize {
let a = unsafe { Repr { rust: self }.raw };
a.len
}
pub const fn as_ptr(self) -> *const T {
self as *const T
}
}
#[lang = "const_ptr"]
impl<T> *const T {
pub const unsafe fn offset(self, count: isize) -> *const T {
unsafe { intrinsics::offset(self, count) }
}
pub const unsafe fn add(self, count: usize) -> Self {
unsafe { self.offset(count as isize) }
}
pub const fn as_ptr(self) -> *const T {
self as *const T
}
}
const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
unsafe {
Repr {
raw: FatPtr { data, len },
}
.rust
}
}
#[lang = "index"]
trait Index<Idx> {
type Output;
fn index(&self, index: Idx) -> &Self::Output;
}
impl<T> [T] {
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub const fn len(&self) -> usize {
unsafe { Repr { rust: self }.raw.len }
}
}
pub unsafe trait SliceIndex<T> {
type Output;
fn get(self, slice: &T) -> Option<&Self::Output>;
unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
fn index(self, slice: &T) -> &Self::Output;
}
unsafe impl<T> SliceIndex<[T]> for usize {
type Output = T;
fn get(self, slice: &[T]) -> Option<&T> {
unsafe { Option::Some(&*self.get_unchecked(slice)) }
}
unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
// SAFETY: the caller guarantees that `slice` is not dangling, so it
// cannot be longer than `isize::MAX`. They also guarantee that
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
// so the call to `add` is safe.
unsafe { slice.as_ptr().add(self) }
}
fn index(self, slice: &[T]) -> &T {
unsafe { &*self.get_unchecked(slice) }
}
}
unsafe impl<T> SliceIndex<[T]> for Range<usize> {
type Output = [T];
fn get(self, slice: &[T]) -> Option<&[T]> {
if self.start > self.end || self.end > slice.len() {
Option::None
} else {
unsafe { Option::Some(&*self.get_unchecked(slice)) }
}
}
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
unsafe {
let a: *const T = slice.as_ptr();
let b: *const T = a.add(self.start);
slice_from_raw_parts(b, self.end - self.start)
}
}
fn index(self, slice: &[T]) -> &[T] {
unsafe { &*self.get_unchecked(slice) }
}
}
impl<T, I> Index<I> for [T]
where
I: SliceIndex<[T]>,
{
type Output = I::Output;
fn index(&self, index: I) -> &I::Output {
unsafe {
let a = "slice-index\n\0";
let b = a as *const str;
let c = b as *const i8;
printf(c);
}
index.index(self)
}
}
fn main() -> i32 {
let a = [1, 2, 3, 4, 5];
let b = a[1];
b - 2
}
see: https://godbolt.org/z/q3rEdjr1e
Integration tests update
We have a hit a break through we our blake3 integration test, so that most of the code now compiles. The remaining issues we have our missing for-loop support and some minor bugs in our range syntax to finish this off. For loop’s sound simple but they actualy depend on a tremendous amount of libcore code, but the benifit here is that once you support for loops you implicitly support iterators from libcore because a for loop is syntactic sugar for calling IntoIterator and calling next with a check on the result on whether to break or not. If you are interested in what this means, try compiling an empty for loop on compiler explorer for Rustc and see how much code is produced when optimizations are turned off to see what we mean.
see: