1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! Panic support for libcore
//!
//! The core library cannot define panicking, but it does *declare* panicking. This
//! means that the functions inside of libcore are allowed to panic, but to be
//! useful an upstream crate must define panicking for libcore to use. The current
//! interface for panicking is:
//!
//! ```
//! # use std::fmt;
//! fn panic_impl(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> !
//! # { loop {} }
//! ```
//!
//! This definition allows for panicking with any general message, but it does not
//! allow for failing with a `Box<Any>` value. The reason for this is that libcore
//! is not allowed to allocate.
//!
//! This module contains a few other panicking functions, but these are just the
//! necessary lang items for the compiler. All panics are funneled through this
//! one function. Currently, the actual symbol is declared in the standard
//! library, but the location of this may change over time.

#![allow(dead_code, missing_docs)]
#![unstable(feature = "core_panic",
            reason = "internal details of the implementation of the `panic!` \
                      and related macros",
            issue = "0")]

use crate::fmt;
use crate::panic::{Location, PanicInfo};

#[cfg(bootstrap)]
#[cold]
// never inline unless panic_immediate_abort to avoid code
// bloat at the call sites as much as possible
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[lang = "panic"]
pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        unsafe { super::intrinsics::abort() }
    }

    // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
    // reduce size overhead. The format_args! macro uses str's Display trait to
    // write expr, which calls Formatter::pad, which must accommodate string
    // truncation and padding (even though none is used here). Using
    // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
    // output binary, saving up to a few kilobytes.
    let (expr, file, line, col) = *expr_file_line_col;
    panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col))
}

#[cfg(not(bootstrap))]
#[cold]
// never inline unless panic_immediate_abort to avoid code
// bloat at the call sites as much as possible
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[lang = "panic"]
pub fn panic(expr: &str, location: &Location<'_>) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        unsafe { super::intrinsics::abort() }
    }

    // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
    // reduce size overhead. The format_args! macro uses str's Display trait to
    // write expr, which calls Formatter::pad, which must accommodate string
    // truncation and padding (even though none is used here). Using
    // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
    // output binary, saving up to a few kilobytes.
    panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), location)
}

#[cfg(bootstrap)]
#[cold]
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[lang = "panic_bounds_check"]
fn panic_bounds_check(file_line_col: &(&'static str, u32, u32),
                     index: usize, len: usize) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        unsafe { super::intrinsics::abort() }
    }

    panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}",
                           len, index), file_line_col)
}

#[cfg(not(bootstrap))]
#[cold]
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[lang = "panic_bounds_check"]
fn panic_bounds_check(location: &Location<'_>, index: usize, len: usize) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        unsafe { super::intrinsics::abort() }
    }

    panic_fmt(
        format_args!("index out of bounds: the len is {} but the index is {}", len, index),
        location
    )
}

#[cfg(bootstrap)]
#[cold]
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[cfg_attr(    feature="panic_immediate_abort" ,inline)]
pub fn panic_fmt(fmt: fmt::Arguments<'_>, file_line_col: &(&'static str, u32, u32)) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        unsafe { super::intrinsics::abort() }
    }

    // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
    extern "Rust" {
        #[lang = "panic_impl"]
        fn panic_impl(pi: &PanicInfo<'_>) -> !;
    }

    let (file, line, col) = *file_line_col;
    let location = Location::internal_constructor(file, line, col);
    let pi = PanicInfo::internal_constructor(Some(&fmt), &location);
    unsafe { panic_impl(&pi) }
}

#[cfg(not(bootstrap))]
#[cold]
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[cfg_attr(    feature="panic_immediate_abort" ,inline)]
pub fn panic_fmt(fmt: fmt::Arguments<'_>, location: &Location<'_>) -> ! {
    if cfg!(feature = "panic_immediate_abort") {
        unsafe { super::intrinsics::abort() }
    }

    // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
    extern "Rust" {
        #[lang = "panic_impl"]
        fn panic_impl(pi: &PanicInfo<'_>) -> !;
    }

    let pi = PanicInfo::internal_constructor(Some(&fmt), location);
    unsafe { panic_impl(&pi) }
}