Change:
and are both broken on s390x since Rust 1.28. When is built without debuginfo, the tests hang with their backtracing processes stuck in a loop. With debuginfo, it fails with output like: I believe the problem is this part of : where doesn't identify that is a 64-bit platform. See also alexcrichton/backtrace-rs. I plan to update that here when it's published, and make a similar fix in .
fixes the backtrace when is built with debuginfo, but I'm still getting a hang without. In GDB, it looks like the unwinder gets to the that catches panics, then loops unwinding that same PC forever. This part of the regression is older -- happens on 1.27.2 as well, but 1.26.2 is fine. Binaries from the older version don't appear to have a distinct symbol at all, but maybe that's just inlined differently. I'm bisecting for that hang now.
Bisecting pointed me at (cc which attributes to all functions. For s390x the base features actually include a removal, . But it doesn't look like the features are applied to the synthesized (), and as a result it doesn't get inlined anymore since it has more features (w/ ) than the callee. We probably should apply target-features to as well. I don't know why the non-inlined can't be unwound -- maybe we need to force ? By default GDB backtrace stops at crate , but tries to go further: Maybe Rust's could have a similar defensive check, at least.
Nice find Definitely makes sense to me, and this should be fixed up (at least the business) in
With , , and , I believe we have this fixed.

Discussion:
use std::ffi::CString; <del> use rustc::hir::CodegenFnAttrFlags; </del> <ins> use rustc::hir::{CodegenFnAttrFlags, CodegenFnAttrs}; </ins> use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::session::Session; use rustc::session::config::Sanitizer;

/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) /// attributes. <del> pub fn from_fn_attrs(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value, id: DefId) { let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(id); </del> <ins> pub fn from_fn_attrs( cx: &CodegenCx<'ll, '_>, llfn: &'ll Value, id: Option<DefId>, ) { let codegen_fn_attrs = id.map(|id| cx.tcx.codegen_fn_attrs(id)) .unwrap_or(CodegenFnAttrs::new()); </ins> inline(llfn, codegen_fn_attrs.inline); <ins> // The `uwtable` attribute according to LLVM is: // //     This attribute indicates that the ABI being targeted requires that an //     unwind table entry be produced for this function even if we can show //     that no exceptions passes by it. This is normally the case for the //     ELF x86-64 abi, but it can be disabled for some compilation units. // // Typically when we're compiling with `-C panic=abort` (which implies this // `no_landing_pads` check) we don't need `uwtable` because we can't // generate any exceptions! On Windows, however, exceptions include other // events such as illegal instructions, segfaults, etc. This means that on // Windows we end up still needing the `uwtable` attribute even if the `-C // panic=abort` flag is passed. // // You can also find more info on why Windows is whitelisted here in: //      https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 if !cx.sess().no_landing_pads() || cx.sess().target.target.options.requires_uwtable { attributes::emit_uwtable(llfn, true); } </ins> set_frame_pointer_elimination(cx, llfn); set_probestack(cx, llfn);

// *in Rust code* may unwind. Foreign items like `extern "C" { // fn foo(); }` are assumed not to unwind **unless** they have // a `#[unwind]` attribute. <del> } else if !cx.tcx.is_foreign_item(id) { </del> <ins> } else if id.map(|id| !cx.tcx.is_foreign_item(id)).unwrap_or(false) { </ins> Some(true) } else { None

// Note that currently the `wasm-import-module` doesn't do anything, but // eventually LLVM 7 should read this and ferry the appropriate import // module to the output file. <del> if cx.tcx.sess.target.target.arch == "wasm32" { if let Some(module) = wasm_import_module(cx.tcx, id) { llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, const_cstr!("wasm-import-module"), &module, ); </del> <ins> if let Some(id) = id { if cx.tcx.sess.target.target.arch == "wasm32" { if let Some(module) = wasm_import_module(cx.tcx, id) { llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, const_cstr!("wasm-import-module"), &module, ); } </ins> } } }

cx.stats.borrow_mut().n_closures += 1; <del> // The `uwtable` attribute according to LLVM is: // //     This attribute indicates that the ABI being targeted requires that an //     unwind table entry be produced for this function even if we can show //     that no exceptions passes by it. This is normally the case for the //     ELF x86-64 abi, but it can be disabled for some compilation units. // // Typically when we're compiling with `-C panic=abort` (which implies this // `no_landing_pads` check) we don't need `uwtable` because we can't // generate any exceptions! On Windows, however, exceptions include other // events such as illegal instructions, segfaults, etc. This means that on // Windows we end up still needing the `uwtable` attribute even if the `-C // panic=abort` flag is passed. // // You can also find more info on why Windows is whitelisted here in: //      https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 if !cx.sess().no_landing_pads() || cx.sess().target.target.options.requires_uwtable { attributes::emit_uwtable(lldecl, true); } </del> let mir = cx.tcx.instance_mir(instance.def); mir::codegen_mir(cx, lldecl, &mir, instance, sig); }

if instance.def.is_inline(tcx) { attributes::inline(llfn, attributes::InlineAttr::Hint); } <del> attributes::from_fn_attrs(cx, llfn, instance.def.def_id()); </del> <ins> attributes::from_fn_attrs(cx, llfn, Some(instance.def.def_id())); </ins> let instance_def_id = instance.def_id();

#![allow(non_upper_case_globals)] <ins> use attributes; </ins> use intrinsics::{self, Intrinsic}; use llvm::{self, TypeKind}; use abi::{Abi, FnType, LlvmType, PassMode};

Abi::Rust ))); let llfn = declare::define_internal_fn(cx, name, rust_fn_ty); <ins> attributes::from_fn_attrs(cx, llfn, None); </ins> let bx = Builder::new_block(cx, llfn, "entry-block"); codegen(bx); llfn

if instance.def.is_inline(cx.tcx) { attributes::inline(lldecl, attributes::InlineAttr::Hint); } <del> attributes::from_fn_attrs(cx, lldecl, instance.def.def_id()); </del> <ins> attributes::from_fn_attrs(cx, lldecl, Some(instance.def.def_id())); </ins> cx.instances.borrow_mut().insert(instance, lldecl); }