diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c698f72955320..6fa3887763cb6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -723,7 +723,7 @@ enum FallbackSuggestion { } #[derive(Copy, Clone)] -enum TypeParameters<'a> { +enum TypeParameters<'tcx, 'a> { NoTypeParameters, HasTypeParameters(// Type parameters. &'a Generics, @@ -733,13 +733,13 @@ enum TypeParameters<'a> { ParamSpace, // The kind of the rib used for type parameters. - RibKind), + RibKind<'tcx>), } // The rib kind controls the translation of local // definitions (`Def::Local`) to upvars (`Def::Upvar`). #[derive(Copy, Clone, Debug)] -enum RibKind { +enum RibKind<'a> { // No translation needs to be applied. NormalRibKind, @@ -758,6 +758,9 @@ enum RibKind { // We're in a constant item. Can't refer to dynamic stuff. ConstantItemRibKind, + + // We passed through an anonymous module. + AnonymousModuleRibKind(Module<'a>), } #[derive(Copy, Clone)] @@ -799,13 +802,13 @@ enum BareIdentifierPatternResolution { /// One local scope. #[derive(Debug)] -struct Rib { +struct Rib<'a> { bindings: HashMap, - kind: RibKind, + kind: RibKind<'a>, } -impl Rib { - fn new(kind: RibKind) -> Rib { +impl<'a> Rib<'a> { + fn new(kind: RibKind<'a>) -> Rib<'a> { Rib { bindings: HashMap::new(), kind: kind, @@ -1180,13 +1183,13 @@ pub struct Resolver<'a, 'tcx: 'a> { // The current set of local scopes, for values. // FIXME #4948: Reuse ribs to avoid allocation. - value_ribs: Vec, + value_ribs: Vec>, // The current set of local scopes, for types. - type_ribs: Vec, + type_ribs: Vec>, // The current set of local scopes, for labels. - label_ribs: Vec, + label_ribs: Vec>, // The trait that the current context can refer to. current_trait_ref: Option<(DefId, TraitRef)>, @@ -1304,6 +1307,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.arenas.modules.alloc(ModuleS::new(parent_link, def, external, is_public)) } + fn get_ribs<'b>(&'b mut self, ns: Namespace) -> &'b mut Vec> { + match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs } + } + #[inline] fn record_import_use(&mut self, import_id: NodeId, name: Name) { if !self.make_glob_map { @@ -2122,7 +2129,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn with_type_parameter_rib(&mut self, type_parameters: TypeParameters, f: F) + fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<'a, 'b>, f: F) where F: FnOnce(&mut Resolver) { match type_parameters { @@ -2191,7 +2198,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn resolve_function(&mut self, rib_kind: RibKind, declaration: &FnDecl, block: &Block) { + fn resolve_function(&mut self, rib_kind: RibKind<'a>, declaration: &FnDecl, block: &Block) { // Create a value rib for the function. self.value_ribs.push(Rib::new(rib_kind)); @@ -2494,18 +2501,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn resolve_block(&mut self, block: &Block) { debug!("(resolving block) entering block"); - self.value_ribs.push(Rib::new(NormalRibKind)); - // Move down in the graph, if there's an anonymous module rooted here. let orig_module = self.current_module; - match orig_module.anonymous_children.borrow().get(&block.id) { - None => { - // Nothing to do. - } - Some(anonymous_module) => { - debug!("(resolving block) found anonymous module, moving down"); - self.current_module = anonymous_module; - } + let anonymous_module = + orig_module.anonymous_children.borrow().get(&block.id).map(|module| *module); + + if let Some(anonymous_module) = anonymous_module { + debug!("(resolving block) found anonymous module, moving down"); + self.value_ribs.push(Rib::new(AnonymousModuleRibKind(anonymous_module))); + self.type_ribs.push(Rib::new(AnonymousModuleRibKind(anonymous_module))); + self.current_module = anonymous_module; + } else { + self.value_ribs.push(Rib::new(NormalRibKind)); } // Check for imports appearing after non-item statements. @@ -2538,6 +2545,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !self.resolved { self.current_module = orig_module; self.value_ribs.pop(); + if let Some(_) = anonymous_module { + self.type_ribs.pop(); + } } debug!("(resolving block) leaving block"); } @@ -3076,7 +3086,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Def::Local(_, node_id) => { for rib in ribs { match rib.kind { - NormalRibKind => { + NormalRibKind | AnonymousModuleRibKind(..) => { // Nothing to do. Continue. } ClosureRibKind(function_id) => { @@ -3124,7 +3134,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Def::TyParam(..) | Def::SelfTy(..) => { for rib in ribs { match rib.kind { - NormalRibKind | MethodRibKind | ClosureRibKind(..) => { + NormalRibKind | MethodRibKind | ClosureRibKind(..) | + AnonymousModuleRibKind(..) => { // Nothing to do. Continue. } ItemRibKind => { @@ -3275,13 +3286,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { namespace: Namespace) -> Option { // Check the local set of ribs. - let (name, ribs) = match namespace { - ValueNS => (ident.name, &self.value_ribs), - TypeNS => (ident.unhygienic_name, &self.type_ribs), - }; + let name = match namespace { ValueNS => ident.name, TypeNS => ident.unhygienic_name }; - for (i, rib) in ribs.iter().enumerate().rev() { - if let Some(def_like) = rib.bindings.get(&name).cloned() { + for i in (0 .. self.get_ribs(namespace).len()).rev() { + if let Some(def_like) = self.get_ribs(namespace)[i].bindings.get(&name).cloned() { match def_like { DlDef(def) => { debug!("(resolving path in local ribs) resolved `{}` to {:?} at {}", @@ -3301,6 +3309,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } + + if let AnonymousModuleRibKind(module) = self.get_ribs(namespace)[i].kind { + if let Success((target, _)) = self.resolve_name_in_module(module, + ident.unhygienic_name, + namespace, + PathSearch, + true) { + if let Some(def) = target.binding.def() { + return Some(LocalDef::from_def(def)); + } + } + } } None diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 79091fd3d6b9d..cd2d5e52462bb 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 e0f8d6f9df963..61f73b00265b8 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/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index c21bf1e6a1fa0..51013d68930ea 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 acce6ed87d00b..2249faac6d701 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 d42a777a019a3..41a6fd05c3741 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/lexical-scoping.rs b/src/test/run-pass/lexical-scoping.rs new file mode 100644 index 0000000000000..36604042d0f25 --- /dev/null +++ b/src/test/run-pass/lexical-scoping.rs @@ -0,0 +1,28 @@ +// 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. + +// Tests that items in subscopes can shadow type parameters and local variables (see issue #23880). + +#![allow(unused)] +struct Foo { x: Box } +impl Foo { + fn foo(&self) { + type Bar = i32; + let _: Bar = 42; + } +} + +fn main() { + let f = 1; + { + fn f() {} + f(); + } +} diff --git a/src/test/run-pass/no-stdio.rs b/src/test/run-pass/no-stdio.rs new file mode 100644 index 0000000000000..3658b6a508ab2 --- /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); +}