Auto merge of #102732 - RalfJung:assert_unsafe_precondition2, r=bjorn3 · rust-lang/rust@538f118 (original) (raw)

`@@ -29,6 +29,73 @@

`

29

29

`use crate::fmt;

`

30

30

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

`

31

31

``

``

32

`+

// First we define the two main entry points that all panics go through.

`

``

33

`` +

// In the end both are just convenience wrappers around panic_impl.

``

``

34

+

``

35

`+

/// The entry point for panicking with a formatted message.

`

``

36

`+

///

`

``

37

`+

/// This is designed to reduce the amount of code required at the call

`

``

38

`` +

/// site as much as possible (so that panic!() has as low an impact

``

``

39

`+

/// on (e.g.) the inlining of other functions as possible), by moving

`

``

40

`+

/// the actual formatting into this shared place.

`

``

41

`+

#[cold]

`

``

42

`+

// If panic_immediate_abort, inline the abort call,

`

``

43

`+

// otherwise avoid inlining because of it is cold path.

`

``

44

`+

#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]

`

``

45

`+

#[cfg_attr(feature = "panic_immediate_abort", inline)]

`

``

46

`+

#[track_caller]

`

``

47

`+

#[lang = "panic_fmt"] // needed for const-evaluated panics

`

``

48

`+

#[rustc_do_not_const_check] // hooked by const-eval

`

``

49

`+

#[rustc_const_unstable(feature = "core_panic", issue = "none")]

`

``

50

`+

pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {

`

``

51

`+

if cfg!(feature = "panic_immediate_abort") {

`

``

52

`+

super::intrinsics::abort()

`

``

53

`+

}

`

``

54

+

``

55

`+

// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call

`

``

56

`` +

// that gets resolved to the #[panic_handler] function.

``

``

57

`+

extern "Rust" {

`

``

58

`+

#[lang = "panic_impl"]

`

``

59

`+

fn panic_impl(pi: &PanicInfo<'_>) -> !;

`

``

60

`+

}

`

``

61

+

``

62

`+

let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);

`

``

63

+

``

64

`` +

// SAFETY: panic_impl is defined in safe Rust code and thus is safe to call.

``

``

65

`+

unsafe { panic_impl(&pi) }

`

``

66

`+

}

`

``

67

+

``

68

`+

/// Like panic_fmt, but without unwinding and track_caller to reduce the impact on codesize.

`

``

69

`` +

/// Also just works on str, as a fmt::Arguments needs more space to be passed.

``

``

70

`+

#[cold]

`

``

71

`+

#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]

`

``

72

`+

#[cfg_attr(feature = "panic_immediate_abort", inline)]

`

``

73

`+

#[cfg_attr(not(bootstrap), rustc_nounwind)]

`

``

74

`+

#[cfg_attr(bootstrap, rustc_allocator_nounwind)]

`

``

75

`+

pub fn panic_str_nounwind(msg: &'static str) -> ! {

`

``

76

`+

if cfg!(feature = "panic_immediate_abort") {

`

``

77

`+

super::intrinsics::abort()

`

``

78

`+

}

`

``

79

+

``

80

`+

// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call

`

``

81

`` +

// that gets resolved to the #[panic_handler] function.

``

``

82

`+

extern "Rust" {

`

``

83

`+

#[lang = "panic_impl"]

`

``

84

`+

fn panic_impl(pi: &PanicInfo<'_>) -> !;

`

``

85

`+

}

`

``

86

+

``

87

`` +

// PanicInfo with the can_unwind flag set to false forces an abort.

``

``

88

`+

let pieces = [msg];

`

``

89

`+

let fmt = fmt::Arguments::new_v1(&pieces, &[]);

`

``

90

`+

let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);

`

``

91

+

``

92

`` +

// SAFETY: panic_impl is defined in safe Rust code and thus is safe to call.

``

``

93

`+

unsafe { panic_impl(&pi) }

`

``

94

`+

}

`

``

95

+

``

96

`+

// Next we define a bunch of higher-level wrappers that all bottom out in the two core functions

`

``

97

`+

// above.

`

``

98

+

32

99

`` /// The underlying implementation of libcore's panic! macro when no formatting is used.

``

33

100

`#[cold]

`

34

101

`// never inline unless panic_immediate_abort to avoid code

`

`@@ -84,62 +151,17 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {

`

84

151

`panic!("index out of bounds: the len is {len} but the index is {index}")

`

85

152

`}

`

86

153

``

87

``

`-

// This function is called directly by the codegen backend, and must not have

`

88

``

`-

// any extra arguments (including those synthesized by track_caller).

`

``

154

`+

/// Panic because we cannot unwind out of a function.

`

``

155

`+

///

`

``

156

`+

/// This function is called directly by the codegen backend, and must not have

`

``

157

`+

/// any extra arguments (including those synthesized by track_caller).

`

89

158

`#[cold]

`

90

159

`#[inline(never)]

`

91

160

`#[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function

`

``

161

`+

#[cfg_attr(not(bootstrap), rustc_nounwind)]

`

``

162

`+

#[cfg_attr(bootstrap, rustc_allocator_nounwind)]

`

92

163

`fn panic_no_unwind() -> ! {

`

93

``

`-

if cfg!(feature = "panic_immediate_abort") {

`

94

``

`-

super::intrinsics::abort()

`

95

``

`-

}

`

96

``

-

97

``

`-

// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call

`

98

``

`` -

// that gets resolved to the #[panic_handler] function.

``

99

``

`-

extern "Rust" {

`

100

``

`-

#[lang = "panic_impl"]

`

101

``

`-

fn panic_impl(pi: &PanicInfo<'_>) -> !;

`

102

``

`-

}

`

103

``

-

104

``

`` -

// PanicInfo with the can_unwind flag set to false forces an abort.

``

105

``

`-

let fmt = format_args!("panic in a function that cannot unwind");

`

106

``

`-

let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);

`

107

``

-

108

``

`` -

// SAFETY: panic_impl is defined in safe Rust code and thus is safe to call.

``

109

``

`-

unsafe { panic_impl(&pi) }

`

110

``

`-

}

`

111

``

-

112

``

`-

/// The entry point for panicking with a formatted message.

`

113

``

`-

///

`

114

``

`-

/// This is designed to reduce the amount of code required at the call

`

115

``

`` -

/// site as much as possible (so that panic!() has as low an impact

``

116

``

`-

/// on (e.g.) the inlining of other functions as possible), by moving

`

117

``

`-

/// the actual formatting into this shared place.

`

118

``

`-

#[cold]

`

119

``

`-

// If panic_immediate_abort, inline the abort call,

`

120

``

`-

// otherwise avoid inlining because of it is cold path.

`

121

``

`-

#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]

`

122

``

`-

#[cfg_attr(feature = "panic_immediate_abort", inline)]

`

123

``

`-

#[track_caller]

`

124

``

`-

#[lang = "panic_fmt"] // needed for const-evaluated panics

`

125

``

`-

#[rustc_do_not_const_check] // hooked by const-eval

`

126

``

`-

#[rustc_const_unstable(feature = "core_panic", issue = "none")]

`

127

``

`-

pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {

`

128

``

`-

if cfg!(feature = "panic_immediate_abort") {

`

129

``

`-

super::intrinsics::abort()

`

130

``

`-

}

`

131

``

-

132

``

`-

// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call

`

133

``

`` -

// that gets resolved to the #[panic_handler] function.

``

134

``

`-

extern "Rust" {

`

135

``

`-

#[lang = "panic_impl"]

`

136

``

`-

fn panic_impl(pi: &PanicInfo<'_>) -> !;

`

137

``

`-

}

`

138

``

-

139

``

`-

let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);

`

140

``

-

141

``

`` -

// SAFETY: panic_impl is defined in safe Rust code and thus is safe to call.

``

142

``

`-

unsafe { panic_impl(&pi) }

`

``

164

`+

panic_str_nounwind("panic in a function that cannot unwind")

`

143

165

`}

`

144

166

``

145

167

`/// This function is used instead of panic_fmt in const eval.

`