Skip to content

rustc fails to remove dead code in exactly one instance of multiple similar code #48627

Closed
@glandium

Description

@glandium

I made a mistake in some code, which essentially made everything statically panic. Which is fine. The problem is that in exactly one instance of the same kind of code, rustc actually failed to remove the non-panicking branch. Note this /might/ be a duplicate of #48253. At least, similarly to #48253, it appears to be a regression in 1.24.0, according to godbolt.

A copy/pastable-to-godbolt and reduced version of the mistaken code is:

#[allow(non_camel_case_types)] 
pub enum c_void {
    // Two dummy variants so the #[repr] attribute can be used.
    #[doc(hidden)]
    __variant1,
    #[doc(hidden)]
    __variant2,
}

pub extern "C" fn malloc(size: usize) -> *mut c_void {
    FUNCS.malloc.unwrap()(size)
}
pub extern "C" fn calloc(nmemb: usize, size: usize) -> *mut c_void {
    FUNCS.calloc.unwrap()(nmemb, size)
}
pub extern "C" fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void {
    FUNCS.realloc.unwrap()(ptr, size)
}

pub struct MallocTable {
    malloc: Option<extern "C" fn(usize) -> *mut c_void>,
    calloc: Option<extern "C" fn(usize, usize) -> *mut c_void>,
    realloc: Option<extern "C" fn(*mut c_void, usize) -> *mut c_void>,
}

pub static FUNCS: MallocTable =
    MallocTable{malloc: None,
                calloc: None,
                realloc: None};

This generates the following assembly (skipping the data fields):

example::malloc:
  push rbp
  mov rbp, rsp
  mov rax, qword ptr [rip + example::FUNCS@GOTPCREL]
  mov rax, qword ptr [rax]
  test rax, rax
  je .LBB0_1
  call rax
  pop rbp
  ret
.LBB0_1:
  lea rdi, [rip + .Lref.2]
  call core::panicking::panic@PLT
  ud2
  ud2
  ud2

example::calloc:
  push rbp
  mov rbp, rsp
  lea rdi, [rip + .Lref.2]
  call core::panicking::panic@PLT
  ud2
  ud2
  ud2

example::realloc:
  push rbp
  mov rbp, rsp
  lea rdi, [rip + .Lref.2]
  call core::panicking::panic@PLT
  ud2
  ud2
  ud2

Note how calloc and realloc are properly just directly panicking because FUNCS is immutable and initialized with empty function pointers, leading to unwrap always panicking, but the same doesn't happen for malloc. Interestingly, removing realloc makes malloc optimized the same way as the others.

The code generated by 1.23.0 was:

example::malloc:
  push rbp
  mov rbp, rsp
  lea rdi, [rip + ref.2]
  call core::panicking::panic@PLT
  ud2

example::calloc:
  push rbp
  mov rbp, rsp
  lea rdi, [rip + ref.2]
  call core::panicking::panic@PLT
  ud2

example::realloc:
  push rbp
  mov rbp, rsp
  lea rdi, [rip + ref.2]
  call core::panicking::panic@PLT
  ud2

Metadata

Metadata

Assignees

Labels

A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-enhancementCategory: An issue proposing an enhancement or a PR with one.I-slowIssue: Problems and improvements with respect to performance of generated code.P-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions