-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Miscellaneous cleanup to formatting #69209
Changes from all commits
bd12cd3
6c45e45
34ef8f5
f6bfdc9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -238,16 +238,8 @@ pub struct Formatter<'a> { | |
// NB. Argument is essentially an optimized partially applied formatting function, | ||
// equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. | ||
|
||
struct Void { | ||
_priv: (), | ||
/// Erases all oibits, because `Void` erases the type of the object that | ||
/// will be used to produce formatted output. Since we do not know what | ||
/// oibits the real types have (and they can have any or none), we need to | ||
/// take the most conservative approach and forbid all oibits. | ||
/// | ||
/// It was added after #45197 showed that one could share a `!Sync` | ||
/// object across threads by passing it into `format_args!`. | ||
_oibit_remover: PhantomData<*mut dyn Fn()>, | ||
extern "C" { | ||
type Opaque; | ||
} | ||
|
||
/// This struct represents the generic "argument" which is taken by the Xprintf | ||
|
@@ -259,16 +251,23 @@ struct Void { | |
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] | ||
#[doc(hidden)] | ||
pub struct ArgumentV1<'a> { | ||
value: &'a Void, | ||
formatter: fn(&Void, &mut Formatter<'_>) -> Result, | ||
value: &'a Opaque, | ||
formatter: fn(&Opaque, &mut Formatter<'_>) -> Result, | ||
} | ||
|
||
impl<'a> ArgumentV1<'a> { | ||
#[inline(never)] | ||
fn show_usize(x: &usize, f: &mut Formatter<'_>) -> Result { | ||
Display::fmt(x, f) | ||
} | ||
// This gurantees a single stable value for the function pointer associated with | ||
// indices/counts in the formatting infrastructure. | ||
// | ||
// Note that a function defined as such would not be correct as functions are | ||
// always tagged unnamed_addr with the current lowering to LLVM IR, so their | ||
// address is not considered important to LLVM and as such the as_usize cast | ||
// could have been miscompiled. In practice, we never call as_usize on non-usize | ||
// containing data (as a matter of static generation of the formatting | ||
// arguments), so this is merely an additional check. | ||
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] | ||
static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |_, _| loop {}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cc @eddyb -- am I correct that this reasoning is correct / this should work? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see how it's much more different from the previous approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my reading of your comment in a different issue, my understanding is that the non-determinism is strictly in the casting from a function (or closure) to the function pointer. But even if the closure here is unnamed_addr, the function pointer produced is guaranteed to be stable. I guess what we don't guarantee is that this closure did not get merged with a different function. But that's fine, we don't technically need to -- anywhere that this could have gotten merged, would have to be associated with a usize in the "value" part of Argument, right? So the safety property would still hold. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I see what the argument is. Indeed, we shouldn't introduce non-determinism and The funny thing though is that because you used There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The signature not mattering is an interesting point. There's probably no way to prevent that collapsing, though, right? We could plausibly do something weird (e.g., print the address of the passed references shifted to the right or something) and just say "no one else will do this", I guess. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you should at least load an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will try to do this in a follow-up PR to avoid getting this bogged down (and r? you on that one). |
||
|
||
impl<'a> ArgumentV1<'a> { | ||
#[doc(hidden)] | ||
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] | ||
pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> { | ||
|
@@ -278,11 +277,13 @@ impl<'a> ArgumentV1<'a> { | |
#[doc(hidden)] | ||
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] | ||
pub fn from_usize(x: &usize) -> ArgumentV1<'_> { | ||
ArgumentV1::new(x, ArgumentV1::show_usize) | ||
ArgumentV1::new(x, USIZE_MARKER) | ||
} | ||
|
||
fn as_usize(&self) -> Option<usize> { | ||
if self.formatter as usize == ArgumentV1::show_usize as usize { | ||
if self.formatter as usize == USIZE_MARKER as usize { | ||
// SAFETY: The `formatter` field is only set to USIZE_MARKER if | ||
// the value is a usize, so this is safe | ||
Some(unsafe { *(self.value as *const _ as *const usize) }) | ||
} else { | ||
None | ||
|
@@ -1356,11 +1357,11 @@ impl<'a> Formatter<'a> { | |
let mut align = old_align; | ||
if self.sign_aware_zero_pad() { | ||
// a sign always goes first | ||
let sign = unsafe { str::from_utf8_unchecked(formatted.sign) }; | ||
let sign = formatted.sign; | ||
self.buf.write_str(sign)?; | ||
|
||
// remove the sign from the formatted parts | ||
formatted.sign = b""; | ||
formatted.sign = ""; | ||
width = width.saturating_sub(sign.len()); | ||
align = rt::v1::Alignment::Right; | ||
self.fill = '0'; | ||
|
@@ -1392,7 +1393,7 @@ impl<'a> Formatter<'a> { | |
} | ||
|
||
if !formatted.sign.is_empty() { | ||
write_bytes(self.buf, formatted.sign)?; | ||
self.buf.write_str(formatted.sign)?; | ||
} | ||
for part in formatted.parts { | ||
match *part { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's funny is that we merged the PR that adds doc comments with it still using
Void
(@anyska went to renameVoid
->Opaque
and found it just in comments, PR coming soon).AlsoEDIT: ah no,"C"
is redundant, I just realized that now.rustfmt
adds it.