GCC Rust Monthly Report #10 September 2021

Thanks again to Open Source Security, inc and Embecosm for their ongoing support for this project.

Milestone Progress

September was another great month for GCC Rust. We finished the trait resolution milestone and have now moved onto control flow two, which focuses on pattern matching semantics; this milestone should also serve to clean up some general aspects of the compiler.

By December, we are aiming to try and compile our first real rust project: https://github.com/BLAKE3-team/BLAKE3/blob/master/reference_impl/reference_impl.rs

If anyone has more suggestions for simple rust projects, please send them to us; this project, blake3, will require us to amend the program to remove the use statements and include this code ourselves, so we do not require the standard library. The goal here is to find as many gaps and bugs, and I would expect even if the compiler can compile the project, we likely have bugs to work through to compile it correctly. I have also completed more timeline planning for the next year of milestones and updated the planning spreadsheet to contain a chart displaying my plan to a working GCC front-end for rust. https://docs.google.com/spreadsheets/d/1B_JFzHgGclpdtPcQvnThkNJnP7Hh8fCIAU1rYFu_23M/edit?usp=sharing

Thank you to everyone who continues to support and work on the compiler.

Linux Plumbers 2021

You can find my talk over on the Linux Plumbers YouTube channel: https://youtu.be/ORwYx5_zmZo?t=8903

It was a great chance to try and show the compiler I hope people found it interesting and if people have questions please join us on zulip or the mailing list.

Monthly Community Call

We had our 7th community call on 1st October 2021 you can find the meeting notes over here: https://github.com/Rust-GCC/Reporting/blob/main/2021-10-01-community-call.md

Detailed changelog

Qualified Paths In Type

In rust there are two types of qualified paths:

These can also reference generic traits which can have generic associated types. This is where rustc’s Type Projections come into play.

trait Foo<T> {
    type A;

    fn test(a: T, b: Self::A) -> (T, Self::A) {
        (a, b)
    }
}

struct Bar<T>(T);
impl<T> Foo<T> for Bar<T> {
    type A = T;
}

pub fn main() {
    let a;
    a = Bar(123);

    let b: <Bar<i32> as Foo<i32>>::A;
    b = 456;

    let c;
    c = <Bar<i32> as Foo<i32>>::test(a.0, 123);
}

The difficultly in this test case is handling the generic associated type. Since the Placeholder Types don’t support the binding of substitutions it took me a while to figure out how to handle this. The only types in the compiler type system that support generic substitutions are algebraic data types and functions (so far). This means the type alias for the associated types needs a method to handle this and this is how projections bind the generic arguments in such a way that a recursive chain is formed to handle this case.

See this commit for more info on the details: https://github.com/Rust-GCC/gccrs/commit/0798add3d3c1bf4b20ecc1b4fa1047ba4ba19759

Super Traits

Getting super traits working is a bit like lowering a trait definition like this:

trait A: B {}
trait A where Self: B {}

Pretty much all of the items in a trait declaration are a bunch of generic functions with the implicit TypeParameter of Self which has the Bound of the super Trait. This example below demonstrates how we combine super traits and qualified paths. Thanks to Philipp Krones for writing this test case.

extern "C" {
    fn printf(s: *const i8, ...);
}

trait A {
    fn a() -> i32 {
        123
    }
}

trait B: A {
    fn b() -> i32 {
        <T as A>::a() + 456
    }
}

struct T;
impl A for T {
    fn a() -> i32 {
        321
    }
}

struct S;
impl A for S {}
impl B for S {}

fn main() -> i32 {
    let aa = S::a();
    let bb = S::b();

    unsafe {
        let a = "%i, %i\n\0";
        let b = a as *const str;
        let c = b as *const i8;

        printf(c, aa, bb);
    }
    0
}

ABI Options

We have added the initial support for other ABI options for example:

extern "stdcall" {
    pub fn test(a: i32) -> i32;
}

extern "C" {
    fn printf(s: *const i8, ...);
}

fn main() -> i32 {
    unsafe {
        let a = 3;
        let res = test(a);

        let a = "%i\n\0";
        let b = a as *const str;
        let c = b as *const i8;

        printf(c, res);
    }
    0
}

Which can be linked against C code such as:

__attribute__ ((stdcall)) int test(int x)  {
  return x + 3;
}

This ABI option can then be used by compiling like this:

$ gccrs -g -O0 -m32 -c test.rs -o test.o
$ gcc -g -O0 -m32 -c lib.c -o lib.o
$ gcc -m32 -o test test.o lib.o

Multiple File Parsing

Thanks to Marc Poulhiès and Arthur Cohen their combined efforts have now let the GCC Rust compiler expand modules

#[path ="modules/valid_path.rs"]
mod path_without_extra_equal;

mod some_module;

Note we still do not have support for visibility modifiers.

Intrinsics

extern "rust-intrinsic" {
    pub fn sqrtf32(x: f32) -> f32;
    pub fn sinf32(x: f32) -> f32;
}

fn main() {
    let mut f32;

    f32 = sqrtf32(5f32);
    f32 = sinf32(39f32);
}

We have only implemented some basic intrinsics so far there is a lot work though see this checklist. Note that we have not implemented the feature gate around allowing users to define this rust-intrinsic block.

Autodref for the dot operator

This example looks similar to stuff we have been able to compile for a while, but we have added in support for the autoderef system such that we can compile this method if we have a reference or we don’t, so the compiler will inject the correct adjustments for the method call for the self argument to be correct. For more information please read: https://doc.rust-lang.org/nightly/nomicon/dot-operator.html

extern "C" {
    fn printf(s: *const i8, ...);
}

struct Foo(i32);
impl Foo {
    fn bar(&self, i: i32) {
        unsafe {
            let a = "%i\n\0";
            let b = a as *const str;
            let c = b as *const i8;

            printf(c, self.0 + i);
        }
    }
}

fn main() {
    let a = Foo(123);
    a.bar(1);

    let b = &Foo(456);
    b.bar(2);
}

https://godbolt.org/z/1heerndbs

Allow GCC to inline

When the Rust for Linux project posted a compiler explorer example comparing compilers it was noticed GCC Rust was missing a case for optimization, see the bug: https://github.com/Rust-GCC/gccrs/issues/547. This was due to all functions in GCC Rust being marked wrongly with DECL_UNINLINEABLE which stops GCC from performing all optimizations required. This is a useful flag, and will likely be used for the main-shim in rust, this ensures on stack unwinding there is frame information left on the stack. See https://godbolt.org/z/4fcf1sv7z

Dynamic Dispatch

We have added initial support for dynamic dispatch which adds code generation for coercion sites such as assignments to generate the vtable and trait object. https://godbolt.org/z/bvxE95rzY

extern "C" {
    fn printf(s: *const i8, ...);
}

struct Foo(i32);
trait Bar {
    fn baz(&self);
}

impl Bar for Foo {
    fn baz(&self) {
        unsafe {
            let a = "%i\n\0";
            let b = a as *const str;
            let c = b as *const i8;

            printf(c, self.0);
        }
    }
}

fn static_dispatch<T: Bar>(t: &T) {
    t.baz();
}

fn dynamic_dispatch(t: &dyn Bar) {
    t.baz();
}

fn main() {
    let a = &Foo(123);
    static_dispatch(a);

    let b: &dyn Bar = a;
    dynamic_dispatch(b);
}

Object Safety checks

As part of doing dynamic dispatch rust enforces rules on what type of traits are deemed object safe for example see:

struct Foo(i32);

trait Bar {
    const A: i32 = 123;
    fn B();
    fn C(&self);
}

pub fn main() {
    let a;
    a = Foo(123);

    let b: &dyn Bar = &a;
}

Here the trait Bar contains two trait items which are not object safe and this results in this error:

<source>:13:13: error: trait bound is not object safe
    4 |     const A: i32 = 123;
      |     ~        
    5 |     fn B();
      |     ~        
......
   13 |     let b: &dyn Bar = &a;
      |             ^

Here the trait B is object safe but its super-trait A is not so we result in an error such as:

struct Foo(i32);

trait A {
    const A: i32 = 123;
    fn B();
    fn C(&self);
}

trait B: A {
    fn test(&self);
}

pub fn main() {
    let a;
    a = Foo(123);

    let b: &dyn B = &a;
}
<source>:17:13: error: trait bound is not object safe
    3 | trait A {
      | ~            
......
   17 |     let b: &dyn B = &a;
      |             ^

Fix GCC Bootstrap builds

Thanks to our whole community who have worked on this to eliminate all the compiler warnings which allows us to perform a full GCC bootstrap build. See our tracking issue for all related fixes to get this working: https://github.com/Rust-GCC/gccrs/issues/336

We will need to add some automation to track compiler warnings in the CI build to catch regressions for bootstrap builds in PR’s.

Merge from upstream GCC

Thanks to Thomas Schwinge we have merged with the latest upstream GCC. The last merge was completed in and around six months ago, this means we get all the relevant updates for DCO contributions and ensure our front-end code is not drifting to become unmergeable. See below before what the –version looked like:

gccrs (GCC) 11.0.1 20210325 (experimental)
Copyright © 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

After

gccrs (GCC) 12.0.0 20210917 (experimental)
Copyright © 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Fix bug with out of range characters

Mark Wielaard identified a bug with our lexer which was incorrectly flagging byte with their high-bit set, this was due to a bad unsigned vs signed check.

bytecharstring.rs:3:14: error: ‘byte char’ ‘�’ out of range
    3 |   let _bc = b'\x80';
      |              ^
bytecharstring.rs:4:14: error: character ‘�’ in byte string out of range
    4 |   let _bs = b"foo\x80bar";
      |              ^

Byte Strings

GCC Rust used a fall though case to implement byte strings as normal str types which was wrong. Byte strings are actually arrays of u8’s for example:

fn main() {
    let a: &[u8; 4];
    a = b"test";
}

Completed Activities

  • Generic Qualified Paths PR655
  • Add missing location info to struct fields and cleanup PR652
  • Cleanup Struct Expression classes PR654
  • Qualified Paths PR651
  • Super Traits PR669 PR666 PR662
  • Support stdcall, fastcall, cdecl ABI options PR661
  • Multiple File Parsing Support PR663 PR664 PR639
  • Initial Compiler Intrinsics PR659 PR660
  • Add compiler switch for mangling options PR656
  • Initial building blocks for enum support PR657
  • TraitObject Support PR684 PR680
  • Autoderef PR672 PR671
  • Fix bug with calling methods via type-bound PR679
  • Allow GCC to decide to inline PR673
  • Building blocks for V0 mangling support PR685
  • Fix bug with generics and unit-types PR674
  • Fix bootstrap build PR689 PR690 PR688
  • Fix bug in lexer for out of range characters PR687
  • Implement Byte Strings PR698

Contributors this month

Overall Task Status

CategoryLast MonthThis MonthDelta
TODO8994+5
In Progress79+2
Completed184199+15
GitHub Issues

Test Cases

CategoryLast MonthThis MonthDelta
Passing40954468+373
XFAIL2121
make check-rust

Bugs

CategoryLast MonthThis MonthDelta
TODO1821+3
In Progress34+1
Completed6469+5
GitHub Bugs

Milestones Progress

MilestoneLast MonthThis MonthDeltaStart DateCompletion DateTarget
Data Structures 1 – Core100%100%30th Nov 202027th Jan 202129th Jan 2021
Control Flow 1 – Core100%100%28th Jan 202110th Feb 202126th Feb 2021
Data Structures 2 – Generics100%100%11th Feb 202114th May 202128th May 2021
Data Structures 3 – Traits88%100%+12%20th May 202117th Sept 202127th Aug 2021
Control Flow 2 – Pattern Matching0%7%+7%20th Sept 202129th Nov 2021
Macros and cfg expansion0%0%1st Dec 202128th Mar 2022
Imports and Visibility0%0%29th Mar 202227th May 2022
Const Generics0%0%30th May 202225th Jul 2022
Intrinsics0%0%6th Sept 202130th Sept 2022
GitHub Milestones

Planned Activities

  • Fix bug in missing coercion site code generation
  • Continue work Closures

Leave a Reply

Your email address will not be published.