From 441b9940ecc2056f04065f8d08ae7cde8bdae684 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 13 Jul 2015 10:53:16 +0200 Subject: [PATCH 01/66] simplify processing of ConstVal objects when not all variants are legal --- src/librustc/middle/const_eval.rs | 52 ++++++++++++--------------- src/librustc/middle/ty.rs | 8 +---- src/test/compile-fail/repeat_count.rs | 45 ++++++++++++++--------- 3 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 7d54b8c284f1f..cf71c53e4032b 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -273,6 +273,22 @@ pub enum ConstVal { Tuple(ast::NodeId), } +impl ConstVal { + pub fn description(&self) -> &'static str { + match *self { + Float(_) => "float", + Int(i) if i < 0 => "negative integer", + Int(_) => "positive integer", + Uint(_) => "unsigned integer", + Str(_) => "string literal", + Binary(_) => "binary array", + Bool(_) => "boolean", + Struct(_) => "struct", + Tuple(_) => "tuple", + } + } +} + pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P { let pat = match expr.node { ast::ExprTup(ref exprs) => @@ -352,16 +368,8 @@ pub enum ErrKind { InvalidOpForFloats(ast::BinOp_), InvalidOpForIntUint(ast::BinOp_), InvalidOpForUintInt(ast::BinOp_), - NegateOnString, - NegateOnBoolean, - NegateOnBinary, - NegateOnStruct, - NegateOnTuple, - NotOnFloat, - NotOnString, - NotOnBinary, - NotOnStruct, - NotOnTuple, + NegateOn(ConstVal), + NotOn(ConstVal), NegateWithOverflow(i64), AddiWithOverflow(i64, i64), @@ -397,16 +405,8 @@ impl ConstEvalErr { InvalidOpForFloats(_) => "can't do this op on floats".into_cow(), InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(), InvalidOpForUintInt(..) => "can't do this op on a usize and isize".into_cow(), - NegateOnString => "negate on string".into_cow(), - NegateOnBoolean => "negate on boolean".into_cow(), - NegateOnBinary => "negate on binary literal".into_cow(), - NegateOnStruct => "negate on struct".into_cow(), - NegateOnTuple => "negate on tuple".into_cow(), - NotOnFloat => "not on float or string".into_cow(), - NotOnString => "not on float or string".into_cow(), - NotOnBinary => "not on binary literal".into_cow(), - NotOnStruct => "not on struct".into_cow(), - NotOnTuple => "not on tuple".into_cow(), + NegateOn(ref const_val) => format!("negate on {}", const_val.description()).into_cow(), + NotOn(ref const_val) => format!("not on {}", const_val.description()).into_cow(), NegateWithOverflow(..) => "attempted to negate with overflow".into_cow(), AddiWithOverflow(..) => "attempted to add with overflow".into_cow(), @@ -754,11 +754,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, } try!(const_uint_checked_neg(i, e, expr_uint_type)) } - Str(_) => signal!(e, NegateOnString), - Bool(_) => signal!(e, NegateOnBoolean), - Binary(_) => signal!(e, NegateOnBinary), - Tuple(_) => signal!(e, NegateOnTuple), - Struct(..) => signal!(e, NegateOnStruct), + const_val => signal!(e, NegateOn(const_val)), } } ast::ExprUnary(ast::UnNot, ref inner) => { @@ -766,11 +762,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, Int(i) => Int(!i), Uint(i) => const_uint_not(i, expr_uint_type), Bool(b) => Bool(!b), - Str(_) => signal!(e, NotOnString), - Float(_) => signal!(e, NotOnFloat), - Binary(_) => signal!(e, NotOnBinary), - Tuple(_) => signal!(e, NotOnTuple), - Struct(..) => signal!(e, NotOnStruct), + const_val => signal!(e, NotOn(const_val)), } } ast::ExprBinary(op, ref a, ref b) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index b4b8fbf2064ad..705e11f0597f1 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -6100,13 +6100,7 @@ impl<'tcx> ctxt<'tcx> { let found = match val { ConstVal::Uint(count) => return count as usize, ConstVal::Int(count) if count >= 0 => return count as usize, - ConstVal::Int(_) => "negative integer", - ConstVal::Float(_) => "float", - ConstVal::Str(_) => "string", - ConstVal::Bool(_) => "boolean", - ConstVal::Binary(_) => "binary array", - ConstVal::Struct(..) => "struct", - ConstVal::Tuple(_) => "tuple" + const_val => const_val.description(), }; span_err!(self.sess, count_expr.span, E0306, "expected positive integer for repeat count, found {}", diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs index 121581412202c..7a0623ba44f02 100644 --- a/src/test/compile-fail/repeat_count.rs +++ b/src/test/compile-fail/repeat_count.rs @@ -12,47 +12,58 @@ fn main() { let n = 1; - let a = [0; n]; //~ ERROR expected constant integer for repeat count, found variable + let a = [0; n]; + //~^ ERROR expected constant integer for repeat count, found variable [E0307] let b = [0; ()]; -//~^ ERROR mismatched types -//~| expected `usize` -//~| found `()` -//~| expected usize -//~| found () -//~| ERROR expected positive integer for repeat count, found tuple + //~^ ERROR mismatched types + //~| expected `usize` + //~| found `()` + //~| expected usize + //~| found ()) [E0308] + //~| ERROR expected positive integer for repeat count, found tuple [E0306] let c = [0; true]; //~^ ERROR mismatched types //~| expected `usize` //~| found `bool` //~| expected usize - //~| found bool - //~| ERROR expected positive integer for repeat count, found boolean + //~| found bool) [E0308] + //~| ERROR expected positive integer for repeat count, found boolean [E0306] let d = [0; 0.5]; //~^ ERROR mismatched types //~| expected `usize` //~| found `_` //~| expected usize - //~| found floating-point variable - //~| ERROR expected positive integer for repeat count, found float + //~| found floating-point variable) [E0308] + //~| ERROR expected positive integer for repeat count, found float [E0306] let e = [0; "foo"]; //~^ ERROR mismatched types //~| expected `usize` //~| found `&'static str` //~| expected usize - //~| found &-ptr - //~| ERROR expected positive integer for repeat count, found string + //~| found &-ptr) [E0308] + //~| ERROR expected positive integer for repeat count, found string literal [E0306] let f = [0; -4_isize]; //~^ ERROR mismatched types //~| expected `usize` //~| found `isize` //~| expected usize - //~| found isize - //~| ERROR expected positive integer for repeat count, found negative integer + //~| found isize) [E0308] + //~| ERROR expected positive integer for repeat count, found negative integer [E0306] let f = [0_usize; -1_isize]; //~^ ERROR mismatched types //~| expected `usize` //~| found `isize` //~| expected usize - //~| found isize - //~| ERROR expected positive integer for repeat count, found negative integer + //~| found isize) [E0308] + //~| ERROR expected positive integer for repeat count, found negative integer [E0306] + struct G { + g: (), + } + let g = [0; G { g: () }]; + //~^ ERROR mismatched types + //~| expected `usize` + //~| found `main::G` + //~| expected usize + //~| found struct `main::G`) [E0308] + //~| ERROR expected positive integer for repeat count, found struct [E0306] } From 0c9e3dc75cf2b2d122af0596225594240ed254eb Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 14 Jul 2015 01:03:24 +0300 Subject: [PATCH 02/66] Fix negate_unsigned feature gate check This commit fixes the negate_unsigned feature gate to appropriately account for infered variables. This is technically a [breaking-change]. --- src/libcore/fmt/num.rs | 2 -- src/libcore/ops.rs | 1 - src/libcoretest/fmt/num.rs | 2 -- src/librand/isaac.rs | 1 - src/librustc/middle/const_eval.rs | 9 ----- src/librustc_lint/builtin.rs | 34 +++++++++++-------- src/librustc_trans/trans/adt.rs | 2 -- src/librustc_typeck/check/mod.rs | 10 ------ src/libstd/num/f32.rs | 1 - src/libstd/num/uint_macros.rs | 1 - src/test/compile-fail/const-eval-overflow.rs | 9 ----- .../feature-gate-negate-unsigned.rs | 25 ++++++++++++-- src/test/compile-fail/lint-type-limits.rs | 11 ------ 13 files changed, 42 insertions(+), 66 deletions(-) diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index fc49f87d10769..ccdd23b868d24 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -12,8 +12,6 @@ // FIXME: #6220 Implement floating point formatting -#![allow(unsigned_negation)] - use prelude::*; use fmt; diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 76d3c1df15998..c2a9b8c8308cd 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -517,7 +517,6 @@ pub trait Neg { macro_rules! neg_impl_core { ($id:ident => $body:expr, $($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[allow(unsigned_negation)] impl Neg for $t { #[stable(feature = "rust1", since = "1.0.0")] type Output = $t; diff --git a/src/libcoretest/fmt/num.rs b/src/libcoretest/fmt/num.rs index cab2175f89781..247c3dcb9c705 100644 --- a/src/libcoretest/fmt/num.rs +++ b/src/libcoretest/fmt/num.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unsigned_negation)] - use core::fmt::radix; #[test] diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index ec9aa2d16d24a..1b2210c89edcb 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -126,7 +126,6 @@ impl IsaacRng { /// Refills the output buffer (`self.rsl`) #[inline] - #[allow(unsigned_negation)] fn isaac(&mut self) { self.c = self.c + w(1); // abbreviations diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 7d54b8c284f1f..0f16c06a9dbbc 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -9,7 +9,6 @@ // except according to those terms. #![allow(non_camel_case_types)] -#![allow(unsigned_negation)] use self::ConstVal::*; @@ -27,7 +26,6 @@ use util::num::ToPrimitive; use syntax::ast::{self, Expr}; use syntax::ast_util; use syntax::codemap::Span; -use syntax::feature_gate; use syntax::parse::token::InternedString; use syntax::ptr::P; use syntax::{codemap, visit}; @@ -745,13 +743,6 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, Float(f) => Float(-f), Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)), Uint(i) => { - if !tcx.sess.features.borrow().negate_unsigned { - feature_gate::emit_feature_err( - &tcx.sess.parse_sess.span_diagnostic, - "negate_unsigned", - e.span, - "unary negation of unsigned integers may be removed in the future"); - } try!(const_uint_checked_neg(i, e, expr_uint_type)) } Str(_) => signal!(e, NegateOnString), diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1574080b313b5..d158307478788 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -53,7 +53,7 @@ use syntax::{abi, ast}; use syntax::ast_util::{self, is_shift_binop, local_def}; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::{self, Span}; -use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; +use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType, emit_feature_err}; use syntax::parse::token; use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64}; use syntax::ptr::P; @@ -88,12 +88,6 @@ impl LintPass for WhileTrue { } } -declare_lint! { - UNSIGNED_NEGATION, - Warn, - "using an unary minus operator on unsigned type" -} - declare_lint! { UNUSED_COMPARISONS, Warn, @@ -128,8 +122,7 @@ impl TypeLimits { impl LintPass for TypeLimits { fn get_lints(&self) -> LintArray { - lint_array!(UNSIGNED_NEGATION, UNUSED_COMPARISONS, OVERFLOWING_LITERALS, - EXCEEDING_BITSHIFTS) + lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS) } fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { @@ -139,9 +132,12 @@ impl LintPass for TypeLimits { ast::ExprLit(ref lit) => { match lit.node { ast::LitInt(_, ast::UnsignedIntLit(_)) => { - cx.span_lint(UNSIGNED_NEGATION, e.span, - "negation of unsigned int literal may \ - be unintentional"); + check_unsigned_negation_feature(cx, e.span); + }, + ast::LitInt(_, ast::UnsuffixedIntLit(_)) => { + if let ty::TyUint(_) = cx.tcx.expr_ty(e).sty { + check_unsigned_negation_feature(cx, e.span); + } }, _ => () } @@ -150,9 +146,7 @@ impl LintPass for TypeLimits { let t = cx.tcx.expr_ty(&**expr); match t.sty { ty::TyUint(_) => { - cx.span_lint(UNSIGNED_NEGATION, e.span, - "negation of unsigned int variable may \ - be unintentional"); + check_unsigned_negation_feature(cx, e.span); }, _ => () } @@ -385,6 +379,16 @@ impl LintPass for TypeLimits { _ => false } } + + fn check_unsigned_negation_feature(cx: &Context, span: Span) { + if !cx.sess().features.borrow().negate_unsigned { + emit_feature_err( + &cx.sess().parse_sess.span_diagnostic, + "negate_unsigned", + span, + "unary negation of unsigned integers may be removed in the future"); + } + } } } diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 2b480abe3f1f3..7b2bdee50fe78 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -41,8 +41,6 @@ //! used unboxed and any field can have pointers (including mutable) //! taken to it, implementing them for Rust seems difficult. -#![allow(unsigned_negation)] - pub use self::Repr::*; use std::rc::Rc; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5a71d1ed0b5bd..887d01b439b4c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -114,7 +114,6 @@ use syntax::attr::AttrMetaMethods; use syntax::ast::{self, DefId, Visibility}; use syntax::ast_util::{self, local_def}; use syntax::codemap::{self, Span}; -use syntax::feature_gate; use syntax::owned_slice::OwnedSlice; use syntax::parse::token; use syntax::print::pprust; @@ -3074,15 +3073,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, tcx.lang_items.neg_trait(), expr, &**oprnd, oprnd_t, unop); } - if let ty::TyUint(_) = oprnd_t.sty { - if !tcx.sess.features.borrow().negate_unsigned { - feature_gate::emit_feature_err( - &tcx.sess.parse_sess.span_diagnostic, - "negate_unsigned", - expr.span, - "unary negation of unsigned integers may be removed in the future"); - } - } } } } diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index c2fb2fa417598..10cdc0c583377 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -12,7 +12,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#![allow(unsigned_negation)] #![doc(primitive = "f32")] use prelude::v1::*; diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 555a5cc3e20e9..902c78c0a46f8 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -9,7 +9,6 @@ // except according to those terms. #![doc(hidden)] -#![allow(unsigned_negation)] macro_rules! uint_module { ($T:ident) => ( diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs index 19b5f9b094c13..f991e5328c104 100644 --- a/src/test/compile-fail/const-eval-overflow.rs +++ b/src/test/compile-fail/const-eval-overflow.rs @@ -17,7 +17,6 @@ // evaluation below (e.g. that performed by trans and llvm), so if you // change this warn to a deny, then the compiler will exit before // those errors are detected. -#![warn(unsigned_negation)] use std::fmt; use std::{i8, i16, i32, i64, isize}; @@ -69,8 +68,6 @@ const VALS_I64: (i64, i64, i64, i64) = const VALS_U8: (u8, u8, u8, u8) = (-u8::MIN, - //~^ WARNING negation of unsigned int variable may be unintentional - // (The above is separately linted; unsigned negation is defined to be !x+1.) u8::MIN - 1, //~^ ERROR attempted to sub with overflow u8::MAX + 1, @@ -81,8 +78,6 @@ const VALS_U8: (u8, u8, u8, u8) = const VALS_U16: (u16, u16, u16, u16) = (-u16::MIN, - //~^ WARNING negation of unsigned int variable may be unintentional - // (The above is separately linted; unsigned negation is defined to be !x+1.) u16::MIN - 1, //~^ ERROR attempted to sub with overflow u16::MAX + 1, @@ -93,8 +88,6 @@ const VALS_U16: (u16, u16, u16, u16) = const VALS_U32: (u32, u32, u32, u32) = (-u32::MIN, - //~^ WARNING negation of unsigned int variable may be unintentional - // (The above is separately linted; unsigned negation is defined to be !x+1.) u32::MIN - 1, //~^ ERROR attempted to sub with overflow u32::MAX + 1, @@ -105,8 +98,6 @@ const VALS_U32: (u32, u32, u32, u32) = const VALS_U64: (u64, u64, u64, u64) = (-u64::MIN, - //~^ WARNING negation of unsigned int variable may be unintentional - // (The above is separately linted; unsigned negation is defined to be !x+1.) u64::MIN - 1, //~^ ERROR attempted to sub with overflow u64::MAX + 1, diff --git a/src/test/compile-fail/feature-gate-negate-unsigned.rs b/src/test/compile-fail/feature-gate-negate-unsigned.rs index 7dc654fe1c8d5..b1c73fab4ffa6 100644 --- a/src/test/compile-fail/feature-gate-negate-unsigned.rs +++ b/src/test/compile-fail/feature-gate-negate-unsigned.rs @@ -11,7 +11,28 @@ // Test that negating unsigned integers is gated by `negate_unsigned` feature // gate -const MAX: usize = -1; +struct S; +impl std::ops::Neg for S { + type Output = u32; + fn neg(self) -> u32 { 0 } +} + +const _MAX: usize = -1; //~^ ERROR unary negation of unsigned integers may be removed in the future -fn main() {} +fn main() { + let a = -1; + //~^ ERROR unary negation of unsigned integers may be removed in the future + let _b : u8 = a; // for infering variable a to u8. + + -a; + //~^ ERROR unary negation of unsigned integers may be removed in the future + + let _d = -1u8; + //~^ ERROR unary negation of unsigned integers may be removed in the future + + for _ in -10..10u8 {} + //~^ ERROR unary negation of unsigned integers may be removed in the future + + -S; // should not trigger the gate; issue 26840 +} diff --git a/src/test/compile-fail/lint-type-limits.rs b/src/test/compile-fail/lint-type-limits.rs index 42515e0f00c76..839d50ae63f90 100644 --- a/src/test/compile-fail/lint-type-limits.rs +++ b/src/test/compile-fail/lint-type-limits.rs @@ -50,14 +50,3 @@ fn qux() { i += 1; } } - -fn quy() { - let i = -23_usize; //~ WARNING negation of unsigned int literal may be unintentional - //~^ WARNING unused variable -} - -fn quz() { - let i = 23_usize; - let j = -i; //~ WARNING negation of unsigned int variable may be unintentional - //~^ WARNING unused variable -} From 22502154e6c1aee835554216d4b5054fd8f570f8 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 15 Jul 2015 20:12:30 +0300 Subject: [PATCH 03/66] =?UTF-8?q?Implement=20lint=20deprecation/removal?= =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and deprecate/remove unsigned_negation lint. This is useful to avoid causing breaking changes in case #![deny(unknown_lints)] is used and lint is removed. --- src/librustc/lint/context.rs | 42 +++++++++++++++++++++++++++--------- src/librustc_lint/lib.rs | 2 ++ 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 567be56b17f29..6d29a1031c6bc 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -75,6 +75,15 @@ enum TargetLint { /// Temporary renaming, used for easing migration pain; see #16545 Renamed(String, LintId), + + /// Lint with this name existed previously, but has been removed/deprecated. + /// The string argument is the reason for removal. + Removed(String), +} + +enum FindLintError { + NotFound, + Removed } impl LintStore { @@ -166,12 +175,16 @@ impl LintStore { self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target)); } + pub fn register_removed(&mut self, name: &str, reason: &str) { + self.by_name.insert(name.into(), Removed(reason.into())); + } + #[allow(unused_variables)] fn find_lint(&self, lint_name: &str, sess: &Session, span: Option) - -> Option + -> Result { match self.by_name.get(lint_name) { - Some(&Id(lint_id)) => Some(lint_id), + Some(&Id(lint_id)) => Ok(lint_id), Some(&Renamed(ref new_name, lint_id)) => { let warning = format!("lint {} has been renamed to {}", lint_name, new_name); @@ -179,17 +192,25 @@ impl LintStore { Some(span) => sess.span_warn(span, &warning[..]), None => sess.warn(&warning[..]), }; - Some(lint_id) - } - None => None + Ok(lint_id) + }, + Some(&Removed(ref reason)) => { + let warning = format!("lint {} has been removed: {}", lint_name, reason); + match span { + Some(span) => sess.span_warn(span, &warning[..]), + None => sess.warn(&warning[..]) + } + Err(FindLintError::Removed) + }, + None => Err(FindLintError::NotFound) } } pub fn process_command_line(&mut self, sess: &Session) { for &(ref lint_name, level) in &sess.opts.lint_opts { match self.find_lint(&lint_name[..], sess, None) { - Some(lint_id) => self.set_level(lint_id, (level, CommandLine)), - None => { + Ok(lint_id) => self.set_level(lint_id, (level, CommandLine)), + Err(_) => { match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone())) .collect::>>() @@ -398,8 +419,8 @@ impl<'a, 'tcx> Context<'a, 'tcx> { } Ok((lint_name, level, span)) => { match self.lints.find_lint(&lint_name, &self.tcx.sess, Some(span)) { - Some(lint_id) => vec![(lint_id, level, span)], - None => { + Ok(lint_id) => vec![(lint_id, level, span)], + Err(FindLintError::NotFound) => { match self.lints.lint_groups.get(&lint_name[..]) { Some(&(ref v, _)) => v.iter() .map(|lint_id: &LintId| @@ -412,7 +433,8 @@ impl<'a, 'tcx> Context<'a, 'tcx> { continue; } } - } + }, + Err(FindLintError::Removed) => { continue; } } } }; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c680906dd135b..54c1a79e10a9b 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -134,4 +134,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { store.register_renamed("raw_pointer_deriving", "raw_pointer_derive"); store.register_renamed("unknown_features", "unused_features"); + + store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); } From ccf90509b8cb211da8aa6a13a877c06d257fc346 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 17 Jul 2015 23:35:41 +0530 Subject: [PATCH 04/66] Don't recurse down closures for duplicate-label checking --- src/librustc/middle/resolve_lifetime.rs | 6 ++++++ src/test/run-pass/issue-25343.rs | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/run-pass/issue-25343.rs diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 9e5ad7b42f5c5..510f1a2a2c9d8 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -372,6 +372,12 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v ast::Block) { impl<'v, 'a> Visitor<'v> for GatherLabels<'a> { fn visit_expr(&mut self, ex: &'v ast::Expr) { + // do not recurse into closures defined in the block + // since they are treated as separate fns from the POV of + // labels_in_fn + if let ast::ExprClosure(..) = ex.node { + return + } if let Some(label) = expression_label(ex) { for &(prior, prior_span) in &self.labels_in_fn[..] { // FIXME (#24278): non-hygienic comparison diff --git a/src/test/run-pass/issue-25343.rs b/src/test/run-pass/issue-25343.rs new file mode 100644 index 0000000000000..9e01d577276b8 --- /dev/null +++ b/src/test/run-pass/issue-25343.rs @@ -0,0 +1,16 @@ +// Copyright 2015 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. + +fn main() { + || { + 'label: loop { + } + }; +} From 6bdfb0534737b371e3b3e4abdec2f5dffd629916 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Tue, 30 Jun 2015 08:53:50 -0700 Subject: [PATCH 05/66] Clarify the usage of "hints" in const_eval. The "hint" mechanism is essentially used as a workaround to compute types for expressions which have not yet been type-checked. This commit clarifies that usage, and limits the effects to the places where it is currently necessary. Fixes #26210. --- src/librustc/diagnostics.rs | 18 ++ src/librustc/middle/check_const.rs | 18 +- src/librustc/middle/check_match.rs | 3 +- src/librustc/middle/const_eval.rs | 171 ++++++++++++------ src/librustc/middle/ty.rs | 20 +- src/librustc_lint/builtin.rs | 3 +- src/librustc_trans/trans/_match.rs | 3 +- src/librustc_trans/trans/consts.rs | 4 +- src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/_match.rs | 15 +- src/librustc_typeck/diagnostics.rs | 18 -- .../compile-fail/lint-exceeding-bitshifts.rs | 6 +- src/test/compile-fail/match-range-fail-2.rs | 23 +++ src/test/compile-fail/match-range-fail.rs | 6 - 14 files changed, 194 insertions(+), 118 deletions(-) create mode 100644 src/test/compile-fail/match-range-fail-2.rs diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 4b77c211df983..4e21efcf9eb6b 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -335,6 +335,24 @@ This error indicates that an attempt was made to divide by zero (or take the remainder of a zero divisor) in a static or constant expression. "##, +E0030: r##" +When matching against a range, the compiler verifies that the range is +non-empty. Range patterns include both end-points, so this is equivalent to +requiring the start of the range to be less than or equal to the end of the +range. + +For example: + +``` +match 5u32 { + // This range is ok, albeit pointless. + 1 ... 1 => ... + // This range is empty, and the compiler can tell. + 1000 ... 5 => ... +} +``` +"##, + E0079: r##" Enum variants which contain no data can be given a custom integer representation. This error indicates that the value provided is not an diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 59f91a50f7421..baaf6b6a0401d 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -26,6 +26,7 @@ use middle::cast::{CastKind}; use middle::const_eval; +use middle::const_eval::EvalHint::ExprTypeChecked; use middle::def; use middle::expr_use_visitor as euv; use middle::infer; @@ -39,6 +40,7 @@ use syntax::codemap::Span; use syntax::visit::{self, Visitor}; use std::collections::hash_map::Entry; +use std::cmp::Ordering; // Const qualification, from partial to completely promotable. bitflags! { @@ -365,6 +367,19 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { ast::PatRange(ref start, ref end) => { self.global_expr(Mode::Const, &**start); self.global_expr(Mode::Const, &**end); + + match const_eval::compare_lit_exprs(self.tcx, start, end) { + Some(Ordering::Less) | + Some(Ordering::Equal) => {} + Some(Ordering::Greater) => { + span_err!(self.tcx.sess, start.span, E0030, + "lower range bound must be less than or equal to upper"); + } + None => { + self.tcx.sess.span_bug( + start.span, "literals of different types in range pat"); + } + } } _ => visit::walk_pat(self, p) } @@ -457,7 +472,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { match node_ty.sty { ty::TyUint(_) | ty::TyInt(_) if div_or_rem => { if !self.qualif.intersects(ConstQualif::NOT_CONST) { - match const_eval::eval_const_expr_partial(self.tcx, ex, None) { + match const_eval::eval_const_expr_partial( + self.tcx, ex, ExprTypeChecked) { Ok(_) => {} Err(msg) => { span_err!(self.tcx.sess, msg.span, E0020, diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index fc2444ed5b45c..d8c2341df2d9f 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -15,6 +15,7 @@ use self::WitnessPreference::*; use middle::const_eval::{compare_const_vals, ConstVal}; use middle::const_eval::{eval_const_expr, eval_const_expr_partial}; use middle::const_eval::{const_expr_to_pat, lookup_const_by_id}; +use middle::const_eval::EvalHint::ExprTypeChecked; use middle::def::*; use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Init}; use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode}; @@ -263,7 +264,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) { ast_util::walk_pat(pat, |p| { if let ast::PatLit(ref expr) = p.node { - match eval_const_expr_partial(cx.tcx, &**expr, None) { + match eval_const_expr_partial(cx.tcx, &**expr, ExprTypeChecked) { Ok(ConstVal::Float(f)) if f.is_nan() => { span_warn!(cx.tcx.sess, p.span, E0003, "unmatchable NaN in pattern, \ diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 7d54b8c284f1f..77d42046f1954 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -12,8 +12,8 @@ #![allow(unsigned_negation)] use self::ConstVal::*; - use self::ErrKind::*; +use self::EvalHint::*; use ast_map; use ast_map::blocks::FnLikeNode; @@ -331,7 +331,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P } pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal { - match eval_const_expr_partial(tcx, e, None) { + match eval_const_expr_partial(tcx, e, ExprTypeChecked) { Ok(r) => r, Err(s) => tcx.sess.span_fatal(s.span, &s.description()) } @@ -436,6 +436,28 @@ impl ConstEvalErr { pub type EvalResult = Result; pub type CastResult = Result; +// FIXME: Long-term, this enum should go away: trying to evaluate +// an expression which hasn't been type-checked is a recipe for +// disaster. That said, it's not clear how to fix ast_ty_to_ty +// to avoid the ordering issue. + +/// Hint to determine how to evaluate constant expressions which +/// might not be type-checked. +#[derive(Copy, Clone, Debug)] +pub enum EvalHint<'tcx> { + /// We have a type-checked expression. + ExprTypeChecked, + /// We have an expression which hasn't been type-checked, but we have + /// an idea of what the type will be because of the context. For example, + /// the length of an array is always `usize`. (This is referred to as + /// a hint because it isn't guaranteed to be consistent with what + /// type-checking would compute.) + UncheckedExprHint(Ty<'tcx>), + /// We have an expression which has not yet been type-checked, and + /// and we have no clue what the type will be. + UncheckedExprNoHint, +} + #[derive(Copy, Clone, PartialEq, Debug)] pub enum IntTy { I8, I16, I32, I64 } #[derive(Copy, Clone, PartialEq, Debug)] @@ -706,26 +728,34 @@ pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) { uint_shift_body overflowing_shr Uint ShiftRightWithOverflow }} -// After type checking, `eval_const_expr_partial` should always suffice. The -// reason for providing `eval_const_expr_with_substs` is to allow -// trait-associated consts to be evaluated *during* type checking, when the -// substs for each expression have not been written into `tcx` yet. +/// Evaluate a constant expression in a context where the expression isn't +/// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked, +/// but a few places need to evaluate constants during type-checking, like +/// computing the length of an array. (See also the FIXME above EvalHint.) pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, e: &Expr, - ty_hint: Option>) -> EvalResult { - eval_const_expr_with_substs(tcx, e, ty_hint, |id| { - tcx.node_id_item_substs(id).substs - }) -} - -pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, - e: &Expr, - ty_hint: Option>, - get_substs: S) -> EvalResult - where S: Fn(ast::NodeId) -> subst::Substs<'tcx> { + ty_hint: EvalHint<'tcx>) -> EvalResult { fn fromb(b: bool) -> ConstVal { Int(b as i64) } - let ety = ty_hint.or_else(|| tcx.expr_ty_opt(e)); + // Try to compute the type of the expression based on the EvalHint. + // (See also the definition of EvalHint, and the FIXME above EvalHint.) + let ety = match ty_hint { + ExprTypeChecked => { + // After type-checking, expr_ty is guaranteed to succeed. + Some(tcx.expr_ty(e)) + } + UncheckedExprHint(ty) => { + // Use the type hint; it's not guaranteed to be right, but it's + // usually good enough. + Some(ty) + } + UncheckedExprNoHint => { + // This expression might not be type-checked, and we have no hint. + // Try to query the context for a type anyway; we might get lucky + // (for example, if the expression was imported from another crate). + tcx.expr_ty_opt(e) + } + }; // If type of expression itself is int or uint, normalize in these // bindings so that isize/usize is mapped to a type with an @@ -741,7 +771,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, let result = match e.node { ast::ExprUnary(ast::UnNeg, ref inner) => { - match try!(eval_const_expr_partial(tcx, &**inner, ety)) { + match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) { Float(f) => Float(-f), Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)), Uint(i) => { @@ -762,7 +792,7 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, } } ast::ExprUnary(ast::UnNot, ref inner) => { - match try!(eval_const_expr_partial(tcx, &**inner, ety)) { + match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) { Int(i) => Int(!i), Uint(i) => const_uint_not(i, expr_uint_type), Bool(b) => Bool(!b), @@ -775,10 +805,16 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, } ast::ExprBinary(op, ref a, ref b) => { let b_ty = match op.node { - ast::BiShl | ast::BiShr => Some(tcx.types.usize), - _ => ety + ast::BiShl | ast::BiShr => { + if let ExprTypeChecked = ty_hint { + ExprTypeChecked + } else { + UncheckedExprHint(tcx.types.usize) + } + } + _ => ty_hint }; - match (try!(eval_const_expr_partial(tcx, &**a, ety)), + match (try!(eval_const_expr_partial(tcx, &**a, ty_hint)), try!(eval_const_expr_partial(tcx, &**b, b_ty))) { (Float(a), Float(b)) => { match op.node { @@ -868,22 +904,25 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, } } ast::ExprCast(ref base, ref target_ty) => { - // This tends to get called w/o the type actually having been - // populated in the ctxt, which was causing things to blow up - // (#5900). Fall back to doing a limited lookup to get past it. let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &**target_ty)) .unwrap_or_else(|| { tcx.sess.span_fatal(target_ty.span, "target type not found for const cast") }); - // Prefer known type to noop, but always have a type hint. - // - // FIXME (#23833): the type-hint can cause problems, - // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result - // type to the sum, and thus no overflow is signaled. - let base_hint = tcx.expr_ty_opt(&**base).unwrap_or(ety); - let val = try!(eval_const_expr_partial(tcx, &**base, Some(base_hint))); + let base_hint = if let ExprTypeChecked = ty_hint { + ExprTypeChecked + } else { + // FIXME (#23833): the type-hint can cause problems, + // e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result + // type to the sum, and thus no overflow is signaled. + match tcx.expr_ty_opt(&base) { + Some(t) => UncheckedExprHint(t), + None => ty_hint + } + }; + + let val = try!(eval_const_expr_partial(tcx, &**base, base_hint)); match cast_const(tcx, val, ety) { Ok(val) => val, Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }), @@ -913,12 +952,16 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, def::FromTrait(trait_id) => match tcx.map.find(def_id.node) { Some(ast_map::NodeTraitItem(ti)) => match ti.node { ast::ConstTraitItem(ref ty, _) => { - let substs = get_substs(e.id); - (resolve_trait_associated_const(tcx, - ti, - trait_id, - substs), - Some(&**ty)) + if let ExprTypeChecked = ty_hint { + let substs = tcx.node_id_item_substs(e.id).substs; + (resolve_trait_associated_const(tcx, + ti, + trait_id, + substs), + Some(&**ty)) + } else { + (None, None) + } } _ => (None, None) }, @@ -947,27 +990,42 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, Some(actual_e) => actual_e, None => signal!(e, NonConstPath) }; - let ety = ety.or_else(|| const_ty.and_then(|ty| ast_ty_to_prim_ty(tcx, ty))); - try!(eval_const_expr_partial(tcx, const_expr, ety)) + let item_hint = if let UncheckedExprNoHint = ty_hint { + match const_ty { + Some(ty) => match ast_ty_to_prim_ty(tcx, ty) { + Some(ty) => UncheckedExprHint(ty), + None => UncheckedExprNoHint + }, + None => UncheckedExprNoHint + } + } else { + ty_hint + }; + try!(eval_const_expr_partial(tcx, const_expr, item_hint)) } ast::ExprLit(ref lit) => { lit_to_const(&**lit, ety) } - ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ety)), + ast::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ty_hint)), ast::ExprBlock(ref block) => { match block.expr { - Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ety)), + Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint)), None => Int(0) } } ast::ExprTup(_) => Tuple(e.id), ast::ExprStruct(..) => Struct(e.id), ast::ExprTupField(ref base, index) => { - if let Ok(c) = eval_const_expr_partial(tcx, base, None) { + let base_hint = if let ExprTypeChecked = ty_hint { + ExprTypeChecked + } else { + UncheckedExprNoHint + }; + if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) { if let Tuple(tup_id) = c { if let ast::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node { if index.node < fields.len() { - return eval_const_expr_partial(tcx, &fields[index.node], None) + return eval_const_expr_partial(tcx, &fields[index.node], base_hint) } else { signal!(e, TupleIndexOutOfBounds); } @@ -983,13 +1041,18 @@ pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>, } ast::ExprField(ref base, field_name) => { // Get the base expression if it is a struct and it is constant - if let Ok(c) = eval_const_expr_partial(tcx, base, None) { + let base_hint = if let ExprTypeChecked = ty_hint { + ExprTypeChecked + } else { + UncheckedExprNoHint + }; + if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) { if let Struct(struct_id) = c { if let ast::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node { // Check that the given field exists and evaluate it if let Some(f) = fields.iter().find(|f| f.ident.node.as_str() == field_name.node.as_str()) { - return eval_const_expr_partial(tcx, &*f.expr, None) + return eval_const_expr_partial(tcx, &*f.expr, base_hint) } else { signal!(e, MissingStructField); } @@ -1165,21 +1228,17 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option { }) } -pub fn compare_lit_exprs<'tcx, S>(tcx: &ty::ctxt<'tcx>, - a: &Expr, - b: &Expr, - ty_hint: Option>, - get_substs: S) -> Option - where S: Fn(ast::NodeId) -> subst::Substs<'tcx> { - let a = match eval_const_expr_with_substs(tcx, a, ty_hint, - |id| {get_substs(id)}) { +pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>, + a: &Expr, + b: &Expr) -> Option { + let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked) { Ok(a) => a, Err(e) => { tcx.sess.span_err(a.span, &e.description()); return None; } }; - let b = match eval_const_expr_with_substs(tcx, b, ty_hint, get_substs) { + let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked) { Ok(b) => b, Err(e) => { tcx.sess.span_err(b.span, &e.description()); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ef337b4163051..ef4dff68a38c4 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -45,6 +45,7 @@ use middle; use middle::cast; use middle::check_const; use middle::const_eval::{self, ConstVal}; +use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def::{self, DefMap, ExportMap}; use middle::dependency_format; use middle::fast_reject; @@ -5758,20 +5759,8 @@ impl<'tcx> ctxt<'tcx> { Some(ref e) => { debug!("disr expr, checking {}", pprust::expr_to_string(&**e)); - // check_expr (from check_const pass) doesn't guarantee - // that the expression is in a form that eval_const_expr can - // handle, so we may still get an internal compiler error - // - // pnkfelix: The above comment was transcribed from - // the version of this code taken from rustc_typeck. - // Presumably the implication is that we need to deal - // with such ICE's as they arise. - // - // Since this can be called from `ty::enum_variants` - // anyway, best thing is to make `eval_const_expr` - // more robust (on case-by-case basis). - - match const_eval::eval_const_expr_partial(self, &**e, Some(repr_type_ty)) { + let hint = UncheckedExprHint(repr_type_ty); + match const_eval::eval_const_expr_partial(self, &**e, hint) { Ok(ConstVal::Int(val)) => current_disr_val = val as Disr, Ok(ConstVal::Uint(val)) => current_disr_val = val as Disr, Ok(_) => { @@ -6086,7 +6075,8 @@ impl<'tcx> ctxt<'tcx> { // Returns the repeat count for a repeating vector expression. pub fn eval_repeat_count(&self, count_expr: &ast::Expr) -> usize { - match const_eval::eval_const_expr_partial(self, count_expr, Some(self.types.usize)) { + let hint = UncheckedExprHint(self.types.usize); + match const_eval::eval_const_expr_partial(self, count_expr, hint) { Ok(val) => { let found = match val { ConstVal::Uint(count) => return count as usize, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1574080b313b5..9529025b60ff5 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -39,6 +39,7 @@ use middle::ty::{self, Ty}; use middle::traits; use middle::{def, pat_util, stability}; use middle::const_eval::{eval_const_expr_partial, ConstVal}; +use middle::const_eval::EvalHint::ExprTypeChecked; use middle::cfg; use rustc::ast_map; use util::nodemap::{FnvHashMap, NodeSet}; @@ -184,7 +185,7 @@ impl LintPass for TypeLimits { if let ast::LitInt(shift, _) = lit.node { shift >= bits } else { false } } else { - match eval_const_expr_partial(cx.tcx, &**r, Some(cx.tcx.types.usize)) { + match eval_const_expr_partial(cx.tcx, &**r, ExprTypeChecked) { Ok(ConstVal::Int(shift)) => { shift as u64 >= bits }, Ok(ConstVal::Uint(shift)) => { shift >= bits }, _ => { false } diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 9a9b9c617a853..925da81d77e6b 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -235,8 +235,7 @@ struct ConstantExpr<'a>(&'a ast::Expr); impl<'a> ConstantExpr<'a> { fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool { - match const_eval::compare_lit_exprs(tcx, self.0, other.0, None, - |id| {tcx.node_id_item_substs(id).substs}) { + match const_eval::compare_lit_exprs(tcx, self.0, other.0) { Some(result) => result == Ordering::Equal, None => panic!("compare_list_exprs: type mismatch"), } diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 242eceb8335b2..302ef68bddc7d 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -23,6 +23,8 @@ use middle::const_eval::{const_int_checked_div, const_uint_checked_div}; use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem}; use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl}; use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr}; +use middle::const_eval::EvalHint::ExprTypeChecked; +use middle::const_eval::eval_const_expr_partial; use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::base::{self, push_ctxt}; use trans::common::*; @@ -591,7 +593,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ast::ExprIndex(ref base, ref index) => { let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); - let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) { + let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked) { Ok(ConstVal::Int(i)) => i as u64, Ok(ConstVal::Uint(u)) => u, _ => cx.sess().span_bug(index.span, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3bb3a63004153..0343b14accff9 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -50,6 +50,7 @@ use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS}; use middle::const_eval::{self, ConstVal}; +use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def; use middle::implicator::object_region_bounds; use middle::resolve_lifetime as rl; @@ -1627,7 +1628,8 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, ty } ast::TyFixedLengthVec(ref ty, ref e) => { - match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.usize)) { + let hint = UncheckedExprHint(tcx.types.usize); + match const_eval::eval_const_expr_partial(tcx, &e, hint) { Ok(r) => { match r { ConstVal::Int(i) => diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index a995401cf5c81..c4b31d578dbfd 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::const_eval; use middle::def; use middle::infer; use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; @@ -23,7 +22,7 @@ use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_typ use require_same_types; use util::nodemap::FnvHashMap; -use std::cmp::{self, Ordering}; +use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::ast; use syntax::ast_util; @@ -130,18 +129,6 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, fcx.write_ty(pat.id, common_type); - // Finally we evaluate the constants and check that the range is non-empty. - let get_substs = |id| fcx.item_substs()[&id].substs.clone(); - match const_eval::compare_lit_exprs(tcx, begin, end, Some(&common_type), get_substs) { - Some(Ordering::Less) | - Some(Ordering::Equal) => {} - Some(Ordering::Greater) => { - span_err!(tcx.sess, begin.span, E0030, - "lower range bound must be less than or equal to upper"); - } - None => tcx.sess.span_bug(begin.span, "literals of different types in range pat") - } - // subtyping doesn't matter here, as the value is some kind of scalar demand::eqtype(fcx, pat.span, expected, lhs_ty); } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ed04fde463c92..6263adf200ff5 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -169,24 +169,6 @@ match string { ``` "##, -E0030: r##" -When matching against a range, the compiler verifies that the range is -non-empty. Range patterns include both end-points, so this is equivalent to -requiring the start of the range to be less than or equal to the end of the -range. - -For example: - -``` -match 5u32 { - // This range is ok, albeit pointless. - 1 ... 1 => ... - // This range is empty, and the compiler can tell. - 1000 ... 5 => ... -} -``` -"##, - E0033: r##" This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a pattern. Every trait defines a type, but because the diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs index 5867bc2f09deb..160551b81cb2e 100644 --- a/src/test/compile-fail/lint-exceeding-bitshifts.rs +++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(negate_unsigned)] #![deny(exceeding_bitshifts)] #![allow(unused_variables)] #![allow(dead_code)] -#![feature(num_bits_bytes, negate_unsigned)] +#![feature(num_bits_bytes)] fn main() { let n = 1u8 << 7; @@ -60,4 +59,7 @@ fn main() { let n = 1_isize << std::isize::BITS; //~ ERROR: bitshift exceeds the type's number of bits let n = 1_usize << std::usize::BITS; //~ ERROR: bitshift exceeds the type's number of bits + + + let n = 1i8<<(1isize+-1); } diff --git a/src/test/compile-fail/match-range-fail-2.rs b/src/test/compile-fail/match-range-fail-2.rs new file mode 100644 index 0000000000000..e30f783ce3637 --- /dev/null +++ b/src/test/compile-fail/match-range-fail-2.rs @@ -0,0 +1,23 @@ +// Copyright 2015 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. + +fn main() { + match 5 { + 6 ... 1 => { } + _ => { } + }; + //~^^^ ERROR lower range bound must be less than or equal to upper + + match 5u64 { + 0xFFFF_FFFF_FFFF_FFFF ... 1 => { } + _ => { } + }; + //~^^^ ERROR lower range bound must be less than or equal to upper +} diff --git a/src/test/compile-fail/match-range-fail.rs b/src/test/compile-fail/match-range-fail.rs index 234b74f76d1e0..05b870b8f41cc 100644 --- a/src/test/compile-fail/match-range-fail.rs +++ b/src/test/compile-fail/match-range-fail.rs @@ -9,12 +9,6 @@ // except according to those terms. fn main() { - match 5 { - 6 ... 1 => { } - _ => { } - }; - //~^^^ ERROR lower range bound must be less than or equal to upper - match "wow" { "bar" ... "foo" => { } }; From 456770472b07a8fe2e3d02bfc12b619d48935df2 Mon Sep 17 00:00:00 2001 From: William Throwe Date: Sat, 18 Jul 2015 02:02:57 -0400 Subject: [PATCH 06/66] Fix rustdoc formatting of impls Some cases displayed negative impls as positive, and some were missing where clauses. This factors all the impl formatting into one function so the different cases can't get out of sync again. --- src/librustdoc/html/format.rs | 13 +++++++++++++ src/librustdoc/html/render.rs | 29 +++++------------------------ 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index fc06dc347b5ed..2255a2e969f1a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -540,6 +540,19 @@ impl fmt::Display for clean::Type { } } +impl fmt::Display for clean::Impl { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "impl{} ", self.generics)); + if let Some(ref ty) = self.trait_ { + try!(write!(f, "{}{} for ", + if self.polarity == Some(clean::ImplPolarity::Negative) { "!" } else { "" }, + *ty)); + } + try!(write!(f, "{}{}", self.for_, WhereClause(&self.generics))); + Ok(()) + } +} + impl fmt::Display for clean::Arguments { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (i, input) in self.values.iter().enumerate() { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 07e3ae975d66d..57c0db8f96e66 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -118,11 +118,8 @@ pub enum ExternalLocation { /// Metadata about an implementor of a trait. pub struct Implementor { pub def_id: ast::DefId, - pub generics: clean::Generics, - pub trait_: clean::Type, - pub for_: clean::Type, pub stability: Option, - pub polarity: Option, + pub impl_: clean::Impl, } /// Metadata about implementations for a type. @@ -644,10 +641,7 @@ fn write_shared(cx: &Context, // going on). If they're in different crates then the crate defining // the trait will be interested in our implementation. if imp.def_id.krate == did.krate { continue } - try!(write!(&mut f, r#""impl{} {}{} for {}","#, - imp.generics, - if imp.polarity == Some(clean::ImplPolarity::Negative) { "!" } else { "" }, - imp.trait_, imp.for_)); + try!(write!(&mut f, r#""{}","#, imp.impl_)); } try!(writeln!(&mut f, r"];")); try!(writeln!(&mut f, "{}", r" @@ -888,11 +882,8 @@ impl DocFolder for Cache { Some(clean::ResolvedPath{ did, .. }) => { self.implementors.entry(did).or_insert(vec![]).push(Implementor { def_id: item.def_id, - generics: i.generics.clone(), - trait_: i.trait_.as_ref().unwrap().clone(), - for_: i.for_.clone(), stability: item.stability.clone(), - polarity: i.polarity.clone(), + impl_: i.clone(), }); } Some(..) | None => {} @@ -1910,8 +1901,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, match cache.implementors.get(&it.def_id) { Some(implementors) => { for i in implementors { - try!(writeln!(w, "
  • impl{} {} for {}{}
  • ", - i.generics, i.trait_, i.for_, WhereClause(&i.generics))); + try!(writeln!(w, "
  • {}
  • ", i.impl_)); } } None => {} @@ -2335,16 +2325,7 @@ fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result { fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink, render_header: bool) -> fmt::Result { if render_header { - try!(write!(w, "

    impl{} ", - i.impl_.generics)); - if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity { - try!(write!(w, "!")); - } - if let Some(ref ty) = i.impl_.trait_ { - try!(write!(w, "{} for ", *ty)); - } - try!(write!(w, "{}{}

    ", i.impl_.for_, - WhereClause(&i.impl_.generics))); + try!(write!(w, "

    {}

    ", i.impl_)); if let Some(ref dox) = i.dox { try!(write!(w, "
    {}
    ", Markdown(dox))); } From a219917e3f762af49f5ccf7a0975122e04f9d764 Mon Sep 17 00:00:00 2001 From: Lee Jeffery Date: Wed, 15 Jul 2015 19:57:47 +0100 Subject: [PATCH 07/66] Fix doc comment parsing in macros. --- src/libcore/str/mod.rs | 20 ++++----- src/libsyntax/ast.rs | 18 ++++++-- src/test/parse-fail/macro-doc-comments-1.rs | 19 +++++++++ src/test/parse-fail/macro-doc-comments-2.rs | 19 +++++++++ src/test/run-pass/macro-doc-comments.rs | 33 +++++++++++++++ src/test/rustdoc/issue-23812.rs | 46 +++++++++++++++++++++ 6 files changed, 142 insertions(+), 13 deletions(-) create mode 100644 src/test/parse-fail/macro-doc-comments-1.rs create mode 100644 src/test/parse-fail/macro-doc-comments-2.rs create mode 100644 src/test/run-pass/macro-doc-comments.rs create mode 100644 src/test/rustdoc/issue-23812.rs diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 7e4c2ba3be875..8683689bbbe24 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -636,10 +636,10 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.split()`."] + /// Created with the method `.split()`. struct Split; reverse: - #[doc="Created with the method `.rsplit()`."] + /// Created with the method `.rsplit()`. struct RSplit; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -650,10 +650,10 @@ generate_pattern_iterators! { generate_pattern_iterators! { forward: - #[doc="Created with the method `.split_terminator()`."] + /// Created with the method `.split_terminator()`. struct SplitTerminator; reverse: - #[doc="Created with the method `.rsplit_terminator()`."] + /// Created with the method `.rsplit_terminator()`. struct RSplitTerminator; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -696,10 +696,10 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.splitn()`."] + /// Created with the method `.splitn()`. struct SplitN; reverse: - #[doc="Created with the method `.rsplitn()`."] + /// Created with the method `.rsplitn()`. struct RSplitN; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -730,10 +730,10 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.match_indices()`."] + /// Created with the method `.match_indices()`. struct MatchIndices; reverse: - #[doc="Created with the method `.rmatch_indices()`."] + /// Created with the method `.rmatch_indices()`. struct RMatchIndices; stability: #[unstable(feature = "str_match_indices", @@ -771,10 +771,10 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.matches()`."] + /// Created with the method `.matches()`. struct Matches; reverse: - #[doc="Created with the method `.rmatches()`."] + /// Created with the method `.rmatches()`. struct RMatches; stability: #[stable(feature = "str_matches", since = "1.2.0")] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a944acad84df1..a0059d33bed84 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -63,6 +63,7 @@ use owned_slice::OwnedSlice; use parse::token::{InternedString, str_to_ident}; use parse::token; use parse::lexer; +use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use print::pprust; use ptr::P; @@ -1079,7 +1080,12 @@ pub enum TokenTree { impl TokenTree { pub fn len(&self) -> usize { match *self { - TtToken(_, token::DocComment(_)) => 2, + TtToken(_, token::DocComment(name)) => { + match doc_comment_style(name.as_str()) { + AttrOuter => 2, + AttrInner => 3 + } + } TtToken(_, token::SpecialVarNt(..)) => 2, TtToken(_, token::MatchNt(..)) => 3, TtDelimited(_, ref delimed) => { @@ -1097,14 +1103,20 @@ impl TokenTree { (&TtToken(sp, token::DocComment(_)), 0) => { TtToken(sp, token::Pound) } - (&TtToken(sp, token::DocComment(name)), 1) => { + (&TtToken(sp, token::DocComment(name)), 1) + if doc_comment_style(name.as_str()) == AttrInner => { + TtToken(sp, token::Not) + } + (&TtToken(sp, token::DocComment(name)), _) => { + let stripped = strip_doc_comment_decoration(name.as_str()); TtDelimited(sp, Rc::new(Delimited { delim: token::Bracket, open_span: sp, tts: vec![TtToken(sp, token::Ident(token::str_to_ident("doc"), token::Plain)), TtToken(sp, token::Eq), - TtToken(sp, token::Literal(token::StrRaw(name, 0), None))], + TtToken(sp, token::Literal( + token::StrRaw(token::intern(&stripped), 0), None))], close_span: sp, })) } diff --git a/src/test/parse-fail/macro-doc-comments-1.rs b/src/test/parse-fail/macro-doc-comments-1.rs new file mode 100644 index 0000000000000..03bcef4fa5ee0 --- /dev/null +++ b/src/test/parse-fail/macro-doc-comments-1.rs @@ -0,0 +1,19 @@ +// Copyright 2015 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. + +macro_rules! outer { + (#[$outer:meta]) => () +} + +outer! { + //! Inner +} //~^ ERROR no rules expected the token `!` + +fn main() { } diff --git a/src/test/parse-fail/macro-doc-comments-2.rs b/src/test/parse-fail/macro-doc-comments-2.rs new file mode 100644 index 0000000000000..a1b112c29b6e0 --- /dev/null +++ b/src/test/parse-fail/macro-doc-comments-2.rs @@ -0,0 +1,19 @@ +// Copyright 2015 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. + +macro_rules! inner { + (#![$inner:meta]) => () +} + +inner! { + /// Outer +} //~^ ERROR no rules expected the token `[` + +fn main() { } diff --git a/src/test/run-pass/macro-doc-comments.rs b/src/test/run-pass/macro-doc-comments.rs new file mode 100644 index 0000000000000..506813df5b374 --- /dev/null +++ b/src/test/run-pass/macro-doc-comments.rs @@ -0,0 +1,33 @@ +// Copyright 2015 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. + +macro_rules! doc { + ( + $(#[$outer:meta])* + mod $i:ident { + $(#![$inner:meta])* + } + ) => + ( + $(#[$outer])* + pub mod $i { + $(#![$inner])* + } + ) +} + +doc! { + /// Outer doc + mod Foo { + //! Inner doc + } +} + +fn main() { } diff --git a/src/test/rustdoc/issue-23812.rs b/src/test/rustdoc/issue-23812.rs new file mode 100644 index 0000000000000..37f6749694c40 --- /dev/null +++ b/src/test/rustdoc/issue-23812.rs @@ -0,0 +1,46 @@ +// Copyright 2015 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. + +macro_rules! doc { + (#[$outer:meta] mod $i:ident { #![$inner:meta] }) => + ( + #[$outer] + pub mod $i { + #![$inner] + } + ) +} + +doc! { + /// Outer comment + mod Foo { + //! Inner comment + } +} + +// @has issue_23812/Foo/index.html +// @has - 'Outer comment' +// @!has - '/// Outer comment' +// @has - 'Inner comment' +// @!has - '//! Inner comment' + + +doc! { + /** Outer block comment */ + mod Bar { + /*! Inner block comment */ + } +} + +// @has issue_23812/Bar/index.html +// @has - 'Outer block comment' +// @!has - '/** Outer block comment */' +// @has - 'Inner block comment' +// @!has - '/*! Inner block comment */' From 1373c4fcf21930a22150210200bdc14f5f935b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Mon, 13 Jul 2015 21:48:07 +0200 Subject: [PATCH 08/66] Properly create debug info for functions We're currently using the actual function type as the return type when creating the debug info for a function, so we're actually creating debug info for a function that takes the same parameters, and returns the actual function type, which is completely wrong. --- .../trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/trans/debuginfo/mod.rs | 51 +++++++++++-------- src/test/debuginfo/basic-types-metadata.rs | 2 +- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 599a255ef8b6c..d1f5240389613 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -920,7 +920,7 @@ pub fn scope_metadata(fcx: &FunctionContext, } } -fn diverging_type_metadata(cx: &CrateContext) -> DIType { +pub fn diverging_type_metadata(cx: &CrateContext) -> DIType { unsafe { llvm::LLVMDIBuilderCreateBasicType( DIB(cx), diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index a873529891731..39def5ed48aee 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -18,7 +18,8 @@ use self::utils::{DIB, span_start, assert_type_for_node_id, contains_nodebug_att create_DIArray, is_node_local_to_unit}; use self::namespace::{namespace_for_item, NamespaceTreeNode}; use self::type_names::compute_debuginfo_type_name; -use self::metadata::{type_metadata, file_metadata, scope_metadata, TypeMap, compile_unit_metadata}; +use self::metadata::{type_metadata, diverging_type_metadata}; +use self::metadata::{file_metadata, scope_metadata, TypeMap, compile_unit_metadata}; use self::source_loc::InternalDebugLocation; use llvm; @@ -30,7 +31,7 @@ use rustc::ast_map; use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block}; use trans; use trans::monomorphize; -use middle::ty::Ty; +use middle::ty::{self, Ty}; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; @@ -325,7 +326,6 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let function_type_metadata = unsafe { let fn_signature = get_function_signature(cx, fn_ast_id, - &*fn_decl, param_substs, span); llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) @@ -402,35 +402,42 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn_ast_id: ast::NodeId, - fn_decl: &ast::FnDecl, param_substs: &Substs<'tcx>, error_reporting_span: Span) -> DIArray { if cx.sess().opts.debuginfo == LimitedDebugInfo { return create_DIArray(DIB(cx), &[]); } - let mut signature = Vec::with_capacity(fn_decl.inputs.len() + 1); - // Return type -- llvm::DIBuilder wants this at index 0 assert_type_for_node_id(cx, fn_ast_id, error_reporting_span); - let return_type = cx.tcx().node_id_to_type(fn_ast_id); - let return_type = monomorphize::apply_param_substs(cx.tcx(), - param_substs, - &return_type); - if return_type.is_nil() { - signature.push(ptr::null_mut()) - } else { - signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP)); - } + let fn_type = cx.tcx().node_id_to_type(fn_ast_id); + + let sig = match fn_type.sty { + ty::TyBareFn(_, ref barefnty) => { + cx.tcx().erase_late_bound_regions(&barefnty.sig) + } + ty::TyClosure(def_id, substs) => { + cx.tcx().erase_late_bound_regions(&cx.tcx().closure_type(def_id, substs).sig) + } + + _ => cx.sess().bug("get_function_metdata: Expected a function type!") + }; + let sig = monomorphize::apply_param_substs(cx.tcx(), param_substs, &sig); + + let mut signature = Vec::with_capacity(sig.inputs.len() + 1); + + // Return type -- llvm::DIBuilder wants this at index 0 + signature.push(match sig.output { + ty::FnConverging(ret_ty) => match ret_ty.sty { + ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), + _ => type_metadata(cx, ret_ty, codemap::DUMMY_SP) + }, + ty::FnDiverging => diverging_type_metadata(cx) + }); // Arguments types - for arg in &fn_decl.inputs { - assert_type_for_node_id(cx, arg.pat.id, arg.pat.span); - let arg_type = cx.tcx().node_id_to_type(arg.pat.id); - let arg_type = monomorphize::apply_param_substs(cx.tcx(), - param_substs, - &arg_type); - signature.push(type_metadata(cx, arg_type, codemap::DUMMY_SP)); + for &argument_type in &sig.inputs { + signature.push(type_metadata(cx, argument_type, codemap::DUMMY_SP)); } return create_DIArray(DIB(cx), &signature[..]); diff --git a/src/test/debuginfo/basic-types-metadata.rs b/src/test/debuginfo/basic-types-metadata.rs index 0134a058c992b..57dabadfbd546 100644 --- a/src/test/debuginfo/basic-types-metadata.rs +++ b/src/test/debuginfo/basic-types-metadata.rs @@ -43,7 +43,7 @@ // gdb-command:whatis f64 // gdb-check:type = f64 // gdb-command:info functions _yyy -// gdb-check:[...]![...]_yyy([...])([...]); +// gdb-check:[...]![...]_yyy([...]); // gdb-command:continue #![allow(unused_variables)] From 47128b8c7ed38b28e1e7788bc9d5197959d450e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Tue, 14 Jul 2015 19:03:13 +0200 Subject: [PATCH 09/66] Create correct debuginfo for closure function signatures Internally, the arguments passed to the closure are represented by a tuple, but the actual function takes them as individual arguments, so we have to untuple the arguments before creating the debuginfo. --- src/librustc_trans/trans/debuginfo/mod.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index 39def5ed48aee..9ce5c457bff33 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -30,7 +30,7 @@ use middle::subst::{self, Substs}; use rustc::ast_map; use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block}; use trans; -use trans::monomorphize; +use trans::{monomorphize, type_of}; use middle::ty::{self, Ty}; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{NodeMap, FnvHashMap, FnvHashSet}; @@ -41,7 +41,7 @@ use std::ffi::CString; use std::ptr; use std::rc::Rc; use syntax::codemap::{Span, Pos}; -use syntax::{ast, codemap, ast_util}; +use syntax::{abi, ast, codemap, ast_util}; use syntax::attr::IntType; use syntax::parse::token::{self, special_idents}; @@ -412,12 +412,13 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, assert_type_for_node_id(cx, fn_ast_id, error_reporting_span); let fn_type = cx.tcx().node_id_to_type(fn_ast_id); - let sig = match fn_type.sty { + let (sig, abi) = match fn_type.sty { ty::TyBareFn(_, ref barefnty) => { - cx.tcx().erase_late_bound_regions(&barefnty.sig) + (cx.tcx().erase_late_bound_regions(&barefnty.sig), barefnty.abi) } ty::TyClosure(def_id, substs) => { - cx.tcx().erase_late_bound_regions(&cx.tcx().closure_type(def_id, substs).sig) + let closure_type = cx.tcx().closure_type(def_id, substs); + (cx.tcx().erase_late_bound_regions(&closure_type.sig), closure_type.abi) } _ => cx.sess().bug("get_function_metdata: Expected a function type!") @@ -435,8 +436,14 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::FnDiverging => diverging_type_metadata(cx) }); + let inputs = &if abi == abi::RustCall { + type_of::untuple_arguments(cx, &sig.inputs) + } else { + sig.inputs + }; + // Arguments types - for &argument_type in &sig.inputs { + for &argument_type in inputs { signature.push(type_metadata(cx, argument_type, codemap::DUMMY_SP)); } From 9175a16bd8c5b37c485dfe36fea8f9df96e02bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Mon, 13 Jul 2015 21:50:21 +0200 Subject: [PATCH 10/66] Generate proper debug info for function pointers Instead of generating pointer debug info, we're currently generating subroutine debug info. --- src/librustc_trans/trans/debuginfo/metadata.rs | 15 ++++++++++++++- src/test/debuginfo/basic-types-metadata.rs | 3 +++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index d1f5240389613..33f60d7e78d96 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -796,7 +796,20 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } ty::TyBareFn(_, ref barefnty) => { - subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span) + let fn_metadata = subroutine_type_metadata(cx, + unique_type_id, + &barefnty.sig, + usage_site_span).metadata; + match debug_context(cx).type_map + .borrow() + .find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => return metadata, + None => { /* proceed normally */ } + }; + + // This is actually a function pointer, so wrap it in pointer DI + MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) + } ty::TyClosure(def_id, substs) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); diff --git a/src/test/debuginfo/basic-types-metadata.rs b/src/test/debuginfo/basic-types-metadata.rs index 57dabadfbd546..1bc2ddef51e05 100644 --- a/src/test/debuginfo/basic-types-metadata.rs +++ b/src/test/debuginfo/basic-types-metadata.rs @@ -42,6 +42,8 @@ // gdb-check:type = f32 // gdb-command:whatis f64 // gdb-check:type = f64 +// gdb-command:whatis fnptr +// gdb-check:type = void (*)(void) // gdb-command:info functions _yyy // gdb-check:[...]![...]_yyy([...]); // gdb-command:continue @@ -65,6 +67,7 @@ fn main() { let u64: u64 = 64; let f32: f32 = 2.5; let f64: f64 = 3.5; + let fnptr : fn() = _zzz; _zzz(); // #break if 1 == 1 { _yyy(); } } From b684826cab859cc6e16419de448f99a47ce2f8f2 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Sun, 19 Jul 2015 15:39:26 -0400 Subject: [PATCH 11/66] add test for #20162 closes #20162 --- src/test/compile-fail/issue-20162.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/compile-fail/issue-20162.rs diff --git a/src/test/compile-fail/issue-20162.rs b/src/test/compile-fail/issue-20162.rs new file mode 100644 index 0000000000000..d3a87689ac5e1 --- /dev/null +++ b/src/test/compile-fail/issue-20162.rs @@ -0,0 +1,17 @@ +// Copyright 2015 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. + +struct X { x: i32 } + +fn main() { + let mut b: Vec = vec![]; + b.sort(); + //~^ ERROR the trait `core::cmp::Ord` is not implemented for the type `X` +} From 34309cdf12e752104474c8083b17615f642dac29 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 6 Jul 2015 20:40:12 +0300 Subject: [PATCH 12/66] implement 'a:'static region bounds Fixes #22863. --- src/librustc/middle/free_region.rs | 30 ++++++++++++++----- .../middle/infer/region_inference/mod.rs | 3 +- src/test/compile-fail/regions-static-bound.rs | 24 +++++++++++++++ src/test/run-pass/regions-static-bound.rs | 28 +++++++++++++++++ 4 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/regions-static-bound.rs create mode 100644 src/test/run-pass/regions-static-bound.rs diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index e08da94c7314a..d902cb07494e3 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -13,18 +13,21 @@ use middle::implicator::Implication; use middle::ty::{self, FreeRegion}; use util::common::can_reach; -use util::nodemap::FnvHashMap; +use util::nodemap::{FnvHashMap, FnvHashSet}; #[derive(Clone)] pub struct FreeRegionMap { - /// `free_region_map` maps from a free region `a` to a list of + /// `map` maps from a free region `a` to a list of /// free regions `bs` such that `a <= b for all b in bs` map: FnvHashMap>, + /// regions that are required to outlive (and therefore be + /// equal to) 'static. + statics: FnvHashSet } impl FreeRegionMap { pub fn new() -> FreeRegionMap { - FreeRegionMap { map: FnvHashMap() } + FreeRegionMap { map: FnvHashMap(), statics: FnvHashSet() } } pub fn relate_free_regions_from_implications<'tcx>(&mut self, @@ -59,6 +62,8 @@ impl FreeRegionMap { } ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { match (r_a, r_b) { + (ty::ReStatic, ty::ReFree(_)) => {}, + (ty::ReFree(fr_a), ty::ReStatic) => self.relate_to_static(fr_a), (ty::ReFree(fr_a), ty::ReFree(fr_b)) => { // Record that `'a:'b`. Or, put another way, `'b <= 'a`. self.relate_free_regions(fr_b, fr_a); @@ -76,8 +81,12 @@ impl FreeRegionMap { } } - pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) { - let mut sups = self.map.entry(sub).or_insert(Vec::new()); + fn relate_to_static(&mut self, sup: FreeRegion) { + self.statics.insert(sup); + } + + fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) { + let mut sups = self.map.entry(sub).or_insert(Vec::new()); if !sups.contains(&sup) { sups.push(sup); } @@ -88,7 +97,7 @@ impl FreeRegionMap { /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub` /// (that is, the user can give two different names to the same lifetime). pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool { - can_reach(&self.map, sub, sup) + can_reach(&self.map, sub, sup) || self.is_static(&sup) } /// Determines whether one region is a subregion of another. This is intended to run *after @@ -116,10 +125,17 @@ impl FreeRegionMap { (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => self.sub_free_region(sub_fr, super_fr), + (ty::ReStatic, ty::ReFree(ref sup_fr)) => self.is_static(sup_fr), + _ => false, } } } -} + /// Determines whether this free-region is required to be 'static + pub fn is_static(&self, super_region: &ty::FreeRegion) -> bool { + debug!("is_static(super_region={:?})", super_region); + self.statics.iter().any(|s| can_reach(&self.map, *s, *super_region)) + } +} diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 4528abfb9294b..4b62c7beab002 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -869,7 +869,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // is the scope `s_id`. Otherwise, as we do not know // big the free region is precisely, the GLB is undefined. let fr_scope = fr.scope.to_code_extent(); - if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope { + if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope || + free_regions.is_static(fr) { Ok(s) } else { Err(TypeError::RegionsNoOverlap(b, a)) diff --git a/src/test/compile-fail/regions-static-bound.rs b/src/test/compile-fail/regions-static-bound.rs new file mode 100644 index 0000000000000..297b6a866da3a --- /dev/null +++ b/src/test/compile-fail/regions-static-bound.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +fn static_id<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'static { t } +fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'b, 'b: 'static { t } +fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { + t //~ ERROR cannot infer an appropriate lifetime +} + +fn error(u: &(), v: &()) { + static_id(&u); //~ ERROR cannot infer an appropriate lifetime + static_id_indirect(&v); //~ ERROR cannot infer an appropriate lifetime +} + +fn main() {} diff --git a/src/test/run-pass/regions-static-bound.rs b/src/test/run-pass/regions-static-bound.rs new file mode 100644 index 0000000000000..1c6411e3b8f11 --- /dev/null +++ b/src/test/run-pass/regions-static-bound.rs @@ -0,0 +1,28 @@ +// Copyright 2015 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. + +fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a () + where 'a: 'static { t } +fn static_id<'a>(t: &'a ()) -> &'static () + where 'a: 'static { t } +fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'b, 'b: 'static { t } +fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t } + +static UNIT: () = (); + +fn main() +{ + let mut val : &'static () = &UNIT; + invariant_id(&mut val); + static_id(val); + static_id_indirect(val); + ref_id(val); +} From 8edcff59d9131dfd78cf1897e861f0ee4140db10 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 6 Jul 2015 21:38:08 +0300 Subject: [PATCH 13/66] return erased regions from fulfill_obligation Fixes #26802. --- src/librustc_trans/trans/common.rs | 10 ++++++---- src/test/run-pass/issue-26802.rs | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/issue-26802.rs diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index d7d3be699cb90..7280c13bc5d75 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -905,11 +905,13 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let vtable = selection.map(|predicate| { fulfill_cx.register_predicate_obligation(&infcx, predicate); }); - let vtable = drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable); + let vtable = erase_regions(tcx, + &drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable) + ); - info!("Cache miss: {:?}", trait_ref); - ccx.trait_cache().borrow_mut().insert(trait_ref, - vtable.clone()); + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + + ccx.trait_cache().borrow_mut().insert(trait_ref, vtable.clone()); vtable } diff --git a/src/test/run-pass/issue-26802.rs b/src/test/run-pass/issue-26802.rs new file mode 100644 index 0000000000000..854340b0eae29 --- /dev/null +++ b/src/test/run-pass/issue-26802.rs @@ -0,0 +1,23 @@ +// Copyright 2015 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. + +trait Foo<'a> { + fn bar<'b>(&self, x: &'b u8) -> u8 where 'a: 'b { *x+7 } +} + +pub struct FooBar; +impl Foo<'static> for FooBar {} +fn test(foobar: FooBar) -> Box> { + Box::new(foobar) +} + +fn main() { + assert_eq!(test(FooBar).bar(&4), 11); +} From 28ce509d3c0b3302e514d5835c43befaed6f449c Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 19 Jul 2015 19:21:31 +0300 Subject: [PATCH 14/66] clean-up find_bound_for_assoc_item --- src/librustc_typeck/astconv.rs | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3bb3a63004153..837f1be8511e7 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1112,7 +1112,7 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, // any ambiguity. fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, ty_param_node_id: ast::NodeId, - ty_param_name: Option, + ty_param_name: ast::Name, assoc_name: ast::Name, span: Span) -> Result, ErrorReported> @@ -1138,21 +1138,11 @@ fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) .collect(); - if let Some(s) = ty_param_name { - // borrowck doesn't like this any other way - one_bound_for_assoc_type(tcx, - suitable_bounds, - &token::get_name(s), - &token::get_name(assoc_name), - span) - } else { - one_bound_for_assoc_type(tcx, - suitable_bounds, - "Self", - &token::get_name(assoc_name), - span) - - } + one_bound_for_assoc_type(tcx, + suitable_bounds, + &token::get_name(ty_param_name), + &token::get_name(assoc_name), + span) } @@ -1251,7 +1241,11 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, } (&ty::TyParam(_), def::DefSelfTy(Some(trait_did), None)) => { assert_eq!(trait_did.krate, ast::LOCAL_CRATE); - match find_bound_for_assoc_item(this, trait_did.node, None, assoc_name, span) { + match find_bound_for_assoc_item(this, + trait_did.node, + token::special_idents::type_self.name, + assoc_name, + span) { Ok(bound) => bound, Err(ErrorReported) => return (tcx.types.err, ty_path_def), } @@ -1260,7 +1254,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, assert_eq!(param_did.krate, ast::LOCAL_CRATE); match find_bound_for_assoc_item(this, param_did.node, - Some(param_name), + param_name, assoc_name, span) { Ok(bound) => bound, From bbeace61198ff7f41c01356beb9cfdfd2bb8a87d Mon Sep 17 00:00:00 2001 From: William Throwe Date: Sun, 19 Jul 2015 22:14:56 -0400 Subject: [PATCH 15/66] Add test of impl formatting --- src/test/rustdoc/impl-parts.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/rustdoc/impl-parts.rs diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs new file mode 100644 index 0000000000000..89c5e60e34314 --- /dev/null +++ b/src/test/rustdoc/impl-parts.rs @@ -0,0 +1,23 @@ +// Copyright 2015 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(optin_builtin_traits)] + +pub trait AnOibit {} + +impl AnOibit for .. {} + +pub struct Foo { field: T } + +// @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \ +// "impl !AnOibit for Foo where T: Sync" +// @has impl_parts/trait.AnOibit.html '//*[@class="item-list"]//code' \ +// "impl !AnOibit for Foo where T: Sync" +impl !AnOibit for Foo where T: Sync {} From 761e11e1c4ab7bb063b76ed7ef914c81c64aa7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Mon, 20 Jul 2015 06:11:59 +0200 Subject: [PATCH 16/66] fixes #27124 for openbsd the "bsd" archive_format don't work under openbsd. use of "" (system ar) is ok. use of "gnu" is ok too. --- src/librustc_back/target/openbsd_base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index 9b20bd927cb7a..4d3f9668c9f6b 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -27,7 +27,7 @@ pub fn opts() -> TargetOptions { "-Wl,--as-needed".to_string(), ), position_independent_executables: true, - archive_format: "bsd".to_string(), + archive_format: "gnu".to_string(), .. Default::default() } } From ac33f1572bc67c028034a6c39929a500bd8ca5a9 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 20 Jul 2015 10:07:53 +0200 Subject: [PATCH 17/66] fix `configure`: allow both `--enable-debug` and `--disable-debuginfo` in one invocation. --- configure | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 3d04cf7519ed4..652b0b477664f 100755 --- a/configure +++ b/configure @@ -323,6 +323,17 @@ envopt() { fi } +enable_if_not_disabled() { + local OP=$1 + local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_') + local ENAB_V="CFG_ENABLE_$UOP" + local EXPLICITLY_DISABLED="CFG_DISABLE_${UOP}_PROVIDED" + eval VV=\$$EXPLICITLY_DISABLED + if [ -z "$VV" ]; then + eval $ENAB_V=1 + fi +} + to_llvm_triple() { case $1 in i686-w64-mingw32) echo i686-pc-windows-gnu ;; @@ -671,10 +682,12 @@ if [ -n "$CFG_ENABLE_DEBUG" ]; then CFG_DISABLE_OPTIMIZE=1 CFG_DISABLE_OPTIMIZE_CXX=1 fi - CFG_ENABLE_DEBUG_ASSERTIONS=1 - CFG_ENABLE_DEBUG_JEMALLOC=1 - CFG_ENABLE_DEBUGINFO=1 - CFG_ENABLE_LLVM_ASSERTIONS=1 + + # Set following variables to 1 unless setting already provided + enable_if_not_disabled debug-assertions + enable_if_not_disabled debug-jemalloc + enable_if_not_disabled debuginfo + enable_if_not_disabled llvm-assertions fi # OK, now write the debugging options From 871ccfb5a92468056e5492c7f2e54a244657a3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Mon, 20 Jul 2015 10:33:44 +0200 Subject: [PATCH 18/66] Add a test for #26468 The fix for #26468 was made upstream and landed with the LLVM update in #27076. Closes #26468 --- src/test/run-pass/issue-26468.rs | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/run-pass/issue-26468.rs diff --git a/src/test/run-pass/issue-26468.rs b/src/test/run-pass/issue-26468.rs new file mode 100644 index 0000000000000..9fb8675e84e9d --- /dev/null +++ b/src/test/run-pass/issue-26468.rs @@ -0,0 +1,38 @@ +// Copyright 2015 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. + +#![allow(dead_code)] + +enum FooMode { + Check = 0x1001, +} + +enum BarMode { + Check = 0x2001, +} + +enum Mode { + Foo(FooMode), + Bar(BarMode), +} + +#[inline(never)] +fn broken(mode: &Mode) -> u32 { + for _ in 0..1 { + if let Mode::Foo(FooMode::Check) = *mode { return 17 } + if let Mode::Bar(BarMode::Check) = *mode { return 19 } + } + return 42; +} + +fn main() { + let mode = Mode::Bar(BarMode::Check); + assert_eq!(broken(&mode), 19); +} From 0ca8e4994ee43ba9dfbded6e129b30ff5fe7a994 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 20 Jul 2015 12:17:55 +0300 Subject: [PATCH 19/66] Convert negate_unsigned feature gate to a warning --- src/librustc_lint/builtin.rs | 14 ++++++++------ .../feature-gate-negate-unsigned.rs | 10 +++++----- 2 files changed, 13 insertions(+), 11 deletions(-) rename src/test/{compile-fail => run-pass}/feature-gate-negate-unsigned.rs (67%) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index d158307478788..e82e0d790e1bb 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -53,7 +53,7 @@ use syntax::{abi, ast}; use syntax::ast_util::{self, is_shift_binop, local_def}; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::{self, Span}; -use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType, emit_feature_err}; +use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; use syntax::parse::token; use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64}; use syntax::ptr::P; @@ -382,11 +382,13 @@ impl LintPass for TypeLimits { fn check_unsigned_negation_feature(cx: &Context, span: Span) { if !cx.sess().features.borrow().negate_unsigned { - emit_feature_err( - &cx.sess().parse_sess.span_diagnostic, - "negate_unsigned", - span, - "unary negation of unsigned integers may be removed in the future"); + // FIXME(#27141): change this to syntax::feature_gate::emit_feature_err… + cx.sess().span_warn(span, + "unary negation of unsigned integers will be feature gated in the future"); + // …and remove following two expressions. + if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; } + cx.sess().fileline_help(span, "add #![feature(negate_unsigned)] to the \ + crate attributes to enable the gate in advance"); } } } diff --git a/src/test/compile-fail/feature-gate-negate-unsigned.rs b/src/test/run-pass/feature-gate-negate-unsigned.rs similarity index 67% rename from src/test/compile-fail/feature-gate-negate-unsigned.rs rename to src/test/run-pass/feature-gate-negate-unsigned.rs index b1c73fab4ffa6..95c8e62be53bc 100644 --- a/src/test/compile-fail/feature-gate-negate-unsigned.rs +++ b/src/test/run-pass/feature-gate-negate-unsigned.rs @@ -18,21 +18,21 @@ impl std::ops::Neg for S { } const _MAX: usize = -1; -//~^ ERROR unary negation of unsigned integers may be removed in the future +//~^ WARN unary negation of unsigned integers will be feature gated in the future fn main() { let a = -1; - //~^ ERROR unary negation of unsigned integers may be removed in the future + //~^ WARN unary negation of unsigned integers will be feature gated in the future let _b : u8 = a; // for infering variable a to u8. -a; - //~^ ERROR unary negation of unsigned integers may be removed in the future + //~^ WARN unary negation of unsigned integers will be feature gated in the future let _d = -1u8; - //~^ ERROR unary negation of unsigned integers may be removed in the future + //~^ WARN unary negation of unsigned integers will be feature gated in the future for _ in -10..10u8 {} - //~^ ERROR unary negation of unsigned integers may be removed in the future + //~^ WARN unary negation of unsigned integers will be feature gated in the future -S; // should not trigger the gate; issue 26840 } From 9bb6545124ca70dff4fa68ecd5188c45607bbdec Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Mon, 20 Jul 2015 08:31:54 -0400 Subject: [PATCH 20/66] add test for #14229 closes #14229 --- src/test/run-pass/issue-14229.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/run-pass/issue-14229.rs diff --git a/src/test/run-pass/issue-14229.rs b/src/test/run-pass/issue-14229.rs new file mode 100644 index 0000000000000..ee2bbe63750c3 --- /dev/null +++ b/src/test/run-pass/issue-14229.rs @@ -0,0 +1,30 @@ +// Copyright 2015 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. + +trait Foo: Sized { + fn foo(self) {} +} + +trait Bar: Sized { + fn bar(self) {} +} + +struct S; + +impl<'l> Foo for &'l S {} + +impl Bar for T {} + +fn main() { + let s = S; + s.foo(); + (&s).bar(); + s.bar(); +} From 4c73dbddcf4f6bce64424203acad203cfb70072a Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Mon, 20 Jul 2015 08:39:51 -0400 Subject: [PATCH 21/66] add test for #19404 closes #19404 --- src/test/run-pass/issue-19404.rs | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/test/run-pass/issue-19404.rs diff --git a/src/test/run-pass/issue-19404.rs b/src/test/run-pass/issue-19404.rs new file mode 100644 index 0000000000000..0eea6ba22cae8 --- /dev/null +++ b/src/test/run-pass/issue-19404.rs @@ -0,0 +1,47 @@ +// Copyright 2015 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(reflect_marker)] + +use std::any::TypeId; +use std::marker::Reflect; +use std::rc::Rc; + +type Fp = Rc; + +struct Engine; + +trait Component: 'static + Reflect {} +impl Component for Engine {} + +trait Env { + fn get_component_type_id(&self, type_id: TypeId) -> Option>; +} + +impl<'a> Env+'a { + fn get_component(&self) -> Option> { + let x = self.get_component_type_id(TypeId::of::()); + None + } +} + +trait Figment { + fn init(&mut self, env: &Env); +} + +struct MyFigment; + +impl Figment for MyFigment { + fn init(&mut self, env: &Env) { + let engine = env.get_component::(); + } +} + +fn main() {} From 3d65c7ff849bea9cd44fc652396d50486396f867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Tue, 14 Jul 2015 19:08:08 +0200 Subject: [PATCH 22/66] Create proper debuginfo for closure variables Variables for closures hold a tuple of captured variables, and not the function itself. Fixes #26484 --- .../trans/debuginfo/metadata.rs | 10 ++++++++-- src/test/debuginfo/basic-types-metadata.rs | 2 +- src/test/run-pass/issue-26484.rs | 20 +++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/issue-26484.rs diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 33f60d7e78d96..5f17197a4b9a7 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -813,8 +813,14 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } ty::TyClosure(def_id, substs) => { let infcx = infer::normalizing_infer_ctxt(cx.tcx(), &cx.tcx().tables); - let sig = infcx.closure_type(def_id, substs).sig; - subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span) + let upvars = infcx.closure_upvars(def_id, substs).unwrap(); + let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); + + prepare_tuple_metadata(cx, + t, + &upvar_types[..], + unique_type_id, + usage_site_span).finalize(cx) } ty::TyStruct(def_id, substs) => { prepare_struct_metadata(cx, diff --git a/src/test/debuginfo/basic-types-metadata.rs b/src/test/debuginfo/basic-types-metadata.rs index 1bc2ddef51e05..2468150a6a5b1 100644 --- a/src/test/debuginfo/basic-types-metadata.rs +++ b/src/test/debuginfo/basic-types-metadata.rs @@ -43,7 +43,7 @@ // gdb-command:whatis f64 // gdb-check:type = f64 // gdb-command:whatis fnptr -// gdb-check:type = void (*)(void) +// gdb-check:type = [...] (*)([...]) // gdb-command:info functions _yyy // gdb-check:[...]![...]_yyy([...]); // gdb-command:continue diff --git a/src/test/run-pass/issue-26484.rs b/src/test/run-pass/issue-26484.rs new file mode 100644 index 0000000000000..d3e6fc85f136f --- /dev/null +++ b/src/test/run-pass/issue-26484.rs @@ -0,0 +1,20 @@ +// Copyright 2015 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. + +// compile-flags:-g + +fn helper bool>(_f: F) { + print!(""); +} + +fn main() { + let cond = 0; + helper(|v| v == cond) +} From 31a62d3b4be308dbfb71dd7114cbb1594a4986f7 Mon Sep 17 00:00:00 2001 From: Paolo Falabella Date: Mon, 20 Jul 2015 17:29:34 +0200 Subject: [PATCH 23/66] s/has gained/has not gained/g I'm pretty sure this was a typo --- src/libcore/iter.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 4c8511eb1902c..415326a8a616e 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2555,7 +2555,7 @@ impl RandomAccessIterator for Inspect #[unstable(feature = "iter_unfold")] #[derive(Clone)] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] pub struct Unfold { @@ -2567,7 +2567,7 @@ pub struct Unfold { #[unstable(feature = "iter_unfold")] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] impl Unfold where F: FnMut(&mut St) -> Option { @@ -3018,7 +3018,7 @@ type IterateState = (F, Option, bool); /// from a given seed value. #[unstable(feature = "iter_iterate")] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] pub type Iterate = Unfold, fn(&mut IterateState) -> Option>; @@ -3027,7 +3027,7 @@ pub type Iterate = Unfold, fn(&mut IterateState) /// repeated applications of the given function `f`. #[unstable(feature = "iter_iterate")] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] pub fn iterate(seed: T, f: F) -> Iterate where From 7e9e3896dfcef4852ca8ad90f91baf5187b0248e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 15 Jul 2015 23:31:24 -0700 Subject: [PATCH 24/66] std: Add IntoRaw{Fd,Handle,Socket} traits This commit is an implementation of [RFC 1174][rfc] which adds three new traits to the standard library: * `IntoRawFd` - implemented on Unix for all I/O types (files, sockets, etc) * `IntoRawHandle` - implemented on Windows for files, processes, etc * `IntoRawSocket` - implemented on Windows for networking types [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1174-into-raw-fd-socket-handle-traits.md Closes #27062 --- src/libstd/fs.rs | 7 +++- src/libstd/net/tcp.rs | 12 +++++-- src/libstd/net/udp.rs | 6 +++- src/libstd/process.rs | 18 +++++++++- src/libstd/sys/common/net.rs | 6 ++++ src/libstd/sys/unix/ext/io.rs | 35 ++++++++++++++++++- src/libstd/sys/unix/ext/process.rs | 22 ++++++++++-- src/libstd/sys/unix/fs.rs | 2 ++ src/libstd/sys/unix/net.rs | 6 +++- src/libstd/sys/unix/pipe.rs | 1 + src/libstd/sys/windows/ext/io.rs | 50 ++++++++++++++++++++++++++- src/libstd/sys/windows/ext/process.rs | 28 +++++++++++++-- src/libstd/sys/windows/fs.rs | 4 +-- src/libstd/sys/windows/net.rs | 10 +++++- src/libstd/sys/windows/pipe.rs | 1 + src/libstd/sys/windows/process.rs | 2 ++ 16 files changed, 195 insertions(+), 15 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 2c78b2894311d..e5f2fcbae8394 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -24,8 +24,8 @@ use ffi::OsString; use io::{self, SeekFrom, Seek, Read, Write}; use path::{Path, PathBuf}; use sys::fs as fs_imp; -use sys_common::{AsInnerMut, FromInner, AsInner}; use sys_common::io::read_to_end_uninitialized; +use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner}; use vec::Vec; /// A reference to an open file on the filesystem. @@ -317,6 +317,11 @@ impl FromInner for File { File { inner: f } } } +impl IntoInner for File { + fn into_inner(self) -> fs_imp::File { + self.inner + } +} impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 66c8403b2685e..c410233df9229 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -17,9 +17,9 @@ use io::prelude::*; use fmt; use io; use net::{ToSocketAddrs, SocketAddr, Shutdown}; -use sys_common::net as net_imp; -use sys_common::{AsInner, FromInner}; use sys_common::io::read_to_end_uninitialized; +use sys_common::net as net_imp; +use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; /// A structure which represents a TCP stream between a local socket and a @@ -220,6 +220,10 @@ impl FromInner for TcpStream { fn from_inner(inner: net_imp::TcpStream) -> TcpStream { TcpStream(inner) } } +impl IntoInner for TcpStream { + fn into_inner(self) -> net_imp::TcpStream { self.0 } +} + impl fmt::Debug for TcpStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) @@ -298,6 +302,10 @@ impl FromInner for TcpListener { } } +impl IntoInner for TcpListener { + fn into_inner(self) -> net_imp::TcpListener { self.0 } +} + impl fmt::Debug for TcpListener { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 0545175d9aee9..a98ccc3873597 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -17,7 +17,7 @@ use fmt; use io::{self, Error, ErrorKind}; use net::{ToSocketAddrs, SocketAddr, IpAddr}; use sys_common::net as net_imp; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; /// A User Datagram Protocol socket. @@ -174,6 +174,10 @@ impl FromInner for UdpSocket { fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) } } +impl IntoInner for UdpSocket { + fn into_inner(self) -> net_imp::UdpSocket { self.0 } +} + impl fmt::Debug for UdpSocket { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) diff --git a/src/libstd/process.rs b/src/libstd/process.rs index a8127b3200f36..3471805b2bce1 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -23,7 +23,7 @@ use path; use sync::mpsc::{channel, Receiver}; use sys::pipe::{self, AnonPipe}; use sys::process as imp; -use sys_common::{AsInner, AsInnerMut, FromInner}; +use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use thread; /// Representation of a running or exited child process. @@ -71,6 +71,10 @@ impl AsInner for Child { fn as_inner(&self) -> &imp::Process { &self.handle } } +impl IntoInner for Child { + fn into_inner(self) -> imp::Process { self.handle } +} + /// A handle to a child procesess's stdin #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdin { @@ -92,6 +96,10 @@ impl AsInner for ChildStdin { fn as_inner(&self) -> &AnonPipe { &self.inner } } +impl IntoInner for ChildStdin { + fn into_inner(self) -> AnonPipe { self.inner } +} + /// A handle to a child procesess's stdout #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdout { @@ -109,6 +117,10 @@ impl AsInner for ChildStdout { fn as_inner(&self) -> &AnonPipe { &self.inner } } +impl IntoInner for ChildStdout { + fn into_inner(self) -> AnonPipe { self.inner } +} + /// A handle to a child procesess's stderr #[stable(feature = "process", since = "1.0.0")] pub struct ChildStderr { @@ -126,6 +138,10 @@ impl AsInner for ChildStderr { fn as_inner(&self) -> &AnonPipe { &self.inner } } +impl IntoInner for ChildStderr { + fn into_inner(self) -> AnonPipe { self.inner } +} + /// The `Command` type acts as a process builder, providing fine-grained control /// over how a new process should be spawned. A default configuration can be /// generated using `Command::new(program)`, where `program` gives a path to the diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 5890e6a78892c..6dd222b8f6e4d 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -184,6 +184,8 @@ impl TcpStream { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) @@ -336,6 +338,8 @@ impl TcpListener { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn socket_addr(&self) -> io::Result { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) @@ -396,6 +400,8 @@ impl UdpSocket { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn socket_addr(&self) -> io::Result { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 79e59ddab5be5..580d2dbcf7425 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -16,7 +16,7 @@ use fs; use net; use os::raw; use sys; -use sys_common::{self, AsInner, FromInner}; +use sys_common::{self, AsInner, FromInner, IntoInner}; /// Raw file descriptors. #[stable(feature = "rust1", since = "1.0.0")] @@ -59,6 +59,18 @@ pub trait FromRawFd { unsafe fn from_raw_fd(fd: RawFd) -> Self; } +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function **transfers ownership** of the underlying file descriptor + /// to the caller. Callers are then the unique owners of the file descriptor + /// and must close the descriptor once it's no longer needed. + fn into_raw_fd(self) -> RawFd; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { @@ -71,6 +83,11 @@ impl FromRawFd for fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } +impl IntoRawFd for fs::File { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for net::TcpStream { @@ -106,3 +123,19 @@ impl FromRawFd for net::UdpSocket { net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) } } + +impl IntoRawFd for net::TcpStream { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +impl IntoRawFd for net::TcpListener { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +impl IntoRawFd for net::UdpSocket { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index cfe7a1f2dda0d..63adae17581a2 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -13,11 +13,11 @@ #![stable(feature = "rust1", since = "1.0.0")] use os::unix::raw::{uid_t, gid_t}; -use os::unix::io::{FromRawFd, RawFd, AsRawFd}; +use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd}; use prelude::v1::*; use process; use sys; -use sys_common::{AsInnerMut, AsInner, FromInner}; +use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; /// Unix-specific extensions to the `std::process::Command` builder #[stable(feature = "rust1", since = "1.0.0")] @@ -92,3 +92,21 @@ impl AsRawFd for process::ChildStderr { self.as_inner().fd().raw() } } + +impl IntoRawFd for process::ChildStdin { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl IntoRawFd for process::ChildStdout { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl IntoRawFd for process::ChildStderr { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 867cdcbab94cb..0c99a30f107d0 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -331,6 +331,8 @@ impl File { } pub fn fd(&self) -> &FileDesc { &self.0 } + + pub fn into_fd(self) -> FileDesc { self.0 } } impl DirBuilder { diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 1f40c18be2f10..37eb7fd2ac803 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -17,7 +17,7 @@ use str; use sys::c; use net::SocketAddr; use sys::fd::FileDesc; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::net::{getsockopt, setsockopt}; use time::Duration; @@ -127,3 +127,7 @@ impl AsInner for Socket { impl FromInner for Socket { fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) } } + +impl IntoInner for Socket { + fn into_inner(self) -> c_int { self.0.into_raw() } +} diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 946857c05bc4a..140f0c042ba8f 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -46,4 +46,5 @@ impl AnonPipe { pub fn raw(&self) -> libc::c_int { self.0.raw() } pub fn fd(&self) -> &FileDesc { &self.0 } + pub fn into_fd(self) -> FileDesc { self.0 } } diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs index f4717eb2425e1..185f1abe64b9a 100644 --- a/src/libstd/sys/windows/ext/io.rs +++ b/src/libstd/sys/windows/ext/io.rs @@ -13,7 +13,7 @@ use fs; use os::windows::raw; use net; -use sys_common::{self, AsInner, FromInner}; +use sys_common::{self, AsInner, FromInner, IntoInner}; use sys; /// Raw HANDLEs. @@ -50,6 +50,18 @@ pub trait FromRawHandle { unsafe fn from_raw_handle(handle: RawHandle) -> Self; } +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw `HANDLE`. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +pub trait IntoRawHandle { + /// Consumes this object, returning the raw underlying handle. + /// + /// This function **transfers ownership** of the underlying handle to the + /// caller. Callers are then the unique owners of the handle and must close + /// it once it's no longer needed. + fn into_raw_handle(self) -> RawHandle; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawHandle for fs::File { fn as_raw_handle(&self) -> RawHandle { @@ -65,6 +77,12 @@ impl FromRawHandle for fs::File { } } +impl IntoRawHandle for fs::File { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + /// Extract raw sockets. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawSocket { @@ -90,6 +108,18 @@ pub trait FromRawSocket { unsafe fn from_raw_socket(sock: RawSocket) -> Self; } +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw `SOCKET`. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +pub trait IntoRawSocket { + /// Consumes this object, returning the raw underlying socket. + /// + /// This function **transfers ownership** of the underlying socket to the + /// caller. Callers are then the unique owners of the socket and must close + /// it once it's no longer needed. + fn into_raw_socket(self) -> RawSocket; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpStream { fn as_raw_socket(&self) -> RawSocket { @@ -130,3 +160,21 @@ impl FromRawSocket for net::UdpSocket { net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) } } + +impl IntoRawSocket for net::TcpStream { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} + +impl IntoRawSocket for net::TcpListener { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} + +impl IntoRawSocket for net::UdpSocket { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 6f59be2687a1b..fde21e9a798ee 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -12,10 +12,10 @@ #![stable(feature = "process_extensions", since = "1.2.0")] -use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle}; +use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle, IntoRawHandle}; use process; use sys; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { @@ -32,6 +32,12 @@ impl AsRawHandle for process::Child { } } +impl IntoRawHandle for process::Child { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::ChildStdin { fn as_raw_handle(&self) -> RawHandle { @@ -52,3 +58,21 @@ impl AsRawHandle for process::ChildStderr { self.as_inner().handle().raw() as *mut _ } } + +impl IntoRawHandle for process::ChildStdin { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + +impl IntoRawHandle for process::ChildStdout { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + +impl IntoRawHandle for process::ChildStderr { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 890cc455d5df2..5dd84e9f71ebc 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -319,6 +319,8 @@ impl File { pub fn handle(&self) -> &Handle { &self.handle } + pub fn into_handle(self) -> Handle { self.handle } + fn reparse_point<'a>(&self, space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]) -> io::Result<(libc::DWORD, &'a c::REPARSE_DATA_BUFFER)> { @@ -357,8 +359,6 @@ impl File { Ok(PathBuf::from(OsString::from_wide(subst))) } } - - pub fn into_handle(self) -> Handle { self.handle } } impl FromInner for File { diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index b765bc6e50085..d58355ed1feef 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -21,7 +21,7 @@ use rt; use sync::Once; use sys; use sys::c; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::net::{setsockopt, getsockopt}; use time::Duration; @@ -184,3 +184,11 @@ impl AsInner for Socket { impl FromInner for Socket { fn from_inner(sock: libc::SOCKET) -> Socket { Socket(sock) } } + +impl IntoInner for Socket { + fn into_inner(self) -> libc::SOCKET { + let ret = self.0; + mem::forget(self); + ret + } +} diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index b2a6607314a50..a7ece66e0f1f7 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -37,6 +37,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { impl AnonPipe { pub fn handle(&self) -> &Handle { &self.inner } + pub fn into_handle(self) -> Handle { self.inner } pub fn raw(&self) -> libc::HANDLE { self.inner.raw() } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 0b0268d4746ab..ca33e11eea059 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -220,6 +220,8 @@ impl Process { } pub fn handle(&self) -> &Handle { &self.handle } + + pub fn into_handle(self) -> Handle { self.handle } } #[derive(PartialEq, Eq, Clone, Copy, Debug)] From 013d47b19b25b94e9740f725425bc836bac6efde Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 20 Jul 2015 09:23:31 -0700 Subject: [PATCH 25/66] syntax: Suppress panic message on `fatal` This commit ensures that the rustc thread does not leak a panic message whenever a call to `fatal` happens. This already happens for the main rustc thread as part of the `rustc_driver::monitor` function, but the compiler also spawns threads for other operations like `-C codegen-units`, and sometimes errors are emitted on these threads as well. To ensure that there's a consistent error-handling experience across threads this unifies these two to never print the panic message in the case of a normal and expected fatal error. This should also fix the flaky `asm-src-loc-codegen-units.rs` test as the output is sometimes garbled if diagnostics are printed while the panic message is also being printed. --- src/libsyntax/diagnostic.rs | 4 ++++ src/libsyntax/lib.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index fbf015169f858..e95813e44babe 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -208,6 +208,10 @@ impl Handler { } pub fn fatal(&self, msg: &str) -> ! { self.emit.borrow_mut().emit(None, msg, None, Fatal); + + // Suppress the fatal error message from the panic below as we've + // already terminated in our own "legitimate" fashion. + io::set_panic(Box::new(io::sink())); panic!(FatalError); } pub fn err(&self, msg: &str) { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 7333265bdd412..d93af5da13c1e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -32,6 +32,7 @@ #![feature(libc)] #![feature(ref_slice)] #![feature(rustc_private)] +#![feature(set_stdio)] #![feature(staged_api)] #![feature(str_char)] #![feature(str_escape)] From 7cb157e74d2f190dd338e0f81c07bf427c22e02d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 17 Jul 2015 08:17:43 -0700 Subject: [PATCH 26/66] Register new snapshots These new snapshots contain the knowledge of how to build the new triples of 32-bit MSVC and 32-bit FreeBSD, both of which should soon start having nightlies/auto builders! This does not currently register bitrig/freebsd snapshots but I believe those will be retroactively added in the near future. --- src/liballoc/lib.rs | 17 ----------------- src/libcollections/lib.rs | 7 ------- src/libcollections/string.rs | 3 --- src/liblibc/lib.rs | 4 ---- src/snapshots.txt | 8 ++++++++ 5 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 5c1fd2a1aa1f4..ead0b4259a987 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -135,20 +135,3 @@ pub fn oom() -> ! { // allocate. unsafe { core::intrinsics::abort() } } - -// FIXME(#14344): When linking liballoc with libstd, this library will be linked -// as an rlib (it only exists as an rlib). It turns out that an -// optimized standard library doesn't actually use *any* symbols -// from this library. Everything is inlined and optimized away. -// This means that linkers will actually omit the object for this -// file, even though it may be needed in the future. -// -// To get around this for now, we define a dummy symbol which -// will never get inlined so the stdlib can call it. The stdlib's -// reference to this symbol will cause this library's object file -// to get linked in to libstd successfully (the linker won't -// optimize it out). -#[doc(hidden)] -#[unstable(feature = "issue_14344_fixme")] -#[cfg(stage0)] -pub fn fixme_14344_be_sure_to_link_to_collections() {} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index a2b2ae220f88e..1f94838499218 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -133,13 +133,6 @@ pub mod btree_set { pub use btree::set::*; } - -// FIXME(#14344) this shouldn't be necessary -#[doc(hidden)] -#[unstable(feature = "issue_14344_fixme")] -#[cfg(stage0)] -pub fn fixme_14344_be_sure_to_link_to_collections() {} - #[cfg(not(test))] mod std { pub use core::ops; // RangeFull diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index ebff4a9126daf..cc58952be600a 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -979,7 +979,6 @@ impl ops::Index for String { } } -#[cfg(not(stage0))] #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut> for String { #[inline] @@ -987,7 +986,6 @@ impl ops::IndexMut> for String { &mut self[..][index] } } -#[cfg(not(stage0))] #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut> for String { #[inline] @@ -995,7 +993,6 @@ impl ops::IndexMut> for String { &mut self[..][index] } } -#[cfg(not(stage0))] #[stable(feature = "derefmut_for_string", since = "1.2.0")] impl ops::IndexMut> for String { #[inline] diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index dfcd08b69907a..c229df34ccf89 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -6535,8 +6535,4 @@ pub mod funcs { } } -#[doc(hidden)] -#[cfg(stage0)] -pub fn issue_14344_workaround() {} // FIXME #14344 force linkage to happen correctly - #[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows diff --git a/src/snapshots.txt b/src/snapshots.txt index 1b2613d8c5045..cb5790b34f4d3 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2015-07-17 d4432b3 + linux-i386 93f6216a35d3bed3cedf244c9aff4cd716336bd9 + linux-x86_64 d8f4967fc71a153c925faecf95a7feadf7e463a4 + macos-i386 29852c4d4b5a851f16d627856a279cae5bf9bd01 + macos-x86_64 1a20259899321062a0325edb1d22990f05d18708 + winnt-i386 df50210f41db9a6f2968be5773b8e3bae32bb823 + winnt-x86_64 d7774b724988485652781a804bdf8e05d28ead48 + S 2015-05-24 ba0e1cd bitrig-x86_64 2a710e16e3e3ef3760df1f724d66b3af34c1ef3f freebsd-x86_64 370db40613f5c08563ed7e38357826dd42d4e0f8 From a7e5c6302b2458a91d4140a6fefea223a4df758d Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Mon, 20 Jul 2015 12:59:33 -0400 Subject: [PATCH 27/66] add test for #10436 closes #10436 --- src/test/run-pass/issue-10436.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/run-pass/issue-10436.rs diff --git a/src/test/run-pass/issue-10436.rs b/src/test/run-pass/issue-10436.rs new file mode 100644 index 0000000000000..81a955b0f22e4 --- /dev/null +++ b/src/test/run-pass/issue-10436.rs @@ -0,0 +1,20 @@ +// Copyright 2015 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. + +fn works(x: T) -> Vec { vec![x] } + +fn also_works(x: T) -> Vec { vec![x] } + +fn main() { + let _: Vec = works(0); + let _: Vec = also_works(0); + let _ = works(0); + let _ = also_works(0); +} From 225ad1752039f6c48189e8e30d4824de691761da Mon Sep 17 00:00:00 2001 From: arthurprs Date: Sun, 19 Jul 2015 13:11:30 -0300 Subject: [PATCH 28/66] impl Debug for Atomic types --- src/libcore/atomic.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index a77df09664313..c6434e71957ae 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -78,6 +78,7 @@ use intrinsics; use cell::UnsafeCell; use default::Default; +use fmt; /// A boolean type which can be safely shared between threads. #[stable(feature = "rust1", since = "1.0.0")] @@ -1089,3 +1090,23 @@ pub fn fence(order: Ordering) { } } } + +macro_rules! impl_Debug { + ($($t:ident)*) => ($( + #[stable(feature = "atomic_debug", since = "1.3.0")] + impl fmt::Debug for $t { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple(stringify!($t)).field(&self.load(Ordering::SeqCst)).finish() + } + } + )*); +} + +impl_Debug!{ AtomicUsize AtomicIsize AtomicBool } + +#[stable(feature = "atomic_debug", since = "1.3.0")] +impl fmt::Debug for AtomicPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("AtomicPtr").field(&self.load(Ordering::SeqCst)).finish() + } +} From 3ae7b72970104d1269fd1ebc31aaaf50830f3a3b Mon Sep 17 00:00:00 2001 From: Alisdair Owens Date: Mon, 20 Jul 2015 18:14:12 +0100 Subject: [PATCH 29/66] Fix wording nit for E0253 --- src/librustc_resolve/diagnostics.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a0d06e5e1244a..23d323440c9b3 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -106,8 +106,7 @@ mod foo { use foo::MyTrait::do_something; ``` -In general, it's not legal to directly import methods belonging to a -trait or concrete type. +It's illegal to directly import methods belonging to a trait or concrete type. "##, E0255: r##" From 27fc0f21c48ad9a8788044467c14611b41afeab3 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Jul 2015 13:16:57 -0400 Subject: [PATCH 30/66] Document iterators in std::io Make them all consistent and link up the documentation. --- src/libstd/io/mod.rs | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 2447473103101..2a0efb9d8a28c 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1188,9 +1188,12 @@ impl Write for Broadcast { } } -/// Adaptor to chain together two instances of `Read`. +/// Adaptor to chain together two readers. /// -/// For more information, see `Read::chain`. +/// This struct is generally created by calling [`chain()`][chain] on a reader. +/// Please see the documentation of `chain()` for more details. +/// +/// [chain]: trait.Read.html#method.chain #[stable(feature = "rust1", since = "1.0.0")] pub struct Chain { first: T, @@ -1266,7 +1269,10 @@ impl BufRead for Take { /// An adaptor which will emit all read data to a specified writer as well. /// -/// For more information see `Read::tee` +/// This struct is generally created by calling [`tee()`][tee] on a reader. +/// Please see the documentation of `tee()` for more details. +/// +/// [tee]: trait.Read.html#method.tee #[unstable(feature = "io", reason = "awaiting stability of Read::tee")] pub struct Tee { reader: R, @@ -1283,9 +1289,12 @@ impl Read for Tee { } } -/// A bridge from implementations of `Read` to an `Iterator` of `u8`. +/// An iterator over `u8` values of a reader. +/// +/// This struct is generally created by calling [`bytes()`][bytes] on a reader. +/// Please see the documentation of `bytes()` for more details. /// -/// See `Read::bytes` for more information. +/// [bytes]: trait.Read.html#method.bytes #[stable(feature = "rust1", since = "1.0.0")] pub struct Bytes { inner: R, @@ -1305,9 +1314,12 @@ impl Iterator for Bytes { } } -/// A bridge from implementations of `Read` to an `Iterator` of `char`. +/// An iterator over the `char`s of a reader. /// -/// See `Read::chars` for more information. +/// This struct is generally created by calling [`chars()`][chars] on a reader. +/// Please see the documentation of `chars()` for more details. +/// +/// [chars]: trait.Read.html#method.chars #[unstable(feature = "io", reason = "awaiting stability of Read::chars")] pub struct Chars { inner: R, @@ -1389,7 +1401,10 @@ impl fmt::Display for CharsError { /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// -/// See `BufRead::split` for more information. +/// This struct is generally created by calling [`split()`][split] on a +/// `BufRead`. Please see the documentation of `split()` for more details. +/// +/// [split]: trait.BufRead.html#method.split #[stable(feature = "rust1", since = "1.0.0")] pub struct Split { buf: B, @@ -1415,10 +1430,12 @@ impl Iterator for Split { } } -/// An iterator over the lines of an instance of `BufRead` split on a newline -/// byte. +/// An iterator over the lines of an instance of `BufRead`. +/// +/// This struct is generally created by calling [`lines()`][lines] on a +/// `BufRead`. Please see the documentation of `lines()` for more details. /// -/// See `BufRead::lines` for more information. +/// [lines]: trait.BufRead.html#method.lines #[stable(feature = "rust1", since = "1.0.0")] pub struct Lines { buf: B, From 1e79917bda90d3b7ea53fc08b0c0c4862dfdca53 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Mon, 20 Jul 2015 13:24:34 -0400 Subject: [PATCH 31/66] Improve Debug impl for File on Windows Adds a path field if a path could be obtained Signed-off-by: Peter Atashian --- src/libstd/sys/windows/fs.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 890cc455d5df2..424d24ea620df 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -369,10 +369,13 @@ impl FromInner for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME(#24570): add more info here (e.g. path, mode) - f.debug_struct("File") - .field("handle", &self.handle.raw()) - .finish() + // FIXME(#24570): add more info here (e.g. mode) + let mut b = f.debug_struct("File"); + b.field("handle", &self.handle.raw()); + if let Ok(path) = get_path(&self) { + b.field("path", &path); + } + b.finish() } } @@ -582,11 +585,7 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> { Ok(()) } -pub fn canonicalize(p: &Path) -> io::Result { - - let mut opts = OpenOptions::new(); - opts.read(true); - let f = try!(File::open(p, &opts)); +fn get_path(f: &File) -> io::Result { super::fill_utf16_buf(|buf, sz| unsafe { c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, libc::VOLUME_NAME_DOS) @@ -595,6 +594,13 @@ pub fn canonicalize(p: &Path) -> io::Result { }) } +pub fn canonicalize(p: &Path) -> io::Result { + let mut opts = OpenOptions::new(); + opts.read(true); + let f = try!(File::open(p, &opts)); + get_path(&f) +} + pub fn copy(from: &Path, to: &Path) -> io::Result { unsafe extern "system" fn callback( _TotalFileSize: libc::LARGE_INTEGER, From 9191a7895574ec3aa5a9b84ce0008d91e32ccd6a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 20 Jul 2015 10:41:52 -0700 Subject: [PATCH 32/66] Revert "Fix `missing_docs` lint for const and static." This reverts commit 00130cff99f88e13fec87378bdf476cfea6aa147. As mentioned in a regression report[1], this caused a notable amount of breakage. Because there's a plan to mitigate[2] this type of breakage, I'm reverting this until then. [1]: https://internals.rust-lang.org/t/new-crater-reports-1-1-stable-vs-beta-2015-07-10-and-nightly-2015-07-10/2358 [2]: https://github.com/rust-lang/rfcs/pull/1193 --- src/librustc_lint/builtin.rs | 2 -- src/test/compile-fail/lint-missing-doc.rs | 21 --------------------- 2 files changed, 23 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1574080b313b5..467ceed60f1be 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1610,8 +1610,6 @@ impl LintPass for MissingDoc { } return }, - ast::ItemConst(..) => "a constant", - ast::ItemStatic(..) => "a static", _ => return }; diff --git a/src/test/compile-fail/lint-missing-doc.rs b/src/test/compile-fail/lint-missing-doc.rs index 5501835886104..04db6c8c8f39c 100644 --- a/src/test/compile-fail/lint-missing-doc.rs +++ b/src/test/compile-fail/lint-missing-doc.rs @@ -149,27 +149,6 @@ pub enum PubBaz3 { #[doc(hidden)] pub fn baz() {} - -const FOO: u32 = 0; -/// dox -pub const FOO1: u32 = 0; -#[allow(missing_docs)] -pub const FOO2: u32 = 0; -#[doc(hidden)] -pub const FOO3: u32 = 0; -pub const FOO4: u32 = 0; //~ ERROR: missing documentation for a const - - -static BAR: u32 = 0; -/// dox -pub static BAR1: u32 = 0; -#[allow(missing_docs)] -pub static BAR2: u32 = 0; -#[doc(hidden)] -pub static BAR3: u32 = 0; -pub static BAR4: u32 = 0; //~ ERROR: missing documentation for a static - - mod internal_impl { /// dox pub fn documented() {} From 686d32643913040d5074fd632fba6a628ea5807c Mon Sep 17 00:00:00 2001 From: Alisdair Owens Date: Sun, 19 Jul 2015 15:18:09 +0100 Subject: [PATCH 33/66] Add diagnostics for E0172, fix inline error message for E0139 --- src/librustc/middle/intrinsicck.rs | 2 +- src/librustc_typeck/diagnostics.rs | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index c5f6f0126de37..a10e0b8dfc29e 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -165,7 +165,7 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> { if from_tc.interior_param() || to_tc.interior_param() { span_err!(self.tcx.sess, span, E0139, "cannot transmute to or from a type that contains \ - type parameters in its interior"); + unsubstituted type parameters"); return; } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index a002ed311e8c5..a6c574e29ef93 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1476,6 +1476,33 @@ return, for example with a `loop` that never breaks or a call to another diverging function (such as `panic!()`). "##, +E0172: r##" +This error means that an attempt was made to specify the type of a variable with +a combination of a concrete type and a trait. Consider the following example: + +``` +fn foo(bar: i32+std::fmt::Display) {} +``` + +The code is trying to specify that we want to receive a signed 32-bit integer +which also implements `Display`. This doesn't make sense: when we pass `i32`, a +concrete type, it implicitly includes all of the traits that it implements. +This includes `Display`, `Debug`, `Clone`, and a host of others. + +If `i32` implements the trait we desire, there's no need to specify the trait +separately. If it does not, then we need to `impl` the trait for `i32` before +passing it into `foo`. Either way, a fixed definition for `foo` will look like +the following: + +``` +fn foo(bar: i32) {} +``` + +To learn more about traits, take a look at the Book: + +https://doc.rust-lang.org/book/traits.html +"##, + E0178: r##" In types, the `+` type operator has low precedence, so it is often necessary to use parentheses. @@ -2196,7 +2223,6 @@ register_diagnostics! { E0164, E0167, E0168, - E0172, E0173, // manual implementations of unboxed closure traits are experimental E0174, // explicit use of unboxed closure methods are experimental E0182, From 7e7ec6b5cd78d16c260b251dfd69cc150332f83d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Jul 2015 14:41:00 -0400 Subject: [PATCH 34/66] Document structures in std::io::utils These provide various special readers, so point their docs to their constructor functions in a manner consistent with everything else. --- src/libstd/io/util.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index c0bced26beffa..dc29811ed5ba1 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -61,6 +61,11 @@ pub fn copy(reader: &mut R, writer: &mut W) -> io::Result Date: Fri, 17 Jul 2015 16:28:04 -0700 Subject: [PATCH 35/66] doc: Clean up primitive short descriptions This makes the primitive descriptions on the front page read properly as descriptions of types and not of the associated modules. --- src/libcollections/slice.rs | 2 +- src/libcollections/str.rs | 2 +- src/libcore/ptr.rs | 2 +- src/libcore/tuple.rs | 2 +- src/librustc_unicode/char.rs | 2 +- src/libstd/array.rs | 4 ++-- src/libstd/num/f32.rs | 2 +- src/libstd/num/f64.rs | 2 +- src/libstd/num/i16.rs | 2 +- src/libstd/num/i32.rs | 2 +- src/libstd/num/i64.rs | 2 +- src/libstd/num/i8.rs | 2 +- src/libstd/num/isize.rs | 2 +- src/libstd/num/u16.rs | 2 +- src/libstd/num/u32.rs | 2 +- src/libstd/num/u64.rs | 2 +- src/libstd/num/u8.rs | 2 +- src/libstd/num/usize.rs | 2 +- src/libstd/tuple.rs | 2 +- 19 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index f5a27565ef7de..ae6cda793d054 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Utilities for slice manipulation +//! A dynamically-sized view into a contiguous sequence, `[T]`. //! //! The `slice` module contains useful code to help work with slice values. //! Slices are a view into a block of memory represented as a pointer and a diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index cb6613998b454..8ab1464379f8f 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unicode string manipulation (the `str` type). +//! Unicode string slices //! //! Rust's `str` type is one of the core primitive types of the language. `&str` //! is the borrowed string type. This type of string can only be created from diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 7b33a41f9556a..b47ced03fba29 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,7 +10,7 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Operations on raw pointers, `*const T`, and `*mut T`. +//! Raw, unsafe pointers, `*const T`, and `*mut T` //! //! Working with raw pointers in Rust is uncommon, //! typically limited to a few patterns. diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index ba6a7c4a5fefa..9e97078c529e1 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations on tuples +//! A finite heterogeneous sequence, `(T, U, ..)` //! //! To access a single element of a tuple one can use the `.0` //! field access syntax. diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index 2596620d39d3d..fb9ff26776202 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Character manipulation (`char` type, Unicode Scalar Value) +//! A Unicode scalar value //! //! This module provides the `CharExt` trait, as well as its //! implementation for the primitive `char` type, in order to allow diff --git a/src/libstd/array.rs b/src/libstd/array.rs index 0dfcc72e37910..f6d133319c848 100644 --- a/src/libstd/array.rs +++ b/src/libstd/array.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A fixed-size array is denoted `[T; N]` for the element type `T` and -//! the compile time constant size `N`. The size must be zero or positive. +//! A fixed-size array, denoted `[T; N]`, for the element type, `T`, and +//! the non-negative compile time constant size, `N`. //! //! Arrays values are created either with an explicit expression that lists //! each element: `[x, y, z]` or a repeat expression: `[x; N]`. The repeat diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 10cdc0c583377..561b84ca21a55 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for 32-bits floats (`f32` type) +//! The 32-bit floating point type #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 41c0fcb9797a6..8a77566faeb92 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for 64-bits floats (`f64` type) +//! The 32-bit floating point type #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] diff --git a/src/libstd/num/i16.rs b/src/libstd/num/i16.rs index 498f19b9b8307..04a45072d1a5b 100644 --- a/src/libstd/num/i16.rs +++ b/src/libstd/num/i16.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 16-bits integers (`i16` type) +//! The 16-bit signed integer type #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i16")] diff --git a/src/libstd/num/i32.rs b/src/libstd/num/i32.rs index aea1e92117bb0..09177c188de3f 100644 --- a/src/libstd/num/i32.rs +++ b/src/libstd/num/i32.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 32-bits integers (`i32` type) +//! The 32-bit signed integer type #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i32")] diff --git a/src/libstd/num/i64.rs b/src/libstd/num/i64.rs index 43794345fe7a4..84fccc9d25fda 100644 --- a/src/libstd/num/i64.rs +++ b/src/libstd/num/i64.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 64-bits integers (`i64` type) +//! The 64-bit signed integer type #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i64")] diff --git a/src/libstd/num/i8.rs b/src/libstd/num/i8.rs index 1b03bf6f4f009..f0e8488384764 100644 --- a/src/libstd/num/i8.rs +++ b/src/libstd/num/i8.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 8-bits integers (`i8` type) +//! The 8-bit signed integer type #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "i8")] diff --git a/src/libstd/num/isize.rs b/src/libstd/num/isize.rs index aa89f858f6f63..b602c7c704ad9 100644 --- a/src/libstd/num/isize.rs +++ b/src/libstd/num/isize.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for pointer-sized signed integers (`isize` type) +//! The pointer-sized signed integer type #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "isize")] diff --git a/src/libstd/num/u16.rs b/src/libstd/num/u16.rs index 3fda77fb69c40..17f254022009c 100644 --- a/src/libstd/num/u16.rs +++ b/src/libstd/num/u16.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 16-bits integers (`u16` type) +//! The 16-bit unsigned integer type #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u16")] diff --git a/src/libstd/num/u32.rs b/src/libstd/num/u32.rs index 8610f0c01473f..13be3677dac59 100644 --- a/src/libstd/num/u32.rs +++ b/src/libstd/num/u32.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 32-bits integers (`u32` type) +//! The 32-bit unsigned integer type #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u32")] diff --git a/src/libstd/num/u64.rs b/src/libstd/num/u64.rs index 3587b06965624..40b6e138307aa 100644 --- a/src/libstd/num/u64.rs +++ b/src/libstd/num/u64.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 64-bits integer (`u64` type) +//! The 64-bit unsigned integer type #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u64")] diff --git a/src/libstd/num/u8.rs b/src/libstd/num/u8.rs index 6a285e8299c1e..02fc807e1f2d1 100644 --- a/src/libstd/num/u8.rs +++ b/src/libstd/num/u8.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 8-bits integers (`u8` type) +//! The 8-bit unsigned integer type #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "u8")] diff --git a/src/libstd/num/usize.rs b/src/libstd/num/usize.rs index b54d8ae96c5cf..548c0dbb8dcea 100644 --- a/src/libstd/num/usize.rs +++ b/src/libstd/num/usize.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for pointer-sized unsigned integers (`usize` type) +//! The pointer-sized unsigned integer type #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "usize")] diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index 08aa979cf631f..1e4de19c87466 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations on tuples +//! A finite heterogeneous sequence, `(T, U, ..)` //! //! To access the _N_-th element of a tuple one can use `N` itself //! as a field of the tuple. From 8497c428e5da665917304ae404b9b3e7b0a94466 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 20 Jul 2015 11:21:02 -0700 Subject: [PATCH 36/66] std: Create separate docs for the primitives Having the primitive and module docs derived from the same source causes problems, primarily that they can't contain hyperlinks cross-referencing each other. This crates dedicated private modules in `std` to document the primitive types, then for all primitives that have a corresponding module, puts hyperlinks in moth the primitive docs and the module docs cross-linking each other. This should help clear up confusion when readers find themselves on the wrong page. --- src/libcollections/slice.rs | 4 +- src/libcollections/str.rs | 36 +-- src/libcore/array.rs | 3 +- src/libcore/char.rs | 1 - src/libcore/lib.rs | 4 - src/libcore/num/f32.rs | 1 - src/libcore/num/f64.rs | 1 - src/libcore/num/i16.rs | 1 - src/libcore/num/i32.rs | 1 - src/libcore/num/i64.rs | 1 - src/libcore/num/i8.rs | 1 - src/libcore/num/isize.rs | 1 - src/libcore/num/u16.rs | 1 - src/libcore/num/u32.rs | 1 - src/libcore/num/u64.rs | 1 - src/libcore/num/u8.rs | 1 - src/libcore/num/usize.rs | 1 - src/libcore/ptr.rs | 75 +------ src/libcore/slice.rs | 1 - src/libcore/str/mod.rs | 1 - src/libcore/tuple.rs | 1 - src/librustc_unicode/char.rs | 9 +- src/libstd/array.rs | 55 ----- src/libstd/bool.rs | 14 -- src/libstd/lib.rs | 10 +- src/libstd/num/f32.rs | 4 +- src/libstd/num/f64.rs | 3 +- src/libstd/num/i16.rs | 3 +- src/libstd/num/i32.rs | 3 +- src/libstd/num/i64.rs | 3 +- src/libstd/num/i8.rs | 3 +- src/libstd/num/isize.rs | 3 +- src/libstd/num/u16.rs | 3 +- src/libstd/num/u32.rs | 3 +- src/libstd/num/u64.rs | 3 +- src/libstd/num/u8.rs | 3 +- src/libstd/num/usize.rs | 3 +- src/libstd/primitive_docs.rs | 420 +++++++++++++++++++++++++++++++++++ src/libstd/tuple.rs | 60 ----- src/libstd/unit.rs | 45 ---- 40 files changed, 461 insertions(+), 327 deletions(-) delete mode 100644 src/libstd/array.rs delete mode 100644 src/libstd/bool.rs create mode 100644 src/libstd/primitive_docs.rs delete mode 100644 src/libstd/tuple.rs delete mode 100644 src/libstd/unit.rs diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index ae6cda793d054..4378d0804df96 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -10,7 +10,6 @@ //! A dynamically-sized view into a contiguous sequence, `[T]`. //! -//! The `slice` module contains useful code to help work with slice values. //! Slices are a view into a block of memory represented as a pointer and a //! length. //! @@ -78,7 +77,8 @@ //! iterators. //! * Further methods that return iterators are `.split()`, `.splitn()`, //! `.chunks()`, `.windows()` and more. -#![doc(primitive = "slice")] +//! +//! *[See also the slice primitive type](../primitive.slice.html).* #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 8ab1464379f8f..25a3441fd5bb6 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -10,41 +10,9 @@ //! Unicode string slices //! -//! Rust's `str` type is one of the core primitive types of the language. `&str` -//! is the borrowed string type. This type of string can only be created from -//! other strings, unless it is a `&'static str` (see below). It is not possible -//! to move out of borrowed strings because they are owned elsewhere. -//! -//! # Examples -//! -//! Here's some code that uses a `&str`: -//! -//! ``` -//! let s = "Hello, world."; -//! ``` -//! -//! This `&str` is a `&'static str`, which is the type of string literals. -//! They're `'static` because literals are available for the entire lifetime of -//! the program. -//! -//! You can get a non-`'static` `&str` by taking a slice of a `String`: -//! -//! ``` -//! let some_string = "Hello, world.".to_string(); -//! let s = &some_string; -//! ``` -//! -//! # Representation -//! -//! Rust's string type, `str`, is a sequence of Unicode scalar values encoded as -//! a stream of UTF-8 bytes. All [strings](../../reference.html#literals) are -//! guaranteed to be validly encoded UTF-8 sequences. Additionally, strings are -//! not null-terminated and can thus contain null bytes. -//! -//! The actual representation of `str`s have direct mappings to slices: `&str` -//! is the same as `&[u8]`. +//! *[See also the `str` primitive type](../primitive.str.html).* + -#![doc(primitive = "str")] #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. diff --git a/src/libcore/array.rs b/src/libcore/array.rs index a9b240de30bef..cfe22b8917874 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -11,8 +11,9 @@ //! Implementations of things like `Eq` for fixed-length arrays //! up to a certain length. Eventually we should able to generalize //! to all lengths. +//! +//! *[See also the array primitive type](../primitive.array.html).* -#![doc(primitive = "array")] #![unstable(feature = "fixed_size_array", reason = "traits and impls are better expressed through generic \ integer constants")] diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 12aa06667a1dd..88aa805668cfa 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -13,7 +13,6 @@ //! For more details, see ::rustc_unicode::char (a.k.a. std::char) #![allow(non_snake_case)] -#![doc(primitive = "char")] #![stable(feature = "core_char", since = "1.2.0")] use iter::Iterator; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 030d2a33f8f65..ef2a33c37dd30 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -154,10 +154,6 @@ pub mod str; pub mod hash; pub mod fmt; -#[doc(primitive = "bool")] -mod bool { -} - // note: does not need to be public mod tuple; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 9270d3f12b073..6b4424093b407 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -10,7 +10,6 @@ //! Operations and constants for 32-bits floats (`f32` type) -#![doc(primitive = "f32")] // FIXME: MIN_VALUE and MAX_VALUE literals are parsed as -inf and inf #14353 #![allow(overflowing_literals)] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index d2ab2695f5e5c..fa7aa2ab5ce8c 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -10,7 +10,6 @@ //! Operations and constants for 64-bits floats (`f64` type) -#![doc(primitive = "f64")] // FIXME: MIN_VALUE and MAX_VALUE literals are parsed as -inf and inf #14353 #![allow(overflowing_literals)] diff --git a/src/libcore/num/i16.rs b/src/libcore/num/i16.rs index 5ea60d0d96d29..dacb4ebcdfa3a 100644 --- a/src/libcore/num/i16.rs +++ b/src/libcore/num/i16.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 16-bits integers (`i16` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i16")] int_module! { i16, 16 } diff --git a/src/libcore/num/i32.rs b/src/libcore/num/i32.rs index 7d9faa998c12e..250d66de70b34 100644 --- a/src/libcore/num/i32.rs +++ b/src/libcore/num/i32.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 32-bits integers (`i32` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i32")] int_module! { i32, 32 } diff --git a/src/libcore/num/i64.rs b/src/libcore/num/i64.rs index 5a70911387b9b..5ed21d7246cd0 100644 --- a/src/libcore/num/i64.rs +++ b/src/libcore/num/i64.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 64-bits integers (`i64` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i64")] int_module! { i64, 64 } diff --git a/src/libcore/num/i8.rs b/src/libcore/num/i8.rs index 1d7d78ffa6c23..0394c12d5c457 100644 --- a/src/libcore/num/i8.rs +++ b/src/libcore/num/i8.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 8-bits integers (`i8` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i8")] int_module! { i8, 8 } diff --git a/src/libcore/num/isize.rs b/src/libcore/num/isize.rs index 2cdfe03eafe7f..066cb10cce265 100644 --- a/src/libcore/num/isize.rs +++ b/src/libcore/num/isize.rs @@ -11,7 +11,6 @@ //! Operations and constants for pointer-sized signed integers (`isize` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "isize")] #[cfg(target_pointer_width = "32")] int_module! { isize, 32 } diff --git a/src/libcore/num/u16.rs b/src/libcore/num/u16.rs index 21635799a77a2..ecf799448483c 100644 --- a/src/libcore/num/u16.rs +++ b/src/libcore/num/u16.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 16-bits integers (`u16` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u16")] uint_module! { u16, i16, 16 } diff --git a/src/libcore/num/u32.rs b/src/libcore/num/u32.rs index 7d520770503d4..b0682b55ac05d 100644 --- a/src/libcore/num/u32.rs +++ b/src/libcore/num/u32.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 32-bits integers (`u32` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u32")] uint_module! { u32, i32, 32 } diff --git a/src/libcore/num/u64.rs b/src/libcore/num/u64.rs index f10822077dc75..dbc6a64a905d2 100644 --- a/src/libcore/num/u64.rs +++ b/src/libcore/num/u64.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 64-bits integer (`u64` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u64")] uint_module! { u64, i64, 64 } diff --git a/src/libcore/num/u8.rs b/src/libcore/num/u8.rs index 3d6922b07b194..bf9347ca62c92 100644 --- a/src/libcore/num/u8.rs +++ b/src/libcore/num/u8.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 8-bits integers (`u8` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u8")] uint_module! { u8, i8, 8 } diff --git a/src/libcore/num/usize.rs b/src/libcore/num/usize.rs index 6fd23425e4d89..67e3c954ab695 100644 --- a/src/libcore/num/usize.rs +++ b/src/libcore/num/usize.rs @@ -11,6 +11,5 @@ //! Operations and constants for pointer-sized unsigned integers (`usize` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "usize")] uint_module! { usize, isize, ::isize::BITS } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index b47ced03fba29..13d95e9ab1a71 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -12,82 +12,9 @@ //! Raw, unsafe pointers, `*const T`, and `*mut T` //! -//! Working with raw pointers in Rust is uncommon, -//! typically limited to a few patterns. -//! -//! Use the `null` function to create null pointers, and the `is_null` method -//! of the `*const T` type to check for null. The `*const T` type also defines -//! the `offset` method, for pointer math. -//! -//! # Common ways to create raw pointers -//! -//! ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`). -//! -//! ``` -//! let my_num: i32 = 10; -//! let my_num_ptr: *const i32 = &my_num; -//! let mut my_speed: i32 = 88; -//! let my_speed_ptr: *mut i32 = &mut my_speed; -//! ``` -//! -//! To get a pointer to a boxed value, dereference the box: -//! -//! ``` -//! let my_num: Box = Box::new(10); -//! let my_num_ptr: *const i32 = &*my_num; -//! let mut my_speed: Box = Box::new(88); -//! let my_speed_ptr: *mut i32 = &mut *my_speed; -//! ``` -//! -//! This does not take ownership of the original allocation -//! and requires no resource management later, -//! but you must not use the pointer after its lifetime. -//! -//! ## 2. Consume a box (`Box`). -//! -//! The `into_raw` function consumes a box and returns -//! the raw pointer. It doesn't destroy `T` or deallocate any memory. -//! -//! ``` -//! # #![feature(box_raw)] -//! let my_speed: Box = Box::new(88); -//! let my_speed: *mut i32 = Box::into_raw(my_speed); -//! -//! // By taking ownership of the original `Box` though -//! // we are obligated to put it together later to be destroyed. -//! unsafe { -//! drop(Box::from_raw(my_speed)); -//! } -//! ``` -//! -//! Note that here the call to `drop` is for clarity - it indicates -//! that we are done with the given value and it should be destroyed. -//! -//! ## 3. Get it from C. -//! -//! ``` -//! # #![feature(libc)] -//! extern crate libc; -//! -//! use std::mem; -//! -//! fn main() { -//! unsafe { -//! let my_num: *mut i32 = libc::malloc(mem::size_of::() as libc::size_t) as *mut i32; -//! if my_num.is_null() { -//! panic!("failed to allocate memory"); -//! } -//! libc::free(my_num as *mut libc::c_void); -//! } -//! } -//! ``` -//! -//! Usually you wouldn't literally use `malloc` and `free` from Rust, -//! but C APIs hand out a lot of pointers generally, so are a common source -//! of raw pointers in Rust. +//! *[See also the pointer primitive types](../primitive.pointer.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "pointer")] use mem; use clone::Clone; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 2c6acbf9157de..9339f232e9197 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -13,7 +13,6 @@ //! For more details `std::slice`. #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "slice")] // How this module is organized. // diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 7e4c2ba3be875..9a860c1c16ea5 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -12,7 +12,6 @@ //! //! For more details, see std::str -#![doc(primitive = "str")] #![stable(feature = "rust1", since = "1.0.0")] use self::pattern::Pattern; diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index 9e97078c529e1..6c5ff22232365 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -28,7 +28,6 @@ //! * `Default` #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "tuple")] use clone::Clone; use cmp::*; diff --git a/src/librustc_unicode/char.rs b/src/librustc_unicode/char.rs index fb9ff26776202..42c19ee6a204d 100644 --- a/src/librustc_unicode/char.rs +++ b/src/librustc_unicode/char.rs @@ -14,9 +14,9 @@ //! implementation for the primitive `char` type, in order to allow //! basic character manipulation. //! -//! A `char` actually represents a -//! *[Unicode Scalar -//! Value](http://www.unicode.org/glossary/#unicode_scalar_value)*, as it can +//! A `char` represents a +//! *[Unicode scalar +//! value](http://www.unicode.org/glossary/#unicode_scalar_value)*, as it can //! contain any Unicode code point except high-surrogate and low-surrogate code //! points. //! @@ -24,9 +24,10 @@ //! (inclusive) are allowed. A `char` can always be safely cast to a `u32`; //! however the converse is not always true due to the above range limits //! and, as such, should be performed via the `from_u32` function. +//! +//! *[See also the `char` primitive type](../primitive.char.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "char")] use core::char::CharExt as C; use core::option::Option::{self, Some, None}; diff --git a/src/libstd/array.rs b/src/libstd/array.rs deleted file mode 100644 index f6d133319c848..0000000000000 --- a/src/libstd/array.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015 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. - -//! A fixed-size array, denoted `[T; N]`, for the element type, `T`, and -//! the non-negative compile time constant size, `N`. -//! -//! Arrays values are created either with an explicit expression that lists -//! each element: `[x, y, z]` or a repeat expression: `[x; N]`. The repeat -//! expression requires that the element type is `Copy`. -//! -//! The type `[T; N]` is `Copy` if `T: Copy`. -//! -//! Arrays of sizes from 0 to 32 (inclusive) implement the following traits -//! if the element type allows it: -//! -//! - `Clone` -//! - `Debug` -//! - `IntoIterator` (implemented for `&[T; N]` and `&mut [T; N]`) -//! - `PartialEq`, `PartialOrd`, `Ord`, `Eq` -//! - `Hash` -//! - `AsRef`, `AsMut` -//! -//! Arrays dereference to [slices (`[T]`)][slice], so their methods can be called -//! on arrays. -//! -//! [slice]: primitive.slice.html -//! -//! Rust does not currently support generics over the size of an array type. -//! -//! # Examples -//! -//! ``` -//! let mut array: [i32; 3] = [0; 3]; -//! -//! array[1] = 1; -//! array[2] = 2; -//! -//! assert_eq!([1, 2], &array[1..]); -//! -//! // This loop prints: 0 1 2 -//! for x in &array { -//! print!("{} ", x); -//! } -//! -//! ``` -//! - -#![doc(primitive = "array")] diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs deleted file mode 100644 index df703b3e43e32..0000000000000 --- a/src/libstd/bool.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2013 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. - -//! The boolean type - -#![doc(primitive = "bool")] -#![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fa90670acfbef..b57cc486e83c8 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -415,12 +415,10 @@ pub mod __rand { pub use rand::{thread_rng, ThreadRng, Rng}; } -// Modules that exist purely to document + host impl docs for primitive types - -mod array; -mod bool; -mod unit; -mod tuple; +// Include a private number of modules that exist soley to provide the +// rustdoc documentation for primitive types. Using `include!` because +// rustdoc only looks for these modules at the crate level. +include!("primitive_docs.rs"); // A curious inner-module that's not exported that contains the binding // 'std' so that macro-expanded references to std::error and such diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 561b84ca21a55..259106ac0b4a3 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -9,10 +9,12 @@ // except according to those terms. //! The 32-bit floating point type +//! +//! *[See also the `f32` primitive type](../primitive.f32.html).* #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#![doc(primitive = "f32")] +#![allow(unsigned_negation)] use prelude::v1::*; diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 8a77566faeb92..3cb1ee06e5cb7 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -9,10 +9,11 @@ // except according to those terms. //! The 32-bit floating point type +//! +//! *[See also the `f64` primitive type](../primitive.f64.html).* #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#![doc(primitive = "f64")] use prelude::v1::*; diff --git a/src/libstd/num/i16.rs b/src/libstd/num/i16.rs index 04a45072d1a5b..e8ad74cce4e77 100644 --- a/src/libstd/num/i16.rs +++ b/src/libstd/num/i16.rs @@ -9,9 +9,10 @@ // except according to those terms. //! The 16-bit signed integer type +//! +//! *[See also the `i16` primitive type](../primitive.i16.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i16")] pub use core::i16::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/i32.rs b/src/libstd/num/i32.rs index 09177c188de3f..d30f76b5580d2 100644 --- a/src/libstd/num/i32.rs +++ b/src/libstd/num/i32.rs @@ -9,9 +9,10 @@ // except according to those terms. //! The 32-bit signed integer type +//! +//! *[See also the `i32` primitive type](../primitive.i32.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i32")] pub use core::i32::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/i64.rs b/src/libstd/num/i64.rs index 84fccc9d25fda..9c3cf23800c2f 100644 --- a/src/libstd/num/i64.rs +++ b/src/libstd/num/i64.rs @@ -9,9 +9,10 @@ // except according to those terms. //! The 64-bit signed integer type +//! +//! *[See also the `i64` primitive type](../primitive.i64.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i64")] pub use core::i64::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/i8.rs b/src/libstd/num/i8.rs index f0e8488384764..fdd45a1e117eb 100644 --- a/src/libstd/num/i8.rs +++ b/src/libstd/num/i8.rs @@ -9,9 +9,10 @@ // except according to those terms. //! The 8-bit signed integer type +//! +//! *[See also the `i8` primitive type](../primitive.i8.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i8")] pub use core::i8::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/isize.rs b/src/libstd/num/isize.rs index b602c7c704ad9..3da96c7601cd3 100644 --- a/src/libstd/num/isize.rs +++ b/src/libstd/num/isize.rs @@ -9,9 +9,10 @@ // except according to those terms. //! The pointer-sized signed integer type +//! +//! *[See also the `isize` primitive type](../primitive.isize.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "isize")] pub use core::isize::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u16.rs b/src/libstd/num/u16.rs index 17f254022009c..6acdc65b9ea09 100644 --- a/src/libstd/num/u16.rs +++ b/src/libstd/num/u16.rs @@ -9,9 +9,10 @@ // except according to those terms. //! The 16-bit unsigned integer type +//! +//! *[See also the `u16` primitive type](../primitive.u16.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u16")] pub use core::u16::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u32.rs b/src/libstd/num/u32.rs index 13be3677dac59..78496f9891069 100644 --- a/src/libstd/num/u32.rs +++ b/src/libstd/num/u32.rs @@ -9,9 +9,10 @@ // except according to those terms. //! The 32-bit unsigned integer type +//! +//! *[See also the `u32` primitive type](../primitive.u32.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u32")] pub use core::u32::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u64.rs b/src/libstd/num/u64.rs index 40b6e138307aa..0c0d5dc3e9d87 100644 --- a/src/libstd/num/u64.rs +++ b/src/libstd/num/u64.rs @@ -9,9 +9,10 @@ // except according to those terms. //! The 64-bit unsigned integer type +//! +//! *[See also the `u64` primitive type](../primitive.u64.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u64")] pub use core::u64::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u8.rs b/src/libstd/num/u8.rs index 02fc807e1f2d1..7ca80d07fd66a 100644 --- a/src/libstd/num/u8.rs +++ b/src/libstd/num/u8.rs @@ -9,9 +9,10 @@ // except according to those terms. //! The 8-bit unsigned integer type +//! +//! *[See also the `u8` primitive type](../primitive.u8.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u8")] pub use core::u8::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/usize.rs b/src/libstd/num/usize.rs index 548c0dbb8dcea..15e783bc40e50 100644 --- a/src/libstd/num/usize.rs +++ b/src/libstd/num/usize.rs @@ -9,9 +9,10 @@ // except according to those terms. //! The pointer-sized unsigned integer type +//! +//! *[See also the `usize` primitive type](../primitive.usize.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "usize")] pub use core::usize::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs new file mode 100644 index 0000000000000..9b4c8af2aa966 --- /dev/null +++ b/src/libstd/primitive_docs.rs @@ -0,0 +1,420 @@ +// Copyright 2015 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. + +#[doc(primitive = "bool")] +// +/// The boolean type. +/// +mod prim_bool { } + +#[doc(primitive = "char")] +// +/// A Unicode scalar value +/// +/// A `char` represents a +/// *[Unicode scalar +/// value](http://www.unicode.org/glossary/#unicode_scalar_value)*, as it can +/// contain any Unicode code point except high-surrogate and low-surrogate code +/// points. +/// +/// As such, only values in the ranges \[0x0,0xD7FF\] and \[0xE000,0x10FFFF\] +/// (inclusive) are allowed. A `char` can always be safely cast to a `u32`; +/// however the converse is not always true due to the above range limits +/// and, as such, should be performed via the `from_u32` function. +/// +/// *[See also the `std::char` module](char/index.html).* +/// +mod prim_char { } + +#[doc(primitive = "unit")] +// +/// The `()` type, sometimes called "unit" or "nil". +/// +/// The `()` type has exactly one value `()`, and is used when there +/// is no other meaningful value that could be returned. `()` is most +/// commonly seen implicitly: functions without a `-> ...` implicitly +/// have return type `()`, that is, these are equivalent: +/// +/// ```rust +/// fn long() -> () {} +/// +/// fn short() {} +/// ``` +/// +/// The semicolon `;` can be used to discard the result of an +/// expression at the end of a block, making the expression (and thus +/// the block) evaluate to `()`. For example, +/// +/// ```rust +/// fn returns_i64() -> i64 { +/// 1i64 +/// } +/// fn returns_unit() { +/// 1i64; +/// } +/// +/// let is_i64 = { +/// returns_i64() +/// }; +/// let is_unit = { +/// returns_i64(); +/// }; +/// ``` +/// +mod prim_unit { } + +#[doc(primitive = "pointer")] +// +/// Raw, unsafe pointers, `*const T`, and `*mut T` +/// +/// Working with raw pointers in Rust is uncommon, +/// typically limited to a few patterns. +/// +/// Use the `null` function to create null pointers, and the `is_null` method +/// of the `*const T` type to check for null. The `*const T` type also defines +/// the `offset` method, for pointer math. +/// +/// # Common ways to create raw pointers +/// +/// ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`). +/// +/// ``` +/// let my_num: i32 = 10; +/// let my_num_ptr: *const i32 = &my_num; +/// let mut my_speed: i32 = 88; +/// let my_speed_ptr: *mut i32 = &mut my_speed; +/// ``` +/// +/// To get a pointer to a boxed value, dereference the box: +/// +/// ``` +/// let my_num: Box = Box::new(10); +/// let my_num_ptr: *const i32 = &*my_num; +/// let mut my_speed: Box = Box::new(88); +/// let my_speed_ptr: *mut i32 = &mut *my_speed; +/// ``` +/// +/// This does not take ownership of the original allocation +/// and requires no resource management later, +/// but you must not use the pointer after its lifetime. +/// +/// ## 2. Consume a box (`Box`). +/// +/// The `into_raw` function consumes a box and returns +/// the raw pointer. It doesn't destroy `T` or deallocate any memory. +/// +/// ``` +/// # #![feature(box_raw)] +/// let my_speed: Box = Box::new(88); +/// let my_speed: *mut i32 = Box::into_raw(my_speed); +/// +/// // By taking ownership of the original `Box` though +/// // we are obligated to put it together later to be destroyed. +/// unsafe { +/// drop(Box::from_raw(my_speed)); +/// } +/// ``` +/// +/// Note that here the call to `drop` is for clarity - it indicates +/// that we are done with the given value and it should be destroyed. +/// +/// ## 3. Get it from C. +/// +/// ``` +/// # #![feature(libc)] +/// extern crate libc; +/// +/// use std::mem; +/// +/// fn main() { +/// unsafe { +/// let my_num: *mut i32 = libc::malloc(mem::size_of::() as libc::size_t) as *mut i32; +/// if my_num.is_null() { +/// panic!("failed to allocate memory"); +/// } +/// libc::free(my_num as *mut libc::c_void); +/// } +/// } +/// ``` +/// +/// Usually you wouldn't literally use `malloc` and `free` from Rust, +/// but C APIs hand out a lot of pointers generally, so are a common source +/// of raw pointers in Rust. +/// +/// *[See also the `std::ptr` module](ptr/index.html).* +/// +mod prim_pointer { } + +#[doc(primitive = "array")] +// +/// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and +/// the non-negative compile time constant size, `N`. +/// +/// Arrays values are created either with an explicit expression that lists +/// each element: `[x, y, z]` or a repeat expression: `[x; N]`. The repeat +/// expression requires that the element type is `Copy`. +/// +/// The type `[T; N]` is `Copy` if `T: Copy`. +/// +/// Arrays of sizes from 0 to 32 (inclusive) implement the following traits +/// if the element type allows it: +/// +/// - `Clone` +/// - `Debug` +/// - `IntoIterator` (implemented for `&[T; N]` and `&mut [T; N]`) +/// - `PartialEq`, `PartialOrd`, `Ord`, `Eq` +/// - `Hash` +/// - `AsRef`, `AsMut` +/// +/// Arrays dereference to [slices (`[T]`)][slice], so their methods can be called +/// on arrays. +/// +/// [slice]: primitive.slice.html +/// +/// Rust does not currently support generics over the size of an array type. +/// +/// # Examples +/// +/// ``` +/// let mut array: [i32; 3] = [0; 3]; +/// +/// array[1] = 1; +/// array[2] = 2; +/// +/// assert_eq!([1, 2], &array[1..]); +/// +/// // This loop prints: 0 1 2 +/// for x in &array { +/// print!("{} ", x); +/// } +/// +/// ``` +/// +mod prim_array { } + +#[doc(primitive = "slice")] +// +/// A dynamically-sized view into a contiguous sequence, `[T]`. +/// +/// Slices are a view into a block of memory represented as a pointer and a +/// length. +/// +/// ``` +/// // slicing a Vec +/// let vec = vec![1, 2, 3]; +/// let int_slice = &vec[..]; +/// // coercing an array to a slice +/// let str_slice: &[&str] = &["one", "two", "three"]; +/// ``` +/// +/// Slices are either mutable or shared. The shared slice type is `&[T]`, +/// while the mutable slice type is `&mut [T]`, where `T` represents the element +/// type. For example, you can mutate the block of memory that a mutable slice +/// points to: +/// +/// ``` +/// let x = &mut [1, 2, 3]; +/// x[1] = 7; +/// assert_eq!(x, &[1, 7, 3]); +/// ``` +/// +/// *[See also the `std::slice` module](slice/index.html).* +/// +mod prim_slice { } + +#[doc(primitive = "str")] +// +/// Unicode string slices +/// +/// Rust's `str` type is one of the core primitive types of the language. `&str` +/// is the borrowed string type. This type of string can only be created from +/// other strings, unless it is a `&'static str` (see below). It is not possible +/// to move out of borrowed strings because they are owned elsewhere. +/// +/// # Examples +/// +/// Here's some code that uses a `&str`: +/// +/// ``` +/// let s = "Hello, world."; +/// ``` +/// +/// This `&str` is a `&'static str`, which is the type of string literals. +/// They're `'static` because literals are available for the entire lifetime of +/// the program. +/// +/// You can get a non-`'static` `&str` by taking a slice of a `String`: +/// +/// ``` +/// let some_string = "Hello, world.".to_string(); +/// let s = &some_string; +/// ``` +/// +/// # Representation +/// +/// Rust's string type, `str`, is a sequence of Unicode scalar values encoded as +/// a stream of UTF-8 bytes. All [strings](../../reference.html#literals) are +/// guaranteed to be validly encoded UTF-8 sequences. Additionally, strings are +/// not null-terminated and can thus contain null bytes. +/// +/// The actual representation of `str`s have direct mappings to slices: `&str` +/// is the same as `&[u8]`. +/// +/// *[See also the `std::str` module](str/index.html).* +/// +mod prim_str { } + +#[doc(primitive = "tuple")] +// +/// A finite heterogeneous sequence, `(T, U, ..)`. +/// +/// To access the _N_-th element of a tuple one can use `N` itself +/// as a field of the tuple. +/// +/// Indexing starts from zero, so `0` returns first value, `1` +/// returns second value, and so on. In general, a tuple with _S_ +/// elements provides aforementioned fields from `0` to `S-1`. +/// +/// If every type inside a tuple implements one of the following +/// traits, then a tuple itself also implements it. +/// +/// * `Clone` +/// * `PartialEq` +/// * `Eq` +/// * `PartialOrd` +/// * `Ord` +/// * `Debug` +/// * `Default` +/// * `Hash` +/// +/// # Examples +/// +/// Accessing elements of a tuple at specified indices: +/// +/// ``` +/// let x = ("colorless", "green", "ideas", "sleep", "furiously"); +/// assert_eq!(x.3, "sleep"); +/// +/// let v = (3, 3); +/// let u = (1, -5); +/// assert_eq!(v.0 * u.0 + v.1 * u.1, -12); +/// ``` +/// +/// Using traits implemented for tuples: +/// +/// ``` +/// let a = (1, 2); +/// let b = (3, 4); +/// assert!(a != b); +/// +/// let c = b.clone(); +/// assert!(b == c); +/// +/// let d : (u32, f32) = Default::default(); +/// assert_eq!(d, (0, 0.0f32)); +/// ``` +/// +mod prim_tuple { } + +#[doc(primitive = "f32")] +/// The 32-bit floating point type +/// +/// *[See also the `std::f32` module](f32/index.html).* +/// +mod prim_f32 { } + +#[doc(primitive = "f64")] +// +/// The 64-bit floating point type +/// +/// *[See also the `std::f64` module](f64/index.html).* +/// +mod prim_f64 { } + +#[doc(primitive = "i8")] +// +/// The 8-bit signed integer type +/// +/// *[See also the `std::i8` module](i8/index.html).* +/// +mod prim_i8 { } + +#[doc(primitive = "i16")] +// +/// The 16-bit signed integer type +/// +/// *[See also the `std::i16` module](i16/index.html).* +/// +mod prim_i16 { } + +#[doc(primitive = "i32")] +// +/// The 32-bit signed integer type +/// +/// *[See also the `std::i32` module](i32/index.html).* +/// +mod prim_i32 { } + +#[doc(primitive = "i64")] +// +/// The 64-bit signed integer type +/// +/// *[See also the `std::i64` module](i64/index.html).* +/// +mod prim_i64 { } + +#[doc(primitive = "u8")] +// +/// The 8-bit unsigned integer type +/// +/// *[See also the `std::u8` module](u8/index.html).* +/// +mod prim_u8 { } + +#[doc(primitive = "u16")] +// +/// The 16-bit unsigned integer type +/// +/// *[See also the `std::u16` module](u16/index.html).* +/// +mod prim_u16 { } + +#[doc(primitive = "u32")] +// +/// The 32-bit unsigned integer type +/// +/// *[See also the `std::u32` module](u32/index.html).* +/// +mod prim_u32 { } + +#[doc(primitive = "u64")] +// +/// The 64-bit unsigned integer type +/// +/// *[See also the `std::u64` module](u64/index.html).* +/// +mod prim_u64 { } + +#[doc(primitive = "isize")] +// +/// The pointer-sized signed integer type +/// +/// *[See also the `std::isize` module](isize/index.html).* +/// +mod prim_isize { } + +#[doc(primitive = "usize")] +// +/// The pointer-sized signed integer type +/// +/// *[See also the `std::usize` module](usize/index.html).* +/// +mod prim_usize { } + diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs deleted file mode 100644 index 1e4de19c87466..0000000000000 --- a/src/libstd/tuple.rs +++ /dev/null @@ -1,60 +0,0 @@ -// 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. - -//! A finite heterogeneous sequence, `(T, U, ..)` -//! -//! To access the _N_-th element of a tuple one can use `N` itself -//! as a field of the tuple. -//! -//! Indexing starts from zero, so `0` returns first value, `1` -//! returns second value, and so on. In general, a tuple with _S_ -//! elements provides aforementioned fields from `0` to `S-1`. -//! -//! If every type inside a tuple implements one of the following -//! traits, then a tuple itself also implements it. -//! -//! * `Clone` -//! * `PartialEq` -//! * `Eq` -//! * `PartialOrd` -//! * `Ord` -//! * `Debug` -//! * `Default` -//! * `Hash` -//! -//! # Examples -//! -//! Accessing elements of a tuple at specified indices: -//! -//! ``` -//! let x = ("colorless", "green", "ideas", "sleep", "furiously"); -//! assert_eq!(x.3, "sleep"); -//! -//! let v = (3, 3); -//! let u = (1, -5); -//! assert_eq!(v.0 * u.0 + v.1 * u.1, -12); -//! ``` -//! -//! Using traits implemented for tuples: -//! -//! ``` -//! let a = (1, 2); -//! let b = (3, 4); -//! assert!(a != b); -//! -//! let c = b.clone(); -//! assert!(b == c); -//! -//! let d : (u32, f32) = Default::default(); -//! assert_eq!(d, (0, 0.0f32)); -//! ``` - -#![doc(primitive = "tuple")] -#![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/unit.rs b/src/libstd/unit.rs deleted file mode 100644 index 2c3ddcd9d4947..0000000000000 --- a/src/libstd/unit.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014 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. - -#![doc(primitive = "unit")] -#![stable(feature = "rust1", since = "1.0.0")] - -//! The `()` type, sometimes called "unit" or "nil". -//! -//! The `()` type has exactly one value `()`, and is used when there -//! is no other meaningful value that could be returned. `()` is most -//! commonly seen implicitly: functions without a `-> ...` implicitly -//! have return type `()`, that is, these are equivalent: -//! -//! ```rust -//! fn long() -> () {} -//! -//! fn short() {} -//! ``` -//! -//! The semicolon `;` can be used to discard the result of an -//! expression at the end of a block, making the expression (and thus -//! the block) evaluate to `()`. For example, -//! -//! ```rust -//! fn returns_i64() -> i64 { -//! 1i64 -//! } -//! fn returns_unit() { -//! 1i64; -//! } -//! -//! let is_i64 = { -//! returns_i64() -//! }; -//! let is_unit = { -//! returns_i64(); -//! }; -//! ``` From 9e18326291e440a0d8aecf4d817e7e3129183a01 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Jul 2015 15:52:43 -0400 Subject: [PATCH 37/66] Update docs for take and broadcast Better and more consistent links to their creators. --- src/libstd/io/mod.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 2447473103101..25f0c9cf55016 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1167,7 +1167,10 @@ pub trait BufRead: Read { /// A `Write` adaptor which will write data to multiple locations. /// -/// For more information, see `Write::broadcast`. +/// This struct is generally created by calling [`broadcast()`][broadcast] on a +/// writer. Please see the documentation of `broadcast()` for more details. +/// +/// [broadcast]: trait.Write.html#method.broadcast #[unstable(feature = "io", reason = "awaiting stability of Write::broadcast")] pub struct Broadcast { first: T, @@ -1213,7 +1216,10 @@ impl Read for Chain { /// Reader adaptor which limits the bytes read from an underlying reader. /// -/// For more information, see `Read::take`. +/// This struct is generally created by calling [`take()`][take] on a reader. +/// Please see the documentation of `take()` for more details. +/// +/// [take]: trait.Read.html#method.take #[stable(feature = "rust1", since = "1.0.0")] pub struct Take { inner: T, From fa28192312f2b22e411fc19db78893acf52fa7cf Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Jul 2015 18:07:35 -0400 Subject: [PATCH 38/66] Write better docs for std::io This is the landing page for all of io, so we should have more than just a sentence here. --- src/libstd/io/mod.rs | 229 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 2447473103101..3016cfa8fe5e3 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -9,6 +9,235 @@ // except according to those terms. //! Traits, helpers, and type definitions for core I/O functionality. +//! +//! The `std::io` module contains a number of common things you'll need +//! when doing input and output. The most core part of this module is +//! the [`Read`][read] and [`Write`][write] traits, which provide the +//! most general interface for reading and writing input and output. +//! +//! [read]: trait.Read.html +//! [write]: trait.Write.html +//! +//! # Read and Write +//! +//! Because they are traits, they're implemented by a number of other types, +//! and you can implement them for your types too. As such, you'll see a +//! few different types of I/O throughout the documentation in this module: +//! `File`s, `TcpStream`s, and somtimes even `Vec`s. For example, `Read` +//! adds a `read()` method, which we can use on `File`s: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let mut f = try!(File::open("foo.txt")); +//! let mut buffer = [0; 10]; +//! +//! // read up to 10 bytes +//! try!(f.read(&mut buffer)); +//! +//! println!("The bytes: {:?}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! `Read` and `Write` are so important, implementors of the two traits have a +//! nickname: readers and writers. So you'll sometimes see 'a reader' instead +//! of 'a type that implements the `Read` trait'. Much easier! +//! +//! ## Seek and BufRead +//! +//! Beyond that, there are two important traits that are provided: [`Seek`][seek] +//! and [`BufRead`][bufread]. Both of these build on top of a reader to control +//! how the reading happens. `Seek` lets you control where the next byte is +//! coming from: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::SeekFrom; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let mut f = try!(File::open("foo.txt")); +//! let mut buffer = [0; 10]; +//! +//! // skip to the last 10 bytes of the file +//! try!(f.seek(SeekFrom::End(-10))); +//! +//! // read up to 10 bytes +//! try!(f.read(&mut buffer)); +//! +//! println!("The bytes: {:?}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! [seek]: trait.Seek.html +//! [bufread]: trait.BufRead.html +//! +//! `BufRead` uses an internal buffer to provide a number of other ways to read, but +//! to show it off, we'll need to talk about buffers in general. Keep reading! +//! +//! ## BufReader and BufWriter +//! +//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be +//! making near-constant calls to the operating system. To help with this, +//! `std::io` comes with two structs, `BufReader` and `BufWriter`, which wrap +//! readers and writers. The wrapper uses a buffer, reducing the number of +//! calls and providing nicer methods for accessing exactly what you want. +//! +//! For example, `BufReader` works with the `BufRead` trait to add extra +//! methods to any reader: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::open("foo.txt")); +//! let mut reader = BufReader::new(f); +//! let mut buffer = String::new(); +//! +//! // read a line into buffer +//! try!(reader.read_line(&mut buffer)); +//! +//! println!("{}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! `BufWriter` doesn't add any new ways of writing, it just buffers every call +//! to [`write()`][write]: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufWriter; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::create("foo.txt")); +//! { +//! let mut writer = BufWriter::new(f); +//! +//! // write a byte to the buffer +//! try!(writer.write(&[42])); +//! +//! } // the buffer is flushed once writer goes out of scope +//! +//! # Ok(()) +//! # } +//! ``` +//! +//! [write]: trait.Write.html#tymethod.write +//! +//! ## Standard input and output +//! +//! A very common source of input is standard input: +//! +//! ``` +//! use std::io; +//! +//! # fn foo() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! try!(io::stdin().read_line(&mut input)); +//! +//! println!("You typed: {}", input.trim()); +//! # Ok(()) +//! # } +//! ``` +//! +//! And a very common source of output is standard output: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! +//! # fn foo() -> io::Result<()> { +//! try!(io::stdout().write(&[42])); +//! # Ok(()) +//! # } +//! ``` +//! +//! Of course, using `io::stdout()` directly is less comon than something like +//! `println!`. +//! +//! ## Iterator types +//! +//! A large number of the structures provided by `std::io` are for various +//! ways of iterating over I/O. For example, `Lines` is used to split over +//! lines: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::open("foo.txt")); +//! let mut reader = BufReader::new(f); +//! +//! for line in reader.lines() { +//! let line = try!(line); +//! println!("{}", line); +//! } +//! +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Functions +//! +//! There are a number of [functions][functions] that offer access to various +//! features. For example, we can use three of these functions to copy everything +//! from standard input to standard output: +//! +//! ``` +//! use std::io; +//! +//! # fn foo() -> io::Result<()> { +//! try!(io::copy(&mut io::stdin(), &mut io::stdout())); +//! # Ok(()) +//! # } +//! ``` +//! +//! [functions]: #functions +//! +//! ## io::Result +//! +//! Last, but certainly not least, is [`io::Result`][result]. This type is used +//! as the return type of many `std::io` functions that can cause an error, and +//! can be returned from your own functions as well. Many of the examples in this +//! module use the [`try!`][try] macro: +//! +//! ``` +//! use std::io; +//! +//! fn read_input() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! try!(io::stdin().read_line(&mut input)); +//! +//! println!("You typed: {}", input.trim()); +//! +//! Ok(()) +//! } +//! ``` +//! +//! The return type of `read_input()`, `io::Result<()>`, is a very common type +//! for functions which don't have a 'real' return value, but do want to return +//! errors if they happen. In this case, the only purpose of this function is +//! to read the line and print it, so we use use `()`. +//! +//! [result]: type.Result.html +//! [try]: macro.try!.html #![stable(feature = "rust1", since = "1.0.0")] From 24c5e492751489280f446f4efff1740a6c3e5aa1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 20 Jul 2015 16:12:48 -0700 Subject: [PATCH 39/66] std: Fix compiling the standard library on i686-MSVC This commit fixes building the standard library with the `i686-pc-windows-msvc` target by correcting an included symbol name to the linker. --- src/libstd/sys/windows/thread_local.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index a2dbb0f834243..7550b7ce6c352 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -231,9 +231,12 @@ pub static p_thread_callback: unsafe extern "system" fn(LPVOID, DWORD, LPVOID) = on_tls_callback; -#[cfg(target_env = "msvc")] +#[cfg(all(target_env = "msvc", target_pointer_width = "64"))] #[link_args = "/INCLUDE:_tls_used"] extern {} +#[cfg(all(target_env = "msvc", target_pointer_width = "32"))] +#[link_args = "/INCLUDE:__tls_used"] +extern {} #[allow(warnings)] unsafe extern "system" fn on_tls_callback(h: LPVOID, From a3e78f4151ee23ad3175402e81247302619c1df7 Mon Sep 17 00:00:00 2001 From: William Throwe Date: Mon, 20 Jul 2015 01:23:46 -0400 Subject: [PATCH 40/66] Add test of cross-crate impl formatting --- .../rustdoc-impl-parts-crosscrate.rs | 15 ++++++++++ src/test/rustdoc/impl-parts-crosscrate.rs | 30 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/test/auxiliary/rustdoc-impl-parts-crosscrate.rs create mode 100644 src/test/rustdoc/impl-parts-crosscrate.rs diff --git a/src/test/auxiliary/rustdoc-impl-parts-crosscrate.rs b/src/test/auxiliary/rustdoc-impl-parts-crosscrate.rs new file mode 100644 index 0000000000000..6e8f80c8f5f9f --- /dev/null +++ b/src/test/auxiliary/rustdoc-impl-parts-crosscrate.rs @@ -0,0 +1,15 @@ +// Copyright 2015 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(optin_builtin_traits)] + +pub trait AnOibit {} + +impl AnOibit for .. {} diff --git a/src/test/rustdoc/impl-parts-crosscrate.rs b/src/test/rustdoc/impl-parts-crosscrate.rs new file mode 100644 index 0000000000000..5fa2e03e0a884 --- /dev/null +++ b/src/test/rustdoc/impl-parts-crosscrate.rs @@ -0,0 +1,30 @@ +// Copyright 2015 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. + +// aux-build:rustdoc-impl-parts-crosscrate.rs +// ignore-cross-compile + +#![feature(optin_builtin_traits)] + +extern crate rustdoc_impl_parts_crosscrate; + +pub struct Bar { t: T } + +// The output file is html embeded in javascript, so the html tags +// aren't stripped by the processing script and we can't check for the +// full impl string. Instead, just make sure something from each part +// is mentioned. + +// @has implementors/rustdoc_impl_parts_crosscrate/trait.AnOibit.js Bar +// @has - Send +// @has - !AnOibit +// @has - Copy +impl !rustdoc_impl_parts_crosscrate::AnOibit for Bar + where T: Copy {} From 778c89c1bb86dbd370e8b51911e2916180f42aec Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 20 Jul 2015 17:12:59 -0700 Subject: [PATCH 41/66] Address feedback --- src/libstd/lib.rs | 6 +++--- src/libstd/num/f32.rs | 2 +- src/libstd/num/f64.rs | 2 +- src/libstd/num/i16.rs | 2 +- src/libstd/num/i32.rs | 2 +- src/libstd/num/i64.rs | 2 +- src/libstd/num/i8.rs | 2 +- src/libstd/num/isize.rs | 2 +- src/libstd/num/u16.rs | 2 +- src/libstd/num/u32.rs | 2 +- src/libstd/num/u64.rs | 2 +- src/libstd/num/u8.rs | 2 +- src/libstd/num/usize.rs | 2 +- src/libstd/primitive_docs.rs | 30 +++++++++++++++--------------- 14 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b57cc486e83c8..82bc1314ad547 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -415,9 +415,9 @@ pub mod __rand { pub use rand::{thread_rng, ThreadRng, Rng}; } -// Include a private number of modules that exist soley to provide the -// rustdoc documentation for primitive types. Using `include!` because -// rustdoc only looks for these modules at the crate level. +// Include a number of private modules that exist solely to provide +// the rustdoc documentation for primitive types. Using `include!` +// because rustdoc only looks for these modules at the crate level. include!("primitive_docs.rs"); // A curious inner-module that's not exported that contains the binding diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 259106ac0b4a3..b8a70d756efff 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 32-bit floating point type +//! The 32-bit floating point type. //! //! *[See also the `f32` primitive type](../primitive.f32.html).* diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 3cb1ee06e5cb7..4f2f59659ac80 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 32-bit floating point type +//! The 64-bit floating point type. //! //! *[See also the `f64` primitive type](../primitive.f64.html).* diff --git a/src/libstd/num/i16.rs b/src/libstd/num/i16.rs index e8ad74cce4e77..eb53e0821f2a6 100644 --- a/src/libstd/num/i16.rs +++ b/src/libstd/num/i16.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 16-bit signed integer type +//! The 16-bit signed integer type. //! //! *[See also the `i16` primitive type](../primitive.i16.html).* diff --git a/src/libstd/num/i32.rs b/src/libstd/num/i32.rs index d30f76b5580d2..3c9eedf38c7cd 100644 --- a/src/libstd/num/i32.rs +++ b/src/libstd/num/i32.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 32-bit signed integer type +//! The 32-bit signed integer type. //! //! *[See also the `i32` primitive type](../primitive.i32.html).* diff --git a/src/libstd/num/i64.rs b/src/libstd/num/i64.rs index 9c3cf23800c2f..2df7478a820bf 100644 --- a/src/libstd/num/i64.rs +++ b/src/libstd/num/i64.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 64-bit signed integer type +//! The 64-bit signed integer type. //! //! *[See also the `i64` primitive type](../primitive.i64.html).* diff --git a/src/libstd/num/i8.rs b/src/libstd/num/i8.rs index fdd45a1e117eb..4e4bee8a791e4 100644 --- a/src/libstd/num/i8.rs +++ b/src/libstd/num/i8.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 8-bit signed integer type +//! The 8-bit signed integer type. //! //! *[See also the `i8` primitive type](../primitive.i8.html).* diff --git a/src/libstd/num/isize.rs b/src/libstd/num/isize.rs index 3da96c7601cd3..d46b6b80d0d25 100644 --- a/src/libstd/num/isize.rs +++ b/src/libstd/num/isize.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The pointer-sized signed integer type +//! The pointer-sized signed integer type. //! //! *[See also the `isize` primitive type](../primitive.isize.html).* diff --git a/src/libstd/num/u16.rs b/src/libstd/num/u16.rs index 6acdc65b9ea09..893618aeffafd 100644 --- a/src/libstd/num/u16.rs +++ b/src/libstd/num/u16.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 16-bit unsigned integer type +//! The 16-bit unsigned integer type. //! //! *[See also the `u16` primitive type](../primitive.u16.html).* diff --git a/src/libstd/num/u32.rs b/src/libstd/num/u32.rs index 78496f9891069..2da2551969657 100644 --- a/src/libstd/num/u32.rs +++ b/src/libstd/num/u32.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 32-bit unsigned integer type +//! The 32-bit unsigned integer type. //! //! *[See also the `u32` primitive type](../primitive.u32.html).* diff --git a/src/libstd/num/u64.rs b/src/libstd/num/u64.rs index 0c0d5dc3e9d87..26a8b53739403 100644 --- a/src/libstd/num/u64.rs +++ b/src/libstd/num/u64.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 64-bit unsigned integer type +//! The 64-bit unsigned integer type. //! //! *[See also the `u64` primitive type](../primitive.u64.html).* diff --git a/src/libstd/num/u8.rs b/src/libstd/num/u8.rs index 7ca80d07fd66a..385754b93a04b 100644 --- a/src/libstd/num/u8.rs +++ b/src/libstd/num/u8.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The 8-bit unsigned integer type +//! The 8-bit unsigned integer type. //! //! *[See also the `u8` primitive type](../primitive.u8.html).* diff --git a/src/libstd/num/usize.rs b/src/libstd/num/usize.rs index 15e783bc40e50..6960ba3b8296b 100644 --- a/src/libstd/num/usize.rs +++ b/src/libstd/num/usize.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The pointer-sized unsigned integer type +//! The pointer-sized unsigned integer type. //! //! *[See also the `usize` primitive type](../primitive.usize.html).* diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 9b4c8af2aa966..066b2b576da49 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -16,7 +16,7 @@ mod prim_bool { } #[doc(primitive = "char")] // -/// A Unicode scalar value +/// A Unicode scalar value. /// /// A `char` represents a /// *[Unicode scalar @@ -72,7 +72,7 @@ mod prim_unit { } #[doc(primitive = "pointer")] // -/// Raw, unsafe pointers, `*const T`, and `*mut T` +/// Raw, unsafe pointers, `*const T`, and `*mut T`. /// /// Working with raw pointers in Rust is uncommon, /// typically limited to a few patterns. @@ -231,7 +231,7 @@ mod prim_slice { } #[doc(primitive = "str")] // -/// Unicode string slices +/// Unicode string slices. /// /// Rust's `str` type is one of the core primitive types of the language. `&str` /// is the borrowed string type. This type of string can only be created from @@ -324,7 +324,7 @@ mod prim_str { } mod prim_tuple { } #[doc(primitive = "f32")] -/// The 32-bit floating point type +/// The 32-bit floating point type. /// /// *[See also the `std::f32` module](f32/index.html).* /// @@ -332,7 +332,7 @@ mod prim_f32 { } #[doc(primitive = "f64")] // -/// The 64-bit floating point type +/// The 64-bit floating point type. /// /// *[See also the `std::f64` module](f64/index.html).* /// @@ -340,7 +340,7 @@ mod prim_f64 { } #[doc(primitive = "i8")] // -/// The 8-bit signed integer type +/// The 8-bit signed integer type. /// /// *[See also the `std::i8` module](i8/index.html).* /// @@ -348,7 +348,7 @@ mod prim_i8 { } #[doc(primitive = "i16")] // -/// The 16-bit signed integer type +/// The 16-bit signed integer type. /// /// *[See also the `std::i16` module](i16/index.html).* /// @@ -356,7 +356,7 @@ mod prim_i16 { } #[doc(primitive = "i32")] // -/// The 32-bit signed integer type +/// The 32-bit signed integer type. /// /// *[See also the `std::i32` module](i32/index.html).* /// @@ -364,7 +364,7 @@ mod prim_i32 { } #[doc(primitive = "i64")] // -/// The 64-bit signed integer type +/// The 64-bit signed integer type. /// /// *[See also the `std::i64` module](i64/index.html).* /// @@ -372,7 +372,7 @@ mod prim_i64 { } #[doc(primitive = "u8")] // -/// The 8-bit unsigned integer type +/// The 8-bit unsigned integer type. /// /// *[See also the `std::u8` module](u8/index.html).* /// @@ -380,7 +380,7 @@ mod prim_u8 { } #[doc(primitive = "u16")] // -/// The 16-bit unsigned integer type +/// The 16-bit unsigned integer type. /// /// *[See also the `std::u16` module](u16/index.html).* /// @@ -388,7 +388,7 @@ mod prim_u16 { } #[doc(primitive = "u32")] // -/// The 32-bit unsigned integer type +/// The 32-bit unsigned integer type. /// /// *[See also the `std::u32` module](u32/index.html).* /// @@ -396,7 +396,7 @@ mod prim_u32 { } #[doc(primitive = "u64")] // -/// The 64-bit unsigned integer type +/// The 64-bit unsigned integer type. /// /// *[See also the `std::u64` module](u64/index.html).* /// @@ -404,7 +404,7 @@ mod prim_u64 { } #[doc(primitive = "isize")] // -/// The pointer-sized signed integer type +/// The pointer-sized signed integer type. /// /// *[See also the `std::isize` module](isize/index.html).* /// @@ -412,7 +412,7 @@ mod prim_isize { } #[doc(primitive = "usize")] // -/// The pointer-sized signed integer type +/// The pointer-sized signed integer type. /// /// *[See also the `std::usize` module](usize/index.html).* /// From a29c8347f2b196c4d5f755d02ab5d65b9be98849 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Jul 2015 20:12:37 -0400 Subject: [PATCH 42/66] Add travis config to TRPL: release channels This should help people configure travis to test all three channels. --- src/doc/trpl/release-channels.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/doc/trpl/release-channels.md b/src/doc/trpl/release-channels.md index 03e65539a2042..1e203c6553ee1 100644 --- a/src/doc/trpl/release-channels.md +++ b/src/doc/trpl/release-channels.md @@ -43,3 +43,26 @@ This will help alert the team in case there’s an accidental regression. Additionally, testing against nightly can catch regressions even sooner, and so if you don’t mind a third build, we’d appreciate testing against all channels. +As an example, many Rust programmers use [Travis](https://travis-ci.org/) to +test their crates, which is free for open source projects. Travis [supports +Rust directly][travis], and you can use a `.travis.yml` file like this to +test on all channels: + +```yaml +language: rust +rust: + - nightly + - beta + - stable + +matrix: + allow_failures: + - rust: nightly +``` + +[travis]: http://docs.travis-ci.com/user/languages/rust/ + +With this configuration, Travis will test all three channels, but if something +breaks on nightly, it won’t fail your build. A similar configuration is +recommended for any CI system, check the documentation of the one you’re +using for more details. From 007246c17f1891cabb84c8a82250703f542cd58e Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 2 Jul 2015 15:37:52 +1200 Subject: [PATCH 43/66] Allow for space between each filemap in the codemap So if a filemap's last byte is at position n in the codemap, then n+1 will not refer to any filemap, and the next filemap will begin an n+2. This is useful for empty files, it means that every file (even empty ones) has a byte in the codemap. Closes #23301, #26504 --- src/libsyntax/codemap.rs | 162 ++++++++++++++++++++---------------- src/libsyntax/diagnostic.rs | 13 +-- 2 files changed, 97 insertions(+), 78 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 5ddcfaef9ea28..2f109b589f143 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -115,6 +115,10 @@ impl Sub for CharPos { /// are *absolute* positions from the beginning of the codemap, not positions /// relative to FileMaps. Methods on the CodeMap can be used to relate spans back /// to the original source. +/// You must be careful if the span crosses more than one file - you will not be +/// able to use many of the functions on spans in codemap and you cannot assume +/// that the length of the span = hi - lo; there may be space in the BytePos +/// range between files. #[derive(Clone, Copy, Hash)] pub struct Span { pub lo: BytePos, @@ -339,7 +343,7 @@ pub struct MultiByteChar { pub bytes: usize, } -/// A single source in the CodeMap +/// A single source in the CodeMap. pub struct FileMap { /// The name of the file that the source came from, source that doesn't /// originate from files has names between angle brackets by convention, @@ -508,6 +512,9 @@ impl FileMap { lines.get(line_number).map(|&line| { let begin: BytePos = line - self.start_pos; let begin = begin.to_usize(); + // We can't use `lines.get(line_number+1)` because we might + // be parsing when we call this function and thus the current + // line is the last one we have line info for. let slice = &src[begin..]; match slice.find('\n') { Some(e) => &slice[..e], @@ -598,27 +605,27 @@ impl CodeMap { Ok(self.new_filemap(path.to_str().unwrap().to_string(), src)) } + fn next_start_pos(&self) -> usize { + let files = self.files.borrow(); + match files.last() { + None => 0, + // Add one so there is some space between files. This lets us distinguish + // positions in the codemap, even in the presence of zero-length files. + Some(last) => last.end_pos.to_usize() + 1, + } + } + + /// Creates a new filemap without setting its line information. If you don't + /// intend to set the line information yourself, you should use new_filemap_and_lines. pub fn new_filemap(&self, filename: FileName, mut src: String) -> Rc { + let start_pos = self.next_start_pos(); let mut files = self.files.borrow_mut(); - let start_pos = match files.last() { - None => 0, - Some(last) => last.end_pos.to_usize(), - }; // Remove utf-8 BOM if any. if src.starts_with("\u{feff}") { src.drain(..3); } - // Append '\n' in case it's not already there. - // This is a workaround to prevent CodeMap.lookup_filemap_idx from - // accidentally overflowing into the next filemap in case the last byte - // of span is also the last byte of filemap, which leads to incorrect - // results from CodeMap.span_to_*. - if !src.is_empty() && !src.ends_with("\n") { - src.push('\n'); - } - let end_pos = start_pos + src.len(); let filemap = Rc::new(FileMap { @@ -645,11 +652,8 @@ impl CodeMap { mut file_local_lines: Vec, mut file_local_multibyte_chars: Vec) -> Rc { + let start_pos = self.next_start_pos(); let mut files = self.files.borrow_mut(); - let start_pos = match files.last() { - None => 0, - Some(last) => last.end_pos.to_usize(), - }; let end_pos = Pos::from_usize(start_pos + source_len); let start_pos = Pos::from_usize(start_pos); @@ -686,39 +690,61 @@ impl CodeMap { /// Lookup source information about a BytePos pub fn lookup_char_pos(&self, pos: BytePos) -> Loc { - let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos); - let line = a + 1; // Line numbers start at 1 let chpos = self.bytepos_to_file_charpos(pos); - let linebpos = (*f.lines.borrow())[a]; - let linechpos = self.bytepos_to_file_charpos(linebpos); - debug!("byte pos {:?} is on the line at byte pos {:?}", - pos, linebpos); - debug!("char pos {:?} is on the line at char pos {:?}", - chpos, linechpos); - debug!("byte is on line: {}", line); - assert!(chpos >= linechpos); - Loc { - file: f, - line: line, - col: chpos - linechpos + match self.lookup_line(pos) { + Ok(FileMapAndLine { fm: f, line: a }) => { + let line = a + 1; // Line numbers start at 1 + let linebpos = (*f.lines.borrow())[a]; + let linechpos = self.bytepos_to_file_charpos(linebpos); + debug!("byte pos {:?} is on the line at byte pos {:?}", + pos, linebpos); + debug!("char pos {:?} is on the line at char pos {:?}", + chpos, linechpos); + debug!("byte is on line: {}", line); + assert!(chpos >= linechpos); + Loc { + file: f, + line: line, + col: chpos - linechpos, + } + } + Err(f) => { + Loc { + file: f, + line: 0, + col: chpos, + } + } } } - fn lookup_line(&self, pos: BytePos) -> FileMapAndLine { + // If the relevant filemap is empty, we don't return a line number. + fn lookup_line(&self, pos: BytePos) -> Result> { let idx = self.lookup_filemap_idx(pos); let files = self.files.borrow(); let f = (*files)[idx].clone(); + + let len = f.lines.borrow().len(); + if len == 0 { + return Err(f); + } + let mut a = 0; { let lines = f.lines.borrow(); let mut b = lines.len(); while b - a > 1 { let m = (a + b) / 2; - if (*lines)[m] > pos { b = m; } else { a = m; } + if (*lines)[m] > pos { + b = m; + } else { + a = m; + } } + assert!(a <= lines.len()); } - FileMapAndLine {fm: f, line: a} + Ok(FileMapAndLine { fm: f, line: a }) } pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt { @@ -880,12 +906,15 @@ impl CodeMap { CharPos(bpos.to_usize() - map.start_pos.to_usize() - total_extra_bytes) } + // Return the index of the filemap (in self.files) which contains pos. fn lookup_filemap_idx(&self, pos: BytePos) -> usize { let files = self.files.borrow(); let files = &*files; - let len = files.len(); + let count = files.len(); + + // Binary search for the filemap. let mut a = 0; - let mut b = len; + let mut b = count; while b - a > 1 { let m = (a + b) / 2; if files[m].start_pos > pos { @@ -894,26 +923,8 @@ impl CodeMap { a = m; } } - // There can be filemaps with length 0. These have the same start_pos as - // the previous filemap, but are not the filemaps we want (because they - // are length 0, they cannot contain what we are looking for). So, - // rewind until we find a useful filemap. - loop { - let lines = files[a].lines.borrow(); - let lines = lines; - if !lines.is_empty() { - break; - } - if a == 0 { - panic!("position {} does not resolve to a source location", - pos.to_usize()); - } - a -= 1; - } - if a >= len { - panic!("position {} does not resolve to a source location", - pos.to_usize()) - } + + assert!(a < count, "position {} does not resolve to a source location", pos.to_usize()); return a; } @@ -1027,10 +1038,13 @@ mod tests { let fm = cm.new_filemap("blork.rs".to_string(), "first line.\nsecond line".to_string()); fm.next_line(BytePos(0)); + // Test we can get lines with partial line info. assert_eq!(fm.get_line(0), Some("first line.")); - // TESTING BROKEN BEHAVIOR: + // TESTING BROKEN BEHAVIOR: line break declared before actual line break. fm.next_line(BytePos(10)); assert_eq!(fm.get_line(1), Some(".")); + fm.next_line(BytePos(12)); + assert_eq!(fm.get_line(2), Some("second line")); } #[test] @@ -1056,9 +1070,9 @@ mod tests { fm1.next_line(BytePos(0)); fm1.next_line(BytePos(12)); - fm2.next_line(BytePos(24)); - fm3.next_line(BytePos(24)); - fm3.next_line(BytePos(34)); + fm2.next_line(fm2.start_pos); + fm3.next_line(fm3.start_pos); + fm3.next_line(fm3.start_pos + BytePos(12)); cm } @@ -1068,11 +1082,15 @@ mod tests { // Test lookup_byte_offset let cm = init_code_map(); - let fmabp1 = cm.lookup_byte_offset(BytePos(22)); + let fmabp1 = cm.lookup_byte_offset(BytePos(23)); assert_eq!(fmabp1.fm.name, "blork.rs"); - assert_eq!(fmabp1.pos, BytePos(22)); + assert_eq!(fmabp1.pos, BytePos(23)); + + let fmabp1 = cm.lookup_byte_offset(BytePos(24)); + assert_eq!(fmabp1.fm.name, "empty.rs"); + assert_eq!(fmabp1.pos, BytePos(0)); - let fmabp2 = cm.lookup_byte_offset(BytePos(24)); + let fmabp2 = cm.lookup_byte_offset(BytePos(25)); assert_eq!(fmabp2.fm.name, "blork2.rs"); assert_eq!(fmabp2.pos, BytePos(0)); } @@ -1085,7 +1103,7 @@ mod tests { let cp1 = cm.bytepos_to_file_charpos(BytePos(22)); assert_eq!(cp1, CharPos(22)); - let cp2 = cm.bytepos_to_file_charpos(BytePos(24)); + let cp2 = cm.bytepos_to_file_charpos(BytePos(25)); assert_eq!(cp2, CharPos(0)); } @@ -1099,7 +1117,7 @@ mod tests { assert_eq!(loc1.line, 2); assert_eq!(loc1.col, CharPos(10)); - let loc2 = cm.lookup_char_pos(BytePos(24)); + let loc2 = cm.lookup_char_pos(BytePos(25)); assert_eq!(loc2.file.name, "blork2.rs"); assert_eq!(loc2.line, 1); assert_eq!(loc2.col, CharPos(0)); @@ -1115,18 +1133,18 @@ mod tests { "first line€€.\n€ second line".to_string()); fm1.next_line(BytePos(0)); - fm1.next_line(BytePos(22)); - fm2.next_line(BytePos(40)); - fm2.next_line(BytePos(58)); + fm1.next_line(BytePos(28)); + fm2.next_line(fm2.start_pos); + fm2.next_line(fm2.start_pos + BytePos(20)); fm1.record_multibyte_char(BytePos(3), 3); fm1.record_multibyte_char(BytePos(9), 3); fm1.record_multibyte_char(BytePos(12), 3); fm1.record_multibyte_char(BytePos(15), 3); fm1.record_multibyte_char(BytePos(18), 3); - fm2.record_multibyte_char(BytePos(50), 3); - fm2.record_multibyte_char(BytePos(53), 3); - fm2.record_multibyte_char(BytePos(58), 3); + fm2.record_multibyte_char(fm2.start_pos + BytePos(10), 3); + fm2.record_multibyte_char(fm2.start_pos + BytePos(13), 3); + fm2.record_multibyte_char(fm2.start_pos + BytePos(18), 3); cm } diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index fbf015169f858..60f713b528927 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -854,11 +854,12 @@ mod test { println!("done"); let vec = data.lock().unwrap().clone(); let vec: &[u8] = &vec; - println!("{}", from_utf8(vec).unwrap()); - assert_eq!(vec, "dummy.txt: 8 \n\ - dummy.txt: 9 \n\ - dummy.txt:10 \n\ - dummy.txt:11 \n\ - dummy.txt:12 \n".as_bytes()); + let str = from_utf8(vec).unwrap(); + println!("{}", str); + assert_eq!(str, "dummy.txt: 8 line8\n\ + dummy.txt: 9 line9\n\ + dummy.txt:10 line10\n\ + dummy.txt:11 e-lä-vän\n\ + dummy.txt:12 tolv\n"); } } From 0e907fa542d7bfa08ca1f55512ffa4a5ff70ed15 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 2 Jul 2015 17:14:14 +1200 Subject: [PATCH 44/66] Provide a filemap ctor with line info --- src/libsyntax/codemap.rs | 30 ++++++++++++++++-------------- src/libsyntax/diagnostic.rs | 7 +------ src/libsyntax/ext/source_util.rs | 4 ++-- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 2f109b589f143..3e5c10702b641 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -642,6 +642,21 @@ impl CodeMap { filemap } + /// Creates a new filemap and sets its line information. + pub fn new_filemap_and_lines(&self, filename: &str, src: &str) -> Rc { + let fm = self.new_filemap(filename.to_string(), src.to_owned()); + let mut byte_pos: u32 = 0; + for line in src.lines() { + // register the start of this line + fm.next_line(BytePos(byte_pos)); + + // update byte_pos to include this line and the \n at the end + byte_pos += line.len() as u32 + 1; + } + fm + } + + /// Allocates a new FileMap representing a source file from an external /// crate. The source code of such an "imported filemap" is not available, /// but we still know enough to generate accurate debuginfo location @@ -1190,19 +1205,6 @@ mod tests { Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } } - fn new_filemap_and_lines(cm: &CodeMap, filename: &str, input: &str) -> Rc { - let fm = cm.new_filemap(filename.to_string(), input.to_string()); - let mut byte_pos: u32 = 0; - for line in input.lines() { - // register the start of this line - fm.next_line(BytePos(byte_pos)); - - // update byte_pos to include this line and the \n at the end - byte_pos += line.len() as u32 + 1; - } - fm - } - /// Test span_to_snippet and span_to_lines for a span coverting 3 /// lines in the middle of a file. #[test] @@ -1210,7 +1212,7 @@ mod tests { let cm = CodeMap::new(); let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; let selection = " \n ^~\n~~~\n~~~~~ \n \n"; - new_filemap_and_lines(&cm, "blork.rs", inputtext); + cm.new_filemap_and_lines("blork.rs", inputtext); let span = span_from_selection(inputtext, selection); // check that we are extracting the text we thought we were extracting diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 60f713b528927..22aea1ce079e3 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -837,12 +837,7 @@ mod test { tolv dreizehn "; - let file = cm.new_filemap("dummy.txt".to_string(), content.to_string()); - for (i, b) in content.bytes().enumerate() { - if b == b'\n' { - file.next_line(BytePos(i as u32)); - } - } + let file = cm.new_filemap_and_lines("dummy.txt", content); let start = file.lines.borrow()[7]; let end = file.lines.borrow()[11]; let sp = mk_sp(start, end); diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 5418b1f43e4af..22517dc5f1bb5 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -156,7 +156,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // dependency information let filename = format!("{}", file.display()); let interned = token::intern_and_get_ident(&src[..]); - cx.codemap().new_filemap(filename, src); + cx.codemap().new_filemap_and_lines(&filename, &src); base::MacEager::expr(cx.expr_str(sp, interned)) } @@ -187,7 +187,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) // Add this input file to the code map to make it available as // dependency information, but don't enter it's contents let filename = format!("{}", file.display()); - cx.codemap().new_filemap(filename, "".to_string()); + cx.codemap().new_filemap_and_lines(&filename, ""); base::MacEager::expr(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes)))) } From bf34187a2f874690798b06d9350c1f6c4755243a Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 3 Jul 2015 12:54:05 +1200 Subject: [PATCH 45/66] Test --- src/test/compile-fail/cfg-empty-codemap.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/test/compile-fail/cfg-empty-codemap.rs diff --git a/src/test/compile-fail/cfg-empty-codemap.rs b/src/test/compile-fail/cfg-empty-codemap.rs new file mode 100644 index 0000000000000..4c27d57008d04 --- /dev/null +++ b/src/test/compile-fail/cfg-empty-codemap.rs @@ -0,0 +1,18 @@ +// Copyright 2015 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 empty codemaps don't ICE (#23301) + +// compile-flags: --cfg "" + +// error-pattern: expected ident, found + +pub fn main() { +} From f47d20aecdcd7db34d41ad1666fd3eee095cc943 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 6 Jul 2015 14:13:19 +1200 Subject: [PATCH 46/66] Use a span from the correct file for the inner span of a module This basically only affects modules which are empty (or only contain comments). Closes #26755 --- src/librustdoc/clean/mod.rs | 4 ++++ src/libsyntax/codemap.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 1 + src/libsyntax/parse/mod.rs | 11 +++++++++-- src/libsyntax/parse/parser.rs | 24 ++++++++++++++---------- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3cc24550297ce..d4eeaa1de109c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1947,6 +1947,10 @@ impl Span { impl Clean for syntax::codemap::Span { fn clean(&self, cx: &DocContext) -> Span { + if *self == DUMMY_SP { + return Span::empty(); + } + let cm = cx.sess().codemap(); let filename = cm.span_to_filename(*self); let lo = cm.lookup_char_pos(self.lo); diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 3e5c10702b641..e6bc3218897d9 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -894,7 +894,7 @@ impl CodeMap { FileMapAndBytePos {fm: fm, pos: offset} } - /// Converts an absolute BytePos to a CharPos relative to the filemap and above. + /// Converts an absolute BytePos to a CharPos relative to the filemap. pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos { let idx = self.lookup_filemap_idx(bpos); let files = self.files.borrow(); diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b6a3788dacc34..621335ecd979c 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -231,6 +231,7 @@ impl<'a> StringReader<'a> { None => { if self.is_eof() { self.peek_tok = token::Eof; + self.peek_span = codemap::mk_sp(self.filemap.end_pos, self.filemap.end_pos); } else { let start_bytepos = self.last_pos; self.peek_tok = self.next_token_inner(); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index d6c28d4144792..34a63fc92feaa 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -11,7 +11,7 @@ //! The main parser interface use ast; -use codemap::{Span, CodeMap, FileMap}; +use codemap::{self, Span, CodeMap, FileMap}; use diagnostic::{SpanHandler, Handler, Auto, FatalError}; use parse::attr::ParserAttr; use parse::parser::Parser; @@ -203,7 +203,14 @@ pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc, cfg: ast::CrateConfig) -> Parser<'a> { - tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg) + let end_pos = filemap.end_pos; + let mut parser = tts_to_parser(sess, filemap_to_tts(sess, filemap), cfg); + + if parser.token == token::Eof && parser.span == codemap::DUMMY_SP { + parser.span = codemap::mk_sp(end_pos, end_pos); + } + + parser } // must preserve old name for now, because quote! from the *existing* diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 28802d323c692..db1b2489f1d9e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4824,8 +4824,14 @@ impl<'a> Parser<'a> { return Err(self.fatal(&format!("expected item, found `{}`", token_str))); } + let hi = if self.span == codemap::DUMMY_SP { + inner_lo + } else { + self.span.lo + }; + Ok(ast::Mod { - inner: mk_sp(inner_lo, self.span.lo), + inner: mk_sp(inner_lo, hi), items: items }) } @@ -4869,8 +4875,7 @@ impl<'a> Parser<'a> { fn push_mod_path(&mut self, id: Ident, attrs: &[Attribute]) { let default_path = self.id_to_interned_str(id); - let file_path = match ::attr::first_attr_value_str_by_name(attrs, - "path") { + let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") { Some(d) => d, None => default_path, }; @@ -5003,13 +5008,12 @@ impl<'a> Parser<'a> { included_mod_stack.push(path.clone()); drop(included_mod_stack); - let mut p0 = - new_sub_parser_from_file(self.sess, - self.cfg.clone(), - &path, - owns_directory, - Some(name), - id_sp); + let mut p0 = new_sub_parser_from_file(self.sess, + self.cfg.clone(), + &path, + owns_directory, + Some(name), + id_sp); let mod_inner_lo = p0.span.lo; let mod_attrs = p0.parse_inner_attributes(); let m0 = try!(p0.parse_mod_items(&token::Eof, mod_inner_lo)); From 99572284dc6e429fd561f25cc3f6d3f778256953 Mon Sep 17 00:00:00 2001 From: Jonathan Hansford Date: Mon, 20 Jul 2015 17:40:52 +0100 Subject: [PATCH 47/66] Guidance on Windows install re "Add to PATH" Updated "Installing Rust" and "After installation" to provide additional guidance to Windows users on including Rust in the Path system variable. --- src/doc/trpl/installing-rust.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/doc/trpl/installing-rust.md b/src/doc/trpl/installing-rust.md index 39e8ea6cbd319..fcceac346a81c 100644 --- a/src/doc/trpl/installing-rust.md +++ b/src/doc/trpl/installing-rust.md @@ -2,7 +2,7 @@ The first step to using Rust is to install it! There are a number of ways to install Rust, but the easiest is to use the `rustup` script. If you're on Linux -or a Mac, all you need to do is this: +or a Mac, all you need to do is this: > Note: you don't need to type in the `$`s, they just indicate the start of > each command. You’ll see many tutorials and examples around the web that @@ -25,6 +25,12 @@ $ sh rustup.sh [insecurity]: http://curlpipesh.tumblr.com If you're on Windows, please download the appropriate [installer][install-page]. +**NOTE:** By default, the Windows installer will not add Rust to the Path system +variable. If this is the only version of Rust you are installing and you want to +be able to run it from the command line, click on "Advanced" on the install +dialog and on the "Product Features" page ensure "Add to PATH" is installed on +the local hard drive. + [install-page]: http://www.rust-lang.org/install.html @@ -87,6 +93,11 @@ rustc 1.0.0 (a59de37e9 2015-05-13) If you did, Rust has been installed successfully! Congrats! +If you didn't and you're on Windows, check that Rust is in your Path system +variable. If it isn't, run the installer again, select "Change" on the "Change, +repair, or remove installation" page and ensure "Add to PATH" is installed on +the local hard drive. + This installer also installs a copy of the documentation locally, so you can read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. On Windows, it's in a `share/doc` directory, inside wherever you installed Rust @@ -101,5 +112,5 @@ resources include [the user’s forum][users], and [irc]: irc://irc.mozilla.org/#rust [mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust -[users]: http://users.rust-lang.org/ +[users]: http://users.rust-lang.org/ [stackoverflow]: http://stackoverflow.com/questions/tagged/rust From 4128583939a71d48d0e9ec948516e039ead8117d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 21 Jul 2015 16:16:21 +0200 Subject: [PATCH 48/66] This test attempts to exercise cyclic structure much of `std::collections` (as much as is possible; e.g. things like `EnumSet` and `BitVec` do not really support carrying references at all, so trying to represent cyclic structure within them dooes not really make sense.) --- src/test/run-pass/dropck_legal_cycles.rs | 759 +++++++++++++++++++++++ 1 file changed, 759 insertions(+) create mode 100644 src/test/run-pass/dropck_legal_cycles.rs diff --git a/src/test/run-pass/dropck_legal_cycles.rs b/src/test/run-pass/dropck_legal_cycles.rs new file mode 100644 index 0000000000000..b4f9b3f945809 --- /dev/null +++ b/src/test/run-pass/dropck_legal_cycles.rs @@ -0,0 +1,759 @@ +// Copyright 2015 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. + +// This test exercises cases where cyclic structure is legal, +// including when the cycles go through data-structures such +// as `Vec` or `TypedArena`. +// +// The intent is to cover as many such cases as possible, ensuring +// that if the compiler did not complain circa Rust 1.x (1.2 as of +// this writing), then it will continue to not complain in the future. +// +// Note that while some of the tests are only exercising using the +// given collection as a "backing store" for a set of nodes that hold +// the actual cycle (and thus the cycle does not go through the +// collection itself in such cases), in general we *do* want to make +// sure to have at least one example exercising a cycle that goes +// through the collection, for every collection type that supports +// this. + +#![feature(vecmap)] + +use std::cell::Cell; +use std::cmp::Ordering; +use std::collections::BinaryHeap; +use std::collections::HashMap; +use std::collections::LinkedList; +use std::collections::VecDeque; +use std::collections::VecMap; +use std::collections::btree_map::BTreeMap; +use std::collections::btree_set::BTreeSet; +use std::hash::{Hash, Hasher}; + +const PRINT: bool = false; + +pub fn main() { + let c_orig = ContextData { + curr_depth: 0, + max_depth: 3, + visited: 0, + max_visits: 1000, + skipped: 0, + curr_mark: 0, + saw_prev_marked: false, + }; + + // Cycle 1: { v[0] -> v[1], v[1] -> v[0] }; + // does not exercise `v` itself + let v: Vec = vec![Named::new("s0"), + Named::new("s1")]; + v[0].next.set(Some(&v[1])); + v[1].next.set(Some(&v[0])); + + let mut c = c_orig.clone(); + c.curr_mark = 10; + assert!(!c.saw_prev_marked); + v[0].for_each_child(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 2: { v[0] -> v, v[1] -> v } + let v: V = Named::new("v"); + v.contents[0].set(Some(&v)); + v.contents[1].set(Some(&v)); + + let mut c = c_orig.clone(); + c.curr_mark = 20; + assert!(!c.saw_prev_marked); + v.for_each_child(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 3: { hk0 -> hv0, hv0 -> hk0, hk1 -> hv1, hv1 -> hk1 }; + // does not exercise `h` itself + + let mut h: HashMap = HashMap::new(); + h.insert(Named::new("hk0"), Named::new("hv0")); + h.insert(Named::new("hk1"), Named::new("hv1")); + for (key, val) in h.iter() { + val.next.set(Some(key)); + key.next.set(Some(val)); + } + + let mut c = c_orig.clone(); + c.curr_mark = 30; + for (key, _) in h.iter() { + c.curr_mark += 1; + c.saw_prev_marked = false; + key.for_each_child(&mut c); + assert!(c.saw_prev_marked); + } + + if PRINT { println!(""); } + + // Cycle 4: { h -> (hmk0,hmv0,hmk1,hmv1), {hmk0,hmv0,hmk1,hmv1} -> h } + + let mut h: HashMap = HashMap::new(); + h.insert(Named::new("hmk0"), Named::new("hmv0")); + h.insert(Named::new("hmk0"), Named::new("hmv0")); + for (key, val) in h.iter() { + val.contents.set(Some(&h)); + key.contents.set(Some(&h)); + } + + let mut c = c_orig.clone(); + c.max_depth = 2; + c.curr_mark = 40; + for (key, _) in h.iter() { + c.curr_mark += 1; + c.saw_prev_marked = false; + key.for_each_child(&mut c); + assert!(c.saw_prev_marked); + // break; + } + + if PRINT { println!(""); } + + // Cycle 5: { vd[0] -> vd[1], vd[1] -> vd[0] }; + // does not exercise vd itself + let mut vd: VecDeque = VecDeque::new(); + vd.push_back(Named::new("d0")); + vd.push_back(Named::new("d1")); + vd[0].next.set(Some(&vd[1])); + vd[1].next.set(Some(&vd[0])); + + let mut c = c_orig.clone(); + c.curr_mark = 50; + assert!(!c.saw_prev_marked); + vd[0].for_each_child(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 6: { vd -> (vd0, vd1), {vd0, vd1} -> vd } + let mut vd: VecDeque = VecDeque::new(); + vd.push_back(Named::new("vd0")); + vd.push_back(Named::new("vd1")); + vd[0].contents.set(Some(&vd)); + vd[1].contents.set(Some(&vd)); + + let mut c = c_orig.clone(); + c.curr_mark = 60; + assert!(!c.saw_prev_marked); + vd[0].for_each_child(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 7: { vm -> (vm0, vm1), {vm0, vm1} -> vm } + let mut vm: VecMap = VecMap::new(); + vm.insert(0, Named::new("vm0")); + vm.insert(1, Named::new("vm1")); + vm[0].contents.set(Some(&vm)); + vm[1].contents.set(Some(&vm)); + + let mut c = c_orig.clone(); + c.curr_mark = 70; + assert!(!c.saw_prev_marked); + vm[0].for_each_child(&mut c); + assert!(c.saw_prev_marked); + + if PRINT { println!(""); } + + // Cycle 8: { ll -> (ll0, ll1), {ll0, ll1} -> ll } + let mut ll: LinkedList = LinkedList::new(); + ll.push_back(Named::new("ll0")); + ll.push_back(Named::new("ll1")); + for e in &ll { + e.contents.set(Some(&ll)); + } + + let mut c = c_orig.clone(); + c.curr_mark = 80; + for e in &ll { + c.curr_mark += 1; + c.saw_prev_marked = false; + e.for_each_child(&mut c); + assert!(c.saw_prev_marked); + // break; + } + + if PRINT { println!(""); } + + // Cycle 9: { bh -> (bh0, bh1), {bh0, bh1} -> bh } + let mut bh: BinaryHeap = BinaryHeap::new(); + bh.push(Named::new("bh0")); + bh.push(Named::new("bh1")); + for b in bh.iter() { + b.contents.set(Some(&bh)); + } + + let mut c = c_orig.clone(); + c.curr_mark = 90; + for b in &bh { + c.curr_mark += 1; + c.saw_prev_marked = false; + b.for_each_child(&mut c); + assert!(c.saw_prev_marked); + // break; + } + + if PRINT { println!(""); } + + // Cycle 10: { btm -> (btk0, btv1), {bt0, bt1} -> btm } + let mut btm: BTreeMap = BTreeMap::new(); + btm.insert(Named::new("btk0"), Named::new("btv0")); + btm.insert(Named::new("btk1"), Named::new("btv1")); + for (k, v) in btm.iter() { + k.contents.set(Some(&btm)); + v.contents.set(Some(&btm)); + } + + let mut c = c_orig.clone(); + c.curr_mark = 100; + for (k, _) in &btm { + c.curr_mark += 1; + c.saw_prev_marked = false; + k.for_each_child(&mut c); + assert!(c.saw_prev_marked); + // break; + } + + if PRINT { println!(""); } + + // Cycle 10: { bts -> (bts0, bts1), {bts0, bts1} -> btm } + let mut bts: BTreeSet = BTreeSet::new(); + bts.insert(Named::new("bts0")); + bts.insert(Named::new("bts1")); + for v in bts.iter() { + v.contents.set(Some(&bts)); + } + + let mut c = c_orig.clone(); + c.curr_mark = 100; + for b in &bts { + c.curr_mark += 1; + c.saw_prev_marked = false; + b.for_each_child(&mut c); + assert!(c.saw_prev_marked); + // break; + } +} + +trait Named { + fn new(&'static str) -> Self; + fn name(&self) -> &str; +} + +trait Marked { + fn mark(&self) -> M; + fn set_mark(&self, mark: M); +} + +struct S<'a> { + name: &'static str, + mark: Cell, + next: Cell>>, +} + +impl<'a> Named for S<'a> { + fn new<'b>(name: &'static str) -> S<'b> { + S { name: name, mark: Cell::new(0), next: Cell::new(None) } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for S<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +struct V<'a> { + name: &'static str, + mark: Cell, + contents: Vec>>>, +} + +impl<'a> Named for V<'a> { + fn new<'b>(name: &'static str) -> V<'b> { + V { name: name, + mark: Cell::new(0), + contents: vec![Cell::new(None), Cell::new(None)] + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for V<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +#[derive(Eq)] +struct H<'a> { + name: &'static str, + mark: Cell, + next: Cell>>, +} + +impl<'a> Named for H<'a> { + fn new<'b>(name: &'static str) -> H<'b> { + H { name: name, mark: Cell::new(0), next: Cell::new(None) } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for H<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +impl<'a> PartialEq for H<'a> { + fn eq(&self, rhs: &H<'a>) -> bool { + self.name == rhs.name + } +} + +impl<'a> Hash for H<'a> { + fn hash(&self, state: &mut H) { + self.name.hash(state) + } +} + +#[derive(Eq)] +struct HM<'a> { + name: &'static str, + mark: Cell, + contents: Cell, HM<'a>>>>, +} + +impl<'a> Named for HM<'a> { + fn new<'b>(name: &'static str) -> HM<'b> { + HM { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for HM<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +impl<'a> PartialEq for HM<'a> { + fn eq(&self, rhs: &HM<'a>) -> bool { + self.name == rhs.name + } +} + +impl<'a> Hash for HM<'a> { + fn hash(&self, state: &mut H) { + self.name.hash(state) + } +} + + +struct VD<'a> { + name: &'static str, + mark: Cell, + contents: Cell>>>, +} + +impl<'a> Named for VD<'a> { + fn new<'b>(name: &'static str) -> VD<'b> { + VD { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for VD<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +struct VM<'a> { + name: &'static str, + mark: Cell, + contents: Cell>>>, +} + +impl<'a> Named for VM<'a> { + fn new<'b>(name: &'static str) -> VM<'b> { + VM { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for VM<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +struct LL<'a> { + name: &'static str, + mark: Cell, + contents: Cell>>>, +} + +impl<'a> Named for LL<'a> { + fn new<'b>(name: &'static str) -> LL<'b> { + LL { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for LL<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +struct BH<'a> { + name: &'static str, + mark: Cell, + contents: Cell>>>, +} + +impl<'a> Named for BH<'a> { + fn new<'b>(name: &'static str) -> BH<'b> { + BH { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for BH<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +impl<'a> Eq for BH<'a> { } + +impl<'a> PartialEq for BH<'a> { + fn eq(&self, rhs: &BH<'a>) -> bool { + self.name == rhs.name + } +} + +impl<'a> PartialOrd for BH<'a> { + fn partial_cmp(&self, rhs: &BH<'a>) -> Option { + Some(self.cmp(rhs)) + } +} + +impl<'a> Ord for BH<'a> { + fn cmp(&self, rhs: &BH<'a>) -> Ordering { + self.name.cmp(rhs.name) + } +} + +struct BTM<'a> { + name: &'static str, + mark: Cell, + contents: Cell, BTM<'a>>>>, +} + +impl<'a> Named for BTM<'a> { + fn new<'b>(name: &'static str) -> BTM<'b> { + BTM { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for BTM<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +impl<'a> Eq for BTM<'a> { } + +impl<'a> PartialEq for BTM<'a> { + fn eq(&self, rhs: &BTM<'a>) -> bool { + self.name == rhs.name + } +} + +impl<'a> PartialOrd for BTM<'a> { + fn partial_cmp(&self, rhs: &BTM<'a>) -> Option { + Some(self.cmp(rhs)) + } +} + +impl<'a> Ord for BTM<'a> { + fn cmp(&self, rhs: &BTM<'a>) -> Ordering { + self.name.cmp(rhs.name) + } +} + +struct BTS<'a> { + name: &'static str, + mark: Cell, + contents: Cell>>>, +} + +impl<'a> Named for BTS<'a> { + fn new<'b>(name: &'static str) -> BTS<'b> { + BTS { name: name, + mark: Cell::new(0), + contents: Cell::new(None) + } + } + fn name(&self) -> &str { self.name } +} + +impl<'a> Marked for BTS<'a> { + fn mark(&self) -> u32 { self.mark.get() } + fn set_mark(&self, mark: u32) { self.mark.set(mark); } +} + +impl<'a> Eq for BTS<'a> { } + +impl<'a> PartialEq for BTS<'a> { + fn eq(&self, rhs: &BTS<'a>) -> bool { + self.name == rhs.name + } +} + +impl<'a> PartialOrd for BTS<'a> { + fn partial_cmp(&self, rhs: &BTS<'a>) -> Option { + Some(self.cmp(rhs)) + } +} + +impl<'a> Ord for BTS<'a> { + fn cmp(&self, rhs: &BTS<'a>) -> Ordering { + self.name.cmp(rhs.name) + } +} + + +trait Context { + fn should_act(&self) -> bool; + fn increase_visited(&mut self); + fn increase_skipped(&mut self); + fn increase_depth(&mut self); + fn decrease_depth(&mut self); +} + +trait PrePost { + fn pre(&mut self, &T); + fn post(&mut self, &T); + fn hit_limit(&mut self, &T); +} + +trait Children<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost, Self: Sized; + + fn descend_into_self(&self, context: &mut C) + where C: Context + PrePost, Self: Sized + { + context.pre(self); + if context.should_act() { + context.increase_visited(); + context.increase_depth(); + self.for_each_child(context); + context.decrease_depth(); + } else { + context.hit_limit(self); + context.increase_skipped(); + } + context.post(self); + } + + fn descend<'b, C>(&self, c: &Cell>, context: &mut C) + where C: Context + PrePost, Self: Sized + { + if let Some(r) = c.get() { + r.descend_into_self(context); + } + } +} + +impl<'a> Children<'a> for S<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + self.descend(&self.next, context); + } +} + +impl<'a> Children<'a> for V<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + for r in &self.contents { + self.descend(r, context); + } + } +} + +impl<'a> Children<'a> for H<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + self.descend(&self.next, context); + } +} + +impl<'a> Children<'a> for HM<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref hm) = self.contents.get() { + for (k, v) in hm.iter() { + for r in &[k, v] { + r.descend_into_self(context); + } + } + } + } +} + +impl<'a> Children<'a> for VD<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref vd) = self.contents.get() { + for r in vd.iter() { + r.descend_into_self(context); + } + } + } +} + +impl<'a> Children<'a> for VM<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref vd) = self.contents.get() { + for (_idx, r) in vd.iter() { + r.descend_into_self(context); + } + } + } +} + +impl<'a> Children<'a> for LL<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref ll) = self.contents.get() { + for r in ll.iter() { + r.descend_into_self(context); + } + } + } +} + +impl<'a> Children<'a> for BH<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref bh) = self.contents.get() { + for r in bh.iter() { + r.descend_into_self(context); + } + } + } +} + +impl<'a> Children<'a> for BTM<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref bh) = self.contents.get() { + for (k, v) in bh.iter() { + for r in &[k, v] { + r.descend_into_self(context); + } + } + } + } +} + +impl<'a> Children<'a> for BTS<'a> { + fn for_each_child(&self, context: &mut C) + where C: Context + PrePost> + { + if let Some(ref bh) = self.contents.get() { + for r in bh.iter() { + r.descend_into_self(context); + } + } + } +} + +#[derive(Copy, Clone)] +struct ContextData { + curr_depth: usize, + max_depth: usize, + visited: usize, + max_visits: usize, + skipped: usize, + curr_mark: u32, + saw_prev_marked: bool, +} + +impl Context for ContextData { + fn should_act(&self) -> bool { + self.curr_depth < self.max_depth && self.visited < self.max_visits + } + fn increase_visited(&mut self) { self.visited += 1; } + fn increase_skipped(&mut self) { self.skipped += 1; } + fn increase_depth(&mut self) { self.curr_depth += 1; } + fn decrease_depth(&mut self) { self.curr_depth -= 1; } +} + +impl> PrePost for ContextData { + fn pre(&mut self, t: &T) { + for _ in 0..self.curr_depth { + if PRINT { print!(" "); } + } + if PRINT { println!("prev {}", t.name()); } + if t.mark() == self.curr_mark { + for _ in 0..self.curr_depth { + if PRINT { print!(" "); } + } + if PRINT { println!("(probably previously marked)"); } + self.saw_prev_marked = true; + } + t.set_mark(self.curr_mark); + } + fn post(&mut self, t: &T) { + for _ in 0..self.curr_depth { + if PRINT { print!(" "); } + } + if PRINT { println!("post {}", t.name()); } + } + fn hit_limit(&mut self, t: &T) { + for _ in 0..self.curr_depth { + if PRINT { print!(" "); } + } + if PRINT { println!("LIMIT {}", t.name()); } + } +} From d68b152c3e2feb6ee18bdf2c992098376dbb528c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 16 Jul 2015 11:59:53 -0700 Subject: [PATCH 49/66] std: Be resilient to failure in pthread_getattr_np This can fail on linux for various reasons, such as the /proc filesystem not being mounted. There are already many cases where we can't set up stack guards, so just don't worry about this case and communicate that no guard was enabled. I've confirmed that this allows the compiler to run in a chroot without /proc mounted. Closes #22642 --- src/libstd/rt/mod.rs | 4 +- src/libstd/sys/common/thread_info.rs | 8 +-- src/libstd/sys/unix/thread.rs | 88 ++++++++++++++++------------ src/libstd/sys/windows/thread.rs | 7 ++- 4 files changed, 60 insertions(+), 47 deletions(-) diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 1729d20da205c..0ac0d03e19d40 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -96,7 +96,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { // own fault handlers if we hit it. sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top); - sys::thread::guard::init(); + let main_guard = sys::thread::guard::init(); sys::stack_overflow::init(); // Next, set up the current Thread with the guard information we just @@ -104,7 +104,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { // 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(sys::thread::guard::main(), thread); + thread_info::set(main_guard, thread); // By default, some platforms will send a *signal* when a EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index ae55bae37aa88..bb47c946e4993 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -18,7 +18,7 @@ use thread::Thread; use thread::LocalKeyState; struct ThreadInfo { - stack_guard: usize, + stack_guard: Option, thread: Thread, } @@ -33,7 +33,7 @@ impl ThreadInfo { THREAD_INFO.with(move |c| { if c.borrow().is_none() { *c.borrow_mut() = Some(ThreadInfo { - stack_guard: 0, + stack_guard: None, thread: NewThread::new(None), }) } @@ -47,10 +47,10 @@ pub fn current_thread() -> Option { } pub fn stack_guard() -> Option { - ThreadInfo::with(|info| info.stack_guard) + ThreadInfo::with(|info| info.stack_guard).and_then(|o| o) } -pub fn set(stack_guard: usize, thread: Thread) { +pub fn set(stack_guard: Option, thread: Thread) { THREAD_INFO.with(|c| assert!(c.borrow().is_none())); THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ stack_guard: stack_guard, diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 17804c8d81ffb..6be61f069266f 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -166,9 +166,10 @@ impl Drop for Thread { not(target_os = "netbsd"), not(target_os = "openbsd")))] pub mod guard { - pub unsafe fn current() -> usize { 0 } - pub unsafe fn main() -> usize { 0 } - pub unsafe fn init() {} + use prelude::v1::*; + + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } } @@ -179,6 +180,8 @@ pub mod guard { target_os = "openbsd"))] #[allow(unused_imports)] pub mod guard { + use prelude::v1::*; + use libc::{self, pthread_t}; use libc::funcs::posix88::mman::mmap; use libc::consts::os::posix88::{PROT_NONE, @@ -191,31 +194,38 @@ pub mod guard { use super::{pthread_self, pthread_attr_destroy}; use sys::os; - // These are initialized in init() and only read from after - static mut GUARD_PAGE: usize = 0; - #[cfg(any(target_os = "macos", target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] - unsafe fn get_stack_start() -> *mut libc::c_void { - current() as *mut libc::c_void + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + current().map(|s| s as *mut libc::c_void) } #[cfg(any(target_os = "linux", target_os = "android"))] - unsafe fn get_stack_start() -> *mut libc::c_void { + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + use super::pthread_attr_init; + + let mut ret = None; let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0); - let mut stackaddr = ptr::null_mut(); - let mut stacksize = 0; - assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); + assert_eq!(pthread_attr_init(&mut attr), 0); + if pthread_getattr_np(pthread_self(), &mut attr) == 0 { + let mut stackaddr = ptr::null_mut(); + let mut stacksize = 0; + assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, + &mut stacksize), 0); + ret = Some(stackaddr); + } assert_eq!(pthread_attr_destroy(&mut attr), 0); - stackaddr + ret } - pub unsafe fn init() { + pub unsafe fn init() -> Option { let psize = os::page_size(); - let mut stackaddr = get_stack_start(); + let mut stackaddr = match get_stack_start() { + Some(addr) => addr, + None => return None, + }; // Ensure stackaddr is page aligned! A parent process might // have reset RLIMIT_STACK to be non-page aligned. The @@ -245,25 +255,21 @@ pub mod guard { let offset = if cfg!(target_os = "linux") {2} else {1}; - GUARD_PAGE = stackaddr as usize + offset * psize; - } - - pub unsafe fn main() -> usize { - GUARD_PAGE + Some(stackaddr as usize + offset * psize) } #[cfg(target_os = "macos")] - pub unsafe fn current() -> usize { + pub unsafe fn current() -> Option { extern { fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void; fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t; } - (pthread_get_stackaddr_np(pthread_self()) as libc::size_t - - pthread_get_stacksize_np(pthread_self())) as usize + Some((pthread_get_stackaddr_np(pthread_self()) as libc::size_t - + pthread_get_stacksize_np(pthread_self())) as usize) } #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))] - pub unsafe fn current() -> usize { + pub unsafe fn current() -> Option { #[repr(C)] struct stack_t { ss_sp: *mut libc::c_void, @@ -280,30 +286,36 @@ pub mod guard { assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0); let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size(); - if pthread_main_np() == 1 { + Some(if pthread_main_np() == 1 { // main thread current_stack.ss_sp as usize - current_stack.ss_size as usize + extra } else { // new thread current_stack.ss_sp as usize - current_stack.ss_size as usize - } + }) } #[cfg(any(target_os = "linux", target_os = "android"))] - pub unsafe fn current() -> usize { + pub unsafe fn current() -> Option { + use super::pthread_attr_init; + + let mut ret = None; let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0); - let mut guardsize = 0; - assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0); - if guardsize == 0 { - panic!("there is no guard page"); + assert_eq!(pthread_attr_init(&mut attr), 0); + if pthread_getattr_np(pthread_self(), &mut attr) == 0 { + let mut guardsize = 0; + assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0); + if guardsize == 0 { + panic!("there is no guard page"); + } + let mut stackaddr = ptr::null_mut(); + let mut size = 0; + assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); + + ret = Some(stackaddr as usize + guardsize as usize); } - let mut stackaddr = ptr::null_mut(); - let mut size = 0; - assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); assert_eq!(pthread_attr_destroy(&mut attr), 0); - - stackaddr as usize + guardsize as usize + return ret } #[cfg(any(target_os = "linux", target_os = "android"))] diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 50dfee4ab1011..42805c2ac52c4 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -86,7 +86,8 @@ impl Thread { } pub mod guard { - pub unsafe fn main() -> usize { 0 } - pub unsafe fn current() -> usize { 0 } - pub unsafe fn init() {} + use prelude::v1::*; + + pub unsafe fn current() -> Option { None } + pub unsafe fn init() -> Option { None } } From cbdc52e9867ce550c2f8a22613106f65cf54a7ef Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 7 Jul 2015 09:35:56 -0400 Subject: [PATCH 50/66] Expand a bit on thread::park spurious wakeups Fixes #26475 --- src/libstd/thread/mod.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index dbb7d3233bc39..3299c848ba724 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -508,9 +508,25 @@ pub fn sleep(dur: Duration) { imp::Thread::sleep(dur) } -/// Blocks unless or until the current thread's token is made available (may wake spuriously). +/// Blocks unless or until the current thread's token is made available. /// -/// See the module doc for more detail. +/// Every thread is equipped with some basic low-level blocking support, via +/// the `park()` function and the [`unpark()`][unpark] method. These can be +/// used as a more CPU-efficient implementation of a spinlock. +/// +/// [unpark]: struct.Thread.html#method.unpark +/// +/// The API is typically used by acquiring a handle to the current thread, +/// placing that handle in a shared data structure so that other threads can +/// find it, and then parking (in a loop with a check for the token actually +/// being acquired). +/// +/// A call to `park` does not guarantee that the thread will remain parked +/// forever, and callers should be prepared for this possibility. +/// +/// See the [module documentation][thread] for more detail. +/// +/// [thread]: index.html // // The implementation currently uses the trivial strategy of a Mutex+Condvar // with wakeup flag, which does not actually allow spurious wakeups. In the From 0eb7303c7062792049c0ec4ff2c42565db6d60ff Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jul 2015 14:00:03 +0200 Subject: [PATCH 51/66] Add E0403 error explanation --- src/librustc_resolve/diagnostics.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a0d06e5e1244a..2a5a31dcd194e 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -274,6 +274,21 @@ on this topic: http://doc.rust-lang.org/reference.html#use-declarations "## +E0403: r##" +Some type parameters have the same name. Example of erroneous code: + +``` +fn foo(s: T, u: T) {} // error: the name `T` is already used for a type + // parameter in this type parameter list +``` + +Please verify you didn't mispell the type parameters. Example: + +``` +fn foo(s: T, u: Y) {} +``` +"## + } register_diagnostics! { @@ -284,7 +299,6 @@ register_diagnostics! { E0258, E0401, // can't use type parameters from outer function E0402, // cannot use an outer type parameter in this context - E0403, // the name `{}` is already used E0404, // is not a trait E0405, // use of undeclared trait name E0406, // undeclared associated type From cd385cbe34d8a9bad2a6d03c1ef50dd04642a379 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jul 2015 14:14:41 +0200 Subject: [PATCH 52/66] Add E0405 error explanation --- src/librustc_resolve/diagnostics.rs | 36 ++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 2a5a31dcd194e..428e084064ebd 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -282,10 +282,41 @@ fn foo(s: T, u: T) {} // error: the name `T` is already used for a type // parameter in this type parameter list ``` -Please verify you didn't mispell the type parameters. Example: +Please verify that none of the type params are misspelled, and rename any +clashing parameters. Example: ``` -fn foo(s: T, u: Y) {} +fn foo(s: T, u: Y) {} // ok! +``` +"##, + +E0405: r##" +You tried to implement an undefined trait on an object. Example of +erroneous code: + +``` +struct Foo; + +impl SomeTrait for Foo {} // error: use of undeclared trait name `SomeTrait` +``` + +Please verify that the name of the trait wasn't misspelled and ensure that it +was imported. Example: + +``` +// solution 1: +use some_file::SomeTrait; + +// solution 2: +trait SomeTrait { + // some functions +} + +struct Foo; + +impl SomeTrait for Foo { // ok! + // implements functions +} ``` "## @@ -300,7 +331,6 @@ register_diagnostics! { E0401, // can't use type parameters from outer function E0402, // cannot use an outer type parameter in this context E0404, // is not a trait - E0405, // use of undeclared trait name E0406, // undeclared associated type E0407, // method is not a member of trait E0408, // variable from pattern #1 is not bound in pattern # From bc79f20ccac4ead82fae1464ea0916e78e04616f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jul 2015 14:55:42 +0200 Subject: [PATCH 53/66] Add E0404 error explanation --- src/librustc_resolve/diagnostics.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 428e084064ebd..d83829150c553 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -290,6 +290,32 @@ fn foo(s: T, u: Y) {} // ok! ``` "##, +E0404: r##" +You tried to implement a non-trait object on an object. Example of erroneous +code: + +``` +struct Foo; +struct Bar; + +impl Foo for Bar {} // error: `Foo` is not a trait +``` + +Please verify you didn't mispelled the trait's name or used the wrong object. +Example: + +``` +trait Foo { + // some functions +} +struct Bar; + +impl Foo for Bar { // ok! + // functions implementation +} +``` +"##, + E0405: r##" You tried to implement an undefined trait on an object. Example of erroneous code: @@ -330,7 +356,6 @@ register_diagnostics! { E0258, E0401, // can't use type parameters from outer function E0402, // cannot use an outer type parameter in this context - E0404, // is not a trait E0406, // undeclared associated type E0407, // method is not a member of trait E0408, // variable from pattern #1 is not bound in pattern # From 95811546e6dabc1946a155c70a4635b9d76dcb8d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jul 2015 15:54:44 +0200 Subject: [PATCH 54/66] Add E0407 error explanation --- src/librustc_resolve/diagnostics.rs | 41 ++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index d83829150c553..b135d9c0c4ab1 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -317,8 +317,7 @@ impl Foo for Bar { // ok! "##, E0405: r##" -You tried to implement an undefined trait on an object. Example of -erroneous code: +A non-trait was implemented. Example of erroneous code: ``` struct Foo; @@ -344,7 +343,42 @@ impl SomeTrait for Foo { // ok! // implements functions } ``` -"## +"##, + +E0407: r##" +A definition of a method not in the implemented trait was given. Example of +erroneous code: + +``` +trait Foo { + fn a(); +} + +struct Bar; + +impl Foo for Bar { + fn a() {} + fn b() {} // error: method `b` is not a member of trait `Foo` +} +``` + +Please verify you didn't mispelled the method name and you used the good +trait. Example: + +``` +trait Foo { + fn a(); + fn b(); +} + +struct Bar; + +impl Foo for Bar { + fn a() {} + fn b() {} // ok! +} +``` +"##, } @@ -357,7 +391,6 @@ register_diagnostics! { E0401, // can't use type parameters from outer function E0402, // cannot use an outer type parameter in this context E0406, // undeclared associated type - E0407, // method is not a member of trait E0408, // variable from pattern #1 is not bound in pattern # E0409, // variable is bound with different mode in pattern # than in // pattern #1 From c13295bbc3c887581828583ad8c09be8a21227c8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jul 2015 16:09:25 +0200 Subject: [PATCH 55/66] Add E0428 error explanation --- src/librustc_resolve/diagnostics.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index b135d9c0c4ab1..96bc3576a94fa 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -380,6 +380,24 @@ impl Foo for Bar { ``` "##, +E0428: r##" +A type or module has been defined more than once. Example of erroneous +code: + +``` +struct Bar; +struct Bar; // error: duplicate definition of value `Bar` +``` + +Please verify you didn't mispelled the type/module's name or remove the +duplicated one. Example: + +``` +struct Bar; +struct Bar2; // ok! +``` +"##, + } register_diagnostics! { @@ -415,7 +433,6 @@ register_diagnostics! { E0425, // unresolved name E0426, // use of undeclared label E0427, // cannot use `ref` binding mode with ... - E0428, // duplicate definition of ... E0429, // `self` imports are only allowed within a { } list E0430, // `self` import can only appear once in the list E0431, // `self` import can only appear in an import list with a non-empty From d2aee954fee04e48de4441df41076fe4abf84336 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Jul 2015 16:46:34 -0400 Subject: [PATCH 56/66] Expand documentation for IntoInnerError Mostly adding examples. --- src/libstd/io/buffered.rs | 74 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index d6561ebb489d7..e8c7d1af74e32 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -269,6 +269,27 @@ pub struct BufWriter { /// An error returned by `into_inner` which combines an error that /// happened while writing out the buffer, and the buffered writer object /// which may be used to recover from the condition. +/// +/// # Examples +/// +/// ```no_run +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// // do stuff with the stream +/// +/// // we want to get our `TcpStream` back, so let's try: +/// +/// let stream = match stream.into_inner() { +/// Ok(s) => s, +/// Err(e) => { +/// // Here, e is an IntoInnerError +/// panic!("An error occurred"); +/// } +/// }; +/// ``` #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoInnerError(W, Error); @@ -384,9 +405,34 @@ impl Drop for BufWriter { } impl IntoInnerError { - /// Returns the error which caused the call to `into_inner` to fail. + /// Returns the error which caused the call to `into_inner()` to fail. /// /// This error was returned when attempting to write the internal buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's log the inner error. + /// // + /// // We'll just 'log' to stdout for this example. + /// println!("{}", e.error()); + /// + /// panic!("An unexpected error occurred."); + /// } + /// }; + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn error(&self) -> &Error { &self.1 } @@ -394,6 +440,32 @@ impl IntoInnerError { /// /// The returned object can be used for error recovery, such as /// re-inspecting the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is a IntoInnerError, let's re-examine the buffer: + /// let buffer = e.into_inner(); + /// + /// // do stuff to try to recover + /// + /// // afterwards, let's just return the stream + /// buffer.into_inner().unwrap() + /// } + /// }; + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> W { self.0 } } From 2e919b4c5107a584ffcf58e4b39a001275845fec Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Jul 2015 17:21:58 +0200 Subject: [PATCH 57/66] Add E0433 error explanation --- src/librustc_resolve/diagnostics.rs | 54 ++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 96bc3576a94fa..21a950060947b 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -272,7 +272,7 @@ See the 'Use Declarations' section of the reference for more information on this topic: http://doc.rust-lang.org/reference.html#use-declarations -"## +"##, E0403: r##" Some type parameters have the same name. Example of erroneous code: @@ -282,7 +282,7 @@ fn foo(s: T, u: T) {} // error: the name `T` is already used for a type // parameter in this type parameter list ``` -Please verify that none of the type params are misspelled, and rename any +Please verify that none of the type parameterss are misspelled, and rename any clashing parameters. Example: ``` @@ -291,8 +291,8 @@ fn foo(s: T, u: Y) {} // ok! "##, E0404: r##" -You tried to implement a non-trait object on an object. Example of erroneous -code: +You tried to implement something which was not a trait on an object. Example of +erroneous code: ``` struct Foo; @@ -301,8 +301,8 @@ struct Bar; impl Foo for Bar {} // error: `Foo` is not a trait ``` -Please verify you didn't mispelled the trait's name or used the wrong object. -Example: +Please verify that you didn't misspell the trait's name or otherwise use the +wrong identifier. Example: ``` trait Foo { @@ -317,7 +317,7 @@ impl Foo for Bar { // ok! "##, E0405: r##" -A non-trait was implemented. Example of erroneous code: +An unknown trait was implemented. Example of erroneous code: ``` struct Foo; @@ -346,8 +346,8 @@ impl SomeTrait for Foo { // ok! "##, E0407: r##" -A definition of a method not in the implemented trait was given. Example of -erroneous code: +A definition of a method not in the implemented trait was given in a trait +implementation. Example of erroneous code: ``` trait Foo { @@ -362,8 +362,8 @@ impl Foo for Bar { } ``` -Please verify you didn't mispelled the method name and you used the good -trait. Example: +Please verify you didn't misspell the method name and you used the correct +trait. First example: ``` trait Foo { @@ -378,6 +378,24 @@ impl Foo for Bar { fn b() {} // ok! } ``` + +Second example: + +``` +trait Foo { + fn a(); +} + +struct Bar; + +impl Foo for Bar { + fn a() {} +} + +impl Bar { + fn b() {} +} +``` "##, E0428: r##" @@ -389,7 +407,7 @@ struct Bar; struct Bar; // error: duplicate definition of value `Bar` ``` -Please verify you didn't mispelled the type/module's name or remove the +Please verify you didn't misspell the type/module's name or remove/rename the duplicated one. Example: ``` @@ -398,6 +416,17 @@ struct Bar2; // ok! ``` "##, +E0433: r##" +Invalid import. Example of erroneous code: + +``` +use something_which_doesnt_exist; +// error: unresolved import `something_which_doesnt_exist` +``` + +Please verify you didn't misspell the import's name. +"##, + } register_diagnostics! { @@ -438,7 +467,6 @@ register_diagnostics! { E0431, // `self` import can only appear in an import list with a non-empty // prefix E0432, // unresolved import - E0433, // failed to resolve E0434, // can't capture dynamic environment in a fn item E0435, // attempt to use a non-constant value in a constant E0437, // type is not a member of trait From e6d8434cb3a379d98e16d63ebde2168f03a28e24 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Mon, 20 Jul 2015 13:31:04 -0400 Subject: [PATCH 58/66] add test for #14382 closes #14382 --- src/test/run-pass/issue-14382.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/test/run-pass/issue-14382.rs diff --git a/src/test/run-pass/issue-14382.rs b/src/test/run-pass/issue-14382.rs new file mode 100644 index 0000000000000..cdb44f6a60675 --- /dev/null +++ b/src/test/run-pass/issue-14382.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +#[derive(Debug)] +struct Matrix4(S); +trait POrd {} + +fn translate>(s: S) -> Matrix4 { Matrix4(s) } + +impl POrd for f32 {} +impl POrd for f64 {} + +fn main() { + let x = 1.0; + let m : Matrix4 = translate(x); + println!("m: {:?}", m); +} From a5c7b96426cbddc1276ab4439ed2cc4a5689abc2 Mon Sep 17 00:00:00 2001 From: Ticki <@> Date: Tue, 21 Jul 2015 21:36:29 +0200 Subject: [PATCH 59/66] Add info about usage of 'unsafe' keyword in bindings to foreign interfaces. --- src/doc/trpl/unsafe.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index 80b0c87473fa2..897795e91533e 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -100,10 +100,14 @@ that you normally can not do. Just three. Here they are: That’s it. It’s important that `unsafe` does not, for example, ‘turn off the borrow checker’. Adding `unsafe` to some random Rust code doesn’t change its -semantics, it won’t just start accepting anything. +semantics, it won’t just start accepting anything. But it will let you write +things that _do_ break some of the rules. -But it will let you write things that _do_ break some of the rules. Let’s go -over these three abilities in order. +You will also encounter the 'unsafe' keyword when writing bindings to foreign +(non-Rust) interfaces. You're encouraged to write a safe, native Rust interface +around the methods provided by the library. + +Let’s go over the basic three abilities listed, in order. ## Access or update a `static mut` From 48870d4f05177aa8e4d8439b71f39283f1880327 Mon Sep 17 00:00:00 2001 From: Ticki <@> Date: Tue, 21 Jul 2015 21:40:11 +0200 Subject: [PATCH 60/66] rust -> Rust --- src/doc/trpl/ffi.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index cbedf86371414..753a5a32e8a1b 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -340,7 +340,7 @@ libraries: Note that frameworks are only available on OSX targets. The different `kind` values are meant to differentiate how the native library -participates in linkage. From a linkage perspective, the rust compiler creates +participates in linkage. From a linkage perspective, the Rust compiler creates two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary). Native dynamic library and framework dependencies are propagated to the final artifact boundary, while static library dependencies are not propagated at @@ -350,9 +350,9 @@ artifact. A few examples of how this model can be used are: * A native build dependency. Sometimes some C/C++ glue is needed when writing - some rust code, but distribution of the C/C++ code in a library format is just + some Rust code, but distribution of the C/C++ code in a library format is just a burden. In this case, the code will be archived into `libfoo.a` and then the - rust crate would declare a dependency via `#[link(name = "foo", kind = + Rust crate would declare a dependency via `#[link(name = "foo", kind = "static")]`. Regardless of the flavor of output for the crate, the native static library @@ -361,7 +361,7 @@ A few examples of how this model can be used are: * A normal dynamic dependency. Common system libraries (like `readline`) are available on a large number of systems, and often a static copy of these - libraries cannot be found. When this dependency is included in a rust crate, + libraries cannot be found. When this dependency is included in a Rust crate, partial targets (like rlibs) will not link to the library, but when the rlib is included in a final target (like a binary), the native library will be linked in. From cf1e078bf65899f466ebe07d29732979a845a718 Mon Sep 17 00:00:00 2001 From: Ticki Date: Tue, 21 Jul 2015 22:09:29 +0200 Subject: [PATCH 61/66] Klabnik nit-picks ;) --- src/doc/trpl/unsafe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index 897795e91533e..1b223365bd63a 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -103,7 +103,7 @@ borrow checker’. Adding `unsafe` to some random Rust code doesn’t change its semantics, it won’t just start accepting anything. But it will let you write things that _do_ break some of the rules. -You will also encounter the 'unsafe' keyword when writing bindings to foreign +You will also encounter the `unsafe` keyword when writing bindings to foreign (non-Rust) interfaces. You're encouraged to write a safe, native Rust interface around the methods provided by the library. From 18f115c2bbc68419bc83677c3875c91b5428cf8e Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Tue, 21 Jul 2015 16:58:26 -0400 Subject: [PATCH 62/66] update compile-fail test for #21174 to account for #27127 --- src/test/compile-fail/issue-21174.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/compile-fail/issue-21174.rs b/src/test/compile-fail/issue-21174.rs index ec258449cb161..30fd2eb4d2f9a 100644 --- a/src/test/compile-fail/issue-21174.rs +++ b/src/test/compile-fail/issue-21174.rs @@ -15,7 +15,7 @@ trait Trait<'a> { fn foo<'a, T: Trait<'a>>(value: T::A) { let new: T::B = unsafe { std::mem::transmute(value) }; -//~^ ERROR: cannot transmute to or from a type that contains type parameters in its interior [E0139] +//~^ ERROR: cannot transmute to or from a type that contains unsubstituted type parameters [E0139] } fn main() { } From c35b2bd226736925961ca6853b2ef29e8094cd90 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 20 Jul 2015 13:27:38 -0700 Subject: [PATCH 63/66] trans: Move rust_try into the compiler This commit moves the IR files in the distribution, rust_try.ll, rust_try_msvc_64.ll, and rust_try_msvc_32.ll into the compiler from the main distribution. There's a few reasons for this change: * LLVM changes its IR syntax from time to time, so it's very difficult to have these files build across many LLVM versions simultaneously. We'll likely want to retain this ability for quite some time into the future. * The implementation of these files is closely tied to the compiler and runtime itself, so it makes sense to fold it into a location which can do more platform-specific checks for various implementation details (such as MSVC 32 vs 64-bit). * This removes LLVM as a build-time dependency of the standard library. This may end up becoming very useful if we move towards building the standard library with Cargo. In the immediate future, however, this commit should restore compatibility with LLVM 3.5 and 3.6. --- mk/rt.mk | 18 -- src/libcore/intrinsics.rs | 6 + src/librustc/middle/lang_items.rs | 2 + src/librustc/middle/weak_lang_items.rs | 2 +- src/librustc_llvm/lib.rs | 6 +- src/librustc_trans/trans/build.rs | 4 + src/librustc_trans/trans/builder.rs | 6 + src/librustc_trans/trans/callee.rs | 17 +- src/librustc_trans/trans/cleanup.rs | 52 +--- src/librustc_trans/trans/closure.rs | 16 +- src/librustc_trans/trans/common.rs | 51 ++++ src/librustc_trans/trans/context.rs | 7 + src/librustc_trans/trans/declare.rs | 21 +- src/librustc_trans/trans/foreign.rs | 4 +- src/librustc_trans/trans/intrinsic.rs | 344 ++++++++++++++++++++++- src/librustc_trans/trans/meth.rs | 4 +- src/librustc_trans/trans/monomorphize.rs | 7 +- src/librustc_typeck/check/mod.rs | 15 + src/libstd/rt/unwind/gcc.rs | 62 ++-- src/libstd/rt/unwind/mod.rs | 19 +- src/libstd/rt/unwind/seh.rs | 5 +- src/rt/rust_try.ll | 54 ---- src/rt/rust_try_msvc_32.ll | 42 --- src/rt/rust_try_msvc_64.ll | 80 ------ src/rustllvm/RustWrapper.cpp | 3 +- 25 files changed, 519 insertions(+), 328 deletions(-) delete mode 100644 src/rt/rust_try.ll delete mode 100644 src/rt/rust_try_msvc_32.ll delete mode 100644 src/rt/rust_try_msvc_64.ll diff --git a/mk/rt.mk b/mk/rt.mk index c70f9e8a37add..69277e774e43b 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -54,15 +54,6 @@ NATIVE_DEPS_miniz_$(1) = miniz.c NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \ rust_android_dummy.c NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S -ifeq ($$(findstring msvc,$(1)),msvc) -ifeq ($$(findstring i686,$(1)),i686) -NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_32.ll -else -NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_64.ll -endif -else -NATIVE_DEPS_rustrt_native_$(1) += rust_try.ll -endif NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S @@ -76,14 +67,6 @@ NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S RT_OUTPUT_DIR_$(1) := $(1)/rt -$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \ - $$(LLVM_CONFIG_$$(CFG_BUILD)) - @mkdir -p $$(@D) - @$$(call E, compile: $$@) - $$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \ - -filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \ - -relocation-model=pic -o $$@ $$< - $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS) @mkdir -p $$(@D) @$$(call E, compile: $$@) @@ -122,7 +105,6 @@ define THIRD_PARTY_LIB OBJS_$(2)_$(1) := $$(NATIVE_DEPS_$(2)_$(1):%=$$(RT_OUTPUT_DIR_$(1))/%) OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.c=.o) OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.cpp=.o) -OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.ll=.o) OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.S=.o) NATIVE_$(2)_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$(2)) $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1)) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 74901553149ab..ef022179772c4 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -602,4 +602,10 @@ extern "rust-intrinsic" { /// Returns the value of the discriminant for the variant in 'v', /// cast to a `u64`; if `T` has no discriminant, returns 0. pub fn discriminant_value(v: &T) -> u64; + + /// Rust's "try catch" construct which invokes the function pointer `f` with + /// the data pointer `data`, returning the exception payload if an exception + /// is thrown (aka the thread panics). + #[cfg(not(stage0))] + pub fn try(f: fn(*mut u8), data: *mut u8) -> *mut u8; } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index cf528e0c8a914..f7cd94f30af12 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -326,6 +326,8 @@ lets_do_this! { StartFnLangItem, "start", start_fn; EhPersonalityLangItem, "eh_personality", eh_personality; + EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch; + MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter; ExchangeHeapLangItem, "exchange_heap", exchange_heap; OwnedBoxLangItem, "owned_box", owned_box; diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 60a9ffc7d2e13..72fda9a7ae06a 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -119,7 +119,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { ) } weak_lang_items! { - panic_fmt, PanicFmtLangItem, rust_begin_unwind; + panic_fmt, PanicFmtLangItem, rust_begin_unwind; stack_exhausted, StackExhaustedLangItem, rust_stack_exhausted; eh_personality, EhPersonalityLangItem, rust_eh_personality; } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 7734704b021a8..83f8619c5eeab 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -134,7 +134,7 @@ pub enum DLLStorageClassTypes { } bitflags! { - flags Attribute : u32 { + flags Attribute : u64 { const ZExt = 1 << 0, const SExt = 1 << 1, const NoReturn = 1 << 2, @@ -161,6 +161,7 @@ bitflags! { const ReturnsTwice = 1 << 29, const UWTable = 1 << 30, const NonLazyBind = 1 << 31, + const OptimizeNone = 1 << 42, } } @@ -2193,7 +2194,8 @@ pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef { pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) { unsafe { - LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, attr.bits() as uint64_t) + LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, + attr.bits() as uint64_t) } } diff --git a/src/librustc_trans/trans/build.rs b/src/librustc_trans/trans/build.rs index 3e4452a23b9f7..5a3fcc8d27f3c 100644 --- a/src/librustc_trans/trans/build.rs +++ b/src/librustc_trans/trans/build.rs @@ -1042,6 +1042,10 @@ pub fn LandingPad(cx: Block, ty: Type, pers_fn: ValueRef, B(cx).landing_pad(ty, pers_fn, num_clauses, cx.fcx.llfn) } +pub fn AddClause(cx: Block, landing_pad: ValueRef, clause: ValueRef) { + B(cx).add_clause(landing_pad, clause) +} + pub fn SetCleanup(cx: Block, landing_pad: ValueRef) { B(cx).set_cleanup(landing_pad) } diff --git a/src/librustc_trans/trans/builder.rs b/src/librustc_trans/trans/builder.rs index e39fc18dc7bf1..107ae378ac446 100644 --- a/src/librustc_trans/trans/builder.rs +++ b/src/librustc_trans/trans/builder.rs @@ -937,6 +937,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) { + unsafe { + llvm::LLVMAddClause(landing_pad, clause); + } + } + pub fn set_cleanup(&self, landing_pad: ValueRef) { self.count_insn("setcleanup"); unsafe { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index debc8dd59c04c..7900000d3a9df 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -620,16 +620,17 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }, ArgVals(args), dest) } -/// This behemoth of a function translates function calls. Unfortunately, in order to generate more -/// efficient LLVM output at -O0, it has quite a complex signature (refactoring this into two -/// functions seems like a good idea). +/// This behemoth of a function translates function calls. Unfortunately, in +/// order to generate more efficient LLVM output at -O0, it has quite a complex +/// signature (refactoring this into two functions seems like a good idea). /// -/// In particular, for lang items, it is invoked with a dest of None, and in that case the return -/// value contains the result of the fn. The lang item must not return a structural type or else -/// all heck breaks loose. +/// In particular, for lang items, it is invoked with a dest of None, and in +/// that case the return value contains the result of the fn. The lang item must +/// not return a structural type or else all heck breaks loose. /// -/// For non-lang items, `dest` is always Some, and hence the result is written into memory -/// somewhere. Nonetheless we return the actual return value of the function. +/// For non-lang items, `dest` is always Some, and hence the result is written +/// into memory somewhere. Nonetheless we return the actual return value of the +/// function. pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, debug_loc: DebugLoc, get_callee: F, diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 1891320313a85..37722d5a549fe 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -122,11 +122,9 @@ pub use self::Heap::*; use llvm::{BasicBlockRef, ValueRef}; use trans::base; use trans::build; -use trans::callee; use trans::common; -use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan}; +use trans::common::{Block, FunctionContext, NodeIdAndSpan}; use trans::debuginfo::{DebugLoc, ToDebugLoc}; -use trans::declare; use trans::glue; use middle::region; use trans::type_::Type; @@ -833,53 +831,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx &[Type::i8p(self.ccx), Type::i32(self.ccx)], false); - // The exception handling personality function. - // - // If our compilation unit has the `eh_personality` lang item somewhere - // within it, then we just need to translate that. Otherwise, we're - // building an rlib which will depend on some upstream implementation of - // this function, so we just codegen a generic reference to it. We don't - // specify any of the types for the function, we just make it a symbol - // that LLVM can later use. - // - // Note that MSVC is a little special here in that we don't use the - // `eh_personality` lang item at all. Currently LLVM has support for - // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the - // *name of the personality function* to decide what kind of unwind side - // tables/landing pads to emit. It looks like Dwarf is used by default, - // injecting a dependency on the `_Unwind_Resume` symbol for resuming - // an "exception", but for MSVC we want to force SEH. This means that we - // can't actually have the personality function be our standard - // `rust_eh_personality` function, but rather we wired it up to the - // CRT's custom personality function, which forces LLVM to consider - // landing pads as "landing pads for SEH". - let target = &self.ccx.sess().target.target; - let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() { - Some(def_id) if !target.options.is_like_msvc => { - callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0), - pad_bcx.fcx.param_substs).val - } - _ => { - let mut personality = self.ccx.eh_personality().borrow_mut(); - match *personality { - Some(llpersonality) => llpersonality, - None => { - let name = if !target.options.is_like_msvc { - "rust_eh_personality" - } else if target.arch == "x86" { - "_except_handler3" - } else { - "__C_specific_handler" - }; - let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); - let f = declare::declare_cfn(self.ccx, name, fty, - self.ccx.tcx().types.i32); - *personality = Some(f); - f - } - } - } - }; + let llpersonality = pad_bcx.fcx.eh_personality(); // The only landing pad clause will be 'cleanup' let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1); diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index d813e9dbf40fa..f00029ec2ff93 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -163,11 +163,10 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc mangle_internal_name_by_path_and_seq(path, "closure") }); - // Currently there’s only a single user of get_or_create_declaration_if_closure and it - // unconditionally defines the function, therefore we use define_* here. - let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", symbol)); - }); + // Currently there’s only a single user of + // get_or_create_declaration_if_closure and it unconditionally defines the + // function, therefore we use define_* here. + let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type); // set an inline hint for all closures attributes::inline(llfn, attributes::InlineAttr::Hint); @@ -388,11 +387,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Create the by-value helper. let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); - let lloncefn = declare::define_internal_rust_fn(ccx, &function_name[..], llonce_fn_ty) - .unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); - }); - + let lloncefn = declare::define_internal_rust_fn(ccx, &function_name, + llonce_fn_ty); let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig); let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index d7d3be699cb90..1e87053c2ae63 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -25,6 +25,7 @@ use middle::lang_items::LangItem; use middle::subst::{self, Substs}; use trans::base; use trans::build; +use trans::callee; use trans::cleanup; use trans::consts; use trans::datum; @@ -479,6 +480,56 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { type_needs_drop_given_env(self.ccx.tcx(), ty, &self.param_env) } + + pub fn eh_personality(&self) -> ValueRef { + // The exception handling personality function. + // + // If our compilation unit has the `eh_personality` lang item somewhere + // within it, then we just need to translate that. Otherwise, we're + // building an rlib which will depend on some upstream implementation of + // this function, so we just codegen a generic reference to it. We don't + // specify any of the types for the function, we just make it a symbol + // that LLVM can later use. + // + // Note that MSVC is a little special here in that we don't use the + // `eh_personality` lang item at all. Currently LLVM has support for + // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the + // *name of the personality function* to decide what kind of unwind side + // tables/landing pads to emit. It looks like Dwarf is used by default, + // injecting a dependency on the `_Unwind_Resume` symbol for resuming + // an "exception", but for MSVC we want to force SEH. This means that we + // can't actually have the personality function be our standard + // `rust_eh_personality` function, but rather we wired it up to the + // CRT's custom personality function, which forces LLVM to consider + // landing pads as "landing pads for SEH". + let target = &self.ccx.sess().target.target; + match self.ccx.tcx().lang_items.eh_personality() { + Some(def_id) if !target.options.is_like_msvc => { + callee::trans_fn_ref(self.ccx, def_id, ExprId(0), + self.param_substs).val + } + _ => { + let mut personality = self.ccx.eh_personality().borrow_mut(); + match *personality { + Some(llpersonality) => llpersonality, + None => { + let name = if !target.options.is_like_msvc { + "rust_eh_personality" + } else if target.arch == "x86" { + "_except_handler3" + } else { + "__C_specific_handler" + }; + let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); + let f = declare::declare_cfn(self.ccx, name, fty, + self.ccx.tcx().types.i32); + *personality = Some(f); + f + } + } + } + } + } } // Basic block context. We create a block context for each basic block diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 5a4bd7ff3a184..760a4ae827aac 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -142,6 +142,7 @@ pub struct LocalCrateContext<'tcx> { dbg_cx: Option>, eh_personality: RefCell>, + rust_try_fn: RefCell>, intrinsics: RefCell>, @@ -461,6 +462,7 @@ impl<'tcx> LocalCrateContext<'tcx> { closure_vals: RefCell::new(FnvHashMap()), dbg_cx: dbg_cx, eh_personality: RefCell::new(None), + rust_try_fn: RefCell::new(None), intrinsics: RefCell::new(FnvHashMap()), n_llvm_insns: Cell::new(0), trait_cache: RefCell::new(FnvHashMap()), @@ -726,6 +728,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.eh_personality } + pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell> { + &self.local.rust_try_fn + } + fn intrinsics<'a>(&'a self) -> &'a RefCell> { &self.local.intrinsics } @@ -923,6 +929,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option void); ifn!("llvm.expect.i1", fn(i1, i1) -> i1); + ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32); // Some intrinsics were introduced in later versions of LLVM, but they have // fallbacks in libc or libm and such. diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index b29da9d560fea..c802de91e38b3 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -176,8 +176,8 @@ pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option Option { +pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, + fn_type: Type, output: ty::FnOutput) -> Option { if get_defined_value(ccx, name).is_some() { None } else { @@ -224,20 +224,21 @@ pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, /// Declare a Rust function with an intention to define it. /// /// Use this function when you intend to define a function. This function will -/// return None if the name already has a definition associated with it. In that -/// case an error should be reported to the user, because it usually happens due -/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes). -pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, - fn_type: ty::Ty<'tcx>) -> Option { +/// return panic if the name already has a definition associated with it. This +/// can happen with #[no_mangle] or #[export_name], for example. +pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + name: &str, + fn_type: ty::Ty<'tcx>) -> ValueRef { if get_defined_value(ccx, name).is_some() { - None + ccx.sess().fatal(&format!("symbol `{}` already defined", name)) } else { - Some(declare_internal_rust_fn(ccx, name, fn_type)) + declare_internal_rust_fn(ccx, name, fn_type) } } -/// Get defined or externally defined (AvailableExternally linkage) value by name. +/// Get defined or externally defined (AvailableExternally linkage) value by +/// name. fn get_defined_value(ccx: &CrateContext, name: &str) -> Option { debug!("get_defined_value(name={:?})", name); let namebuf = CString::new(name).unwrap_or_else(|_|{ diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 9e8c0189a9762..e102e3cd062be 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -627,9 +627,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.tcx().map.path_to_string(id), id, t); - let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", ps)); - }); + let llfn = declare::define_internal_rust_fn(ccx, &ps, t); attributes::from_fn_attrs(ccx, attrs, llfn); base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]); llfn diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index b449c3ad060b8..e78218fd10dd8 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -10,6 +10,7 @@ #![allow(non_upper_case_globals)] +use arena::TypedArena; use llvm; use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind}; use middle::subst; @@ -23,6 +24,7 @@ use trans::cleanup::CleanupMethods; use trans::common::*; use trans::datum::*; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::expr; use trans::glue; use trans::type_of::*; @@ -31,7 +33,8 @@ use trans::machine; use trans::machine::llsize_of; use trans::type_::Type; use middle::ty::{self, Ty, HasTypeFlags}; -use syntax::abi::RustIntrinsic; +use middle::subst::Substs; +use syntax::abi::{self, RustIntrinsic}; use syntax::ast; use syntax::parse::token; @@ -302,6 +305,42 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } + let call_debug_location = DebugLoc::At(call_info.id, call_info.span); + + // For `try` we need some custom control flow + if &name[..] == "try" { + if let callee::ArgExprs(ref exprs) = args { + let (func, data) = if exprs.len() != 2 { + ccx.sess().bug("expected two exprs as arguments for \ + `try` intrinsic"); + } else { + (&exprs[0], &exprs[1]) + }; + + // translate arguments + let func = unpack_datum!(bcx, expr::trans(bcx, func)); + let func = unpack_datum!(bcx, func.to_rvalue_datum(bcx, "func")); + let data = unpack_datum!(bcx, expr::trans(bcx, data)); + let data = unpack_datum!(bcx, data.to_rvalue_datum(bcx, "data")); + + let dest = match dest { + expr::SaveIn(d) => d, + expr::Ignore => alloc_ty(bcx, tcx.mk_mut_ptr(tcx.types.i8), + "try_result"), + }; + + // do the invoke + bcx = try_intrinsic(bcx, func.val, data.val, dest, + call_debug_location); + + fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope); + return Result::new(bcx, dest); + } else { + ccx.sess().bug("expected two exprs as arguments for \ + `try` intrinsic"); + } + } + // Push the arguments. let mut llargs = Vec::new(); bcx = callee::trans_args(bcx, @@ -314,8 +353,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); - let call_debug_location = DebugLoc::At(call_info.id, call_info.span); - // These are the only intrinsic functions that diverge. if &name[..] == "abort" { let llfn = ccx.get_intrinsic(&("llvm.trap")); @@ -989,3 +1026,304 @@ fn with_overflow_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ret } } + +fn try_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + func: ValueRef, + data: ValueRef, + dest: ValueRef, + dloc: DebugLoc) -> Block<'blk, 'tcx> { + if bcx.sess().no_landing_pads() { + Call(bcx, func, &[data], None, dloc); + Store(bcx, C_null(Type::i8p(bcx.ccx())), dest); + bcx + } else if bcx.sess().target.target.options.is_like_msvc { + trans_msvc_try(bcx, func, data, dest, dloc) + } else { + trans_gnu_try(bcx, func, data, dest, dloc) + } +} + +// MSVC's definition of the `rust_try` function. The exact implementation here +// is a little different than the GNU (standard) version below, not only because +// of the personality function but also because of the other fiddly bits about +// SEH. LLVM also currently requires us to structure this a very particular way +// as explained below. +// +// Like with the GNU version we generate a shim wrapper +fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + func: ValueRef, + data: ValueRef, + dest: ValueRef, + dloc: DebugLoc) -> Block<'blk, 'tcx> { + let llfn = get_rust_try_fn(bcx.fcx, &mut |try_fn_ty, output| { + let ccx = bcx.ccx(); + let dloc = DebugLoc::None; + let rust_try = declare::define_internal_rust_fn(ccx, "__rust_try", + try_fn_ty); + let (fcx, block_arena); + block_arena = TypedArena::new(); + fcx = new_fn_ctxt(ccx, rust_try, ast::DUMMY_NODE_ID, false, + output, ccx.tcx().mk_substs(Substs::trans_empty()), + None, &block_arena); + let bcx = init_function(&fcx, true, output); + let then = fcx.new_temp_block("then"); + let catch = fcx.new_temp_block("catch"); + let catch_return = fcx.new_temp_block("catch-return"); + let catch_resume = fcx.new_temp_block("catch-resume"); + let personality = fcx.eh_personality(); + + let eh_typeid_for = ccx.get_intrinsic(&"llvm.eh.typeid.for"); + let rust_try_filter = match bcx.tcx().lang_items.msvc_try_filter() { + Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0), + bcx.fcx.param_substs).val, + None => bcx.sess().bug("msvc_try_filter not defined"), + }; + + // Type indicator for the exception being thrown, not entirely sure + // what's going on here but it's what all the examples in LLVM use. + let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], + false); + + llvm::SetFunctionAttribute(rust_try, llvm::Attribute::NoInline); + llvm::SetFunctionAttribute(rust_try, llvm::Attribute::OptimizeNone); + let func = llvm::get_param(rust_try, 0); + let data = llvm::get_param(rust_try, 1); + + // Invoke the function, specifying our two temporary landing pads as the + // ext point. After the invoke we've terminated our basic block. + Invoke(bcx, func, &[data], then.llbb, catch.llbb, None, dloc); + + // All the magic happens in this landing pad, and this is basically the + // only landing pad in rust tagged with "catch" to indicate that we're + // catching an exception. The other catch handlers in the GNU version + // below just catch *all* exceptions, but that's because most exceptions + // are already filtered out by the gnu personality function. + // + // For MSVC we're just using a standard personality function that we + // can't customize (e.g. _except_handler3 or __C_specific_handler), so + // we need to do the exception filtering ourselves. This is currently + // performed by the `__rust_try_filter` function. This function, + // specified in the landingpad instruction, will be invoked by Windows + // SEH routines and will return whether the exception in question can be + // caught (aka the Rust runtime is the one that threw the exception). + // + // To get this to compile (currently LLVM segfaults if it's not in this + // particular structure), when the landingpad is executing we test to + // make sure that the ID of the exception being thrown is indeed the one + // that we were expecting. If it's not, we resume the exception, and + // otherwise we return the pointer that we got Full disclosure: It's not + // clear to me what this `llvm.eh.typeid` stuff is doing *other* then + // just allowing LLVM to compile this file without segfaulting. I would + // expect the entire landing pad to just be: + // + // %vals = landingpad ... + // %ehptr = extractvalue { i8*, i32 } %vals, 0 + // ret i8* %ehptr + // + // but apparently LLVM chokes on this, so we do the more complicated + // thing to placate it. + let vals = LandingPad(catch, lpad_ty, personality, 1); + let rust_try_filter = BitCast(catch, rust_try_filter, Type::i8p(ccx)); + AddClause(catch, vals, rust_try_filter); + let ehptr = ExtractValue(catch, vals, 0); + let sel = ExtractValue(catch, vals, 1); + let filter_sel = Call(catch, eh_typeid_for, &[rust_try_filter], None, + dloc); + let is_filter = ICmp(catch, llvm::IntEQ, sel, filter_sel, dloc); + CondBr(catch, is_filter, catch_return.llbb, catch_resume.llbb, dloc); + + // Our "catch-return" basic block is where we've determined that we + // actually need to catch this exception, in which case we just return + // the exception pointer. + Ret(catch_return, ehptr, dloc); + + // The "catch-resume" block is where we're running this landing pad but + // we actually need to not catch the exception, so just resume the + // exception to return. + Resume(catch_resume, vals); + + // On the successful branch we just return null. + Ret(then, C_null(Type::i8p(ccx)), dloc); + + return rust_try + }); + + // Note that no invoke is used here because by definition this function + // can't panic (that's what it's catching). + let ret = Call(bcx, llfn, &[func, data], None, dloc); + Store(bcx, ret, dest); + return bcx; +} + +// Definition of the standard "try" function for Rust using the GNU-like model +// of exceptions (e.g. the normal semantics of LLVM's landingpad and invoke +// instructions). +// +// This translation is a little surprising for two reasons: +// +// 1. We always call a shim function instead of inlining the call to `invoke` +// manually here. This is done because in LLVM we're only allowed to have one +// personality per function definition. The call to the `try` intrinsic is +// being inlined into the function calling it, and that function may already +// have other personality functions in play. By calling a shim we're +// guaranteed that our shim will have the right personality function. +// +// 2. Instead of making one shim (explained above), we make two shims! The +// reason for this has to do with the technical details about the +// implementation of unwinding in the runtime, but the tl;dr; is that the +// outer shim's personality function says "catch rust exceptions" and the +// inner shim's landing pad will not `resume` the exception being thrown. +// This means that the outer shim's landing pad is never run and the inner +// shim's return value is the return value of the whole call. +// +// The double-shim aspect is currently done for implementation ease on the +// runtime side of things, and more info can be found in +// src/libstd/rt/unwind/gcc.rs. +fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + func: ValueRef, + data: ValueRef, + dest: ValueRef, + dloc: DebugLoc) -> Block<'blk, 'tcx> { + let llfn = get_rust_try_fn(bcx.fcx, &mut |try_fn_ty, output| { + let ccx = bcx.ccx(); + let dloc = DebugLoc::None; + + // Type indicator for the exception being thrown, not entirely sure + // what's going on here but it's what all the examples in LLVM use. + let lpad_ty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], + false); + + // Define the "inner try" shim + let rust_try_inner = declare::define_internal_rust_fn(ccx, + "__rust_try_inner", + try_fn_ty); + trans_rust_try(ccx, rust_try_inner, lpad_ty, bcx.fcx.eh_personality(), + output, dloc, &mut |bcx, then, catch| { + let func = llvm::get_param(rust_try_inner, 0); + let data = llvm::get_param(rust_try_inner, 1); + Invoke(bcx, func, &[data], then.llbb, catch.llbb, None, dloc); + C_null(Type::i8p(ccx)) + }); + + // Define the "outer try" shim. + let rust_try = declare::define_internal_rust_fn(ccx, "__rust_try", + try_fn_ty); + let catch_pers = match bcx.tcx().lang_items.eh_personality_catch() { + Some(did) => callee::trans_fn_ref(ccx, did, ExprId(0), + bcx.fcx.param_substs).val, + None => bcx.tcx().sess.bug("eh_personality_catch not defined"), + }; + trans_rust_try(ccx, rust_try, lpad_ty, catch_pers, output, dloc, + &mut |bcx, then, catch| { + let func = llvm::get_param(rust_try, 0); + let data = llvm::get_param(rust_try, 1); + Invoke(bcx, rust_try_inner, &[func, data], then.llbb, catch.llbb, + None, dloc) + }); + return rust_try + }); + + // Note that no invoke is used here because by definition this function + // can't panic (that's what it's catching). + let ret = Call(bcx, llfn, &[func, data], None, dloc); + Store(bcx, ret, dest); + return bcx; + + // Translates both the inner and outer shims described above. The only + // difference between these two is the function invoked and the personality + // involved, so a common routine is shared. + // + // bcx: + // invoke %func(%args...) normal %normal unwind %unwind + // + // normal: + // ret null + // + // unwind: + // (ptr, _) = landingpad + // br (ptr != null), done, reraise + // + // done: + // ret ptr + // + // reraise: + // resume + // + // Note that the branch checking for `null` here isn't actually necessary, + // it's just an unfortunate hack to make sure that LLVM doesn't optimize too + // much. If this were not present, then LLVM would correctly deduce that our + // inner shim should be tagged with `nounwind` (as it catches all + // exceptions) and then the outer shim's `invoke` will be translated to just + // a simple call, destroying that entry for the personality function. + // + // To ensure that both shims always have an `invoke` this check against null + // confuses LLVM enough to the point that it won't infer `nounwind` and + // we'll proceed as normal. + fn trans_rust_try<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + llfn: ValueRef, + lpad_ty: Type, + personality: ValueRef, + output: ty::FnOutput<'tcx>, + dloc: DebugLoc, + invoke: &mut FnMut(Block, Block, Block) -> ValueRef) { + let (fcx, block_arena); + block_arena = TypedArena::new(); + fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false, + output, ccx.tcx().mk_substs(Substs::trans_empty()), + None, &block_arena); + let bcx = init_function(&fcx, true, output); + let then = bcx.fcx.new_temp_block("then"); + let catch = bcx.fcx.new_temp_block("catch"); + let reraise = bcx.fcx.new_temp_block("reraise"); + let catch_return = bcx.fcx.new_temp_block("catch-return"); + + let invoke_ret = invoke(bcx, then, catch); + Ret(then, invoke_ret, dloc); + let vals = LandingPad(catch, lpad_ty, personality, 1); + AddClause(catch, vals, C_null(Type::i8p(ccx))); + let ptr = ExtractValue(catch, vals, 0); + let valid = ICmp(catch, llvm::IntNE, ptr, C_null(Type::i8p(ccx)), dloc); + CondBr(catch, valid, catch_return.llbb, reraise.llbb, dloc); + Ret(catch_return, ptr, dloc); + Resume(reraise, vals); + } +} + +// Helper to generate the `Ty` associated with `rust_Try` +fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, + f: &mut FnMut(Ty<'tcx>, + ty::FnOutput<'tcx>) -> ValueRef) + -> ValueRef { + let ccx = fcx.ccx; + if let Some(llfn) = *ccx.rust_try_fn().borrow() { + return llfn + } + + // Define the types up front for the signatures of the rust_try and + // rust_try_inner functions. + let tcx = ccx.tcx(); + let i8p = tcx.mk_mut_ptr(tcx.types.i8); + let fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: vec![i8p], + output: ty::FnOutput::FnConverging(tcx.mk_nil()), + variadic: false, + }), + }); + let fn_ty = tcx.mk_fn(None, fn_ty); + let output = ty::FnOutput::FnConverging(i8p); + let try_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: vec![fn_ty, i8p], + output: output, + variadic: false, + }), + }); + let rust_try = f(tcx.mk_fn(None, try_fn_ty), output); + *ccx.rust_try_fn().borrow_mut() = Some(rust_try); + return rust_try +} diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 1fa996f76b9a2..8901361b27976 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -550,9 +550,7 @@ fn trans_object_shim<'a, 'tcx>( let shim_fn_ty = tcx.mk_fn(None, fty); let method_bare_fn_ty = tcx.mk_fn(None, method_ty); let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); - let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); - }); + let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty); let sig = ccx.tcx().erase_late_bound_regions(&fty.sig); diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 98fe57ec31446..217181da1421a 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -137,10 +137,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let lldecl = if abi != abi::Rust { foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..]) } else { - // FIXME(nagisa): perhaps needs a more fine grained selection? See setup_lldecl below. - declare::define_internal_rust_fn(ccx, &s[..], mono_ty).unwrap_or_else(||{ - ccx.sess().bug(&format!("symbol `{}` already defined", s)); - }) + // FIXME(nagisa): perhaps needs a more fine grained selection? See + // setup_lldecl below. + declare::define_internal_rust_fn(ccx, &s, mono_ty) }; ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9042cedccc857..17140db904f62 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5096,6 +5096,21 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { ty::BrAnon(0))), param(ccx, 0))], tcx.types.u64), + "try" => { + let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); + let fn_ty = ty::BareFnTy { + unsafety: ast::Unsafety::Normal, + abi: abi::Rust, + sig: ty::Binder(FnSig { + inputs: vec![mut_u8], + output: ty::FnOutput::FnConverging(tcx.mk_nil()), + variadic: false, + }), + }; + let fn_ty = tcx.mk_bare_fn(fn_ty); + (0, vec![tcx.mk_fn(None, fn_ty), mut_u8], mut_u8) + } + ref other => { span_err!(tcx.sess, it.span, E0093, "unrecognized intrinsic function: `{}`", *other); diff --git a/src/libstd/rt/unwind/gcc.rs b/src/libstd/rt/unwind/gcc.rs index 84c6d6864a9e5..87941e79b2f7d 100644 --- a/src/libstd/rt/unwind/gcc.rs +++ b/src/libstd/rt/unwind/gcc.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(private_no_mangle_fns)] + use prelude::v1::*; use any::Any; -use libc::c_void; use rt::libunwind as uw; struct Exception { @@ -41,7 +42,7 @@ pub unsafe fn panic(data: Box) -> ! { } } -pub unsafe fn cleanup(ptr: *mut c_void) -> Box { +pub unsafe fn cleanup(ptr: *mut u8) -> Box { let my_ep = ptr as *mut Exception; rtdebug!("caught {}", (*my_ep).uwe.exception_class); let cause = (*my_ep).cause.take(); @@ -89,7 +90,7 @@ pub mod eabi { use rt::libunwind as uw; use libc::c_int; - extern "C" { + extern { fn __gcc_personality_v0(version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -98,9 +99,8 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - #[allow(private_no_mangle_fns)] + #[lang = "eh_personality"] + #[no_mangle] extern fn rust_eh_personality( version: c_int, actions: uw::_Unwind_Action, @@ -115,8 +115,9 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( _version: c_int, actions: uw::_Unwind_Action, _exception_class: uw::_Unwind_Exception_Class, @@ -142,7 +143,7 @@ pub mod eabi { use rt::libunwind as uw; use libc::c_int; - extern "C" { + extern { fn __gcc_personality_sj0(version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -151,9 +152,9 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality( + #[lang = "eh_personality"] + #[no_mangle] + pub extern fn rust_eh_personality( version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -167,8 +168,9 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( _version: c_int, actions: uw::_Unwind_Action, _exception_class: uw::_Unwind_Exception_Class, @@ -196,17 +198,16 @@ pub mod eabi { use rt::libunwind as uw; use libc::c_int; - extern "C" { + extern { fn __gcc_personality_v0(state: uw::_Unwind_State, ue_header: *mut uw::_Unwind_Exception, context: *mut uw::_Unwind_Context) -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - #[allow(private_no_mangle_fns)] - extern "C" fn rust_eh_personality( + #[lang = "eh_personality"] + #[no_mangle] + extern fn rust_eh_personality( state: uw::_Unwind_State, ue_header: *mut uw::_Unwind_Exception, context: *mut uw::_Unwind_Context @@ -217,8 +218,9 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( state: uw::_Unwind_State, _ue_header: *mut uw::_Unwind_Exception, _context: *mut uw::_Unwind_Context @@ -266,7 +268,7 @@ pub mod eabi { } type _Unwind_Personality_Fn = - extern "C" fn( + extern fn( version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -274,7 +276,7 @@ pub mod eabi { context: *mut uw::_Unwind_Context ) -> uw::_Unwind_Reason_Code; - extern "C" { + extern { fn __gcc_personality_seh0( exceptionRecord: *mut EXCEPTION_RECORD, establisherFrame: *mut c_void, @@ -291,10 +293,9 @@ pub mod eabi { ) -> EXCEPTION_DISPOSITION; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - #[allow(private_no_mangle_fns)] - extern "C" fn rust_eh_personality( + #[lang = "eh_personality"] + #[no_mangle] + extern fn rust_eh_personality( exceptionRecord: *mut EXCEPTION_RECORD, establisherFrame: *mut c_void, contextRecord: *mut CONTEXT, @@ -307,15 +308,16 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( exceptionRecord: *mut EXCEPTION_RECORD, establisherFrame: *mut c_void, contextRecord: *mut CONTEXT, dispatcherContext: *mut DISPATCHER_CONTEXT ) -> EXCEPTION_DISPOSITION { - extern "C" fn inner( + extern fn inner( _version: c_int, actions: uw::_Unwind_Action, _exception_class: uw::_Unwind_Exception_Class, diff --git a/src/libstd/rt/unwind/mod.rs b/src/libstd/rt/unwind/mod.rs index c403976745aa4..db2310ba361b3 100644 --- a/src/libstd/rt/unwind/mod.rs +++ b/src/libstd/rt/unwind/mod.rs @@ -69,7 +69,6 @@ use cmp; use panicking; use fmt; use intrinsics; -use libc::c_void; use mem; use sync::atomic::{self, Ordering}; use sys_common::mutex::Mutex; @@ -127,7 +126,7 @@ extern {} /// run. pub unsafe fn try(f: F) -> Result<(), Box> { let mut f = Some(f); - return inner_try(try_fn::, &mut f as *mut _ as *mut c_void); + return inner_try(try_fn::, &mut f as *mut _ as *mut u8); // If an inner function were not used here, then this generic function `try` // uses the native symbol `rust_try`, for which the code is statically @@ -140,11 +139,12 @@ pub unsafe fn try(f: F) -> Result<(), Box> { // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll` // files and instead just have this non-generic shim the compiler can take // care of exposing correctly. - unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void) + #[cfg(not(stage0))] + unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) -> Result<(), Box> { let prev = PANICKING.with(|s| s.get()); PANICKING.with(|s| s.set(false)); - let ep = rust_try(f, data); + let ep = intrinsics::try(f, data); PANICKING.with(|s| s.set(prev)); if ep.is_null() { Ok(()) @@ -152,8 +152,13 @@ pub unsafe fn try(f: F) -> Result<(), Box> { Err(imp::cleanup(ep)) } } + #[cfg(stage0)] + unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) + -> Result<(), Box> { + Ok(f(data)) + } - extern fn try_fn(opt_closure: *mut c_void) { + fn try_fn(opt_closure: *mut u8) { let opt_closure = opt_closure as *mut Option; unsafe { (*opt_closure).take().unwrap()(); } } @@ -163,8 +168,8 @@ pub unsafe fn try(f: F) -> Result<(), Box> { // When f(...) returns normally, the return value is null. // When f(...) throws, the return value is a pointer to the caught // exception object. - fn rust_try(f: extern fn(*mut c_void), - data: *mut c_void) -> *mut c_void; + fn rust_try(f: extern fn(*mut u8), + data: *mut u8) -> *mut u8; } } diff --git a/src/libstd/rt/unwind/seh.rs b/src/libstd/rt/unwind/seh.rs index 632ab4f8e2537..ed44f9a8bda94 100644 --- a/src/libstd/rt/unwind/seh.rs +++ b/src/libstd/rt/unwind/seh.rs @@ -102,7 +102,7 @@ pub unsafe fn panic(data: Box) -> ! { rtabort!("could not unwind stack"); } -pub unsafe fn cleanup(ptr: *mut c_void) -> Box { +pub unsafe fn cleanup(ptr: *mut u8) -> Box { // The `ptr` here actually corresponds to the code of the exception, and our // real data is stored in our thread local. rtassert!(ptr as DWORD == RUST_PANIC); @@ -135,8 +135,9 @@ fn rust_eh_personality() { // to ensure that it's code is RUST_PANIC, which was set by the call to // `RaiseException` above in the `panic` function. #[no_mangle] +#[lang = "msvc_try_filter"] pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS, - _rbp: *mut c_void) -> i32 { + _rbp: *mut u8) -> i32 { unsafe { ((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32 } diff --git a/src/rt/rust_try.ll b/src/rt/rust_try.ll deleted file mode 100644 index 8643131d0fb74..0000000000000 --- a/src/rt/rust_try.ll +++ /dev/null @@ -1,54 +0,0 @@ -; Copyright 2013 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. - -; Rust's try-catch -; When f(...) returns normally, the return value is null. -; When f(...) throws, the return value is a pointer to the caught exception object. - -; See also: libstd/rt/unwind/mod.rs - -define i8* @rust_try(void (i8*)* %f, i8* %env) - personality i8* bitcast (i32 (...)* @rust_eh_personality_catch to i8*) -{ - - %1 = invoke i8* @rust_try_inner(void (i8*)* %f, i8* %env) - to label %normal - unwind label %catch - -normal: - ret i8* %1 - -catch: - landingpad { i8*, i32 } catch i8* null - ; rust_try_inner's landing pad does not resume unwinds, so execution will - ; never reach here - ret i8* null -} - -define internal i8* @rust_try_inner(void (i8*)* %f, i8* %env) - personality i8* bitcast (i32 (...)* @rust_eh_personality to i8*) -{ - - invoke void %f(i8* %env) - to label %normal - unwind label %catch - -normal: - ret i8* null - -catch: - %1 = landingpad { i8*, i32 } catch i8* null - ; extract and return pointer to the exception object - %2 = extractvalue { i8*, i32 } %1, 0 - ret i8* %2 -} - -declare i32 @rust_eh_personality(...) -declare i32 @rust_eh_personality_catch(...) diff --git a/src/rt/rust_try_msvc_32.ll b/src/rt/rust_try_msvc_32.ll deleted file mode 100644 index bdee53b136e10..0000000000000 --- a/src/rt/rust_try_msvc_32.ll +++ /dev/null @@ -1,42 +0,0 @@ -; Copyright 2015 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. - -; For more comments about what's going on here see rust_try_msvc_64.ll. The only -; difference between that and this file is the personality function used as it's -; different for 32-bit MSVC than it is for 64-bit. - -define i8* @rust_try(void (i8*)* %f, i8* %env) - personality i8* bitcast (i32 (...)* @_except_handler3 to i8*) -{ - invoke void %f(i8* %env) - to label %normal - unwind label %catch - -normal: - ret i8* null -catch: - %vals = landingpad { i8*, i32 } - catch i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*) - %ehptr = extractvalue { i8*, i32 } %vals, 0 - %sel = extractvalue { i8*, i32 } %vals, 1 - %filter_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*)) - %is_filter = icmp eq i32 %sel, %filter_sel - br i1 %is_filter, label %catch-return, label %catch-resume - -catch-return: - ret i8* %ehptr - -catch-resume: - resume { i8*, i32 } %vals -} - -declare i32 @_except_handler3(...) -declare i32 @__rust_try_filter(i8*, i8*) -declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind diff --git a/src/rt/rust_try_msvc_64.ll b/src/rt/rust_try_msvc_64.ll deleted file mode 100644 index c38e6081bf2d3..0000000000000 --- a/src/rt/rust_try_msvc_64.ll +++ /dev/null @@ -1,80 +0,0 @@ -; Copyright 2015 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. - -; 64-bit MSVC's definition of the `rust_try` function. This function can't be -; defined in Rust as it's a "try-catch" block that's not expressible in Rust's -; syntax, so we're using LLVM to produce an object file with the associated -; handler. -; -; To use the correct system implementation details, this file is separate from -; the standard rust_try.ll as we need specifically use the __C_specific_handler -; personality function or otherwise LLVM doesn't emit SEH handling tables. -; There's also a few fiddly bits about SEH right now in LLVM that require us to -; structure this a fairly particular way! -; -; See also: src/libstd/rt/unwind/seh.rs - -define i8* @rust_try(void (i8*)* %f, i8* %env) - personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) -{ - invoke void %f(i8* %env) - to label %normal - unwind label %catch - -normal: - ret i8* null - -; Here's where most of the magic happens, this is the only landing pad in rust -; tagged with "catch" to indicate that we're catching an exception. The other -; catch handlers in rust_try.ll just catch *all* exceptions, but that's because -; most exceptions are already filtered out by their personality function. -; -; For MSVC we're just using a standard personality function that we can't -; customize, so we need to do the exception filtering ourselves, and this is -; currently performed by the `__rust_try_filter` function. This function, -; specified in the landingpad instruction, will be invoked by Windows SEH -; routines and will return whether the exception in question can be caught (aka -; the Rust runtime is the one that threw the exception). -; -; To get this to compile (currently LLVM segfaults if it's not in this -; particular structure), when the landingpad is executing we test to make sure -; that the ID of the exception being thrown is indeed the one that we were -; expecting. If it's not, we resume the exception, and otherwise we return the -; pointer that we got -; -; Full disclosure: It's not clear to me what this `llvm.eh.typeid` stuff is -; doing *other* then just allowing LLVM to compile this file without -; segfaulting. I would expect the entire landing pad to just be: -; -; %vals = landingpad ... -; %ehptr = extractvalue { i8*, i32 } %vals, 0 -; ret i8* %ehptr -; -; but apparently LLVM chokes on this, so we do the more complicated thing to -; placate it. -catch: - %vals = landingpad { i8*, i32 } - catch i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*) - %ehptr = extractvalue { i8*, i32 } %vals, 0 - %sel = extractvalue { i8*, i32 } %vals, 1 - %filter_sel = call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @__rust_try_filter to i8*)) - %is_filter = icmp eq i32 %sel, %filter_sel - br i1 %is_filter, label %catch-return, label %catch-resume - -catch-return: - ret i8* %ehptr - -catch-resume: - resume { i8*, i32 } %vals -} - -declare i32 @__C_specific_handler(...) -declare i32 @__rust_try_filter(i8*, i8*) -declare i32 @llvm.eh.typeid.for(i8*) readnone nounwind diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 163e95b890f4b..5007af0e777b8 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -120,7 +120,8 @@ extern "C" void LLVMAddDereferenceableCallSiteAttr(LLVMValueRef Instr, unsigned idx, B))); } -extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) { +extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, + uint64_t Val) { Function *A = unwrap(Fn); AttrBuilder B; B.addRawValue(Val); From e22c6f7caa61f3bb47df694944a3515e725dea9e Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Jul 2015 13:02:02 -0400 Subject: [PATCH 64/66] Improve documentation for std::io::BufWriter Mostly through adding examples. --- src/libstd/io/buffered.rs | 102 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index d6561ebb489d7..780b4f86c0e82 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -252,14 +252,49 @@ impl Seek for BufReader { } } -/// Wraps a Writer and buffers output to it. +/// Wraps a writer and buffers its output. /// -/// It can be excessively inefficient to work directly with a `Write`. For -/// example, every call to `write` on `TcpStream` results in a system call. A -/// `BufWriter` keeps an in memory buffer of data and writes it to the -/// underlying `Write` in large, infrequent batches. +/// It can be excessively inefficient to work directly with something that +/// implements `Write`. For example, every call to `write` on `TcpStream` +/// results in a system call. A `BufWriter` keeps an in-memory buffer of data +/// and writes it to an underlying writer in large, infrequent batches. /// /// The buffer will be written out when the writer is dropped. +/// +/// # Examples +/// +/// Let's write the numbers one through ten to a `TcpStream`: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::net::TcpStream; +/// +/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); +/// +/// for i in 1..10 { +/// stream.write(&[i]).unwrap(); +/// } +/// ``` +/// +/// Because we're not buffering, we write each one in turn, incurring the +/// overhead of a system call per byte written. We can fix this with a +/// `BufWriter`: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// for i in 1..10 { +/// stream.write(&[i]).unwrap(); +/// } +/// ``` +/// +/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped +/// together by the buffer, and will all be written out in one system call when +/// the `stream` is dropped. #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter { inner: Option, @@ -275,12 +310,33 @@ pub struct IntoInnerError(W, Error); impl BufWriter { /// Creates a new `BufWriter` with a default buffer capacity. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } /// Creates a new `BufWriter` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with a buffer of a hundred bytes. + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); + /// let mut buffer = BufWriter::with_capacity(100, stream); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> BufWriter { BufWriter { @@ -313,6 +369,18 @@ impl BufWriter { } /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_ref(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } @@ -321,12 +389,36 @@ impl BufWriter { /// # Warning /// /// It is inadvisable to directly write to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_mut(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } /// Unwraps this `BufWriter`, returning the underlying writer. /// /// The buffer is written out before returning the writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // unwrap the TcpStream and flush the buffer + /// let stream = buffer.into_inner().unwrap(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(mut self) -> Result>> { match self.flush_buf() { From f2c73459acba7019f285289df421ccd72724c387 Mon Sep 17 00:00:00 2001 From: Jonathan Hansford Date: Wed, 22 Jul 2015 08:26:40 +0100 Subject: [PATCH 65/66] Path changed to %PATH% The two references to the "Path system variable" have changed to the "%PATH% system variable". --- src/doc/trpl/installing-rust.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/trpl/installing-rust.md b/src/doc/trpl/installing-rust.md index fcceac346a81c..83750ec3b01ad 100644 --- a/src/doc/trpl/installing-rust.md +++ b/src/doc/trpl/installing-rust.md @@ -25,11 +25,11 @@ $ sh rustup.sh [insecurity]: http://curlpipesh.tumblr.com If you're on Windows, please download the appropriate [installer][install-page]. -**NOTE:** By default, the Windows installer will not add Rust to the Path system -variable. If this is the only version of Rust you are installing and you want to -be able to run it from the command line, click on "Advanced" on the install -dialog and on the "Product Features" page ensure "Add to PATH" is installed on -the local hard drive. +**NOTE:** By default, the Windows installer will not add Rust to the %PATH% +system variable. If this is the only version of Rust you are installing and you +want to be able to run it from the command line, click on "Advanced" on the +install dialog and on the "Product Features" page ensure "Add to PATH" is +installed on the local hard drive. [install-page]: http://www.rust-lang.org/install.html @@ -93,7 +93,7 @@ rustc 1.0.0 (a59de37e9 2015-05-13) If you did, Rust has been installed successfully! Congrats! -If you didn't and you're on Windows, check that Rust is in your Path system +If you didn't and you're on Windows, check that Rust is in your %PATH% system variable. If it isn't, run the installer again, select "Change" on the "Change, repair, or remove installation" page and ensure "Add to PATH" is installed on the local hard drive. From e31ad959cc30ca69be67a96b5e45202ccc865ffe Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 20 Jul 2015 15:43:57 -0400 Subject: [PATCH 66/66] Improve documentation for std::io::LineWriter Beef up the struct docs, add examples for the methods. --- src/libstd/io/buffered.rs | 123 +++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index d6561ebb489d7..d02bd5187f5f3 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -417,17 +417,74 @@ impl fmt::Display for IntoInnerError { } } -/// Wraps a Writer and buffers output to it, flushing whenever a newline +/// Wraps a writer and buffers output to it, flushing whenever a newline /// (`0x0a`, `'\n'`) is detected. /// -/// The buffer will be written out when the writer is dropped. +/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output. +/// But it only does this batched write when it goes out of scope, or when the +/// internal buffer is full. Sometimes, you'd prefer to write each line as it's +/// completed, rather than the entire buffer at once. Enter `LineWriter`. It +/// does exactly that. +/// +/// [bufwriter]: struct.BufWriter.html +/// +/// If there's still a partial line in the buffer when the `LineWriter` is +/// dropped, it will flush those contents. +/// +/// # Examples +/// +/// We can use `LineWriter` to write one line at a time, significantly +/// reducing the number of actual writes to the file. +/// +/// ``` +/// use std::fs::File; +/// use std::io::prelude::*; +/// use std::io::LineWriter; +/// +/// # fn foo() -> std::io::Result<()> { +/// let road_not_taken = b"I shall be telling this with a sigh +/// Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference."; +/// +/// let file = try!(File::create("poem.txt")); +/// let mut file = LineWriter::new(file); +/// +/// for &byte in road_not_taken.iter() { +/// file.write(&[byte]).unwrap(); +/// } +/// +/// // let's check we did the right thing. +/// let mut file = try!(File::open("poem.txt")); +/// let mut contents = String::new(); +/// +/// try!(file.read_to_string(&mut contents)); +/// +/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct LineWriter { inner: BufWriter, } impl LineWriter { - /// Creates a new `LineWriter` + /// Creates a new `LineWriter`. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::new(file); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> LineWriter { // Lines typically aren't that long, don't use a giant buffer @@ -436,12 +493,40 @@ impl LineWriter { /// Creates a new `LineWriter` with a specified capacity for the internal /// buffer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::with_capacity(100, file); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> LineWriter { LineWriter { inner: BufWriter::with_capacity(cap, inner) } } /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::new(file); + /// + /// let reference = file.get_ref(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { self.inner.get_ref() } @@ -449,12 +534,44 @@ impl LineWriter { /// /// Caution must be taken when calling methods on the mutable reference /// returned as extra writes could corrupt the output stream. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let mut file = LineWriter::new(file); + /// + /// // we can use reference just like file + /// let reference = file.get_mut(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() } /// Unwraps this `LineWriter`, returning the underlying writer. /// /// The internal buffer is written out before returning the writer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// + /// let writer: LineWriter = LineWriter::new(file); + /// + /// let file: File = try!(writer.into_inner()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result>> { self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {