Thanks again to Open Source Security, inc and Embecosm for their ongoing support for this project.
Milestone Progress
Another week of steady progress, where we landed the initial support for operator overloading, was all due to merging the lang-items work, which has unblocked a bunch of stuff within the compiler. The other major work was the first steps to remove the GCC abstractions we inherited from gccgo. The goal of GCC Rust has always been to make a GCC quality front-end for Rust and the GCC tree structures are very well suited to static analysis, and removing this abstraction will make work on const generics down the line much more straightforward.
This milestone has been an excellent opportunity to test the front-end on more complex test cases and fix bugs arising from this, which overall is hardening the code paths and understanding how Rust works in general.
Thank you to everyone who continues to support and work on the compiler.
Completed Activities
- Merge LangItems work and operator overloading support PR801
- Remove Btype, Bexpression, etc. abstractions over gcc trees PR805
- Fix MethodCalls for covariant impl blocks PR810
- Remove implicit name hack for trait associated types PR811
Contributors this month
Overall Task Status
Category | Last Week | This Week | Delta |
TODO | 93 | 93 | — |
In Progress | 14 | 17 | +3 |
Completed | 244 | 246 | +2 |
Test Cases
Category | Last Week | This Week | Delta |
Passing | 4931 | 5106 | +255 |
XFAIL | 21 | 21 | – |
Bugs
Category | Last Week | This Week | Delta |
TODO | 23 | 24 | +1 |
In Progress | 4 | 6 | +2 |
Completed | 86 | 87 | +1 |
Milestones 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 | 70% | 80% | +10% | 20th Sept 2021 | – | 29th Nov 2021 |
Macros and cfg expansion | 0% | 0% | – | 1st Dec 2021 | – | 28th Mar 2022 |
Imports and Visibility | 0% | 0% | – | 29th Mar 2022 | – | 27th May 2022 |
Const Generics | 0% | 0% | – | 30th May 2022 | – | 25th Jul 2022 |
Intrinsics | 0% | 0% | – | 6th Sept 2021 | – | 30th Sept 2022 |
Risks
Risk | Impact (1-3) | Likelihood (0-10) | Risk (I * L) | Mitigation |
Rust Language Changes | 3 | 7 | 21 | Keep up to date with the Rust language on a regular basis |
Going over target dates | 3 | 5 | 15 | Maintain status reports and issue tracking to stakeholders |
Planned Activities
- Finish work code generation for enums
- Fix Qualified Path bug
Detailed changelog
Operator Overloading
Rust supports operator overloading of many different operations, we have added support for all the regular arithmetic operators (+,-,*,/,%), compound assignments such as (+=, …), the unary negation operators (!x, and -x). There is support for the deref operations but there are a few bugs to work through there to get it right. Since we cannot compile libcore yet we require you to define the lang items you want to use within your crate, we have taken the same traits from libcore to be sure that we can compile them correctly.
extern "C" {
fn printf(s: *const i8, ...);
}
#[lang = "add"]
pub trait Add<Rhs = Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
impl Add for i32 {
type Output = i32;
fn add(self, other: i32) -> i32 {
self + other
}
}
struct Foo(i32);
impl Add for Foo {
type Output = Foo;
fn add(self, other: Foo) -> Foo {
Foo(self.0 + other.0)
}
}
fn main() {
let res;
res = Foo(1) + Foo(2);
unsafe {
let a = "%i\n\0";
let b = a as *const str;
let c = b as *const i8;
printf(c, res.0);
}
}
The purpose of this test case is to ensure that when we add the Foo structure together that it will break down into calling the operator overload for i32. It should be noted that when you turn on optimizations these function calls are fully inlined just like C++ operator overloads.
See compiler explorer for more information https://godbolt.org/z/95bc4eWPW
Covariant Self’s within impl blocks
Impl blocks on rust support all types without bounds. Which mens the specified Self type for an impl block in this examples case is a reference to a generic type parameter. This means when we do a method call we must handle this case. Method resolution breaks down into two phases, the candidate probe then the actual resolution from the candidates. The first is about searching for a function named correctly which matches the impl block Self type then we use the autoderef mechanism to match the self parameter to find the candidate. Probing for candidates in method calls is a little bit unclear to me yet, but I believe the correct mechanism is meant to be looking for any impl block with a function named correctly then check via autodref if our receiver can be autoderef’d to the impl blocks implicit Self type to find all the potential candidates. Then we autoderef on small self.
pub trait Foo {
type Target;
fn bar(&self) -> &Self::Target;
}
impl<T> Foo for &T {
type Target = T;
fn bar(&self) -> &T {
*self
}
}
pub fn main() {
let a: i32 = 123;
let b: &i32 = &a;
b.bar();
}
Remove GCC abstraction types
- The goal of GCC Rust has always been to make a GCC quality front-end for Rust.
- This means this goal comes first before any long term goal of porting the code to new compiler platforms etc.
- The GCC IR is very suitable for further static analysis, and the abstractions will make this very awkward.
- In the long term, we could potentially look at building a borrow checker at the GENERIC tree level, which might have some interesting code to share with wider GCC.
- Constant Folding
- Const Generics will be very awkward until this is removed.
- The abstraction requires features such as constant Folding, which does not fit very well right now.
So overall removing the abstraction is going to make some things much easier to work with. For example, in the short term, code generation for unions/ADTs/match-expr could be simplified a lot if we remove this. It also might help attract more GCC people to work with the backend code generation piece to clean up the code here.