diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7a4b38d1b4249..2b3609e28a6a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,5 +47,14 @@ example, if it's 2014, and you change a Rust file that was created in // Copyright 2010-2014 The Rust Project Developers. ``` +# Coordination and communication + +Get feedback from other developers on +[discuss.rust-lang.org][discuss], and +[#rust-internals][pound-rust-internals]. + +[pound-rust-internals]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals +[discuss]: http://discuss.rust-lang.org + For more details, please refer to [Note-development-policy](https://github.com/rust-lang/rust/wiki/Note-development-policy). diff --git a/src/doc/guide.md b/src/doc/guide.md index 55465651cfb4b..838d54f81c455 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -101,7 +101,7 @@ you can access through [Mibbit](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust). Click that link, and you'll be chatting with other Rustaceans (a silly nickname we call ourselves), and we can help you out. Other great resources include [our -mailing list](https://mail.mozilla.org/listinfo/rust-dev), [the /r/rust +forum](http://discuss.rust-lang.org/), [the /r/rust subreddit](http://www.reddit.com/r/rust), and [Stack Overflow](http://stackoverflow.com/questions/tagged/rust). diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index 9e663eb0317ef..5588152a244c4 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -157,8 +157,8 @@ syn region rustString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=rustE syn region rustString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=rustEscape,rustEscapeUnicode,rustEscapeError,rustStringContinuation,@Spell syn region rustString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell -syn region rustAttribute start="#!\?\[" end="\]" contains=rustString,rustDeriving -syn region rustDeriving start="deriving(" end=")" contained contains=rustTrait +syn region rustAttribute start="#!\?\[" end="\]" contains=rustString,rustDerive +syn region rustDerive start="derive(" end=")" contained contains=rustTrait " Number literals syn match rustDecNumber display "\<[0-9][0-9_]*\%([iu]\%(8\|16\|32\|64\)\=\)\=" @@ -263,7 +263,7 @@ hi def link rustMacro Macro hi def link rustType Type hi def link rustTodo Todo hi def link rustAttribute PreProc -hi def link rustDeriving PreProc +hi def link rustDerive PreProc hi def link rustStorage StorageClass hi def link rustObsoleteStorage Error hi def link rustLifetime Special @@ -275,7 +275,7 @@ hi def link rustBoxPlacementExpr rustKeyword " Other Suggestions: " hi rustAttribute ctermfg=cyan -" hi rustDeriving ctermfg=cyan +" hi rustDerive ctermfg=cyan " hi rustAssert ctermfg=yellow " hi rustPanic ctermfg=red " hi rustMacro ctermfg=magenta diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 59106aa97772a..fb355e3918b92 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -600,11 +600,9 @@ mod tests { use std::ops::Drop; use std::option::Option; use std::option::Option::{Some, None}; - use std::str::Str; use std::sync::atomic; use std::sync::atomic::Ordering::{Acquire, SeqCst}; use std::task; - use std::kinds::Send; use std::vec::Vec; use super::{Arc, Weak, weak_count, strong_count}; use std::sync::Mutex; diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index a5b8c5f3e5718..37a51d9968211 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -1876,14 +1876,9 @@ impl<'a> Iterator for SymmetricDifference<'a> { #[cfg(test)] mod tests { use prelude::*; - use core::iter::range_step; use core::u32; - use std::rand; - use std::rand::Rng; - use test::{Bencher, black_box}; - use super::{Bitv, BitvSet, from_fn, from_bytes}; - use bitv; + use super::{Bitv, from_fn, from_bytes}; #[test] fn test_to_str() { diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index e4c9e51a8455b..3d89f59560514 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -1418,7 +1418,6 @@ mod tests { use self::Taggy::*; use self::Taggypar::*; use prelude::*; - use core::cmp; use core::iter; use std::fmt::Show; use std::hash; diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index b931809e6036e..1a7fcff4eedcc 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -10,7 +10,7 @@ // // ignore-lexer-test FIXME #15679 -use core::char::{escape_unicode, escape_default}; +use core::char::escape_default; #[test] fn test_is_lowercase() { diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 82e91c5b7120a..87058c43084f0 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -13,7 +13,6 @@ use core::fmt::Show; use core::num::{NumCast, cast}; use core::ops::{Add, Sub, Mul, Div, Rem}; use core::kinds::Copy; -use std::str::from_str; mod int_macros; mod i8; diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 01e55fb2edd9a..ec61266591563 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -168,10 +168,10 @@ //! dot::Id::new(format!("N{}", n)).unwrap() //! } //! fn node_label<'b>(&'b self, n: &Nd) -> dot::LabelText<'b> { -//! dot::LabelStr(self.nodes[*n].as_slice().into_cow()) +//! dot::LabelText::LabelStr(self.nodes[*n].as_slice().into_cow()) //! } //! fn edge_label<'b>(&'b self, _: &Ed) -> dot::LabelText<'b> { -//! dot::LabelStr("⊆".into_cow()) +//! dot::LabelText::LabelStr("⊆".into_cow()) //! } //! } //! @@ -225,10 +225,10 @@ //! } //! fn node_label<'b>(&'b self, n: &Nd<'b>) -> dot::LabelText<'b> { //! let &(i, _) = n; -//! dot::LabelStr(self.nodes[i].as_slice().into_cow()) +//! dot::LabelText::LabelStr(self.nodes[i].as_slice().into_cow()) //! } //! fn edge_label<'b>(&'b self, _: &Ed<'b>) -> dot::LabelText<'b> { -//! dot::LabelStr("⊆".into_cow()) +//! dot::LabelText::LabelStr("⊆".into_cow()) //! } //! } //! @@ -274,7 +274,7 @@ #![feature(globs, slicing_syntax)] #![feature(unboxed_closures)] -pub use self::LabelText::*; +use self::LabelText::*; use std::borrow::IntoCow; use std::io; @@ -586,10 +586,9 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N #[cfg(test)] mod tests { use self::NodeLabels::*; - use super::{Id, LabelText, LabelStr, EscStr, Labeller}; - use super::{Nodes, Edges, GraphWalk, render}; + use super::{Id, Labeller, Nodes, Edges, GraphWalk, render}; + use super::LabelText::{mod, LabelStr, EscStr}; use std::io::IoResult; - use std::str; use std::borrow::IntoCow; /// each node is an index in a vector in the graph. diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 4ee5b2d5e8349..7642c866d6081 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -177,7 +177,7 @@ use std::mem; use std::os; use std::rt; use std::slice; -use std::sync::{Once, ONCE_INIT}; +use std::sync::{Once, ONCE_INIT, StaticMutex, MUTEX_INIT}; use regex::Regex; @@ -193,6 +193,8 @@ pub const MAX_LOG_LEVEL: u32 = 255; /// The default logging level of a crate if no other is specified. const DEFAULT_LOG_LEVEL: u32 = 1; +static LOCK: StaticMutex = MUTEX_INIT; + /// An unsafe constant that is the maximum logging level of any module /// specified. This is the first line of defense to determining whether a /// logging statement should be run. @@ -279,9 +281,18 @@ impl Drop for DefaultLogger { pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { // Test the literal string from args against the current filter, if there // is one. - match unsafe { FILTER.as_ref() } { - Some(filter) if !filter.is_match(args.to_string()[]) => return, - _ => {} + unsafe { + let _g = LOCK.lock(); + match FILTER as uint { + 0 => {} + 1 => panic!("cannot log after main thread has exited"), + n => { + let filter = mem::transmute::<_, &Regex>(n); + if !filter.is_match(args.to_string().as_slice()) { + return + } + } + } } // Completely remove the local logger from TLS in case anyone attempts to @@ -363,9 +374,15 @@ pub fn mod_enabled(level: u32, module: &str) -> bool { // This assertion should never get tripped unless we're in an at_exit // handler after logging has been torn down and a logging attempt was made. - assert!(unsafe { !DIRECTIVES.is_null() }); - enabled(level, module, unsafe { (*DIRECTIVES).iter() }) + let _g = LOCK.lock(); + unsafe { + assert!(DIRECTIVES as uint != 0); + assert!(DIRECTIVES as uint != 1, + "cannot log after the main thread has exited"); + + enabled(level, module, (*DIRECTIVES).iter()) + } } fn enabled(level: u32, @@ -421,14 +438,15 @@ fn init() { // Schedule the cleanup for the globals for when the runtime exits. rt::at_exit(move |:| { + let _g = LOCK.lock(); assert!(!DIRECTIVES.is_null()); let _directives: Box> = mem::transmute(DIRECTIVES); - DIRECTIVES = 0 as *const Vec; + DIRECTIVES = 1 as *const Vec; if !FILTER.is_null() { let _filter: Box = mem::transmute(FILTER); - FILTER = 0 as *const _; + FILTER = 1 as *const _; } }); } diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 92aa70548c82b..0063b2a514e02 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -509,7 +509,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { let method_call = ty::MethodCall::expr(call_expr.id); let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().get(&method_call) { Some(method) => method.ty, - None => ty::expr_ty(self.tcx, func_or_rcvr) + None => ty::expr_ty_adjusted(self.tcx, func_or_rcvr) }); let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs index 06fef66c1e003..8a2ecbca20d55 100644 --- a/src/librustc/middle/cfg/graphviz.rs +++ b/src/librustc/middle/cfg/graphviz.rs @@ -60,16 +60,16 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> { fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> { if i == self.cfg.entry { - dot::LabelStr("entry".into_cow()) + dot::LabelText::LabelStr("entry".into_cow()) } else if i == self.cfg.exit { - dot::LabelStr("exit".into_cow()) + dot::LabelText::LabelStr("exit".into_cow()) } else if n.data.id == ast::DUMMY_NODE_ID { - dot::LabelStr("(dummy_node)".into_cow()) + dot::LabelText::LabelStr("(dummy_node)".into_cow()) } else { let s = self.ast_map.node_to_string(n.data.id); // left-aligns the lines let s = replace_newline_with_backslash_l(s); - dot::EscStr(s.into_cow()) + dot::LabelText::EscStr(s.into_cow()) } } @@ -87,7 +87,7 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> { let s = replace_newline_with_backslash_l(s); label.push_str(format!("exiting scope_{} {}", i, s[])[]); } - dot::EscStr(label.into_cow()) + dot::LabelText::EscStr(label.into_cow()) } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 0c3438abb2b47..64d0facf95100 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1149,7 +1149,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ast::ExprCall(ref f, ref args) => { let diverges = !self.ir.tcx.is_method_call(expr.id) && { - let t_ret = ty::ty_fn_ret(ty::expr_ty(self.ir.tcx, &**f)); + let t_ret = ty::ty_fn_ret(ty::expr_ty_adjusted(self.ir.tcx, &**f)); t_ret == ty::FnDiverging }; let succ = if diverges { diff --git a/src/librustc_back/rpath.rs b/src/librustc_back/rpath.rs index 955081a3af64c..97a1d38c1a753 100644 --- a/src/librustc_back/rpath.rs +++ b/src/librustc_back/rpath.rs @@ -151,7 +151,6 @@ fn minimize_rpaths(rpaths: &[String]) -> Vec { mod test { use super::{RPathConfig}; use super::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output}; - use syntax::abi; #[test] fn test_rpaths_to_flags() { diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index ac6b962d64704..a54a2eeb5918a 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -137,8 +137,8 @@ impl<'a, 'tcx> dot::Labeller<'a, Node<'a>, Edge<'a>> for DataflowLabeller<'a, 't let suffix = self.dataflow_for(dataflow::Exit, n); let inner_label = self.inner.node_label(n); inner_label - .prefix_line(dot::LabelStr(prefix.into_cow())) - .suffix_line(dot::LabelStr(suffix.into_cow())) + .prefix_line(dot::LabelText::LabelStr(prefix.into_cow())) + .suffix_line(dot::LabelText::LabelStr(suffix.into_cow())) } fn edge_label(&'a self, e: &Edge<'a>) -> dot::LabelText<'a> { self.inner.edge_label(e) } } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 169e52bcfe5be..aeaf215a89b2a 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -576,7 +576,7 @@ pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_call"); trans_call_inner(in_cx, Some(common::expr_info(call_ex)), - expr_ty(in_cx, f), + expr_ty_adjusted(in_cx, f), |cx, _| trans(cx, f), args, Some(dest)).bcx diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index ee93c896433a1..153c6463fbebb 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -8,8 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use super::autoderef; +use super::AutorefArgs; +use super::check_argument_types; +use super::check_expr; +use super::check_method_argument_types; +use super::err_args; +use super::FnCtxt; +use super::LvaluePreference; +use super::method; +use super::structurally_resolved_type; +use super::TupleArgumentsFlag; +use super::write_call; + +use middle::infer; +use middle::ty::{mod, Ty}; use syntax::ast; use syntax::codemap::Span; +use syntax::parse::token; +use syntax::ptr::P; use CrateCtxt; /// Check that it is legal to call methods of the trait corresponding @@ -44,3 +61,165 @@ pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); } } + +pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + call_expr: &ast::Expr, + callee_expr: &ast::Expr, + arg_exprs: &[P]) +{ + check_expr(fcx, callee_expr); + let original_callee_ty = fcx.expr_ty(callee_expr); + let (callee_ty, _, result) = + autoderef(fcx, + callee_expr.span, + original_callee_ty, + Some(callee_expr.id), + LvaluePreference::NoPreference, + |adj_ty, idx| { + let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None }; + try_overloaded_call_step(fcx, call_expr, callee_expr, + adj_ty, autoderefref) + }); + + match result { + None => { + // this will report an error since original_callee_ty is not a fn + confirm_builtin_call(fcx, call_expr, original_callee_ty, arg_exprs); + } + + Some(CallStep::Builtin) => { + confirm_builtin_call(fcx, call_expr, callee_ty, arg_exprs); + } + + Some(CallStep::Overloaded(method_callee)) => { + confirm_overloaded_call(fcx, call_expr, arg_exprs, method_callee); + } + } +} + +enum CallStep<'tcx> { + Builtin, + Overloaded(ty::MethodCallee<'tcx>) +} + +fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + call_expr: &ast::Expr, + callee_expr: &ast::Expr, + adjusted_ty: Ty<'tcx>, + autoderefref: ty::AutoDerefRef<'tcx>) + -> Option> +{ + // If the callee is a bare function or a closure, then we're all set. + match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { + ty::ty_bare_fn(..) | ty::ty_closure(_) => { + fcx.write_adjustment(callee_expr.id, + callee_expr.span, + ty::AdjustDerefRef(autoderefref)); + return Some(CallStep::Builtin); + } + + _ => {} + } + + // Try the options that are least restrictive on the caller first. + for &(opt_trait_def_id, method_name) in [ + (fcx.tcx().lang_items.fn_trait(), token::intern("call")), + (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")), + (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")), + ].iter() { + let trait_def_id = match opt_trait_def_id { + Some(def_id) => def_id, + None => continue, + }; + + match method::lookup_in_trait_adjusted(fcx, + call_expr.span, + Some(&*callee_expr), + method_name, + trait_def_id, + autoderefref.clone(), + adjusted_ty, + None) { + None => continue, + Some(method_callee) => { + return Some(CallStep::Overloaded(method_callee)); + } + } + } + + None +} + +fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, + call_expr: &ast::Expr, + callee_ty: Ty<'tcx>, + arg_exprs: &[P]) +{ + let error_fn_sig; + + let fn_sig = match callee_ty.sty { + ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) | + ty::ty_closure(box ty::ClosureTy {ref sig, ..}) => { + sig + } + _ => { + fcx.type_error_message(call_expr.span, |actual| { + format!("expected function, found `{}`", actual) + }, callee_ty, None); + + // This is the "default" function signature, used in case of error. + // In that case, we check each argument against "error" in order to + // set up all the node type bindings. + error_fn_sig = ty::Binder(ty::FnSig { + inputs: err_args(fcx.tcx(), arg_exprs.len()), + output: ty::FnConverging(fcx.tcx().types.err), + variadic: false + }); + + &error_fn_sig + } + }; + + // Replace any late-bound regions that appear in the function + // signature with region variables. We also have to + // renormalize the associated types at this point, since they + // previously appeared within a `Binder<>` and hence would not + // have been normalized before. + let fn_sig = + fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, + infer::FnCall, + fn_sig).0; + let fn_sig = + fcx.normalize_associated_types_in(call_expr.span, &fn_sig); + + // Call the generic checker. + let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>]. + check_argument_types(fcx, + call_expr.span, + fn_sig.inputs[], + arg_exprs.as_slice(), + AutorefArgs::No, + fn_sig.variadic, + TupleArgumentsFlag::DontTupleArguments); + + write_call(fcx, call_expr, fn_sig.output); +} + +fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, + call_expr: &ast::Expr, + arg_exprs: &[P], + method_callee: ty::MethodCallee<'tcx>) +{ + let arg_exprs: Vec<_> = arg_exprs.iter().collect(); // for some weird reason we take &[&P<...>]. + let output_type = check_method_argument_types(fcx, + call_expr.span, + method_callee.ty, + call_expr, + arg_exprs.as_slice(), + AutorefArgs::No, + TupleArgumentsFlag::TupleArguments); + let method_call = ty::MethodCall::expr(call_expr.id); + fcx.inh.method_map.borrow_mut().insert(method_call, method_callee); + write_call(fcx, call_expr, output_type); +} + diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 82525b71052d2..b2c1f3621f7cd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2229,7 +2229,8 @@ pub enum LvaluePreference { /// /// Note: this method does not modify the adjustments table. The caller is responsible for /// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods. -pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, +pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, + sp: Span, base_ty: Ty<'tcx>, expr_id: Option, mut lvalue_pref: LvaluePreference, @@ -2276,58 +2277,6 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, (fcx.tcx().types.err, 0, None) } -/// Attempts to resolve a call expression as an overloaded call. -fn try_overloaded_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - call_expression: &ast::Expr, - callee: &ast::Expr, - callee_type: Ty<'tcx>, - args: &[&P]) - -> bool { - // Bail out if the callee is a bare function or a closure. We check those - // manually. - match structurally_resolved_type(fcx, callee.span, callee_type).sty { - ty::ty_bare_fn(..) | ty::ty_closure(_) => return false, - _ => {} - } - - // Try the options that are least restrictive on the caller first. - for &(maybe_function_trait, method_name) in [ - (fcx.tcx().lang_items.fn_trait(), token::intern("call")), - (fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")), - (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")), - ].iter() { - let function_trait = match maybe_function_trait { - None => continue, - Some(function_trait) => function_trait, - }; - let method_callee = - match method::lookup_in_trait(fcx, - call_expression.span, - Some(&*callee), - method_name, - function_trait, - callee_type, - None) { - None => continue, - Some(method_callee) => method_callee, - }; - let method_call = MethodCall::expr(call_expression.id); - let output_type = check_method_argument_types(fcx, - call_expression.span, - method_callee.ty, - call_expression, - args, - AutorefArgs::No, - TupleArguments); - fcx.inh.method_map.borrow_mut().insert(method_call, method_callee); - write_call(fcx, call_expression, output_type); - - return true - } - - false -} - fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, method_call: Option, @@ -2690,7 +2639,6 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, check_argument_types(fcx, sp, err_inputs[], - callee_expr, args_no_rcvr, autoref_args, false, @@ -2703,7 +2651,6 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, check_argument_types(fcx, sp, fty.sig.0.inputs.slice_from(1), - callee_expr, args_no_rcvr, autoref_args, fty.sig.0.variadic, @@ -2723,7 +2670,6 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, fn_inputs: &[Ty<'tcx>], - _callee_expr: &ast::Expr, args: &[&P], autoref_args: AutorefArgs, variadic: bool, @@ -3107,63 +3053,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, debug!(">> typechecking: expr={} expected={}", expr.repr(fcx.tcx()), expected.repr(fcx.tcx())); - // A generic function for doing all of the checking for call expressions - fn check_call(fcx: &FnCtxt, - call_expr: &ast::Expr, - f: &ast::Expr, - args: &[&P]) { - // Store the type of `f` as the type of the callee - let fn_ty = fcx.expr_ty(f); - - // Extract the function signature from `in_fty`. - let fn_ty = structurally_resolved_type(fcx, f.span, fn_ty); - - // This is the "default" function signature, used in case of error. - // In that case, we check each argument against "error" in order to - // set up all the node type bindings. - let error_fn_sig = ty::Binder(FnSig { - inputs: err_args(fcx.tcx(), args.len()), - output: ty::FnConverging(fcx.tcx().types.err), - variadic: false - }); - - let fn_sig = match fn_ty.sty { - ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) | - ty::ty_closure(box ty::ClosureTy {ref sig, ..}) => sig, - _ => { - fcx.type_error_message(call_expr.span, |actual| { - format!("expected function, found `{}`", actual) - }, fn_ty, None); - &error_fn_sig - } - }; - - // Replace any late-bound regions that appear in the function - // signature with region variables. We also have to - // renormalize the associated types at this point, since they - // previously appeared within a `Binder<>` and hence would not - // have been normalized before. - let fn_sig = - fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, - infer::FnCall, - fn_sig).0; - let fn_sig = - fcx.normalize_associated_types_in(call_expr.span, - &fn_sig); - - // Call the generic checker. - check_argument_types(fcx, - call_expr.span, - fn_sig.inputs[], - f, - args, - AutorefArgs::No, - fn_sig.variadic, - DontTupleArguments); - - write_call(fcx, call_expr, fn_sig.output); - } - // Checks a method call. fn check_method_call(fcx: &FnCtxt, expr: &ast::Expr, @@ -4165,24 +4054,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, check_block_with_expected(fcx, &**b, expected); fcx.write_ty(id, fcx.node_ty(b.id)); } - ast::ExprCall(ref f, ref args) => { - // Index expressions need to be handled separately, to inform them - // that they appear in call position. - check_expr(fcx, &**f); - let f_ty = fcx.expr_ty(&**f); - - let args: Vec<_> = args.iter().map(|x| x).collect(); - if !try_overloaded_call(fcx, expr, &**f, f_ty, args[]) { - check_call(fcx, expr, &**f, args[]); - let args_err = args.iter().fold(false, - |rest_err, a| { - // is this not working? - let a_ty = fcx.expr_ty(&***a); - rest_err || ty::type_is_error(a_ty)}); - if ty::type_is_error(f_ty) || args_err { - fcx.write_error(id); - } - } + ast::ExprCall(ref callee, ref args) => { + callee::check_call(fcx, expr, &**callee, args.as_slice()); } ast::ExprMethodCall(ident, ref tps, ref args) => { check_method_call(fcx, expr, ident, args[], tps[], lvalue_pref); diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index cd991c5f884f5..af6daaf261ef2 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -25,30 +25,21 @@ //! out.write(b"Hello, world!"); //! ``` +use prelude::v1::*; use self::StdSource::*; -use boxed::Box; use cell::RefCell; -use clone::Clone; use failure::LOCAL_STDERR; use fmt; -use io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer, - standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; -use kinds::{Sync, Send}; +use io::{IoResult, IoError, OtherIoError}; +use io::{standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; use libc; use mem; -use option::Option; -use option::Option::{Some, None}; -use ops::{Deref, DerefMut, FnOnce}; -use result::Result::{Ok, Err}; +use ops::{Deref, DerefMut}; use rt; -use slice::SliceExt; -use str::StrExt; -use string::String; +use sync::{Arc, Mutex, MutexGuard, StaticMutex, MUTEX_INIT}; use sys::{fs, tty}; -use sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT}; use uint; -use vec::Vec; // And so begins the tale of acquiring a uv handle to a stdio stream on all // platforms in all situations. Our story begins by splitting the world into two @@ -217,14 +208,15 @@ impl Reader for StdinReader { pub fn stdin() -> StdinReader { // We're following the same strategy as kimundi's lazy_static library static mut STDIN: *const StdinReader = 0 as *const StdinReader; - static ONCE: Once = ONCE_INIT; + static LOCK: StaticMutex = MUTEX_INIT; unsafe { - ONCE.call_once(|| { - // The default buffer capacity is 64k, but apparently windows doesn't like - // 64k reads on stdin. See #13304 for details, but the idea is that on - // windows we use a slightly smaller buffer that's been seen to be - // acceptable. + let _g = LOCK.lock(); + if STDIN as uint == 0 { + // The default buffer capacity is 64k, but apparently windows + // doesn't like 64k reads on stdin. See #13304 for details, but the + // idea is that on windows we use a slightly smaller buffer that's + // been seen to be acceptable. let stdin = if cfg!(windows) { BufferedReader::with_capacity(8 * 1024, stdin_raw()) } else { @@ -237,11 +229,15 @@ pub fn stdin() -> StdinReader { // Make sure to free it at exit rt::at_exit(|| { - mem::transmute::<_, Box>(STDIN); - STDIN = 0 as *const _; + let g = LOCK.lock(); + let stdin = STDIN; + STDIN = 1 as *const _; + drop(g); + mem::transmute::<_, Box>(stdin); }); - }); - + } else if STDIN as uint == 1 { + panic!("accessing stdin after the main thread has exited") + } (*STDIN).clone() } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 7c8aab2b31dae..078aed003242d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -230,13 +230,13 @@ pub mod task; pub mod thread; pub mod sync; +#[path = "sys/common/mod.rs"] mod sys_common; + #[cfg(unix)] #[path = "sys/unix/mod.rs"] mod sys; #[cfg(windows)] #[path = "sys/windows/mod.rs"] mod sys; -#[path = "sys/common/mod.rs"] mod sys_common; - pub mod rt; mod failure; diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs index 5823f8453d84a..08dabd3b0b603 100644 --- a/src/libstd/rt/at_exit_imp.rs +++ b/src/libstd/rt/at_exit_imp.rs @@ -29,6 +29,8 @@ type Queue = Vec; static LOCK: Mutex = MUTEX_INIT; static mut QUEUE: *mut Queue = 0 as *mut Queue; +const DTOR_RUN_ITERS: uint = 10; + unsafe fn init() { if QUEUE.is_null() { let state: Box = box Vec::new(); @@ -49,7 +51,7 @@ pub fn cleanup() { unsafe { LOCK.lock(); let queue = QUEUE; - QUEUE = 1 as *mut _; + QUEUE = 1u as *mut _; LOCK.unlock(); // make sure we're not recursively cleaning up diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 68aaa1b3ae55d..5df702dde1e91 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -93,9 +93,7 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { // but we just do this to name the main thread and to give it correct // info about the stack bounds. let thread: Thread = NewThread::new(Some("
".to_string())); - thread_info::set((my_stack_bottom, my_stack_top), - sys::thread::guard::main(), - thread); + thread_info::set(sys::thread::guard::main(), thread); // By default, some platforms will send a *signal* when a EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE @@ -134,20 +132,14 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { } } -/// Enqueues a procedure to run when the runtime is cleaned up -/// -/// The procedure passed to this function will be executed as part of the -/// runtime cleanup phase. For normal rust programs, this means that it will run -/// after all other threads have exited. -/// -/// The procedure is *not* executed with a local `Thread` available to it, so -/// primitives like logging, I/O, channels, spawning, etc, are *not* available. -/// This is meant for "bare bones" usage to clean up runtime details, this is -/// not meant as a general-purpose "let's clean everything up" function. +/// Enqueues a procedure to run when the main thread exits. /// /// It is forbidden for procedures to register more `at_exit` handlers when they /// are running, and doing so will lead to a process abort. -pub fn at_exit(f: F) { +/// +/// Note that other threads may still be running when `at_exit` routines start +/// running. +pub fn at_exit(f: F) { at_exit_imp::push(Thunk::new(f)); } @@ -163,8 +155,5 @@ pub fn at_exit(f: F) { pub unsafe fn cleanup() { args::cleanup(); sys::stack_overflow::cleanup(); - // FIXME: (#20012): the resources being cleaned up by at_exit - // currently are not prepared for cleanup to happen asynchronously - // with detached threads using the resources; for now, we leak. - // at_exit_imp::cleanup(); + at_exit_imp::cleanup(); } diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index 6f6be2e111df4..b34195c9d7e0d 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -68,7 +68,7 @@ use intrinsics; use libc::c_void; use mem; use sync::atomic; -use sync::{Once, ONCE_INIT}; +use sys_common::mutex::{Mutex, MUTEX_INIT}; use rt::libunwind as uw; @@ -529,11 +529,20 @@ pub fn begin_unwind(msg: M, file_line: &(&'static str, uint)) -> /// Doing this split took the LLVM IR line counts of `fn main() { panic!() /// }` from ~1900/3700 (-O/no opts) to 180/590. #[inline(never)] #[cold] // this is the slow path, please never inline this -fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> ! { +fn begin_unwind_inner(msg: Box, + file_line: &(&'static str, uint)) -> ! { // Make sure the default failure handler is registered before we look at the // callbacks. - static INIT: Once = ONCE_INIT; - INIT.call_once(|| unsafe { register(failure::on_fail); }); + unsafe { + static LOCK: Mutex = MUTEX_INIT; + static mut INIT: bool = false; + LOCK.lock(); + if !INIT { + register(failure::on_fail); + INIT = true; + } + LOCK.unlock(); + } // First, invoke call the user-defined callbacks triggered on thread panic. // diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index bdf1bf3dfd02c..09d22387c4478 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -20,6 +20,8 @@ //! can be created in the future and there must be no active timers at that //! time. +#![macro_escape] + use prelude::v1::*; use cell::UnsafeCell; @@ -69,6 +71,17 @@ struct RaceBox(helper_signal::signal); unsafe impl Send for RaceBox {} unsafe impl Sync for RaceBox {} +macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => ( + static $name: Helper<$m> = Helper { + lock: ::sync::MUTEX_INIT, + cond: ::sync::CONDVAR_INIT, + chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, + signal: ::cell::UnsafeCell { value: 0 }, + initialized: ::cell::UnsafeCell { value: false }, + shutdown: ::cell::UnsafeCell { value: false }, + }; +) } + impl Helper { /// Lazily boots a helper thread, becoming a no-op if the helper has already /// been spawned. @@ -85,7 +98,7 @@ impl Helper { { unsafe { let _guard = self.lock.lock().unwrap(); - if !*self.initialized.get() { + if *self.chan.get() as uint == 0 { let (tx, rx) = channel(); *self.chan.get() = mem::transmute(box tx); let (receive, send) = helper_signal::new(); @@ -94,15 +107,17 @@ impl Helper { let receive = RaceBox(receive); let t = f(); - Thread::spawn(move |:| { + Thread::spawn(move || { helper(receive.0, rx, t); let _g = self.lock.lock().unwrap(); *self.shutdown.get() = true; self.cond.notify_one() }).detach(); - rt::at_exit(move|:| { self.shutdown() }); + rt::at_exit(move || { self.shutdown() }); *self.initialized.get() = true; + } else if *self.chan.get() as uint == 1 { + panic!("cannot continue usage after shutdown"); } } } @@ -117,7 +132,9 @@ impl Helper { // Must send and *then* signal to ensure that the child receives the // message. Otherwise it could wake up and go to sleep before we // send the message. - assert!(!self.chan.get().is_null()); + assert!(*self.chan.get() as uint != 0); + assert!(*self.chan.get() as uint != 1, + "cannot continue usage after shutdown"); (**self.chan.get()).send(msg).unwrap(); helper_signal::signal(*self.signal.get() as helper_signal::signal); } @@ -130,9 +147,13 @@ impl Helper { // returns. let mut guard = self.lock.lock().unwrap(); + let ptr = *self.chan.get(); + if ptr as uint == 1 { + panic!("cannot continue usage after shutdown"); + } // Close the channel by destroying it let chan: Box> = mem::transmute(*self.chan.get()); - *self.chan.get() = 0 as *mut Sender; + *self.chan.get() = 1 as *mut Sender; drop(chan); helper_signal::signal(*self.signal.get() as helper_signal::signal); diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index 97015f74a4a10..fe9f669789566 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(missing_docs)] -#![allow(dead_code)] +#![macro_escape] use io::{mod, IoError, IoResult}; use prelude::v1::*; diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs index 567c26956efe9..322d2f202f772 100644 --- a/src/libstd/sys/common/mutex.rs +++ b/src/libstd/sys/common/mutex.rs @@ -29,6 +29,7 @@ impl Mutex { /// Behavior is undefined if the mutex is moved after the first method is /// called on the mutex. #[inline] + #[allow(dead_code)] // sys is not exported yet pub unsafe fn new() -> Mutex { Mutex(imp::Mutex::new()) } /// Lock the mutex blocking the current thread until it is available. diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 94a2c9b78faef..2132f2b2b6d64 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -24,7 +24,9 @@ use ptr::{mod, null, null_mut}; use sys::{mod, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock, wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval, decode_error_detailed}; -use sync::{Arc, Mutex, MutexGuard}; +use sync::{Arc, Mutex}; +#[cfg(not(target_os = "linux"))] +use sync::MutexGuard; use sys_common::{mod, keep_going, short_write, timeout}; use cmp; use io; @@ -611,11 +613,13 @@ impl Drop for Inner { fn drop(&mut self) { unsafe { close_sock(self.fd); } } } +#[cfg(not(target_os = "linux"))] pub struct Guard<'a> { pub fd: sock_t, pub guard: MutexGuard<'a, ()>, } +#[cfg(not(target_os = "linux"))] #[unsafe_destructor] impl<'a> Drop for Guard<'a> { fn drop(&mut self) { diff --git a/src/libstd/sys/common/rwlock.rs b/src/libstd/sys/common/rwlock.rs index df016b9e293b7..b7c4cfcd0f5fe 100644 --- a/src/libstd/sys/common/rwlock.rs +++ b/src/libstd/sys/common/rwlock.rs @@ -26,6 +26,7 @@ impl RWLock { /// Usage of an RWLock is undefined if it is moved after its first use (any /// function calls below). #[inline] + #[allow(dead_code)] // sys is not exported yet pub unsafe fn new() -> RWLock { RWLock(imp::RWLock::new()) } /// Acquire shared access to the underlying lock, blocking the current diff --git a/src/libstd/sys/common/stack.rs b/src/libstd/sys/common/stack.rs index 2a88e20c8fa1f..1966a9544e1a5 100644 --- a/src/libstd/sys/common/stack.rs +++ b/src/libstd/sys/common/stack.rs @@ -121,37 +121,6 @@ pub unsafe fn record_os_managed_stack_bounds(stack_lo: uint, _stack_hi: uint) { record_sp_limit(stack_lo + RED_ZONE); } -#[inline(always)] -pub unsafe fn record_rust_managed_stack_bounds(stack_lo: uint, stack_hi: uint) { - // When the old runtime had segmented stacks, it used a calculation that was - // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic - // symbol resolution, llvm function calls, etc. In theory this red zone - // value is 0, but it matters far less when we have gigantic stacks because - // we don't need to be so exact about our stack budget. The "fudge factor" - // was because LLVM doesn't emit a stack check for functions < 256 bytes in - // size. Again though, we have giant stacks, so we round all these - // calculations up to the nice round number of 20k. - record_sp_limit(stack_lo + RED_ZONE); - - return target_record_stack_bounds(stack_lo, stack_hi); - - #[cfg(not(windows))] #[inline(always)] - unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {} - - #[cfg(all(windows, target_arch = "x86"))] #[inline(always)] - unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) { - // stack range is at TIB: %fs:0x04 (top) and %fs:0x08 (bottom) - asm!("mov $0, %fs:0x04" :: "r"(stack_hi) :: "volatile"); - asm!("mov $0, %fs:0x08" :: "r"(stack_lo) :: "volatile"); - } - #[cfg(all(windows, target_arch = "x86_64"))] #[inline(always)] - unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) { - // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom) - asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile"); - asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile"); - } -} - /// Records the current limit of the stack as specified by `end`. /// /// This is stored in an OS-dependent location, likely inside of the thread diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index 92b936e74f654..dd1106fe0b192 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(dead_code)] // stack_guard isn't used right now on all platforms + use core::prelude::*; use cell::RefCell; @@ -16,10 +18,6 @@ use thread::Thread; use thread_local::State; struct ThreadInfo { - // This field holds the known bounds of the stack in (lo, hi) - // form. Not all threads necessarily know their precise bounds, - // hence this is optional. - stack_bounds: (uint, uint), stack_guard: uint, thread: Thread, } @@ -36,7 +34,6 @@ impl ThreadInfo { THREAD_INFO.with(move |c| { if c.borrow().is_none() { *c.borrow_mut() = Some(ThreadInfo { - stack_bounds: (0, 0), stack_guard: 0, thread: NewThread::new(None), }) @@ -54,10 +51,9 @@ pub fn stack_guard() -> uint { ThreadInfo::with(|info| info.stack_guard) } -pub fn set(stack_bounds: (uint, uint), stack_guard: uint, thread: Thread) { +pub fn set(stack_guard: uint, thread: Thread) { THREAD_INFO.with(|c| assert!(c.borrow().is_none())); THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ - stack_bounds: stack_bounds, stack_guard: stack_guard, thread: thread, })); diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs index 9d7188a37bcdf..1ca64d288f803 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys/common/thread_local.rs @@ -55,11 +55,11 @@ //! ``` #![allow(non_camel_case_types)] +#![allow(dead_code)] // sys isn't exported yet use prelude::v1::*; use sync::atomic::{mod, AtomicUint}; -use sync::{Mutex, Once, ONCE_INIT}; use sys::thread_local as imp; @@ -140,9 +140,6 @@ pub const INIT_INNER: StaticKeyInner = StaticKeyInner { key: atomic::ATOMIC_UINT_INIT, }; -static INIT_KEYS: Once = ONCE_INIT; -static mut KEYS: *mut Mutex> = 0 as *mut _; - impl StaticKey { /// Gets the value associated with this TLS key /// diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index 9e26475f814b7..b0fca87d73630 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -83,12 +83,12 @@ /// to symbols. This is a bit of a hokey implementation as-is, but it works for /// all unix platforms we support right now, so it at least gets the job done. +use prelude::v1::*; + use c_str::CString; -use io::{IoResult, Writer}; +use io::IoResult; use libc; use mem; -use option::Option::{mod, Some, None}; -use result::Result::{Ok, Err}; use sync::{StaticMutex, MUTEX_INIT}; use sys_common::backtrace::*; @@ -151,7 +151,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> { // I/O done here is blocking I/O, not green I/O, so we don't have to // worry about this being a native vs green mutex. static LOCK: StaticMutex = MUTEX_INIT; - let _g = unsafe { LOCK.lock() }; + let _g = LOCK.lock(); try!(writeln!(w, "stack backtrace:")); @@ -241,12 +241,8 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { #[cfg(not(any(target_os = "macos", target_os = "ios")))] fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { - use iter::{Iterator, IteratorExt}; use os; - use path::GenericPath; - use ptr::PtrExt; use ptr; - use slice::SliceExt; //////////////////////////////////////////////////////////////////////// // libbacktrace.h API diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 4199cbc1bb9f5..46a1bf31c00b4 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -10,30 +10,14 @@ #![allow(missing_docs)] #![allow(non_camel_case_types)] -#![allow(unused_imports)] -#![allow(dead_code)] -#![allow(unused_unsafe)] -#![allow(unused_mut)] extern crate libc; -use num; use num::{Int, SignedInt}; use prelude::v1::*; use io::{mod, IoResult, IoError}; use sys_common::mkerr_libc; -macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => ( - static $name: Helper<$m> = Helper { - lock: ::sync::MUTEX_INIT, - cond: ::sync::CONDVAR_INIT, - chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, - signal: ::cell::UnsafeCell { value: 0 }, - initialized: ::cell::UnsafeCell { value: false }, - shutdown: ::cell::UnsafeCell { value: false }, - }; -) } - pub mod backtrace; pub mod c; pub mod ext; diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index 81f8659d6ae08..c9cb46b0289f1 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -11,7 +11,6 @@ use cell::UnsafeCell; use kinds::Sync; use sys::sync as ffi; -use sys_common::mutex; pub struct Mutex { inner: UnsafeCell } @@ -26,6 +25,7 @@ pub const MUTEX_INIT: Mutex = Mutex { unsafe impl Sync for Mutex {} +#[allow(dead_code)] // sys isn't exported yet impl Mutex { #[inline] pub unsafe fn new() -> Mutex { diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 6a8f55e79c872..d838ff82905fe 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -10,17 +10,16 @@ //! Implementation of `std::os` functionality for unix systems +#![allow(unused_imports)] // lots of cfg code here + use prelude::v1::*; use c_str::ToCStr; -use error::{FromError, Error}; -use fmt; use io::{IoError, IoResult}; -use libc::{mod, c_int, c_char, c_void}; +use libc::{mod, c_int, c_char}; use os; -use path::{BytesContainer}; +use path::BytesContainer; use ptr; -use sync::atomic::{AtomicInt, SeqCst}; use sys::fs::FileDesc; use os::TMPBUF_SZ; diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 623f3f6a89c9d..e4fd36d8abc12 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -142,7 +142,7 @@ impl UnixStream { fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: unsafe { self.inner.lock.lock().unwrap() }, + guard: self.inner.lock.lock().unwrap(), }; assert!(set_nonblocking(self.fd(), true).is_ok()); ret diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index af09bf4fbd0a2..b9b43389be7c1 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -12,10 +12,10 @@ use prelude::v1::*; use self::Req::*; use c_str::{CString, ToCStr}; -use collections; +use collections::HashMap; use hash::Hash; use io::process::{ProcessExit, ExitStatus, ExitSignal}; -use io::{mod, IoResult, IoError, EndOfFile}; +use io::{IoResult, EndOfFile}; use libc::{mod, pid_t, c_void, c_int}; use mem; use os; @@ -328,7 +328,7 @@ impl Process { // The actual communication between the helper thread and this thread is // quite simple, just a channel moving data around. - unsafe { HELPER.boot(register_sigchld, waitpid_helper) } + HELPER.boot(register_sigchld, waitpid_helper); match self.try_wait() { Some(ret) => return Ok(ret), @@ -336,7 +336,7 @@ impl Process { } let (tx, rx) = channel(); - unsafe { HELPER.send(NewChild(self.pid, tx, deadline)); } + HELPER.send(NewChild(self.pid, tx, deadline)); return match rx.recv() { Ok(e) => Ok(e), Err(..) => Err(timeout("wait timed out")), @@ -420,8 +420,15 @@ impl Process { Ok(NewChild(pid, tx, deadline)) => { active.push((pid, tx, deadline)); } + // Once we've been disconnected it means the main + // thread is exiting (at_exit has run). We could + // still have active waiter for other threads, so + // we're just going to drop them all on the floor. + // This means that they won't receive a "you're + // done" message in which case they'll be considered + // as timed out, but more generally errors will + // start propagating. Err(TryRecvError::Disconnected) => { - assert!(active.len() == 0); break 'outer; } Err(TryRecvError::Empty) => break, @@ -553,7 +560,7 @@ fn with_argv(prog: &CString, args: &[CString], cb(ptrs.as_ptr()) } -fn with_envp(env: Option<&collections::HashMap>, +fn with_envp(env: Option<&HashMap>, cb: F) -> T where F : FnOnce(*const c_void) -> T, diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs index 0d63ff14ff26b..4f9b06685ec0c 100644 --- a/src/libstd/sys/unix/rwlock.rs +++ b/src/libstd/sys/unix/rwlock.rs @@ -17,6 +17,7 @@ pub const RWLOCK_INIT: RWLock = RWLock { inner: UnsafeCell { value: ffi::PTHREAD_RWLOCK_INITIALIZER }, }; +#[allow(dead_code)] // sys isn't exported yet impl RWLock { #[inline] pub unsafe fn new() -> RWLock { diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 95ab9b459d671..647619fa23161 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -34,7 +34,6 @@ impl Drop for Handler { #[cfg(any(target_os = "linux", target_os = "macos"))] mod imp { - use core::prelude::*; use sys_common::stack; use super::Handler; diff --git a/src/libstd/sys/unix/tcp.rs b/src/libstd/sys/unix/tcp.rs index 13ccf685fd7fc..26c2bb8ed600e 100644 --- a/src/libstd/sys/unix/tcp.rs +++ b/src/libstd/sys/unix/tcp.rs @@ -136,10 +136,6 @@ impl TcpAcceptor { Err(sys_common::eof()) } - pub fn socket_name(&mut self) -> IoResult { - net::sockname(self.fd(), libc::getsockname) - } - pub fn set_timeout(&mut self, timeout: Option) { self.deadline = timeout.map(|a| sys::timer::now() + a).unwrap_or(0); } diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs index 80f93dd2f618c..8cd69f236cf34 100644 --- a/src/libstd/sys/unix/timer.rs +++ b/src/libstd/sys/unix/timer.rs @@ -100,7 +100,7 @@ pub fn now() -> u64 { fn helper(input: libc::c_int, messages: Receiver, _: ()) { let mut set: c::fd_set = unsafe { mem::zeroed() }; - let mut fd = FileDesc::new(input, true); + let fd = FileDesc::new(input, true); let mut timeout: libc::timeval = unsafe { mem::zeroed() }; // active timers are those which are able to be selected upon (and it's a @@ -168,8 +168,15 @@ fn helper(input: libc::c_int, messages: Receiver, _: ()) { 1 => { loop { match messages.try_recv() { + // Once we've been disconnected it means the main thread + // is exiting (at_exit has run). We could still have + // active timers for other threads, so we're just going + // to drop them all on the floor. This is all we can + // really do, however, to prevent resource leakage. The + // remaining timers will likely start panicking quickly + // as they attempt to re-use this thread but are + // disallowed to do so. Err(TryRecvError::Disconnected) => { - assert!(active.len() == 0); break 'outer; } diff --git a/src/libstd/sys/unix/tty.rs b/src/libstd/sys/unix/tty.rs index 4ef687d41d8ee..d8cb067b946a6 100644 --- a/src/libstd/sys/unix/tty.rs +++ b/src/libstd/sys/unix/tty.rs @@ -44,5 +44,4 @@ impl TTY { pub fn get_winsize(&mut self) -> IoResult<(int, int)> { Err(sys_common::unimpl()) } - pub fn isatty(&self) -> bool { false } } diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 319a458087b9b..ee80ae731a36d 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -7,19 +7,22 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -/// As always, windows has something very different than unix, we mainly want -/// to avoid having to depend too much on libunwind for windows. -/// -/// If you google around, you'll find a fair bit of references to built-in -/// functions to get backtraces on windows. It turns out that most of these are -/// in an external library called dbghelp. I was unable to find this library -/// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent -/// of it. -/// -/// You'll also find that there's a function called CaptureStackBackTrace -/// mentioned frequently (which is also easy to use), but sadly I didn't have a -/// copy of that function in my mingw install (maybe it was broken?). Instead, -/// this takes the route of using StackWalk64 in order to walk the stack. + +//! As always, windows has something very different than unix, we mainly want +//! to avoid having to depend too much on libunwind for windows. +//! +//! If you google around, you'll find a fair bit of references to built-in +//! functions to get backtraces on windows. It turns out that most of these are +//! in an external library called dbghelp. I was unable to find this library +//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent +//! of it. +//! +//! You'll also find that there's a function called CaptureStackBackTrace +//! mentioned frequently (which is also easy to use), but sadly I didn't have a +//! copy of that function in my mingw install (maybe it was broken?). Instead, +//! this takes the route of using StackWalk64 in order to walk the stack. + +#![allow(dead_code)] // constants/fields aren't always used on all platforms use c_str::CString; use intrinsics; @@ -294,7 +297,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> { // According to windows documentation, all dbghelp functions are // single-threaded. static LOCK: StaticMutex = MUTEX_INIT; - let _g = unsafe { LOCK.lock() }; + let _g = LOCK.lock(); // Open up dbghelp.dll, we don't link to it explicitly because it can't // always be found. Additionally, it's nice having fewer dependencies. diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 1ee57434fb91a..b563c356a7634 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -15,7 +15,6 @@ #![allow(non_camel_case_types)] use libc; -use prelude::v1::*; pub const WSADESCRIPTION_LEN: uint = 256; pub const WSASYS_STATUS_LEN: uint = 128; diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 523d60c71aa8b..e893a7dea6b78 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -10,21 +10,17 @@ //! Blocking Windows-based file I/O -use alloc::arc::Arc; use libc::{mod, c_int}; -use c_str::CString; +use io; use mem; -use sys::os::fill_utf16_buf_and_decode; -use path; use ptr; -use str; -use io; +use sys::os::fill_utf16_buf_and_decode; use prelude::v1::*; use sys; use sys::os; -use sys_common::{keep_going, eof, mkerr_libc}; +use sys_common::{unimpl, mkerr_libc}; use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use io::{IoResult, IoError, FileStat, SeekStyle}; @@ -445,7 +441,7 @@ pub fn stat(p: &Path) -> IoResult { // FIXME: move this to platform-specific modules (for now)? pub fn lstat(_p: &Path) -> IoResult { // FIXME: implementation is missing - Err(super::unimpl()) + Err(unimpl()) } pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 1034f0615d994..797a4db2de39c 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -11,31 +11,14 @@ #![allow(missing_docs)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] -#![allow(unused_imports)] -#![allow(dead_code)] -#![allow(unused_unsafe)] -#![allow(unused_mut)] - -extern crate libc; use prelude::v1::*; -use num; -use mem; use io::{mod, IoResult, IoError}; +use libc; +use mem; use sync::{Once, ONCE_INIT}; -macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => ( - static $name: Helper<$m> = Helper { - lock: ::sync::MUTEX_INIT, - cond: ::sync::CONDVAR_INIT, - chan: ::cell::UnsafeCell { value: 0 as *mut ::sync::mpsc::Sender<$m> }, - signal: ::cell::UnsafeCell { value: 0 }, - initialized: ::cell::UnsafeCell { value: false }, - shutdown: ::cell::UnsafeCell { value: false }, - }; -) } - pub mod backtrace; pub mod c; pub mod ext; @@ -181,14 +164,6 @@ pub fn init_net() { } } -pub fn unimpl() -> IoError { - IoError { - kind: io::IoUnavailable, - desc: "operation is not implemented", - detail: None, - } -} - pub fn to_utf16(s: Option<&str>) -> IoResult> { match s { Some(s) => Ok({ diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index dfdee0e0385c5..825d5699ab7d2 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -15,7 +15,6 @@ use prelude::v1::*; -use fmt; use io::{IoResult, IoError}; use iter::repeat; use libc::{c_int, c_void}; diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index f173d5fc6d4cb..17fe8d5ce76e0 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -365,7 +365,7 @@ impl UnixStream { // acquire the lock. // // See comments in close_read() about why this lock is necessary. - let guard = unsafe { self.inner.lock.lock() }; + let guard = self.inner.lock.lock(); if self.read_closed() { return Err(eof()) } @@ -441,7 +441,7 @@ impl UnixStream { // going after we woke up. // // See comments in close_read() about why this lock is necessary. - let guard = unsafe { self.inner.lock.lock() }; + let guard = self.inner.lock.lock(); if self.write_closed() { return Err(epipe()) } @@ -516,14 +516,14 @@ impl UnixStream { // close_read() between steps 1 and 2. By atomically executing steps 1 // and 2 with a lock with respect to close_read(), we're guaranteed that // no thread will erroneously sit in a read forever. - let _guard = unsafe { self.inner.lock.lock() }; + let _guard = self.inner.lock.lock(); self.inner.read_closed.store(true, atomic::SeqCst); self.cancel_io() } pub fn close_write(&mut self) -> IoResult<()> { // see comments in close_read() for why this lock is necessary - let _guard = unsafe { self.inner.lock.lock() }; + let _guard = self.inner.lock.lock(); self.inner.write_closed.store(true, atomic::SeqCst); self.cancel_io() } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index cb99a886ce4fc..42086106f7708 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,24 +10,22 @@ use prelude::v1::*; -use libc::{pid_t, c_void, c_int}; +use libc::{pid_t, c_void}; use libc; use c_str::{CString, ToCStr}; use io; use mem; use os; use ptr; -use io::process::{ProcessExit, ExitStatus, ExitSignal}; +use io::process::{ProcessExit, ExitStatus}; use collections; use path::BytesContainer; use hash::Hash; use io::{IoResult, IoError}; -use sys::fs; -use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; +use sys::timer; use sys::fs::FileDesc; -use sys_common::helper_thread::Helper; -use sys_common::{AsInner, mkerr_libc, timeout}; +use sys_common::{AsInner, timeout}; use io::fs::PathExtensions; @@ -122,8 +120,6 @@ impl Process { use libc::funcs::extra::msvcrt::get_osfhandle; use mem; - use iter::{Iterator, IteratorExt}; - use str::StrExt; if cfg.gid().is_some() || cfg.uid().is_some() { return Err(IoError { diff --git a/src/libstd/sys/windows/stack_overflow.rs b/src/libstd/sys/windows/stack_overflow.rs index e8b447022cbf4..67f185a2e4d32 100644 --- a/src/libstd/sys/windows/stack_overflow.rs +++ b/src/libstd/sys/windows/stack_overflow.rs @@ -14,7 +14,7 @@ use ptr; use mem; use libc; use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL}; -use sys_common::{stack, thread_info}; +use sys_common::stack; pub struct Handler { _data: *mut libc::c_void @@ -30,14 +30,6 @@ impl Drop for Handler { fn drop(&mut self) {} } -// get_task_info is called from an exception / signal handler. -// It returns the guard page of the current task or 0 if that -// guard page doesn't exist. None is returned if there's currently -// no local task. -unsafe fn get_task_guard_page() -> uint { - thread_info::stack_guard() -} - // This is initialized in init() and only read from after static mut PAGE_SIZE: uint = 0; diff --git a/src/libstd/sys/windows/tcp.rs b/src/libstd/sys/windows/tcp.rs index 5a929f6b2b5ff..ce241f05a533b 100644 --- a/src/libstd/sys/windows/tcp.rs +++ b/src/libstd/sys/windows/tcp.rs @@ -8,17 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use prelude::v1::*; + use io::net::ip; use io::IoResult; use libc; use mem; use ptr; -use prelude::v1::*; -use super::{last_error, last_net_error, retry, sock_t}; +use super::{last_error, last_net_error, sock_t}; use sync::{Arc, atomic}; -use sys::fs::FileDesc; use sys::{mod, c, set_nonblocking, wouldblock, timer}; -use sys_common::{mod, timeout, eof, net}; +use sys_common::{timeout, eof, net}; pub use sys_common::net::TcpStream; @@ -205,10 +205,6 @@ impl TcpAcceptor { Err(eof()) } - pub fn socket_name(&mut self) -> IoResult { - net::sockname(self.socket(), libc::getsockname) - } - pub fn set_timeout(&mut self, timeout: Option) { self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); } diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 4498f56c00a1e..59ab5f5c4d990 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use boxed::Box; use cmp; use mem; diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index b96e26c7a86a6..8d0f413b4db08 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -137,9 +137,9 @@ unsafe fn init_dtors() { rt::at_exit(move|| { DTOR_LOCK.lock(); let dtors = DTORS; - DTORS = 0 as *mut _; + DTORS = 1 as *mut _; mem::transmute::<_, Box>>(dtors); - assert!(DTORS.is_null()); // can't re-init after destructing + assert!(DTORS as uint == 1); // can't re-init after destructing DTOR_LOCK.unlock(); }); } @@ -147,6 +147,9 @@ unsafe fn init_dtors() { unsafe fn register_dtor(key: Key, dtor: Dtor) { DTOR_LOCK.lock(); init_dtors(); + assert!(DTORS as uint != 0); + assert!(DTORS as uint != 1, + "cannot create new TLS keys after the main thread has exited"); (*DTORS).push((key, dtor)); DTOR_LOCK.unlock(); } @@ -154,6 +157,9 @@ unsafe fn register_dtor(key: Key, dtor: Dtor) { unsafe fn unregister_dtor(key: Key) -> bool { DTOR_LOCK.lock(); init_dtors(); + assert!(DTORS as uint != 0); + assert!(DTORS as uint != 1, + "cannot unregister destructors after the main thread has exited"); let ret = { let dtors = &mut *DTORS; let before = dtors.len(); @@ -232,6 +238,7 @@ unsafe extern "system" fn on_tls_callback(h: LPVOID, } } +#[allow(dead_code)] // not actually dead unsafe fn run_dtors() { let mut any_run = true; for _ in range(0, 5i) { diff --git a/src/libstd/sys/windows/timer.rs b/src/libstd/sys/windows/timer.rs index 343b78543bfd0..f026cf72cb92f 100644 --- a/src/libstd/sys/windows/timer.rs +++ b/src/libstd/sys/windows/timer.rs @@ -20,17 +20,14 @@ //! Other than that, the implementation is pretty straightforward in terms of //! the other two implementations of timers with nothing *that* new showing up. -use self::Req::*; use prelude::v1::*; +use self::Req::*; use libc; use ptr; - use io::IoResult; -use sync::mpsc::{channel, Sender, Receiver, TryRecvError}; -use sys::c; -use sys::fs::FileDesc; use sys_common::helper_thread::Helper; +use sync::mpsc::{channel, TryRecvError, Sender, Receiver}; helper_init! { static HELPER: Helper } @@ -80,9 +77,10 @@ fn helper(input: libc::HANDLE, messages: Receiver, _: ()) { None => {} } } + // See the comment in unix::timer for why we don't have any + // asserts here and why we're likely just leaving timers on + // the floor as we exit. Err(TryRecvError::Disconnected) => { - assert_eq!(objs.len(), 1); - assert_eq!(chans.len(), 0); break 'outer; } Err(..) => break diff --git a/src/libstd/sys/windows/tty.rs b/src/libstd/sys/windows/tty.rs index 7591025d76d6f..393e3cd4f2a85 100644 --- a/src/libstd/sys/windows/tty.rs +++ b/src/libstd/sys/windows/tty.rs @@ -37,9 +37,10 @@ use str::from_utf8; use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS}; use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT}; use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE}; -use super::c::{ERROR_ILLEGAL_CHARACTER}; use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode}; +use sys_common::unimpl; + fn invalid_encoding() -> IoError { IoError { kind: io::InvalidInput, @@ -151,11 +152,8 @@ impl TTY { // Make a CONSOLE_SCREEN_BUFFER_INFO // Call GetConsoleScreenBufferInfo // Maybe call GetLargestConsoleWindowSize instead? - Err(super::unimpl()) + Err(unimpl()) } - - // Let us magically declare this as a TTY - pub fn isatty(&self) -> bool { true } } impl Drop for TTY { diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 3c87309dabcf3..97f61b08bcbcc 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -232,13 +232,10 @@ impl Builder { let my_stack_top = addr as uint; let my_stack_bottom = my_stack_top - stack_size + 1024; unsafe { - stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top); + stack::record_os_managed_stack_bounds(my_stack_bottom, + my_stack_top); + thread_info::set(imp::guard::current(), their_thread); } - thread_info::set( - (my_stack_bottom, my_stack_top), - unsafe { imp::guard::current() }, - their_thread - ); let mut output = None; let f: Thunk<(), T> = if stdout.is_some() || stderr.is_some() { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a705872b53d93..96b1a93ff9440 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1667,7 +1667,6 @@ mod test { // are ASTs encodable? #[test] fn check_asts_encodable() { - use std::io; let e = Crate { module: Mod { inner: Span { diff --git a/src/rust-installer b/src/rust-installer index 3a37981744a5a..48395771f0b0b 160000 --- a/src/rust-installer +++ b/src/rust-installer @@ -1 +1 @@ -Subproject commit 3a37981744a5af2433fed551f742465c78c9af7f +Subproject commit 48395771f0b0b5cbd435245dc02dc50822685eef diff --git a/src/test/compile-fail/issue-19692.rs b/src/test/compile-fail/issue-19692.rs index 4069ea6b997c4..7794c34a04b81 100644 --- a/src/test/compile-fail/issue-19692.rs +++ b/src/test/compile-fail/issue-19692.rs @@ -12,7 +12,7 @@ struct Homura; fn akemi(homura: Homura) { let Some(ref madoka) = Some(homura.kaname()); //~ ERROR does not implement any method - madoka.clone(); //~ ERROR the type of this value must be known + madoka.clone(); } fn main() { } diff --git a/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs new file mode 100644 index 0000000000000..0303954ce2a96 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs @@ -0,0 +1,28 @@ +// Copyright 2012 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. + +// Test that the call operator autoderefs when calling a bounded type parameter. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +fn call_with_2(x: &fn(int) -> int) -> int +{ + x(2) // look ma, no `*` +} + +fn subtract_22(x: int) -> int { x - 22 } + +pub fn main() { + let subtract_22: fn(int) -> int = subtract_22; + let z = call_with_2(&subtract_22); + assert_eq!(z, -20); +} diff --git a/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs new file mode 100644 index 0000000000000..305f496e668a8 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs @@ -0,0 +1,26 @@ +// Copyright 2012 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. + +// Test that the call operator autoderefs when calling a bounded type parameter. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +fn call_with_2(x: &mut F) -> int + where F : FnMut(int) -> int +{ + x(2) // look ma, no `*` +} + +pub fn main() { + let z = call_with_2(&mut |x| x - 22); + assert_eq!(z, -20); +} diff --git a/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs new file mode 100644 index 0000000000000..8909f4e261faa --- /dev/null +++ b/src/test/run-pass/unboxed-closures-call-sugar-object-autoderef.rs @@ -0,0 +1,27 @@ +// Copyright 2012 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. + +// Test that the call operator autoderefs when calling to an object type. + +#![feature(unboxed_closures)] + +use std::ops::FnMut; + +fn make_adder(x: int) -> Boxint + 'static> { + box move |y| { x + y } +} + +pub fn main() { + let mut adder = make_adder(3); + let z = adder(2); + println!("{}", z); + assert_eq!(z, 5); +} +