Rollup merge of #67784 - Mark-Simulacrum:residual-pad-integral, r=dtolnay

Reset Formatter flags on exit from pad_integral

This fixes a bug where after calling pad_integral with appropriate flags, the
fill and alignment flags would be set to '0' and 'Right' and left as such even
after exiting pad_integral, which meant that future calls on the same Formatter
would get incorrect flags reported.

This is quite difficult to observe in practice, as almost all formatting
implementations in practice don't call `Display::fmt` directly, but rather use
`write!` or a similar macro, which means that they cannot observe the effects of
the wrong flags (as `write!` creates a fresh Formatter instance). However, we
include a test case.

A manual check leads me to believe this is the only case where we failed to reset the flags appropriately, but I could have missed something.
This commit is contained in:
Yuki Okushi 2020-01-15 21:51:42 +09:00 committed by GitHub
commit e800fe199c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 3 deletions

View file

@ -1244,12 +1244,15 @@ impl<'a> Formatter<'a> {
// The sign and prefix goes before the padding if the fill character
// is zero
Some(min) if self.sign_aware_zero_pad() => {
self.fill = '0';
self.align = rt::v1::Alignment::Right;
let old_fill = crate::mem::replace(&mut self.fill, '0');
let old_align = crate::mem::replace(&mut self.align, rt::v1::Alignment::Right);
write_prefix(self, sign, prefix)?;
let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?;
self.buf.write_str(buf)?;
post_padding.write(self.buf)
post_padding.write(self.buf)?;
self.fill = old_fill;
self.align = old_align;
Ok(())
}
// Otherwise, the sign and prefix goes after the padding
Some(min) => {

View file

@ -28,3 +28,18 @@ fn test_estimated_capacity() {
assert_eq!(format_args!("{}, hello!", "World").estimated_capacity(), 0);
assert_eq!(format_args!("{}. 16-bytes piece", "World").estimated_capacity(), 32);
}
#[test]
fn pad_integral_resets() {
struct Bar;
impl core::fmt::Display for Bar {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
"1".fmt(f)?;
f.pad_integral(true, "", "5")?;
"1".fmt(f)
}
}
assert_eq!(format!("{:<03}", Bar), "1 0051 ");
}