Skip to content

Commit

Permalink
Make sure formatter errors are emitted by the default Write::write_fmt
Browse files Browse the repository at this point in the history
Previously, if an error was returned from the formatter that did not
originate in an underlying writer error, Write::write_fmt would return
successfully even if the formatting did not complete (was interrupted by
an `fmt::Error` return).

Now we choose to emit an io::Error with kind Other for formatter errors.

Since this may reveal error returns from `write!()` and similar that
previously passed silently, it's a kind of a [breaking-change].
  • Loading branch information
bluss committed Feb 26, 2016
1 parent 8842e28 commit 6cfafad
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
9 changes: 8 additions & 1 deletion src/libstd/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1055,7 +1055,14 @@ pub trait Write {
let mut output = Adaptor { inner: self, error: Ok(()) };
match fmt::write(&mut output, fmt) {
Ok(()) => Ok(()),
Err(..) => output.error
Err(..) => {
// check if the error came from the underlying `Write` or not
if output.error.is_err() {
output.error
} else {
Err(Error::new(ErrorKind::Other, "formatter error"))
}
}
}
}

Expand Down
54 changes: 54 additions & 0 deletions src/test/run-pass/write-fmt-errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::io::{self, Error, Write, sink};

struct ErrorDisplay;

impl fmt::Display for ErrorDisplay {
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
Err(fmt::Error)
}
}

struct ErrorWriter;

const FORMAT_ERROR: io::ErrorKind = io::ErrorKind::Other;
const WRITER_ERROR: io::ErrorKind = io::ErrorKind::NotConnected;

impl Write for ErrorWriter {
fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
Err(Error::new(WRITER_ERROR, "not connected"))
}

fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

fn main() {
// Test that the error from the formatter is propagated.
let res = write!(sink(), "{} {} {}", 1, ErrorDisplay, "bar");
assert!(res.is_err(), "formatter error did not propagate");
assert_eq!(res.unwrap_err().kind(), FORMAT_ERROR);

// Test that an underlying error is propagated
let res = write!(ErrorWriter, "abc");
assert!(res.is_err(), "writer error did not propagate");

// Writer error
let res = write!(ErrorWriter, "abc {}", ErrorDisplay);
assert!(res.is_err(), "writer error did not propagate");
assert_eq!(res.unwrap_err().kind(), WRITER_ERROR);

// Formatter error
let res = write!(ErrorWriter, "{} abc", ErrorDisplay);
assert!(res.is_err(), "formatter error did not propagate");
assert_eq!(res.unwrap_err().kind(), FORMAT_ERROR);
}

0 comments on commit 6cfafad

Please sign in to comment.