Skip to content

Failed assert got 1400 instead of 14 after become tail call at -O3 #158017

Closed

Description

@kevin-valerio

-O3 passes the previous stack values instead of the tuple values passed to the tail call
I tried a patch but it's a non trivial one so I haven't submitted any PR

Repro:

#![feature(explicit_tail_calls, unboxed_closures)]
#![expect(incomplete_features)]
#![allow(dead_code)]

#[derive(Copy, Clone)]
struct Thing { a: u64, b: u64, c: u64, d: u64 }

#[inline(never)]
fn seed_stack() {
    let mut values = (
        Thing { a: 100, b: 200, c: 300, d: 400 },
        Thing { a: 500, b: 600, c: 700, d: 800 },
    );
    std::hint::black_box(&mut values);
}

#[inline(never)]
extern "rust-call" fn callee((left, right): (Thing, Thing)) -> u64 {
    left.a.wrapping_add(left.b).wrapping_add(right.a).wrapping_add(right.b)
}

#[inline(never)]
extern "rust-call" fn caller((left, right): (Thing, Thing)) -> u64 {
    become callee((right, left));
}

fn main() {
    seed_stack();
    let left = Thing { a: 1, b: 2, c: 3, d: 4 };
    let right = Thing { a: 5, b: 6, c: 7, d: 8 };
    println!("got={}", caller((left, right)));
}
$ rustc +nightly-2026-05-10 repro.rs -C opt-level=0 -o repro_o0
$ ./repro_o0
got=14
$ rustc +nightly-2026-05-10 repro.rs -C opt-level=3 -o repro_o3
$ ./repro_o3
got=1400

Activity

  1. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Jun 17, 2026
  2. theemathas commented on Jun 17, 2026

    @theemathas
    Contributor

    Possibly related to #155241.

    cc @dianqk (author of #155343)

  3. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    I-miscompileIssue: Correct Rust code lowers to incorrect machine code
    A-codegenArea: Code generation
    and removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Jun 17, 2026
  4. theemathas commented on Jun 17, 2026

    @theemathas
    Contributor

    Slightly smaller repro:

    #![feature(explicit_tail_calls, unboxed_closures)]
    #![expect(incomplete_features)]
    
    #[inline(never)]
    fn seed_stack() {
        let mut values = [100_u64; 8];
        std::hint::black_box(&mut values);
    }
    
    #[inline(never)]
    extern "rust-call" fn callee((value,): ([u64; 4],)) -> u64 {
        value[0]
    }
    
    #[inline(never)]
    extern "rust-call" fn caller((_,): ([u64; 4],)) -> u64 {
        become callee(([5, 6, 7, 8],));
    }
    
    fn main() {
        seed_stack();
        println!("{}", caller(([1, 2, 3, 4],)));
    }

    Prints 5 in debug, prints 100 in release.

  5. self-assigned this
    on Jun 17, 2026
  6. WaffleLapkin commented on Jun 23, 2026

    @WaffleLapkin
    Member

    @kevin-valerio is there any particular reason why you were experimenting with extern "rust-call" tail calls?

  7. kevin-valerio commented on Jun 23, 2026

    @kevin-valerio
    ContributorAuthor

    @kevin-valerio is there any particular reason why you were experimenting with extern "rust-call" tail calls?

    @WaffleLapkin Yes! It's all described in this Zullip thread

  8. added 4 commits that reference this issue on Jun 25, 2026
  9. removed their assignment
    on Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-codegenArea: Code generationC-bugCategory: This is a bug.F-explicit_tail_calls`#![feature(explicit_tail_calls)]`F-unboxed_closures`#![feature(unboxed_closures)]`I-miscompileIssue: Correct Rust code lowers to incorrect machine codeT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions