Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2888,6 +2888,14 @@ pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: Spe
return false;
}

// With `-C panic=abort`, all non-FFI functions are required to not unwind.
//
// Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
// function defined in Rust is also required to abort.
if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
return false;
}

// With -Z panic-in-drop=abort, drop_in_place never unwinds.
//
// This is not part of `codegen_fn_attrs` as it can differ between crates
Expand Down
19 changes: 12 additions & 7 deletions src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
// compile-flags: -C panic=abort

// Test that `nounwind` atributes are not applied to `C-unwind` extern functions
// even when the code is compiled with `panic=abort`.
// Test that `nounwind` atributes are also applied to extern `C-unwind` Rust functions
// when the code is compiled with `panic=abort`.

#![crate_type = "lib"]
#![feature(c_unwind)]

extern "C-unwind" {
fn may_unwind();
}

// CHECK: @rust_item_that_can_unwind() unnamed_addr #0
#[no_mangle]
pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() {
// CHECK: call void @_ZN4core9panicking15panic_no_unwind
may_unwind();
}

extern "C-unwind" {
// CHECK: @may_unwind() unnamed_addr #1
fn may_unwind();
}

// Now, make sure that the LLVM attributes for this functions are correct. First, make
// sure that the first item is correctly marked with the `nounwind` attribute:
//
// CHECK-NOT: attributes #0 = { {{.*}}nounwind{{.*}} }
// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may_unwind must not be marked with nounwind as otherwise you would get UB when it unwinds instead of an abort. Can you add a check that may_unwind gets a different attributes list without the nounwind attribute?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically C-unwind foreign declarations must not get nounwind. C-unwind function definitions can get nounwind.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what this is doing though: The #0 attributes with nounwind apply to rust_item_that_can_unwind and the #1 attributes without nounwind apply to may_unwind.

Copy link
Member Author

@nbdd0121 nbdd0121 May 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added the #1 check after @bjorn3's comments -- the original test doesn't check the attribute of may_unwind. It's not wrong, but the test could be expanded.

//
// Now, check that foreign item is correctly marked without the `nounwind` attribute.
// CHECK-NOT: attributes #1 = { {{.*}}nounwind{{.*}} }