GCC Rust Weekly Status Report 13

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

Array Capacity and constant folding

This week fixed several bugs in the compiler one of the big issues was constant expressions. In rust array capacities must be constant’s the default implementation simply just expected a LiteralExpression but this is not correct. Consider the example below:

let a:[_; 1+1+1] = [1,2,3];

This is a toy example but demonstrates that rust should be able to fold the capacity expression of (1+1+1). Constant folding is a complex piece of work to get right and respect all mathematical rules, but GCC already does this for us in gcc/fold-const.c so this PR-383 takes advantage of this.

const TEST:usize = 2;
let a:[_; TEST+1] = [1,2,3];

GCC also takes into account the fact that the name TEST is a const item such that it can then fold this example again into 3. However, there are limitations to constant folding in Rust consider this example:

let size = 2;
let a:[_; size+1] = [1,2,3];

Although it would indeed be possible for GCC to constant fold this into 3, rust disallows this and return:

error[E0435]: attempt to use a non-constant value in a constant 
For more information about this error, try `rustc --explain E0435`.

When we have a variable reference in a constant expression it is not always possible to fold its values since it will depend on constant propagation as well as constant folding. Even when it references immutable values the initializer expression may not be constant so it won’t always be possible to determine the value at compile time.

Block Expressions and Never Type

New contributor lrh2000 proposed introducing the rust never type to make the compiler more in line with Rustc. This change breaks down into several building blocks in rust you can write:

fn test() -> i32 {
    let a:u32 = 123;
    let b:i32 = 456;

Here the compiler needs to track the usage of the semi colon to track which is the final expression of the block, you can see this comment for more info on how rustc handles this.

This is where things start to get a little more complex consider this example:

fn test() -> i32 {
    let a = return 123;

In this example, you can see those return expressions are valid expressions in rust. The old implementation in the compiler inferred return expressions as either unit or the type of the return expression. Rustc actually makes this a never type as it is a change in control flow. The old implementation also stripped unreachable code as a way to enforce the typing rules for cases such as:

fn test() -> i32 {
    if x > 1 {
        return 5;
    } else {
        return 0;
    return 1;

When you have a block that is not the final expression in the block the type resolver needs to enforce the IfExpr resolves to unit type. Since the compiler used to type resolve the return expressions here into i32 instead of NeverType it meant that the rules were not correct. This is now fixed which his recent PRs.


As part of onboarding potential google summer of code students, we have been encouraging them to write test cases for the compiler. This has three benefits here:

  • Learning to compile and invoke the compiler
  • Understanding the state of the compiler as it stands
  • The project gets free test cases

Arthur proposed xfail testcases but it was found that the compiler at the time was crashing on these at that point. It seems reasonable that XFAIL testsuite should be able to support cases which ICE such that when crashes are fixed we should see a change in the testsuite and update the relevant testcases appropriately. Thanks to Marc this is now available though the dg-ice annotation.

Milestone Progress

In rust when you specify a TypePath that needs substitution the compiler needs to error correctly (rustc –explain E0107), untill PR-381 this used to cause a crash.

struct Foo<A>(A);

fn main() {
    let a: Foo = Foo::<i32>(123);
    // { dg-error "Invalid number of generic arguments to generic type" "" { target { *-*-* } } .-1 }

This also extends over to cases such as:

struct Foo<A>(A);

impl Foo {
    // { dg-error "Invalid number of generic arguments to generic type" "" { target { *-*-* } } .-1 }
    fn test() -> i32 {

The reason this is important is that it is a building block for my work into defaults on Type Parameters since the following is valid rust code:

struct Foo<A=f32>(A);

impl Foo {
    fn test() -> i32 {

Completed Activities

  • Track Semicolon in block expressions like rustc – PR-380
  • Fix crash when TypePath requiring generic substitution did not receive any generic arguments – PR-381
  • Use GCC fold-const.c to enforce const expressions on array capacity – PR-383
  • Add support to test suite to test for ICE to allow adding test cases which crash – PR-384
  • Undo block expression work which removed unreachable code in HIR lowering – PR-387 PR-390
  • Assign outer attributes in the AST as part of the IfLetExpr node constructor – PR-388

Overall Task Status

CategoryLast WeekThis WeekDelta
In Progress88
GitHub Issues

Test Cases

CategoryLast WeekThis WeekDelta
make check-rust


CategoryLast WeekThis WeekDelta
In Progress43-1
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 – Generics79%84%+5%11th Feb 202128th May 2021
Data Structures 3 – Traits0%0%27th Aug 2021
Control Flow 2 – Pattern Matching0%0%29th Oct 2021
Imports and Visibility0%0%TBD
GitHub Milestones


RiskImpact (1-3)Likelihood (0-10)Risk (I*L)Mitigation
Copyright assignments2510Be 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

  • Complete work on partial substitutions
  • Complete work on default type parameters

Leave a Reply

Your email address will not be published.