about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/iter.rs8
-rw-r--r--src/libstd/io/stdio.rs2
-rw-r--r--src/libstd/sys/windows/process.rs11
-rw-r--r--src/libsyntax/errors/emitter.rs4
-rw-r--r--src/libsyntax/parse/parser.rs6
-rw-r--r--src/test/run-fail-fulldeps/qquote.rs2
-rw-r--r--src/test/run-pass/no-stdio.rs124
7 files changed, 147 insertions, 10 deletions
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index ddc4fb32cde..3f1c0f6a549 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -4252,13 +4252,15 @@ impl<A: Step> RangeFrom<A> {
     ///
     /// # Examples
     ///
-    /// ```ignore
-    /// for i in (0u8..).step_by(2) {
+    /// ```
+    /// # #![feature(step_by)]
+    ///
+    /// for i in (0u8..).step_by(2).take(10) {
     ///     println!("{}", i);
     /// }
     /// ```
     ///
-    /// This prints all even `u8` values.
+    /// This prints the first ten even natural integers (0 to 18).
     #[unstable(feature = "step_by", reason = "recent addition",
                issue = "27741")]
     pub fn step_by(self, by: A) -> StepBy<A, Self> {
diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs
index 79091fd3d6b..cd2d5e52462 100644
--- a/src/libstd/io/stdio.rs
+++ b/src/libstd/io/stdio.rs
@@ -112,7 +112,7 @@ impl<W: io::Write> io::Write for Maybe<W> {
 impl<R: io::Read> io::Read for Maybe<R> {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         match *self {
-            Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), buf.len()),
+            Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), 0),
             Maybe::Fake => Ok(0)
         }
     }
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs
index e0f8d6f9df9..61f73b00265 100644
--- a/src/libstd/sys/windows/process.rs
+++ b/src/libstd/sys/windows/process.rs
@@ -351,10 +351,15 @@ fn make_dirp(d: Option<&OsString>) -> (*const u16, Vec<u16>) {
 impl Stdio {
     fn to_handle(&self, stdio_id: c::DWORD) -> io::Result<Handle> {
         match *self {
+            // If no stdio handle is available, then inherit means that it
+            // should still be unavailable so propagate the
+            // INVALID_HANDLE_VALUE.
             Stdio::Inherit => {
-                stdio::get(stdio_id).and_then(|io| {
-                    io.handle().duplicate(0, true, c::DUPLICATE_SAME_ACCESS)
-                })
+                match stdio::get(stdio_id) {
+                    Ok(io) => io.handle().duplicate(0, true,
+                                                    c::DUPLICATE_SAME_ACCESS),
+                    Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)),
+                }
             }
             Stdio::Raw(handle) => {
                 RawHandle::new(handle).duplicate(0, true, c::DUPLICATE_SAME_ACCESS)
diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs
index c21bf1e6a1f..51013d68930 100644
--- a/src/libsyntax/errors/emitter.rs
+++ b/src/libsyntax/errors/emitter.rs
@@ -10,7 +10,7 @@
 
 use self::Destination::*;
 
-use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span};
+use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, DUMMY_SP, Pos, Span};
 use diagnostics;
 
 use errors::{Level, RenderSpan, DiagnosticBuilder};
@@ -109,8 +109,8 @@ impl Emitter for EmitterWriter {
             lvl: Level) {
         let error = match sp {
             Some(COMMAND_LINE_SP) => self.emit_(FileLine(COMMAND_LINE_SP), msg, code, lvl),
+            Some(DUMMY_SP) | None => print_diagnostic(&mut self.dst, "", lvl, msg, code),
             Some(sp) => self.emit_(FullSpan(sp), msg, code, lvl),
-            None => print_diagnostic(&mut self.dst, "", lvl, msg, code),
         };
 
         if let Err(e) = error {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index acce6ed87d0..2249faac6d7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2218,6 +2218,12 @@ impl<'a> Parser<'a> {
                         ex = ExprBreak(None);
                     }
                     hi = self.last_span.hi;
+                } else if self.token.is_keyword(keywords::Let) {
+                    // Catch this syntax error here, instead of in `check_strict_keywords`, so
+                    // that we can explicitly mention that let is not to be used as an expression
+                    let mut db = self.fatal("expected expression, found statement (`let`)");
+                    db.note("variable declaration using `let` is a statement");
+                    return Err(db);
                 } else if self.check(&token::ModSep) ||
                         self.token.is_ident() &&
                         !self.check_keyword(keywords::True) &&
diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs
index d42a777a019..41a6fd05c37 100644
--- a/src/test/run-fail-fulldeps/qquote.rs
+++ b/src/test/run-fail-fulldeps/qquote.rs
@@ -10,7 +10,7 @@
 
 // ignore-cross-compile
 
-// error-pattern:expected identifier, found keyword `let`
+// error-pattern:expected expression, found statement (`let`)
 
 #![feature(quote, rustc_private)]
 
diff --git a/src/test/run-pass/no-stdio.rs b/src/test/run-pass/no-stdio.rs
new file mode 100644
index 00000000000..3658b6a508a
--- /dev/null
+++ b/src/test/run-pass/no-stdio.rs
@@ -0,0 +1,124 @@
+// 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.
+
+#![feature(libc)]
+
+extern crate libc;
+
+use std::process::{Command, Stdio};
+use std::env;
+use std::io::{self, Read, Write};
+
+#[cfg(unix)]
+unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
+    let doit = |a| {
+        let r = libc::dup(a);
+        assert!(r >= 0);
+        return r
+    };
+    let a = doit(0);
+    let b = doit(1);
+    let c = doit(2);
+
+    assert!(libc::close(0) >= 0);
+    assert!(libc::close(1) >= 0);
+    assert!(libc::close(2) >= 0);
+
+    let r = f();
+
+    assert!(libc::dup2(a, 0) >= 0);
+    assert!(libc::dup2(b, 1) >= 0);
+    assert!(libc::dup2(c, 2) >= 0);
+
+    return r
+}
+
+#[cfg(windows)]
+unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
+    type DWORD = u32;
+    type HANDLE = *mut u8;
+    type BOOL = i32;
+
+    const STD_INPUT_HANDLE: DWORD = -10i32 as DWORD;
+    const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
+    const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
+    const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
+
+    extern "system" {
+        fn GetStdHandle(which: DWORD) -> HANDLE;
+        fn SetStdHandle(which: DWORD, handle: HANDLE) -> BOOL;
+    }
+
+    let doit = |id| {
+        let handle = GetStdHandle(id);
+        assert!(handle != INVALID_HANDLE_VALUE);
+        assert!(SetStdHandle(id, INVALID_HANDLE_VALUE) != 0);
+        return handle
+    };
+
+    let a = doit(STD_INPUT_HANDLE);
+    let b = doit(STD_OUTPUT_HANDLE);
+    let c = doit(STD_ERROR_HANDLE);
+
+    let r = f();
+
+    let doit = |id, handle| {
+        assert!(SetStdHandle(id, handle) != 0);
+    };
+    doit(STD_INPUT_HANDLE, a);
+    doit(STD_OUTPUT_HANDLE, b);
+    doit(STD_ERROR_HANDLE, c);
+
+    return r
+}
+
+fn main() {
+    if env::args().len() > 1 {
+        println!("test");
+        assert!(io::stdout().write(b"test\n").is_ok());
+        assert!(io::stderr().write(b"test\n").is_ok());
+        assert_eq!(io::stdin().read(&mut [0; 10]).unwrap(), 0);
+        return
+    }
+
+    // First, make sure reads/writes without stdio work if stdio itself is
+    // missing.
+    let (a, b, c) = unsafe {
+        without_stdio(|| {
+            let a = io::stdout().write(b"test\n");
+            let b = io::stderr().write(b"test\n");
+            let c = io::stdin().read(&mut [0; 10]);
+
+            (a, b, c)
+        })
+    };
+
+    assert_eq!(a.unwrap(), 5);
+    assert_eq!(b.unwrap(), 5);
+    assert_eq!(c.unwrap(), 0);
+
+    // Second, spawn a child and do some work with "null" descriptors to make
+    // sure it's ok
+    let me = env::current_exe().unwrap();
+    let status = Command::new(&me)
+                        .arg("next")
+                        .stdin(Stdio::null())
+                        .stdout(Stdio::null())
+                        .stderr(Stdio::null())
+                        .status().unwrap();
+    assert!(status.success(), "{:?} isn't a success", status);
+
+    // Finally, close everything then spawn a child to make sure everything is
+    // *still* ok.
+    let status = unsafe {
+        without_stdio(|| Command::new(&me).arg("next").status())
+    }.unwrap();
+    assert!(status.success(), "{:?} isn't a success", status);
+}