From 0d80b2a0415e39a4b9421919d2b131f23e0d42de Mon Sep 17 00:00:00 2001 From: Nick Hamann Date: Fri, 22 May 2015 19:32:02 -0500 Subject: [PATCH 01/38] docs: Improve descriptions for some methods in core::cell. --- src/libcore/cell.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 45a8012210417..67ae19079c8c2 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -212,7 +212,7 @@ impl Cell { } } - /// Gets a reference to the underlying `UnsafeCell`. + /// Returns a reference to the underlying `UnsafeCell`. /// /// # Unsafety /// @@ -439,7 +439,7 @@ impl RefCell { } } - /// Gets a reference to the underlying `UnsafeCell`. + /// Returns a reference to the underlying `UnsafeCell`. /// /// This can be used to circumvent `RefCell`'s safety checks. /// @@ -671,8 +671,8 @@ impl UnsafeCell { /// /// # Unsafety /// - /// This function is unsafe because there is no guarantee that this or other threads are - /// currently inspecting the inner value. + /// This function is unsafe because this thread or another thread may currently be + /// inspecting the inner value. /// /// # Examples /// From bbf8ba7c2351caba1b585346e5709f8eb476f169 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 24 May 2015 10:38:59 +0200 Subject: [PATCH 02/38] Implement Eq for Cell and RefCell. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `core::cell::Cell` and `core::cell::RefCell` currently implement `PartialEq` when `T` does, and just defer to comparing `T` values. There is no reason the same shouldn’t apply to `Eq`. This enables `#[derive(Eq, PartialEq)]` on e.g. structs that have a `RefCell` field. --- src/libcore/cell.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 45a8012210417..8f531de261118 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -143,7 +143,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use clone::Clone; -use cmp::PartialEq; +use cmp::{PartialEq, Eq}; use default::Default; use marker::{Copy, Send, Sync, Sized}; use ops::{Deref, DerefMut, Drop}; @@ -263,6 +263,9 @@ impl PartialEq for Cell { } } +#[stable(feature = "cell_eq", since = "1.2.0")] +impl Eq for Cell {} + /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](index.html) for more. @@ -273,7 +276,7 @@ pub struct RefCell { } /// An enumeration of values returned from the `state` method on a `RefCell`. -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[unstable(feature = "std_misc")] pub enum BorrowState { /// The cell is currently being read, there is at least one active `borrow`. @@ -479,6 +482,9 @@ impl PartialEq for RefCell { } } +#[stable(feature = "cell_eq", since = "1.2.0")] +impl Eq for RefCell {} + struct BorrowRef<'b> { _borrow: &'b Cell, } From 16334e508e6c7feaea7cdf68649f6cbc29fadb3a Mon Sep 17 00:00:00 2001 From: Max Jacobson Date: Mon, 25 May 2015 22:35:53 -0400 Subject: [PATCH 03/38] Add a missing space to the Glossary page of TRPL r? @steveklabnik --- src/doc/trpl/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/glossary.md b/src/doc/trpl/glossary.md index 9845fcbdcd173..c97da0e95b823 100644 --- a/src/doc/trpl/glossary.md +++ b/src/doc/trpl/glossary.md @@ -19,7 +19,7 @@ In the example above `x` and `y` have arity 2. `z` has arity 3. When a compiler is compiling your program, it does a number of different things. One of the things that it does is turn the text of your program into an -‘abstract syntax tree’, or‘AST’. This tree is a representation of the +‘abstract syntax tree’, or ‘AST’. This tree is a representation of the structure of your program. For example, `2 + 3` can be turned into a tree: ```text From d323c14f631576c639219d18f2574b4f2380172a Mon Sep 17 00:00:00 2001 From: Kubilay Kocak Date: Tue, 26 May 2015 18:23:33 +1000 Subject: [PATCH 04/38] Remove redundant compiler check. Allow CC override Currently, there are two conditional blocks that exist to check for "clang or gcc" On line 866: ``` if [ -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ] then err "either clang or gcc is required" fi ``` and on line 1019: ``` if [ -z "$CC" -a -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ] then err "either clang or gcc is required" fi ``` Given the order of the clauses, this results in the "either clang or gcc is required" error from the earlier block, (even) when CC is set. The expected behaviour is to honour user-flags, in this case CC. Aside from removing all hand-holdy compiler checks in favour of actual compiler *feature* checks, this change removes the redundant former block in favour of the latter block, which appears designed to allow the expected behaviour. --- configure | 5 ----- 1 file changed, 5 deletions(-) diff --git a/configure b/configure index efa836ca97646..20a5fa390f00b 100755 --- a/configure +++ b/configure @@ -863,11 +863,6 @@ then CFG_DISABLE_JEMALLOC=1 fi -if [ -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ] -then - err "either clang or gcc is required" -fi - # OS X 10.9, gcc is actually clang. This can cause some confusion in the build # system, so if we find that gcc is clang, we should just use clang directly. if [ $CFG_OSTYPE = apple-darwin -a -z "$CFG_ENABLE_CLANG" ] From ae10e478eb61e75ebf3a7bf672b34b582555fd8e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 26 May 2015 17:12:39 +0300 Subject: [PATCH 05/38] Implement defaults for associated types --- src/librustc/metadata/decoder.rs | 35 ++++++---- src/librustc/metadata/encoder.rs | 23 ++++--- src/librustc/middle/traits/project.rs | 50 +++++++------- src/librustc/middle/ty.rs | 5 +- src/librustc/util/ppaux.rs | 2 +- src/librustc_typeck/check/mod.rs | 17 ++--- src/librustc_typeck/collect.rs | 48 ++++++------- src/librustdoc/clean/inline.rs | 8 ++- src/librustdoc/clean/mod.rs | 69 +++++++++---------- src/test/run-pass/default-associated-types.rs | 30 ++++++++ 10 files changed, 167 insertions(+), 120 deletions(-) create mode 100644 src/test/run-pass/default-associated-types.rs diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 42dcc9661ca2d..5eefb99b058f1 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -252,6 +252,13 @@ fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> |_, did| translate_def_id(cdata, did)) } +fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option> { + reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| { + parse_ty_data(tp.data, cdata.cnum, tp.start, tcx, + |_, did| translate_def_id(cdata, did)) + }) +} + fn doc_method_fty<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> ty::BareFnTy<'tcx> { let tp = reader::get_doc(doc, tag_item_method_fty); @@ -875,24 +882,24 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, id: ast::NodeId, tcx: &ty::ctxt<'tcx>) -> ty::ImplOrTraitItem<'tcx> { - let method_doc = lookup_item(id, cdata.data()); + let item_doc = lookup_item(id, cdata.data()); - let def_id = item_def_id(method_doc, cdata); + let def_id = item_def_id(item_doc, cdata); - let container_id = item_require_parent_item(cdata, method_doc); + let container_id = item_require_parent_item(cdata, item_doc); let container_doc = lookup_item(container_id.node, cdata.data()); let container = match item_family(container_doc) { Trait => TraitContainer(container_id), _ => ImplContainer(container_id), }; - let name = item_name(&*intr, method_doc); - let vis = item_visibility(method_doc); + let name = item_name(&*intr, item_doc); + let vis = item_visibility(item_doc); - match item_sort(method_doc) { + match item_sort(item_doc) { Some('C') => { - let ty = doc_type(method_doc, tcx, cdata); - let default = get_provided_source(method_doc, cdata); + let ty = doc_type(item_doc, tcx, cdata); + let default = get_provided_source(item_doc, cdata); ty::ConstTraitItem(Rc::new(ty::AssociatedConst { name: name, ty: ty, @@ -903,11 +910,11 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, })) } Some('r') | Some('p') => { - let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics); - let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics); - let fty = doc_method_fty(method_doc, tcx, cdata); - let explicit_self = get_explicit_self(method_doc); - let provided_source = get_provided_source(method_doc, cdata); + let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics); + let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics); + let fty = doc_method_fty(item_doc, tcx, cdata); + let explicit_self = get_explicit_self(item_doc); + let provided_source = get_provided_source(item_doc, cdata); ty::MethodTraitItem(Rc::new(ty::Method::new(name, generics, @@ -920,8 +927,10 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, provided_source))) } Some('t') => { + let ty = maybe_doc_type(item_doc, tcx, cdata); ty::TypeTraitItem(Rc::new(ty::AssociatedType { name: name, + ty: ty, vis: vis, def_id: def_id, container: container, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 0908ffd249fe4..8eefb4d5011d2 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -894,12 +894,12 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } -fn encode_info_for_associated_type(ecx: &EncodeContext, - rbml_w: &mut Encoder, - associated_type: &ty::AssociatedType, - impl_path: PathElems, - parent_id: NodeId, - impl_item_opt: Option<&ast::ImplItem>) { +fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, + rbml_w: &mut Encoder, + associated_type: &ty::AssociatedType<'tcx>, + impl_path: PathElems, + parent_id: NodeId, + impl_item_opt: Option<&ast::ImplItem>) { debug!("encode_info_for_associated_type({:?},{:?})", associated_type.def_id, token::get_name(associated_type.name)); @@ -913,8 +913,6 @@ fn encode_info_for_associated_type(ecx: &EncodeContext, encode_parent_item(rbml_w, local_def(parent_id)); encode_item_sort(rbml_w, 't'); - encode_bounds_and_type_for_item(rbml_w, ecx, associated_type.def_id.local_id()); - let stab = stability::lookup(ecx.tcx, associated_type.def_id); encode_stability(rbml_w, stab); @@ -923,7 +921,14 @@ fn encode_info_for_associated_type(ecx: &EncodeContext, if let Some(ii) = impl_item_opt { encode_attributes(rbml_w, &ii.attrs); - encode_type(ecx, rbml_w, ty::node_id_to_type(ecx.tcx, ii.id)); + } else { + encode_predicates(rbml_w, ecx, + &ty::lookup_predicates(ecx.tcx, associated_type.def_id), + tag_item_generics); + } + + if let Some(ty) = associated_type.ty { + encode_type(ecx, rbml_w, ty); } rbml_w.end_tag(); diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index f6bde80e29875..700aaad8b72d3 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -857,37 +857,39 @@ fn confirm_impl_candidate<'cx,'tcx>( -> (Ty<'tcx>, Vec>) { // there don't seem to be nicer accessors to these: - let impl_items_map = selcx.tcx().impl_items.borrow(); let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow(); - let impl_items = impl_items_map.get(&impl_vtable.impl_def_id).unwrap(); - let mut impl_ty = None; - for impl_item in impl_items { - let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() { - ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(), - ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; } - }; - - if assoc_type.name != obligation.predicate.item_name { - continue; + for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] { + if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] { + if assoc_ty.name == obligation.predicate.item_name { + return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs), + impl_vtable.nested.into_vec()); + } } - - let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id); - impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs)); - break; } - match impl_ty { - Some(ty) => (ty, impl_vtable.nested.into_vec()), - None => { - // This means that the impl is missing a - // definition for the associated type. This error - // ought to be reported by the type checker method - // `check_impl_items_against_trait`, so here we - // just return ty_err. - (selcx.tcx().types.err, vec!()) + let trait_ref = obligation.predicate.trait_ref; + for trait_item in ty::trait_items(selcx.tcx(), trait_ref.def_id).iter() { + if let &ty::TypeTraitItem(ref assoc_ty) = trait_item { + if assoc_ty.name == obligation.predicate.item_name { + if let Some(ty) = assoc_ty.ty { + return (ty.subst(selcx.tcx(), trait_ref.substs), + impl_vtable.nested.into_vec()); + } else { + // This means that the impl is missing a + // definition for the associated type. This error + // ought to be reported by the type checker method + // `check_impl_items_against_trait`, so here we + // just return ty_err. + return (selcx.tcx().types.err, vec!()); + } + } } } + + selcx.tcx().sess.span_bug(obligation.cause.span, + &format!("No associated type for {}", + trait_ref.repr(selcx.tcx()))); } impl<'tcx> Repr<'tcx> for ProjectionTyError<'tcx> { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 2ccbb0c5c103e..a67a968ea2cf9 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -136,7 +136,7 @@ impl ImplOrTraitItemContainer { pub enum ImplOrTraitItem<'tcx> { ConstTraitItem(Rc>), MethodTraitItem(Rc>), - TypeTraitItem(Rc), + TypeTraitItem(Rc>), } impl<'tcx> ImplOrTraitItem<'tcx> { @@ -267,8 +267,9 @@ pub struct AssociatedConst<'tcx> { } #[derive(Clone, Copy, Debug)] -pub struct AssociatedType { +pub struct AssociatedType<'tcx> { pub name: ast::Name, + pub ty: Option>, pub vis: ast::Visibility, pub def_id: ast::DefId, pub container: ImplOrTraitItemContainer, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index cf2911ab182ef..6f71def11886d 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1077,7 +1077,7 @@ impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> { } } -impl<'tcx> Repr<'tcx> for ty::AssociatedType { +impl<'tcx> Repr<'tcx> for ty::AssociatedType<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("AssociatedType(name: {}, vis: {}, def_id: {})", self.name.repr(tcx), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index eb6e90414e3fd..05aad1d64f729 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1070,7 +1070,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Check for missing items from trait let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id); let associated_consts = ty::associated_consts(tcx, impl_trait_ref.def_id); - let mut missing_methods = Vec::new(); + let mut missing_items = Vec::new(); for trait_item in &*trait_items { match *trait_item { ty::ConstTraitItem(ref associated_const) => { @@ -1086,8 +1086,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, associated_consts.iter().any(|ac| ac.default.is_some() && ac.name == associated_const.name); if !is_implemented && !is_provided { - missing_methods.push(format!("`{}`", - token::get_name(associated_const.name))); + missing_items.push(format!("`{}`", + token::get_name(associated_const.name))); } } ty::MethodTraitItem(ref trait_method) => { @@ -1103,7 +1103,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let is_provided = provided_methods.iter().any(|m| m.name == trait_method.name); if !is_implemented && !is_provided { - missing_methods.push(format!("`{}`", token::get_name(trait_method.name))); + missing_items.push(format!("`{}`", token::get_name(trait_method.name))); } } ty::TypeTraitItem(ref associated_type) => { @@ -1115,17 +1115,18 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, _ => false, } }); - if !is_implemented { - missing_methods.push(format!("`{}`", token::get_name(associated_type.name))); + let is_provided = associated_type.ty.is_some(); + if !is_implemented && !is_provided { + missing_items.push(format!("`{}`", token::get_name(associated_type.name))); } } } } - if !missing_methods.is_empty() { + if !missing_items.is_empty() { span_err!(tcx.sess, impl_span, E0046, "not all trait items implemented, missing: {}", - missing_methods.connect(", ")); + missing_items.connect(", ")); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2fba967b3b237..6507f6dc37242 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -718,15 +718,17 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .insert(local_def(id), ty::ConstTraitItem(associated_const)); } -fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - ident: ast::Ident, - id: ast::NodeId, - vis: ast::Visibility) +fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + container: ImplOrTraitItemContainer, + ident: ast::Ident, + id: ast::NodeId, + vis: ast::Visibility, + ty: Option>) { let associated_type = Rc::new(ty::AssociatedType { name: ident.name, vis: vis, + ty: ty, def_id: local_def(id), container: container }); @@ -876,21 +878,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { if let ast::TypeImplItem(ref ty) = impl_item.node { if opt_trait_ref.is_none() { span_err!(tcx.sess, impl_item.span, E0202, - "associated items are not allowed in inherent impls"); + "associated types are not allowed in inherent impls"); } - as_refsociated_type(ccx, ImplContainer(local_def(it.id)), - impl_item.ident, impl_item.id, impl_item.vis); - let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); - tcx.tcache.borrow_mut().insert(local_def(impl_item.id), - TypeScheme { - generics: ty::Generics::empty(), - ty: typ, - }); - tcx.predicates.borrow_mut().insert(local_def(impl_item.id), - ty::GenericPredicates::empty()); - write_ty_to_tcx(tcx, impl_item.id, typ); + + convert_associated_type(ccx, ImplContainer(local_def(it.id)), + impl_item.ident, impl_item.id, impl_item.vis, + Some(typ)); } } @@ -973,9 +968,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { // Convert all the associated types. for trait_item in trait_items { match trait_item.node { - ast::TypeTraitItem(..) => { - as_refsociated_type(ccx, TraitContainer(local_def(it.id)), - trait_item.ident, trait_item.id, ast::Public); + ast::TypeTraitItem(_, ref opt_ty) => { + let typ = opt_ty.as_ref().map({ + |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty) + }); + + convert_associated_type(ccx, TraitContainer(local_def(it.id)), + trait_item.ident, trait_item.id, ast::Public, + typ); } _ => {} } @@ -2292,10 +2292,10 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, let lifetimes_in_associated_types: HashSet<_> = impl_items.iter() - .filter_map(|item| match item.node { - ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)), - ast::ConstImplItem(..) | ast::MethodImplItem(..) | - ast::MacImplItem(..) => None, + .map(|item| ty::impl_or_trait_item(tcx, local_def(item.id))) + .filter_map(|item| match item { + ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, + ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None }) .flat_map(|ty| ctp::parameters_for_type(ty).into_iter()) .filter_map(|p| match p { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9c64b7b4ab623..fcc4e5bb96c88 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -362,11 +362,13 @@ pub fn build_impl(cx: &DocContext, } ty::TypeTraitItem(ref assoc_ty) => { let did = assoc_ty.def_id; - let type_scheme = ty::lookup_item_type(tcx, did); - let predicates = ty::lookup_predicates(tcx, did); + let type_scheme = ty::TypeScheme { + ty: assoc_ty.ty.unwrap(), + generics: ty::Generics::empty() + }; // Not sure the choice of ParamSpace actually matters here, // because an associated type won't have generics on the LHS - let typedef = (type_scheme, predicates, + let typedef = (type_scheme, ty::GenericPredicates::empty(), subst::ParamSpace::TypeSpace).clean(cx); Some(clean::Item { name: Some(assoc_ty.name.clean(cx)), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 95444bb915872..b5aa27d0b0394 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2724,43 +2724,40 @@ impl<'tcx> Clean for ty::AssociatedConst<'tcx> { } } -impl Clean for ty::AssociatedType { +impl<'tcx> Clean for ty::AssociatedType<'tcx> { fn clean(&self, cx: &DocContext) -> Item { - // When loading a cross-crate associated type, the bounds for this type - // are actually located on the trait/impl itself, so we need to load - // all of the generics from there and then look for bounds that are - // applied to this associated type in question. - let predicates = ty::lookup_predicates(cx.tcx(), self.container.id()); - let generics = match self.container { - ty::TraitContainer(did) => { - let def = ty::lookup_trait_def(cx.tcx(), did); - (&def.generics, &predicates, subst::TypeSpace).clean(cx) - } - ty::ImplContainer(did) => { - let ty = ty::lookup_item_type(cx.tcx(), did); - (&ty.generics, &predicates, subst::TypeSpace).clean(cx) - } - }; let my_name = self.name.clean(cx); - let mut bounds = generics.where_predicates.iter().filter_map(|pred| { - let (name, self_type, trait_, bounds) = match *pred { - WherePredicate::BoundPredicate { - ty: QPath { ref name, ref self_type, ref trait_ }, - ref bounds - } => (name, self_type, trait_, bounds), - _ => return None, - }; - if *name != my_name { return None } - match **trait_ { - ResolvedPath { did, .. } if did == self.container.id() => {} - _ => return None, - } - match **self_type { - Generic(ref s) if *s == "Self" => {} - _ => return None, - } - Some(bounds) - }).flat_map(|i| i.iter().cloned()).collect::>(); + + let mut bounds = if let ty::TraitContainer(did) = self.container { + // When loading a cross-crate associated type, the bounds for this type + // are actually located on the trait/impl itself, so we need to load + // all of the generics from there and then look for bounds that are + // applied to this associated type in question. + let def = ty::lookup_trait_def(cx.tcx(), did); + let predicates = ty::lookup_predicates(cx.tcx(), did); + let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); + generics.where_predicates.iter().filter_map(|pred| { + let (name, self_type, trait_, bounds) = match *pred { + WherePredicate::BoundPredicate { + ty: QPath { ref name, ref self_type, ref trait_ }, + ref bounds + } => (name, self_type, trait_, bounds), + _ => return None, + }; + if *name != my_name { return None } + match **trait_ { + ResolvedPath { did, .. } if did == self.container.id() => {} + _ => return None, + } + match **self_type { + Generic(ref s) if *s == "Self" => {} + _ => return None, + } + Some(bounds) + }).flat_map(|i| i.iter().cloned()).collect::>() + } else { + vec![] + }; // Our Sized/?Sized bound didn't get handled when creating the generics // because we didn't actually get our whole set of bounds until just now @@ -2776,7 +2773,7 @@ impl Clean for ty::AssociatedType { source: DUMMY_SP.clean(cx), name: Some(self.name.clean(cx)), attrs: inline::load_attrs(cx, cx.tcx(), self.def_id), - inner: AssociatedTypeItem(bounds, None), + inner: AssociatedTypeItem(bounds, self.ty.clean(cx)), visibility: self.vis.clean(cx), def_id: self.def_id, stability: stability::lookup(cx.tcx(), self.def_id).clean(cx), diff --git a/src/test/run-pass/default-associated-types.rs b/src/test/run-pass/default-associated-types.rs new file mode 100644 index 0000000000000..b3def429b9b8c --- /dev/null +++ b/src/test/run-pass/default-associated-types.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 { + type Out = T; + fn foo(&self) -> Self::Out; +} + +impl Foo for () { + fn foo(&self) -> u32 { + 4u32 + } +} + +impl Foo for bool { + type Out = (); + fn foo(&self) {} +} + +fn main() { + assert_eq!(<() as Foo>::foo(&()), 4u32); + assert_eq!(>::foo(&true), ()); +} From 04c7b82c1944857c268ff79993f69c16545efb52 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 20 May 2015 23:19:55 -0400 Subject: [PATCH 06/38] Document std::env::const values --- src/libstd/env.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 126ef38b9188f..3e38f9e6c4de7 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -598,40 +598,94 @@ pub fn page_size() -> usize { pub mod consts { /// A string describing the architecture of the CPU that this is currently /// in use. + /// + /// Some possible values: + /// + /// - x86 + /// - x86_64 + /// - arm + /// - aarch64 + /// - mips + /// - mipsel + /// - powerpc #[stable(feature = "env", since = "1.0.0")] pub const ARCH: &'static str = super::arch::ARCH; /// The family of the operating system. In this case, `unix`. + /// + /// Some possible values: + /// + /// - unix + /// - windows #[stable(feature = "env", since = "1.0.0")] pub const FAMILY: &'static str = super::os::FAMILY; /// A string describing the specific operating system in use: in this /// case, `linux`. + /// + /// Some possible values: + /// + /// - linux + /// - macos + /// - ios + /// - freebsd + /// - dragonfly + /// - bitrig + /// - openbsd + /// - android + /// - windows #[stable(feature = "env", since = "1.0.0")] pub const OS: &'static str = super::os::OS; /// Specifies the filename prefix used for shared libraries on this /// platform: in this case, `lib`. + /// + /// Some possible values: + /// + /// - lib + /// - `""` (an empty string) #[stable(feature = "env", since = "1.0.0")] pub const DLL_PREFIX: &'static str = super::os::DLL_PREFIX; /// Specifies the filename suffix used for shared libraries on this /// platform: in this case, `.so`. + /// + /// Some possible values: + /// + /// - .so + /// - .dylib + /// - .dll #[stable(feature = "env", since = "1.0.0")] pub const DLL_SUFFIX: &'static str = super::os::DLL_SUFFIX; /// Specifies the file extension used for shared libraries on this /// platform that goes after the dot: in this case, `so`. + /// + /// Some possible values: + /// + /// - .so + /// - .dylib + /// - .dll #[stable(feature = "env", since = "1.0.0")] pub const DLL_EXTENSION: &'static str = super::os::DLL_EXTENSION; /// Specifies the filename suffix used for executable binaries on this /// platform: in this case, the empty string. + /// + /// Some possible values: + /// + /// - exe + /// - `""` (an empty string) #[stable(feature = "env", since = "1.0.0")] pub const EXE_SUFFIX: &'static str = super::os::EXE_SUFFIX; /// Specifies the file extension, if any, used for executable binaries /// on this platform: in this case, the empty string. + /// + /// Some possible values: + /// + /// - exe + /// - `""` (an empty string) #[stable(feature = "env", since = "1.0.0")] pub const EXE_EXTENSION: &'static str = super::os::EXE_EXTENSION; From 65a3245319405e4dd53f10abdbc042502d184c93 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 26 May 2015 20:01:20 +0300 Subject: [PATCH 07/38] Add tests for fixed issues Fixes #23037. Fixes #25339. --- src/test/compile-fail/issue-23073.rs | 17 +++++++++++++ src/test/run-pass/issue-25339.rs | 36 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/test/compile-fail/issue-23073.rs create mode 100644 src/test/run-pass/issue-25339.rs diff --git a/src/test/compile-fail/issue-23073.rs b/src/test/compile-fail/issue-23073.rs new file mode 100644 index 0000000000000..1286ba873be5a --- /dev/null +++ b/src/test/compile-fail/issue-23073.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. + +trait Foo { type T; } +trait Bar { + type Foo: Foo; + type FooT = <::Foo>::T; //~ ERROR ambiguous associated type +} + +fn main() {} diff --git a/src/test/run-pass/issue-25339.rs b/src/test/run-pass/issue-25339.rs new file mode 100644 index 0000000000000..af172000fdb1a --- /dev/null +++ b/src/test/run-pass/issue-25339.rs @@ -0,0 +1,36 @@ +// 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. + +use std::marker::PhantomData; + +pub trait Routing { + type Output; + fn resolve(&self, input: I); +} + +pub trait ToRouting { + type Input; + type Routing : ?Sized = Routing; + fn to_routing(self) -> Self::Routing; +} + +pub struct Mount> { + action: R, + _marker: PhantomData +} + +impl> Mount { + pub fn create>(mount: &str, input: T) { + input.to_routing(); + } +} + +fn main() { +} From bc7c62de6d2b9fbd6cc024a036494107e8c19f6f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 26 May 2015 09:48:24 -0700 Subject: [PATCH 08/38] mk: Ensure LINK_$(1) is defined for all targets The changes scaled back in 4cc025d8 were a little too aggressive and broke a bunch of cross compilations by not defining the `LINK_$(1)` variable for all targets. This commit ensures that the variable is defined for all targets by defaulting it to the normal compiler if it's not already defined (it's only defined specially for MSVC). Closes #25723 --- mk/cfg/aarch64-linux-android.mk | 1 - mk/cfg/aarch64-unknown-linux-gnu.mk | 1 - mk/cfg/arm-linux-androideabi.mk | 1 - mk/cfg/i686-apple-darwin.mk | 1 - mk/cfg/i686-unknown-linux-gnu.mk | 1 - mk/cfg/x86_64-apple-darwin.mk | 1 - mk/cfg/x86_64-pc-windows-gnu.mk | 1 - mk/cfg/x86_64-unknown-linux-gnu.mk | 1 - mk/platform.mk | 9 +++++++++ 9 files changed, 9 insertions(+), 8 deletions(-) diff --git a/mk/cfg/aarch64-linux-android.mk b/mk/cfg/aarch64-linux-android.mk index 9e0245e093d8a..d7a1405c3d0a8 100644 --- a/mk/cfg/aarch64-linux-android.mk +++ b/mk/cfg/aarch64-linux-android.mk @@ -1,7 +1,6 @@ # aarch64-linux-android configuration # CROSS_PREFIX_aarch64-linux-android- CC_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-gcc -LINK_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-gcc CXX_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-g++ CPP_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-gcc -E AR_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-ar diff --git a/mk/cfg/aarch64-unknown-linux-gnu.mk b/mk/cfg/aarch64-unknown-linux-gnu.mk index 88d7700db820f..6637423e4951a 100644 --- a/mk/cfg/aarch64-unknown-linux-gnu.mk +++ b/mk/cfg/aarch64-unknown-linux-gnu.mk @@ -1,7 +1,6 @@ # aarch64-unknown-linux-gnu configuration CROSS_PREFIX_aarch64-unknown-linux-gnu=aarch64-linux-gnu- CC_aarch64-unknown-linux-gnu=gcc -LINK_aarch64-unknown-linux-gnu=gcc CXX_aarch64-unknown-linux-gnu=g++ CPP_aarch64-unknown-linux-gnu=gcc -E AR_aarch64-unknown-linux-gnu=ar diff --git a/mk/cfg/arm-linux-androideabi.mk b/mk/cfg/arm-linux-androideabi.mk index a66f70f6305ed..fdd38ba75fe58 100644 --- a/mk/cfg/arm-linux-androideabi.mk +++ b/mk/cfg/arm-linux-androideabi.mk @@ -1,5 +1,4 @@ # arm-linux-androideabi configuration -LINK_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-gcc CC_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-gcc CXX_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-g++ CPP_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-gcc -E diff --git a/mk/cfg/i686-apple-darwin.mk b/mk/cfg/i686-apple-darwin.mk index 25b692449aa29..7ebb492bb21fe 100644 --- a/mk/cfg/i686-apple-darwin.mk +++ b/mk/cfg/i686-apple-darwin.mk @@ -1,6 +1,5 @@ # i686-apple-darwin configuration CC_i686-apple-darwin=$(CC) -LINK_i686-apple-darwin=cc CXX_i686-apple-darwin=$(CXX) CPP_i686-apple-darwin=$(CPP) AR_i686-apple-darwin=$(AR) diff --git a/mk/cfg/i686-unknown-linux-gnu.mk b/mk/cfg/i686-unknown-linux-gnu.mk index 1c5de9a2c05e6..88c0907f63b2a 100644 --- a/mk/cfg/i686-unknown-linux-gnu.mk +++ b/mk/cfg/i686-unknown-linux-gnu.mk @@ -1,6 +1,5 @@ # i686-unknown-linux-gnu configuration CC_i686-unknown-linux-gnu=$(CC) -LINK_i686-unknown-linux-gnu=cc CXX_i686-unknown-linux-gnu=$(CXX) CPP_i686-unknown-linux-gnu=$(CPP) AR_i686-unknown-linux-gnu=$(AR) diff --git a/mk/cfg/x86_64-apple-darwin.mk b/mk/cfg/x86_64-apple-darwin.mk index 9d3361b7fc638..4c68d3dcf37b4 100644 --- a/mk/cfg/x86_64-apple-darwin.mk +++ b/mk/cfg/x86_64-apple-darwin.mk @@ -1,6 +1,5 @@ # x86_64-apple-darwin configuration CC_x86_64-apple-darwin=$(CC) -LINK_x86_64-apple-darwin=cc CXX_x86_64-apple-darwin=$(CXX) CPP_x86_64-apple-darwin=$(CPP) AR_x86_64-apple-darwin=$(AR) diff --git a/mk/cfg/x86_64-pc-windows-gnu.mk b/mk/cfg/x86_64-pc-windows-gnu.mk index 10aaf137e8b3a..4118ea26c072b 100644 --- a/mk/cfg/x86_64-pc-windows-gnu.mk +++ b/mk/cfg/x86_64-pc-windows-gnu.mk @@ -1,7 +1,6 @@ # x86_64-pc-windows-gnu configuration CROSS_PREFIX_x86_64-pc-windows-gnu=x86_64-w64-mingw32- CC_x86_64-pc-windows-gnu=gcc -LINK_x86_64-pc-windows-gnu=gcc CXX_x86_64-pc-windows-gnu=g++ CPP_x86_64-pc-windows-gnu=gcc -E AR_x86_64-pc-windows-gnu=ar diff --git a/mk/cfg/x86_64-unknown-linux-gnu.mk b/mk/cfg/x86_64-unknown-linux-gnu.mk index 1735d1eb3f798..044c687c9fc4c 100644 --- a/mk/cfg/x86_64-unknown-linux-gnu.mk +++ b/mk/cfg/x86_64-unknown-linux-gnu.mk @@ -1,6 +1,5 @@ # x86_64-unknown-linux-gnu configuration CC_x86_64-unknown-linux-gnu=$(CC) -LINK_x86_64-unknown-linux-gnu=cc CXX_x86_64-unknown-linux-gnu=$(CXX) CPP_x86_64-unknown-linux-gnu=$(CPP) AR_x86_64-unknown-linux-gnu=$(AR) diff --git a/mk/platform.mk b/mk/platform.mk index 26a6db1c5bd1a..8a5e58c46f676 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -120,6 +120,15 @@ endef $(foreach target,$(CFG_TARGET), \ $(eval $(call ADD_INSTALLED_OBJECTS,$(target)))) +define DEFINE_LINKER + ifndef LINK_$(1) + LINK_$(1) := $$(CC_$(1)) + endif +endef + +$(foreach target,$(CFG_TARGET), \ + $(eval $(call DEFINE_LINKER,$(target)))) + # The -Qunused-arguments sidesteps spurious warnings from clang define FILTER_FLAGS ifeq ($$(CFG_USING_CLANG),1) From 909cbbeda81f64fe9d92e2d4fe5325cc9a4a327a Mon Sep 17 00:00:00 2001 From: Johannes Oertel Date: Tue, 26 May 2015 23:46:55 +0200 Subject: [PATCH 09/38] Enable colored test output when capturing output of tests The output of individual tests can be captured now so it's safe to use colorized output even when running tests in parallel. Closes #782. --- src/libtest/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 575f29b3bc97f..da86e727c6874 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -740,7 +740,7 @@ fn should_sort_failures_before_printing_them() { fn use_color(opts: &TestOpts) -> bool { match opts.color { - AutoColor => get_concurrency() == 1 && stdout_isatty(), + AutoColor => !opts.nocapture && stdout_isatty(), AlwaysColor => true, NeverColor => false, } From ff682048804453b67199acc9c64f332e58251c41 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 26 May 2015 20:34:50 +1200 Subject: [PATCH 10/38] Add a WONTFIX message to a failing test. Closes #20184 --- src/librustc_trans/back/link.rs | 2 +- src/librustc_trans/back/write.rs | 4 ++-- src/test/compile-fail/asm-src-loc-codegen-units.rs | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 844a0a698677f..c416a9810eb0e 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -279,7 +279,7 @@ pub fn sanitize(s: &str) -> String { } pub fn mangle>(path: PI, - hash: Option<&str>) -> String { + hash: Option<&str>) -> String { // Follow C++ namespace-mangling style, see // http://en.wikipedia.org/wiki/Name_mangling for more info. // diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index a9e9e3f4048ac..aec8f2b3fa748 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -342,8 +342,8 @@ struct HandlerFreeVars<'a> { } unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>, - msg: &'b str, - cookie: c_uint) { + msg: &'b str, + cookie: c_uint) { use syntax::codemap::ExpnId; match cgcx.lto_ctxt { diff --git a/src/test/compile-fail/asm-src-loc-codegen-units.rs b/src/test/compile-fail/asm-src-loc-codegen-units.rs index 5ebcdb20b1952..79f0c436759b3 100644 --- a/src/test/compile-fail/asm-src-loc-codegen-units.rs +++ b/src/test/compile-fail/asm-src-loc-codegen-units.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. // -// ignore-stage1 (#20184) +// WONTFIX(#20184) Needs landing pads (not present in stage1) or the compiler hangs. +// ignore-stage1 // compile-flags: -C codegen-units=2 // error-pattern: build without -C codegen-units for more exact errors From 577bbaceb982623ecd2b220a31a162ccb3b1d378 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 5 May 2015 16:30:13 -0400 Subject: [PATCH 11/38] Add note about filesystems to fs::rename Fixes #24816 --- src/libstd/fs.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 5a05c61e064df..0a19350851ea0 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -844,6 +844,8 @@ pub fn symlink_metadata>(path: P) -> io::Result { /// Rename a file or directory to a new name. /// +/// This will not work if the new name is on a different mount point. +/// /// # Errors /// /// This function will return an error if the provided `from` doesn't exist, if From ea5c8eb2c9ca9af16a141b0e9b0f22c1b99b0495 Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Tue, 26 May 2015 16:03:41 -0700 Subject: [PATCH 12/38] Bump manpage date and version for 1.2.0-dev. Estimating August as the release date for 1.2.0. --- man/rustc.1 | 2 +- man/rustdoc.1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/man/rustc.1 b/man/rustc.1 index b15829db431df..36f4e529b6c52 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -1,4 +1,4 @@ -.TH RUSTC "1" "March 2014" "rustc 0.13.0" "User Commands" +.TH RUSTC "1" "August 2015" "rustc 1.2.0" "User Commands" .SH NAME rustc \- The Rust compiler .SH SYNOPSIS diff --git a/man/rustdoc.1 b/man/rustdoc.1 index 1738354fb43d5..b710c2c3a2560 100644 --- a/man/rustdoc.1 +++ b/man/rustdoc.1 @@ -1,4 +1,4 @@ -.TH RUSTDOC "1" "March 2014" "rustdoc 0.13.0" "User Commands" +.TH RUSTDOC "1" "August 2015" "rustdoc 1.2.0" "User Commands" .SH NAME rustdoc \- generate documentation from Rust source code .SH SYNOPSIS From bb61b0b8bb7c078bfa035cd5c392f029802b49ec Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Tue, 26 May 2015 16:06:43 -0700 Subject: [PATCH 13/38] Update rustc manpage. rustc -C target-cpu=help is no longer supported. Recommend the llc tool intead like 'rustc --help'. --- man/rustc.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/rustc.1 b/man/rustc.1 index 36f4e529b6c52..0cb1c5dc32b8e 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -160,7 +160,7 @@ If the value is 'help', then a list of available CPUs is printed. \fBtarget\-feature\fR='\fI+feature1\fR,\fI\-feature2\fR' A comma\[hy]separated list of features to enable or disable for the target. A preceding '+' enables a feature while a preceding '\-' disables it. -Available features can be discovered through \fItarget\-cpu=help\fR. +Available features can be discovered through \fIllc -mcpu=help\fR. .TP \fBpasses\fR=\fIval\fR A space\[hy]separated list of extra LLVM passes to run. From 279ec9b9b871dc6ef52ebc808adca177f596795e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 27 May 2015 09:15:19 -0700 Subject: [PATCH 14/38] test: Join child threads on windows in tests Windows tests can often deadlock if a child thread continues after the main thread and then panics, and a `println!` executed in a child thread after the main thread has exited is at risk of panicking. --- src/test/run-pass/macro-with-braces-in-expr-position.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/run-pass/macro-with-braces-in-expr-position.rs b/src/test/run-pass/macro-with-braces-in-expr-position.rs index 4881a5ab647ec..326d1cafe6c78 100644 --- a/src/test/run-pass/macro-with-braces-in-expr-position.rs +++ b/src/test/run-pass/macro-with-braces-in-expr-position.rs @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(std_misc)] - use std::thread; macro_rules! expr { ($e: expr) => { $e } } macro_rules! spawn { ($($code: tt)*) => { - expr!(thread::spawn(move|| {$($code)*})) + expr!(thread::spawn(move|| {$($code)*}).join()) } } From c68e65251c86ffdb21aecec56ec45e303d952d79 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 27 May 2015 20:31:56 +0300 Subject: [PATCH 15/38] test fixes --- src/test/compile-fail/assoc-inherent.rs | 2 +- src/test/compile-fail/issue-22673.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/assoc-inherent.rs b/src/test/compile-fail/assoc-inherent.rs index e68c3e30b9a7b..7eab831258f2e 100644 --- a/src/test/compile-fail/assoc-inherent.rs +++ b/src/test/compile-fail/assoc-inherent.rs @@ -13,7 +13,7 @@ struct Foo; impl Foo { - type Bar = isize; //~ERROR associated items are not allowed in inherent impls + type Bar = isize; //~ERROR associated types are not allowed in inherent impls } fn main() {} diff --git a/src/test/compile-fail/issue-22673.rs b/src/test/compile-fail/issue-22673.rs index 6983d1f0706a0..442e6bcda5a09 100644 --- a/src/test/compile-fail/issue-22673.rs +++ b/src/test/compile-fail/issue-22673.rs @@ -10,7 +10,7 @@ trait Expr : PartialEq { //~^ ERROR: unsupported cyclic reference between types/traits detected - type Item = Expr; + type Item; } fn main() {} From 699fc80780b50d302a74475ff9240995d8117516 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 27 May 2015 20:42:42 +0300 Subject: [PATCH 16/38] Address review comments --- src/librustc/middle/traits/project.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 700aaad8b72d3..969f82cc5ae1b 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -859,6 +859,7 @@ fn confirm_impl_candidate<'cx,'tcx>( // there don't seem to be nicer accessors to these: let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow(); + // Look for the associated type in the impl for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] { if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] { if assoc_ty.name == obligation.predicate.item_name { @@ -868,6 +869,7 @@ fn confirm_impl_candidate<'cx,'tcx>( } } + // It is not in the impl - get the default from the trait. let trait_ref = obligation.predicate.trait_ref; for trait_item in ty::trait_items(selcx.tcx(), trait_ref.def_id).iter() { if let &ty::TypeTraitItem(ref assoc_ty) = trait_item { From 62e5dee1c5743bb01b32a8b7eec691c02d528bf3 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 27 May 2015 14:51:58 -0400 Subject: [PATCH 17/38] fix example for E0018 Fixes #25326 --- src/librustc/diagnostics.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 9d459027bf5cd..9f576d0dae0e4 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -218,9 +218,9 @@ Therefore, casting one of these non-constant pointers to an integer results in a non-constant integer which lead to this error. Example: ``` -const X: u32 = 50; -const Y: *const u32 = &X; -println!("{:?}", Y); +const X: u32 = 1; +const Y: usize = &X as *const u32 as usize; +println!("{}", Y); ``` "##, From 4db7e56b016a73ae5788328985db1b82b4c3c807 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 27 May 2015 15:02:42 -0400 Subject: [PATCH 18/38] Small wording fix in TRPL: lifetimes Fixes #25438 --- src/doc/trpl/lifetimes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index 0039f90b82c35..04ae4c7ccf3cc 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -134,8 +134,8 @@ x: &'a i32, # } ``` -uses it. So why do we need a lifetime here? We need to ensure that any reference -to a `Foo` cannot outlive the reference to an `i32` it contains. +uses it. So why do we need a lifetime here? We need to ensure that any +reference to the contained `i32` does not outlive the containing `Foo`. ## Thinking in scopes From 6c2b340fdcb5a38a4e93883f4816b019cb12fc19 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Wed, 27 May 2015 12:37:29 -0700 Subject: [PATCH 19/38] Improve docs for Vec::as_slice and as_mut_slice Fixes #25622. --- src/libcollections/vec.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 4d52eb8e8ae67..8dacfa53bc980 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -440,6 +440,8 @@ impl Vec { } /// Extracts a slice containing the entire vector. + /// + /// Equivalent to `&s[..]`. #[inline] #[unstable(feature = "convert", reason = "waiting on RFC revision")] @@ -447,7 +449,9 @@ impl Vec { self } - /// Deprecated: use `&mut s[..]` instead. + /// Extracts a mutable slice of the entire vector. + /// + /// Equivalent to `&mut s[..]`. #[inline] #[unstable(feature = "convert", reason = "waiting on RFC revision")] From 875d3562452930657ab59766568c02bcfab851bd Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Wed, 27 May 2015 19:16:00 -0400 Subject: [PATCH 20/38] Remove mentions of int / uint from the isize / usize docs --- src/libcore/num/isize.rs | 4 ---- src/libcore/num/usize.rs | 4 ---- src/libstd/num/isize.rs | 4 ---- src/libstd/num/usize.rs | 4 ---- 4 files changed, 16 deletions(-) diff --git a/src/libcore/num/isize.rs b/src/libcore/num/isize.rs index 0fd0d90b12501..2cdfe03eafe7f 100644 --- a/src/libcore/num/isize.rs +++ b/src/libcore/num/isize.rs @@ -9,10 +9,6 @@ // except according to those terms. //! Operations and constants for pointer-sized signed integers (`isize` type) -//! -//! This type was recently added to replace `int`. The rollout of the -//! new type will gradually take place over the alpha cycle along with -//! the development of clearer conventions around integer types. #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "isize")] diff --git a/src/libcore/num/usize.rs b/src/libcore/num/usize.rs index 602ef4fe45e73..6fd23425e4d89 100644 --- a/src/libcore/num/usize.rs +++ b/src/libcore/num/usize.rs @@ -9,10 +9,6 @@ // except according to those terms. //! Operations and constants for pointer-sized unsigned integers (`usize` type) -//! -//! This type was recently added to replace `uint`. The rollout of the -//! new type will gradually take place over the alpha cycle along with -//! the development of clearer conventions around integer types. #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "usize")] diff --git a/src/libstd/num/isize.rs b/src/libstd/num/isize.rs index 7fb2cd81ababf..aa89f858f6f63 100644 --- a/src/libstd/num/isize.rs +++ b/src/libstd/num/isize.rs @@ -9,10 +9,6 @@ // except according to those terms. //! Operations and constants for pointer-sized signed integers (`isize` type) -//! -//! This type was recently added to replace `int`. The rollout of the -//! new type will gradually take place over the alpha cycle along with -//! the development of clearer conventions around integer types. #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "isize")] diff --git a/src/libstd/num/usize.rs b/src/libstd/num/usize.rs index 19964c306a79b..b54d8ae96c5cf 100644 --- a/src/libstd/num/usize.rs +++ b/src/libstd/num/usize.rs @@ -9,10 +9,6 @@ // except according to those terms. //! Operations and constants for pointer-sized unsigned integers (`usize` type) -//! -//! This type was recently added to replace `uint`. The rollout of the -//! new type will gradually take place over the alpha cycle along with -//! the development of clearer conventions around integer types. #![stable(feature = "rust1", since = "1.0.0")] #![doc(primitive = "usize")] From a959cc435f4f5821d26ae36716d6a46e2af550af Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Wed, 27 May 2015 19:20:32 -0400 Subject: [PATCH 21/38] Remove mentions of int / uint from public documentation --- src/doc/complement-design-faq.md | 2 +- src/doc/style/errors/ergonomics.md | 8 ++++---- src/doc/style/features/functions-and-methods/input.md | 10 +++++----- src/doc/style/features/functions-and-methods/output.md | 4 ++-- src/doc/style/features/let.md | 4 ++-- src/doc/style/features/traits/reuse.md | 2 +- src/doc/style/features/types/newtype.md | 4 ++-- src/doc/style/style/features.md | 2 +- src/doc/style/style/imports.md | 2 +- src/doc/style/style/whitespace.md | 2 +- src/doc/trpl/associated-types.md | 2 +- src/doc/trpl/box-syntax-and-patterns.md | 2 +- src/doc/trpl/traits.md | 2 +- 13 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/doc/complement-design-faq.md b/src/doc/complement-design-faq.md index e0a56a1a631d4..e887ed0cc5297 100644 --- a/src/doc/complement-design-faq.md +++ b/src/doc/complement-design-faq.md @@ -160,7 +160,7 @@ that all delimiters be balanced. ## `->` for function return type This is to make the language easier to parse for humans, especially in the face -of higher-order functions. `fn foo(f: fn(int): int, fn(T): U): U` is not +of higher-order functions. `fn foo(f: fn(i32): i32, fn(T): U): U` is not particularly easy to read. ## Why is `let` used to introduce variables? diff --git a/src/doc/style/errors/ergonomics.md b/src/doc/style/errors/ergonomics.md index d2fcf27e93cdf..d530301a90939 100644 --- a/src/doc/style/errors/ergonomics.md +++ b/src/doc/style/errors/ergonomics.md @@ -14,8 +14,8 @@ use std::io::{File, Open, Write, IoError}; struct Info { name: String, - age: int, - rating: int + age: i32, + rating: i32 } fn write_info(info: &Info) -> Result<(), IoError> { @@ -36,8 +36,8 @@ use std::io::{File, Open, Write, IoError}; struct Info { name: String, - age: int, - rating: int + age: i32, + rating: i32 } fn write_info(info: &Info) -> Result<(), IoError> { diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md index b0912ea0203dc..9b9500008c2f6 100644 --- a/src/doc/style/features/functions-and-methods/input.md +++ b/src/doc/style/features/functions-and-methods/input.md @@ -57,15 +57,15 @@ it becomes. Prefer ```rust -fn foo>(c: T) { ... } +fn foo>(c: T) { ... } ``` over any of ```rust -fn foo(c: &[int]) { ... } -fn foo(c: &Vec) { ... } -fn foo(c: &SomeOtherCollection) { ... } +fn foo(c: &[i32]) { ... } +fn foo(c: &Vec) { ... } +fn foo(c: &SomeOtherCollection) { ... } ``` if the function only needs to iterate over the data. @@ -121,7 +121,7 @@ The primary exception: sometimes a function is meant to modify data that the caller already owns, for example to re-use a buffer: ```rust -fn read(&mut self, buf: &mut [u8]) -> IoResult +fn read(&mut self, buf: &mut [u8]) -> IoResult ``` (From the [Reader trait](http://static.rust-lang.org/doc/master/std/io/trait.Reader.html#tymethod.read).) diff --git a/src/doc/style/features/functions-and-methods/output.md b/src/doc/style/features/functions-and-methods/output.md index a83e2b76bcb7f..3e43d1e416d76 100644 --- a/src/doc/style/features/functions-and-methods/output.md +++ b/src/doc/style/features/functions-and-methods/output.md @@ -19,7 +19,7 @@ Prefer ```rust struct SearchResult { found: bool, // item in container? - expected_index: uint // what would the item's index be? + expected_index: usize // what would the item's index be? } fn binary_search(&self, k: Key) -> SearchResult @@ -27,7 +27,7 @@ fn binary_search(&self, k: Key) -> SearchResult or ```rust -fn binary_search(&self, k: Key) -> (bool, uint) +fn binary_search(&self, k: Key) -> (bool, usize) ``` over diff --git a/src/doc/style/features/let.md b/src/doc/style/features/let.md index 87117a20d7a49..f13a84f6fee86 100644 --- a/src/doc/style/features/let.md +++ b/src/doc/style/features/let.md @@ -5,7 +5,7 @@ Prefer ```rust -fn use_mutex(m: sync::mutex::Mutex) { +fn use_mutex(m: sync::mutex::Mutex) { let guard = m.lock(); do_work(guard); drop(guard); // unlock the lock @@ -16,7 +16,7 @@ fn use_mutex(m: sync::mutex::Mutex) { over ```rust -fn use_mutex(m: sync::mutex::Mutex) { +fn use_mutex(m: sync::mutex::Mutex) { do_work(m.lock()); // do other work } diff --git a/src/doc/style/features/traits/reuse.md b/src/doc/style/features/traits/reuse.md index 6735023ae6800..61f8db87cde89 100644 --- a/src/doc/style/features/traits/reuse.md +++ b/src/doc/style/features/traits/reuse.md @@ -15,7 +15,7 @@ trait Printable { fn print(&self) { println!("{:?}", *self) } } -impl Printable for int {} +impl Printable for i32 {} impl Printable for String { fn print(&self) { println!("{}", *self) } diff --git a/src/doc/style/features/types/newtype.md b/src/doc/style/features/types/newtype.md index 60c17fc2a52e2..e69aa3b83bfa4 100644 --- a/src/doc/style/features/types/newtype.md +++ b/src/doc/style/features/types/newtype.md @@ -43,12 +43,12 @@ promises to the client. For example, consider a function `my_transform` that returns a compound iterator type `Enumerate>>`. We wish to hide this type from the -client, so that the client's view of the return type is roughly `Iterator<(uint, +client, so that the client's view of the return type is roughly `Iterator<(usize, T)>`. We can do so using the newtype pattern: ```rust struct MyTransformResult(Enumerate>>); -impl Iterator<(uint, T)> for MyTransformResult { ... } +impl Iterator<(usize, T)> for MyTransformResult { ... } fn my_transform>(iter: Iter) -> MyTransformResult { ... diff --git a/src/doc/style/style/features.md b/src/doc/style/style/features.md index f73517c2b9c3b..b5d0b484ccda5 100644 --- a/src/doc/style/style/features.md +++ b/src/doc/style/style/features.md @@ -3,7 +3,7 @@ Terminate `return` statements with semicolons: ``` rust -fn foo(bar: int) -> Option { +fn foo(bar: i32) -> Option { if some_condition() { return None; } diff --git a/src/doc/style/style/imports.md b/src/doc/style/style/imports.md index 207a3fd7f8d16..cf3fd4163a26e 100644 --- a/src/doc/style/style/imports.md +++ b/src/doc/style/style/imports.md @@ -44,7 +44,7 @@ For example: use option::Option; use mem; -let i: int = mem::transmute(Option(0)); +let i: isize = mem::transmute(Option(0)); ``` > **[FIXME]** Add rationale. diff --git a/src/doc/style/style/whitespace.md b/src/doc/style/style/whitespace.md index b21b280dff0d7..c28a723209563 100644 --- a/src/doc/style/style/whitespace.md +++ b/src/doc/style/style/whitespace.md @@ -10,7 +10,7 @@ ``` rust #[deprecated = "Use `bar` instead."] -fn foo(a: uint, b: uint) -> uint { +fn foo(a: usize, b: usize) -> usize { a + b } ``` diff --git a/src/doc/trpl/associated-types.md b/src/doc/trpl/associated-types.md index 55e2787cc2591..ec96880f12a95 100644 --- a/src/doc/trpl/associated-types.md +++ b/src/doc/trpl/associated-types.md @@ -43,7 +43,7 @@ trait Graph { Now, our clients can be abstract over a given `Graph`: ```rust,ignore -fn distance(graph: &G, start: &G::N, end: &G::N) -> uint { ... } +fn distance(graph: &G, start: &G::N, end: &G::N) -> usize { ... } ``` No need to deal with the `E`dge type here! diff --git a/src/doc/trpl/box-syntax-and-patterns.md b/src/doc/trpl/box-syntax-and-patterns.md index 1cf84bfd658c0..8d83b64d68313 100644 --- a/src/doc/trpl/box-syntax-and-patterns.md +++ b/src/doc/trpl/box-syntax-and-patterns.md @@ -58,7 +58,7 @@ fn main() { ``` The idea is that by passing around a box, you're only copying a pointer, rather -than the hundred `int`s that make up the `BigStruct`. +than the hundred `i32`s that make up the `BigStruct`. This is an antipattern in Rust. Instead, write this: diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index efa16f2942f06..9ac170ddec298 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -146,7 +146,7 @@ print_area(5); We get a compile-time error: ```text -error: failed to find an implementation of trait main::HasArea for int +error: the trait `HasArea` is not implemented for the type `_` [E0277] ``` So far, we’ve only added trait implementations to structs, but you can From 080311d1f9919fe877414b2e0c9e8260ae157ccf Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 28 May 2015 00:35:56 +0300 Subject: [PATCH 22/38] Prevent comparison and dereferencing of raw pointers in constexprs Fixes #25826. --- src/librustc/diagnostics.rs | 4 ++- src/librustc/middle/check_const.rs | 31 +++++++++++++++++++----- src/test/compile-fail/const-deref-ptr.rs | 16 ++++++++++++ src/test/compile-fail/issue-17458.rs | 2 +- src/test/compile-fail/issue-25826.rs | 16 ++++++++++++ 5 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/const-deref-ptr.rs create mode 100644 src/test/compile-fail/issue-25826.rs diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 9d459027bf5cd..d1e7084150eb3 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -892,6 +892,8 @@ register_diagnostics! { E0316, // nested quantification of lifetimes E0370, // discriminant overflow E0378, // method calls limited to constant inherent methods - E0394 // cannot refer to other statics by value, use the address-of + E0394, // cannot refer to other statics by value, use the address-of // operator or a constant instead + E0395, // pointer comparison in const-expr + E0396 // pointer dereference in const-expr } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index c54517e00173b..3e084f3eeb305 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -536,11 +536,32 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, "allocations are not allowed in {}s", v.msg()); } } - ast::ExprUnary(ast::UnDeref, ref ptr) => { - match ty::node_id_to_type(v.tcx, ptr.id).sty { + ast::ExprUnary(op, ref inner) => { + match ty::node_id_to_type(v.tcx, inner.id).sty { ty::ty_ptr(_) => { - // This shouldn't be allowed in constants at all. + assert!(op == ast::UnDeref); + + v.add_qualif(ConstQualif::NOT_CONST); + if v.mode != Mode::Var { + span_err!(v.tcx.sess, e.span, E0396, + "raw pointers cannot be dereferenced in {}s", v.msg()); + } + } + _ => {} + } + } + ast::ExprBinary(op, ref lhs, _) => { + match ty::node_id_to_type(v.tcx, lhs.id).sty { + ty::ty_ptr(_) => { + assert!(op.node == ast::BiEq || op.node == ast::BiNe || + op.node == ast::BiLe || op.node == ast::BiLt || + op.node == ast::BiGe || op.node == ast::BiGt); + v.add_qualif(ConstQualif::NOT_CONST); + if v.mode != Mode::Var { + span_err!(v.tcx.sess, e.span, E0395, + "raw pointers cannot be compared in {}s", v.msg()); + } } _ => {} } @@ -553,7 +574,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, v.add_qualif(ConstQualif::NOT_CONST); if v.mode != Mode::Var { span_err!(v.tcx.sess, e.span, E0018, - "can't cast a pointer to an integer in {}s", v.msg()); + "raw pointers cannot be cast to integers in {}s", v.msg()); } } _ => {} @@ -695,8 +716,6 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } ast::ExprBlock(_) | - ast::ExprUnary(..) | - ast::ExprBinary(..) | ast::ExprIndex(..) | ast::ExprField(..) | ast::ExprTupField(..) | diff --git a/src/test/compile-fail/const-deref-ptr.rs b/src/test/compile-fail/const-deref-ptr.rs new file mode 100644 index 0000000000000..fa15f3e87c694 --- /dev/null +++ b/src/test/compile-fail/const-deref-ptr.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. + +// Check that you can't dereference raw pointers in constants. + +fn main() { + static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~ ERROR E0396 + println!("{}", C); +} diff --git a/src/test/compile-fail/issue-17458.rs b/src/test/compile-fail/issue-17458.rs index a3a9e17cb3c06..f5b7a0c13b728 100644 --- a/src/test/compile-fail/issue-17458.rs +++ b/src/test/compile-fail/issue-17458.rs @@ -9,7 +9,7 @@ // except according to those terms. static X: usize = 0 as *const usize as usize; -//~^ ERROR: can't cast a pointer to an integer in statics +//~^ ERROR: raw pointers cannot be cast to integers in statics fn main() { assert_eq!(X, 0); diff --git a/src/test/compile-fail/issue-25826.rs b/src/test/compile-fail/issue-25826.rs new file mode 100644 index 0000000000000..00e1279d58a0e --- /dev/null +++ b/src/test/compile-fail/issue-25826.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 id(t: T) -> T { t } +fn main() { + const A: bool = id:: as *const () < id:: as *const (); + //~^ ERROR raw pointers cannot be compared in constants [E0395] + println!("{}", A); +} From b2c8719341edaade2d8ccccf8e3db7ef4c208ca5 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 26 May 2015 10:35:53 +1200 Subject: [PATCH 23/38] save-analysis: move another couple of things to the API --- src/librustc_trans/save/dump_csv.rs | 69 +++++++++++-------------- src/librustc_trans/save/mod.rs | 80 ++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 40 deletions(-) diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index 00a1f728b9b00..5c630533ec33d 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -508,7 +508,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { self.process_formals(&decl.inputs, &fn_data.qualname); self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); } else { - unreachable!(); + self.sess.span_bug(item.span, "expected FunctionData"); } for arg in &decl.inputs { @@ -538,7 +538,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { &var_data.type_value, var_data.scope); } else { - unreachable!(); + self.sess.span_bug(item.span, "expected VariableData"); } self.visit_ty(&typ); @@ -768,22 +768,18 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } fn process_mod(&mut self, - item: &ast::Item, // The module in question, represented as an item. - m: &ast::Mod) { - let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id)); - - let cm = self.sess.codemap(); - let filename = cm.span_to_filename(m.inner); - - let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Mod); - self.fmt.mod_str(item.span, - sub_span, - item.id, - &qualname[..], - self.cur_scope, - &filename[..]); - - self.nest(item.id, |v| visit::walk_mod(v, m)); + item: &ast::Item) { // The module in question, represented as an item. + let mod_data = self.save_ctxt.get_item_data(item); + if let super::Data::ModData(mod_data) = mod_data { + self.fmt.mod_str(item.span, + Some(mod_data.span), + mod_data.id, + &mod_data.qualname, + mod_data.scope, + &mod_data.filename); + } else { + self.sess.span_bug(item.span, "expected ModData"); + } } fn process_path(&mut self, @@ -1188,7 +1184,10 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { } ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) => self.process_trait(item, generics, trait_refs, methods), - ast::ItemMod(ref m) => self.process_mod(item, m), + ast::ItemMod(ref m) => { + self.process_mod(item); + self.nest(item.id, |v| visit::walk_mod(v, m)); + } ast::ItemTy(ref ty, ref ty_params) => { let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id)); let value = ty_to_string(&**ty); @@ -1295,30 +1294,22 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { ast::ExprStruct(ref path, ref fields, ref base) => self.process_struct_lit(ex, path, fields, base), ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args), - ast::ExprField(ref sub_ex, ident) => { + ast::ExprField(ref sub_ex, _) => { if generated_code(sub_ex.span) { return } - self.visit_expr(&**sub_ex); - let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex).sty; - match *ty { - ty::ty_struct(def_id, _) => { - let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id); - for f in &fields { - if f.name == ident.node.name { - let sub_span = self.span.span_for_last_ident(ex.span); - self.fmt.ref_str(recorder::VarRef, - ex.span, - sub_span, - f.id, - self.cur_scope); - break; - } - } - } - _ => self.sess.span_bug(ex.span, - &format!("Expected struct type, found {:?}", ty)), + self.visit_expr(&sub_ex); + + let field_data = self.save_ctxt.get_expr_data(ex); + if let super::Data::VariableRefData(field_data) = field_data { + self.fmt.ref_str(recorder::VarRef, + ex.span, + Some(field_data.span), + field_data.ref_id, + field_data.scope); + } else { + self.sess.span_bug(ex.span, "expected VariableRefData"); } }, ast::ExprTupField(ref sub_ex, idx) => { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index c5c4a75ef823b..27297d8aa8d94 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -49,6 +49,12 @@ pub enum Data { FunctionData(FunctionData), /// Data for local and global variables (consts and statics). VariableData(VariableData), + /// Data for modules. + ModData(ModData), + + /// Data for the use of some variable (e.g., the use of a local variable, which + /// will refere to that variables declaration). + VariableRefData(VariableRefData), } /// Data for all kinds of functions and methods. @@ -72,6 +78,26 @@ pub struct VariableData { pub type_value: String, } +/// Data for modules. +pub struct ModData { + pub id: NodeId, + pub name: String, + pub qualname: String, + pub span: Span, + pub scope: NodeId, + pub filename: String, +} + +/// Data for the use of some item (e.g., the use of a local variable, which +/// will refere to that variables declaration (by ref_id)). +pub struct VariableRefData { + pub name: String, + pub span: Span, + pub scope: NodeId, + pub ref_id: DefId, +} + + impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn new(sess: &'l Session, analysis: &'l ty::CrateAnalysis<'tcx>, @@ -97,7 +123,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_item_data(&self, item: &ast::Item) -> Data { match item.node { - ast::Item_::ItemFn(..) => { + ast::ItemFn(..) => { let name = self.analysis.ty_cx.map.path_to_string(item.id); let qualname = format!("::{}", name); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); @@ -146,6 +172,58 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { type_value: ty_to_string(&typ), }) } + ast::ItemMod(ref m) => { + let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id)); + + let cm = self.sess.codemap(); + let filename = cm.span_to_filename(m.inner); + + let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod); + + Data::ModData(ModData { + id: item.id, + name: get_ident(item.ident).to_string(), + qualname: qualname, + span: sub_span.unwrap(), + scope: self.analysis.ty_cx.map.get_parent(item.id), + filename: filename, + }) + } + _ => { + // FIXME + unimplemented!(); + } + } + } + + pub fn get_expr_data(&self, expr: &ast::Expr) -> Data { + match expr.node { + ast::ExprField(ref sub_ex, ident) => { + let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &sub_ex).sty; + match *ty { + ty::ty_struct(def_id, _) => { + let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id); + for f in &fields { + if f.name == ident.node.name { + let sub_span = self.span_utils.span_for_last_ident(expr.span); + return Data::VariableRefData(VariableRefData { + name: get_ident(ident.node).to_string(), + span: sub_span.unwrap(), + scope: self.analysis.ty_cx.map.get_parent(expr.id), + ref_id: f.id, + }); + } + } + + self.sess.span_bug(expr.span, + &format!("Couldn't find field {} on {:?}", + &get_ident(ident.node), + ty)) + } + _ => self.sess.span_bug(expr.span, + &format!("Expected struct type, found {:?}", ty)), + } + } _ => { // FIXME unimplemented!(); From 23ec00751e8da1b8f138745cfcf6d861c0987915 Mon Sep 17 00:00:00 2001 From: Rein Henrichs Date: Wed, 27 May 2015 22:35:46 -0700 Subject: [PATCH 24/38] TRPL: fix typo, borow for borrow --- src/doc/trpl/references-and-borrowing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md index bb5adac5ebfc1..b69db228f2724 100644 --- a/src/doc/trpl/references-and-borrowing.md +++ b/src/doc/trpl/references-and-borrowing.md @@ -206,7 +206,7 @@ fn main() { ^ ``` -In other words, the mutable borow is held through the rest of our example. What +In other words, the mutable borrow is held through the rest of our example. What we want is for the mutable borrow to end _before_ we try to call `println!` and make an immutable borrow. In Rust, borrowing is tied to the scope that the borrow is valid for. And our scopes look like this: From d061a0f8d51ca2e4d21409e4083bedd430998d88 Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Thu, 28 May 2015 18:11:32 +0800 Subject: [PATCH 25/38] floating-point types are machine types, not machine-dependent types --- src/doc/reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 8d1b93ce3c8b9..e263d40459c89 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3255,8 +3255,8 @@ User-defined types have limited capabilities. The primitive types are the following: * The boolean type `bool` with values `true` and `false`. -* The machine types. -* The machine-dependent integer and floating-point types. +* The machine types (integer and floating-point). +* The machine-dependent integer types. #### Machine types From 2a63cc771565836c6c468fd6e20b84cbcb1abc44 Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Thu, 28 May 2015 16:18:26 +0200 Subject: [PATCH 26/38] TRPL: Fix Unescaped URL --- src/doc/trpl/conditional-compilation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/conditional-compilation.md b/src/doc/trpl/conditional-compilation.md index 73eb0101692af..a944b852d249f 100644 --- a/src/doc/trpl/conditional-compilation.md +++ b/src/doc/trpl/conditional-compilation.md @@ -34,7 +34,7 @@ These can nest arbitrarily: As for how to enable or disable these switches, if you’re using Cargo, they get set in the [`[features]` section][features] of your `Cargo.toml`: -[features]: http://doc.crates.io/manifest.html#the-[features]-section +[features]: http://doc.crates.io/manifest.html#the-%5Bfeatures%5D-section ```toml [features] From 16a47c2d916ad51660d638b85e30125ac3f3fe53 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 27 May 2015 14:15:24 -0400 Subject: [PATCH 27/38] remove references to IoResult This is now std::io::Result --- src/doc/style/errors/ergonomics.md | 2 +- src/doc/style/features/functions-and-methods/input.md | 2 +- src/doc/style/ownership/builders.md | 2 +- src/libcollections/fmt.rs | 4 ++-- src/libstd/rand/mod.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/style/errors/ergonomics.md b/src/doc/style/errors/ergonomics.md index d530301a90939..f2e23963e106c 100644 --- a/src/doc/style/errors/ergonomics.md +++ b/src/doc/style/errors/ergonomics.md @@ -63,4 +63,4 @@ for more details. ### The `Result`-`impl` pattern [FIXME] > **[FIXME]** Document the way that the `io` module uses trait impls -> on `IoResult` to painlessly propagate errors. +> on `std::io::Result` to painlessly propagate errors. diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md index 9b9500008c2f6..a1310de2e6063 100644 --- a/src/doc/style/features/functions-and-methods/input.md +++ b/src/doc/style/features/functions-and-methods/input.md @@ -121,7 +121,7 @@ The primary exception: sometimes a function is meant to modify data that the caller already owns, for example to re-use a buffer: ```rust -fn read(&mut self, buf: &mut [u8]) -> IoResult +fn read(&mut self, buf: &mut [u8]) -> std::io::Result ``` (From the [Reader trait](http://static.rust-lang.org/doc/master/std/io/trait.Reader.html#tymethod.read).) diff --git a/src/doc/style/ownership/builders.md b/src/doc/style/ownership/builders.md index 8f721a9767672..54992341ce54a 100644 --- a/src/doc/style/ownership/builders.md +++ b/src/doc/style/ownership/builders.md @@ -75,7 +75,7 @@ impl Command { } /// Executes the command as a child process, which is returned. - pub fn spawn(&self) -> IoResult { + pub fn spawn(&self) -> std::io::Result { ... } } diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index cb023bcb7a586..817a5baf3d1be 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -164,8 +164,8 @@ //! provides some helper methods. //! //! Additionally, the return value of this function is `fmt::Result` which is a -//! typedef to `Result<(), IoError>` (also known as `IoResult<()>`). Formatting -//! implementations should ensure that they return errors from `write!` +//! typedef to `Result<(), std::io::Error>` (also known as `std::io::Result<()>`). +//! Formatting implementations should ensure that they return errors from `write!` //! correctly (propagating errors upward). //! //! An example of implementing the formatting traits would look diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index e11a5818966fa..b806afc5951d8 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -95,7 +95,7 @@ impl StdRng { /// appropriate. /// /// Reading the randomness from the OS may fail, and any error is - /// propagated via the `IoResult` return value. + /// propagated via the `io::Result` return value. pub fn new() -> io::Result { OsRng::new().map(|mut r| StdRng { rng: r.gen() }) } From d0e6396a18503be956afbc79521bc407da89ceba Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Wed, 20 May 2015 16:45:41 +0200 Subject: [PATCH 28/38] Document #[repr] on non-C-like enums rustc accepts the following today: #[repr(u8)] enum Flag { Dropped, Alive(T), } and it has a good use (it appears to me): this inhibits the non-nullable pointer optimization that the regular Option and similar enums allow. Document this in the reference, and add tests to make sure it compiles. This means that we guarantee with `repr` that the discriminant will be present and with that size, but not sure if we want to guarantee anything more (no guarantee on placement in struct). --- src/doc/reference.md | 13 ++- .../run-pass/enum-discrim-manual-sizing-2.rs | 107 ++++++++++++++++++ 2 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 src/test/run-pass/enum-discrim-manual-sizing-2.rs diff --git a/src/doc/reference.md b/src/doc/reference.md index 21e9be59ebbdf..57c0f2da185fa 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1892,12 +1892,13 @@ interpreted: On `enum`s: -- `repr` - on C-like enums, this sets the underlying type used for - representation. Takes one argument, which is the primitive - type this enum should be represented for, or `C`, which specifies that it - should be the default `enum` size of the C ABI for that platform. Note that - enum representation in C is undefined, and this may be incorrect when the C - code is compiled with certain flags. +- `repr` - this sets the underlying type used for representation of the + discriminant. Takes one argument, which is the primitive type this enum + should be represented as, or `C`, which specifies that it should be the + default `enum` size of the C ABI for that platform. Note that enum + representation in C is implementation defined, and this may be incorrect when + the C code is compiled with certain flags. The representation attribute + inhibits elision of the enum discriminant in layout optimizations. On `struct`s: diff --git a/src/test/run-pass/enum-discrim-manual-sizing-2.rs b/src/test/run-pass/enum-discrim-manual-sizing-2.rs new file mode 100644 index 0000000000000..0470a9e19d580 --- /dev/null +++ b/src/test/run-pass/enum-discrim-manual-sizing-2.rs @@ -0,0 +1,107 @@ +// 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. + +// Test that explicit discriminant sizing inhibits the non-nullable pointer +// optimization in enum layout. + +use std::mem::size_of; + +#[repr(i8)] +enum Ei8 { + _None, + _Some(T), +} + +#[repr(u8)] +enum Eu8 { + _None, + _Some(T), +} + +#[repr(i16)] +enum Ei16 { + _None, + _Some(T), +} + +#[repr(u16)] +enum Eu16 { + _None, + _Some(T), +} + +#[repr(i32)] +enum Ei32 { + _None, + _Some(T), +} + +#[repr(u32)] +enum Eu32 { + _None, + _Some(T), +} + +#[repr(i64)] +enum Ei64 { + _None, + _Some(T), +} + +#[repr(u64)] +enum Eu64 { + _None, + _Some(T), +} + +#[repr(isize)] +enum Eint { + _None, + _Some(T), +} + +#[repr(usize)] +enum Euint { + _None, + _Some(T), +} + +#[repr(C)] +enum EC { + _None, + _Some(T), +} + +pub fn main() { + assert_eq!(size_of::>(), 1); + assert_eq!(size_of::>(), 1); + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>(), 4); + assert_eq!(size_of::>(), 4); + assert_eq!(size_of::>(), 8); + assert_eq!(size_of::>(), 8); + assert_eq!(size_of::>(), size_of::()); + assert_eq!(size_of::>(), size_of::()); + + let ptrsize = size_of::<&i32>(); + assert!(size_of::>() > ptrsize); + assert!(size_of::>() > ptrsize); + assert!(size_of::>() > ptrsize); + assert!(size_of::>() > ptrsize); + assert!(size_of::>() > ptrsize); + assert!(size_of::>() > ptrsize); + assert!(size_of::>() > ptrsize); + assert!(size_of::>() > ptrsize); + assert!(size_of::>() > ptrsize); + assert!(size_of::>() > ptrsize); + + assert!(size_of::>() > ptrsize); +} From 5249cbb7fa31ea2e6e8d77b49bfda386215b1ce7 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Thu, 28 May 2015 10:44:31 +0200 Subject: [PATCH 29/38] collections: Make BinaryHeap panic safe in sift_up / sift_down Use a struct called Hole that keeps track of an invalid location in the vector and fills the hole on drop. I include a run-pass test that the current BinaryHeap fails, and the new one passes. Fixes #25842 --- src/libcollections/binary_heap.rs | 113 +++++++++++++++----- src/test/run-pass/binary-heap-panic-safe.rs | 108 +++++++++++++++++++ 2 files changed, 196 insertions(+), 25 deletions(-) create mode 100644 src/test/run-pass/binary-heap-panic-safe.rs diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index af7112a5cb4e3..00e4002f82f4f 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -153,7 +153,7 @@ use core::prelude::*; use core::iter::{FromIterator}; -use core::mem::{zeroed, replace, swap}; +use core::mem::swap; use core::ptr; use slice; @@ -484,46 +484,42 @@ impl BinaryHeap { // The implementations of sift_up and sift_down use unsafe blocks in // order to move an element out of the vector (leaving behind a - // zeroed element), shift along the others and move it back into the - // vector over the junk element. This reduces the constant factor - // compared to using swaps, which involves twice as many moves. - fn sift_up(&mut self, start: usize, mut pos: usize) { + // hole), shift along the others and move the removed element back into the + // vector at the final location of the hole. + // The `Hole` type is used to represent this, and make sure + // the hole is filled back at the end of its scope, even on panic. + // Using a hole reduces the constant factor compared to using swaps, + // which involves twice as many moves. + fn sift_up(&mut self, start: usize, pos: usize) { unsafe { - let new = replace(&mut self.data[pos], zeroed()); + // Take out the value at `pos` and create a hole. + let mut hole = Hole::new(&mut self.data, pos); - while pos > start { - let parent = (pos - 1) >> 1; - - if new <= self.data[parent] { break; } - - let x = replace(&mut self.data[parent], zeroed()); - ptr::write(&mut self.data[pos], x); - pos = parent; + while hole.pos() > start { + let parent = (hole.pos() - 1) / 2; + if hole.removed() <= hole.get(parent) { break } + hole.move_to(parent); } - ptr::write(&mut self.data[pos], new); } } fn sift_down_range(&mut self, mut pos: usize, end: usize) { + let start = pos; unsafe { - let start = pos; - let new = replace(&mut self.data[pos], zeroed()); - + let mut hole = Hole::new(&mut self.data, pos); let mut child = 2 * pos + 1; while child < end { let right = child + 1; - if right < end && !(self.data[child] > self.data[right]) { + if right < end && !(hole.get(child) > hole.get(right)) { child = right; } - let x = replace(&mut self.data[child], zeroed()); - ptr::write(&mut self.data[pos], x); - pos = child; - child = 2 * pos + 1; + hole.move_to(child); + child = 2 * hole.pos() + 1; } - ptr::write(&mut self.data[pos], new); - self.sift_up(start, pos); + pos = hole.pos; } + self.sift_up(start, pos); } fn sift_down(&mut self, pos: usize) { @@ -554,6 +550,73 @@ impl BinaryHeap { pub fn clear(&mut self) { self.drain(); } } +/// Hole represents a hole in a slice i.e. an index without valid value +/// (because it was moved from or duplicated). +/// In drop, `Hole` will restore the slice by filling the hole +/// position with the value that was originally removed. +struct Hole<'a, T: 'a> { + data: &'a mut [T], + /// `elt` is always `Some` from new until drop. + elt: Option, + pos: usize, +} + +impl<'a, T> Hole<'a, T> { + /// Create a new Hole at index `pos`. + fn new(data: &'a mut [T], pos: usize) -> Self { + unsafe { + let elt = ptr::read(&data[pos]); + Hole { + data: data, + elt: Some(elt), + pos: pos, + } + } + } + + #[inline(always)] + fn pos(&self) -> usize { self.pos } + + /// Return a reference to the element removed + #[inline(always)] + fn removed(&self) -> &T { + self.elt.as_ref().unwrap() + } + + /// Return a reference to the element at `index`. + /// + /// Panics if the index is out of bounds. + /// + /// Unsafe because index must not equal pos. + #[inline(always)] + unsafe fn get(&self, index: usize) -> &T { + debug_assert!(index != self.pos); + &self.data[index] + } + + /// Move hole to new location + /// + /// Unsafe because index must not equal pos. + #[inline(always)] + unsafe fn move_to(&mut self, index: usize) { + debug_assert!(index != self.pos); + let index_ptr: *const _ = &self.data[index]; + let hole_ptr = &mut self.data[self.pos]; + ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); + self.pos = index; + } +} + +impl<'a, T> Drop for Hole<'a, T> { + fn drop(&mut self) { + // fill the hole again + unsafe { + let pos = self.pos; + ptr::write(&mut self.data[pos], self.elt.take().unwrap()); + } + } +} + /// `BinaryHeap` iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter <'a, T: 'a> { diff --git a/src/test/run-pass/binary-heap-panic-safe.rs b/src/test/run-pass/binary-heap-panic-safe.rs new file mode 100644 index 0000000000000..4888a8b84fc42 --- /dev/null +++ b/src/test/run-pass/binary-heap-panic-safe.rs @@ -0,0 +1,108 @@ +// 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(std_misc, collections, catch_panic, rand)] + +use std::__rand::{thread_rng, Rng}; +use std::thread; + +use std::collections::BinaryHeap; +use std::cmp; +use std::sync::Arc; +use std::sync::Mutex; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + +static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + +// old binaryheap failed this test +// +// Integrity means that all elements are present after a comparison panics, +// even if the order may not be correct. +// +// Destructors must be called exactly once per element. +fn test_integrity() { + #[derive(Eq, PartialEq, Ord, Clone, Debug)] + struct PanicOrd(T, bool); + + impl Drop for PanicOrd { + fn drop(&mut self) { + // update global drop count + DROP_COUNTER.fetch_add(1, Ordering::SeqCst); + } + } + + impl PartialOrd for PanicOrd { + fn partial_cmp(&self, other: &Self) -> Option { + if self.1 || other.1 { + panic!("Panicking comparison"); + } + self.0.partial_cmp(&other.0) + } + } + let mut rng = thread_rng(); + const DATASZ: usize = 32; + const NTEST: usize = 10; + + // don't use 0 in the data -- we want to catch the zeroed-out case. + let data = (1..DATASZ + 1).collect::>(); + + // since it's a fuzzy test, run several tries. + for _ in 0..NTEST { + for i in 1..DATASZ + 1 { + DROP_COUNTER.store(0, Ordering::SeqCst); + + let mut panic_ords: Vec<_> = data.iter() + .filter(|&&x| x != i) + .map(|&x| PanicOrd(x, false)) + .collect(); + let panic_item = PanicOrd(i, true); + + // heapify the sane items + rng.shuffle(&mut panic_ords); + let heap = Arc::new(Mutex::new(BinaryHeap::from_vec(panic_ords))); + let inner_data; + + { + let heap_ref = heap.clone(); + + + // push the panicking item to the heap and catch the panic + let thread_result = thread::catch_panic(move || { + heap.lock().unwrap().push(panic_item); + }); + assert!(thread_result.is_err()); + + // Assert no elements were dropped + let drops = DROP_COUNTER.load(Ordering::SeqCst); + //assert!(drops == 0, "Must not drop items. drops={}", drops); + + { + // now fetch the binary heap's data vector + let mutex_guard = match heap_ref.lock() { + Ok(x) => x, + Err(poison) => poison.into_inner(), + }; + inner_data = mutex_guard.clone().into_vec(); + } + } + let drops = DROP_COUNTER.load(Ordering::SeqCst); + assert_eq!(drops, DATASZ); + + let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::>(); + data_sorted.sort(); + assert_eq!(data_sorted, data); + } + } +} + +fn main() { + test_integrity(); +} + From 977d40fbfad4e36f1d264396b11b8b06f9ac921d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 27 May 2015 14:28:07 -0400 Subject: [PATCH 30/38] Improve Debug documentation --- src/libcore/fmt/mod.rs | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index da873f76d1bdd..ee1cab4076dc5 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -269,6 +269,50 @@ impl<'a> Display for Arguments<'a> { /// Format trait for the `:?` format. Useful for debugging, all types /// should implement this. +/// +/// Generally speaking, you should just `derive` a `Debug` implementation. +/// +/// # Examples +/// +/// Deriving an implementation: +/// +/// ``` +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// let origin = Point { x: 0, y: 0 }; +/// +/// println!("The origin is: {:?}", origin); +/// ``` +/// +/// Manually implementing: +/// +/// ``` +/// use std::fmt; +/// +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// impl fmt::Debug for Point { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "({}, {})", self.x, self.y) +/// } +/// } +/// +/// let origin = Point { x: 0, y: 0 }; +/// +/// println!("The origin is: {:?}", origin); +/// ``` +/// +/// There are a number of `debug_*` methods on `Formatter` to help you with manual +/// implementations, such as [`debug_struct`][debug_struct]. +/// +/// [debug_struct]: ../std/fmt/struct.Formatter.html#method.debug_struct #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \ defined in your crate, add `#[derive(Debug)]` or \ From 15ab4813223ed5252a9c434f14eb5b66462b018b Mon Sep 17 00:00:00 2001 From: Mathieu David Date: Thu, 28 May 2015 23:47:27 +0200 Subject: [PATCH 31/38] removed lonely closing parenthesis There was no opening parenthesis for this closing parenthesis... --- src/doc/trpl/method-syntax.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index e5f490e15e13e..1f694f71a883f 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -4,7 +4,7 @@ Functions are great, but if you want to call a bunch of them on some data, it can be awkward. Consider this code: ```rust,ignore -baz(bar(foo))); +baz(bar(foo)); ``` We would read this left-to right, and so we see ‘baz bar foo’. But this isn’t the From 15aeea5477f1cf0fed4fead4ba1cfda37eba7c8d Mon Sep 17 00:00:00 2001 From: Mathieu David Date: Fri, 29 May 2015 00:43:39 +0200 Subject: [PATCH 32/38] Corrected typo "workd" corrected to "world" --- src/doc/trpl/traits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index 9ac170ddec298..2ef9e7ca22e60 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -285,7 +285,7 @@ fn bar(x: T, y: K) where T: Clone, K: Clone + Debug { fn main() { foo("Hello", "world"); - bar("Hello", "workd"); + bar("Hello", "world"); } ``` From 19cb2a77076657063768e6db342a38933f0ba874 Mon Sep 17 00:00:00 2001 From: David Campbell Date: Sat, 14 Feb 2015 14:17:03 -0500 Subject: [PATCH 33/38] add newline before list in functions-and-methods The current version of hoedown treats lists interrupting paragraphs in the Markdown.pl style rather than CommonMark, so a newline is needed for the list to be rendered properly. --- src/doc/style/features/functions-and-methods/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/style/features/functions-and-methods/README.md b/src/doc/style/features/functions-and-methods/README.md index 2dcfc382d0baf..611cd564ccac7 100644 --- a/src/doc/style/features/functions-and-methods/README.md +++ b/src/doc/style/features/functions-and-methods/README.md @@ -20,6 +20,7 @@ for any operation that is clearly associated with a particular type. Methods have numerous advantages over functions: + * They do not need to be imported or qualified to be used: all you need is a value of the appropriate type. * Their invocation performs autoborrowing (including mutable borrows). From 06706510cbb0035b713a32c17291742c8090d9eb Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 21 Feb 2015 10:53:42 -0500 Subject: [PATCH 34/38] Make adjancent code examples more similar --- src/doc/style/features/let.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/style/features/let.md b/src/doc/style/features/let.md index f13a84f6fee86..6f423c6de8e15 100644 --- a/src/doc/style/features/let.md +++ b/src/doc/style/features/let.md @@ -61,8 +61,8 @@ conditional expression. Prefer ```rust -s.iter().map(|x| x * 2) - .collect::>() +let v = s.iter().map(|x| x * 2) + .collect::>(); ``` over From 4d90b4d9b8ba4275be9031bf19c49f90c33c9823 Mon Sep 17 00:00:00 2001 From: David Campbell Date: Mon, 30 Mar 2015 18:31:42 -0400 Subject: [PATCH 35/38] Update let.md -- follow whitespace style guideline "Idiomatic code should not use extra whitespace in the middle of a line to provide alignment." --- src/doc/style/features/let.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/style/features/let.md b/src/doc/style/features/let.md index 6f423c6de8e15..4a0bf4353b90e 100644 --- a/src/doc/style/features/let.md +++ b/src/doc/style/features/let.md @@ -34,7 +34,7 @@ Prefer ```rust let foo = match bar { - Baz => 0, + Baz => 0, Quux => 1 }; ``` From 31a007af1964891ef820b10c6a8d3e667fbca1ae Mon Sep 17 00:00:00 2001 From: David Campbell Date: Mon, 30 Mar 2015 18:35:17 -0400 Subject: [PATCH 36/38] remove extra space from "over" code as well --- src/doc/style/features/let.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/style/features/let.md b/src/doc/style/features/let.md index 4a0bf4353b90e..01dff3dcceaf1 100644 --- a/src/doc/style/features/let.md +++ b/src/doc/style/features/let.md @@ -44,7 +44,7 @@ over ```rust let foo; match bar { - Baz => { + Baz => { foo = 0; } Quux => { From d0744ba3e7b60a25837af8350b3af7ef1d2b4548 Mon Sep 17 00:00:00 2001 From: Nils Liberg Date: Sat, 23 May 2015 11:19:11 +0200 Subject: [PATCH 37/38] Fix mistake: "to to" -> "to" --- src/doc/style/ownership/builders.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/style/ownership/builders.md b/src/doc/style/ownership/builders.md index 54992341ce54a..348be516e374d 100644 --- a/src/doc/style/ownership/builders.md +++ b/src/doc/style/ownership/builders.md @@ -16,7 +16,7 @@ If `T` is such a data structure, consider introducing a `T` _builder_: value. When possible, choose a better name: e.g. `Command` is the builder for `Process`. 2. The builder constructor should take as parameters only the data _required_ to - to make a `T`. + make a `T`. 3. The builder should offer a suite of convenient methods for configuration, including setting up compound inputs (like slices) incrementally. These methods should return `self` to allow chaining. From adac861db28b79f52455b1fd3121cd1964d0aceb Mon Sep 17 00:00:00 2001 From: Nils Liberg Date: Sat, 23 May 2015 17:31:57 +0200 Subject: [PATCH 38/38] Fix link to newtypes page --- src/doc/style/features/functions-and-methods/input.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md index a1310de2e6063..072021194c13e 100644 --- a/src/doc/style/features/functions-and-methods/input.md +++ b/src/doc/style/features/functions-and-methods/input.md @@ -159,7 +159,7 @@ fn foo(a: u8) { ... } Note that [`ascii::Ascii`](http://static.rust-lang.org/doc/master/std/ascii/struct.Ascii.html) is a _wrapper_ around `u8` that guarantees the highest bit is zero; see -[newtype patterns]() for more details on creating typesafe wrappers. +[newtype patterns](../types/newtype.md) for more details on creating typesafe wrappers. Static enforcement usually comes at little run-time cost: it pushes the costs to the boundaries (e.g. when a `u8` is first converted into an