Code change:
<ins> //@ revisions: enable-backchain disable-backchain //@ assembly-output: emit-asm //@ compile-flags: -O --crate-type=lib --target=s390x-unknown-linux-gnu //@ needs-llvm-components: systemz //@[enable-backchain] compile-flags: -Ctarget-feature=+backchain //@[disable-backchain] compile-flags: -Ctarget-feature=-backchain #![feature(no_core, lang_items)] #![no_std] #![no_core] #[lang = "sized"] trait Sized {} extern "C" { fn extern_func(); } // CHECK-LABEL: test_backchain #[no_mangle] extern "C" fn test_backchain() -> i32 { // Here we try to match if backchain register is saved to the parameter area (stored in r15/sp) // And also if a new parameter area (160 bytes) is allocated for the upcoming function call // enable-backchain: lgr [[REG1:.*]], %r15 // enable-backchain-NEXT: aghi %r15, -160 // enable-backchain: stg [[REG1]], 0(%r15) // disable-backchain: aghi %r15, -160 // disable-backchain-NOT: stg %r{{.*}}, 0(%r15) unsafe { extern_func(); } // enable-backchain-NEXT: brasl %r{{.*}}, extern_func@PLT // disable-backchain: brasl %r{{.*}}, extern_func@PLT // Make sure that the expected return value is written into %r2 (return register): // enable-backchain-NEXT: lghi %r2, 1 // disable-backchain: lghi %r2, 0 #[cfg(target_feature = "backchain")] { 1 } #[cfg(not(target_feature = "backchain"))] { 0 } // CHECK: br %r{{.*}} } </ins>

Related discussion:
text: introduced what I think is a logic error: is now always on s390x targets, even if the feature gate is not set. I verified this with Miri, which shares the logic with rustc so it should be a correct test. This should print when built without (as the feature seems off-by-default), but prints instead: Cc
I believe this is intended. is an always-available code-generation option in LLVM disguised as a target feature. Also, enabling for a single function is useless due to how IBM Z's mechanism works.
By "always available" you mean that there is no difference between and ? But then why would one set this feature?
There are differences between the code generated with or without attribute. Still, unlike other processors, this is a platform-specific (potential) unwinding mechanism that does not require additional processor features when you don't have DWARF information or don't want to use it (profilers on IBM Z systems may use it).
The point of is to reflect whether the feature is enabled. It doesn't matter whether it could be enabled or anything like that. For example, is false unless you are building with . It's not about whether static builds are "available" (that's not even a meaningful question), it's about the flags used to build this code. Maybe you are confusing with . Those are not the same thing. If this is not actually a target feature, then it is not clear that we want this to be a target feature in Rust. Though I guess is (unfortunately) precedent here. What happens when I mix code built with and without ? Does anything go wrong?
No, it just means you won't be able to perform unwinding actions based purely on backchain information.
If you want to know how Clang passes attribute in this situation, you can take a look at this Godbolt playground: In this example, is specified (see ), so the compiler needs to generate backchain-enabled code.
Okay, thanks. I don't fully understand the consequences of that -- if this makes Rust panic catching go wrong, that still seems bad -- but :shrug: whatever. The point of the issue is that the behavior of is wrong. Are you still arguing against that or have my examples above been convincing?