Change:
} else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) { // Special attribute for allocator functions, which can't unwind false <del> } else if let Some(id) = id { </del> <ins> } else if let Some(_) = id { // rust-lang/rust#64655, rust-lang/rust#63909: to minimize // risk associated with changing cases where nounwind // attribute is attached, this code is deliberately mimicking // old control flow based on whether `id` is `Some` or `None`. // // However, in the long term we should either: // - fold this into final else (i.e. stop inspecting `id`) // - or, adopt Rust PR #63909. // // see also Rust RFC 2753. </ins> let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); <del> if cx.tcx.is_foreign_item(id) { // Foreign items like `extern "C" { fn foo(); }` are assumed not to // unwind false } else if sig.abi != Abi::Rust && sig.abi != Abi::RustCall { // Any items defined in Rust that *don't* have the `extern` ABI are // defined to not unwind. We insert shims to abort if an unwind // happens to enforce this. false } else { // Anything else defined in Rust is assumed that it can possibly // unwind </del> <ins> if sig.abi == Abi::Rust || sig.abi == Abi::RustCall { // Any Rust method (or `extern "Rust" fn` or `extern // "rust-call" fn`) is explicitly allowed to unwind // (unless it has no-unwind attribute, handled above). </ins> true <ins> } else { // Anything else is either: // //  1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or // //  2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`). // // Foreign items (case 1) are assumed to not unwind; it is // UB otherwise. (At least for now; see also // rust-lang/rust#63909 and Rust RFC 2753.) // // Items defined in Rust with non-Rust ABIs (case 2) are also // not supposed to unwind. Whether this should be enforced // (versus stating it is UB) and *how* it would be enforced // is currently under discussion; see rust-lang/rust#58794. // // In either case, we mark item as explicitly nounwind. false </ins> } } else { // assume this can possibly unwind, avoiding the application of a // `nounwind` attribute below. <ins> // // (But: See comments in previous branch. Specifically, it is // unclear whether there is real value in the assumption this // can unwind. The conservatism here may just be papering over // a real problem by making some UB a bit harder to hit.) </ins> true });

Discussion:
Hi, It looks like calls to are getting removed when using for a release build. It doesn't seem to occur with or . I've got a test case here: , which can be reproduced like this: (more details in the ) For context, I first noticed this in a project where I am using an to communciate between threads, where a producer thread reads messages from the network, and the main thread saves those to a database. I was relying on the fact that the implementation for a channel will in effect close the channel, so the main thread can find out that the producer has failed, and so we should kill the process. What I saw instead was the producer thread panicing, but the main thread would never get woken up. I've seen this on macOS and Linux .
triage: P-high. Assigning to self. Removing nomination label.
Doing some bisection. This was introduced between Rust 1.32 and 1.33
More specifically, this was introduced between nightly-2018-12-08 and nightly-2018-12-14: (unfortunately no nightlies are available between those two points in the rustup archive.)
These are the PR's that bors merged between those two points:
According to my bisection via local builds, this was injected by (!)
(Have I mentioned before that we probably need to be doing more testing of the various LTO configurations? Would it be feasible to run our test suite in all of the lto modes from {, , } ?)
For what its worth, 's PR fixes this (I think; I need to double-check atop a rebased-on-master version). yes, confirmed now atop rebased version
Thanks for tracking this down
Okay I some instrumentation to the compiler and I think I know where the problem here is coming from. Here's the executive summary: PR changed the logic for where we add the LLVM attribute PR has asserted, from the beginning, that some of that new logic was wrong. In particular, it noted that: I myself was confused by this comment, because it looked to me like the PR as written was taking pains to return for abis that match and . So why is the test crate in this issue illustrating the problem outlined by above? First of all, here is a standalone that reproduces the problem for me.

(You still have to turn on to observe the issue, but no other optimizations; e.g. still reproduces the issue for me): Running the compiler with gave me intermediate files that I could disassemble via and then inspect the resulting files. This led me to notice that some functions had on them that I did not expect. Second, I instrumented a local to report (via ) whenever it used either of these two cases: Just imagine the above, with two inserted calls that look like: println!("choosing unwind=false for foreign item {:?} with sig: {:?}", id, sig); and println!("choosing unwind=false for non-foreign {:?} with sig: {:?}", id, sig); And then I reviewed the output this spits out during both the stage1 bootstrapping and the actual compilation of the test case above. Here's the smoking gun from that output, I think: Unfortunately, the impl for does not include the abi (nor the unsafety). I'm guessing we'd see "Rust" there if that were included. namely, we are going through that first branch, already mentioned by , when we compile this declaration: This causes the generated declaration for to be tagged , even though that function is pretty much the function that is going to unwind. (But you need to have a somewhat nasty combination of factors to actually observe the optimization performed by LLVM in this case, which is how I guess this has gone relatively unobserved for so long, apart from what noticed in their own work.)
The short version of my previous comment is that I bet I could make a small change to mark extern fn's with Rust or RustCall ABIs as unwinding, which would have less impact than proposal and thus be a better candidate for backport. Update: Confirmed locally; yes we can fix this via a small targeted change. (Not sure if it will be the right long term solution, but it certainly seems like the right short-term step if only for backport purposes.)