@@ -15,14 +15,15 @@ use rustc::hir::{CodegenFnAttrFlags, CodegenFnAttrs};
1515use rustc:: hir:: def_id:: { DefId , LOCAL_CRATE } ;
1616use rustc:: session:: Session ;
1717use rustc:: session:: config:: Sanitizer ;
18- use rustc:: ty:: TyCtxt ;
18+ use rustc:: ty:: { self , TyCtxt , PolyFnSig } ;
1919use rustc:: ty:: layout:: HasTyCtxt ;
2020use rustc:: ty:: query:: Providers ;
2121use rustc_data_structures:: sync:: Lrc ;
2222use rustc_data_structures:: fx:: FxHashMap ;
2323use rustc_target:: spec:: PanicStrategy ;
2424use rustc_codegen_ssa:: traits:: * ;
2525
26+ use abi:: Abi ;
2627use attributes;
2728use llvm:: { self , Attribute } ;
2829use llvm:: AttributePlace :: Function ;
@@ -60,7 +61,7 @@ pub fn emit_uwtable(val: &'ll Value, emit: bool) {
6061
6162/// Tell LLVM whether the function can or cannot unwind.
6263#[ inline]
63- pub fn unwind ( val : & ' ll Value , can_unwind : bool ) {
64+ fn unwind ( val : & ' ll Value , can_unwind : bool ) {
6465 Attribute :: NoUnwind . toggle_llfn ( Function , val, !can_unwind) ;
6566}
6667
@@ -150,9 +151,10 @@ pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) {
150151/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
151152/// attributes.
152153pub fn from_fn_attrs (
153- cx : & CodegenCx < ' ll , ' _ > ,
154+ cx : & CodegenCx < ' ll , ' tcx > ,
154155 llfn : & ' ll Value ,
155156 id : Option < DefId > ,
157+ sig : PolyFnSig < ' tcx > ,
156158) {
157159 let codegen_fn_attrs = id. map ( |id| cx. tcx . codegen_fn_attrs ( id) )
158160 . unwrap_or_else ( || CodegenFnAttrs :: new ( ) ) ;
@@ -194,28 +196,37 @@ pub fn from_fn_attrs(
194196 llvm:: AttributePlace :: ReturnValue , llfn) ;
195197 }
196198
197- let can_unwind = if codegen_fn_attrs. flags . contains ( CodegenFnAttrFlags :: UNWIND ) {
198- Some ( true )
199+ unwind ( llfn, if cx. tcx . sess . panic_strategy ( ) != PanicStrategy :: Unwind {
200+ // In panic=abort mode we assume nothing can unwind anywhere, so
201+ // optimize based on this!
202+ false
203+ } else if codegen_fn_attrs. flags . contains ( CodegenFnAttrFlags :: UNWIND ) {
204+ // If a specific #[unwind] attribute is present, use that
205+ true
199206 } else if codegen_fn_attrs. flags . contains ( CodegenFnAttrFlags :: RUSTC_ALLOCATOR_NOUNWIND ) {
200- Some ( false )
201-
202- // Perhaps questionable, but we assume that anything defined
203- // *in Rust code* may unwind. Foreign items like `extern "C" {
204- // fn foo(); }` are assumed not to unwind **unless** they have
205- // a `#[unwind]` attribute.
206- } else if id. map ( |id| !cx. tcx . is_foreign_item ( id) ) . unwrap_or ( false ) {
207- Some ( true )
208- } else {
209- None
210- } ;
211-
212- match can_unwind {
213- Some ( false ) => attributes:: unwind ( llfn, false ) ,
214- Some ( true ) if cx. tcx . sess . panic_strategy ( ) == PanicStrategy :: Unwind => {
215- attributes:: unwind ( llfn, true ) ;
207+ // Special attribute for allocator functions, which can't unwind
208+ false
209+ } else if let Some ( id) = id {
210+ let sig = cx. tcx . normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , & sig) ;
211+ if cx. tcx . is_foreign_item ( id) {
212+ // Foreign items like `extern "C" { fn foo(); }` are assumed not to
213+ // unwind
214+ false
215+ } else if sig. abi != Abi :: Rust && sig. abi != Abi :: RustCall {
216+ // Any items defined in Rust that *don't* have the `extern` ABI are
217+ // defined to not unwind. We insert shims to abort if an unwind
218+ // happens to enforce this.
219+ false
220+ } else {
221+ // Anything else defined in Rust is assumed that it can possibly
222+ // unwind
223+ true
216224 }
217- Some ( true ) | None => { }
218- }
225+ } else {
226+ // assume this can possibly unwind, avoiding the application of a
227+ // `nounwind` attribute below.
228+ true
229+ } ) ;
219230
220231 // Always annotate functions with the target-cpu they are compiled for.
221232 // Without this, ThinLTO won't inline Rust functions into Clang generated
0 commit comments