rust-lang / rust-lang/rust

panic branch does not get removed in presence of other function (that also does not get it removed)

Open
#119,923 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-LLVM C-bug I-heavy I-slow T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I tried this code (compiler explorer):

#[derive(Clone, Copy)]
pub enum Enum {
    None,
    Variant1,
    Variant2,
}

impl Enum {
    #[no_mangle]
    pub fn as_str_1(self) -> &'static str {
        // switch table for reference
        match self {
            Self::None => "",
            Self::Variant1 => "1",
            Self::Variant2 => "2",
        }
    }

    #[no_mangle]
    pub fn as_str_2(self) -> &'static str {
        let len = (self as usize + 1) / 2;
        let offs = self as usize / 2;
        &"12"[offs..len + offs]
    }

    #[no_mangle]
    pub fn as_str_3(self) -> &'static str {
        let len = (self as usize + 1) / 2;
        let offs = self as usize;
        &" 12"[offs..len + offs]
    }
}

and this code (compiler explorer):

#[derive(Clone, Copy)]
pub enum Enum {
    None,
    Variant1,
    Variant2,
}

impl Enum {
    #[no_mangle]
    pub fn as_str_1(self) -> &'static str {
        // switch table for reference
        match self {
            Self::None => "",
            Self::Variant1 => "1",
            Self::Variant2 => "2",
        }
    }

    #[no_mangle]
    pub fn as_str_2(self) -> &'static str {
        let len = (self as usize + 1) / 2;
        let offs = self as usize / 2;
        &"12"[offs..len + offs]
    }
}

(difference between the two is that as_str_3 only exists in the first example)

I expected to see this happen:
all as_str_ functions compile to roughly the same code (no memory accesses, just some pointer addition and getting the length right)

something like this (compiler explorer):

as_str_4:
        movzx   edx, dil
        lea     rax, [rip + .L__unnamed_3]
        add     rax, rdx
        inc     edx
        shr     edx
        ret

.L__unnamed_3:
        .ascii  " 12"

Instead, this happened:
as_str_1 became a switch table, so i pointed the compiler in the right direction with as_str_2, i tried a few other things, as_str_3 with an integer division less but a byte longer string and as_str_4 with unsafe code to get the desired output.
as_str_2's panic branch only got removed when i commented as_str_3 out, as_str_3 always had one

Meta

rustc --version --verbose:

rustc 1.77.0-nightly (62d7ed4a6 2024-01-11)
binary: rustc
commit-hash: 62d7ed4a6775c4490e493093ca98ef7c215b835b
commit-date: 2024-01-11
host: x86_64-unknown-linux-gnu
release: 1.77.0-nightly
LLVM version: 17.0.6

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the two Compiler Explorer reproductions and the reported rustc 1.77.0-nightly version, comparing the generated assembly for as_str_2 with and without as_str_3. Trace the compiler's handling of the slice-indexing panic branch and verify whether the unwanted branch is removed while preserving the reported output.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.