Rollup merge of #126956 - joboet:fmt_no_extern_ty, r=RalfJung · model-checking/verify-rust-std@ae98528 (original) (raw)

`@@ -5,6 +5,7 @@

`

5

5

``

6

6

`use super::*;

`

7

7

`use crate::hint::unreachable_unchecked;

`

``

8

`+

use crate::ptr::NonNull;

`

8

9

``

9

10

`#[lang = "format_placeholder"]

`

10

11

`#[derive(Copy, Clone)]

`

`@@ -66,7 +67,13 @@ pub(super) enum Flag {

`

66

67

``

67

68

`#[derive(Copy, Clone)]

`

68

69

`enum ArgumentType<'a> {

`

69

``

`-

Placeholder { value: &'a Opaque, formatter: fn(&Opaque, &mut Formatter<'_>) -> Result },

`

``

70

`+

Placeholder {

`

``

71

`` +

// INVARIANT: formatter has type fn(&T, _) -> _ for some T, and value

``

``

72

`` +

// was derived from a &'a T.

``

``

73

`+

value: NonNull<()>,

`

``

74

`+

formatter: unsafe fn(NonNull<()>, &mut Formatter<'_>) -> Result,

`

``

75

`+

_lifetime: PhantomData<&'a ()>,

`

``

76

`+

},

`

70

77

`Count(usize),

`

71

78

`}

`

72

79

``

`@@ -90,21 +97,15 @@ pub struct Argument<'a> {

`

90

97

`impl<'a> Argument<'a> {

`

91

98

`#[inline(always)]

`

92

99

`fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> {

`

93

``

`` -

// SAFETY: mem::transmute(x) is safe because

``

94

``

`` -

// 1. &'b T keeps the lifetime it originated with 'b

``

95

``

`-

// (so as to not have an unbounded lifetime)

`

96

``

`` -

// 2. &'b T and &'b Opaque have the same memory layout

``

97

``

`` -

// (when T is Sized, as it is here)

``

98

``

`` -

// mem::transmute(f) is safe since fn(&T, &mut Formatter<'_>) -> Result

``

99

``

`` -

// and fn(&Opaque, &mut Formatter<'_>) -> Result have the same ABI

``

100

``

`` -

// (as long as T is Sized)

``

101

``

`-

unsafe {

`

102

``

`-

Argument {

`

103

``

`-

ty: ArgumentType::Placeholder {

`

104

``

`-

formatter: mem::transmute(f),

`

105

``

`-

value: mem::transmute(x),

`

106

``

`-

},

`

107

``

`-

}

`

``

100

`+

Argument {

`

``

101

`` +

// INVARIANT: this creates an ArgumentType<'b> from a &'b T and

``

``

102

`` +

// a fn(&T, ...), so the invariant is maintained.

``

``

103

`+

ty: ArgumentType::Placeholder {

`

``

104

`+

value: NonNull::from(x).cast(),

`

``

105

`+

// SAFETY: function pointers always have the same layout.

`

``

106

`+

formatter: unsafe { mem::transmute(f) },

`

``

107

`+

_lifetime: PhantomData,

`

``

108

`+

},

`

108

109

`}

`

109

110

`}

`

110

111

``

`@@ -162,7 +163,14 @@ impl<'a> Argument<'a> {

`

162

163

`#[inline(always)]

`

163

164

`pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {

`

164

165

`match self.ty {

`

165

``

`-

ArgumentType::Placeholder { formatter, value } => formatter(value, f),

`

``

166

`+

// SAFETY:

`

``

167

`` +

// Because of the invariant that if formatter had the type

``

``

168

`` +

// fn(&T, _) -> _ then value has type &'b T where 'b is

``

``

169

`` +

// the lifetime of the ArgumentType, and because references

``

``

170

`` +

// and NonNull are ABI-compatible, this is completely equivalent

``

``

171

`` +

// to calling the original function passed to new with the

``

``

172

`+

// original reference, which is sound.

`

``

173

`+

ArgumentType::Placeholder { formatter, value, .. } => unsafe { formatter(value, f) },

`

166

174

`// SAFETY: the caller promised this.

`

167

175

`ArgumentType::Count(_) => unsafe { unreachable_unchecked() },

`

168

176

`}

`

`@@ -208,7 +216,3 @@ impl UnsafeArg {

`

208

216

`Self { _private: () }

`

209

217

`}

`

210

218

`}

`

211

``

-

212

``

`-

extern "C" {

`

213

``

`-

type Opaque;

`

214

``

`-

}

`