GCC Rust Weekly Status Report 37

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

Milestone Progress

This week we have started ramping up the progress and have merged our update to Method Resolution to support autoderef properly by respecting the deref lang items. This is a crucial feature of the Rust language, which allows methods to be resolved at compile-time without a vtable when types are hidden via indirection of boxing. I have one last branch of work implementing slices that need tidying up and rebasing, letting us compile even more of the goal test case. Timeline-wise, we are lucky as much of the mechanics and boiler pate for this new expand pass for macros, and cfg expansion is already in place, so this shouldn’t affect the timeline.

Next, I will be merging this work on Slices and beginning the work on cfg-expansion, so we take advantage of the existing expansion code to strip code as required from name resolution and hir lowering/desugaring.

Completed Activities

  • BugFix location info on RECORD and UNION types PR879
  • Fix the gimple names of generic methods PR880
  • Add enum TraitItemKind to HIR TraitItems PR881
  • New hir mappings helper to iterate trait items PR882
  • Extract new AsyncConstStatus to be shared with AST and HIR PR883
  • Improve error message on failure to find a method PR885
  • Method Resolution should use the lang_item deref to autoderef PR873
  • Merge from upstream GCC

Contributors this Week

Overall Task Status

CategoryLast WeekThis WeekDelta
TODO99100+1
In Progress1819+1
Completed266270+4
GitHub Issues

Test Cases

CategoryLast WeekThis WeekDelta
Passing55495605+56
Failed
XFAIL2121
XPASS
make check-rust

Bugs

CategoryLast WeekThis WeekDelta
TODO3434
In Progress56+1
Completed97101+4
GitHub Bugs

Milestones Progress

MilestoneLast WeekThis WeekDeltaStart 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 – Traits100%100%20th May 202117th Sept 202127th Aug 2021
Control Flow 2 – Pattern Matching100%100%20th Sept 202129th Nov 2021
Macros and cfg expansion0%9%+9%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

Risks

RiskImpact (1-3)Likelihood (0-10)Risk (I * L)Mitigation
Rust Language Changes3721Keep up to date with the Rust language on a regular basis
Going over target dates3515Maintain status reports and issue tracking to stakeholders

Planned Activities

Detailed changelog

Autoderef includes calling into the deref operator overloads so for example.

pub trait Deref {
    type Target;

    fn deref(&self) -> &Self::Target;
}

impl<T> Deref for &T {
    type Target = T;

    fn deref(&self) -> &T {
        *self
    }
}

struct Bar(i32);
impl Bar {
    fn foobar(self) -> i32 {
        self.0
    }
}

struct Foo<T>(T);
impl<T> Deref for Foo<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

fn main() {
    let bar = Bar(123);
    let foo: Foo<&Bar> = Foo(&bar);
    let foobar: i32 = foo.foobar();
}

You can see here we have a nested structure of Foo<&Bar> and Foo is a generic structure, and we have a method call of foo.foobar(). This is an interesting case of method resolution showing how rust allows for multiple dereference to find the apropriate method of foobar. In this method call expression foo is of type Foo<&Bar> the generic structure is a covariant Reference Type (&) of the structure Bar. The method foobar has a receiver type of a simple Bar being passed by value. So in order for this function to be called the method resolution system has an algorithm of:

  • reciever = Foo<&Bar>
  • Find all methods named foobar
  • try and match the receiver (self) with this reciever
  • so that means we have Foo<&Bar> vs Bar which does not match
  • Go back to the start and try by taking an immutable refernece
  • &Foo<&Bar> does not match Bar
  • Go back to the start and try by taking a mutable reference
  • &mut Foo<&Bar> does not match Bar
  • Try and dereference the original receiver Foo<&Bar>
  • Do we have the deref lang item defined
  • if yes resolve the method by the same mechanism for Foo<&Bar> for deref
  • Get the result type of this function which is &&Bar do the dereference
  • Now we have &Bar and a new adjustment for the original receiver
  • Try and match &Bar to the foobar method reciever of Bar
  • Try taking an immutable reference &&Bar
  • Try taking a mutable reference &mut &Bar
  • Try and deref &Bar we have the generic implementation of deref for &T
  • Call this derefernece like before to get down to Bar
  • Now try Bar on the foobar reciever Bar and it matches

We have now resolved the method with two dereference adjustments so the function call becomes:

i32 main ()
{
  i32 D.103;
  const struct Bar bar;
  const struct Foo<&Bar> foo;
  const i32 foobar;

  try
    {
      bar.0 = 123;
      foo.0 = &bar;
      _1 = <Foo as Deref>::deref<&Bar> (&foo);
      _2 = <&T as Deref>::deref<Bar> (_1);
      foobar = Bar::foobar (*_2);
      D.103 = foobar + -123;
      return D.103;
    }
  finally
    {
      bar = {CLOBBER};
      foo = {CLOBBER};
    }
}

Obviously GCC will optimize this with -O2 so that it does not require function calls but the gimple will show us what is actually going on. As far as I am aware rustc pre-optimizes this regardless of optimizations being turned on or not, these lang item functions are easily inlineable so it makes more sense to me to let GCC’s middle-end take care of this for us.

see https://godbolt.org/z/qjnq6Yoxb

Leave a Reply

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