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
``
`-
}
`