about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev@gmail.com>2020-01-15 21:51:42 +0900
committerGitHub <noreply@github.com>2020-01-15 21:51:42 +0900
commite800fe199cbfbbaa46dfa519e46b594512c068be (patch)
tree0b15d5a0f1ff7fa3c14d9179462362562735ec66 /src/libcore
parent632387f38dfbac0f2b8b8900c840fff7f1fb888e (diff)
parent73996df6291001f0742b6409249329301aa77a23 (diff)
downloadrust-e800fe199cbfbbaa46dfa519e46b594512c068be.tar.gz
rust-e800fe199cbfbbaa46dfa519e46b594512c068be.zip
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.
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/fmt/mod.rs9
-rw-r--r--src/libcore/tests/fmt/mod.rs15
2 files changed, 21 insertions, 3 deletions
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 6c8d1626b09..e68f3c58a3e 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -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) => {
diff --git a/src/libcore/tests/fmt/mod.rs b/src/libcore/tests/fmt/mod.rs
index d86e21cf40b..7b281ce48e6 100644
--- a/src/libcore/tests/fmt/mod.rs
+++ b/src/libcore/tests/fmt/mod.rs
@@ -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  ");
+}