Skip to content

Commit

Permalink
Auto merge of #63909 - RalfJung:nounwind, r=<try>
Browse files Browse the repository at this point in the history
fix nounwind attribute logic

With #62603 landed, we no longer add abort-on-panic shims to `extern "C"` functions. However, that means we should also not emit `nounwind` for `extern fn` because we are not actually catching those panics. The comment justifying that `nounwind` in the source is just factually wrong.

I also noticed that we annotate `extern` *declarations* (of any ABI) with `nounwind`, which seems wrong? I removed this. Code like mozjpeg (the code that prompted the removal of the abort-on-panic shim) throws a panic from Rust code that enters C code (meaning the `extern "C"` *definition* must not have `nounwind`, or else we got UB), but then the panic bubbles through the C code and re-enters Rust code (meaning the `extern "C"` *declaration* that gets called from the Rust side must not have `nounwind` either).

This should be beta-backported if #62603 gets backported.
  • Loading branch information
bors committed Aug 28, 2019
2 parents ac21131 + 47e4193 commit 8894a68
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 29 deletions.
23 changes: 3 additions & 20 deletions src/librustc_codegen_llvm/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ use rustc::hir::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::session::Session;
use rustc::session::config::{Sanitizer, OptLevel};
use rustc::ty::{self, TyCtxt, PolyFnSig};
use rustc::ty::{TyCtxt, PolyFnSig};
use rustc::ty::layout::HasTyCtxt;
use rustc::ty::query::Providers;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_data_structures::fx::FxHashMap;
use rustc_target::spec::PanicStrategy;
use rustc_codegen_ssa::traits::*;

use crate::abi::Abi;
use crate::attributes;
use crate::llvm::{self, Attribute};
use crate::llvm::AttributePlace::Function;
Expand Down Expand Up @@ -201,7 +200,7 @@ pub fn from_fn_attrs(
cx: &CodegenCx<'ll, 'tcx>,
llfn: &'ll Value,
id: Option<DefId>,
sig: PolyFnSig<'tcx>,
_sig: PolyFnSig<'tcx>,
) {
let codegen_fn_attrs = id.map(|id| cx.tcx.codegen_fn_attrs(id))
.unwrap_or_else(|| CodegenFnAttrs::new());
Expand Down Expand Up @@ -268,27 +267,11 @@ pub fn from_fn_attrs(
// optimize based on this!
false
} else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) {
// If a specific #[unwind] attribute is present, use that
// If a specific #[unwind] attribute is present, use that.
true
} else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
// Special attribute for allocator functions, which can't unwind
false
} else if let Some(id) = id {
let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
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
true
}
} else {
// assume this can possibly unwind, avoiding the application of a
// `nounwind` attribute below.
Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2528,6 +2528,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
} else if attr.check_name(sym::rustc_allocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
} else if attr.check_name(sym::unwind) {
// FIXME: We currently assume it can unwind even with `#[unwind(aborts)]`.
codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND;
} else if attr.check_name(sym::ffi_returns_twice) {
if tcx.is_foreign_item(id) {
Expand Down
28 changes: 25 additions & 3 deletions src/test/codegen/extern-functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,38 @@
#![feature(unwind_attributes)]

extern {
// CHECK: Function Attrs: nounwind
// CHECK-NEXT: declare void @extern_fn
// CHECK-NOT: nounwind
// CHECK: declare void @extern_fn
fn extern_fn();
// CHECK-NOT: Function Attrs: nounwind
// CHECK-NOT: nounwind
// CHECK: declare void @unwinding_extern_fn
#[unwind(allowed)]
fn unwinding_extern_fn();
// CHECK-NOT: nounwind
// CHECK: declare void @aborting_extern_fn
#[unwind(aborts)]
fn aborting_extern_fn(); // FIXME: we don't have the attribute here
}

extern "Rust" {
// CHECK-NOT: nounwind
// CHECK: declare void @rust_extern_fn
fn rust_extern_fn();
// CHECK-NOT: nounwind
// CHECK: declare void @rust_unwinding_extern_fn
#[unwind(allowed)]
fn rust_unwinding_extern_fn();
// CHECK-NOT: nounwind
// CHECK: declare void @rust_aborting_extern_fn
#[unwind(aborts)]
fn rust_aborting_extern_fn(); // FIXME: we don't have the attribute here
}

pub unsafe fn force_declare() {
extern_fn();
unwinding_extern_fn();
aborting_extern_fn();
rust_extern_fn();
rust_unwinding_extern_fn();
rust_aborting_extern_fn();
}
6 changes: 0 additions & 6 deletions src/test/codegen/nounwind-extern.rs

This file was deleted.

15 changes: 15 additions & 0 deletions src/test/codegen/unwind-extern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// compile-flags: -C opt-level=0

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

// make sure these all do *not* get the attribute
// CHECK-NOT: nounwind

pub extern fn foo() {} // right now we don't abort-on-panic, so we also shouldn't have `nounwind`
#[unwind(allowed)]
pub extern fn foo_allowed() {}

pub extern "Rust" fn bar() {}
#[unwind(allowed)]
pub extern "Rust" fn bar_allowed() {}

0 comments on commit 8894a68

Please sign in to comment.