Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler segfaults when boxing a ZST from an external crate #28766

Closed
kylewlacy opened this issue Sep 30, 2015 · 8 comments
Closed

Compiler segfaults when boxing a ZST from an external crate #28766

kylewlacy opened this issue Sep 30, 2015 · 8 comments
Assignees
Labels
I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️

Comments

@kylewlacy
Copy link

Demonstration

I uploaded a repo with the simplest possible case I could come up with that demonstrates this issue here. Here's how it works:

$ rustc --version --verbose
    rustc 1.4.0-dev (d2e13e822 2015-09-15)
    binary: rustc
    commit-hash: d2e13e822a73e0ea46ae9e21afdd3155fc997f6d
    commit-date: 2015-09-15
    host: x86_64-apple-darwin
    release: 1.4.0-dev
$ git clone https://github.com/kylewlacy/rust-segfault.git
$ cd rust-segfault
$ cargo build --release --verbose
   Compiling my_crate v0.1.0 (file:///Users/kyle/Desktop/rust-segfault)
     Running `rustc my_crate/src/lib.rs --crate-name my_crate --crate-type lib -C opt-level=3 -C metadata=ab97f46dd8433ebe -C extra-filename=-ab97f46dd8433ebe --out-dir /Users/kyle/Desktop/rust-segfault/target/release/deps --emit=dep-info,link -L dependency=/Users/kyle/Desktop/rust-segfault/target/release/deps -L dependency=/Users/kyle/Desktop/rust-segfault/target/release/deps`
   Compiling segfault v0.1.0 (file:///Users/kyle/Desktop/rust-segfault)
     Running `rustc src/lib.rs --crate-name segfault --crate-type lib -C opt-level=3 --out-dir /Users/kyle/Desktop/rust-segfault/target/release --emit=dep-info,link -L dependency=/Users/kyle/Desktop/rust-segfault/target/release -L dependency=/Users/kyle/Desktop/rust-segfault/target/release/deps --extern my_crate=/Users/kyle/Desktop/rust-segfault/target/release/deps/libmy_crate-ab97f46dd8433ebe.rlib`
Could not compile `segfault`.

Caused by:
  Process didn't exit successfully: `rustc src/lib.rs --crate-name segfault --crate-type lib -C opt-level=3 --out-dir /Users/kyle/Desktop/rust-segfault/target/release --emit=dep-info,link -L dependency=/Users/kyle/Desktop/rust-segfault/target/release -L dependency=/Users/kyle/Desktop/rust-segfault/target/release/deps --extern my_crate=/Users/kyle/Desktop/rust-segfault/target/release/deps/libmy_crate-ab97f46dd8433ebe.rlib` (signal: 11)

Explanation

So I have a crate in my project, brilliantly named my_crate. my_crate is pretty simple, it contains a struct, called Foo, made up of zero-sized types. Foo also has a constructor function called Foo::new():

// my_crate/lib.rs
pub struct Foo(());

impl Foo {
    fn new() -> Self {
        Foo(())
    }
}

Now, in my library, segfault, I have a single function, called box_foo(), that just returns a Box<Foo>. It constructs a Foo, then boxes it:

// segfault/lib.rs
extern crate my_crate;
use my_crate::Foo;

pub fn box_foo() -> Box<Foo> {
    Box::new(Foo::new())
}

Well, that's about it. Building segfault and my_crate with cargo build works perfectly fine. However, cargo build --release crashes with a signal 11, a segfault.

Some observations

  • Foo must be a zero-sized type, but cannot be a unit struct
  • Foo must be constructed with a function (e.g Box::new(Foo(()) would not segfault)
  • Foo must be from another crate
  • The segfault only occurs if box_foo() is public (otherwise it's dead code, and I guess rustc doesn't even attempt to compile it?)
  • The segfault only occurs when optimizing the outer library
  • The optimization level doesn't matter, it just has to be >0
  • The constructor fn doesn't have to be in impl Foo, but it does have to come from my_crate
  • The fn that creates the box has to be in the outer library (e.g. let boxed: Box<Foo> = Foo::new_box(); would not segfault)
  • Using a newtype in place of Foo has the same issue
  • The crash is not caused by returning a Box<Foo>, but by constructing one with Box::new. That is, the following also causes a segfault:
pub fn foo_ptr_mut() -> *mut Foo {
    let boxed = Box::new(Foo::new());
    Box::into_raw(boxed)
}
@alexcrichton
Copy link
Member

Looks like this is tripping an LLVM assertion:

Assertion failed: (!empty()), function back, file /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/llvm/include/llvm/ADT/SmallVector.h, line 157.

I think if you use nightly it's got LLVM assertions enabled, which is why it looks like a segfault on stable!

@alexcrichton alexcrichton added the I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ label Sep 30, 2015
@arielb1
Copy link
Contributor

arielb1 commented Sep 30, 2015

@alexcrichton

backtrace?

@arielb1
Copy link
Contributor

arielb1 commented Sep 30, 2015

cc @dotdash

@alexcrichton
Copy link
Member

Backtrace for me looks like:

(lldb) r
Process 3153 launched: '/Users/acrichton/.multirust/toolchains/nightly/bin/rustc' (x86_64)
Assertion failed: (!empty()), function back, file /Users/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-mac/build/src/llvm/include/llvm/ADT/SmallVector.h, line 157.
Process 3153 stopped
* thread #2: tid = 0xfe28, 0x00007fff866c8286 libsystem_kernel.dylib`__pthread_kill + 10, name = 'rustc', stop reason = signal SIGABRT
    frame #0: 0x00007fff866c8286 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill:
->  0x7fff866c8286 <+10>: jae    0x7fff866c8290            ; <+20>
    0x7fff866c8288 <+12>: movq   %rax, %rdi
    0x7fff866c828b <+15>: jmp    0x7fff866c3c53            ; cerror_nocancel
    0x7fff866c8290 <+20>: retq   
(lldb) bt
* thread #2: tid = 0xfe28, 0x00007fff866c8286 libsystem_kernel.dylib`__pthread_kill + 10, name = 'rustc', stop reason = signal SIGABRT
  * frame #0: 0x00007fff866c8286 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fff8c1cd9f9 libsystem_pthread.dylib`pthread_kill + 90
    frame #2: 0x000000010321ab36 librustc_llvm-10cbabc2.dylib`abort + 22
    frame #3: 0x000000010321ab11 librustc_llvm-10cbabc2.dylib`__assert_rtn + 81
    frame #4: 0x00000001029acc4b librustc_llvm-10cbabc2.dylib`llvm::returnTypeIsEligibleForTailCall(llvm::Function const*, llvm::Instruction const*, llvm::ReturnInst const*, llvm::TargetLoweringBase const&) + 1995
    frame #5: 0x00000001029ac44c librustc_llvm-10cbabc2.dylib`llvm::isInTailCallPosition(llvm::ImmutableCallSite, llvm::TargetMachine const&) + 412
    frame #6: 0x00000001028eee72 librustc_llvm-10cbabc2.dylib`llvm::SelectionDAGBuilder::LowerCallTo(llvm::ImmutableCallSite, llvm::SDValue, bool, llvm::MachineBasicBlock*) + 802
    frame #7: 0x00000001028e07db librustc_llvm-10cbabc2.dylib`llvm::SelectionDAGBuilder::visitCall(llvm::CallInst const&) + 1899
    frame #8: 0x00000001028d6c1a librustc_llvm-10cbabc2.dylib`llvm::SelectionDAGBuilder::visit(llvm::Instruction const&) + 74
    frame #9: 0x000000010291de45 librustc_llvm-10cbabc2.dylib`llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) + 8117
    frame #10: 0x000000010291af11 librustc_llvm-10cbabc2.dylib`llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) + 1489
    frame #11: 0x00000001026812e4 librustc_llvm-10cbabc2.dylib`(anonymous namespace)::X86DAGToDAGISel::runOnMachineFunction(llvm::MachineFunction&) + 20
    frame #12: 0x0000000102a795cd librustc_llvm-10cbabc2.dylib`llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 125
    frame #13: 0x0000000103182f5c librustc_llvm-10cbabc2.dylib`llvm::FPPassManager::runOnFunction(llvm::Function&) + 332
    frame #14: 0x00000001031831bb librustc_llvm-10cbabc2.dylib`llvm::FPPassManager::runOnModule(llvm::Module&) + 59
    frame #15: 0x0000000103183616 librustc_llvm-10cbabc2.dylib`llvm::legacy::PassManagerImpl::run(llvm::Module&) + 774
    frame #16: 0x00000001031839dd librustc_llvm-10cbabc2.dylib`llvm::legacy::PassManager::run(llvm::Module&) + 13
    frame #17: 0x000000010202b7a7 librustc_llvm-10cbabc2.dylib`LLVMRustWriteOutputFile + 359
    frame #18: 0x00000001003edc98 librustc_trans-10cbabc2.dylib`back::write::write_output_file::h7b6a0917c12edcb5T9c + 104
    frame #19: 0x00000001003f040b librustc_trans-10cbabc2.dylib`back::write::optimize_and_codegen::closure.46290 + 1195
    frame #20: 0x00000001003f8881 librustc_trans-10cbabc2.dylib`back::write::execute_work_item::h029ce2382e4b96b4aZd + 5857
    frame #21: 0x00000001003f1c12 librustc_trans-10cbabc2.dylib`back::write::run_passes::h22631cc38b7ec107oKd + 5762
    frame #22: 0x0000000100054340 librustc_driver-10cbabc2.dylib`driver::phase_5_run_llvm_passes::ha14186a8d79e2f35YPa + 272
    frame #23: 0x00000001000070b4 librustc_driver-10cbabc2.dylib`driver::compile_input::hbc83f2980ca7f4710ba + 6532
    frame #24: 0x0000000100169931 librustc_driver-10cbabc2.dylib`run_compiler::h33fbe472d39f4682rqc + 4929
    frame #25: 0x000000010016718c librustc_driver-10cbabc2.dylib`boxed::F.FnBox$LT$A$GT$::call_box::h4139096335926771660 + 348
    frame #26: 0x0000000100166a93 librustc_driver-10cbabc2.dylib`sys_common::unwind::try::try_fn::h18182466805119396236 + 51
    frame #27: 0x0000000103faf299 libstd-10cbabc2.dylib`__rust_try + 9
    frame #28: 0x0000000103fa3d21 libstd-10cbabc2.dylib`sys_common::unwind::try::inner_try::hac438d316ecc2316T6r + 97
    frame #29: 0x0000000100166c43 librustc_driver-10cbabc2.dylib`boxed::F.FnBox$LT$A$GT$::call_box::h9346591452946938098 + 227
    frame #30: 0x0000000103fb782e libstd-10cbabc2.dylib`sys::thread::Thread::new::thread_start::h770a3938c0de9490puw + 142
    frame #31: 0x00007fff8c1cc05a libsystem_pthread.dylib`_pthread_body + 131
    frame #32: 0x00007fff8c1cbfd7 libsystem_pthread.dylib`_pthread_start + 176
    frame #33: 0x00007fff8c1c93ed libsystem_pthread.dylib`thread_start + 13
``

@arielb1
Copy link
Contributor

arielb1 commented Oct 7, 2015

Problematic IR:

; ModuleID = 'segfault.0.rs'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

%"9.my_crate::Foo" = type { {} }

; Function Attrs: uwtable
define noalias %"9.my_crate::Foo"* @_ZN7box_foo20hf984887980016f2cgaaE() unnamed_addr #0 {
entry-block:
  %0 = tail call %"9.my_crate::Foo" @"_ZN13_$LT$impl$GT$3new20h7a0183b89d396887kaaE"()
  ret %"9.my_crate::Foo"* inttoptr (i64 1 to %"9.my_crate::Foo"*)
}

declare %"9.my_crate::Foo" @"_ZN13_$LT$impl$GT$3new20h7a0183b89d396887kaaE"() unnamed_addr

attributes #0 = { uwtable }

Why is there a tail call followed by a ret? The unoptimized code is

; ModuleID = 'segfault.0.rs'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

%str_slice = type { i8*, i64 }
%"2.core::fmt::Formatter" = type { i32, i32, i8, %"2.core::option::Option<usize>", %"2.core::option::Option<usize>", { i8*, void (i8*)** }, %"2.core::slice::Iter<core::fmt::ArgumentV1>", { %"2.core::fmt::ArgumentV1"*, i64 } }
%"2.core::option::Option<usize>" = type { i64, [0 x i64], [1 x i64] }
%"2.core::slice::Iter<core::fmt::ArgumentV1>" = type { %"2.core::fmt::ArgumentV1"*, %"2.core::fmt::ArgumentV1"*, %"2.core::marker::PhantomData<&'static core::fmt::ArgumentV1>" }
%"2.core::fmt::ArgumentV1" = type { %"2.core::fmt::Void"*, i8 (%"2.core::fmt::Void"*, %"2.core::fmt::Formatter"*)* }
%"2.core::fmt::Void" = type {}
%"2.core::marker::PhantomData<&'static core::fmt::ArgumentV1>" = type {}
%"9.my_crate::Foo" = type { {} }
%"2.core::fmt::Arguments" = type { { %str_slice*, i64 }, %"2.core::option::Option<&'static [core::fmt::rt::v1::Argument]>", { %"2.core::fmt::ArgumentV1"*, i64 } }
%"2.core::option::Option<&'static [core::fmt::rt::v1::Argument]>" = type { { %"2.core::fmt::rt::v1::Argument"*, i64 } }
%"2.core::fmt::rt::v1::Argument" = type { %"2.core::fmt::rt::v1::Position", %"2.core::fmt::rt::v1::FormatSpec" }
%"2.core::fmt::rt::v1::Position" = type { i64, [0 x i64], [1 x i64] }
%"2.core::fmt::rt::v1::FormatSpec" = type { i32, i8, i32, %"2.core::fmt::rt::v1::Count", %"2.core::fmt::rt::v1::Count" }
%"2.core::fmt::rt::v1::Count" = type { i64, [0 x i64], [1 x i64] }

@const2476 = internal unnamed_addr constant i64 0
@const2480 = internal unnamed_addr constant {}* inttoptr (i64 1 to {}*)
@const2481 = internal unnamed_addr constant i8* inttoptr (i64 1 to i8*)
@const2497 = internal unnamed_addr constant i8 1
@_ZN4heap24check_size_and_alignment14_MSG_FILE_LINE20hc3b2d56120089136JbaE = external global { %str_slice, %str_slice, i32 }
@const2504 = internal unnamed_addr constant i64 64
@const2505 = internal unnamed_addr constant i64 -9223372036854775808
@const2506 = internal unnamed_addr constant i64 9223372036854775807
@const2514 = internal unnamed_addr constant { { i8*, i8* } } zeroinitializer
@_ZN4heap24check_size_and_alignment15__STATIC_FMTSTR20hfa6992380310c546wcaE = external global { %str_slice*, i64 }
@const2621 = internal unnamed_addr constant i8 (i64*, %"2.core::fmt::Formatter"*)* @"_ZN3fmt3num13_$LT$impl$GT$3fmt20h61c12488bb3d5903AZVE"
@_ZN4heap24check_size_and_alignment10_FILE_LINE20hcf2a8ce10e9354d6gcaE = external global { %str_slice, i32 }
@const2632 = internal unnamed_addr constant i64 1
@_ZN4heap24check_size_and_alignment15__STATIC_FMTSTR20hfa6992380310c546qdaE = external global { %str_slice*, i64 }
@_ZN4heap24check_size_and_alignment10_FILE_LINE20hcf2a8ce10e9354d6adaE = external global { %str_slice, i32 }
@const2641 = internal unnamed_addr constant i8* null

; Function Attrs: uwtable
define noalias %"9.my_crate::Foo"* @_ZN7box_foo20hf984887980016f2cgaaE() unnamed_addr #0 {
entry-block:
  %0 = call %"9.my_crate::Foo" @"_ZN13_$LT$impl$GT$3new20h7a0183b89d396887kaaE"()
  %1 = call i8* @_ZN4heap15exchange_malloc20h496cd3d208c78b0aJfaE(i64 0, i64 1)
  %2 = bitcast i8* %1 to %"9.my_crate::Foo"*
  ret %"9.my_crate::Foo"* %2
}

; Function Attrs: inlinehint uwtable
define internal i8* @_ZN4heap15exchange_malloc20h496cd3d208c78b0aJfaE(i64, i64) unnamed_addr #1 {
entry-block:
  %sret_slot = alloca i8*
  %size = alloca i64
  %align = alloca i64
  %ptr = alloca i8*
  %2 = alloca i8
  store i64 %0, i64* %size, align 8
  store i64 %1, i64* %align, align 8
  %3 = load i64, i64* %size, align 8
  %4 = icmp eq i64 %3, 0
  br i1 %4, label %then-block-41-, label %else-block

then-block-41-:                                   ; preds = %entry-block
  store i8* inttoptr (i64 1 to i8*), i8** %sret_slot, align 8
  br label %join

else-block:                                       ; preds = %entry-block
  %5 = load i64, i64* %size, align 8
  %6 = load i64, i64* %align, align 8
  %7 = call i8* @_ZN4heap8allocate20h8f9906da8b1122b2PdaE(i64 %5, i64 %6)
  store i8* %7, i8** %ptr, align 8
  %8 = load i8*, i8** %ptr, align 8
  %9 = call zeroext i1 @"_ZN3ptr13_$LT$impl$GT$7is_null7is_null21h14748829460356738718E"(i8* %8)
  %10 = zext i1 %9 to i8
  store i8 %10, i8* %2, align 1
  %11 = load i8, i8* %2, align 1, !range !0
  %12 = trunc i8 %11 to i1
  br i1 %12, label %then-block-59-, label %next-block

then-block-59-:                                   ; preds = %else-block
  call void @_ZN3oom20hd9170b7f1397402fatbE()
  unreachable

next-block:                                       ; preds = %else-block
  %13 = load i8*, i8** %ptr, align 8
  store i8* %13, i8** %sret_slot, align 8
  br label %join

join:                                             ; preds = %next-block, %then-block-41-
  %14 = load i8*, i8** %sret_slot, align 8
  ret i8* %14
}

; Function Attrs: inlinehint uwtable
define internal i8* @_ZN4heap8allocate20h8f9906da8b1122b2PdaE(i64, i64) unnamed_addr #1 {
entry-block:
  %size.i = alloca i64
  %align.i = alloca i64
  %2 = alloca %"2.core::fmt::Arguments"
  %3 = alloca { %str_slice*, i64 }
  %4 = alloca [1 x %"2.core::fmt::ArgumentV1"]
  %5 = alloca { i64* }
  %match.i = alloca { i64* }
  %__llmatch.i = alloca i64**
  %__arg0.i = alloca i64*
  %__coerce_target.i = alloca { %"2.core::fmt::ArgumentV1"*, i64 }
  %6 = alloca i8
  %7 = alloca %"2.core::fmt::Arguments"
  %8 = alloca { %str_slice*, i64 }
  %9 = alloca [1 x %"2.core::fmt::ArgumentV1"]
  %10 = alloca { i64* }
  %match2.i = alloca { i64* }
  %__llmatch4.i = alloca i64**
  %__arg05.i = alloca i64*
  %__coerce_target7.i = alloca { %"2.core::fmt::ArgumentV1"*, i64 }
  %size = alloca i64
  %align = alloca i64
  %__arg = alloca i64
  %__arg1 = alloca i64
  store i64 %0, i64* %size, align 8
  store i64 %1, i64* %align, align 8
  %11 = load i64, i64* %size, align 8
  %12 = load i64, i64* %align, align 8
  store i64 %11, i64* %size.i, align 8
  store i64 %12, i64* %align.i, align 8
  %13 = load i64, i64* %size.i, align 8
  %14 = icmp ne i64 %13, 0
  %15 = xor i1 %14, true
  br i1 %15, label %then-block-112-.i, label %next-block.i

then-block-112-.i:                                ; preds = %entry-block
  call void @_ZN9panicking5panic20h52df14a965b04688KKKE({ %str_slice, %str_slice, i32 }* noalias readonly dereferenceable(40) @_ZN4heap24check_size_and_alignment14_MSG_FILE_LINE20hc3b2d56120089136JbaE)
  unreachable

next-block.i:                                     ; preds = %entry-block
  %16 = load i64, i64* %size.i, align 8
  %17 = icmp ule i64 %16, 9223372036854775807
  %18 = xor i1 %17, true
  br i1 %18, label %then-block-145-.i, label %next-block1.i

then-block-145-.i:                                ; preds = %next-block.i
  %19 = bitcast { %str_slice*, i64 }* %3 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %19, i8* bitcast ({ %str_slice*, i64 }* @_ZN4heap24check_size_and_alignment15__STATIC_FMTSTR20hfa6992380310c546wcaE to i8*), i64 16, i32 8, i1 false)
  %20 = getelementptr inbounds { %str_slice*, i64 }, { %str_slice*, i64 }* %3, i32 0, i32 0
  %21 = load %str_slice*, %str_slice** %20
  %22 = getelementptr inbounds { %str_slice*, i64 }, { %str_slice*, i64 }* %3, i32 0, i32 1
  %23 = load i64, i64* %22
  %24 = getelementptr inbounds { i64* }, { i64* }* %5, i32 0, i32 0
  store i64* %size.i, i64** %24, align 8
  %25 = bitcast { i64* }* %5 to i64*
  %26 = load i64, i64* %25, align 8
  %27 = bitcast { i64* }* %match.i to i64*
  store i64 %26, i64* %27, align 8
  %28 = getelementptr inbounds { i64* }, { i64* }* %match.i, i32 0, i32 0
  store i64** %28, i64*** %__llmatch.i
  %29 = load i64**, i64*** %__llmatch.i
  %30 = load i64*, i64** %29, align 8, !nonnull !1
  store i64* %30, i64** %__arg0.i, align 8
  %31 = getelementptr inbounds [1 x %"2.core::fmt::ArgumentV1"], [1 x %"2.core::fmt::ArgumentV1"]* %4, i32 0, i32 0
  %32 = load i64*, i64** %__arg0.i, align 8, !nonnull !1
  call void @"_ZN3fmt13_$LT$impl$GT$3new3new20h4621647584932494472E"(%"2.core::fmt::ArgumentV1"* noalias nocapture sret dereferenceable(16) %31, i64* noalias readonly dereferenceable(8) %32, i8 (i64*, %"2.core::fmt::Formatter"*)* @"_ZN3fmt3num13_$LT$impl$GT$3fmt20h61c12488bb3d5903AZVE")
  %33 = bitcast [1 x %"2.core::fmt::ArgumentV1"]* %4 to %"2.core::fmt::ArgumentV1"*
  %34 = getelementptr inbounds { %"2.core::fmt::ArgumentV1"*, i64 }, { %"2.core::fmt::ArgumentV1"*, i64 }* %__coerce_target.i, i32 0, i32 0
  store %"2.core::fmt::ArgumentV1"* %33, %"2.core::fmt::ArgumentV1"** %34
  %35 = getelementptr inbounds { %"2.core::fmt::ArgumentV1"*, i64 }, { %"2.core::fmt::ArgumentV1"*, i64 }* %__coerce_target.i, i32 0, i32 1
  store i64 1, i64* %35
  %36 = getelementptr inbounds { %"2.core::fmt::ArgumentV1"*, i64 }, { %"2.core::fmt::ArgumentV1"*, i64 }* %__coerce_target.i, i32 0, i32 0
  %37 = load %"2.core::fmt::ArgumentV1"*, %"2.core::fmt::ArgumentV1"** %36
  %38 = getelementptr inbounds { %"2.core::fmt::ArgumentV1"*, i64 }, { %"2.core::fmt::ArgumentV1"*, i64 }* %__coerce_target.i, i32 0, i32 1
  %39 = load i64, i64* %38
  call void @"_ZN3fmt13_$LT$impl$GT$6new_v120h5e9764a905143b40HJWE"(%"2.core::fmt::Arguments"* noalias nocapture sret dereferenceable(48) %2, %str_slice* noalias nonnull readonly %21, i64 %23, %"2.core::fmt::ArgumentV1"* noalias nonnull readonly %37, i64 %39)
  call void @_ZN9panicking9panic_fmt20h9106226f5abb116edMKE(%"2.core::fmt::Arguments"* noalias nocapture dereferenceable(48) %2, { %str_slice, i32 }* noalias readonly dereferenceable(24) @_ZN4heap24check_size_and_alignment10_FILE_LINE20hcf2a8ce10e9354d6gcaE)
  unreachable

next-block1.i:                                    ; preds = %next-block.i
  %40 = load i64, i64* %align.i, align 8
  %41 = call zeroext i1 @"_ZN3num13_$LT$impl$GT$15is_power_of_two20hcabd0a0fb3e6b19ar8iE"(i64 %40)
  %42 = zext i1 %41 to i8
  store i8 %42, i8* %6, align 1
  %43 = load i8, i8* %6, align 1, !range !0
  %44 = trunc i8 %43 to i1
  %45 = xor i1 %44, true
  br i1 %45, label %then-block-201-.i, label %_ZN4heap24check_size_and_alignment20hfe4e6278eec1ce19mbaE.exit

then-block-201-.i:                                ; preds = %next-block1.i
  %46 = bitcast { %str_slice*, i64 }* %8 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %46, i8* bitcast ({ %str_slice*, i64 }* @_ZN4heap24check_size_and_alignment15__STATIC_FMTSTR20hfa6992380310c546qdaE to i8*), i64 16, i32 8, i1 false)
  %47 = getelementptr inbounds { %str_slice*, i64 }, { %str_slice*, i64 }* %8, i32 0, i32 0
  %48 = load %str_slice*, %str_slice** %47
  %49 = getelementptr inbounds { %str_slice*, i64 }, { %str_slice*, i64 }* %8, i32 0, i32 1
  %50 = load i64, i64* %49
  %51 = getelementptr inbounds { i64* }, { i64* }* %10, i32 0, i32 0
  store i64* %align.i, i64** %51, align 8
  %52 = bitcast { i64* }* %10 to i64*
  %53 = load i64, i64* %52, align 8
  %54 = bitcast { i64* }* %match2.i to i64*
  store i64 %53, i64* %54, align 8
  %55 = getelementptr inbounds { i64* }, { i64* }* %match2.i, i32 0, i32 0
  store i64** %55, i64*** %__llmatch4.i
  %56 = load i64**, i64*** %__llmatch4.i
  %57 = load i64*, i64** %56, align 8, !nonnull !1
  store i64* %57, i64** %__arg05.i, align 8
  %58 = getelementptr inbounds [1 x %"2.core::fmt::ArgumentV1"], [1 x %"2.core::fmt::ArgumentV1"]* %9, i32 0, i32 0
  %59 = load i64*, i64** %__arg05.i, align 8, !nonnull !1
  call void @"_ZN3fmt13_$LT$impl$GT$3new3new20h4621647584932494472E"(%"2.core::fmt::ArgumentV1"* noalias nocapture sret dereferenceable(16) %58, i64* noalias readonly dereferenceable(8) %59, i8 (i64*, %"2.core::fmt::Formatter"*)* @"_ZN3fmt3num13_$LT$impl$GT$3fmt20h61c12488bb3d5903AZVE")
  %60 = bitcast [1 x %"2.core::fmt::ArgumentV1"]* %9 to %"2.core::fmt::ArgumentV1"*
  %61 = getelementptr inbounds { %"2.core::fmt::ArgumentV1"*, i64 }, { %"2.core::fmt::ArgumentV1"*, i64 }* %__coerce_target7.i, i32 0, i32 0
  store %"2.core::fmt::ArgumentV1"* %60, %"2.core::fmt::ArgumentV1"** %61
  %62 = getelementptr inbounds { %"2.core::fmt::ArgumentV1"*, i64 }, { %"2.core::fmt::ArgumentV1"*, i64 }* %__coerce_target7.i, i32 0, i32 1
  store i64 1, i64* %62
  %63 = getelementptr inbounds { %"2.core::fmt::ArgumentV1"*, i64 }, { %"2.core::fmt::ArgumentV1"*, i64 }* %__coerce_target7.i, i32 0, i32 0
  %64 = load %"2.core::fmt::ArgumentV1"*, %"2.core::fmt::ArgumentV1"** %63
  %65 = getelementptr inbounds { %"2.core::fmt::ArgumentV1"*, i64 }, { %"2.core::fmt::ArgumentV1"*, i64 }* %__coerce_target7.i, i32 0, i32 1
  %66 = load i64, i64* %65
  call void @"_ZN3fmt13_$LT$impl$GT$6new_v120h5e9764a905143b40HJWE"(%"2.core::fmt::Arguments"* noalias nocapture sret dereferenceable(48) %7, %str_slice* noalias nonnull readonly %48, i64 %50, %"2.core::fmt::ArgumentV1"* noalias nonnull readonly %64, i64 %66)
  call void @_ZN9panicking9panic_fmt20h9106226f5abb116edMKE(%"2.core::fmt::Arguments"* noalias nocapture dereferenceable(48) %7, { %str_slice, i32 }* noalias readonly dereferenceable(24) @_ZN4heap24check_size_and_alignment10_FILE_LINE20hcf2a8ce10e9354d6adaE)
  unreachable

_ZN4heap24check_size_and_alignment20hfe4e6278eec1ce19mbaE.exit: ; preds = %next-block1.i
  %67 = load i64, i64* %size, align 8
  %68 = load i64, i64* %align, align 8
  store i64 %67, i64* %__arg, align 8
  %69 = load i64, i64* %__arg
  store i64 %68, i64* %__arg1, align 8
  %70 = load i64, i64* %__arg1
  %71 = call i8* @__rust_allocate(i64 %69, i64 %70)
  ret i8* %71
}

; Function Attrs: cold noinline noreturn
declare void @_ZN9panicking5panic20h52df14a965b04688KKKE({ %str_slice, %str_slice, i32 }* noalias readonly dereferenceable(40)) unnamed_addr #2

; Function Attrs: cold noinline noreturn
declare void @_ZN9panicking9panic_fmt20h9106226f5abb116edMKE(%"2.core::fmt::Arguments"* noalias nocapture dereferenceable(48), { %str_slice, i32 }* noalias readonly de
referenceable(24)) unnamed_addr #2

; Function Attrs: inlinehint uwtable
define internal void @"_ZN3fmt13_$LT$impl$GT$6new_v120h5e9764a905143b40HJWE"(%"2.core::fmt::Arguments"* noalias nocapture sret dereferenceable(48), %str_slice* noalias nonnull readonly, i64, %"2.core::fmt::ArgumentV1"* noalias nonnull readonly, i64) unnamed_addr #1 {
entry-block:
  %pieces = alloca { %str_slice*, i64 }
  %args = alloca { %"2.core::fmt::ArgumentV1"*, i64 }
  %5 = getelementptr inbounds { %str_slice*, i64 }, { %str_slice*, i64 }* %pieces, i32 0, i32 0
  store %str_slice* %1, %str_slice** %5
  %6 = getelementptr inbounds { %str_slice*, i64 }, { %str_slice*, i64 }* %pieces, i32 0, i32 1
  store i64 %2, i64* %6
  %7 = getelementptr inbounds { %"2.core::fmt::ArgumentV1"*, i64 }, { %"2.core::fmt::ArgumentV1"*, i64 }* %args, i32 0, i32 0
  store %"2.core::fmt::ArgumentV1"* %3, %"2.core::fmt::ArgumentV1"** %7
  %8 = getelementptr inbounds { %"2.core::fmt::ArgumentV1"*, i64 }, { %"2.core::fmt::ArgumentV1"*, i64 }* %args, i32 0, i32 1
  store i64 %4, i64* %8
  %9 = getelementptr inbounds %"2.core::fmt::Arguments", %"2.core::fmt::Arguments"* %0, i32 0, i32 0
  %10 = bitcast { %str_slice*, i64 }* %pieces to i8*
  %11 = bitcast { %str_slice*, i64 }* %9 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %11, i8* %10, i64 16, i32 8, i1 false)
  %12 = getelementptr inbounds %"2.core::fmt::Arguments", %"2.core::fmt::Arguments"* %0, i32 0, i32 1
  %13 = bitcast %"2.core::option::Option<&'static [core::fmt::rt::v1::Argument]>"* %12 to { { i8*, i8* } }*
  %14 = bitcast { { i8*, i8* } }* %13 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %14, i8* bitcast ({ { i8*, i8* } }* @const2514 to i8*), i64 16, i32 8, i1 false)
  %15 = getelementptr inbounds %"2.core::fmt::Arguments", %"2.core::fmt::Arguments"* %0, i32 0, i32 2
  %16 = bitcast { %"2.core::fmt::ArgumentV1"*, i64 }* %args to i8*
  %17 = bitcast { %"2.core::fmt::ArgumentV1"*, i64 }* %15 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %17, i8* %16, i64 16, i32 8, i1 false)
  ret void
}

; Function Attrs: nounwind
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #3

; Function Attrs: uwtable
define internal void @"_ZN3fmt13_$LT$impl$GT$3new3new20h4621647584932494472E"(%"2.core::fmt::ArgumentV1"* noalias nocapture sret dereferenceable(16), i64* noalias readonly dereferenceable(8), i8 (i64*, %"2.core::fmt::Formatter"*)*) unnamed_addr #0 {
entry-block:
  %x = alloca i64*
  %f = alloca i8 (i64*, %"2.core::fmt::Formatter"*)*
  store i64* %1, i64** %x, align 8
  store i8 (i64*, %"2.core::fmt::Formatter"*)* %2, i8 (i64*, %"2.core::fmt::Formatter"*)** %f, align 8
  %3 = getelementptr inbounds %"2.core::fmt::ArgumentV1", %"2.core::fmt::ArgumentV1"* %0, i32 0, i32 1
  %4 = load i8 (i64*, %"2.core::fmt::Formatter"*)*, i8 (i64*, %"2.core::fmt::Formatter"*)** %f, align 8
  %5 = bitcast i8 (i64*, %"2.core::fmt::Formatter"*)* %4 to i8 (%"2.core::fmt::Void"*, %"2.core::fmt::Formatter"*)*
  store i8 (%"2.core::fmt::Void"*, %"2.core::fmt::Formatter"*)* %5, i8 (%"2.core::fmt::Void"*, %"2.core::fmt::Formatter"*)** %3
  %6 = getelementptr inbounds %"2.core::fmt::ArgumentV1", %"2.core::fmt::ArgumentV1"* %0, i32 0, i32 0
  %7 = load i64*, i64** %x, align 8, !nonnull !1
  %8 = bitcast i64* %7 to %"2.core::fmt::Void"*
  store %"2.core::fmt::Void"* %8, %"2.core::fmt::Void"** %6
  ret void
}

declare i8 @"_ZN3fmt3num13_$LT$impl$GT$3fmt20h61c12488bb3d5903AZVE"(i64* noalias readonly dereferenceable(8), %"2.core::fmt::Formatter"* noalias dereferenceable(96)) unnamed_addr

; Function Attrs: inlinehint uwtable
define internal zeroext i1 @"_ZN3num13_$LT$impl$GT$15is_power_of_two20hcabd0a0fb3e6b19ar8iE"(i64) unnamed_addr #1 {
entry-block:
  %self = alloca i64
  %1 = alloca i64
  %2 = alloca i64
  %3 = alloca i64
  %4 = alloca i64
  store i64 %0, i64* %self, align 8
  %5 = load i64, i64* %self, align 8
  %6 = call i64 @"_ZN3num13_$LT$impl$GT$3one20h790da5113c87c0645lhE"()
  store i64 %6, i64* %2, align 8
  %7 = load i64, i64* %2, align 8
  %8 = call i64 @"_ZN3num13_$LT$impl$GT$12wrapping_sub20h362106a5499b8ea7s5iE"(i64 %5, i64 %7)
  store i64 %8, i64* %1, align 8
  %9 = load i64, i64* %1, align 8
  %10 = load i64, i64* %self, align 8
  %11 = and i64 %9, %10
  %12 = call i64 @"_ZN3num13_$LT$impl$GT$4zero20hc4254551c8413675WlhE"()
  store i64 %12, i64* %3, align 8
  %13 = load i64, i64* %3, align 8
  %14 = icmp eq i64 %11, %13
  br i1 %14, label %before_rhs, label %join

join:                                             ; preds = %before_rhs, %entry-block
  %15 = phi i1 [ %14, %entry-block ], [ %22, %before_rhs ]
  %16 = zext i1 %15 to i8
  %17 = trunc i8 %16 to i1
  ret i1 %17

before_rhs:                                       ; preds = %entry-block
  %18 = load i64, i64* %self, align 8
  %19 = call i64 @"_ZN3num13_$LT$impl$GT$4zero20hc4254551c8413675WlhE"()
  store i64 %19, i64* %4, align 8
  %20 = load i64, i64* %4, align 8
  %21 = icmp eq i64 %18, %20
  %22 = xor i1 %21, true
  br label %join
}

; Function Attrs: inlinehint uwtable
define internal i64 @"_ZN3num13_$LT$impl$GT$12wrapping_sub20h362106a5499b8ea7s5iE"(i64, i64) unnamed_addr #1 {
entry-block:
  %self = alloca i64
  %rhs = alloca i64
  store i64 %0, i64* %self, align 8
  store i64 %1, i64* %rhs, align 8
  %2 = load i64, i64* %self, align 8
  %3 = load i64, i64* %rhs, align 8
  %4 = sub i64 %2, %3
  ret i64 %4
}

; Function Attrs: inlinehint uwtable
define internal i64 @"_ZN3num13_$LT$impl$GT$3one20h790da5113c87c0645lhE"() unnamed_addr #1 {
entry-block:
  ret i64 1
}

; Function Attrs: inlinehint uwtable
define internal i64 @"_ZN3num13_$LT$impl$GT$4zero20hc4254551c8413675WlhE"() unnamed_addr #1 {
entry-block:
  ret i64 0
}

; Function Attrs: nounwind
declare noalias i8* @__rust_allocate(i64, i64) unnamed_addr #3

; Function Attrs: inlinehint uwtable
define internal zeroext i1 @"_ZN3ptr13_$LT$impl$GT$7is_null7is_null21h14748829460356738718E"(i8*) unnamed_addr #1 {
entry-block:
  %self = alloca i8*
  store i8* %0, i8** %self, align 8
  %1 = load i8*, i8** %self, align 8
  %2 = icmp eq i8* %1, null
  %3 = zext i1 %2 to i8
  %4 = trunc i8 %3 to i1
  ret i1 %4
}

; Function Attrs: cold noinline noreturn
declare void @_ZN3oom20hd9170b7f1397402fatbE() unnamed_addr #2

declare %"9.my_crate::Foo" @"_ZN13_$LT$impl$GT$3new20h7a0183b89d396887kaaE"() unnamed_addr

attributes #0 = { uwtable }
attributes #1 = { inlinehint uwtable }
attributes #2 = { cold noinline noreturn }
attributes #3 = { nounwind }

!0 = !{i8 0, i8 2}
!1 = !{}

and compiles on vanilla and rustc

@arielb1
Copy link
Contributor

arielb1 commented Oct 7, 2015

cc @dotdash

@eefriedman
Copy link
Contributor

Why is there a tail call followed by a ret?

tail doesn't mean what you think it means; details in LLVM LangRef, but basically "tail" doesn't actually mean the call is in a tail position.


It looks like a real LLVM bug, but one that rustc could easily dodge by generating declare void @[...] instead of declare %"9.my_crate::Foo" @[...].

@jonas-schievink
Copy link
Contributor

Quoting the LLVM reference:

The optional “tail” marker indicates that the callee function does not access any allocas or varargs in the caller. Note that calls may be marked “tail” even if they do not occur before a ret instruction. If the “tail” marker is present, the function call is eligible for tail call optimization, but might not in fact be optimized into a jump.

@dotdash dotdash self-assigned this Jan 15, 2016
dotdash added a commit to dotdash/rust that referenced this issue Jan 15, 2016
The only way to get a value for a zero-sized type is `undef`, so
there's really no point in actually having a return type other than
void for such types. Also, while the comment in return_type_is_void
mentioned something about aiding C ABI support, @eddyb correctly
pointed out on IRC that there is no such thing as a zero-sized type in
C. And even with clang, which allows empty structs, those get
translated as void return types as well.

Fixes rust-lang#28766
Manishearth added a commit to Manishearth/rust that referenced this issue Jan 17, 2016
The only way to get a value for a zero-sized type is `undef`, so
there's really no point in actually having a return type other than
void for such types. Also, while the comment in return_type_is_void
mentioned something about aiding C ABI support, @eddyb correctly
pointed out on IRC that there is no such thing as a zero-sized type in
C. And even with clang, which allows empty structs, those get
translated as void return types as well.

Fixes rust-lang#28766
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
Projects
None yet
Development

No branches or pull requests

6 participants