From 082c03b0780b2de24b68be04e96d1596a7c5b3cf Mon Sep 17 00:00:00 2001 From: Daan Sprenkels Date: Wed, 6 Jan 2016 23:58:45 +0100 Subject: [PATCH 1/8] libsyntax: note that `let a = (let b = something)` is invalid in parse_bottom_expr (parser.rs) --- src/libsyntax/parse/parser.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bfa42e761294..edb1f7eb926c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2199,6 +2199,12 @@ impl<'a> Parser<'a> { UnsafeBlock(ast::UserProvided), attrs); } + if self.eat_keyword(keywords::Let) { + return Err(self.span_fatal(self.span, + "`let` is not an expression, so it cannot \ + be used in this way")) + + } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = try!(self.parse_expr()); From 79f2cff44ec62cf42f6c97d28dc4286de683b1e5 Mon Sep 17 00:00:00 2001 From: Daan Sprenkels Date: Fri, 8 Jan 2016 00:01:59 +0100 Subject: [PATCH 2/8] libsyntax: move check for keyword Let to a more logical spot --- src/libsyntax/parse/parser.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index edb1f7eb926c..f3809455fe0f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2134,6 +2134,12 @@ impl<'a> Parser<'a> { } hi = self.last_span.hi; } + _ 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 msg = "`let` is not an expression, so it cannot be used in this way"; + return Err(self.diagnostic().struct_span_err(self.span, &msg)); + }, _ => { if self.eat_lt() { let (qself, path) = @@ -2199,12 +2205,6 @@ impl<'a> Parser<'a> { UnsafeBlock(ast::UserProvided), attrs); } - if self.eat_keyword(keywords::Let) { - return Err(self.span_fatal(self.span, - "`let` is not an expression, so it cannot \ - be used in this way")) - - } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = try!(self.parse_expr()); From 2b1e2732930830fc295d26bfb4bb29931e7e84ac Mon Sep 17 00:00:00 2001 From: Daan Sprenkels Date: Thu, 14 Jan 2016 16:04:35 +0100 Subject: [PATCH 3/8] Update qquote.rs test case and make unexpected `let` error fatal --- src/libsyntax/parse/parser.rs | 12 ++++++------ src/test/run-fail-fulldeps/qquote.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f3809455fe0f..c071670ea6e2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2134,12 +2134,6 @@ impl<'a> Parser<'a> { } hi = self.last_span.hi; } - _ 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 msg = "`let` is not an expression, so it cannot be used in this way"; - return Err(self.diagnostic().struct_span_err(self.span, &msg)); - }, _ => { if self.eat_lt() { let (qself, path) = @@ -2162,6 +2156,12 @@ impl<'a> Parser<'a> { let lo = self.last_span.lo; return self.parse_while_expr(None, lo, attrs); } + 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 msg = "`let` is not an expression, so it cannot be used in this way"; + self.span_err(self.span, msg); + } if self.token.is_lifetime() { let lifetime = self.get_lifetime(); let lo = self.span.lo; diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index d42a777a019a..297a1da25b5d 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:`let` is not an expression, so it cannot be used in this way #![feature(quote, rustc_private)] From 1745153eaeeb0793876b36422bda6764483ceefb Mon Sep 17 00:00:00 2001 From: Daan Sprenkels Date: Thu, 14 Jan 2016 16:52:24 +0100 Subject: [PATCH 4/8] do not additionally note about unexpected identifier after unexpected let error, by moving unexpected let check into the proper if-else clause --- src/libsyntax/parse/parser.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c071670ea6e2..daa13885e0d1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2156,12 +2156,6 @@ impl<'a> Parser<'a> { let lo = self.last_span.lo; return self.parse_while_expr(None, lo, attrs); } - 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 msg = "`let` is not an expression, so it cannot be used in this way"; - self.span_err(self.span, msg); - } if self.token.is_lifetime() { let lifetime = self.get_lifetime(); let lo = self.span.lo; @@ -2224,6 +2218,11 @@ 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 msg = "`let` is not an expression, so it cannot be used in this way"; + return Err(self.fatal(&msg)); } else if self.check(&token::ModSep) || self.token.is_ident() && !self.check_keyword(keywords::True) && From fee457d3af355f24ef321ea7250e968638f403c8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 24 Jan 2016 21:14:56 -0800 Subject: [PATCH 5/8] std: Fix some behavior without stdio handles On all platforms, reading from stdin where the actual stdin isn't present should return 0 bytes as having been read rather than the entire buffer. On Windows, handle the case where we're inheriting stdio handles but one of them isn't present. Currently the behavior is to fail returning an I/O error but instead this commit corrects it to detecting this situation and propagating the non-set handle. Closes #31167 --- src/libstd/io/stdio.rs | 2 +- src/libstd/sys/windows/process.rs | 11 ++- src/test/run-pass/no-stdio.rs | 124 ++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/no-stdio.rs diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 79091fd3d6b9..cd2d5e52462b 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -112,7 +112,7 @@ impl io::Write for Maybe { impl io::Read for Maybe { fn read(&mut self, buf: &mut [u8]) -> io::Result { 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 e0f8d6f9df96..61f73b00265b 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) { impl Stdio { fn to_handle(&self, stdio_id: c::DWORD) -> io::Result { 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/test/run-pass/no-stdio.rs b/src/test/run-pass/no-stdio.rs new file mode 100644 index 000000000000..3658b6a508ab --- /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 or the MIT license +// , 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: 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: 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); +} From d829019ff4874e2a4f1b6780c442dfa524e75d38 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 26 Jan 2016 13:49:21 +0530 Subject: [PATCH 6/8] Make emitter handle DUMMY_SP correctly --- src/libsyntax/errors/emitter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index c21bf1e6a1fa..51013d68930e 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 { From 065e47eb3b23a9bd3074d3406157f0aafc575150 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 26 Jan 2016 13:53:28 +0530 Subject: [PATCH 7/8] Improve error message for let-in-expr-position --- src/libsyntax/parse/parser.rs | 5 +++-- src/test/run-fail-fulldeps/qquote.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index daa13885e0d1..4ee3ce63a8d0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2221,8 +2221,9 @@ impl<'a> Parser<'a> { } 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 msg = "`let` is not an expression, so it cannot be used in this way"; - return Err(self.fatal(&msg)); + 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 297a1da25b5d..41a6fd05c374 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:`let` is not an expression, so it cannot be used in this way +// error-pattern:expected expression, found statement (`let`) #![feature(quote, rustc_private)] From 70d4f263ba3d1db40f246ebe600992abb1ac85be Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 25 Jan 2016 00:56:34 +0100 Subject: [PATCH 8/8] RangeFrom::step_by docs: fix example The previous example did not do what its description said. In it panicked on integer overflow in debug mode, and went into an infinite loop in release mode (wrapping back to 0 after printing 254). --- src/libcore/iter.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index ddc4fb32cde4..3f1c0f6a5492 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -4252,13 +4252,15 @@ impl RangeFrom { /// /// # 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 {