GCC Rust Monthly Report #8 July 2021

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

Milestone Progress

The month of July saw good progress getting through some of the bigger tickets. I was hoping to get my TypeBounds branch merged, which will allow us to make more useful generic code such as:

trait Foo {
    fn default() -> i32;
    fn get(self) -> i32;
}

fn type_bound_test<T: Foo>(a: T) -> i32 {
    T::default() + a.get()
}

I had a bereavement in my family, which means I lost a few days. So my focus will be to get this work closed out this week as it should be the last big PR to get merged. In completing the Traits work, the remaining tasks will be building upon this PR, such as optional type bounds, where clauses, default (optional) trait items and operator overloading.

Generic Associated Types

In other news the Rustc compiler is now close to stabalizing GAT’s (Generic Associated Types) this is something I did not factor into my Traits milestone. Since GCC Rust does not support const generics yet, it seems like a better idea to tackle this as part of that milestone down the line. If I extend the timeline of the traits milestone now and start working on this it might hurt progress, since this feature will still need more work down the line to support const generics anyway.

Is the milestone on track?

As part of investigating the Generic Associated Types work, I realised we had a few tasks scoped within the traits milestone, which are actually to do with pattern matching, not traits, such as the ref keyword within match arms and destructuring.

Overall, I feel a lot more comfortable with the remaining time and if I do go over the target date, I believe it will be limited to 1 or 2 weeks. As I have stated before, Traits within Rust are very subtle and affect everything within the type system, making it a complex milestone to hit. I am aiming in the future to release some blog posts on some of the exciting cases within rust, which should detail some of the more undocumented behaviour within the Rustc compiler that has caught me out a few times, such as autoderefs and method resolution. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=eaea790fd1fa506c7fb2b65941c3ea26

Monthly Community Call

We will be having our 5th community call as the first Friday of the month:

Google Summer of Code

Both students have been passed Wenzhang Yang, Arthur Cohen the first review as part of the GSoC program and will continue their work until August 16th and we hope they wish to continue contributing to GCC Rust.

Detailed changelog

Hello World

In order to compile the official Rustc Hello world, gccrust must support libcore, libstd and macros which is a little bit further down the line but what we can do now support are extern “C” blocks which allow us to call printf such as:

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

fn main() -> i32 {
    unsafe {
        let a = "Hello World %i\n";
        let b = a as *const str;
        let c = b as *const i8;

        printf(c, 123);
    }
    0
}

This is a crucial milestone as it tests casts as well as allowing us to call into libc which lets us output variables to check the compiled logic in automated tests.

Union support

Mark Wielaard has produced a series of patches which adds union support such as:

union U
{
  f1: u8
}

union V
{
  f1: u8,
  f2: u16,
  f3: i32,
}

struct S
{
  f1: U,
  f2: V
}

fn main ()
{
  let u = U { f1: 16 };
  let v = V { f2: 365 };
  let s = S { f1: u, f2: v };
  let _v125 = unsafe
    { let mut uv: u64;
      uv = s.f1.f1 as u64;
      uv += s.f2.f1 as u64;
      uv += s.f2.f2 as u64;
      uv -= s.f2.f3 as u64;
      uv
    };
}

The remaining piece is to add dead-code scanning for unions which can be easily done via Wenzhang Yang google summer of code work in the DeadCode pass.

Handle doc comments

Our parser failed to handle inner and outer doc comments which is now fixed and example is below.

// comment line not a doc
/* comment block not a doc                   */

//! inner line comment for most outer crate
/*! inner block comment for most outer crate */

// comment line not a doc
/* comment block not a doc                   */

/// outer doc line for module
/** outer doc block for module               */
pub mod module
{
  //!  inner line doc
  //!! inner line doc!
  /*!  inner block doc  */
  /*!! inner block doc! */

  //   line comment
  ///  outer line doc
  //// line comment

  /*   block comment   */
  /**  outer block doc */
  /*** block comment   */

  mod block_doc_comments
  {
    /*   /* */  /** */  /*! */  */
    /*!  /* */  /** */  /*! */  */
    /**  /* */  /** */  /*! */  */
    mod item { }
  }

  pub mod empty
  {
    //!
    /*!*/
    //

    ///
    mod doc { }
    /**/
    /***/
  }
}

Associated Type Errors

Extending from last week the placeholder types are not updated as part of the Trait impl block resolution so we can enforce rules where the TypePath to Self::A is properly enforced such as:

trait Foo {
    type A;

    fn baz(a: Self::A) -> Self::A;
}

struct Bar<T>(T);

impl<T> Foo for Bar<T> {
    type A = i32;

    fn baz(a: f32) -> f32 {
        // { dg-error "expected .i32. got .f32." "" { target *-*-* } .-1 }
        // { dg-error "method .baz. has an incompatible type for trait .Foo." "" { target *-*-* } .-2 }
        a
    }
}

fn main() {
    let a;
    a = Bar::<i32>::baz(123f32);
}
test.rs:12:15: error: expected [i32] got [f32]
    4 |     fn baz(a: Self::A) -> Self::A;
      |               ~
......
   12 |     fn baz(a: f32) -> f32 {
      |               ^
test.rs:12:5: error: method ‘baz’ has an incompatible type for trait ‘Foo’
    4 |     fn baz(a: Self::A) -> Self::A;
      |     ~
......
   12 |     fn baz(a: f32) -> f32 {
      |     ^

Missing Trait Items within Impl Block

trait Foo {
    const A: i32;

    fn test(self);
}

struct Bar;
impl Foo for Bar {}
test.rs:8:1: error: missing A, test in implementation of trait ‘Foo’
    2 |     const A: i32;
      |     ~
    3 | 
    4 |     fn test(self);
      |     ~
......
    8 | impl Foo for Bar {}
      | ^

Some items are optional and should not cause this error for example a function with a block this does not cause this error.

Raw Pointers and Coercions

In rust you cannot implement pointers untill you have implemented type coercions. For example:

pub fn main() {
    let mut num = 2;
    let a: *const i32 = &num;
}

The borrow expression of num signifies a Reference (int&) but to get a pointer we need to explicitly say we want ‘a’ to be a pointer and the assignment statement is not an assignment it is a coercion-site this allows the compiler to make a coercion of (int&) into (const int*). Coercion sites allow to move from mutable references to const references but not the other way round. This is explicitly different to TypeCasts using ‘as’ keyword which allows you ignore mutability.

Initial support for unsafe

We now support compiling unsafe blocks such as:

pub fn main() {
    let mut num = 2;
    let r1: *const i32 = &num;
    let r2 = unsafe { *r1 } + unsafe { *r1 };
    let r3 = num;
    num = 4;
    let r4 = num + unsafe { *r1 } * r3;
    let _eightteen = r2 + r3 + r4;
}

Currently, this fixes the ICE we had and does not implement the rules for error checking that raw pointer dereferences must be inside unsafe this will come later on.

Completed Activities

  • Hello world PR596 PR597 PR598
  • Union support PR601 PR590 PR602
  • Fix location info for let while let expressions PR600
  • Add some documentation to DeadCode scan PR560 PR559
  • Improve error handling in DeadCode scan PR558 PR555
  • Cleanup warning messages in DeadCode scan PR554
  • Support shebang and UTF-8 BOM parsing PR546 PR552
  • Initial building blocks for Associated Types and Constants PR551
  • Fix bug in GIMPLE naming for primitive types PR548
  • Cargo GCCRS cleanup CARGO-PR38 CARGO-PR33
  • Support enviroment variable flags in cargo CARGO-PR32
  • Support doc comments PR561
  • Cleanup and comments to DeadCode Pass PR571 PR564 PR562
  • Warn for unused impl items via DeadCode pass PR567
  • Add missing DefId mappings PR568
  • Add const modifier to TyTy equality interface PR572
  • Add missing test cases to close out unit-structs PR570
  • Some Trait items are optional and should not error PR569
  • Enforce mandatory trait items and placeholder type checking PR566
  • Assignments are a type of coercion site PR577
  • Add lowering and typechecking for unsafe blocks PR582 PR587
  • Raw pointers PR579 PR589
  • Support byte string literals PR594
  • Fix bug parsing unsafe in expressions PR591
  • Fix parser bug in ranges PR593
  • Cleanup PR578 PR585 PR586

Contributors this month

Excluding merges, 4 authors have pushed 75 commits to master and 84 commits to all branches. On master, 146 files have changed and there have been 8,010 additions and 1,345 deletions.

Overall Task Status

CategoryLast MonthThis MonthDelta
TODO8683-3
In Progress79+2
Completed157177+20
GitHub Issues

Test Cases

CategoryLast MonthThis MonthDelta
Passing30273629+602
XFAIL1514-1
make check-rust

Bugs

CategoryLast MonthThis MonthDelta
TODO1919
In Progress43-1
Completed5159+8
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 – Traits40%80%+40%20th May 202127th Aug 2021
Control Flow 2 – Pattern Matching0%0%29th Oct 2021
Imports and Visibility0%0%TBD
Macros and cfg expansion0%0%TBD
Const Generics0%0%TBD
Intrinsics0%0%TBD
GitHub Milestones

Risks

RiskImpact (1-3)Likelihood (0-10)Risk (I * L)Mitigation
Copyright assignments224Be up front on all PRs that the code is destined to be upstreamed to FSF
Rust Language Changes3721Keep up to date with the Rust language on a regular basis

Planned Activities

  • Get Type bounds work merged
  • Add more test cases for casts and coercions

2 thoughts on “GCC Rust Monthly Report #8 July 2021

  1. > some of the more undocumented behaviour within the Rustc compiler that has caught me out a few times, such as autoderefs and method resolution. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=eaea790fd1fa506c7fb2b65941c3ea26

    I believe this behavior is not undocumented. https://doc.rust-lang.org/nightly/nomicon/dot-operator.html mentions that trait methods are tried first before automatic reference is tried. This explains the playpen example.

    More information is also on https://rustc-dev-guide.rust-lang.org/method-lookup.html

    1. Hi, thanks for the links. Though the method-lookup link does contain “TODO: Is this FIXME still accurate?”. But the point I was trying to make is more about why. So in the example, I shared I was sharing that if you change it slightly by making both methods have a receiver of self it now becomes ambiguous in a language perspective. Yes, the implementation prefers the impl block over the trait-impl block. But if you then add in references and mutability it now becomes the one which is least mutable or least autoderf operations required. From a compiler perspective its not as fully documented as I would like.

      Though the rust nomicon link is something i haven’t seen before which helps describe the autoderef which is something i have been trying to understand from reading the compiler code. Thanks for that.

Leave a Reply

Your email address will not be published. Required fields are marked *