Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc: Switch extern functions to abort by default on panic #55982

Merged
merged 1 commit into from
Dec 13, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
57 changes: 34 additions & 23 deletions src/librustc_codegen_llvm/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ use rustc::hir::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::session::Session;
use rustc::session::config::Sanitizer;
use rustc::ty::TyCtxt;
use rustc::ty::{self, TyCtxt, PolyFnSig};
use rustc::ty::layout::HasTyCtxt;
use rustc::ty::query::Providers;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::fx::FxHashMap;
use rustc_target::spec::PanicStrategy;
use rustc_codegen_ssa::traits::*;

use abi::Abi;
use attributes;
use llvm::{self, Attribute};
use llvm::AttributePlace::Function;
Expand Down Expand Up @@ -60,7 +61,7 @@ pub fn emit_uwtable(val: &'ll Value, emit: bool) {

/// Tell LLVM whether the function can or cannot unwind.
#[inline]
pub fn unwind(val: &'ll Value, can_unwind: bool) {
fn unwind(val: &'ll Value, can_unwind: bool) {
Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind);
}

Expand Down Expand Up @@ -150,9 +151,10 @@ pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) {
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
/// attributes.
pub fn from_fn_attrs(
cx: &CodegenCx<'ll, '_>,
cx: &CodegenCx<'ll, 'tcx>,
llfn: &'ll Value,
id: Option<DefId>,
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 @@ -194,28 +196,37 @@ pub fn from_fn_attrs(
llvm::AttributePlace::ReturnValue, llfn);
}

let can_unwind = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) {
Some(true)
unwind(llfn, if cx.tcx.sess.panic_strategy() != PanicStrategy::Unwind {
// In panic=abort mode we assume nothing can unwind anywhere, so
// optimize based on this!
false
} else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) {
// If a specific #[unwind] attribute is present, use that
true
} else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
Some(false)

// Perhaps questionable, but we assume that anything defined
// *in Rust code* may unwind. Foreign items like `extern "C" {
// fn foo(); }` are assumed not to unwind **unless** they have
// a `#[unwind]` attribute.
} else if id.map(|id| !cx.tcx.is_foreign_item(id)).unwrap_or(false) {
Some(true)
} else {
None
};

match can_unwind {
Some(false) => attributes::unwind(llfn, false),
Some(true) if cx.tcx.sess.panic_strategy() == PanicStrategy::Unwind => {
attributes::unwind(llfn, true);
// 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
}
Some(true) | None => {}
}
} else {
// assume this can possibly unwind, avoiding the application of a
// `nounwind` attribute below.
true
});

// Always annotate functions with the target-cpu they are compiled for.
// Without this, ThinLTO won't inline Rust functions into Clang generated
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_codegen_llvm/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub fn get_fn(
if instance.def.is_inline(tcx) {
attributes::inline(cx, llfn, attributes::InlineAttr::Hint);
}
attributes::from_fn_attrs(cx, llfn, Some(instance.def.def_id()));
attributes::from_fn_attrs(cx, llfn, Some(instance.def.def_id()), sig);

let instance_def_id = instance.def_id();

Expand Down
1 change: 0 additions & 1 deletion src/librustc_codegen_llvm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,6 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
));

let llfn = self.declare_fn("rust_eh_unwind_resume", sig);
attributes::unwind(llfn, true);
attributes::apply_target_cpu_attr(self, llfn);
unwresume.set(Some(llfn));
llfn
Expand Down
11 changes: 1 addition & 10 deletions src/librustc_codegen_llvm/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ use rustc::ty::{self, PolyFnSig};
use rustc::ty::layout::LayoutOf;
use rustc::session::config::Sanitizer;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_target::spec::PanicStrategy;
use abi::{Abi, FnType, FnTypeExt};
use abi::{FnType, FnTypeExt};
use attributes;
use context::CodegenCx;
use type_::Type;
Expand Down Expand Up @@ -86,10 +85,6 @@ fn declare_raw_fn(
_ => {},
}

if cx.tcx.sess.panic_strategy() != PanicStrategy::Unwind {
attributes::unwind(llfn, false);
}

attributes::non_lazy_bind(cx.sess(), llfn);

llfn
Expand Down Expand Up @@ -132,10 +127,6 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
}

if sig.abi != Abi::Rust && sig.abi != Abi::RustCall {
attributes::unwind(llfn, false);
}

fty.apply_attrs_llfn(llfn);

llfn
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_codegen_llvm/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1081,7 +1081,7 @@ fn gen_fn<'ll, 'tcx>(
Abi::Rust
));
let llfn = cx.define_internal_fn(name, rust_fn_sig);
attributes::from_fn_attrs(cx, llfn, None);
attributes::from_fn_attrs(cx, llfn, None, rust_fn_sig);
let bx = Builder::new_block(cx, llfn, "entry-block");
codegen(bx);
llfn
Expand Down
7 changes: 6 additions & 1 deletion src/librustc_codegen_llvm/mono_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,12 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
if instance.def.is_inline(self.tcx) {
attributes::inline(self, lldecl, attributes::InlineAttr::Hint);
}
attributes::from_fn_attrs(self, lldecl, Some(instance.def.def_id()));
attributes::from_fn_attrs(
self,
lldecl,
Some(instance.def.def_id()),
mono_sig,
);

self.instances.borrow_mut().insert(instance, lldecl);
}
Expand Down
7 changes: 1 addition & 6 deletions src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,12 +628,7 @@ fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
// unwind anyway. Don't stop them.
let attrs = &tcx.get_attrs(fn_def_id);
match attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs) {
None => {
// FIXME(rust-lang/rust#48251) -- Had to disable
// abort-on-panic for backwards compatibility reasons.
false
}

None => true,
Some(UnwindAttr::Allowed) => false,
Some(UnwindAttr::Aborts) => true,
}
Expand Down
16 changes: 16 additions & 0 deletions src/test/codegen/nounwind-extern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -O

#![crate_type = "lib"]

// CHECK: Function Attrs: norecurse nounwind
pub extern fn foo() {}
3 changes: 0 additions & 3 deletions src/test/run-pass/abort-on-c-abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@
// ignore-cloudabi no env and process
// ignore-emscripten no processes

#![feature(unwind_attributes)]

use std::{env, panic};
use std::io::prelude::*;
use std::io;
use std::process::{Command, Stdio};

#[unwind(aborts)]
extern "C" fn panic_in_ffi() {
panic!("Test");
}
Expand Down
1 change: 1 addition & 0 deletions src/test/run-pass/extern/extern-call-deep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

// run-pass
// ignore-wasm32-bare no libc to test ffi with
// ignore-emscripten blows the JS stack

#![feature(rustc_private)]

Expand Down